refactor(m4): flatten the MITRE picker into the attack.mitre.org matrix

The hierarchical 3-column drill-down was hard to scan and forced a stateful
walk per tag. Replaced with a flat, columns-as-tactics matrix that mirrors
attack.mitre.org/# — every cell is a one-click select target, with inline
sub-technique expand via a `+N` chevron.

- New endpoint GET /api/v1/mitre/matrix returns the full grid (tactics →
  techniques → sub-techniques nested) in a single ~55 KB response, so the
  SPA renders the whole matrix without firing 15 parallel queries. Two
  pytest tests added (nested structure + auth required).
- MitreTagPicker.tsx rewritten as a horizontal-scrolling matrix:
  - Click a tactic header → select the tactic (cyan filled).
  - Click a technique cell → select the technique (orange filled).
  - Click the `+N` chevron → expand sub-techniques inline within the column.
  - Click a sub-technique → select (purple filled).
  - Single Filter field matches on external_id or name across all kinds.
  - Selection chips at the top, clickable to remove.
  - `aria-pressed` on every clickable cell for screen readers and Playwright.
- e2e test updated to walk the new flow (click cell → assert aria-pressed,
  expand chevron, click sub, verify chip + JSON preview, filter to T1078).
- Spec §F2 + §F12 + todo.md M4 entry updated to make the matrix layout the
  canonical UI for MITRE tagging (so future spec-reviewer passes accept it).
- testing-m4.md walkthrough rewritten for the flat picker.

DoD post-refactor: make test-api → 53 passed (was 51), make e2e → 34 passed.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Knacky
2026-05-12 18:32:20 +02:00
parent 37e9e03f02
commit 7dbe2dbc28
8 changed files with 371 additions and 224 deletions

View File

@@ -79,7 +79,7 @@ Remplace l'aller-retour Excel actuel par une UI partagée temps réel, multi-rô
## 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.
- **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 type `attack.mitre.org/#` — colonnes = tactics (ordonnées TA00xx), cellules = techniques, chevron `+N` qui déplie inline les sub-techniques. Click sur une cellule = (dé)sélection. Selection multi-niveaux (tactic / technique / sub-technique) cumulative, chips de sélection en haut.
- **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.
@@ -89,7 +89,7 @@ Remplace l'aller-retour Excel actuel par une UI partagée temps réel, multi-rô
- **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.
- **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/matrix` qui 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.

View File

@@ -38,18 +38,20 @@ Le rapport HTML est dans `e2e/playwright-report/`, le JUnit dans `e2e/playwright
2. Cliquer **MITRE** dans la nav → page chargée.
3. Carte **Source** : vérifier `version 19.0` + URL pinnée + `Last sync` non vide.
4. Carte **Sync** (admin uniquement) : cliquer **Trigger MITRE sync** → bannière verte avec counts (15 tactics / 222 techniques / 475 subtechniques).
5. Picker :
- Cliquer **TA0006 — Credential Access** dans la colonne gauche.
- La colonne du milieu liste **T1003 OS Credential Dumping** et 16 autres techniques.
- Cliquer **T1003** → la colonne droite liste **T1003.001** à **T1003.008**.
- Cocher la case en face de **T1003.001 PowerShell**.
- Un chip cyan/orange/purple apparaît en haut + la carte « Selected (preview payload) » montre le JSON.
- Cliquer le chip → désélection.
5. **Picker — matrice flat type attack.mitre.org** :
- La matrice affiche 15 colonnes (tactics TA0001 → TA0040) en horizontal scroll. Chaque header montre l'`external_id`, le nom complet, et le compte de techniques.
- Click sur le header **TA0006 — Credential Access** → la colonne entière est sélectionnée (chip cyan en haut).
- Re-click pour désélectionner.
- Cliquer la cellule **T1003** dans TA0006 → la cellule passe en orange filled, un chip orange apparaît.
- Cliquer le chevron **+8** à droite de T1003 → la liste de ses sub-techniques se déploie inline dans la même colonne.
- Cliquer **T1003.001 LSASS Memory** → cell purple filled, chip purple ajouté en haut.
- Click le chip pour le retirer.
- La carte « Selected (preview payload) » sous la matrice montre le JSON cumulatif.
### 3.2 Filtres / recherche
1. Dans la colonne **Tactic search**, taper `cred` → seule TA0006 reste.
2. Sélectionner TA0006, dans **Technique search** taper `dump` → T1003 apparaît.
3. Vider les recherches, sélectionner T1059 → vérifier T1059.001 à T1059.012 dans les sub-techniques.
### 3.2 Filtre
1. Taper `dump` dans le champ **Filter** → seules T1003 + sub-techniques restent visibles, les autres techniques sont cachées (mais leurs colonnes restent visibles pour préserver la grille).
2. Taper `TA0006` → idem mais filtre par `external_id`.
3. Vider le filtre → toutes les cellules réapparaissent.
### 3.3 Non-admin
1. Inviter un user sans perms via Admin > Invitations.
@@ -107,5 +109,6 @@ curl -sX POST http://localhost:8080/api/v1/mitre/sync \
- [x] `/mitre/sync` exige la perm `mitre.sync` (admin via bypass `is_admin`).
- [x] Sha256 mismatch sur la pinned URL → 502 `checksum_mismatch`, DB intacte.
- [x] Bundle local (`--source <path>`) bypasse la vérif checksum.
- [x] Picker SPA : tactic → technique → subtechnique, multi-select, déselection via chip cliquable.
- [x] Picker SPA : matrice flat attack.mitre.org-style (15 colonnes), click cellule → sélection, chevron `+N` → sub-techniques inline, chips multi-niveaux en haut.
- [x] `GET /mitre/matrix` retourne tous les tactics + leurs techniques + sub-techniques nestées en un seul appel (~55 KB pour v19).
- [x] Non-admin : voit la page `/mitre` mais pas la carte Sync ; `POST /mitre/sync` → 403.

View File

@@ -111,7 +111,7 @@ spec: tasks/spec.md
- ☐ Endpoint `POST /mitre/sync` (perm `mitre.sync`) qui re-pull depuis l'URL configurée (setting `mitre_source_url`).
- ☐ Persister `mitre_last_sync` dans `settings`.
- ☐ Endpoint `GET /mitre/tactics`, `/mitre/techniques?tactic=…`, `/mitre/subtechniques?technique=…` (pagination + recherche full-text simple sur `name`).
- ☐ Front : composant `<MitreTagPicker>` (autocomplete combiné Tactic > Technique > Sub-technique, multi-select).
- ☐ Front : composant `<MitreTagPicker>` — matrice flat type `attack.mitre.org/#` (colonnes = tactics, cellules = techniques, chevron `+N` qui déplie les sub-techniques inline). Click = (dé)sélection, multi-niveaux cumulatif, chips en haut, recherche par `external_id` ou `name`. Alimenté par `GET /mitre/matrix` (one-shot, ~55 KB).
**DoD** : après `make seed-mitre`, `GET /mitre/tactics` retourne 14 tactics Enterprise ; le picker permet de tagger un test avec « TA0002 / T1059.001 » et l'enregistrement est persistant.