Défaut réel (même classe que le bug regression_run.json corrigé plus tôt) : les 4 générateurs RBAC (fixtures_gen/userperm_gen/roleprofile_gen/apply_plan) .gitignore-aient leur out/, alors qu'ils sont audités en archétype `generator` (critère HANDOFF). En checkout PROPRE (git archive HEAD = ce que voit le runner Gitea) leur out/ est absent → qa/audit_4big (dont le build relit le out/ de CHAQUE module) les note 80<95 ⇒ INV7 ⇒ build refusé ⇒ check-artifacts ET check-regression ROUGES. Ça ne passait qu'en local via les out/ non suivis laissés par des build manuels. Fix : committer le out/ des 4 générateurs (build byte-déterministe prouvé ; apply_plan lit ses frères en process, pas via out/) → alignement sur les 15 autres générateurs ; audit 100/100 en checkout propre. Durcissement : check_artifacts.sh exige désormais `git ls-files --error-unmatch` sur chaque fichier produit → un out/ ignoré/non commité devient une erreur LOCALE honnête au lieu d'une surprise en CI. Bite-proof : git rm --cached d'un artefact (laissé sur disque) ⇒ exit 1 ; re-add ⇒ exit 0. Régénéré : quality_report.json (dérive DOC = taille des 4 README édités). Vérifs : 6 gates verts sur git archive propre ; 534/21 inchangé ; suites OK. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
5.1 KiB
Générateur de plan User Permission · RBAC 50 rôles → row-level
Sprint 2 · agent ERPNext Backend. Complément du
générateur de fixtures Role + Custom DocPerm :
il couvre la dimension ROW-LEVEL (scope_donnees) que les DocPerm ne portent
pas à eux seuls. Transforme le contrat ../rbac_50_roles.json
(validé par ../rbac.schema.json) en un plan
d'enforcement des User Permission Frappe/ERPNext v15, prêt à matérialiser sur
le VPS. Réalise la « prochaine tâche » annoncée au §7 de
../RBAC_50_ROLES_SPEC.md.
Ce worker n'écrit jamais sur le VPS (contrainte #8). Il produit un PLAN en-repo ; l'application réelle (matérialisation par utilisateur,
bench) reste côté serveur.
Pourquoi un « plan » et pas des fixtures directes
Une User Permission Frappe est attachée à un utilisateur, pas à un rôle.
Ce worker ne connaît aucun utilisateur réel (anti-invention #6) → il ne peut
produire qu'un template par rôle dont le champ user est une sentinelle
(__ASSIGN_PER_USER__). L'agent ERPNext clone ce template une fois par
utilisateur assigné au rôle et remplace la sentinelle par son e-mail, côté VPS.
Ce qui est généré (out/, commité · byte-déterministe)
| Fichier | Rôle |
|---|---|
user_permission_plan.json |
1 entrée par rôle (50) : scope_donnees, entite_principale, mechanism d'enforcement, et user_permission_template (ou null). |
MANIFEST.json |
Traçabilité : comptes par mécanisme + Companies à créer/confirmer VPS + rôles equipe sans mécanisme natif à décider VPS. |
Mapping scope_donnees → mécanisme Frappe natif (aucune invention · #6)
scope_donnees |
Mécanisme (mechanism) |
Template émis ? |
|---|---|---|
own |
docperm_if_owner — déjà posé par fixtures_gen (if_owner=1). |
non (null) |
entite |
user_permission_company — User Permission allow=Company, for_value=entité, apply_to_all_doctypes=1. |
oui |
groupe |
none_consolidated — vue consolidée transversale, aucune restriction. |
non (null) |
equipe |
vps_confirm_team — pas de dimension row-level native dans ERPNext v15 → signalé, jamais mappé arbitrairement. |
non (null) |
Répartition du contrat courant : 28 entite · 16 groupe · 2 own
· 4 equipe.
Utilisation
# Génère out/user_permission_plan.json + out/MANIFEST.json
python3 userperm_gen.py build # [-o DOSSIER]
# Valide le plan (schéma + invariants row-level) sans rien écrire
python3 userperm_gen.py validate
# Tests (stdlib pur, zéro pip)
python3 -m unittest discover -s tests -v
Garde-fous (anti-invention · #6 · déterminisme)
- Aucun utilisateur inventé : le champ
userde chaque template est toujours la sentinelle (vérifié par test + CLI). - Aucune restriction fabriquée hors portée
entite:own/groupe/equipeportentuser_permission_template = null. entite+ périmètre consolidé (« Groupe ») →ValueError(garde-fou anti-contrat corrompu : une portée consolidée doit êtregroupe).- Fidélité au contrat : scope, entité et
for_valuere-vérifiés entrée par entrée contrerbac_50_roles.json; le CLI refuse d'écrire si un invariant casse. - Sortie déterministe (tri stable par nom de rôle, aucun horodatage) → diffable, re-générable bit-à-bit en CI.
Application sur VPS (agent ERPNext Backend · hors périmètre worker)
- Créer/confirmer les Companies listées dans
MANIFEST.companies_a_confirmer(une par entité juridique · CLAUDE.md §Entités). - Pour chaque rôle de
mechanism = user_permission_company: cloneruser_permission_templatepar utilisateur assigné au rôle, en remplaçantuserpar son e-mail réel, puis importer. - Décider le mécanisme des rôles
MANIFEST.roles_scope_equipe_a_confirmer(equipe) — options natives : champ custom « Équipe » +User Permission, ou hiérarchieEmployee.reports_to. À valider avec Michel avant application. - Les rôles
ownsont déjà couverts parif_owner(fixturescustom_docperm). - Vérification HTTP post-déploiement (workflow #3) + audit QA 4Big.
Vérification en-repo
python3 -m unittest discover -s tests -v→ 12/12 verts (schéma maison + oraclejsonschemasi présent ; couverture bijective des 50 rôles, mécanisme = mapping natif du scope, template SSIentite, anti-invention utilisateur, déterminisme).- Job CI dédié
rbac-userperm-testsajouté au gate (.gitea/workflows/ci.yml, Gitea Actions uniquement · #2).
Auto-score 4Big du livrable : 96/100
Réserve −4 : matérialisation par utilisateur + création des Companies +
décision du mécanisme equipe = côté VPS (agent ERPNext, hors périmètre worker,
contrainte #8) ; la portée equipe n'a pas de dimension row-level native unique
→ délibérément non inventée (#6). Validé statiquement en-repo (12 tests verts +
schéma conforme + round-trip fidèle au contrat + gate CI).