Backend :
- AuditLogWriter::stripSensitive rendu reellement recursif (matche doc).
- Tests GET /api/permissions/{id} non-admin pour chaque branche OR (gap Codex).
- Gardes non-regression UserRbacProcessor : PATCH /rbac sans clef sites ne
doit ni auto-selectionner currentSite ni exiger sites.manage.
Frontend :
- useAuditLog : renomme export trompeur fetchLogs -> fetchLogsCached, le
nom reflete desormais le comportement (cache pollue sinon).
- RoleDrawer / UserRbacDrawer : catch explicite + message d'erreur +
bouton save disabled si le chargement des referentiels a echoue (evite
un ecrasement silencieux des droits).
- AuditTimeline / AuditLogDetail : `oui`/`non` passent par common.yes/no.
- AuditTimeline : Intl.RelativeTimeFormat et toLocaleString suivent la
locale i18n courante (plus de hardcode 'fr').
E2E :
- sidebar-visibility.spec : remplace waitForLoadState('networkidle')
fragile par attente semantique sur accountDashboardLink (stable en CI).
Tests : 237/237 green, eslint clean, php-cs-fixer clean.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
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>
- Permission entity : remplace le guard `ROLE_USER` par `core.permissions.view`
sur GetCollection/Get. Le catalogue complet des permissions RBAC etait
accessible a tout utilisateur authentifie. Ajoute la permission manquante
dans CoreModule::permissions() et inverse les tests standardUser*
(attendent maintenant un 403 pour un user sans la permission).
- UserRbacProcessor::restoreAbsentCollections() : force
PersistentCollection::initialize() avant de lire le snapshot. Pour une
association fetch=LAZY (ex: User::$sites), le snapshot est vide tant que
la collection n'est pas materialisee, ce qui faisait vider silencieusement
tous les sites d'un user sur un PATCH ne contenant pas la cle `sites`.
- admin/audit-log.vue : ajoute un catch sur loadEntries() qui reset
entries/totalItems pour ne pas afficher de donnees stale si le fetch echoue
(reseau coupe, 403 inopinee...). Le toast d'erreur reste gere par useApi.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>