docs: sprint 5 wrap-up — CHANGELOG + README + 6 lessons + plan final
- CHANGELOG: sprint 5 entry under [Unreleased] (templates CRUD + instantiation + nav + dropdown + decorrelation). Sprint 4 moved to its own [Sprint 4] section. - README: status bump to sprint 5, test counts refreshed (226/121/201). - tasks/lessons.md: 6 sprint-5 lessons captured (spec-reviewer 2-pass before dispatch finally clicked, endpoint path drift caught visually not by spec-review, screenshot script mocks lag path changes, silent URL "improvements" by backend, apply_patch wrong primitive for creation copy paths, IntegrityError catch beats pre-check SELECT, SendMessage rule applies to all team agents). - tasks/todo.md: status flipped to 🟢 SPRINT COMPLET. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
43
CHANGELOG.md
43
CHANGELOG.md
@@ -6,6 +6,49 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/)
|
||||
|
||||
## [Unreleased]
|
||||
|
||||
### Added — Sprint 5 (Simulation templates)
|
||||
|
||||
**Backend** (226 pytest passing — 193 sprint-1-to-4 + 28 sprint 5 + 5 post-code-review)
|
||||
- `SimulationTemplate` model (table `simulation_templates`) — UNIQUE constraint on `name`, JSON `techniques` + `tactic_ids` (default `[]`, NOT NULL via `server_default`), Text fields `description` / `commands` / `prerequisites`, FK `created_by_id` to `users`, `created_at` / `updated_at`.
|
||||
- Alembic migration `0005_simulation_templates.py` — CREATE TABLE (SQLite native, no batch); downgrade via DROP TABLE.
|
||||
- 5 new endpoints under `/api/templates`, all gated `@role_required("admin", "redteam")` (SOC → 403):
|
||||
- `GET /api/templates` — list, sorted name ASC, serialized with enriched `techniques: [{id, name, tactics}]` and `tactics: [{id, name}]`.
|
||||
- `POST /api/templates` — create. `name` required (400 if empty), unique (409 via `IntegrityError` catch, no pre-check race). `technique_ids` / `tactic_ids` validated upfront — type check `isinstance(list)` (400 with friendly message) THEN resolved against the bundle / `_TACTIC_IDS` (400 with id on unknown).
|
||||
- `GET /api/templates/<tid>` — single, 404 on miss.
|
||||
- `PATCH /api/templates/<tid>` — partial update. Same validations. 409 on `name` conflict; no-op rename (`name == current`) returns 200.
|
||||
- `DELETE /api/templates/<tid>` — 204. **No cascade** to instantiated simulations (decoupling guarantee).
|
||||
- `POST /api/engagements/<eid>/simulations` extended with optional `template_id`. When provided:
|
||||
- Template loaded (404 on miss).
|
||||
- Fields copied directly onto the new `Simulation` ORM object (`techniques`, `tactic_ids`, `description`, `commands`, `prerequisites`, and `name` if missing from body).
|
||||
- **Explicit non-call to `apply_patch()` / `_resolve_*` helpers** — avoids re-hitting the MITRE bundle AND avoids triggering the auto-transition `pending → in_progress`. Status stays `pending`, engagement stays `planned` (no `_maybe_activate_engagement` call). Decorrelation: no `template_id` FK on `Simulation`, deep copy of JSON arrays.
|
||||
- New helpers in `mitre.py` reused / re-exposed; new `serialize_template()` in `serializers.py` mirrors `serialize_simulation` (minus SOC fields, status, executed_at) and uses the shared `_enrich_techniques` + `_enrich_tactics` (no duplication).
|
||||
- All migration tests (0003, 0004, 0005) now use `Path(__file__).resolve().parent.parent / "migrations" / "versions" / "..."` — sprint 4's hardcoded-path MAJOR is closed for the third sprint running.
|
||||
|
||||
**Frontend** (121 vitest passing — 92 sprint-1-to-4 + 26 sprint 5 + 3 post-code-review)
|
||||
- New page `TemplatesListPage` (`/admin/templates`, admin+redteam only) — table (Name / MITRE count / Created by / Updated / Actions), `+ New` CTA with Plus icon.
|
||||
- New page `TemplateFormPage` (`/admin/templates/new` and `/admin/templates/:id/edit`) — single-column FormField stack (sidesteps the multi-column grid trap that broke AC-17.3 on UsersAdminPage). Includes `MitreTechniquePicker` + `MitreMatrixModal` inline (NOT `MitreTechniquesField` — that one auto-saves; template form needs batched save). Delete via `ConfirmDialog`.
|
||||
- New component `TemplatePickerModal` — modal listing all templates (Name / MITRE count / Created by). Empty state when `useTemplates()` returns `[]`: "No templates available — Create one from the Templates page."
|
||||
- New nav link "Templates" in `Layout.tsx` topbar — visible to admin + redteam only, masked for SOC. Mirrors the pattern used by the "Users" link.
|
||||
- `SimulationList` "New" button refactored into a **split-button dropdown**: `[+ New] [▼]`. Primary half → `/.../simulations/new` (blank). Dropdown → "Blank" + "From template…". Open dropdown closes on click-outside or Escape (sprint 3 picker pattern). Empty-state `SimulationList` now also exposes the same dropdown (so users can instantiate from a template on a fresh engagement without creating a blank first).
|
||||
- `dark:shadow-floating-dark` consistently applied to the new dropdown and `TemplatePickerModal` — matches the sprint 4 shadow token model. `dark:hover:bg-fog` on dropdown items for contrast.
|
||||
- New types: `SimulationTemplate`, `SimulationTemplateCreateInput`, `SimulationTemplatePatchInput`. `SimulationCreateInput` extended with `template_id?: number`.
|
||||
- New TanStack Query hooks (`useTemplates`, `useTemplate`, `useCreateTemplate`, `useUpdateTemplate`, `useDeleteTemplate`) with cache invalidation on mutations.
|
||||
- API client `frontend/src/api/templates.ts` — 5 calls to `/api/templates*`. (Sprint-5 in-flight bug : initial commit `90fc5ba` used `/simulation-templates` paths everywhere; caught immediately, fixed in `2b70011`.)
|
||||
|
||||
**Acceptance tests** (Playwright, **201 passed**)
|
||||
- 3 new spec files (one per US): `us26-templates-crud.spec.ts` (22 tests), `us27-instantiate-from-template.spec.ts` (14 tests), `us28-templates-nav.spec.ts` (8 tests).
|
||||
- Coverage gaps from code-reviewer filled: bidirectional template↔instance decorrelation, dropdown click-outside + Escape, SOC + template_id 403.
|
||||
- Sprint 2/3 spec adapts: `us4-engagements.spec.ts` and `us7-simulation-create.spec.ts` now use `getByTestId('new-simulation-btn')` instead of `getByRole('link', /new simulation/)` — the link became a split-button dropdown.
|
||||
- 1 pre-existing flaky in `us3-users-admin AC-3.4` (DB contamination across runs) — predates sprint 5, unrelated.
|
||||
|
||||
### Changed
|
||||
- 2026-05-28 — SPEC.md § Templates de simulations added (between § Fonctionnement and § Authentification & rôles). Spells out the decoupling rule and the SOC-zero-access RBAC.
|
||||
- 2026-05-28 — `POST /api/engagements/<eid>/simulations` API contract: `name` is now optional when `template_id` is provided (falls back to `template.name`).
|
||||
|
||||
---
|
||||
|
||||
## [Sprint 4] — UI polish + workflow tightening + dark mode + process hygiene (merged 2026-05-28)
|
||||
|
||||
### Added — Sprint 4 (UI polish + workflow tightening + dark mode + process hygiene)
|
||||
|
||||
**Backend** (193 pytest passing — 192 sprint-1-to-3 + 1 sprint-4)
|
||||
|
||||
Reference in New Issue
Block a user