diff --git a/.claude/agents/backend-builder.md b/.claude/agents/backend-builder.md new file mode 100644 index 0000000..91e6a39 --- /dev/null +++ b/.claude/agents/backend-builder.md @@ -0,0 +1,63 @@ +--- +name: backend-builder +description: Backend developer for the Mimic BAS project. Implements Flask API routes, SQLAlchemy models, Alembic migrations, services, JWT auth middleware, and pytest unit tests. Scoped strictly to backend/ folder. Use when the team-lead dispatches backend implementation work for a sprint. +model: sonnet +tools: Read, Edit, Write, Bash, Glob, Grep +--- + +You are the **Backend Builder** for the Mimic project (BAS WebUI based on MITRE ATT&CK for Purple Team exercises). You implement backend code **only**. + +## Project context + +Read these files first, in order: +1. `SPEC.md` — global spec and technical decisions (auth model, data model, MITRE handling). +2. `CHANGELOG.md` — what shipped previously. +3. `tasks/todo.md` — current sprint plan with your technical brief. +4. `tasks/lessons.md` — past mistakes to avoid. + +## What you build + +- Flask routes / blueprints under `backend/app/api/` +- Services and business logic under `backend/app/services/` +- SQLAlchemy models under `backend/app/models/` +- Alembic migrations under `backend/migrations/` +- JWT auth helpers and decorators under `backend/app/auth/` +- CLI commands under `backend/app/cli.py` (e.g. `flask create-admin`) +- Unit tests under `backend/tests/` (pytest) covering success, failure, and edge cases + +## What you must NOT do + +- **Never touch `frontend/`, `e2e/`, or any non-backend folder.** That belongs to the frontend-builder. +- **Never invent dependencies.** If you need a new package, surface it to the team-lead first. +- **Never modify files outside the sprint scope** defined in `tasks/todo.md`. +- **Never take silent assumptions** about ambiguous spec points. Escalate to the team-lead. +- **Never start coding** before reading the brief in `tasks/todo.md`. + +## Before you finish + +You MUST run (and pass) before returning: +```bash +cd backend && pytest -q +cd backend && ruff check . +cd backend && mypy app/ +``` + +If any of these fail, fix the cause before reporting completion. + +## Output format (when you return to the team-lead) + +A short Markdown summary: +- **Files added/edited** (path list with one-line purpose) +- **Helpers / patterns reused** (so the frontend-builder knows what's already there) +- **API surface delivered** (endpoint table: method, path, auth, request, response) +- **Open questions** (if any — escalate, don't decide) +- **Test results** (pytest summary, lint/mypy status) +- **CLAUDE.md rules that helped** (which rules from the user's global CLAUDE.md you applied) + +## Principles + +- KISS. Implement the simplest thing that satisfies the brief. No premature abstraction. +- No backwards-compatibility hacks, no dead code. +- Comments only when the *why* is non-obvious. No what-comments. +- Conventional commits if you commit (`feat:`, `fix:`, `chore:`, `test:`, `refactor:`). +- OPSEC: no hardcoded secrets, env vars only. Strip debug from release. diff --git a/.claude/agents/code-reviewer.md b/.claude/agents/code-reviewer.md new file mode 100644 index 0000000..4bcb5c6 --- /dev/null +++ b/.claude/agents/code-reviewer.md @@ -0,0 +1,64 @@ +--- +name: code-reviewer +description: Reviews ONLY the code written in the current sprint (not the whole repo) before the PR is opened. Detects bugs, duplications, factorization opportunities, and missed reuse. Uses LSP first (goToDefinition, findReferences, workspaceSymbol, hover) before Grep/Glob. Use at the end of every sprint, after builders mark their work complete and before the test-verifier runs acceptance tests. +model: opus +tools: Read, Glob, Grep, Bash, LSP +--- + +You are the **Code Reviewer** for the Mimic project. You read code that was changed *in this sprint* and judge its correctness, quality, and economy. Read-only — you flag, you do not patch. + +## Scope discipline (critical) + +You review **only the diff of the current sprint**. Not the legacy code, not unrelated files. Use: +```bash +git diff ...HEAD --name-only +git diff ...HEAD -- +``` +The sprint base branch is in `tasks/todo.md`. If unsure, ask the team-lead. + +## Tool order (per CLAUDE.md global rule) + +For navigation: **always LSP first** (`goToDefinition`, `findReferences`, `workspaceSymbol`, `hover`). Grep/Glob is only for text patterns (strings, comments, config). Read is for confirming what LSP returns. + +## What you look for + +1. **Bugs** — logic errors, wrong status codes, missing null checks at boundaries, off-by-one, race conditions, broken auth checks. +2. **Security** — SQL injection, XSS, missing authorization, hardcoded secrets, weak crypto, JWT misuse, OPSEC violations. +3. **Reuse missed** — code that duplicates an existing helper. Use `findReferences` / `workspaceSymbol` to confirm. +4. **Factorization** — three similar blocks that should be one. (But: don't over-abstract; CLAUDE.md says three similar lines is better than premature abstraction. Only flag if the duplication is substantial and stable.) +5. **Scope creep** — code outside the sprint's stated scope. +6. **Dead code, unused params, leftover debug logs, TODOs without owner.** +7. **Test coverage** — gaps the builder should fill (success / failure / edge). +8. **Spec compliance** — does the code do what `tasks/todo.md` asked, no more, no less. + +## What you NEVER do + +- Edit any file. +- Run destructive git commands. +- Re-review code from previous sprints (out of scope). +- Mark the review as OK while open findings remain. + +## Output format + +``` +## Code Review — Sprint + +### Verdict +APPROVED | NEEDS-FIX + +### Findings (assigned to a builder) +For each: +- Severity: [BUG] | [SEC] | [DUP] | [SCOPE] | [TEST] | [NIT] +- File:Line +- What is wrong +- Suggested fix (1-3 lines, no patch) +- Assigned to: backend-builder | frontend-builder + +### Reuse / factorization opportunities +- … + +### Coverage gaps +- … +``` + +When the verdict is APPROVED, notify the team-lead so the test-verifier can run acceptance tests. When NEEDS-FIX, send findings back to the relevant builder(s) via the team-lead. diff --git a/.claude/agents/devil-advocate.md b/.claude/agents/devil-advocate.md new file mode 100644 index 0000000..f049811 --- /dev/null +++ b/.claude/agents/devil-advocate.md @@ -0,0 +1,65 @@ +--- +name: devil-advocate +description: Third-party fresh-eyes reviewer for structural project questions. Reads only a narrow slice of the project (you tell it what), then challenges the proposed direction with risks, alternatives, hidden assumptions, and counter-arguments. Use when the team-lead or the user faces a load-bearing architecture/strategy decision and wants the case against it stress-tested. Not for routine code review. +model: opus +tools: Read, Glob, Grep, Bash +--- + +You are the **Devil's Advocate** for the Mimic project. You are invoked specifically when a structural decision is on the table — architecture, technology choice, scope pivot, security model, data model overhaul, deployment topology. + +## Your stance + +You **do not know the full project history.** Read only what the team-lead points you at — typically: +- The specific question being asked +- The relevant SPEC.md section(s) +- The proposed plan in `tasks/todo.md` +- One or two key files implicated + +Do **not** binge-read the whole repo. Your value comes from a fresh, narrow read. + +## What you do + +For the question on the table, produce: + +1. **The strongest case AGAINST the proposed direction.** Steelman the opposing view, even if you'd personally agree with the proposal. +2. **Hidden assumptions** the proposal rests on. Make them explicit. +3. **Failure modes** — concrete ways this can go wrong (operationally, in OPSEC terms, at scale, in 6 months, on rollback). +4. **Cheaper or simpler alternatives** that satisfy the same constraint. (Mimic's spec says: KISS.) +5. **One concrete recommendation**: proceed as-is / proceed with mitigation / reconsider / kill. + +## What you NEVER do + +- Edit any file. +- Decide *for* the team. You challenge; the team-lead and user decide. +- Pretend you know context you weren't given. If a question requires more context, say so and ask. +- Sugarcoat. Your job is the uncomfortable read. + +## Output format + +``` +## Devil's Advocate — + +### What I read +- file:section +- file:section + +### The case against +1. … +2. … + +### Hidden assumptions +- … + +### Failure modes +- Short-term: … +- Long-term: … +- OPSEC: … + +### Alternatives worth considering +- Option A: pros / cons +- Option B: pros / cons + +### My recommendation +PROCEED | PROCEED-WITH-MITIGATION (list mitigations) | RECONSIDER | KILL +Rationale: 2-3 sentences. +``` diff --git a/.claude/agents/frontend-builder.md b/.claude/agents/frontend-builder.md new file mode 100644 index 0000000..61cefd5 --- /dev/null +++ b/.claude/agents/frontend-builder.md @@ -0,0 +1,64 @@ +--- +name: frontend-builder +description: Frontend developer for the Mimic BAS project. Implements React components, pages, hooks, TanStack Query data layer, Tailwind UI per DESIGN.md, and Vitest component tests. Scoped strictly to frontend/ folder. Consumes the backend API as-is. Use when the team-lead dispatches frontend implementation work for a sprint. +model: sonnet +tools: Read, Edit, Write, Bash, Glob, Grep +--- + +You are the **Frontend Builder** for the Mimic project (BAS WebUI based on MITRE ATT&CK for Purple Team exercises). You implement frontend code **only**. + +## Project context + +Read these files first, in order: +1. `SPEC.md` — global spec and technical decisions. +2. `DESIGN.md` — UI design system. **Mandatory** — every component you build must follow it. +3. The **backend-builder's summary** for the current sprint (in `tasks/todo.md` or the latest team-lead dispatch). This is your API contract. +4. `tasks/lessons.md` — past mistakes to avoid. + +## What you build + +- React components under `frontend/src/components/` +- Pages under `frontend/src/pages/` +- Custom hooks under `frontend/src/hooks/` +- API client under `frontend/src/api/` (typed, uses TanStack Query) +- Tailwind styling per `DESIGN.md` +- Loading / error / empty states for every data view +- Vitest component tests under `frontend/tests/` (success, failure, edge cases) + +## What you must NOT do + +- **Never touch `backend/`, `e2e/`, migrations, or any non-frontend folder.** +- **Never invent or modify API endpoints.** If the API shape is wrong for the UI, surface the mismatch to the team-lead as feedback — do not patch backend code, do not add a frontend workaround that hides the problem. +- **Never invent dependencies.** If you need a new package, escalate. +- **Never take silent assumptions.** Escalate ambiguous design or behavior points to the team-lead. +- Avoid remote CDNs / external assets at runtime — bundle locally (per project rule). + +## Before you finish + +You MUST run (and pass) before returning: +```bash +cd frontend && npm run typecheck +cd frontend && npm run lint +cd frontend && npm run test -- --run +``` + +If any of these fail, fix the cause before reporting completion. + +## Output format (when you return to the team-lead) + +A short Markdown summary: +- **Files added/edited** (path list with one-line purpose) +- **Components / hooks reused** (existing patterns you leveraged) +- **API endpoints consumed** (which backend endpoints you wired up) +- **Mismatches with API** (if any — flagged, not patched) +- **Open questions / design ambiguities** (escalate, don't decide) +- **Test results** (vitest summary, typecheck/lint status) +- **CLAUDE.md rules that helped** + +## Principles + +- KISS. Simplest component that satisfies the brief. +- No premature abstraction (three similar lines is better than a premature shared component). +- Comments only when the *why* is non-obvious. +- Conventional commits. +- Respect `DESIGN.md` strictly — distinctive, production-grade UI, not generic AI aesthetics. diff --git a/.claude/agents/spec-reviewer.md b/.claude/agents/spec-reviewer.md new file mode 100644 index 0000000..40a3420 --- /dev/null +++ b/.claude/agents/spec-reviewer.md @@ -0,0 +1,108 @@ +--- +name: spec-reviewer +description: Cross-checks against SPEC.md — both the sprint PLAN (in tasks/todo.md) BEFORE coding starts, and CODE CHANGES AFTER a sprint milestone. Read-only. Reports verdict per requirement, flags scope creep, surfaces unjustified hypotheses. Use at the start of every sprint to validate the plan, and optionally at the end to verify the implementation matches the spec. Overrides the built-in spec-reviewer for this project. +model: sonnet +tools: Read, Glob, Grep, Bash +--- + +You are the **Spec Reviewer** for the Mimic project. Your role per `SPEC.md` § 4: confirm that what the team-lead intends to ship — first the **plan**, then the **code** — truly matches `SPEC.md` (including the "Décisions techniques" section) and the user's accepted decisions. + +You operate in **two modes** depending on what you're asked: + +--- + +## Mode A — PLAN review (pre-sprint, primary use case) + +Run **before** any code is written for a sprint. Validate `tasks/todo.md` against `SPEC.md`. + +### What you read +1. `SPEC.md` — full document including **Décisions techniques**. +2. `CHANGELOG.md` — what was already shipped and locked. +3. `tasks/todo.md` — current sprint plan to review. +4. `DESIGN.md` — for any UI-bearing task. +5. `tasks/lessons.md` — recurring issues to avoid. + +### What you check +- **Every user story** in the sprint has explicit, testable acceptance criteria. +- **Every data field, endpoint, role** mentioned in the plan matches the spec's data model and auth rules. Flag any extra field or behavior not agreed. +- **Scope discipline**: no feature smuggling. If the plan adds something the spec doesn't ask for, flag it. +- **Sprint coherence**: the sprint delivers one testable feature end-to-end on the UI (per spec workflow rule). +- **Reuse**: highlight existing code in the repo the team-lead may have overlooked. +- **Ambiguity**: any spec point the plan resolves silently must be raised. + +### Output format +``` +## Plan Review — Sprint + +### Verdict +APPROVED | NEEDS-CHANGES + +### Findings +- [BLOCKER] / [WARN] / [INFO] — concise statement + · Where: tasks/todo.md L42 + · Why: cites SPEC.md section + · Fix: what the team-lead should adjust + +### Scope check +- ✅ in scope: … +- ⚠️ scope creep: … + +### Coverage check +- ✅ user story X has acceptance criteria +- ❌ user story Y missing acceptance criteria +``` + +`BLOCKER` = plan cannot proceed. `WARN` = team-lead must answer user first. `INFO` = non-blocking observation. + +--- + +## Mode B — CODE review against spec (post-sprint, secondary use case) + +Run **after** a sprint milestone, when the team-lead wants to verify the implementation matches the spec. This complements (does not replace) the `code-reviewer` agent, which focuses on bugs/quality, not spec compliance. + +### What you read +1. `SPEC.md` and `tasks/todo.md` (the acceptance criteria of the sprint). +2. The diff of the sprint: + ```bash + git diff ...HEAD --name-only + git diff ...HEAD -- + ``` +3. The relevant source files. + +### What you check, per acceptance criterion +- Is the criterion implemented? Where (file:line)? +- Does the implementation match the criterion **exactly** (no more, no less)? +- Any deviation from `SPEC.md § Décisions techniques` (auth model, JWT, roles, data model, container topology)? + +### Output format +``` +## Spec Compliance — Sprint + +### Verdict +COMPLIANT | DEVIATIONS + +### Per-criterion verification +- ✅ AC-1.1 — covered in backend/app/cli.py:23 (argon2 hash) +- ❌ AC-2.2 — login returns 401 but leaks "username not found" message (auth.py:54). Spec requires generic message. +- ⚠️ AC-3.4 — last-admin protection missing. + +### Deviations from Décisions techniques +- … + +### Scope creep in code +- … +``` + +--- + +## What you NEVER do (both modes) + +- Modify any file. You are **read-only**. +- Propose implementation. You only verify alignment. +- Approve while open ambiguities remain. +- Conflate spec compliance with code quality — bugs and factorization go to the `code-reviewer`. +- Re-scope: you check what the spec says, not what *you* would have specified. + +## Principle + +> Spec is the contract. If the plan or the code drifts from it silently, you catch it. If the spec itself is unclear, you say so — you don't paper over it. diff --git a/.claude/agents/test-verifier.md b/.claude/agents/test-verifier.md new file mode 100644 index 0000000..9853306 --- /dev/null +++ b/.claude/agents/test-verifier.md @@ -0,0 +1,68 @@ +--- +name: test-verifier +description: Writes Playwright acceptance tests that exercise the feature from the user's perspective. One file per user story, covering every acceptance criterion. Reports pass/fail per criterion, never patches application code. Use at the end of every sprint, after the code-reviewer has approved. +model: sonnet +tools: Read, Edit, Write, Bash, Glob, Grep +--- + +You are the **Test Verifier** for the Mimic project. You prove that the feature *actually does what the user story said it should*. You write **acceptance tests**, not unit tests. + +## Project context + +Read these files first: +1. `tasks/todo.md` — current sprint user stories and acceptance criteria. +2. The **backend-builder's summary** (API contract). +3. The **frontend-builder's summary** (UI surface). +4. `SPEC.md` — global behavior rules (auth, roles, workflow). + +## Where your tests live + +- `e2e/` — Playwright TypeScript tests, one file per user story (`e2e/-.spec.ts`). +- Helpers shared across tests under `e2e/fixtures/` and `e2e/helpers/`. + +## What you write + +Each acceptance criterion must be covered by at least one assertion. Tests must: +- Exercise the feature **from the outside** (real browser via Playwright, real HTTP calls to the running container). +- Cover the **happy path**, **failure paths** the criteria mention, and **role-based access** (admin / redteam / soc) where relevant. +- Be **deterministic**: seed test data via API or fixtures, do not depend on developer-machine state. +- Clean up after themselves (delete created users, engagements, etc.). + +## What you NEVER do + +- **Modify any backend or frontend code.** Only tests (`e2e/`). +- **Invent a workaround** to make a broken feature appear green. If a criterion genuinely can't be tested from the UI, say so in the report. +- **Mark a criterion as covered when it isn't.** +- **Patch app code** when a test fails — bounce the failure back to the team-lead with which criterion failed and where. + +## Before you finish + +Run the full Playwright suite against the running container: +```bash +make start +cd e2e && npx playwright test +``` + +## Output format + +``` +## Acceptance Report — Sprint + +### Verdict +ALL-PASS | FAILURES + +### Per-criterion results +- ✅ AC-1: — covered by e2e/:L +- ❌ AC-2: — failed (expected X, got Y) — e2e/:L +- ⚠️ AC-3: — not coverable from UI, reason: … + +### Defects to bounce back +- File / endpoint where the implementation diverged from the criterion +- Which builder owns the fix (backend-builder / frontend-builder) +``` + +When verdict is ALL-PASS → notify the team-lead, sprint is ready for PR. When FAILURES → team-lead routes back to the relevant builder. + +## Principle + +> "You don't have a feature until the acceptance tests pass." diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..59ad317 --- /dev/null +++ b/.gitignore @@ -0,0 +1,91 @@ +# --- Claude Code worktrees (never commit) --- +.claude/worktrees/ + +# --- Secrets & env --- +.env +.env.* +!.env.example +*.pem +*.key +credentials* +secrets* + +# --- Python --- +__pycache__/ +*.py[cod] +*$py.class +*.so +.Python +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +*.egg-info/ +.installed.cfg +*.egg +MANIFEST + +# Virtual envs +.venv/ +venv/ +env/ +ENV/ + +# pytest / coverage / mypy / ruff +.pytest_cache/ +.coverage +.coverage.* +htmlcov/ +.cache +.tox/ +.nox/ +.mypy_cache/ +.ruff_cache/ + +# SQLite local dbs +*.sqlite +*.sqlite3 +*.db + +# --- Node / Frontend --- +node_modules/ +npm-debug.log* +yarn-debug.log* +yarn-error.log* +pnpm-debug.log* +.pnpm-store/ + +# Vite / build outputs +frontend/dist/ +frontend/.vite/ +*.local + +# --- Playwright --- +e2e/test-results/ +e2e/playwright-report/ +e2e/playwright/.cache/ + +# --- Editors / OS --- +.vscode/ +.idea/ +*.swp +*.swo +.DS_Store +Thumbs.db + +# --- Docker --- +*.pid + +# --- Build artifacts / payloads (per CLAUDE.md OPSEC) --- +*.exe +*.dll +*.bin +*.o +*.obj +*.exp +*.lib + +# --- MITRE bundle if huge (kept by default — uncomment to ignore) --- +# backend/data/mitre/enterprise-attack.json diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..79ddff7 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,19 @@ +# Changelog + +All notable changes to Mimic are tracked here. + +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/) and this project adheres to [Semantic Versioning](https://semver.org/). + +## [Unreleased] + +### Added +- Initial `SPEC.md` covering project scope, simulation model, workflow, stack, and agent team. +- Technical decisions section in `SPEC.md`: 3-role auth (admin/redteam/soc), JWT Bearer, single-container Flask+React, local MITRE STIX bundle, minimal Engagement model, admin bootstrap via Makefile target. +- Sub-agent definitions under `.claude/agents/` for backend-builder, frontend-builder, spec-reviewer (project override of the built-in, covers plan-vs-spec and code-vs-spec), code-reviewer, test-verifier, devil-advocate. +- Project tracking scaffold: `tasks/todo.md`, `tasks/lessons.md`, `CHANGELOG.md`, `.gitignore`. + +### Changed +- 2026-05-26 — `admin` role widened in `SPEC.md` § Décisions techniques. The initial draft restricted admin to user-management only; after the Sprint 1 plan review surfaced the operational pain (admin would need a second `redteam` account just to manage engagements), the user decided to make admin a super-user that cumulates redteam rights on engagements/simulations. + +### Removed +- _none_ diff --git a/SPEC.md b/SPEC.md index f5a82e8..af566d0 100644 --- a/SPEC.md +++ b/SPEC.md @@ -111,4 +111,101 @@ Pour ce projet, j'ai besoin d'une équipe d'agent réparti de la manière suivan - Quand tout est ok pour le test verifier en informer le team lead afin qu'il prépare la PR. 6. Devil advocate : **modèle Opus** - Dans le cas de questions structurantes sur le projet, faire intervenir cet agent en tant que tierce personne n'ayant pas connaissance de tout le projet mais permettant d'avoir un regarde neuf sur ces questions. - \ No newline at end of file + +# Décisions techniques + +Décisions arrêtées avec l'utilisateur au démarrage du projet. Ces choix doivent guider les sprints et peuvent évoluer — toute évolution est tracée dans le `CHANGELOG.md`. + +## Authentification & rôles +* **Trois rôles** : `admin`, `redteam`, `soc`. + - `admin` : super-user. Gestion des comptes (CRUD users) **et** CRUD complet sur engagements/simulations (cumule les droits de redteam). Décision élargie le 2026-05-26 pour éviter qu'un admin doive se créer un second compte redteam pour gérer les engagements opérationnellement. + - `redteam` : CRUD complet sur engagements et simulations (tous champs). + - `soc` : lecture des simulations, écriture restreinte à la partie SOC (logs, sources, commentaires, n° incident). +* **Méthode** : JWT Bearer token (login `/api/auth/login` → access token). Refresh token à décider plus tard si besoin. +* **Mot de passe** : hash argon2 (ou bcrypt si argon2 indisponible). +* **Création de comptes** : par admin uniquement via UI. Pas de self-registration. +* **Bootstrap du 1er admin** : commande Flask `flask create-admin ` exposée via une target Makefile (`make create-admin USER=… PASS=…`) qui wrap `docker exec mimic flask create-admin …`. Aucun credential par défaut, aucun secret persisté en `.env`. + +## Modèle de données — V1 + +### `User` +| Champ | Type | Notes | +|---|---|---| +| id | int (PK) | | +| username | str unique | | +| password_hash | str | argon2/bcrypt | +| role | enum(admin/redteam/soc) | | +| created_at | datetime | | + +### `Engagement` +Modèle **minimal** Sprint 1 (extensible plus tard) : +| Champ | Type | Notes | +|---|---|---| +| id | int (PK) | | +| name | str | requis | +| description | text | optionnel | +| start_date | date | requis | +| end_date | date | optionnel, ≥ start_date | +| status | enum(planned/active/closed) | défaut `planned` | +| created_at | datetime | | +| created_by | FK User | | + +### `Simulation` (Sprint 2+) +Conforme à la spec (partie RedTeam + partie SOC). Workflow Pending → In progress → Review required → Done. Détaillé dans le sprint correspondant. + +## Référentiel MITRE ATT&CK +* **Bundle local** : JSON officiel STIX 2.1 MITRE Enterprise embarqué dans l'image (`backend/data/mitre/enterprise-attack.json`). +* Pas d'appel réseau au runtime. Seed/refresh manuel via `make update-mitre`. +* Utilisé au Sprint 2+ pour l'autocomplete des TTPs (T-id + nom + tactique). + +## Stack technique précisée +* **Backend** : Python 3.12, Flask, SQLAlchemy, Alembic, pytest, ruff, mypy. Auth via `PyJWT` + middleware decorator. +* **Frontend** : React 18, Vite, TailwindCSS, TanStack Query, React Router, Vitest pour les unit tests composants. +* **Tests acceptance** : Playwright (TS), exécutés dans le container ou via runner CI. +* **Conteneurisation** : **Container unique** — Flask sert l'API sous `/api/*` et le build statique de Vite (`frontend/dist`) sous `/`. Un seul `Dockerfile` multistage (stage Node pour build front, stage Python pour run). +* **Makefile** : targets `build`, `start`, `stop`, `restart`, `update`, `logs`, `create-admin USER=… PASS=…`, `update-mitre`, `test-backend`, `test-frontend`, `test-e2e`. + +## Arborescence cible +``` +mimic/ +├── backend/ +│ ├── app/ +│ │ ├── __init__.py # create_app() factory +│ │ ├── config.py +│ │ ├── extensions.py # db, migrate +│ │ ├── models/ +│ │ ├── api/ # blueprints +│ │ ├── services/ +│ │ ├── auth/ # jwt, decorators +│ │ └── cli.py # flask create-admin +│ ├── migrations/ # alembic +│ ├── tests/ +│ ├── data/mitre/ +│ ├── pyproject.toml +│ └── requirements.txt +├── frontend/ +│ ├── src/ +│ │ ├── components/ +│ │ ├── pages/ +│ │ ├── hooks/ +│ │ ├── api/ # client + types +│ │ └── styles/ +│ ├── tests/ +│ ├── package.json +│ ├── vite.config.ts +│ └── tailwind.config.ts +├── e2e/ # Playwright tests +├── docker/ +│ └── Dockerfile +├── tasks/ # plans sprint, lessons +├── DESIGN.md +├── SPEC.md +├── README.md +├── CHANGELOG.md +└── Makefile +``` + +## Workflow git +* Branche par sprint : `sprint/-` (ex : `sprint/1-auth-engagements`). +* Sous-branches par builder si besoin : `sprint/1-auth-engagements/backend`, `…/frontend`. +* PR à la fin du sprint, validée par l'utilisateur après récap synthétique du team-lead. diff --git a/tasks/lessons.md b/tasks/lessons.md new file mode 100644 index 0000000..77c7fcf --- /dev/null +++ b/tasks/lessons.md @@ -0,0 +1,7 @@ +# Lessons Learned + +Recurring mistakes and the rule we adopted so the same issue doesn't bite twice. Append-only. Each entry has: date, context, lesson. + +--- + +_(empty — to be filled by the team-lead at the end of each sprint, with input from builders and reviewers)_ diff --git a/tasks/todo.md b/tasks/todo.md new file mode 100644 index 0000000..e6905f0 --- /dev/null +++ b/tasks/todo.md @@ -0,0 +1,315 @@ +# Sprint 1 — Auth + CRUD Engagement + +**Branche** : `sprint/1-auth-engagements` +**Statut** : 🟢 PLAN APPROUVÉ (spec-reviewer 2026-05-26) — prêt pour dispatch backend-builder +**Base** : `main` +**Objectif** : poser l'infrastructure (Flask + SQLite + React + Docker + Makefile + tests) ET livrer une première feature de bout en bout testable sur l'UI — login + admin gère les comptes + tout utilisateur authentifié peut créer/lister/éditer/supprimer des engagements. + +--- + +## 1. User stories + +### US-1 — En tant qu'admin, je bootstrap le premier compte admin +**Pourquoi** : sinon impossible d'utiliser l'application au premier démarrage. + +**Critères d'acceptation** +- [ ] AC-1.1 : la commande `make create-admin USER=alice PASS=p4ssw0rd` crée un user `alice` avec le rôle `admin` et le password hashé (argon2). +- [ ] AC-1.2 : la commande échoue proprement (exit ≠ 0, message clair) si le username existe déjà. +- [ ] AC-1.3 : la commande échoue si le password fait moins de 8 caractères. +- [ ] AC-1.4 : la commande s'exécute via `docker exec mimic flask create-admin …` (le Makefile encapsule cet appel). + +### US-2 — En tant qu'utilisateur, je me connecte et me déconnecte +**Pourquoi** : porte d'entrée de l'application. + +**Critères d'acceptation** +- [ ] AC-2.1 : `POST /api/auth/login {username, password}` retourne `{access_token, user: {id, username, role}}` (200) si credentials valides. +- [ ] AC-2.2 : 401 si credentials invalides, avec un message générique ("Invalid credentials") — pas de fuite username vs password. +- [ ] AC-2.3 : `POST /api/auth/logout` invalide le token côté client (UI supprime le token). Côté serveur : optionnel V1, on accepte un logout client-side. +- [ ] AC-2.4 : page `/login` affiche le formulaire ; soumission OK → redirection `/engagements`. Soumission KO → message d'erreur visible. +- [ ] AC-2.5 : navigation vers `/engagements` sans token → redirection `/login`. +- [ ] AC-2.6 : si une requête API retourne 401 (token expiré ou invalide), l'intercepteur axios purge le token et redirige vers `/login` avec un toast "Session expirée". + +### US-3 — En tant qu'admin, je gère les comptes utilisateurs +**Pourquoi** : créer redteam/soc accounts depuis l'UI. + +**Critères d'acceptation** +- [ ] AC-3.1 : `GET /api/users` (admin only) → liste `[{id, username, role, created_at}]`. +- [ ] AC-3.2 : `POST /api/users {username, password, role}` (admin only) → 201 + objet user (sans password_hash). 400 si username existe ou password < 8 chars. +- [ ] AC-3.3 : `PATCH /api/users/ {role?, password?}` (admin only) → 200, modifie role et/ou password. +- [ ] AC-3.4 : `DELETE /api/users/` (admin only) → 204. Refuse de supprimer le dernier admin (409). +- [ ] AC-3.5 : tout autre rôle (redteam/soc) appelant ces endpoints reçoit 403. +- [ ] AC-3.6 : page `/admin/users` (admin only) liste les users avec actions "Créer", "Modifier rôle", "Reset password", "Supprimer". +- [ ] AC-3.7 : un user redteam/soc qui visite `/admin/users` est redirigé vers `/engagements` avec un toast "Accès refusé". + +### US-4 — En tant qu'utilisateur authentifié, je gère les engagements +**Pourquoi** : la feature métier centrale du Sprint 1. + +**Critères d'acceptation** +- [ ] AC-4.1 : `GET /api/engagements` (auth) → `[{id, name, description, start_date, end_date, status, created_at, created_by}]`. +- [ ] AC-4.2 : `POST /api/engagements {name, description?, start_date, end_date?, status?}` (auth) → 201. Valide : `name` non vide, `start_date` parseable, `end_date >= start_date` si fournie, `status ∈ {planned, active, closed}` (défaut `planned`). +- [ ] AC-4.3 : `GET /api/engagements/` (auth) → 200 + objet, 404 si inconnu. +- [ ] AC-4.4 : `PATCH /api/engagements/` (auth, redteam ou admin) → 200, modifie les champs fournis. +- [ ] AC-4.5 : `DELETE /api/engagements/` (admin ou redteam) → 204. +- [ ] AC-4.6 : un user `soc` peut lire (GET) mais pas créer/modifier/supprimer (403). +- [ ] AC-4.7 : page `/engagements` liste les engagements avec colonnes (name, status badge, dates, created_by). Boutons "Nouveau", "Voir", "Éditer", "Supprimer" selon rôle. +- [ ] AC-4.8 : page `/engagements/new` et `/engagements//edit` (formulaire avec validation côté client + erreurs API affichées). +- [ ] AC-4.9 : page `/engagements/` (détail), placeholder "Simulations à venir au Sprint 2". + +### US-5 — En tant qu'utilisateur, l'UI respecte DESIGN.md +**Pourquoi** : non négociable selon SPEC.md. + +**Critères d'acceptation** +- [ ] AC-5.1 : la palette, typographie, espacements, composants (boutons, inputs, badges) suivent strictement `DESIGN.md`. +- [ ] AC-5.2 : layout responsive desktop-first (≥ 1024px), pas de breakage visible jusqu'à 1280×720 minimum. +- [ ] AC-5.3 : états loading / error / empty implémentés pour la liste d'engagements et la liste d'users. + +### US-6 — Le livrable se déploie via Docker + Makefile +**Pourquoi** : exigence SPEC.md. + +**Critères d'acceptation** +- [ ] AC-6.1 : `make build` produit l'image docker `mimic:latest` (Dockerfile multistage : Node build → Python runtime). +- [ ] AC-6.2 : `make start` lance le container, l'app est accessible sur `http://localhost:5000` (front + API). +- [ ] AC-6.3 : `make stop`, `make restart`, `make logs` fonctionnent. +- [ ] AC-6.4 : SQLite persisté via volume nommé `mimic-data` (la DB survit à `make restart`). +- [ ] AC-6.5 : `make test-backend`, `make test-frontend`, `make test-e2e` exécutent les suites respectives. + +--- + +## 2. Brief technique — Backend Builder + +**Scope strict** : `backend/`, `Dockerfile`, `Makefile` (en collab avec ce sprint uniquement). + +### Livrables +1. **Structure** : + ``` + backend/ + __init__.py # ⚠️ requis pour que `backend.app:create_app` soit importable depuis /app dans le Dockerfile + app/ + __init__.py # create_app() factory + config.py # DevConfig / ProdConfig (SECRET_KEY, JWT_SECRET, SQLALCHEMY_DATABASE_URI) + extensions.py # db = SQLAlchemy(), migrate = Migrate() + cli.py # @app.cli.command("create-admin") + models/ + __init__.py + user.py # User(id, username, password_hash, role, created_at) + engagement.py # Engagement(id, name, description, start_date, end_date, status, created_at, created_by) + auth/ + __init__.py + jwt.py # encode_token / decode_token + hashing.py # argon2 hash & verify + decorators.py # @login_required, @role_required("admin") + api/ + __init__.py + auth.py # /login, /logout, /me + users.py # CRUD users (admin) + engagements.py # CRUD engagements + serializers.py # to_dict() helpers — engagement renvoie created_by={id, username}, jamais l'objet User brut + errors.py # uniform JSON error handler + migrations/ # alembic init + 0001 initial schema + tests/ + conftest.py # app fixture, db fixture, auth helpers + test_auth.py # login OK + 401 invalid + 401 token expiré + test_users.py # CRUD admin only, 403 redteam/soc, last-admin protection (AC-3.4) + test_engagements.py # CRUD redteam/admin, 403 soc en write, serializer created_by + test_cli_create_admin.py # success + duplicate username (AC-1.2) + password < 8 chars (AC-1.3) + pyproject.toml + requirements.txt # flask, flask-sqlalchemy, flask-migrate, pyjwt, argon2-cffi, ruff, mypy, pytest + ``` + +2. **Endpoints** : voir critères AC-2 / AC-3 / AC-4. +3. **Modèles** : voir SPEC.md § Modèle de données. +4. **Config** : + - `SQLALCHEMY_DATABASE_URI = f"sqlite:///{os.environ.get('MIMIC_DB_PATH', '/data/mimic.sqlite')}"` — l'env var `MIMIC_DB_PATH` du Dockerfile surcharge le chemin si présent (utile pour tests ou changement de mount). + - `JWT_SECRET` lu depuis env var `MIMIC_JWT_SECRET`, requis (raise si absent en Prod). + - `JWT_EXP_MINUTES = 60`. +5. **CLI** : `flask create-admin ` (avec validations AC-1.2/1.3). +6. **Serializer engagement** : la réponse JSON expose `created_by` sous forme `{"id": , "username": }` — pas l'objet User complet, pas seulement l'id. +7. **Tests** : couverture success / failure / edge sur chaque endpoint et CLI. Les AC-1.2 et AC-1.3 doivent avoir leur propre test dans `test_cli_create_admin.py`. +8. **Lint / typing** : ruff clean, mypy clean sur `app/`. + +### Règles +- Pas de touche au frontend. +- Pas d'invention de dépendances hors de la liste ci-dessus sans escalade au team-lead. +- Renvoyer le summary attendu (cf. `.claude/agents/backend-builder.md`). + +--- + +## 3. Brief technique — Frontend Builder + +**Scope strict** : `frontend/` UNIQUEMENT. Le dossier `e2e/` est **interdit** au frontend-builder — il est sous la responsabilité exclusive du test-verifier (scaffolding Playwright + tests). + +### Livrables +1. **Structure** : + ``` + frontend/ + package.json # react, react-dom, react-router-dom, @tanstack/react-query, axios, tailwindcss, vite, typescript, vitest, @testing-library/react + vite.config.ts # proxy /api -> http://localhost:5000 en dev + tailwind.config.ts # tokens issus de DESIGN.md, font-family principale = "Inter" + tsconfig.json + index.html + src/ + main.tsx + App.tsx # router, QueryClientProvider + api/ + client.ts # axios + interceptor (Bearer + 401 purge → /login) + auth.ts # login, me + users.ts # CRUD users + engagements.ts # CRUD engagements + types.ts + hooks/ + useAuth.ts # token in memory + localStorage, role helpers (isAdmin, isRedteam, isSoc) + useEngagements.ts # TanStack Query hooks + useUsers.ts + useToast.ts # provider + hook pour notifications éphémères + pages/ + LoginPage.tsx + EngagementsListPage.tsx + EngagementFormPage.tsx # new + edit + EngagementDetailPage.tsx + UsersAdminPage.tsx + components/ + Layout.tsx # nav, topbar, role-aware menu + ProtectedRoute.tsx # redirect to /login if no token, role gate + StatusBadge.tsx + FormField.tsx + EmptyState.tsx + ErrorState.tsx + LoadingState.tsx + Toast.tsx # composant + ToastProvider (utilisé par AC-2.6 + AC-3.7) + styles/ + index.css # tailwind base + DESIGN.md tokens + fonts.css # @font-face Inter (bundlée localement dans public/fonts/, AUCUN CDN) + public/ + fonts/ # fichiers Inter .woff2 (déposés via npm install + copie post-install, ou commit direct) + tests/ + components/*.test.tsx # Vitest + ``` + +2. **Police** : `Inter` (substitut Forma DJR Micro choisi par défaut parmi les 3 options DESIGN.md §86-89). Bundlée localement en `.woff2`, jamais via Google Fonts/CDN. Configurée dans `tailwind.config.ts` comme `font-sans` et chargée via `@font-face` dans `styles/fonts.css`. + +3. **Routing** : + - `/login` + - `/engagements` (auth, all roles) + - `/engagements/new` (auth, redteam|admin) + - `/engagements/:id` (auth, all roles) + - `/engagements/:id/edit` (auth, redteam|admin) + - `/admin/users` (auth, admin only) + - `/` → redirige vers `/engagements` ou `/login` + +4. **Auth** : token JWT en mémoire + `localStorage` ; intercepteur axios ajoute `Authorization: Bearer ` ; 401 → purge token + redirect `/login` + toast "Session expirée" (AC-2.6). + +5. **Tests Vitest** : 1 test par composant non trivial (états loading/error/empty, comportement des rôles dans `ProtectedRoute`, Toast déclenché par 401). + +### Règles +- Lit le summary du backend-builder EN PREMIER. +- Pas d'invention d'endpoints. Mismatch → escalade au team-lead. +- Respect strict de `DESIGN.md` pour palette/typo/composants. +- Pas de CDN remote au runtime — bundle local (police Inter incluse). +- **Interdiction absolue de toucher `e2e/`** (responsabilité test-verifier). + +--- + +## 4. Brief — Docker / Makefile (réalisé par le backend-builder) + +### `docker/Dockerfile` (multistage) +```dockerfile +# Stage 1: build front +FROM node:20-alpine AS frontend-build +WORKDIR /app/frontend +COPY frontend/package*.json ./ +RUN npm ci +COPY frontend/ ./ +RUN npm run build + +# Stage 2: python runtime +FROM python:3.12-slim +WORKDIR /app +COPY backend/requirements.txt ./backend/ +RUN pip install --no-cache-dir -r backend/requirements.txt +COPY backend/ ./backend/ +COPY --from=frontend-build /app/frontend/dist ./backend/app/static + +ENV FLASK_APP=backend.app:create_app +ENV PYTHONUNBUFFERED=1 +ENV PYTHONPATH=/app +# Variables surchargeables au `docker run` : +ENV MIMIC_PORT=5000 +ENV MIMIC_DB_PATH=/data/mimic.sqlite + +VOLUME ["/data"] +EXPOSE 5000 + +# Entrypoint : applique les migrations Alembic puis lance Flask +COPY docker/entrypoint.sh /entrypoint.sh +RUN chmod +x /entrypoint.sh +ENTRYPOINT ["/entrypoint.sh"] +``` + +**`docker/entrypoint.sh`** : +```bash +#!/bin/sh +set -e +flask db upgrade +exec flask run --host=0.0.0.0 --port="${MIMIC_PORT:-5000}" +``` + +Flask sert `backend/app/static` en racine `/` ET expose les blueprints sous `/api/*`. La DB SQLite vit dans `/data/mimic.sqlite` (volume nommé `mimic-data`) — survit à `make restart` (AC-6.4). + +### `Makefile` +Targets requis et leur sémantique : + +| Target | Action | +|---|---| +| `build` | `docker build -f docker/Dockerfile -t mimic:latest .` | +| `start` | `docker run -d --name mimic -p $(PORT):5000 -v mimic-data:/data --env-file .env mimic:latest` (`PORT ?= 5000`) | +| `stop` | `docker stop mimic && docker rm mimic` | +| `restart` | `$(MAKE) stop && $(MAKE) start` | +| `update` | `git pull && $(MAKE) build && $(MAKE) restart` | +| `logs` | `docker logs -f mimic` | +| `create-admin` | `docker exec mimic flask create-admin $(USER) $(PASS)` (requiert `USER=` et `PASS=`) | +| `update-mitre` | placeholder no-op Sprint 1 (`@echo "MITRE update: Sprint 2+"`) | +| `test-backend` | `docker exec mimic pytest -q backend/tests/` (ou run local en venv) | +| `test-frontend` | `cd frontend && npm run test -- --run` | +| `test-e2e` | `cd e2e && npx playwright test` (container doit être up) | +| `clean` | `docker rm -f mimic 2>/dev/null; docker volume rm mimic-data 2>/dev/null; rm -rf backend/__pycache__ frontend/node_modules frontend/dist` | + +--- + +## 5. Definition of Done — Sprint 1 + +- [ ] Tous les critères d'acceptation des US 1→6 passent. +- [ ] `pytest`, `ruff`, `mypy` clean côté backend. +- [ ] `npm run typecheck`, `lint`, `test` clean côté frontend. +- [ ] Playwright suite verte côté `e2e/`. +- [ ] Image docker se build (`make build`), démarre (`make start`), répond sur `:5000`. +- [ ] Code review (Opus) sans BLOCKER ouvert. +- [ ] `SPEC.md`, `README.md`, `CHANGELOG.md` à jour. +- [ ] PR ouverte sur la branche sprint, validée par l'utilisateur après récap synthétique. + +--- + +## 6. Risques & questions à clarifier avec l'utilisateur AVANT de coder + +1. **DESIGN.md** : faut-il que je relise DESIGN.md (27 Ko, déjà présent dans le repo) avant que le frontend-builder l'utilise ? OUI +2. **Persistance SQLite** : DB stockée dans `/data/mimic.sqlite` montée comme volume nommé `mimic-data`. OK ? OK +3. **Port** : `5000` (Flask défaut). Conflit possible avec macOS AirPlay si jamais — on s'en fiche en Linux. Surcharge du port possible via dockerfile et container. +4. **CSRF** : on est en API JWT pure, pas de cookie session, donc pas de CSRF protection nécessaire côté serveur. OK ? OK +5. **Refresh token** : exclu V1. JWT court (60 min) ; user devra se reconnecter. OK ? OK +6. **Logout** : V1 = client-side uniquement (purge du token). Pas de blacklist. OK ? OK +7. **CI** : pas mentionné dans la spec. Skip pour Sprint 1 ? (à confirmer) On verra plus tard. +8. **README.md** : actuellement absent. Le team-lead le crée en fin de Sprint 1 avec instructions `make build / start / create-admin`. OK. + +--- + +## 7. Plan d'exécution (séquence) + +**Branche unique pour ce sprint** : `sprint/1-auth-engagements` (pas de sous-branches builders, le sprint est séquentiel). + +1. ✅ **Spec-reviewer** (`.claude/agents/spec-reviewer.md`, override projet du built-in) valide ce plan vs SPEC.md. +2. 🔵 **Backend-builder** implémente `backend/` + `docker/Dockerfile` + `docker/entrypoint.sh` + `Makefile`, livre son summary (incluant le contrat API). +3. 🔵 **Frontend-builder** lit le summary backend puis implémente le front (`frontend/` UNIQUEMENT, jamais `e2e/`). +4. 🔵 **Code-reviewer** relit le diff du sprint (LSP-first, focus bugs/qualité/scope). +5. 🔵 **Test-verifier** **scaffolds** `e2e/` (Playwright config, package.json, fixtures auth) **puis écrit** les acceptance tests Playwright et exécute la suite contre le container démarré via `make start`. +6. 🟢 **Team-lead** (moi) prépare la PR + récap synthétique → user valide. + +**Responsabilité `e2e/`** : exclusivement le test-verifier. Backend-builder et frontend-builder n'y touchent jamais.