User: «Enlève également le workflow d'un test, quand on saisit des
informations côtés redteam cela signifie qu'il a été exécuté et donc
en attente d'une review blueteam.»
Backend (update_mission_test_fields)
- At the end of every PUT, inspect the touched-field set:
- any red write on state in {pending, skipped, blocked} → state=executed
+ auto-stamp executed_at=now() if absent
- any blue write on state=executed → state=reviewed_by_blue
- /transition endpoint kept for back-fill/admin use, not called from UI.
Frontend MissionTestPage
- Removed the transition-buttons header block and the `transition`
mutation. State pill stays as a passive indicator.
- New labels: "Not started" / "Awaiting review" / "Reviewed" describe
the implicit lifecycle, no longer exposing the state-machine concept.
E2E
- The SPA test that clicked `transition-executed` now verifies the
implicit promotion: typing red fields and saving flips the pill from
"Not started" → "Awaiting review", no button click required.
Spec
- §4 reword: "Cycle de vie implicite, piloté par les écritures" replaces
the old "Workflow par test instance" bullet.
Tests
- 3 new pytest: red_command-alone implicit execute + auto-stamp,
blue write promotes executed→reviewed, blue write on pending no-op.
- 142 pytest + 49 Playwright green.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
19 KiB
type, date, revised, tags, status, project
| type | date | revised | tags | status | project | ||
|---|---|---|---|---|---|---|---|
| spec | 2026-05-08 | 2026-05-15 |
|
ready | Metamorph |
2026-05-15 amendment — added 5 blue-side review fields to the M7 scope (cf. §4 in-scope bullet on blue saisie, §F6, §8 model) and reworked the per-test UX to a full-bleed tabular view with inline edit. All other commitments stand. Detailed delta at the bottom of §4.
Metamorph — Spec
Spec finalisée après tour de questions du 2026-05-08. §12 et §13 vides : prête pour l'exécution. Le tracking quotidien bascule sur
Templates/Project.md.
1. Pitch (3 lignes max)
Plateforme web collaborative purple team : la red team saisit les tests réalisés (procédure, commande, horodatage), la blue team annote en parallèle ses preuves de détection (alertes, logs, fichiers). À la fin de la mission, Metamorph génère un slide reveal.js synthétisant les tests par catégorie MITRE ATT&CK et leur statut de détection. Remplace l'aller-retour Excel actuel par une UI partagée temps réel, multi-rôles, avec lien d'invitation et permissions cloisonnées.
2. Problème
- Le workflow actuel (Excel → mail → Excel) est fastidieux, non versionné, sans contrôle d'accès, sans cohérence d'horodatage.
- L'horodatage précis et la séparation temporelle entre tests sont critiques pour que la blue team corrèle correctement ses logs.
- Aucune traçabilité des contributions red vs blue, aucune garantie d'intégrité (red peut écraser un commentaire blue).
- Les purple sont récurrents : il faut pouvoir réutiliser des batteries de tests (templates) sans recopier.
3. Utilisateurs & cas d'usage
- Acteurs : Administrateurs, Red Teamers, Blue Teamers (rôles atomiques par groupe custom — voir §5 F1).
- Scénarios principaux :
- Admin crée des tests unitaires (templates) classifiés MITRE ATT&CK et les regroupe en scénarios réutilisables.
- Admin invite des utilisateurs via lien à usage unique, leur assigne un ou plusieurs groupes (perms atomiques).
- Red Teamer crée une mission, l'associe à un client/cible, sélectionne des scénarios, assigne les membres.
- Red Teamer exécute les tests manuellement (sur la machine cible ou via tunnel hors plateforme), saisit dans Metamorph la commande lancée, l'output et un timestamp auto-capturé (overridable).
- Blue Teamer consulte la mission (visibilité whitebox dès le début), annote chaque test : niveau de détection (taxonomie configurable), commentaires markdown, fichiers de preuves (logs, captures, EVTX).
- Red Teamer génère le slide de synthèse reveal.js et l'exporte en PDF.
- Utilisateur invité crée son compte via le lien d'invitation, change son mot de passe, accède aux missions où il est assigné.
- Red Teamer ne peut pas modifier les champs blue (perm
mission.write_blue_fieldsabsente) et inversement.
4. Périmètre
In scope (MVP v1)
- Auth locale JWT (access 1h / refresh 30j), Argon2id, min 8 chars.
- Lien d'invitation à usage unique (token URL, expiration 7j, hors mail).
- Bootstrap : token d'install affiché dans les logs au 1er démarrage pour créer le 1er admin via
/setup. - Groupes custom + permissions atomiques (familles : user/group/invitation, test_template, scenario_template, mission, mission.write_red_fields, mission.write_blue_fields). 3 groupes pré-seedés :
admin,redteam,blueteam. - CRUD tests unitaires (templates) avec classification MITRE Enterprise (Tactic + Technique + Sub-technique multi-tags).
- CRUD scénarios (groupements ordonnés de tests, drag-and-drop pour la position).
- CRUD missions (nom, client/cible, dates début/fin, membres red+blue assignés, description/ROE markdown, statut
draft → in_progress → completed → archived). - Snapshot des templates au moment de l'instanciation dans une mission (modifier un template ne touche pas les missions existantes).
- Saisie des résultats red (texte uniquement : commande, output, commentaires) avec horodatage auto au clic « Marquer exécuté » + override manuel.
- Saisie des preuves blue : multi-fichiers (PNG/JPG/PDF/TXT/LOG/JSON/CSV/EVTX/ZIP, max 25 Mo/fichier, SHA256 stocké) + commentaires markdown + niveau de détection (taxonomie custom paramétrable par admin, seed par défaut :
detected_blocked / detected_alert / logged_only / not_detected). - Saisie côté blue — fiche de review étendue (amendement 2026-05-15) : en plus du commentaire et du niveau de détection, la fiche de review d'un test capture les 5 champs additionnels que la blue maintenait en Excel —
log_source(texte court : Firewall / NDR / Proxy / AV / EDR / …),siem_logs(texte long, extrait brut de logs collectés au SIEM), sous-record cyber-incident(incident_at: timestamptz, incident_number: texte court, incident_recipient_email: email)qui matérialise l'alerte envoyée à l'équipe SOC. Tous ces champs sont blue-side et gated parmission.write_blue_fields. - Cycle de vie d'un test instance — implicite, piloté par les écritures (amendement 2026-05-15 bis) : aucun bouton de transition exposé en UI. La colonne
statedu DB reste (pending / executed / reviewed_by_blue / skipped / blocked) mais elle est auto-promue par le service à chaque PUT : (1) toute écriture côté red sur un testpending|skipped|blockedfait passer àexecutedet auto-stampexecuted_at = now()si absent ; (2) toute écriture côté blue sur un testexecutedfait passer àreviewed_by_blue. Une écriture blue sur un testpendingn'auto-promote pas (seule la red implique l'exécution). L'endpoint/transitionest conservé pour back-fill admin mais n'est plus appelé par l'UI. - Visibilité mission : whitebox totale pour la blue team dès la création (pas de masquage des procédures).
- Édition concurrente : last-write-wins + indicateur « modifié par X il y a Ns » via polling léger. Conflits red/blue impossibles par construction (champs disjoints).
- Notifications in-app uniquement (badge + liste), pas de SMTP.
- Génération slide reveal.js standalone (un fichier HTML autoportant) basé sur
tasks/design.md, avec export PDF côté client (bouton intégré). Catégorisation par défaut MITRE Tactic, regroupement custom optionnel par mission. - i18n FR + EN avec switch utilisateur.
- Soft delete partout + bouton « purge définitive » admin.
- Export d'une mission : JSON complet (API + UI) et CSV des résultats agrégés.
- Logs JSON structurés sur stdout, niveau configurable via
LOG_LEVEL. - Single-tenant + isolation stricte par mission : un utilisateur non-admin ne liste que les missions où il est membre.
Out of scope v1 — explicitement exclu
- Tunnel C2/ligolo (binaires, orchestration, exécution distante).
- Intégration Keycloak / OIDC.
- Audit log immuable et versioning des contenus.
- 2FA (TOTP/WebAuthn).
- SMTP / envoi de mail (notifications, invitations).
- Antivirus / scan ClamAV des uploads.
- Multi-tenancy / workspaces.
- Notifications mail.
- Logos / branding personnalisable.
Nice-to-have — backlog v2+
- Bascule auth vers Keycloak (OIDC, SSO).
- API d'ingestion pour qu'un C2 externe pousse les résultats automatiquement (hooks d'intégration).
- Audit log détaillé + versioning par champ critique.
- 2FA TOTP self-service.
- Notifications mail optionnelles.
- Intégration des binaires tunnel fournis par l'utilisateur pour l'exécution automatisée.
- Métriques Prometheus.
5. Exigences fonctionnelles
- F1 — Gestion users/groupes/invitations par admin avec permissions atomiques (familles listées en §4).
- F2 — CRUD tests unitaires templates avec MITRE ATT&CK (Tactic+Technique+Sub-technique multi), procédure markdown/code, prérequis, résultat attendu red, détection attendue blue, niveau OPSEC (low/med/high), tags libres, IOCs attendus. Représentation UI du picker MITRE : matrice flat fidèle à
attack.mitre.org/#—- Full-bleed : le picker s'étend sur toute la largeur du viewport (s'échappe du
max-w-pageglobal du layout) pour exposer un maximum de cellules sans scroll. - 15 colonnes equal-width via
grid-template-columns: repeat(N, minmax(7rem, 1fr)); scroll horizontal seulement en dernier recours sur viewport étroit (<≈1680px). - Wrap word-only :
overflow-wrap: normal+hyphens: none— les noms cassent uniquement sur les espaces, jamais au milieu d'un mot. - Headers = nom de la tactic seul + compteur de techniques en 10px ; l'
external_idTA00xxn'apparaît qu'au hover (title) et dans les chips de sélection. - Cellules = nom de la technique seul (idem pour
T1xxxau hover) ; chevron▸ N / ▾ Nqui déplie inline les sub-techniques dans la colonne. - Police sans-serif uniforme
text-xs(12px) pour cells + headers,10pxpour les sub-counts. - Click sur une cellule = (dé)sélection ; selection multi-niveaux (tactic / technique / sub-technique) cumulative ; chips de sélection en haut avec
external_id · namecliquables pour retirer.
- Full-bleed : le picker s'étend sur toute la largeur du viewport (s'échappe du
- F3 — CRUD scénarios = liste ordonnée (drag-and-drop) de tests unitaires.
- F4 — CRUD missions (métadonnées §4) composées d'un ou plusieurs scénarios, snapshot des templates à l'instanciation.
- F5 — Saisie côté red : commande lancée, output texte, commentaires markdown, statut, timestamp auto+override.
- F6 — Saisie côté blue : niveau de détection (enum custom plateforme), commentaires markdown, multi-fichiers (whitelist), source de log (texte court, max 120 caractères, free-form en v1 — promu en taxonomie M8+), extrait SIEM (texte long, max 200_000 caractères côté API), sous-record cyber-incident dont les 3 champs sont indépendants et tous optionnels :
incident_at(timestamptz, exige un offset explicite —Zou+HH:MM; les naïves sont rejetées en 400),incident_number(texte court, max 120),incident_recipient_email(texte avec validation RFC-shape permissive — autorise.local/.corp/.testpour les domaines internes). UI: vue tabulaire pleine largeur d'écran (échappe lemax-w-pagedu layout) à raison d'un tableau par scénario, une ligne par test. Colonnes :Test | Procédure | Exécution | Source de log | Commentaires | Logs SIEM | Cyber Incident. Ledetection_levelest rendu dans la cellule Commentaires sous forme de pill colorée au-dessus du commentaire (pas de 8ᵉ colonne). Édition inline : double-clic sur une ligne → un seul row passe en édition à la fois (les autres restent en lecture, le double-clic d'une autre ligne propose de save/discard la précédente) ; les cellules deviennent des inputs gated par les perms red/blue de l'utilisateur ; Esc annule (revert vers le snapshot serveur), Save commit, clic en dehors prompt si dirty. La page détail d'un test (/missions/{id}/tests/{test_id}) reste accessible pour l'upload de preuves (dropzone + table). - F7 — Génération slide reveal.js standalone + export PDF client, groupé par MITRE Tactic (custom optionnel).
- F8 — Notifications in-app (badge + flux) à chaque transition de statut d'un test concernant l'utilisateur.
- F9 — Export mission : JSON complet (API + UI), CSV agrégé.
- F10 — Soft delete + purge admin.
- F11 — Switch i18n FR/EN par utilisateur (préférence persistée).
- F12 — Sync MITRE ATT&CK Enterprise : dataset STIX embarqué (seed) + job admin manuel pour re-puller depuis github.com/mitre/cti. Le picker (cf. F2) se base sur un endpoint
GET /mitre/matrixqui retourne la grille complète (tactics → techniques → sub-techniques) en un seul appel.
6. Exigences non fonctionnelles
- NF-perf : UI fluide, pagination côté API au-delà de 50 éléments par liste, lazy-loading des fichiers de preuves.
- NF-platform : Debian x64 dernière stable, déploiement docker-compose (api Flask + Postgres + front nginx statique).
- NF-network : connectivité requise vers la DB Postgres (réseau interne compose). TLS terminé par un reverse proxy externe (à l'opérateur de la prod). Pas de connectivité sortante requise sauf sync MITRE manuelle.
- NF-state : PostgreSQL pour toutes les données structurées (volume Docker
metamorph_db). Fichiers de preuves stockés sous/data/evidence/<mission_id>/<test_id>/<sha256>(volume Dockermetamorph_evidence). Rétention indéfinie tant que non purgée. - NF-observability : logs JSON sur stdout (champs : ts, level, msg, request_id, user_id, action),
LOG_LEVELenv. Pas de métriques Prometheus en v1. - NF-security : Argon2id, JWT signés HS256 (clé via env
JWT_SECRET), CSRF non requis (Bearer token), CORS strict (origin du front uniquement), rate-limit basique sur/auth/*(10 req/min/IP). Permissions vérifiées côté serveur sur chaque endpoint, pas seulement côté UI. - NF-i18n : tous les libellés UI passent par un fichier de traduction. Données MITRE conservées en EN (officielles).
7. Contraintes techniques
- Backend : Python 3.12+, Flask, SQLAlchemy + Alembic (migrations), psycopg2/psycopg3, pyjwt, argon2-cffi, marshmallow ou pydantic v2 pour la validation.
- Frontend : React 18 + Vite + TypeScript + TailwindCSS + TanStack Query + react-router. Tokens design (couleurs, typo, espacements de
tasks/design.md) traduits entailwind.config.ts+ composants RTOps réutilisables. - Slide : reveal.js (CDN récupéré et servi en statique par le front), génération côté client à partir des données de l'API.
- DB : PostgreSQL 16+.
- Build : Linux. Livraison docker-compose (api, db, front-static-nginx). Dockerfile multi-stage par service. Makefile pour
dev,build,up,migrate,seed-mitre. - Dépendances JS : limitées au strict nécessaire ; chaque lib pinned. Bundle Vite, pas de CDN runtime.
- i18n :
react-i18nextcôté front,flask-babelcôté back pour les messages d'erreur API. - Logs :
python-json-loggerou équivalent.
8. Entrées / sorties / données
- Inputs :
- UI : saisie red (texte), saisie blue (texte + uploads multipart), uploads de fichiers (validation MIME + extension).
- Seed : dataset STIX MITRE ATT&CK Enterprise au premier
up(ou commandeflask metamorph seed-mitre).
- Outputs :
- Slide reveal.js HTML standalone (un fichier
.htmlautoportant, généré côté serveur ou côté client à partir des données API). - Export JSON mission complet (sans binaires de preuves).
- Export CSV des résultats agrégés (test, mission, statut, niveau détection, timestamp).
- Slide reveal.js HTML standalone (un fichier
- Modèle de données (entités principales — détail dans
tasks/todo.md) :users,groups,permissions,user_groups,group_permissions,invitationsmitre_tactics,mitre_techniques,mitre_subtechniquestest_templates,scenario_templates,scenario_template_tests(jointure ordonnée)missions,mission_members,mission_scenarios(snapshot),mission_tests(snapshot + state d'exécution + annotations redred_command/red_output/red_comment_md+ annotations blueblue_comment_md/detection_level_id/blue_log_source/blue_siem_logs/blue_incident_at/blue_incident_number/blue_incident_recipient_email),mission_categories(custom)evidence_files(FKmission_test_id, sha256, mime, size, path)notifications(in-app)detection_levels(taxonomie custom, seedée avec 4 niveaux par défaut)settings(clés plateforme, ex:mitre_last_sync)
9. Interfaces
- UI Web (seule interface utilisateur). Design :
tasks/design.mdstrictement (palette, typo JetBrains Mono / IBM Plex Sans, cards bordées par accent, comment-style headings// Section). - API REST JSON consommée par le front (préfixe
/api/v1). Auth Bearer JWT. Endpoints :/auth/*,/users,/groups,/invitations,/test-templates,/scenario-templates,/missions,/missions/:id/tests/:test_id,/missions/:id/tests/:test_id/evidence,/missions/:id/export.json,/missions/:id/export.csv,/missions/:id/slide.html,/mitre/sync,/notifications,/detection-levels,/settings. Schéma OpenAPI généré (flask-smorest ou apispec). - CLI Flask (admin opérations) :
flask metamorph create-admin(fallback),flask metamorph seed-mitre,flask metamorph print-install-token,flask metamorph purge-soft-deleted.
10. Critères de succès / Definition of Done
- Premier boot : token d'install affiché dans les logs, accès
/setuppermet de créer le 1er admin. - Admin crée un groupe custom et lui attribue des permissions atomiques (write_red_fields uniquement, par exemple).
- Admin envoie un lien d'invitation, l'utilisateur s'enregistre avec succès et hérite des bons groupes.
- Admin importe la matrice MITRE et crée un test unitaire avec Tactic+Technique+Sub-technique. (≥ 14 tactics Enterprise — la v19 du pin actuel en ship 15.)
- Admin compose un scénario de 3 tests ordonnés via drag-and-drop.
- Red Teamer crée une mission avec scénario, assigne 1 red + 1 blue.
- Red Teamer marque un test « exécuté », saisit commande+output, timestamp auto capturé.
- Blue Teamer voit la notification, annote avec niveau de détection + 2 fichiers de preuves (PDF + .evtx, < 25 Mo).
- Red Teamer ne peut pas (HTTP 403) écrire dans les champs blue ; idem inverse.
- Red Teamer génère le slide reveal.js, vérifie le rendu (catégorisation MITRE, accents couleur design.md), exporte en PDF côté navigateur.
- Admin exporte la mission en JSON et CSV.
- Admin soft-delete un test ; admin purge définitivement.
- Switch i18n FR ↔ EN persiste entre sessions.
docker compose updepuis zéro produit un déploiement fonctionnel sur Debian x64.- Logs API en JSON sur stdout, lisibles avec
journalctl/docker logs.
11. Risques & inconnues
- Techniques
- Génération slide reveal.js « standalone » avec données dynamiques : à valider qu'on inline correctement les données et ressources sans dépendre du back une fois exporté.
- Performances upload preuves multi-fichiers (25 Mo × N) : streaming côté Flask + limite globale par requête à fixer.
- Snapshot vs référence : bien isoler les tables
mission_testsdestest_templatesà l'instanciation pour ne pas drift.
- OPSEC : faible. La plateforme est utilisée en interne avec consentement (purple team avec blue informée).
- Inconnues levées : tunnel/C2 reporté en v2, cloisonnement multi-tenant non requis, audit log non requis pour MVP.
12. Hypothèses à valider
(vide — toutes les zones de flou ont été levées par le tour de questions du 2026-05-08)
13. Questions ouvertes pour Claude
(vide — prêt à passer en exécution)
Liens
- Project tracking : Projects/Metamorph
- Design system :
tasks/design.md - Plan d'exécution :
tasks/todo.md(à créer) - Wiki connexes :
- Troubleshooting :