Issues remontees par la seconde passe de review de la PR #9 :
- Regression `GET /api/permissions` 403 silencieux sur les drawers RBAC
(UserRbacDrawer, RoleDrawer) apres le fix precedent qui imposait
`core.permissions.view`. Les users porteurs de `core.users.manage` /
`core.roles.manage` ne voyaient plus le catalogue pour hydrater leurs
checkboxes. Elargit la security expression sur Permission en OR avec
ces deux codes : les gestionnaires ont par nature besoin du catalogue
(codes/libelles seuls, pas de secret expose).
- Race condition dans UserRbacProcessor : `restoreAbsentCollections()`
lisait le snapshot Doctrine hors transaction, puis `wrapInTransaction()`
flushait plus tard. Fenetre courte mais reelle ou une modification
concurrente aurait pu etre annulee par une restauration depuis un
snapshot stale. Deplace l'appel a l'interieur de la transaction.
- Stale-data sur les pages admin users / roles / sites : meme pattern
try/finally sans catch que sur audit-log (deja corrige). Aligne les
trois pages avec un catch qui reset la liste locale.
- Tests manquants : garde de non-regression sur PATCH /rbac sans `sites`
(assure que la collection elle-meme est preservee, pas seulement le
currentSite). Couverture positive sur GET /api/permissions pour les
trois branches OR de la security expression (permissions.view,
users.manage, roles.manage) via des users non-admin.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Le drawer RBAC de /admin/users initialisait l'etat des sites a partir du payload
/api/users (groupe user:list) qui n'expose pas la collection sites. Consequence :
la section "Sites autorises" affichait toujours 0 case cochee, et la sauvegarde
ecrasait silencieusement les sites existants en BDD.
- Ajout d'une operation GET /users/{id}/rbac (groupe user:rbac:read) dediee au
chargement du detail pour l'edition : payload list reste leger, detail riche
sur une URI symetrique au PATCH existant.
- Drawer charge desormais GET /users/{id}/rbac pour initialiser sites, roles
et directPermissions ; UserListItem ne contient plus sites (inutilise).
- Colonne "Sites" retiree de la table /admin/users : l'info est consultee via
le drawer, pas la liste (evite aussi la fuite cross-site pour les users avec
core.users.view mais sans sites.bypass_scope).
- Garde anti-ecrasement dans UserRbacProcessor : respect de la semantique
merge-patch+json (cle absente = preservee, cle = [] = vidage explicite).
Restaure les collections ManyToMany absentes du payload a partir du snapshot
Doctrine. Couvre roles, directPermissions et sites.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>