Journal d'audit
Toute action mutante (POST / PUT / PATCH / DELETE) sur /admin/* est journalisée automatiquement par AdminAuditMiddleware, monté au niveau du groupe admin — aucune action n’a besoin d’être modifiée. Les GET (lectures : stats, santé, listes) ne sont pas tracés pour ne pas noyer le signal.
Le middleware enveloppe toute la pile : il observe le statut final, y compris les 403 d’auth refusée (un essai non autorisé est aussi un événement de sécurité conservé).
Stockage : base SQLite locale var/admin_audit.sqlite (hors MySQL), via AdminAuditLogger. Choix délibéré : zéro dépendance, fichier unique archivable, requêtable (contrairement à un log plat), et fonctionne même si MySQL est injoignable. Écriture best-effort : un échec d’audit n’interrompt jamais l’action admin (erreur envoyée dans error_log).
Schéma (table admin_audit, créée automatiquement au premier write) :
| Colonne | Type | Description |
|---|---|---|
id | INTEGER PK | auto-incrément |
created_at | TEXT | ISO 8601 |
method | TEXT | POST / PUT / PATCH / DELETE |
path | TEXT | chemin appelé (ex. /admin/media/{hex}/published) |
query | TEXT | query string (ou null) |
status | INTEGER | statut HTTP final (inclut les 403) |
ip | TEXT | REMOTE_ADDR (pas de X-Forwarded-For) |
token_fp | TEXT | empreinte du token (12 hex de SHA-256), jamais le token brut — null si absent |
user_agent | TEXT | en-tête User-Agent (ou null) |
Le token_fp permet de corréler les actions d’un même appelant sans stocker le secret. Quand des tokens par opérateur existeront, l’empreinte pointera vers un opérateur nommé.
Consulter le journal : via l’API, l’endpoint GET /admin/audit (filtres + pagination keyset). Ou en lecture directe SQLite (ex. les 20 dernières actions) :
sqlite3 var/admin_audit.sqlite \ "SELECT created_at, method, path, status, ip, token_fp FROM admin_audit ORDER BY id DESC LIMIT 20;"