D-008 frames the group-based RBAC layout as an OIDC-prep mechanism that must seed exactly the three F11 spec roles and their canonical permission matrix. Custom groups remain out of v1 scope. D-009 reaffirms H32: replayability lives only on run.snapshot_json. The ttp_version table listed in B0.2 must be dropped from the initial migration.
4.2 KiB
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("<key>")}}→ reads fromoutput_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_extractalways 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.
D-008 — Group-based RBAC vs spec F11 fixed roles
Context. Spec F11 declares 3 fixed roles (rt_operator, rt_lead,
soc_analyst) with an explicit permission matrix. Sprint 0 plan (B0.6, D-003)
introduces group / permission / group_permission / user_group tables to
prepare OIDC v2 claim-to-group mapping without code change.
Decision. Group-based model accepted as an implementation layout, not a
scope extension:
- The 3 spec roles MUST exist as the 3 seeded groups at bootstrap
(
rt_operator,rt_lead,soc_analyst). - The F11 permission matrix is the canonical source: groups receive exactly the permissions of their matching role; no custom permissions UI v1.
- Custom groups, group editing UI, or per-engagement group overrides = OUT of v1.
- Any drift between seeded group permissions and the F11 matrix is a spec violation, not a configuration choice.
D-009 — ttp_version table forbidden (H32 reaffirmed)
Context. Sprint 0 plan (B0.2) lists ttp_version among the initial tables.
Spec hypothesis H32 explicitly excludes this: "Snapshot de rejouabilité =
run.snapshot_json uniquement (pas de table ttp_version séparée —
simplification MVP)".
Decision. Drop ttp_version from the initial migration. The ttp.version
column (informational, §8) is kept. Replayability lives solely on
run.snapshot_json. Re-introducing ttp_version requires explicit spec amendment
through the team-lead.