Dark mode (toggle topbar light/dark/system + localStorage persistence) avec split de tokens ink (text themed) vs slab (surface dark fixe non-inversée). Audit complet des composants pour zéro couleur hardcodée hors-tokens.
MITRE matrix modal overhaul : grille 12 colonnes, plus de scroll horizontal à 1280×720, look proche d'attack.mitre.org. Sélection de tactique (TA-id) en plus des techniques et sub-techniques.
Refonte input MITRE : autocomplete inline + bouton matrice à droite (suppression des boutons textuels "Add Technique"/"Quick Search"). Chips compacts avec référence seule (T-id ou TA-id) + tooltip nom au survol.
Done = terminal + Reopen : PATCH sur une simu done retourne 409 ; nouveau cas transition done → review_required ouvert aux 3 rôles. UI cohérente (read-only + bouton Reopen seul).
Engagement auto-status : planned → active automatique à la première simulation in_progress. Pas de retour arrière auto.
14 commits sur la branche, dont 4 fixes post-design-review et 2 fixes post-code-review.
Comment tester en local
make build && make start # auto-détecte podman si pas de docker
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 :
Theme toggle — clique le ☀️ / 🌙 / 🖥 dans la topbar pour cycler light/dark/system. Recharge → la pref persiste.
Matrix modale — ouvre une simu, click l'icône matrice. Toutes les 12 tactiques tiennent sans scroll horizontal. Click sur un header de tactique (ex: DISCOVERY) = sélection TA-id en plus des techniques.
Tags compacts — sélectionne T1059 + TA0007 → chips affichent T1059 et TA0007 (référence seule). Survol = nom complet en tooltip.
Done terminal — clôture une simu (status → done). Toute édition désactivée. Click "Reopen" → retour à review_required, édition redevient possible.
Engagement auto-active — crée un nouvel engagement (planned), crée+remplis une simu, sauve. L'engagement passe auto en active.
UsersAdmin alignement — visite /admin/users. Les 3 labels Username/Password/Role sont sur la même baseline, idem pour les inputs et le bouton Create.
PR helper — vérifier que cette PR a été créée via make open-pr (dogfood).
Notes
Breaking API : GET /api/mitre/matrix retourne maintenant tactic_id en TA-format (TA0007) au lieu du slug interne (discovery). Aligne sur le format accepté par PATCH tactic_ids. Caught by e2e — fixed in commit a824df0.
Spec drift résolu : sprint 3 §0 SPEC update qui avait été oublié au commit est porté ici dans ba313a3.
Sprint 5 prévu : templates de simulations pré-remplies (item 8 du QA sprint 3).
## Summary
- **Dark mode** (toggle topbar light/dark/system + `localStorage` persistence) avec split de tokens `ink` (text themed) vs `slab` (surface dark fixe non-inversée). Audit complet des composants pour zéro couleur hardcodée hors-tokens.
- **MITRE matrix modal overhaul** : grille 12 colonnes, plus de scroll horizontal à 1280×720, look proche d'attack.mitre.org. Sélection de tactique (TA-id) en plus des techniques et sub-techniques.
- **Refonte input MITRE** : autocomplete inline + bouton matrice à droite (suppression des boutons textuels "Add Technique"/"Quick Search"). Chips compacts avec référence seule (T-id ou TA-id) + tooltip nom au survol.
- **Done = terminal + Reopen** : PATCH sur une simu `done` retourne 409 ; nouveau cas transition `done → review_required` ouvert aux 3 rôles. UI cohérente (read-only + bouton Reopen seul).
- **Engagement auto-status** : `planned → active` automatique à la première simulation `in_progress`. Pas de retour arrière auto.
- **UI polish** : dédoublonnage CTA "New" sur EngagementsList, alignement enfin pixel-perfect sur UsersAdmin (3e tentative, refactor structural 3-row grid), audit boutons (icônes lucide + label court).
- **Process hygiene** : nouvel agent `design-reviewer` (run après frontend-builder), screenshots devenu MANDATORY au DoD du frontend-builder.
- **Infra** : `scripts/open-pr.sh` + `make open-pr SPRINT=N TITLE="..." BODY=path` — cette PR est ouverte avec ce nouveau target (dogfood AC-25.4).
## Test plan
- Backend : **193/193** pytest (`ruff` + `mypy` clean).
- Frontend : **92/92** vitest (`typecheck` + `lint` clean).
- E2e Playwright : **158/158** (toutes les ACs sprint 4 US-17 → US-23 + régression sprint 1-3 verts).
- Migration 0004 : Alembic round-trip testé (NOT NULL contrainte vérifiée post-upgrade).
- Reproductibilité : tests migration utilisent maintenant `Path(__file__)` (plus de hardcoded paths).
- 14 commits sur la branche, dont 4 fixes post-design-review et 2 fixes post-code-review.
## Comment tester en local
```bash
make build && make start # auto-détecte podman si pas de docker
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. **Theme toggle** — clique le `☀️ / 🌙 / 🖥` dans la topbar pour cycler light/dark/system. Recharge → la pref persiste.
2. **Matrix modale** — ouvre une simu, click l'icône matrice. Toutes les 12 tactiques tiennent sans scroll horizontal. Click sur un header de tactique (ex: DISCOVERY) = sélection TA-id en plus des techniques.
3. **Tags compacts** — sélectionne T1059 + TA0007 → chips affichent `T1059` et `TA0007` (référence seule). Survol = nom complet en tooltip.
4. **Done terminal** — clôture une simu (status → done). Toute édition désactivée. Click "Reopen" → retour à `review_required`, édition redevient possible.
5. **Engagement auto-active** — crée un nouvel engagement (planned), crée+remplis une simu, sauve. L'engagement passe auto en `active`.
6. **UsersAdmin alignement** — visite `/admin/users`. Les 3 labels Username/Password/Role sont sur la même baseline, idem pour les inputs et le bouton Create.
7. **PR helper** — vérifier que cette PR a été créée via `make open-pr` (dogfood).
## Notes
- Breaking API : `GET /api/mitre/matrix` retourne maintenant `tactic_id` en TA-format (`TA0007`) au lieu du slug interne (`discovery`). Aligne sur le format accepté par PATCH `tactic_ids`. Caught by e2e — fixed in commit `a824df0`.
- Spec drift résolu : sprint 3 §0 SPEC update qui avait été oublié au commit est porté ici dans `ba313a3`.
- Sprint 5 prévu : templates de simulations pré-remplies (item 8 du QA sprint 3).
🤖 Generated with [Claude Code](https://claude.com/claude-code)
The sprint 3 plan §0 updated SPEC.md § Simulation to reflect multi-techniques
(plural + autocomplete + matrix modal + sub-techniques). That edit sat in the
sprint 3 worktree but was never committed, so PR #6 merged the multi-tech
code without the corresponding spec text. Applying it here at the start of
sprint 4 so SPEC and main are aligned again.
Lesson captured in tasks/lessons.md for sprint 4 wrap-up: always
git status before declaring sprint complete.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- tasks/todo.md: sprint 4 plan with 9 user stories (US-17 → US-25), 9 décisions arrêtées
- SPEC.md § Fonctionnement: Done is terminal, Reopen returns to review_required (open to all roles); engagement auto-flips planned → active when any simulation hits in_progress, no auto-rollback
- SPEC.md § Référentiel MITRE: sprint 3 multi-tech + sprint 4 tactic_ids separated field
- SPEC.md § UI/UX (new): theming light/dark/system with system default, button convention (icon + ≤8-char label), modal focus trap V1
- SPEC.md § Workflows: design-reviewer inserted between frontend-builder and code-reviewer; PR via make open-pr
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
US-24 — Process hygiene UI:
- New .claude/agents/design-reviewer.md (model: opus, read-only) — visual + design-system reviewer that runs after frontend-builder and before code-reviewer. Audits alignment, DESIGN.md tokens, light/dark consistency, typo hierarchy, whitespace rhythm, responsive sanity at 1280x720, button convention, V1 a11y. Output format mirrors code-reviewer.
- Updated .claude/agents/frontend-builder.md DoD: screenshots are MANDATORY (one per feature/state introduced or modified, light+dark when theming is in scope). Hard block on "Dev server not started" — must be flagged explicitly. Screenshots feed the design-reviewer step.
US-25 — PR helper:
- scripts/open-pr.sh wraps `POST /api/v1/repos/{owner}/{repo}/pulls`. Detects host/owner/repo from `git remote get-url origin`, reads basic-auth credentials from `~/.git-credentials` (same source as `git push`, no token in env), uses jq to compose the multiline-safe payload. Validates args, prints PR URL on success, exits non-zero with the server message on failure.
- Makefile target `open-pr TITLE="..." BODY=path/to/body.md [BASE=main]` wraps the script with the same arg validation.
- README.md "Make targets" table extended.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- Add fixed slab/slab-text/slab-muted tokens so utility strip and footer never
invert to near-white in dark mode (root token split: ink is themed text,
slab is fixed dark surface)
- btn-ink uses fixed#111827 so confirm dialogs stay dark-on-dark readable
- Toast error surface switched to slab; success uses text-white (not text-ink-on)
- StatusBadge active and SimulationStatusBadge review_required/done use text-white
instead of text-canvas/text-ink-on (prevents near-black text on colored pill
in dark mode)
- Modal backdrops (MitreMatrixModal, ConfirmDialog) switched to .modal-backdrop
class (fixed rgba(0,0,0,0.6)) instead of bg-ink/60 which turned near-white
- Card shadow lifted in dark mode via .dark .card-product override
- MitreMatrixModal panel uses shadow-floating-dark in dark mode
- UsersAdminPage form: items-start + explicit label-height spacer on button
column for pixel-perfect baseline alignment (AC-17.3 structural fix)
92/92 tests passing, typecheck and lint clean.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- bump dark hairline from #374151 → #4b5563 for visible table borders
- topbar header bg-canvas → bg-paper for dark-mode lift vs canvas body
- UsersAdminPage create-form: Option A structural 3-row grid (labels / inputs / hints)
to fix AC-17.3 alignment; removes FormField wrapper that caused row-height misalignment
- EngagementsListPage: replace text "+ New" with lucide Plus icon per design spec
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- btn-ink: replace inline background-color #111827 with @apply bg-slab (and add
slab-hover token #1f2937 for the hover state) so the token system is consistent
- EngagementsListPage: header button "+ New" → "+ New engagement" to match
empty-state CTA label
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- test_engagement_lifecycle.py, test_simulations_techniques.py: replace hardcoded
absolute paths with Path(__file__).parent.parent / migrations/... (portable)
- simulation_workflow.py: remove dead branch in transition() — the IN_PROGRESS
hook was unreachable since _ALLOWED_TRANSITIONS only targets review_required/done
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- mitre.py: add _SLUG_TO_TA_ID reverse map; _build_matrix() now emits tactic_id
as TA-id (e.g. "TA0007") so frontend can send it back verbatim in PATCH tactic_ids
- test_mitre.py: update all matrix assertions to use TA-ids; add
test_get_matrix_tactic_id_is_ta_format regression guard
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Remove test.fail annotation from AC-21.6 "Apply from modal includes
tactic in result". GET /api/mitre/matrix now returns tactic_id in TA-format
("TA0007") so the PATCH succeeds and the tactic chip appears.
Update button selector in both AC-21.6 tests from title*="discovery"
to title*="TA0007" to match the fixed matrix response format.
Suite: 158 passed, 0 failed.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- CHANGELOG: sprint 4 entry under [Unreleased] (covers all 9 US: dark mode, MITRE matrix overhaul, tactic_ids, done read-only + Reopen, engagement auto-status, UI polish, design-reviewer agent, PR helper, screenshots mandatory). Sprint 3 moved to its own [Sprint 3] section.
- README: status bump, test counts refreshed (193/92/158).
- tasks/lessons.md: 7 sprint-4 lessons captured (git status before sprint close, endpoint round-trip mismatch caught only by e2e, ink vs slab token split, structural row layout > class tweaks, hardcoded paths in migration tests, screenshots with auth, builder cross-context summaries as accidental re-dispatch).
- tasks/todo.md: status flipped to 🟢 SPRINT COMPLET, execution sequence ticks updated with commit hashes.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
knacky
merged commit 9873c535c6 into main2026-05-28 04:01:21 +00:00
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Summary
localStoragepersistence) avec split de tokensink(text themed) vsslab(surface dark fixe non-inversée). Audit complet des composants pour zéro couleur hardcodée hors-tokens.doneretourne 409 ; nouveau cas transitiondone → review_requiredouvert aux 3 rôles. UI cohérente (read-only + bouton Reopen seul).planned → activeautomatique à la première simulationin_progress. Pas de retour arrière auto.design-reviewer(run après frontend-builder), screenshots devenu MANDATORY au DoD du frontend-builder.scripts/open-pr.sh+make open-pr SPRINT=N TITLE="..." BODY=path— cette PR est ouverte avec ce nouveau target (dogfood AC-25.4).Test plan
ruff+mypyclean).typecheck+lintclean).Path(__file__)(plus de hardcoded paths).Comment tester en local
Scénarios :
☀️ / 🌙 / 🖥dans la topbar pour cycler light/dark/system. Recharge → la pref persiste.T1059etTA0007(référence seule). Survol = nom complet en tooltip.review_required, édition redevient possible.active./admin/users. Les 3 labels Username/Password/Role sont sur la même baseline, idem pour les inputs et le bouton Create.make open-pr(dogfood).Notes
GET /api/mitre/matrixretourne maintenanttactic_iden TA-format (TA0007) au lieu du slug interne (discovery). Aligne sur le format accepté par PATCHtactic_ids. Caught by e2e — fixed in commita824df0.ba313a3.🤖 Generated with Claude Code
US-24 — Process hygiene UI: - New .claude/agents/design-reviewer.md (model: opus, read-only) — visual + design-system reviewer that runs after frontend-builder and before code-reviewer. Audits alignment, DESIGN.md tokens, light/dark consistency, typo hierarchy, whitespace rhythm, responsive sanity at 1280x720, button convention, V1 a11y. Output format mirrors code-reviewer. - Updated .claude/agents/frontend-builder.md DoD: screenshots are MANDATORY (one per feature/state introduced or modified, light+dark when theming is in scope). Hard block on "Dev server not started" — must be flagged explicitly. Screenshots feed the design-reviewer step. US-25 — PR helper: - scripts/open-pr.sh wraps `POST /api/v1/repos/{owner}/{repo}/pulls`. Detects host/owner/repo from `git remote get-url origin`, reads basic-auth credentials from `~/.git-credentials` (same source as `git push`, no token in env), uses jq to compose the multiline-safe payload. Validates args, prints PR URL on success, exits non-zero with the server message on failure. - Makefile target `open-pr TITLE="..." BODY=path/to/body.md [BASE=main]` wraps the script with the same arg validation. - README.md "Make targets" table extended. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>- Simulation model: add tactic_ids JSON column (nullable=False, default=[]) - Migration 0004: ADD COLUMN tactic_ids (server_default='[]', no batch needed) - mitre.py: add _TACTIC_IDS map, lookup_tactic(), get_tactic_name() - simulation_workflow.py: done guard (409) before RBAC; SOC gate += tactic_ids; _resolve_tactic_ids() validates against hardcoded map; auto-transition += tactic_ids; transition done→review_required is Reopen (all 3 roles); _maybe_activate_engagement hook - serializers.py: _enrich_tactics() → serialize_simulation adds tactics:[{id,name}] - test_simulations_tactics.py: valid/invalid/dedup/SOC gate/auto-transition/no-bundle - test_simulations_done_readonly.py: 409 all roles, Reopen all roles, invalid transitions, after-reopen ok - test_engagement_lifecycle.py: planned→active on auto-transition, already active/closed unchanged, migration 0004 round-trip - Updated test_simulations_patch.py + test_simulations_workflow.py for AC-18 behavior Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>Remove test.fail annotation from AC-21.6 "Apply from modal includes tactic in result". GET /api/mitre/matrix now returns tactic_id in TA-format ("TA0007") so the PATCH succeeds and the tactic chip appears. Update button selector in both AC-21.6 tests from title*="discovery" to title*="TA0007" to match the fixed matrix response format. Suite: 158 passed, 0 failed. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>