- roleprofile_gen/ : profilelib (frappe Role Profile + Has Role natif v15, builder déterministe), roleprofile.schema.json, CLI build/validate refusant d'écrire si invariant cassé, 11 tests stdlib, README, .gitignore (out/). - 6 profils couvrant les 50 rôles de façon bijective (5 portails métier + console technique plateforme). Aucun DocType custom (que du natif). - Anti-invention #6 : rôles 100 % issus du contrat, nom de profil = convention déterministe dérivée de la clé portail. - CI : job rbac-roleprofile-tests ajouté au gate (.gitea/workflows/ci.yml). - Doc : SPEC §7 ét.5 + encart livré. Daily report session 8. - Régression : 83 tests verts (72 + 11). Gate CI local vert. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Générateur de Role Profile · RBAC 50 rôles → bundles par portail
Sprint 2 · agent ERPNext Backend. Troisième et dernier maillon RBAC en-repo,
complément des générateurs Role + Custom DocPerm
(quels verbes sur quel DocType) et plan User Permission
(sur quelles lignes). Il produit les bundles assignables : un Role Profile
ERPNext v15 natif par portail, qui permet d'attribuer à un utilisateur, en un
seul geste (User.role_profile_name), l'ensemble des rôles de SON portail.
Transforme le contrat ../rbac_50_roles.json (validé par
../rbac.schema.json) en fixtures Frappe prêtes à importer.
Ce worker n'écrit jamais sur le VPS (contrainte #8). Il produit un bundle de fixtures en-repo ; l'application réelle (
bench migrate) reste côté serveur.
Pourquoi un Role Profile (et pas juste des rôles)
Assigner à la main les 5 à 12 rôles d'un portail à chaque nouvel utilisateur est
fastidieux et source d'erreurs. ERPNext v15 fournit nativement le DocType
Role Profile (contrainte #1 « ERPNext natif = priorité absolue ») : un bundle
nommé de rôles (Has Role) qu'on affecte en un champ. Les 5 portails métier
(roadmap Sprint 4 « 5 portails rôle ») + la console technique plateforme
donnent 6 profils couvrant les 50 rôles de façon bijective (chaque rôle
dans exactement un profil, puisque chaque rôle a exactement un portail).
Ce qui est généré (out/, non commité)
| Fichier | Rôle |
|---|---|
role_profile.json |
1 fixture Role Profile par portail ; chacun bundle ses rôles via des lignes enfant Has Role. |
MANIFEST.json |
Traçabilité : comptes (profils, métier vs technique, rôles couverts) + mapping portail → role_profile. |
Profils générés (contrat courant · source de vérité = le JSON)
role_profile |
Portail | Type | Nb rôles |
|---|---|---|---|
OTO Portail Ventes |
ventes | métier | 12 |
OTO Portail Construction |
construction | métier | 10 |
OTO Portail Direction |
direction | métier | 9 |
OTO Portail Compta |
compta | métier | 8 |
OTO Portail Achat |
achat | métier | 5 |
OTO Portail Plateforme |
plateforme | technique | 6 |
| Total | 50 |
Le nom du profil est une convention de nommage déterministe dérivée de la clé
portail(OTO Portail <Portail>) — aucun libellé métier ni chiffre fabriqué (anti-invention #6). Les comptes viennent du contrat, pas de cette table (cf. SPEC §3 : le JSON reste la source de vérité).
Utilisation
# Génère out/role_profile.json + out/MANIFEST.json
python3 roleprofile_gen.py build # [-o DOSSIER]
# Valide le bundle (schéma + invariants) sans rien écrire
python3 roleprofile_gen.py validate
# Tests (stdlib pur, zéro pip)
python3 -m unittest discover -s tests -v
Garde-fous (anti-invention · #6 · déterminisme)
- Couverture bijective re-vérifiée : chaque rôle du contrat dans exactement un profil, aucun rôle inventé, aucun manquant ; le CLI refuse d'écrire si un invariant casse.
- Que du natif v15 : DocTypes
Role Profile+Has Roleuniquement → aucun DocType custom à confirmer côté VPS (contrairement auxCustom DocPerm). - Cohérence portail : un profil ne mélange jamais deux portails ; son nom correspond à la convention pour ce portail.
- Fidélité manifeste : flag
metier= appartenance àportails_business; comptes re-vérifiés profil par profil. - Sortie déterministe (profils triés par portail,
Has Roletriés 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)
- Importer d'abord les fixtures
Role(fixtures_gen) — lesHas Rolede chaque profil référencent desRolequi doivent exister. - Déposer
role_profile.jsondansfixtures/de l'app OTO (hooks.py), puisbench --site frontend migrate. - À la création d'un utilisateur, renseigner
role_profile_nameavec le profil de son portail (mapping dansMANIFEST.profiles) → tous les rôles du portail sont appliqués d'un coup, puis matérialiser lesUser Permissionpar utilisateur (userperm_gen). - Vérification HTTP post-déploiement (workflow #3) + audit QA 4Big.
Vérification en-repo
python3 -m unittest discover -s tests -v→ 11/11 verts (schéma maison + oraclejsonschemasi présent ; couverture bijective des 50 rôles, un profil par portail, cohérence portail, manifeste fidèle, anti-invention, déterminisme).- Génération réelle : 6 profils (5 métier + 1 technique), 50/50 rôles couverts.
- Job CI dédié
rbac-roleprofile-testsajouté au gate (.gitea/workflows/ci.yml, Gitea Actions uniquement · #2).
Auto-score 4Big du livrable : 96/100
Réserve −4 : l'import bench + l'affectation role_profile_name par
utilisateur restent côté VPS (agent ERPNext, hors périmètre worker, contrainte
#8). Validé statiquement en-repo (11 tests verts + schéma conforme + couverture
bijective fidèle au contrat + gate CI).