Files
oto-enterprise-os-dtp/05_deliverables_mvp/rbac/userperm_gen
Claude Code DTP Worker b1b011ab81 [DTP-Worker] Sprint 2 · Générateur plan User Permission (RBAC row-level scope_donnees → Frappe)
Complète le pipeline RBAC (Role + Custom DocPerm déjà livrés) par la dimension
row-level. Mapping natif ERPNext v15 des 4 scope_donnees :
- entite → User Permission allow=Company (28 templates, user=sentinelle)
- own    → if_owner (déjà posé par fixtures_gen)
- groupe → aucune restriction (vue consolidée)
- equipe → pas de dimension native → signalé VPS (jamais mappé, #6)

Module userperm_gen/ : permlib/{frappe,builder}, CLI build/validate (refuse
d'écrire si invariant KO), userperm.schema.json (validateur maison, zéro pip),
12 tests unittest, README. Job CI rbac-userperm-tests ajouté au gate.
Docs SPEC §7 + fixtures_gen README cousues. Régression 72 tests verts, gate OK.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-30 03:33:44 +00:00
..

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/, non commité)

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_companyUser 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_teampas 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 user de chaque template est toujours la sentinelle (vérifié par test + CLI).
  • Aucune restriction fabriquée hors portée entite : own/groupe/equipe portent user_permission_template = null.
  • entite + périmètre consolidé (« Groupe ») → ValueError (garde-fou anti-contrat corrompu : une portée consolidée doit être groupe).
  • Fidélité au contrat : scope, entité et for_value re-vérifiés entrée par entrée contre rbac_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)

  1. Créer/confirmer les Companies listées dans MANIFEST.companies_a_confirmer (une par entité juridique · CLAUDE.md §Entités).
  2. Pour chaque rôle de mechanism = user_permission_company : cloner user_permission_template par utilisateur assigné au rôle, en remplaçant user par son e-mail réel, puis importer.
  3. Décider le mécanisme des rôles MANIFEST.roles_scope_equipe_a_confirmer (equipe) — options natives : champ custom « Équipe » + User Permission, ou hiérarchie Employee.reports_to. À valider avec Michel avant application.
  4. Les rôles own sont déjà couverts par if_owner (fixtures custom_docperm).
  5. Vérification HTTP post-déploiement (workflow #3) + audit QA 4Big.

Vérification en-repo

  • python3 -m unittest discover -s tests -v12/12 verts (schéma maison + oracle jsonschema si présent ; couverture bijective des 50 rôles, mécanisme = mapping natif du scope, template SSI entite, anti-invention utilisateur, déterminisme).
  • Job CI dédié rbac-userperm-tests ajouté 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).