[DTP-Worker] Sprint 8 · buffer · Legal/CONFOTUR (2e surface) : la CROSS-COHÉRENCE PERMISSIONS du DocType — le CŒUR sécurité du livrable — énumérait EN PROSE, PAR rôle, son portail ET son jeu d'ACTIONS RBAC sans AUCUN gate d'IDENTITÉ.
Le §« Cœur du livrable : cross-cohérence » →Permissions du README legal/confotur énumère À LA MAIN, PAR rôle, role_id + portail + actions (« mot pour mot les permissions_cibles RBAC … ni ajout ni retrait ») : `ventes-confotur` (Ventes) → read/write/create/print · `legal-onapi` (Direction) → read/write/create · `legal-directeur` (Direction) → read/write/**submit**/report. Le bloc CONFOTUR existant ne gate QUE le COMPTE (« 3 rôles ») — AVEUGLE à leur identité. Ces 3 lignes sont DATA-DERIVED d'out/MANIFEST.json (roles_rbac_utilises[] : role_id · portail · permissions, recomputé du contrat rbac_50_roles.json à chaque build) et projetées dans out/doctype_confotur_application.json (permissions[] par nom de rôle) — les DEUX byte-gatés par check_artifacts. PIÈGE : le compte « 3 rôles » ne voit pas l'identité → PROMOUVOIR ventes-confotur à submit (élévation de privilège cassant la séparation des pouvoirs dont is_submittable est déduit) · RETIRER une action · RÉAFFECTER un portail · RENOMMER un rôle · AJOUTER une ligne fantôme laissait la prose périmée pendant que les artefacts disent autre chose → l'agent ERPNext Backend câblerait le mauvais jeu de permissions (le risque même que la cross-cohérence veut prévenir) — « vert trompeur » qu'aucune suite tests/ (qui teste des FONCTIONS de mapping RBAC, pas la prose) n'attrape. Même patron d'IDENTITÉ que le catalogue RBAC fixtures_gen (singleton set_user_permissions) et la cross-cohérence e-CF DGII. Nouveau bloc dans ci/check_readme_claims.sh (après le bloc de comptes CONFOTUR) : (1) jeu d'actions + portail de CHAQUE rôle recomputés de roles_rbac_utilises[], prose exigée EXACTE (set-diff · casse normalisée) ; (2) identité d'ensemble README⇔MANIFEST (aucun rôle fantôme NI manquant). Cohérences croisées en bonus (mordent un artefact INTERNEMENT incohérent) : MANIFEST ⇄ DocType d'accord sur le jeu d'actions par rôle · séparation des pouvoirs — submit porté par EXACTEMENT un rôle (legal-directeur) et is_submittable==True déduit de sa présence (README:31). Un claim absent échoue AUSSI. 7 morsures vérifiées : README promeut ventes-confotur à submit (en trop=[submit]) · README réaffecte legal-onapi Direction→Ventes (portail) · README retire report de legal-directeur (absents=[report]) · README renomme un role_id (fantôme=[legal-conseil] + manquant=[legal-onapi]) · énumération supprimée (INTROUVABLE) · artefact MANIFEST promeut ventes-confotur à submit (README périmé + séparation cassée + incohérence MANIFEST⇄DocType) · artefact DocType is_submittable=false alors qu'un rôle porte submit (incohérence interne) ; restauré = green : 3 rôles portail+actions == MANIFEST · identité d'ensemble · submit singleton · is_submittable=True · exit 0. État courant : aucun jeu d'actions périmé (anti-invention #6, rien à réécrire) — le défaut est la surface ungated. ci/README.md (table + détail « 2e surface CONFOTUR ») mis à jour · working tree byte-restauré (git checkout --, JAMAIS git clean) · 7 gates re-verts. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -1,5 +1,60 @@
|
|||||||
# Activity Log · 2026-07-31 · Claude Code DTP
|
# Activity Log · 2026-07-31 · Claude Code DTP
|
||||||
|
|
||||||
|
## Session `20260731_220140` · Buffer S8 · Domaine Legal/CONFOTUR (2e surface) : la **cross-cohérence PERMISSIONS** du DocType — le CŒUR sécurité du livrable — énumérait EN PROSE, PAR rôle, son **portail** ET son **jeu d'actions RBAC** (`ventes-confotur`→read/write/create/print · `legal-onapi`→read/write/create · `legal-directeur`→read/write/**submit**/report) SANS AUCUN gate d'IDENTITÉ. Le bloc CONFOTUR existant ne gate QUE le COMPTE (« 3 rôles »).
|
||||||
|
|
||||||
|
**Tâche** : **Sprint 8 · buffer** (DevOps CI/CD · QA). Roadmap fonctionnellement
|
||||||
|
close ; poursuite de la série anti-dérive (CLAUDE.md #6). Même patron d'IDENTITÉ que
|
||||||
|
le catalogue RBAC `fixtures_gen` (séparation des pouvoirs `set_user_permissions`) ou
|
||||||
|
la cross-cohérence e-CF DGII — appliqué à la 2ᵉ surface data-derived du README
|
||||||
|
`legal/confotur`, jamais gatée.
|
||||||
|
|
||||||
|
**Dérive silencieuse fermée** :
|
||||||
|
- `05_deliverables_mvp/legal/confotur/README.md` §« Cœur du livrable :
|
||||||
|
cross-cohérence » →Permissions (l.28-30) énumère, PAR rôle, `role_id` + portail +
|
||||||
|
jeu d'actions, annoncé « **mot pour mot** les `permissions_cibles` RBAC … ni ajout
|
||||||
|
ni retrait ».
|
||||||
|
- Sources faisant autorité (byte-gatées par `check_artifacts`) :
|
||||||
|
`out/MANIFEST.json.roles_rbac_utilises[]` (`role_id` · `portail` · `permissions`,
|
||||||
|
recomputé du contrat `rbac_50_roles.json` à chaque build) + sa projection
|
||||||
|
`out/doctype_confotur_application.json.permissions[]` (par nom de rôle ERPNext).
|
||||||
|
- Piège : le compte « 3 rôles » est AVEUGLE à leur identité. PROMOUVOIR
|
||||||
|
`ventes-confotur` à `submit` (élévation de privilège cassant la séparation des
|
||||||
|
pouvoirs dont `is_submittable` est déduit), RETIRER une action, RÉAFFECTER un
|
||||||
|
portail, RENOMMER un rôle ou AJOUTER une ligne fantôme laissait la prose périmée
|
||||||
|
pendant que les artefacts disent autre chose → l'agent ERPNext Backend câblerait le
|
||||||
|
mauvais jeu de permissions (le risque même que la cross-cohérence veut prévenir).
|
||||||
|
Aucune suite `tests/` (qui teste des FONCTIONS de mapping RBAC, pas la prose)
|
||||||
|
n'attrape ce « vert trompeur ».
|
||||||
|
- **État courant** : **aucun jeu d'actions périmé** — les 3 lignes recoupent les
|
||||||
|
artefacts exactement (anti-invention #6, rien à réécrire). Le défaut est la
|
||||||
|
**surface ungated**.
|
||||||
|
|
||||||
|
**Gate ajouté** (`ci/check_readme_claims.sh`, nouveau bloc « Legal · CONFOTUR
|
||||||
|
cross-cohérence PERMISSIONS » après le bloc de comptes CONFOTUR) : (1) jeu d'actions
|
||||||
|
+ portail de CHAQUE rôle recomputés de `roles_rbac_utilises[]`, prose exigée EXACTE
|
||||||
|
(set-diff · casse normalisée) ; (2) identité d'ensemble README ⇔ MANIFEST (aucun rôle
|
||||||
|
fantôme NI manquant). Cohérences croisées en bonus (mordent un artefact INTERNEMENT
|
||||||
|
incohérent) : MANIFEST ⇄ DocType d'accord sur le jeu d'actions par rôle · séparation
|
||||||
|
des pouvoirs — `submit` porté par EXACTEMENT un rôle (`legal-directeur`) et
|
||||||
|
`is_submittable == True` déduit de sa présence (README:31). Un claim absent échoue
|
||||||
|
AUSSI (traçabilité).
|
||||||
|
|
||||||
|
**7 morsures vérifiées** : README promeut `ventes-confotur` à `submit` (en
|
||||||
|
trop=[submit]) · README réaffecte `legal-onapi` Direction→Ventes (portail) · README
|
||||||
|
retire `report` de `legal-directeur` (absents=[report]) · README renomme un `role_id`
|
||||||
|
(fantôme=[legal-conseil] + manquant=[legal-onapi]) · énumération supprimée
|
||||||
|
(INTROUVABLE) · artefact MANIFEST promeut `ventes-confotur` à `submit` (README périmé
|
||||||
|
+ séparation cassée `[legal-directeur,ventes-confotur]` + incohérence MANIFEST⇄DocType)
|
||||||
|
· artefact DocType `is_submittable=false` alors qu'un rôle porte `submit` (incohérence
|
||||||
|
interne) ; restauré = green : 3 rôles portail+actions == MANIFEST · identité d'ensemble
|
||||||
|
· `submit` singleton · `is_submittable=True` · exit 0. Working tree byte-restauré
|
||||||
|
(`git checkout --`, JAMAIS `git clean`) · **7 gates re-verts**.
|
||||||
|
|
||||||
|
- `ci/README.md` (table récap + détail « 2ᵉ surface du même README CONFOTUR ») mis à jour.
|
||||||
|
- **Hors périmètre worker (VPS · #8)** : néant (gate bash/python3 stdlib en-repo ;
|
||||||
|
édition **hors** `05_deliverables_mvp/*/out` ⇒ 0 dérive d'artefact).
|
||||||
|
- **Auto-score 4Big** : 96/100.
|
||||||
|
|
||||||
## Session `20260731_210134` · Buffer S8 · **CI ROUGE sur `main` — régression réelle réparée** : le gate `guard_constraints.sh` (lancé par `ci.yml:28`) échouait au `HEAD` `0790fa7`, alors que le message de commit précédent affirmait « 7 gates re-verts ».
|
## Session `20260731_210134` · Buffer S8 · **CI ROUGE sur `main` — régression réelle réparée** : le gate `guard_constraints.sh` (lancé par `ci.yml:28`) échouait au `HEAD` `0790fa7`, alors que le message de commit précédent affirmait « 7 gates re-verts ».
|
||||||
|
|
||||||
**Tâche** : **Sprint 8 · buffer** (DevOps CI/CD · QA). Contrairement aux sessions
|
**Tâche** : **Sprint 8 · buffer** (DevOps CI/CD · QA). Contrairement aux sessions
|
||||||
|
|||||||
+30
-2
File diff suppressed because one or more lines are too long
@@ -1136,6 +1136,117 @@ if conf_exp is not None:
|
|||||||
bad(f"Legal confotur · {path_f} — dit {'/'.join(m.groups())} MAIS "
|
bad(f"Legal confotur · {path_f} — dit {'/'.join(m.groups())} MAIS "
|
||||||
f"MANIFEST dit {'/'.join(conf_exp)} ({conf_src}) → régénérer le doc")
|
f"MANIFEST dit {'/'.join(conf_exp)} ({conf_src}) → régénérer le doc")
|
||||||
|
|
||||||
|
# ============================================================================
|
||||||
|
# Legal · CONFOTUR — cross-cohérence PERMISSIONS (2e surface du MÊME README) :
|
||||||
|
# l'IDENTITÉ des 3 rôles + leur jeu d'ACTIONS exact — le CŒUR sécurité du livrable.
|
||||||
|
# ----------------------------------------------------------------------------
|
||||||
|
# Le bloc CONFOTUR ci-dessus ne gate que le COMPTE (« 3 rôles »). La section
|
||||||
|
# « Cœur du livrable : cross-cohérence » du README (05_deliverables_mvp/legal/
|
||||||
|
# confotur/README.md §Permissions) énumère À LA MAIN, PAR rôle, son portail ET son
|
||||||
|
# jeu d'actions RBAC — annoncé « mot pour mot les permissions_cibles RBAC … ni
|
||||||
|
# ajout ni retrait » :
|
||||||
|
# - `ventes-confotur` (portail Ventes) → read/write/create/print
|
||||||
|
# - `legal-onapi` (portail Direction) → read/write/create
|
||||||
|
# - `legal-directeur` (portail Direction) → read/write/**submit**/report
|
||||||
|
# Ces trois lignes sont DATA-DERIVED d'out/MANIFEST.json (`roles_rbac_utilises[]` :
|
||||||
|
# role_id · portail · `permissions`, recomputé du contrat rbac_50_roles.json à
|
||||||
|
# chaque build) et projetées dans out/doctype_confotur_application.json
|
||||||
|
# (`permissions[]` par nom de rôle) — les DEUX byte-gatés par check_artifacts. Le
|
||||||
|
# compte « 3 rôles » est AVEUGLE à leur identité : PROMOUVOIR `ventes-confotur` à
|
||||||
|
# `submit` (élévation de privilège — casse la séparation des pouvoirs dont
|
||||||
|
# is_submittable est déduit), RETIRER une action, RÉAFFECTER un portail, RENOMMER
|
||||||
|
# un rôle ou AJOUTER une ligne fantôme laisse la prose périmée pendant que les
|
||||||
|
# artefacts disent autre chose → l'agent ERPNext Backend câblerait le mauvais jeu
|
||||||
|
# de permissions (le risque même que la cross-cohérence veut prévenir) — « vert
|
||||||
|
# trompeur » qu'aucune suite tests/ (qui teste des FONCTIONS de mapping RBAC, pas
|
||||||
|
# la prose) n'attrape. Même patron d'IDENTITÉ que le catalogue RBAC fixtures_gen
|
||||||
|
# (séparation des pouvoirs `set_user_permissions`) ou la cross-cohérence e-CF. On
|
||||||
|
# RECOMPUTE chaque jeu d'actions + portail depuis le MANIFEST (zéro duplication du
|
||||||
|
# contrat #6) et on exige que la prose l'encode EXACTEMENT (set-diff : absent ET en
|
||||||
|
# trop · casse normalisée), + l'identité d'ensemble (README ⇔ MANIFEST, aucun rôle
|
||||||
|
# fantôme ni manquant). Cohérences croisées en bonus (mordent un artefact
|
||||||
|
# INTERNEMENT incohérent) : MANIFEST ⇄ DocType d'accord sur le jeu d'actions par
|
||||||
|
# rôle · séparation des pouvoirs : `submit` porté par EXACTEMENT un rôle et
|
||||||
|
# is_submittable=True déduit de sa présence (README:31). Un claim absent échoue
|
||||||
|
# AUSSI (traçabilité).
|
||||||
|
# ============================================================================
|
||||||
|
CONF_RD2 = f"{D}/legal/confotur/README.md"
|
||||||
|
_CONF_PERM_FLAGS = ("read", "write", "create", "submit", "cancel", "amend",
|
||||||
|
"delete", "report", "export", "import", "print", "email", "share")
|
||||||
|
try:
|
||||||
|
conf_roles = load("legal/confotur/out/MANIFEST.json")["roles_rbac_utilises"]
|
||||||
|
conf_perm_by_id = {r["role_id"]: set(r["permissions"]) for r in conf_roles}
|
||||||
|
conf_portail_by_id = {r["role_id"]: r["portail"] for r in conf_roles}
|
||||||
|
conf_name_by_id = {r["role_id"]: r["erpnext_role_name"] for r in conf_roles}
|
||||||
|
conf_dt = load("legal/confotur/out/doctype_confotur_application.json")
|
||||||
|
conf_dt_perm_by_name = {p["role"]: {f for f in _CONF_PERM_FLAGS if p.get(f)}
|
||||||
|
for p in conf_dt["permissions"]}
|
||||||
|
conf_submittable = bool(conf_dt.get("is_submittable"))
|
||||||
|
except (OSError, KeyError, ValueError, TypeError) as e:
|
||||||
|
bad(f"Legal confotur perms · artefact illisible/inattendu : {e}"); conf_roles = None
|
||||||
|
if conf_roles:
|
||||||
|
# bonus 1 : les DEUX artefacts (MANIFEST ⇄ DocType) d'accord sur le jeu d'actions
|
||||||
|
for rid, perms in conf_perm_by_id.items():
|
||||||
|
nm = conf_name_by_id[rid]
|
||||||
|
dt_perms = conf_dt_perm_by_name.get(nm)
|
||||||
|
if dt_perms is None:
|
||||||
|
bad(f"Legal confotur perms · rôle `{rid}` ({nm}) ABSENT des permissions du DocType")
|
||||||
|
elif dt_perms != perms:
|
||||||
|
bad(f"Legal confotur perms · incohérence artefacts pour `{rid}` : MANIFEST "
|
||||||
|
f"{sorted(perms)} MAIS DocType {sorted(dt_perms)}")
|
||||||
|
else:
|
||||||
|
good(f"Legal confotur perms · `{rid}` — MANIFEST {sorted(perms)} == DocType (accord)")
|
||||||
|
# bonus 2 : séparation des pouvoirs — `submit` porté par EXACTEMENT un rôle, et
|
||||||
|
# is_submittable DÉDUIT de sa présence (README:31). Singleton sécurité (cf. RBAC Admin).
|
||||||
|
conf_submitters = {rid for rid, p in conf_perm_by_id.items() if "submit" in p}
|
||||||
|
if len(conf_submitters) != 1:
|
||||||
|
bad(f"Legal confotur perms · séparation des pouvoirs : action `submit` portée par "
|
||||||
|
f"{sorted(conf_submitters)} (attendu 1 — ni vacant, ni élévation de privilège)")
|
||||||
|
elif conf_submittable is not True:
|
||||||
|
bad(f"Legal confotur perms · un rôle porte `submit` MAIS is_submittable="
|
||||||
|
f"{conf_submittable} → DocType incohérent")
|
||||||
|
else:
|
||||||
|
good(f"Legal confotur perms · séparation des pouvoirs — `submit` singleton "
|
||||||
|
f"{sorted(conf_submitters)} · is_submittable=True (déduit · README:31)")
|
||||||
|
conf_rd2 = read_norm(CONF_RD2)
|
||||||
|
if conf_rd2 is not None:
|
||||||
|
for rid in sorted(conf_perm_by_id):
|
||||||
|
exp_perms = conf_perm_by_id[rid]
|
||||||
|
exp_portail = conf_portail_by_id[rid]
|
||||||
|
m = re.search(rf"`{re.escape(rid)}` \(portail ([^)]+)\) → ([\w/*]+)", conf_rd2)
|
||||||
|
if m is None:
|
||||||
|
bad(f"Legal confotur perms · {CONF_RD2} — ligne du rôle `{rid}` INTROUVABLE "
|
||||||
|
f"(attendu portail {exp_portail} · {sorted(exp_perms)})")
|
||||||
|
continue
|
||||||
|
got_portail = m.group(1).strip().lower()
|
||||||
|
got_perms = {t.replace("*", "").strip().lower()
|
||||||
|
for t in m.group(2).split("/") if t.replace("*", "").strip()}
|
||||||
|
if got_portail != exp_portail:
|
||||||
|
bad(f"Legal confotur perms · `{rid}` — {CONF_RD2} dit portail "
|
||||||
|
f"« {m.group(1).strip()} » MAIS MANIFEST dit « {exp_portail} » → régénérer")
|
||||||
|
elif got_perms != exp_perms:
|
||||||
|
miss = sorted(exp_perms - got_perms); extra = sorted(got_perms - exp_perms)
|
||||||
|
detail = (f" · absents={miss}" if miss else "") + \
|
||||||
|
(f" · en trop={extra}" if extra else "")
|
||||||
|
bad(f"Legal confotur perms · `{rid}` — {CONF_RD2} énumère {sorted(got_perms)} "
|
||||||
|
f"MAIS MANIFEST {sorted(exp_perms)}{detail} → régénérer le README")
|
||||||
|
else:
|
||||||
|
good(f"Legal confotur perms · `{rid}` — portail {got_portail} · actions "
|
||||||
|
f"{sorted(got_perms)} == MANIFEST")
|
||||||
|
# identité d'ensemble : README ⇔ MANIFEST (aucun rôle fantôme NI manquant) —
|
||||||
|
# rd_ids = rôles réellement écrits dans la prose §Permissions (patron identique).
|
||||||
|
rd_ids = set(re.findall(r"`([a-z][a-z-]+)` \(portail [^)]+\) → [\w/*]+", conf_rd2))
|
||||||
|
exp_ids = set(conf_perm_by_id)
|
||||||
|
if rd_ids == exp_ids:
|
||||||
|
good(f"Legal confotur perms · identité d'ensemble — {sorted(rd_ids)} == "
|
||||||
|
f"roles_rbac_utilises (aucun rôle fantôme/manquant)")
|
||||||
|
else:
|
||||||
|
miss = sorted(exp_ids - rd_ids); extra = sorted(rd_ids - exp_ids)
|
||||||
|
detail = (f" · absents={miss}" if miss else "") + \
|
||||||
|
(f" · en trop (fantôme)={extra}" if extra else "")
|
||||||
|
bad(f"Legal confotur perms · {CONF_RD2} — rôles énumérés {sorted(rd_ids)} MAIS "
|
||||||
|
f"MANIFEST {sorted(exp_ids)}{detail} → régénérer le README")
|
||||||
|
|
||||||
# ============================================================================
|
# ============================================================================
|
||||||
# Audit 5D · synthèse de l'audit de conformité (contrôles / dimensions / verdict
|
# Audit 5D · synthèse de l'audit de conformité (contrôles / dimensions / verdict
|
||||||
# pass-fail-à confirmer) — même classe de « vert trompeur », transcrite À LA MAIN
|
# pass-fail-à confirmer) — même classe de « vert trompeur », transcrite À LA MAIN
|
||||||
|
|||||||
Reference in New Issue
Block a user