From 4d9447082f082d3ecef74163091442e0cfd7f05d Mon Sep 17 00:00:00 2001 From: Knacky Date: Mon, 8 Jun 2026 19:23:02 +0200 Subject: [PATCH] =?UTF-8?q?docs:=20sprint=206=20amendment=20=E2=80=94=207-?= =?UTF-8?q?column=20schema=20in=20CHANGELOG=20+=20PR=20body?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Post-review user decision (2026-06-08) switched the export payload to a fixed 7-column FR handoff schema (Scénario / Test / Source de log / Commentaires SOC / Exécution / Logs remontés au SIEM / Cyber incident). Logged in CHANGELOG [Unreleased] Changed section with commit refs (SPEC fdab324, backend 7335b9f, e2e aeb4bdb) and updated PR #9 body counters: 255 pytest (was 253), 136 vitest unchanged, 223 e2e unchanged. --- CHANGELOG.md | 1 + tasks/pr-body-sprint-6.md | 36 ++++++++++++++++++++++++++++++++++++ 2 files changed, 37 insertions(+) create mode 100644 tasks/pr-body-sprint-6.md diff --git a/CHANGELOG.md b/CHANGELOG.md index 94d342c..6ec2c6c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -36,6 +36,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/) ### Changed - 2026-06-07 — SPEC.md § Export d'engagement added (between § Templates de simulations and § Stacks techniques). Committed as the **first** sprint commit (`7aaa5cc`), applying the fix-candidate from sprint 5's recurrent "SPEC.md uncommitted at sprint close" lesson. Four-sprint recurrence finally broken. - 2026-06-08 — Team `mimic` (persistent `.claude/teams/mimic/config.json`) instantiated with the full 7-agent project roster (backend-builder, frontend-builder, spec-reviewer, code-reviewer, design-reviewer, test-verifier, devil-advocate). Agents are spawned with an idle prompt at sprint start and woken via SendMessage per phase — flip vs the old "spawn-with-task-only" policy that hit the "team roster is flat" gotcha when respawning. Persistent across sprints from sprint 7+. +- 2026-06-08 (post-review, pre-merge) — **Export schema switched to a fixed 7-column handoff layout** uniform across MD/CSV/PDF. Columns (FR headers): `Scénario`, `Test`, `Source de log`, `Commentaires SOC`, `Exécution` (multi-line concat without labels — `executed_at` → `commands` → `execution_result`), `Logs remontés au SIEM`, `Cyber incident`. Removed from the export (intentional, handoff-focused): simulation status, MITRE techniques/tactics, prerequisites, id, created_at, updated_at. Markdown switched from narrative-per-simulation to a GFM table. PDF switched from sectioned HTML to a single ``. SPEC `fdab324`, backend refactor `7335b9f`, e2e adaptation `aeb4bdb`. Final counters: backend 255 pytest, frontend 136 vitest, e2e 223 Playwright. --- diff --git a/tasks/pr-body-sprint-6.md b/tasks/pr-body-sprint-6.md new file mode 100644 index 0000000..1479fb5 --- /dev/null +++ b/tasks/pr-body-sprint-6.md @@ -0,0 +1,36 @@ +## Summary +- **Engagement export** : `GET /api/engagements//export?format=md|csv|pdf` — clôt la boucle « remplace l'Excel partagé RT ↔ SOC » du SPEC. +- **3 formats livrés** : Markdown (table GFM 7 colonnes), CSV (7 colonnes machine-readable, défense formula-injection), PDF (table HTML→PDF via WeasyPrint). +- **Schéma fixe 7 colonnes FR** uniforme MD/CSV/PDF (décision post-review, pre-merge) : `Scénario`, `Test`, `Source de log`, `Commentaires SOC`, `Exécution` (multi-ligne sans labels — `executed_at` → `commands` → `execution_result`), `Logs remontés au SIEM`, `Cyber incident`. Champs retirés intentionnellement : status, MITRE techniques/tactics, prerequisites, id, created_at, updated_at. +- **UI** : split-button dropdown `[Export ▼]` sur `EngagementDetailPage`, 3 items. Les **deux moitiés ouvrent le menu** (différence sémantique vs sprint 5 où la gauche naviguait blank — il n'y a pas de format "défaut" évident). +- **RBAC SOC zero access** : admin + redteam exportent ; SOC ne voit pas le bouton (DOM-absent) et tous endpoints `/api/engagements//export*` → 403. +- **Security MEDIUM fix mid-sprint** : CSV formula injection défusée par `_csv_safe()` (apostrophe-prefix sur `=`/`+`/`-`/`@`/`\t`/`\r`). Le red team aurait pu injecter une formule qui s'exécute chez le SOC à l'ouverture de l'Excel. + +## Test plan +- **Backend** : **255/255** pytest (`ruff` + `mypy` clean). +- **Frontend** : **136/136** vitest (`typecheck` + `lint` clean). +- **E2e Playwright** : **223/223** verts — baseline sprint 5 = 201, +22 sprint 6. + +## Comment tester en local +```bash +make build && make start # auto-podman, +50 MB d'image (deps WeasyPrint) +make create-admin USER=alice PASS=changeme8 # si premier setup +# Ouvrir http://127.0.0.1:5000 (IPv4 explicite si IPv6 par défaut) +``` + +Scénarios : +1. **Export Markdown** — login admin → engagement avec ≥ 2 simulations → header → `[Export ▼]` → Markdown. Le `.md` téléchargé contient le nom de l'engagement, ses dates, et le détail de chaque simulation RT + SOC. +2. **Export CSV** — même flow → CSV. Ouvre dans LibreOffice : 1 ligne header + N lignes simulations, commands multilines correctement échappés, colonnes RT et SOC visibles. +3. **Export PDF** — même flow → PDF. Le fichier doit s'ouvrir dans un viewer PDF avec un rendu propre (titres, sections, tables). +4. **CSV formula injection (sécurité)** — crée une simulation avec `name = "=cmd|'/c calc'!A1"`, exporte le CSV, ouvre dans Excel/LibreOffice. La cellule doit afficher le texte littéral `=cmd|'/c calc'!A1` (apostrophe forcé), pas exécuter la formule. +5. **SOC zero access** — login en SOC → engagement → bouton `Export` ABSENT du header. Test API direct : `curl -H "Authorization: Bearer " http://127.0.0.1:5000/api/engagements/1/export?format=md` → `403`. +6. **Engagement vide** — engagement avec 0 simulations → export OK (header seul ; CSV = 1 ligne header). +7. **Filename normalisé** — engagement nommé `"Opération Spéciale"` → filename Content-Disposition = `engagement--operation-speciale-YYYYMMDD.` (NFKD strip des accents). + +## Notes +- **Endpoint unique** avec query param `format`, pas 3 routes séparées — 1 RBAC à protéger, 1 test d'intégration RBAC. +- **PDF pipeline** : WeasyPrint (Python HTML→PDF). Le PDF est généré depuis les MÊMES DONNÉES que le Markdown (pas depuis le string Markdown) via `_render_engagement_html()`. CSS inline ≤ 30 lignes. +- **Dockerfile** : +6 libs minimales pour WeasyPrint (`libcairo2 libpango-1.0-0 libpangoft2-1.0-0 libharfbuzz0b libfontconfig1 shared-mime-info`). `libgdk-pixbuf-2.0-0` exclu (text-only PDF, vérifié `weasyprint --info`). +- **Process wins sprint 6** : SPEC.md committed en commit #1 du sprint (recurrence 4 sprints enfin tuée) ; spec-reviewer 2-pass APPROVED avant dispatch backend (0 addendum mid-implementation, comme sprint 5) ; team `mimic` persistante avec les 7 agents idle (cohérence cross-sprint à partir du sprint 7+). + +🤖 Generated with [Claude Code](https://claude.com/claude-code)