Knacky 6995c4c860 fix(design): address design-reviewer findings F1-F6 — nav slab, spinner, badge coverage, mono discipline
F3: nav-bar-top bg-paper → bg-slab text-slab-text (3-band slab anchoring restored).
    NavLinks: text-slab-muted default, text-slab-text + border-primary active.
    Logo span: text-ink → text-slab-text.
F2: (you) label extracted from font-mono td into adjacent font-sans span.
F1: Loader2 circular spinner → EXPORTING… text with animate-pulse (terminal-SOC compatible).

Screenshots regenerated:
- All 8 pages light+dark (01→10)
- 05-simulation-form-edit light+dark (F6)
- 11-mitre-matrix-modal light+dark (F6)
- 12-toast-success light+dark (F6)
- 13-confirm-dialog light+dark (F6)
- admin-light/dark-open/closed regenerated from HEAD (F4)

F4: StatusBadge.tsx confirmed single code path — planned → bg-warn-soft (no divergence in code).
    Divergence in prior captures was stale cache; regenerated admin-* confirm consistency.
F5: Simulations seeded (pending/in_progress/review_required/done) via API;
    10-sim-list-badges shows all 4 semantic badge colors.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-09 19:43:08 +02:00

Mimic

Mimic is a Breach and Attack Simulation (BAS) web UI built on the MITRE ATT&CK matrix. It replaces the flat Excel spreadsheets that red-teams and SOC analysts pass around at the end of an engagement, providing a shared workspace for Purple Team handoffs.

Status: Sprint 6 — Engagement export. Admin/redteam can now export an engagement to Markdown, CSV, or PDF in one click from EngagementDetailPage. The export contains the engagement header and all simulations with both Red Team and SOC fields — closing the "replace the shared Excel" loop. CSV cells are defused against spreadsheet formula injection. SOC has no access to the export.


Quick start

Prerequisites: Docker (or Podman) + GNU Make. Linux/macOS host.

# 1. Configure secrets
cp .env.example .env
# Edit .env and set MIMIC_JWT_SECRET to a strong random value:
#   sed -i "s|replace-me-with-a-strong-random-secret|$(openssl rand -hex 32)|" .env

# 2. Build and start the container
make build
make start

# 3. Bootstrap the first admin (run once, the container must be up)
make create-admin USER=alice PASS=changeme8

# 4. Open the UI
xdg-open http://localhost:5000     # Linux
# or visit http://localhost:5000 manually

Log in with the credentials from step 3. The admin can create additional users (redteam / soc) from /admin/users.

To stop or restart:

make stop
make restart      # stop + start, preserves the SQLite volume
make logs         # tail container logs

To override the host port:

make start PORT=8080

Architecture

Single-container deployment. A multistage Dockerfile builds the Vite frontend, then copies the static assets into the Flask backend image so Flask serves both the API (under /api/*) and the SPA (everything else).

┌───────────────────────────────────────────┐
│ Container: mimic:latest                   │
│                                           │
│  Flask (Python 3.12)                      │
│   ├── /api/* ── blueprints (auth, users,  │
│   │              engagements, simulations,│
│   │              mitre)                   │
│   └── /     ── SPA fallback → React build │
│                                           │
│  SQLAlchemy ── SQLite at /data/mimic.sqlite │
│                       (volume: mimic-data)│
└───────────────────────────────────────────┘
  • Auth: JWT Bearer tokens (HS256, 60-min TTL). Stateless — no refresh tokens, no server-side session.
  • Roles: admin (super-user — cumulates redteam rights on engagements/simulations), redteam (CRUD engagements + simulations, full field access), soc (read everything, write-only on the SOC half of simulations once the redteam marks them review_required).
  • Password hashing: argon2 via argon2-cffi.
  • Migrations: Alembic, applied automatically by the container entrypoint (flask db upgrade && flask run).
  • MITRE ATT&CK: STIX 2.1 Enterprise bundle committed at backend/data/mitre/enterprise-attack.json and indexed at app boot. make update-mitre re-fetches the latest bundle and (if the container is running) restarts it to reload the index. The endpoint GET /api/mitre/techniques?q= powers the autocomplete on simulations.
  • Simulation workflow: Pending → In progress (auto-transition when redteam saves any non-empty field) → Review required (manual, redteam) → Done (manual, redteam or SOC). The state machine is enforced server-side; the UI surfaces the appropriate transition button per role + current state.

See SPEC.md § "Décisions techniques" for the full architecture rationale and DESIGN.md for the UI design system.


Project layout

mimic/
├── backend/         # Flask app, SQLAlchemy models, Alembic migrations, pytest suite
├── frontend/        # Vite + React + Tailwind + TanStack Query, Vitest suite
├── e2e/             # Playwright acceptance tests (one spec per user story)
├── docker/          # Dockerfile (multistage) + entrypoint.sh
├── tasks/           # Sprint plans (tasks/todo.md) and lessons (tasks/lessons.md)
├── .claude/agents/  # Sub-agent definitions for the team (read-only at runtime)
├── Makefile         # all operational entry points
├── SPEC.md          # functional + technical spec
├── DESIGN.md        # UI design system (palette, typography, components)
└── CHANGELOG.md

Make targets

Target What it does
make build Build the mimic:latest container image (multistage: Node → Python). Uses docker if installed, otherwise podman — override with make build CONTAINER_CMD=podman
make start Start the container (port from PORT, default 5000; mounts mimic-data volume)
make stop Stop and remove the container
make restart make stop && make start — preserves the SQLite volume
make update git pull && make build && make restart
make logs docker logs -f mimic
make create-admin USER=… PASS=… Run flask create-admin inside the container
make update-mitre Fetch the latest MITRE STIX 2.1 Enterprise bundle into backend/data/mitre/; auto-restart the container if running. Commit the resulting file change manually.
make test-backend pytest -q inside the container
make test-frontend npm run test -- --run in frontend/
make test-e2e Playwright acceptance suite (container must be running)
make clean Remove container + volume + Python/Node caches
make open-pr TITLE="…" BODY=path Open a PR on the Gitea repo for the current branch via the REST API. Reads credentials from ~/.git-credentials (same source as git push) — no token in env. Wraps scripts/open-pr.sh. Defaults BASE=main.

Development (without Docker)

Backend:

cd backend
python -m venv .venv && source .venv/bin/activate
pip install -r requirements.txt
export MIMIC_JWT_SECRET=dev-secret
export MIMIC_DB_PATH=./mimic.sqlite
flask --app backend.app:create_app db upgrade
flask --app backend.app:create_app run --port 5000

Frontend:

cd frontend
npm install
npm run dev          # http://localhost:5173 with /api proxied to :5000

Tests:

cd backend && pytest -q                # 253 tests
cd frontend && npm run test -- --run   # 136 tests
cd e2e && npx playwright test          # 223 tests (needs container up — use MIMIC_BASE_URL=http://127.0.0.1:5000 if localhost resolves to IPv6)

Documentation


License

Internal project — not yet open-sourced.

Description
No description provided
Readme 9.2 MiB
Languages
TypeScript 59.7%
Python 39%
CSS 0.5%
Shell 0.4%
Makefile 0.2%
Other 0.1%