From 047583eb9c6f13e4a4a4165baa277d8db4dbdaa4 Mon Sep 17 00:00:00 2001 From: knacky Date: Thu, 21 May 2026 20:10:47 +0200 Subject: [PATCH] chore: bootstrap repo skeleton with sprint 0 plan - .gitignore (Python, Node, RT/maldev hygiene, secrets) - README.md (project framing, stack, conventions, status) - CHANGELOG.md (team kickoff decisions Q1/Q2/Q3, T2/T3/T4, auth strategy) - tasks/spec-decisions.md (D-001..D-007 arbitrations on top of frozen spec) - tasks/todo.md (sprint 0 backlog: B0.* / F0.* / S0.* / R0.*) - tasks/lessons.md (empty, populated as work progresses) - backend/ frontend/ docs/ scaffolding Co-Authored-By: Claude Opus 4.7 (1M context) --- .gitignore | 64 +++++++++++++++++++++++++++++++++++++++++ CHANGELOG.md | 26 +++++++++++++++++ README.md | 56 ++++++++++++++++++++++++++++++++++++ backend/.gitkeep | 0 docs/.gitkeep | 0 frontend/.gitkeep | 0 tasks/lessons.md | 7 +++++ tasks/spec-decisions.md | 58 +++++++++++++++++++++++++++++++++++++ tasks/todo.md | 52 +++++++++++++++++++++++++++++++++ 9 files changed, 263 insertions(+) create mode 100644 .gitignore create mode 100644 CHANGELOG.md create mode 100644 README.md create mode 100644 backend/.gitkeep create mode 100644 docs/.gitkeep create mode 100644 frontend/.gitkeep create mode 100644 tasks/lessons.md create mode 100644 tasks/spec-decisions.md create mode 100644 tasks/todo.md diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..7fed7c1 --- /dev/null +++ b/.gitignore @@ -0,0 +1,64 @@ +# Secrets +.env +.env.local +.env.*.local +*.pem +*.key + +# Python +__pycache__/ +*.py[cod] +*$py.class +*.so +.Python +.venv/ +venv/ +env/ +.pytest_cache/ +.mypy_cache/ +.ruff_cache/ +.coverage +htmlcov/ +*.egg-info/ +dist/ +build/ + +# Node / Frontend +node_modules/ +dist/ +build/ +.vite/ +coverage/ +.eslintcache +playwright-report/ +test-results/ + +# Build artifacts (RT/maldev hygiene) +*.exe +*.dll +*.bin +*.o +*.obj +*.pdb + +# IDE +.vscode/ +.idea/ +*.swp +*.swo +.DS_Store + +# OS +Thumbs.db + +# DB local +*.sqlite +*.sqlite3 +*.db + +# Logs +*.log +logs/ + +# Docker +.docker/ diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..38b3b9c --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,26 @@ +# Changelog + +All notable changes to Mimic. Format inspired by [Keep a Changelog](https://keepachangelog.com). +Versioning starts at `0.1.0` when sprint 0 lands. + +## [Unreleased] + +### Team decisions (2026-05-21) + +- **Q1** — SOC client collaboration in the live cockpit is assumed valid (no PoC sheet). +- **Q2** — Mimic is deployed on RT infrastructure (not at client). SOC client connects over + the internet through the existing RT reverse proxy (out of Mimic scope). +- **Q3** — Project framed as "improve the existing shared sheet workflow", not "rebuild Caldera". +- **T2** — C2 credentials stored in a dedicated `c2_credential` table with version + retirement + (Fernet-encrypted `config_json`). Active row per engagement = `retired_at IS NULL`, max version. +- **T3** — Jinja templating exposes two accessors: `{{outputs.text}}` (stdout) and + `{{outputs.blob("key")}}` (binary, 10 MB cap, UTF-8 with latin-1 fallback). +- **T4** — `soc_session.token_opaque` stores a bcrypt hash; the clear token is delivered + out-of-band and never re-displayable. +- **Auth** — v1: local user/password (bcrypt + Flask session). v2: Keycloak OIDC mapping + onto the same group model. RBAC is group-based from day one. + +### Sprint 0 in progress + +Repo skeleton, data model, `C2Connector` ABC, Jinja2 sandbox, local auth + RBAC, flat CRUD, +UX wireframes (mock data). No real connector, no reporting until PR1/PR2/PR3 land. diff --git a/README.md b/README.md new file mode 100644 index 0000000..01d2e6f --- /dev/null +++ b/README.md @@ -0,0 +1,56 @@ +# 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 (unit tests only) +- **Deploy** Docker + Ansible + +## 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/`, `fix/`, `docs/`, `chore/`. Long-lived: `main`. +- Commits: Conventional Commits (`feat:`, `fix:`, `chore:`, `docs:`, `test:`, `refactor:`). +- PRs: each branch → review (`code-reviewer`) → team-lead merges. No direct push to `main`. + +## Build & run + +`make` targets land at the end of sprint 0. For now the repo is skeleton-only. diff --git a/backend/.gitkeep b/backend/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/docs/.gitkeep b/docs/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/frontend/.gitkeep b/frontend/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/tasks/lessons.md b/tasks/lessons.md new file mode 100644 index 0000000..f8b3549 --- /dev/null +++ b/tasks/lessons.md @@ -0,0 +1,7 @@ +# Lessons + +Patterns to remember across sprints. Updated after every correction or non-obvious decision. + +--- + +(empty — populated as work progresses) diff --git a/tasks/spec-decisions.md b/tasks/spec-decisions.md new file mode 100644 index 0000000..2888fa9 --- /dev/null +++ b/tasks/spec-decisions.md @@ -0,0 +1,58 @@ +# Spec decisions log + +This file tracks implementation arbitrations *on top* of the frozen spec +(`Projects/Mimic — Spec.md` in the RT-SecondBrain vault). + +Format: one entry per decision, newest first. + +--- + +## 2026-05-21 — Team kickoff decisions + +### D-001 — SOC collaboration hypothesis +**Context.** Devils-advocate flagged the sociological assumption that SOC analysts +will cote in the live cockpit. +**Decision.** Hypothesis accepted as-is. No paper PoC. Risk owned by lead RT. + +### D-002 — Mimic deployment location +**Context.** Spec §6 NF-network did not pin where Mimic is physically deployed. +**Decision.** Mimic runs on RT infrastructure. SOC client connects through the +existing RT reverse proxy (Caddy, out of Mimic scope). Mimic → Mythic / Home C2 +through outbound VPN. RT R&D (TTP library, stealthy variants) never sits on +client premises. + +### D-003 — Authentication strategy +**Context.** Spec mentions OIDC Keycloak but lab onboarding cost is high. +**Decision.** v1 ships **local auth** (username/password, bcrypt, Flask server-side +sessions). v2 adds Keycloak OIDC. The RBAC model is **group-based from day one**, +so OIDC will map claims to existing groups without touching application code. +SOC sessions remain a distinct mechanism (`soc_session.token_opaque` bcrypt hash, +clear token out-of-band). + +### D-004 — C2 credential storage (T2) +**Context.** Engagement.config_json (encrypted JSON column) vs dedicated table. +**Decision.** Dedicated table `c2_credential (id, engagement_id, c2_type, +config_json_fernet, version, created_at, retired_at)`. Active row per engagement = +`retired_at IS NULL`, highest version. Rotation = insert + retire previous. +Fernet key in env, never in DB. + +### D-005 — Cleanup template variable sources (T3) +**Context.** Jinja `{{outputs.X}}` source ambiguity. +**Decision.** Two accessors: +- `{{outputs.text}}` → `run_step.output_text` (stdout/UTF-8 text). +- `{{outputs.blob("")}}` → reads from `output_blob_ref`, hard cap **10 MB** + (consistent with F8 evidence limit), UTF-8 decoding with latin-1 fallback, + silent refusal + log entry if the blob is non-decodable. +`regex_extract` always operates on the resulting string. + +### D-006 — SOC session token storage (T4) +**Context.** `soc_session.token_opaque` storage form. +**Decision.** bcrypt hash. Clear token generated server-side at session creation, +returned **once** in the API response, delivered out-of-band to the SOC analyst. +Never re-displayable. + +### D-007 — Reverse proxy scope +**Context.** Mimic exposure to internet for SOC client access. +**Decision.** Reverse proxy (Caddy + TLS + IP allowlist) handled by existing RT +infrastructure. Mimic ships an HTTP listener on localhost only; the deployment +playbook wires it behind the existing proxy. diff --git a/tasks/todo.md b/tasks/todo.md new file mode 100644 index 0000000..9dfd1c9 --- /dev/null +++ b/tasks/todo.md @@ -0,0 +1,52 @@ +# Sprint 0 — Mimic + +Repo skeleton + foundational modules. Nothing that depends on PR1/PR2/PR3. + +## Backend (`backend`) + +- [ ] B0.1 — `backend/` Python project: `pyproject.toml` (ruff, mypy strict, pytest, coverage), + `Makefile`, `Dockerfile`, `docker-compose.yml` for Postgres dev DB. +- [ ] B0.2 — Alembic init + complete initial migration covering the §8 schema (incl. `ttp_version`, + `c2_credential`, `user`, `group`, `user_group`, `permission`, `group_permission`, + `soc_session`, audit_log with write-only Postgres role). +- [ ] B0.3 — SQLAlchemy 2 typed mapped classes for every table + repositories scaffold. +- [ ] B0.4 — `C2Connector` ABC + dataclasses (`Payload`, `TaskHandle`, `TaskResult`) + enum + `payload_type` + factory keyed on `c2_type`. **No real implementation.** +- [ ] B0.5 — Jinja2 SandboxedEnvironment + `regex_extract` filter via `google-re2` + + `{{outputs.text}}` and `{{outputs.blob(key)}}` accessors with 10 MB cap. +- [ ] B0.6 — Local auth (login/password bcrypt + Flask server-side sessions) + RBAC + group-based decorators + F11 permission matrix declared in code. +- [ ] B0.7 — Flat CRUD endpoints (engagements, hosts, TTPs, scenarios) — no orchestration, + no WebSocket, no reporting yet. +- [ ] B0.8 — pytest baseline: unit (SQLite) + integration scaffold (testcontainers Postgres). + +## Frontend (`ux-frontend`) + +- [ ] F0.1 — `frontend/` Vite + React + TypeScript strict + Tailwind 4 + TanStack Query 5, + eslint strict + prettier, Playwright skeleton. +- [ ] F0.2 — Design system provisional: semantic tokens in `theme.css` (status colors, RT accent, + data mono / UI sans), dark-first palette, placeholder logo. +- [ ] F0.3 — Wireframes (via `frontend-design` skill) on mock data: + Login + engagement selection, Live cockpit, Scenario composer, + Report + MITRE matrix, TTP library + import. +- [ ] F0.4 — Routing skeleton + role-aware layout shell (no real auth wired yet). + +## Spec / Docs (`spec-analyst`) + +- [ ] S0.1 — Cross-check the data model in B0.2 against §8 of the spec; report deltas before merge. +- [ ] S0.2 — Cross-check the RBAC matrix in B0.6 against F11; report deltas before merge. +- [ ] S0.3 — Maintain `tasks/spec-decisions.md` as new arbitrations land. +- [ ] S0.4 — Open `docs/architecture.md` once backend layout is committed. + +## Review (`code-reviewer`) + +- [ ] R0.1 — Review each PR per the published charter; block on security/OPSEC violations. +- [ ] R0.2 — Verify mypy strict and ruff clean before approving any backend PR. +- [ ] R0.3 — Verify TS strict, no `useEffect(fetch)`, exhaustive deps before approving any frontend PR. + +## Conventions + +- Branches: `feature/`, `fix/`, `docs/`, `chore/`. Long-lived: `main`. +- Commits: Conventional Commits (`feat:`, `fix:`, `chore:`, `docs:`, `test:`, `refactor:`). +- PRs: each branch → review (`code-reviewer`) → team-lead merges. +- No direct push to `main`.