Aller au contenu

Auditor Workbench + MSP Cockpit

Auditor Workbench (/auditor)

POST /api/v1/auditor/bundle avec body {period_start, period_end}. Owner / admin / auditor uniquement. TOTP requis en production (purpose auditor_bundle) ; pas de TOTP en dev.

Contenu du bundle (ZIP) :

manifest.json métadonnées du bundle + liste des packs + liste des clés
verify.py vérificateur Ed25519 hors-ligne (basé sur pynacl)
signing_keys.json clés publiques + raisons de rotation sur la période
compliance_summary.md rapport d'audit en markdown
evidence_packs/<id>.tar.gz chaque pack de la période (uniquement depuis
des chemins de stockage en allowlist)

Garde anti path-traversal : evidence_packs.storage_uri DOIT commencer par l’un des chemins suivants :

  • /var/lib/monsys/ai-evidence-packs/
  • /var/lib/monsys/copilot-evidence-packs/
  • /var/lib/monsys/openai-evidence-packs/

Sinon le pack est exclu du bundle (une ligne archive_path:"" reste dans manifest.json pour la traçabilité).

L’URL de téléchargement est one-shot, expiration 24 h. Le claim atomique est dans l’UPDATE :

UPDATE auditor_bundle_tokens
SET downloaded_at = NOW(), downloaded_by = $3
WHERE token = $1 AND tenant_id = $2
AND downloaded_at IS NULL AND expires_at > NOW()
RETURNING file_path

Le MVCC Postgres + le row-lock garantissent que deux requêtes concurrentes ne reçoivent pas toutes les deux le RETURNING.

Vérification hors-ligne

Chaque destinataire exécute python3 verify.py (pynacl) à l’intérieur du bundle décompressé. Aucun réseau, aucun credential monsys nécessaire — vérifie la signature de chaque pack contre le signing_keys.json embarqué. Output :

pack 1234: OK
pack 1235: BAD SIGNATURE
=== 12 OK, 1 BAD ===

Exit code 0 = tout OK, 1 = au moins un pack échoue.

MSP Cockpit (/msp/cockpit)

GET /api/v1/msp/overview. Strictement isolé : role = msp_operator OU is_superadmin = true. Un user owner/admin classique reçoit 403 — cet endpoint parcourt chaque tenant de la plateforme.

Par tenant :

  • nom + plan
  • Trust Score actuel + Δ7j
  • nombre d’alertes critical+warning ouvertes
  • nombre de lignes d’evidence compliance en échec
  • dernière activité de login

Tri par défaut = urgency-composite :

urgency = open_alerts*5 + failing_controls
+ (-Δ7d if Δ7d < 0)
+ 0.5 * (60 - score) if score < 60

Le tri par colonne est disponible depuis le dashboard (urgency / nom / score).

Nouveaux rôles

La migration 064 étend le CHECK sur users.role avec :

RôleAccès
auditorread-only + génération/téléchargement de bundle (TOTP requis en production)
msp_operatorcross-tenant via /api/v1/msp/overview

Les rôles existants (analyst, admin, owner) restent inchangés.