70e022ccd6
- 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>
104 lines
5.2 KiB
Markdown
104 lines
5.2 KiB
Markdown
# 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`](../fixtures_gen/README.md)
|
||
(quels verbes sur quel DocType) et [plan `User Permission`](../userperm_gen/README.md)
|
||
(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`](../rbac_50_roles.json) (validé par
|
||
[`../rbac.schema.json`](../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
|
||
|
||
```bash
|
||
# 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 Role` uniquement → aucun
|
||
DocType custom à confirmer côté VPS (contrairement aux `Custom 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 Role` trié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)
|
||
|
||
1. Importer d'abord les fixtures `Role` ([`fixtures_gen`](../fixtures_gen/README.md))
|
||
— les `Has Role` de chaque profil référencent des `Role` qui doivent exister.
|
||
2. Déposer `role_profile.json` dans `fixtures/` de l'app OTO (`hooks.py`), puis
|
||
`bench --site frontend migrate`.
|
||
3. À la création d'un utilisateur, renseigner `role_profile_name` avec le profil
|
||
de son portail (mapping dans `MANIFEST.profiles`) → tous les rôles du portail
|
||
sont appliqués d'un coup, puis matérialiser les `User Permission` par
|
||
utilisateur ([`userperm_gen`](../userperm_gen/README.md)).
|
||
4. 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 +
|
||
oracle `jsonschema` si 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-tests` ajouté 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).
|