Commit Graph

19 Commits

Author SHA1 Message Date
Matthieu
6df4316950 test(core) : RBAC #345 - functional coverage voter + last admin guard 2026-04-15 16:38:15 +02:00
Matthieu
d1e4402368 feat(core) : RBAC #345 - expose effectivePermissions via /api/me
- Ajoute #[Groups(['me:read'])] sur getEffectivePermissions() dans User.php
- Fixe la serialisation de isAdmin : le prefixe "is" etait strip par Symfony,
  expose desormais via le getter avec #[SerializedName('isAdmin')] + groups lecture,
  la propriete conserve uniquement le groupe d'ecriture user:rbac:write
- Cree MeApiTest avec 4 tests fonctionnels (isAdmin admin, permissions vides user,
  401 sans auth, effectivePermissions avec role portant une permission)
2026-04-15 16:10:11 +02:00
Matthieu
80b63cd7d7 feat(core) : RBAC #345 - UserRbacProcessor last admin guard 2026-04-15 16:00:34 +02:00
Matthieu
ba5eb804f2 feat(core) : RBAC #345 - UserProcessor DELETE guard
Introduit AdminHeadcountGuardInterface pour permettre le mock en tests
unitaires, puis cree UserProcessor qui protege DELETE /api/users/{id}
contre la suppression du dernier administrateur via la garde domaine.
2026-04-15 15:57:19 +02:00
Matthieu
ab2f11d40d feat(core) : RBAC #345 - PermissionVoter symfony 2026-04-15 15:51:23 +02:00
Matthieu
4325b1d8a0 feat(core) : RBAC #345 - AdminHeadcountGuard domain service 2026-04-15 15:45:55 +02:00
Matthieu
0ccbc70f27 fix(core) : RBAC #344 - ferme leak user list + test cascade delete role 2026-04-15 14:53:49 +02:00
Matthieu
534bdbccdd refactor(core) : RBAC #344 - polish review - narrow rbac read group + fail-fast processors 2026-04-15 14:28:02 +02:00
Matthieu
3c7dc88fe7 feat(core) : RBAC #344 - UserRbacProcessor + endpoint /users/{id}/rbac
Ajoute une operation Patch dediee `PATCH /api/users/{id}/rbac` (nom
`user_rbac_patch`) qui accepte exclusivement les champs RBAC isAdmin,
roles et directPermissions via le groupe user:rbac:write. L'endpoint est
separe volontairement du Patch profil existant pour isoler la modification
des droits de celle des donnees profil (decision 0fc4e16).

UserRbacProcessor delegue au PersistProcessor Doctrine decore et applique
une garde auto-suicide : un admin ne peut pas retirer ses propres droits
administrateur (compare l'etat entrant a l'etat UnitOfWork). La garde
'dernier admin' globale est reportee au ticket #345.

La propriete Doctrine $roles est renommee $rbacRoles pour eviter la
collision avec UserInterface::getRoles() (qui renvoie list<string>) lors
de la normalization API Platform. La cle JSON reste `roles` grace a
SerializedName, le contrat API est inchange.

