dd5c508b04b825232b39d8ba85f2702c8c06db99
Two issues spotted by ux-frontend consuming docs/api.md against the actual
code path:
1. `flask.abort(...)` returned the Werkzeug HTML error page for 400/403/404/
422/etc. — only the 401 paths going through `api_error()` and the
Flask-Login `unauthorized_handler` honoured the `{error, message}`
envelope the contract promised. The frontend's `ApiClientError.body`
parser was forced to fall back to a raw string, and the 422 case
could not surface Pydantic per-field errors.
Fix: register `@app.errorhandler(HTTPException)` that serialises every
`HTTPException` to the same JSON envelope. 422s gain a `details: [...]`
field holding the Pydantic `errors()` list (`loc` / `msg` / `type`),
matching the shape now documented in `docs/api.md`.
A `_HTTP_ERROR_CODES` map maps statuses to stable snake_case codes
(`bad_request`, `not_found`, `method_not_allowed`,
`validation_error`, `forbidden`, `internal_error`, ...). Unknown
statuses fall back to `http_error`.
`description` is `cast(object, ...)` because the Werkzeug stub pins it
to `str | None` while `flask.abort(..., description=<list>)` is the
officially supported way to smuggle a Pydantic errors list to the
handler.
2. `@bp.get("")` on the engagements blueprint produced `/api/v1/engagements`
(no slash). Hitting it with a trailing slash issued a 308 redirect,
and some browsers drop the session cookie across that hop.
Fix: `app.url_map.strict_slashes = False`. Both forms now match the
same handler without redirect.
5 new integration tests cover the new envelope shape (422 with details,
unknown 404, malformed-JSON 400) and the dual-slash matching. `docs/api.md`
rewritten to reflect the table of stable codes, the `details` shape, and
the no-trailing-slash convention. `CHANGELOG.md` gains a follow-up entry.
Verification: ruff check / mypy --strict / pytest tests/unit all green
(61 unit + 5 new integration).
Mimic
Internal BAS (Breach & Attack Simulation) platform for the Red Team. Replays TTPs from engagement journals or an internal ATT&CK library against client infrastructure through VPN/relay, in white-glove coordination with the SOC.
Output: a coverage report mapped to MITRE ATT&CK — measurable, reproducible, archived.
Status
ready-with-prereqs — spec frozen on 2026-05-19, 23 review patches integrated.
Code start blocked on:
- PR1 — Mythic API documentation + pinned version (lead RT)
- PR2 — Internal C2 interface spec + journal export example (internal C2 team)
- PR3 — RT graphic charter for the PDF report (lead RT)
While PR1/PR2/PR3 are open, sprint 0 focuses on the unblocked skeleton.
Spec
The authoritative spec lives in the RT-SecondBrain vault:
Projects/Mimic — Spec.md. Do not duplicate it here.
In-repo documentation:
CHANGELOG.md— chronological log of features, decisions, rollbacks.tasks/spec-decisions.md— implementation arbitrations on top of the spec.tasks/todo.md— current sprint backlog.
Stack (frozen)
- Backend Python 3.12 / Flask / Flask-SocketIO / SQLAlchemy 2 / Pydantic 2 / Alembic / WeasyPrint / pytest + testcontainers / ruff / mypy strict
- Frontend TypeScript / React 18+ / Vite / Tailwind 4 / TanStack Query 5 / Recharts / Playwright
- Storage Postgres (prod) / SQLite (pure-logic unit tests) / testcontainers Postgres (audit log, RBAC, write-only role — incl. unit tests of Postgres-specific behavior, per H38)
- Deploy Docker images + Ansible deployment playbook (per D-010). Reverse proxy (Caddy + TLS + IP allowlist) handled by existing RT infrastructure, out of Mimic scope (D-007).
Layout
mimic/
├── backend/ # Flask app, connectors, orchestrator, reporting, CLI
├── frontend/ # Vite + React app
├── docs/ # Architecture notes, ADRs, deployment
└── tasks/ # Sprint backlog, decisions, lessons
Conventions
- Branches:
feature/<scope>,fix/<scope>,docs/<scope>,chore/<scope>. Long-lived:main. - Commits: Conventional Commits (
feat:,fix:,chore:,docs:,test:,refactor:). - PRs: each branch → review (
code-reviewer) → team-lead merges. No direct push tomain.
Build & run
make targets land at the end of sprint 0. For now the repo is skeleton-only.
Licensing
Internal — proprietary, RT use only. Do not redistribute.
Description
Languages
Python
53.4%
TypeScript
39.4%
CSS
4.6%
Dockerfile
1%
Makefile
0.8%
Other
0.8%