fix(rbac) : add dedicated time-tracking.entries.manage permission
Pull Request — Quality gate / Frontend (build) (pull_request) Successful in 1m15s
Pull Request — Quality gate / Backend (PHP CS + PHPUnit) (pull_request) Successful in 2m32s

La revue de sécurité a relevé que les écritures de TimeEntry (Post/Patch/Delete)
étaient gardées par time-tracking.entries.view : une permission de lecture
accordait l'écriture (confusion lecture/écriture, least-privilege).

- Ajout de la permission time-tracking.entries.manage (catalogue cohérent avec
  les autres modules en view/manage).
- Écritures TimeEntry recâblées sur entries.manage ; self-service conservé
  (object.getUser() == user). Lecture inchangée (entries.view).
This commit is contained in:
Matthieu
2026-06-23 17:10:58 +02:00
parent 5e3607658a
commit 4a7fd46493
2 changed files with 4 additions and 6 deletions
@@ -48,9 +48,9 @@ use Symfony\Component\Serializer\Attribute\Groups;
security: "is_granted('time-tracking.entries.view')",
),
new Get(security: "is_granted('time-tracking.entries.view')"),
new Post(security: "is_granted('time-tracking.entries.view')"),
new Patch(security: "is_granted('ROLE_ADMIN') or (is_granted('time-tracking.entries.view') and object.getUser() == user)"),
new Delete(security: "is_granted('ROLE_ADMIN') or (is_granted('time-tracking.entries.view') and object.getUser() == user)"),
new Post(security: "is_granted('time-tracking.entries.manage')"),
new Patch(security: "is_granted('ROLE_ADMIN') or (is_granted('time-tracking.entries.manage') and object.getUser() == user)"),
new Delete(security: "is_granted('ROLE_ADMIN') or (is_granted('time-tracking.entries.manage') and object.getUser() == user)"),
],
normalizationContext: ['groups' => ['time_entry:read']],
denormalizationContext: ['groups' => ['time_entry:write']],
@@ -26,15 +26,13 @@ final class TimeTrackingModule implements ModuleInterface
/**
* Permissions RBAC fin du Module TimeTracking (2.1).
*
* Additif : alimente le catalogue RBAC. La sécurité des opérations API
* reste en ROLE_USER (non recâblée ici).
*
* @return list<array{code: string, label: string}>
*/
public static function permissions(): array
{
return [
['code' => 'time-tracking.entries.view', 'label' => 'Voir les saisies de temps'],
['code' => 'time-tracking.entries.manage', 'label' => 'Gérer les saisies de temps'],
['code' => 'time-tracking.entries.export', 'label' => 'Exporter les saisies de temps'],
];
}