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>
93 lines
3.3 KiB
JSON
93 lines
3.3 KiB
JSON
{
|
|
"$schema": "http://json-schema.org/draft-07/schema#",
|
|
"$id": "https://oto-enterprise-os-dtp/rbac/roleprofile.schema.json",
|
|
"title": "Bundle Role Profile généré depuis rbac_50_roles.json",
|
|
"description": "Contrat de sortie de roleprofile_gen.py. Validé par le validateur maison Publiciste (zéro pip) dans le job CI rbac-roleprofile-tests. Un Role Profile ERPNext v15 natif par portail distinct du contrat ; chaque profil bundle les rôles (Has Role) de son portail. Couverture bijective des 50 rôles.",
|
|
"type": "object",
|
|
"additionalProperties": false,
|
|
"required": ["manifest", "role_profile"],
|
|
"properties": {
|
|
"manifest": {
|
|
"type": "object",
|
|
"additionalProperties": false,
|
|
"required": [
|
|
"generated_from",
|
|
"source_version",
|
|
"cible_rbac_roles",
|
|
"counts",
|
|
"profiles"
|
|
],
|
|
"properties": {
|
|
"generated_from": { "type": "string", "const": "rbac_50_roles.json" },
|
|
"source_version": { "type": "string", "pattern": "^[0-9]+\\.[0-9]+\\.[0-9]+$" },
|
|
"cible_rbac_roles": { "type": "integer", "const": 50 },
|
|
"counts": {
|
|
"type": "object",
|
|
"additionalProperties": false,
|
|
"required": [
|
|
"role_profiles",
|
|
"portails_metier",
|
|
"portails_techniques",
|
|
"roles_couverts"
|
|
],
|
|
"properties": {
|
|
"role_profiles": { "type": "integer", "minimum": 1 },
|
|
"portails_metier": { "type": "integer", "minimum": 0 },
|
|
"portails_techniques": { "type": "integer", "minimum": 0 },
|
|
"roles_couverts": { "type": "integer", "minimum": 50, "maximum": 50 }
|
|
}
|
|
},
|
|
"profiles": {
|
|
"type": "array",
|
|
"minItems": 1,
|
|
"items": { "$ref": "#/definitions/profile_meta" }
|
|
}
|
|
}
|
|
},
|
|
"role_profile": {
|
|
"type": "array",
|
|
"minItems": 1,
|
|
"items": { "$ref": "#/definitions/role_profile_fixture" }
|
|
}
|
|
},
|
|
"definitions": {
|
|
"profile_meta": {
|
|
"type": "object",
|
|
"additionalProperties": false,
|
|
"required": ["portail", "role_profile", "metier", "nb_roles"],
|
|
"properties": {
|
|
"portail": { "type": "string", "minLength": 1 },
|
|
"role_profile": { "type": "string", "pattern": "^OTO Portail " },
|
|
"metier": { "type": "boolean" },
|
|
"nb_roles": { "type": "integer", "minimum": 1 }
|
|
}
|
|
},
|
|
"role_profile_fixture": {
|
|
"type": "object",
|
|
"additionalProperties": false,
|
|
"required": ["doctype", "name", "role_profile", "roles"],
|
|
"properties": {
|
|
"doctype": { "type": "string", "const": "Role Profile" },
|
|
"name": { "type": "string", "pattern": "^OTO Portail " },
|
|
"role_profile": { "type": "string", "pattern": "^OTO Portail " },
|
|
"roles": {
|
|
"type": "array",
|
|
"minItems": 1,
|
|
"items": { "$ref": "#/definitions/has_role_row" }
|
|
}
|
|
}
|
|
},
|
|
"has_role_row": {
|
|
"type": "object",
|
|
"additionalProperties": false,
|
|
"required": ["doctype", "parentfield", "parenttype", "role"],
|
|
"properties": {
|
|
"doctype": { "type": "string", "const": "Has Role" },
|
|
"parentfield": { "type": "string", "const": "roles" },
|
|
"parenttype": { "type": "string", "const": "Role Profile" },
|
|
"role": { "type": "string", "pattern": "^OTO " }
|
|
}
|
|
}
|
|
}
|
|
}
|