Tests : 6 unitaires (UserRbacProcessorTest) + 8 fonctionnels
(UserRbacApiTest) couvrant promotion admin, remplacement des collections
roles/directPermissions, 401/403, filtrage du groupe denormalization
(`username` ignore), preservation de isAdmin sur le Patch profil, et
garde auto-suicide.
2026-04-15 14:17:18 +02:00
Matthieu
168a47f2b8 refactor(test) : RBAC #344 - AbstractApiTestCase pour mutualiser auth JWT
Extrait l'helper authenticatedClient(), $alwaysBootKernel et getEm() dans
une classe de base commune aux tests fonctionnels API Platform du module
Core. Supprime la duplication entre PermissionApiTest et RoleApiTest
(flaggee en code review de la Task 2). Prepare le terrain pour le nouveau
UserRbacApiTest introduit avec la Task 4.
2026-04-15 12:14:20 +02:00
Matthieu
87aa1d0b04 test(core) : RBAC #344 - renforce docblock setCode + assertion message exception 2026-04-15 12:05:26 +02:00
Matthieu
d527fbe2d1 feat(core) : RBAC #344 - RoleProcessor + gardes systeme et code immuable 2026-04-15 11:58:37 +02:00
Matthieu
efc12c8bdb fix(test) : RBAC #344 - role test cleanup + SystemRoles constant + assertion seuil 2026-04-15 11:53:01 +02:00
Matthieu
7be0260b29 feat(core) : RBAC #344 - API Platform Role CRUD nominal + validators 2026-04-15 11:41:21 +02:00
Matthieu
f79f061131 fix(test) : RBAC #344 - corrige EM stale et ajoute cas orphan=true 2026-04-15 11:15:41 +02:00
Matthieu
fdb7aded82 feat(core) : RBAC #344 - API Platform Permission en lecture seule
- Expose l'entite Permission via ApiResource (GetCollection + Get uniquement)
- Serialisation limitee au groupe permission:read (id, code, label, module, orphan)
- Securite temporaire is_granted('ROLE_ADMIN'), a remplacer par
  is_granted('core.permissions.view') au ticket #345
- Filtres : SearchFilter exact sur module, BooleanFilter sur orphan
- Configure api_platform.mapping.paths pour que le compile pass AP decouvre
  les ApiResource/ApiFilter declares dans src/Module/Core/Domain/Entity
- Ajoute symfony/browser-kit et symfony/http-client en dev pour les tests
  fonctionnels API Platform, plus KERNEL_CLASS dans phpunit.dist.xml
- Tests fonctionnels PermissionApiTest : collection, get item, filtres
  module et orphan, 405 sur POST, 401 non authentifie, 403 non-admin
2026-04-15 11:03:22 +02:00
Matthieu
7aa32b1972 feat(core) : RBAC Task 3 - mutation User (isAdmin + roles RBAC + permissions directes)
- Suppression de la colonne JSON roles (persiste jusqu'a la migration Task 5)
- Ajout is_admin bool (seul levier de bypass RBAC via getRoles())
- Ajout ManyToMany User-Role (EAGER, table user_role)
- Ajout ManyToMany User-Permission directes (EAGER, table user_permission)
- getEffectivePermissions() : union dedupliquee triee, utilisee par le
  futur PermissionVoter (#345)
- getRbacRoles() pour ne pas shadow getRoles() de UserInterface Symfony
- Tests unitaires couvrant derivation getRoles, union, deduplication, tri

Ticket #343 - 3/7 : migration du User vers le modele RBAC relationnel.
Fetch EAGER documente : evite le lazy-load au refresh JWT.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-14 16:48:49 +02:00
Matthieu
0fc0b57e37 refactor(core) : RBAC Task 1 - polish apres revue qualite
- Permission : guards constructeur (code/label/module non vides, code avec point)
- Permission::revive() reutilise updateMetadata() pour eviter la duplication
- Suppression de SystemRolesTest (tautologique, ne capture aucun comportement)
- Role::permissions : commentaire explicite sur la raison du fetch EAGER
- Alignement des types de retour sur static (style User.php)
- Nouveau test Role::addPermission avec permissions distinctes

Ticket #343 - Task 1 polish (revue qualite).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-14 16:37:53 +02:00
Matthieu
f0ea9201f5 feat(core) : RBAC Task 1 - entites Permission et Role + domaine securite
- Entite Permission avec methodes markOrphan/revive/updateMetadata
- Entite Role avec addPermission/removePermission/ensureDeletable
- Constantes SystemRoles (codes admin/user partages)
- Exception SystemRoleDeletionException pour la garde de suppression
- Tests unitaires couvrant le comportement domaine (pas de BDD)

Ticket #343 - 1/7 : fondations RBAC (domaine pur, sans persistence).
Les entites ne portent pas encore repositoryClass (ajoute en Task 2).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-14 16:30:15 +02:00