--- type: testing milestone: M6 date: "2026-05-13" project: Metamorph --- # Testing M6 — Missions & snapshot ## 1. Lancement de la stack ```bash make clean make up make migrate make seed-mitre # MITRE tags are snapshotted onto mission_tests; without them # the snapshot will simply have an empty mitre_tags array ``` > L'admin stable `admin@metamorph.local / AdminPass1234!` est restauré > automatiquement par le hook `afterAll` du spec e2e M6, mais la 1ʳᵉ fois, > bootstrappe-le via `/setup` (ou laisse les tests faire le travail). ## 2. Tests automatisés ```bash make test-api # 103 tests pytest dont 22 M6 (snapshot, membership, transitions, members CRUD, perm gating) make e2e # 43 tests Playwright dont 5 M6 (snapshot freezing, non-admin visibility, transitions, wizard, list filter) ``` Rapport HTML : `e2e/playwright-report/`. ## 3. Smoke navigateur ### Pré-requis - Stack `make up` + admin loggé. - MITRE seedé (`/mitre` montre 15 tactics). - Au moins **1 test_template** et **1 scenario_template** dans le catalogue M5 (pour avoir quelque chose à snapshotter). ### 3.1 Liste & création (`/missions`) 1. Cliquer **Missions** dans la nav (visible si tu as la perm `mission.read` ou tu es admin) → la liste s'affiche avec un message vide la 1ʳᵉ fois. 2. Cliquer **+ New mission** → page wizard `/missions/new`. 3. **Étape 1 — Metadata** : - `Name` (requis) → `purple-2026-Q2` - `Client / target` → `Acme Corp` - `Start date` / `End date` → si tu inverses, un message en rouge apparaît et **Next** est désactivé. - `ROE / Description` (markdown) → optionnel. 4. **Next** → **Étape 2 — Scenarios** : - Le catalogue M5 s'affiche en grille de boutons. Cliquer un scénario le sélectionne (bordure cyan). - Le sous-titre du Card affiche le total de tests qui seront snapshotés. 5. **Next** → **Étape 3 — Members** : - Le roster (issu de `/users/roster`) liste les utilisateurs actifs. - Pour chaque user, deux boutons **Red** / **Blue** togglent l'inclusion + le rôle. ✕ retire. - Si tu es un redteamer non-admin, tu es pré-sélectionné en `red` (auto-add côté backend si tu oublies). 6. **Create mission** → redirection vers `/missions/`. La nouvelle mission apparaît en haut de la liste après retour. ### 3.2 Filtres (`/missions`) - **Search** : full-text sur `name` / `description_md`. - **Client** : LIKE sur `client_target`. - **Status** : select draft / in_progress / completed / archived. - Les filtres sont combinés en AND (ex : `status=in_progress & client=acme`). ### 3.3 Page détail (`/missions/`) 1. En-tête : nom + status pill + boutons de transition. - **draft** → boutons `→ In Progress` et `→ Archived`. - **in_progress** → `→ Completed` et `→ Archived`. - **completed** → `→ Archived` uniquement. - **archived** → aucun bouton. 2. Cliquer un bouton → status update immédiat (cache invalidé, badge re-rendu). 3. **Delete** (en rose) → confirm prompt → soft-delete → redirige vers `/missions`. Réapparait via `?include_deleted=true` (admin only). 4. **Tabs** : - **tests** : tableau par scénario avec `# | Test | MITRE | OPSEC | State`. Les MITRE chips affichent l'external_id frozen. - **members** : pills Red/Blue avec email + display_name. - **synthesis** : placeholder « lands in M10 ». - **export** : placeholder « lands in M11 ». ## 4. Vérification du snapshot (DoD) 1. Crée une mission qui référence un scenario_template `sc1` contenant `test_template_t1`. 2. Aller dans `/admin/tests`, éditer `test_template_t1` : changer le nom et les tags MITRE. 3. Retour sur `/missions/` (rafraîchir si la cache TanStack tient encore) → la table montre **toujours** l'ancien nom et l'ancien tag MITRE. Le snapshot est gelé. ✅ ## 5. Vérification visibilité par membership 1. Login en admin, créer 2 missions : - `m-only-admin` sans aucun membre. - `m-shared` avec Alice (red) en membre. 2. Login en Alice. 3. `/missions` → seule `m-shared` apparaît dans la liste. `GET /api/v1/missions/` retourne **404** (pas 403 — pas de fuite d'existence). 4. Alice tente de PUT/transition/delete sur `m-only-admin` → 404 idem. ## 6. Vérification transitions | from | to | result | |-------------|---------------|--------| | draft | in_progress | 200 | | draft | archived | 200 | | draft | completed | **409 invalid_transition** | | in_progress | completed | 200 | | in_progress | archived | 200 | | completed | archived | 200 | | completed | in_progress | **409** | | archived | (anything) | **409** | | any | (same status) | 200 (no-op) | ```bash curl -X POST -H "Authorization: Bearer $T" -H 'Content-Type: application/json' \ -d '{"status":"completed"}' \ http://localhost:8080/api/v1/missions//transition ``` ## 7. Quick teardown ```bash make down # ou pour un reset complet : curl -X POST http://localhost:8080/api/v1/diag/reset # test-only, wipes everything ``` > Reminder: `make test-api` and `make e2e` **share the dev DB container** — > running them mid-session WILL wipe user data. The M6 spec's `afterAll` > restores the stable admin and re-seeds MITRE, but custom templates / missions > you've created by hand are lost. Cf. `tasks/lessons.md` (M5 lessons section).