Skip to content

SnowOps — Project State

Current Phase

  • M1: Sign-offs in flight
  • M2a: Core Baseline FUNCTIONALLY CODE-COMPLETE (v0.40) — every non-postponed asset is 🟦+. W-series postponed (D35).
  • M2b: 14-asset core CODE-COMPLETE — E0 (v0.42) + V2 + V3 (v0.43) + S1 (v0.44) + S2 (v0.45) + L1 (v0.46) + L2 (v0.47) + L4 (v0.48) + F12 (v0.49) + B6 (v0.50) + F11 (v0.51) shipped; K1 + K2 (PR #12) + D5 (PR #13) landed externally and merged. 14/14 in-repo — nothing external remaining. Focus now: runbook sign-offs.
  • GTM: Track A COMPLETE (v0.34) — 39 files under docs/gtm/. Awaiting human sign-offs.

Last Updated: 2026-06-10 (v0.71) — D71: M (data protection & privacy) series completed — M4 Purview + M5 DLP + M7 GDPR/CCPA evidence code-complete. Every M1–M7 asset is now 🟦+.

Prior: 2026-06-10 (v0.70) — D70 completed the H (identity) series (H4 SCIM + H6 access reviews).

Prior: 2026-06-10 (v0.69) — D69 batch (N1 + N2 + N7 + V1 + V4) finished the N (network) and V (documentation) series.

Prior: 2026-06-10 (v0.68) — D68 batch (I4 + I6 + I7 + U4 + U5) finished the I / U series. · 2026-06-09 (v0.67) — D66 batch (V5 + J8 + J7 + R3 + K5) finished the J / R / K series + the D65 client-posture pair.


In Flight

Item Status Notes
M2b 14-asset core 🟦 code-complete all 14 in-repo (E0+V2+V3+S1+S2+L1+L2+L4+F12+B6+F11 + K1+K2+D5); nothing external remaining
N3 + N4 (WAF Policy + DDoS) 🟦 code-complete (v0.60) N3 runbook N3.md · N4 runbook N4.md — sign-offs pending
E2–E6 (E series) 🟦 code-complete (v0.61) E2 Vanta · E3 Drata stub · E4 Resource Graph · E5 Evidence Sync · E6 Access Review — sign-offs pending
D60 batch (J3/K3/J5/K4/R4) 🟦 code-complete (v0.66) J3 Sentinel · K3 SOAR · J5 Grafana · K4 PIR · R4 CAB — runbooks J3/K3/J5/K4/R4, sign-offs pending
D66 batch (V5/J8/J7/R3/K5) 🟦 code-complete (v0.67) V5 posture report · J8 client dashboard · J7 cost-controlled logs · R3 emergency change · K5 tabletop — runbooks V5/J8/J7/R3/K5; finishes the J/R/K series; sign-offs pending
D68 batch (I4/I6/I7/U4/U5) 🟦 code-complete (v0.68) I4 DAST · I6 patch-compliance · I7 CVE-triage+SLA · U4 FinOps dashboard · U5 cost-anomaly — runbooks I4/I6/I7/U4/U5; finishes the I/U series; sign-offs pending
D69 batch (N1/N2/N7/V1/V4) 🟦 code-complete (v0.69) N1 landing-zone connectivity · N2 Firewall Premium · N7 zero-trust ref · V1 policy templates · V4 compliance-manual — runbooks N1/N2/N7/V1/V4; finishes the N/V series; sign-offs pending
D70 H-series finish (H4/H6) 🟦 code-complete (v0.70) H4 SCIM provisioning · H6 Entra access reviews — runbooks H4/H6; completes the H identity series; sign-offs pending
D71 M-series finish (M4/M5/M7) 🟦 code-complete (v0.71) M4 Purview baseline · M5 DLP policy pack · M7 data inventory + DSAR — runbooks M4/M5/M7; completes the M data-protection series; sign-offs pending
M2a runbook sign-offs 🟧 X7+U+N+M+J offline parts are ~5 min each
GTM Track A 🟦 complete Human sign-offs pending (see §0)

Open Issues / Tech Debt (v0.55 repo review — 2026-06-04)

Surfaced by a full-repo review. Full detail + IDs in docs/context/10-gap-register.md (G15–G20). Fixed in the same pass except G18 (seeded, ongoing).

# Issue Severity Status
G15 B1 test red — apps/github-onboarder/src/load-template.test.ts asserted a stale workflow file list High ✅ Fixed — test now walks disk dynamically; 38/38 pass
G16 No PR CI job ran apps/* unit tests; B1 had no workflow High ✅ Fixed — added .github/workflows/app-tests.yml (dynamic matrix, 13 apps)
G17 CLAUDE.md §2 repo layout stale Med ✅ Fixed — §2 refreshed
G18 Zero ADRs despite 50 decisions; DoD #5 + §3 require ADRs Med 🟧 Seeded — docs/adr/ README + template + ADRs 0001–0004; backfill rest ongoing
G19 F7 live/validate.sh false-positive hclfmt warning (deprecated CLI flags) Low ✅ Fixed — modern hcl fmt --check, now a hard fail
G20 U3/K3 scaffold READMEs described absent behavior Low ✅ Fixed — "SCAFFOLD — postponed" banners + §2 tags

Open Issues / Tech Debt (Compliance control-mapping review — 2026-06-07)

Surfaced while reading compliance/*/control-mapping.md end to end against the asset glossary + project state. Full detail in docs/context/10-gap-register.md (G21–G22).

# Issue Severity Status
G21 Control-mapping docs (CIS Azure 6.4/6.5, COMPLIANCE-GUIDE.md Vanta sync, ~25× O/P/Q-series refs) cited shipped-but-marked-roadmap assets (N3/N4), the wrong asset (D2 vs E2), and a stale O↔P↔Q→V letter mapping Med ✅ Fixed in same pass — see G21 detail
G22 No CI lint ties compliance/*/control-mapping.md asset-code refs to 00-asset-glossary.md / shipped status — same staleness class as G15, will recur every time an asset ships or M4 items get reassigned letters Med ⬜ Queued — needs a small Node lint script (extract codes → resolve vs. glossary → cross-check roadmap markers vs. code_complete status); longer-term: generate the 4 mapping docs from one compliance/control-mappings.yaml source of truth

Verified passing in this review: terraform fmt -check (modules/live/sandbox) ✅ · Go terratest vet + compile ✅ · all 14 app suites now green (github-onboarder fixed) · live/validate.sh ✅. Tooling: node 26, go 1.26, terraform 1.15.


Runbook Sign-Off Backlog (Ordered)

Execute offline Parts A+B first (~5 min each). Cloud parts (C/D) are optional promotion-path extenders.

Priority Runbook Cloud? Time Cost
1 V2 docs/runbooks/test/V2.md No ~5 min $0
2 V3 docs/runbooks/test/V3.md No ~5 min $0
3 E0 docs/runbooks/test/E0.md Partial (Part C) ~6 min offline $0
4 X7 docs/runbooks/test/X7.md No ~5 min $0
5 U1 docs/runbooks/test/U1.md Yes (Part C) ~5 min offline $0
6 U2 docs/runbooks/test/U2.md Yes (Part C/D) ~5 min offline $0
7 N5 docs/runbooks/test/N5.md Yes (Part C/D) ~5 min offline $0
8 N6 docs/runbooks/test/N6.md Yes (Part C/D) ~5 min offline $0
9 M1 docs/runbooks/test/M1.md Yes ~5 min offline $0
10 M2 docs/runbooks/test/M2.md Yes (Part C) ~5 min offline ~$1
11 M3 docs/runbooks/test/M3.md Yes ~5 min offline $0
12 M6 docs/runbooks/test/M6.md Yes ~5 min offline $0
13 J1 docs/runbooks/test/J1.md Yes (Part C/D) ~5 min offline $0
14 J2 docs/runbooks/test/J2.md Yes (Part C/D) ~5 min offline $0
15 J6 docs/runbooks/test/J6.md Yes (Part C/D) ~5 min offline $0
16 H5 docs/runbooks/test/H5.md Yes (Part C) ~5 min offline $0
17 H7 docs/runbooks/test/H7.md Yes (Part C/D) ~5 min offline $0 (needs P1)
18 F8 docs/runbooks/test/F8.md Optional (kind) ~5 min offline $0
19 B5 docs/runbooks/test/B5.md Yes (Part C) ~5 min offline $0 (needs P2)
20 B4 docs/runbooks/test/B4.md Yes (Part C) ~8 min $0
21 B3 docs/runbooks/test/B3.md Yes (Part C) ~12 min $0
22 B2 docs/runbooks/test/B2.md Yes (Part C) ~25 min $0
23 C3 docs/runbooks/test/C3.md Yes (Parts C–F) ~75 min $0
24 C2 docs/runbooks/test/C2.md Yes (Parts C–E) ~40 min <$1
25 H1 docs/runbooks/test/H1.md Yes ~25 min $0
26 H2 docs/runbooks/test/H2.md Yes (needs P1) ~30 min $0
27 H3 docs/runbooks/test/H3.md Yes (needs P2) ~30 min $0
28 F3 docs/runbooks/test/F3.md Yes (Part C) ~30 min ~$10
29 F5 docs/runbooks/test/F5.md Yes (Part C) ~25 min ~$2
30 F4 docs/runbooks/test/F4.md Yes (Part C) ~30 min ~$5
31 D4 docs/runbooks/test/D4.md Optional (kind) ~5 min offline $0
32 F2 docs/runbooks/test/F2.md Yes (Part C) ~35 min ~$5
33 F0 docs/runbooks/test/F0.md No ~15 min $0
34 B1 docs/runbooks/test/B1.md Yes ~60 min $0
35+ D2, X1, X2, C1, G0–G6, A1, A5, F1, F6 Mix Various Various

M2b 14-Asset Core Progress (D36)

# Asset Scope Status Est. Time Cloud Cost
1 ✅ E0 Compliance snapshot (Policy + Defender score, wired to C1) 🟦 v0.42
2 ✅ V2 Architecture diagram generator (apps/diagram-generator/) 🟦 v0.43
3 ✅ V3 Runbook generator (apps/runbook-generator/) 🟦 v0.43
4 ✅ S1 Drift detection (scheduled terraform plan → ticket via TicketPlatform) 🟦 v0.44
5 ✅ S2 Azure Policy compliance dashboard (apps/compliance-dashboard/) 🟦 v0.45
6 ✅ K1 IR runbook library (docs/runbooks/incident/) 🟦 (external, merged)
7 ✅ K2 On-call integration (modules/azure/oncall-integration/) 🟦 (external, merged)
8 ✅ L1 Azure Backup policy module (modules/azure/backup-policy/) 🟦 v0.46
9 ✅ L2 Cross-region replication (object replication + SQL failover group) 🟦 v0.47
10 ✅ L4 Automated restore drill (apps/restore-drill/ → S2 DR panel) 🟦 v0.48
11 ✅ D5 Policy waiver engine (waivers/, OPA exception records, CI expiry enforcement) 🟦 (external, merged PR #13)
12 ✅ F12 Brownfield import library (modules/azure/import-blocks/, 9 modules) 🟦 v0.49
13 ✅ B6 Client self-service bootstrap (prerequisite checker + validator) (apps/client-bootstrap/) 🟦 v0.50
14 ✅ F11 Module versioning + private registry (apps/module-registry/) 🟦 v0.51

Rule (D36): ALL other M2b/M3 assets are POSTPONED until these 14 are code-complete + signed off. Depth before breadth.


Next 5 Selected (v0.53 — D48)

After the M2b 14-asset core went code-complete, the next 5 most-important postponed/unbuilt items were selected. Reconciliation: C5 (ADO pipelines) was found already built in commit 51c7fc4 — docs were stale; it's now marked 🟦 code-complete and dropped from the candidate set.

# Asset Rationale Status
1 I3 — CodeQL SAST No code-analysis layer existed; D2 covered only IaC/secrets 🟦 code-complete (v0.53)
2 I2 — Dependency scanning dependabot.yml existed but no PR gate / alert digest 🟦 code-complete (v0.53)
3 I1 — Container image scanning Closes G6 (non-K8s container security); reusable image scan 🟦 code-complete (v0.53)
4 E7 — TicketPlatform adapters Closes G8; unblocks E6/I5/K4/P3; generalizes the S1 seed 🟦 code-complete (v0.54)
5 F7 — Terragrunt live-infra reference The missing per-env/region module wiring repo; deploy enablement 🟦 code-complete (v0.55)

Done (v0.53): I1 + I2 + I3 — the M2a CI security-scanning suite (docs/runbooks/test/I1.md, I2.md, I3.md). Done (v0.54): E7 — apps/ticket-platform/ (GitHub/Jira/Linear/ADO adapters + CLI, 26 tests); S1 repointed (interface-compatible). Runbook docs/runbooks/test/E7.md. Done (v0.55): F7 — live/ Terragrunt reference (root + _envcommon + bootstrap + per-env/region units; baseline→net/kv/acr DAG; offline validate.sh). Runbook docs/runbooks/test/F7.md.

✅ Next-5 (D48) COMPLETE. Candidate next batch: runbook sign-offs (in parallel), then M3 tail (W4 client offboarding) / M2b additional (J4 alert pack, X5 pipeline integration tests, X8 synthetic monitoring) / M4 advanced.


Next 5 Selected (v0.56 — D51)

With the next-5 (D48) complete, the next 5 most-important postponed items were selected. Priority rule: depth before breadth (D36) + milestone order — finish the remaining M2b "additional" assets (M2b §84) before advancing to M3 tail / M4. All five are M2b. The heavier network items (N3 WAF, N4 DDoS — CO-owned, cloud-cost) are deferred to a later batch.

# Asset Rationale Status
1 J4 — Alert rule pack No detection-rule layer existed; identity/network/privilege/data-exfil KQL alerts over the J1 LAW, wired to K2 action groups 🟦 code-complete (v0.56)
2 I5 — Defender → ticket via E7 Newly unblocked by E7 (D49); first consumer proving the TicketPlatform adapter; closes the Defender-alert→ticket loop 🟦 code-complete (v0.58)
3 X5 — Pipeline integration tests M2a CI gates (C1–C3) had no integration test consumers; reusable-workflow test repos 🟦 code-complete (v0.57)
4 X8 — Synthetic monitoring No availability/latency synthetic probes; Azure Monitor standard webtests + alert rules 🟦 code-complete (v0.57)
5 R2 — Production change log Merged-PR → changelog generator; reuses E7 for change-record tickets where required 🟦 code-complete (v0.59)

✅ D51 batch COMPLETE (all 5): J4 (v0.56) · X5 + X8 (v0.57) · I5 (v0.58) · R2 (v0.59).

Done (v0.56): J4 — modules/azure/alert-rule-pack/ (curated scheduled-query alert rules across four threat domains — identity/privilege/network/data-exfil; domain toggles + per-rule overrides + freeform custom rules; consumes the J1 workspace + K2 action groups by ARM ID). Offline TestAlertRulePackValidate green. Runbook docs/runbooks/test/J4.md.

Done (v0.57) — X series complete (X5 + X8): - X5tests/pipeline-integration/ reusable-workflow contract gate (contract_check.py + test_contract_check.py, 11 unit tests; offline validate.sh; CI .github/workflows/pipeline-integration.yml) + live it-{container-build-sign,aks-deploy,terraform-plan-apply}.yml consumers driving the existing fixtures against the sandbox. Catches workflow_call interface drift across all callers offline. Runbook docs/runbooks/test/X5.md. - X8modules/azure/synthetic-monitoring/ (App Insights standard availability tests + per-test availability metric alerts; optional workspace-based AI component; consumes the J1 workspace + K2 action groups by ARM ID). Offline TestSyntheticMonitoringValidate green. Runbook docs/runbooks/test/X8.md.

X series: X1✅ X2✅ X3🟩 X4✅ X5✅ X6(ongoing runbooks) X7✅ X8✅ — all X assets now code-complete/shipped except the ongoing X6 runbook track.

Done (v0.58): I5 — apps/defender-ticketer/ (Defender for Cloud alerts → idempotent tickets via the E7 snowops-ticket CLI; the first E7 consumer). Pure normalize/filter/dedupe core behind a Collector seam; consumes E7 at run time (no build-coupling, per D49). 21 jest tests; offline dry-run + E7 output-contract verified. Runbook docs/runbooks/test/I5.md.

Done (v0.59): R2 — apps/change-log/ (production change log: merged PRs / squash commits → categorized Keep-a-Changelog markdown; pure categorize/render core behind a collector seam — git log / gh pr list / fixture; optional E7 change-record ticket per release via the same run-time bridge as I5). 32 jest tests; offline + live git log + prepend verified. Runbook docs/runbooks/test/R2.md. D51 batch complete — next: open backlog (runbook sign-offs in parallel; M4 advanced; heavier net N3/N4).

Done (v0.60): N3 + N4 — WAF Policy Module (modules/azure/waf-policy/) + DDoS Protection (modules/azure/ddos-protection/); the deferred M2b-additional network items.

Done (v0.61): E2–E6 — M4 evidence chain (Vanta adapter, Drata stub, Resource Graph library, evidence sync, access review).

Done (v0.62): W4 + L3 (D56) — Client Offboarding Playbook (docs/runbooks/offboarding/) finishes the M3 tail; DR Runbook Templates (docs/runbooks/dr/) complete the DR series with L1/L2/L4. Documentation assets — verification is manual runbook sign-off. Next: runbook sign-offs in parallel; remaining M4 advanced (J3, S3/S4, L5, O/P/Q, T); W1–W3 last (D35).


Next 5 Selected (v0.63+ — D57)

With the D51 batch + the W4/L3/N3/N4/E2–E6 follow-ons complete, the next 5 most-important postponed items were selected by the same depth-before-breadth (D36) + "finish near-complete series / unblock scaffolds / extend E7" rationale D48/D51 used. Candidates were the items the v0.62 roadmap line already flagged as the remaining M4-advanced backlog: J3, S3/S4, L5, O/P/Q, T.

# Asset Rationale Status
1 L5 — RTO/RPO doc generator Completes the DR series (L1/L2/L3/L4 all code-complete); small, standalone, evidence-only — merges already-shipped L1/L2/L4 outputs into one client doc, no new infra 🟦 code-complete (v0.63)
2 S3 — Auto-remediation playbooks (Logic Apps) Closes the loop the S series opens with S1 drift detection — detect → remediate; the natural next step now S1/S2 are shipped 🟦 code-complete (v0.64)
3 S4 — Compliance scorecard generator Pairs with S2 dashboard + E0 snapshots → branded PDF for client/sales reporting; finishes the S series alongside S3 🟦 code-complete (v0.65)
4 J3 — Microsoft Sentinel deployment Unblocks K3 (Sentinel SOAR playbooks — was a postponed scaffold per G20) and J5 (Grafana dashboards); the missing SIEM layer the J/K series assume 🟦 code-complete (v0.66)
5 K4 — Post-incident review + GH issue via E7 Newly tractable now E7 ships adapters (same "first/early E7 consumer" rationale that selected I5 in D51) — closes part of the K series 🟦 code-complete (v0.66)

Rationale for the order: L5 first because it's the smallest, purely additive (reuses L1/L2/L4 outputs verbatim, ships zero new Azure resources), and finishes a series outright. S3+S4 next because they finish the S series and because S3 is the natural "what do we do about the drift S1 finds" follow-on. J3 then K4 because J3 unblocks two scaffolds/postponed items at once (K3, J5) and K4 extends the now-proven E7 ticketing bridge.

Done (v0.63): L5 — apps/rto-rpo-doc-generator/ (pure adapt → render + jest, same mold as E0/S1/S2/L4; merges L1 retention_summary + L2 replication_summary + L4 RestoreDrillReports into one evidence-backed RTO/RPO objectives markdown doc; documents only drilled workloads; states the mechanism, never a fabricated minute figure, for continuously-replicating SQL failover groups; 15 jest tests). Runbook docs/runbooks/test/L5.md. Completes the DR series (L1/L2/L3/L4/L5 all code-complete).

Done (v0.64): S3 — modules/azure/auto-remediation-playbooks/ (curated Logic App playbook pack: enforce-mandatory-tags, lock-down-public-storage, remove-risky-nsg-rule, enable-resource-diagnostics; structural dry-run/enforce split — Terraform renders Compose (intent record) vs. Http+ManagedServiceIdentity action bodies at plan time, so dry_run playbooks are structurally incapable of writing to Azure regardless of RBAC, extending the B3/D21 audit-only-by-default stance to active remediation; per-playbook enabled/mode overrides + custom_playbooks escape hatch; consumes the J1 workspace by ARM ID). Offline Terratest gate TestAutoRemediationPlaybooksValidate; runbook docs/runbooks/test/S3.md. Closes the detect→ remediate loop S1 opened. Next code: S4.

Done (v0.65): S4 — apps/compliance-scorecard-generator/ (pure adapt → render + jest, the E0/S1/S2/L4/L5 mold; turns one E0 ComplianceSnapshot + optional S2 ComplianceDashboard + branding into a versioned, branded one-page scorecard.md/scorecard.html (+ optional Pandoc scorecard.pdf) + model.json; the only derived figure is a documented A–F grading band — the simple mean of policy-compliance % and Secure Score %, banded through a fixed five-way split, with its derivation printed inline, the same "never fabricate, show your work" stance as L5/S3; framework badges and trend direction are strict 1:1 re-presentations of S2's pass/attention status and real delta signs; branding resolves against documented neutral defaults so an unbranded run still looks professional; both optional inputs honestly state when they weren't supplied rather than silently omitting sections; 24 jest tests). Offline-only — no live phase; runbook docs/runbooks/test/S4.md. Finishes the S series (S1/S2/S3/S4 all code-complete). Next code: J3.


Next 5 Selected (v0.66 — D60)

With the D57 batch's L5/S3/S4 shipped, the two still-queued D57 items (J3, K4) were carried forward and joined by K3/J5/R4 — confirmed with the user — to form a tight SIEM + observability + IR/change-ticketing batch. Same depth-before-breadth (D36) + "finish near-complete series / unblock scaffolds / extend E7" lens. J3 is the keystone (onboarding Sentinel unblocks K3 + J5); K4 + R4 extend the proven E7 ticketing bridge (I5/R2 → K4/R4).

# Asset Rationale Status
1 J3 — Microsoft Sentinel deployment The missing SIEM layer; unblocks K3 + J5 🟦 code-complete (v0.66)
2 K3 — Sentinel SOAR playbooks Retires the misleading apps/soar-playbooks scaffold (G20); active-IR containment over J3 incidents 🟦 code-complete (v0.66)
3 J5 — Managed Grafana dashboards-as-code The observability presentation layer over the J1 workspace 🟦 code-complete (v0.66)
4 K4 — Post-incident review via E7 Third E7 consumer; blameless PIR + tracking issue from closed incidents 🟦 code-complete (v0.66)
5 R4 — CAB automation via E7 Fourth E7 consumer; high-impact changes → CAB review tickets (SOC2 CC8.1) 🟦 code-complete (v0.66)

✅ D60 batch COMPLETE (all 5).

  • J3modules/azure/sentinel/: onboards the J1 workspace + toggleable connectors + curated Sentinel-native scheduled analytics rules → incidents (entity mappings + MITRE tactics) + opt-in Defender incident-creation rule. Offline TestSentinelValidate. Runbook J3.md. (D61)
  • K3modules/azure/sentinel-soar/: isolate-account / disable-SP / quarantine-VM Logic App playbooks reusing S3's structural dry_run/enforce split + per-playbook Graph/ARM audience; retires the apps/soar-playbooks/ scaffold. Offline TestSentinelSoarValidate. Runbook K3.md. (D62)
  • J5modules/azure/grafana-dashboards/: Managed Grafana + Monitoring Reader / Grafana RBAC + committed dashboards-as-code (offline scripts/validate.sh gate + az-based deploy script). Offline TestGrafanaDashboardsValidate. Runbook J5.md. (D63)
  • K4apps/post-incident-review/: closed incidents → blameless PIR docs + idempotent tracking issues via the E7 CLI bridge; 23 jest tests. Runbook K4.md. (D64)
  • R4apps/cab-automation/: high-impact changes → CAB review tickets via the E7 CLI bridge; 24 jest tests. Runbook R4.md. (D64)

Next: Client-Facing Posture Visibility (D65) — planned next (see below); then runbook sign-offs in parallel; remaining M4 advanced (J7 Basic-Logs strategy, H4/H6 IAM, I4/I6/I7 vuln, M4/M5/M7 data, N2/N7 net, O/P/Q/T series, U4/U5 cost, V1/V4 docs, R3 emergency-change, K5 tabletop); W1–W3 last (D35).


Client-Facing Posture Visibility (v0.67 — D65, planned)

Why: for an automation MSP, invisible value drives churn — the client should see the guardrails, backups, DR drills, incident handling, and cost governance SnowOps runs for them. This is the retention/QBR (Y11) and upsell ("Baseline → here's what Advanced lights up") artifact, and a sales proof asset. ~80% of the building blocks already exist (E0/S2/S4/L5/J5/V2) — the work is composition + packaging, not new infrastructure.

Approach (D65): two audience tiers, both composed from existing assets; organized by SnowOps deliverable, not by raw Azure metric; the per-client- subscription model (B-series) means each client's J5 instance is already isolated, so a shared multi-tenant portal (W5, D35) is explicitly deferred. Sequence V5 first (the near-free retention/sales artifact), then J8.

# Asset Tier Scope Status
1 V5 — Client Cloud Posture Report Tier 2 (periodic, exec/QBR) apps/posture-report/ — offline composer bundling E0 + S2 + S4 + L5 + V2 (+ optional K4) into one branded HTML/PDF report, sections by deliverable, tagged Baseline/Advanced 🟦 code-complete (v0.67)
2 J8 — Client Overview Dashboard Tier 1 (live, engineer) client-facing read-only Grafana dashboard added to the J5 module + client_grafana_viewers access hook + folder-aware deploy 🟦 code-complete (v0.67)

V5 — Client Cloud Posture Report (Tier 2) — implementation plan

  1. Scaffold apps/posture-report/ from the E0/S2/S4/L5 mold (copy the I5/S4 tsconfig/jest config; @snowops/posture-report, bin snowops-posture-report).
  2. compose.ts (pure): re-declare the input contracts (E0 ComplianceSnapshot, S2 ComplianceDashboard, S4 scorecard model.json, L5 RTO/RPO model, V2 diagram svg/d2 — no cross-package import, per D37/D40) → one PostureReportModel (schemaVersion 1.0). Every figure is a re-presentation of a source number; a missing input renders an honest "not supplied" section (L5/S4 never-fabricate stance).
  3. Section taxonomy (shared with J8): exec summary + overall grade (S4) · your guardrails (policy/Defender, E0) · your data is protected (backup coverage L1 + restore-drill + RTO/RPO L4/L5) · your compliance posture (framework rollup
  4. trend, S2) · incidents we handled (reuse a K4 report when supplied) · cost governance (roadmap until a U-series feed exists) · architecture (V2). Each section tagged [Baseline]/[Advanced]; ungated sections become upsell teasers.
  5. render.ts (pure): self-contained posture-report.html (inline CSS, no external refs — golden-file test, V2/S2/S4 pattern) + a markdown summary. pdf.ts: near-verbatim S4/G3 Pandoc-spawn (best-effort; failure logged, never fails the run).
  6. Branding: reuse S4's BrandingConfig (neutral defaults; only clientName required).
  7. CLI (index.ts): --snapshot (E0, required) · --dashboard (S2) · --scorecard (S4 model) · --rto-rpo (L5) · --diagram (V2) · --incidents (K4 report) · --branding · --out-dir. Optional inputs degrade honestly.
  8. Delivery: .github/workflows/posture-report.yml (monthly + dispatch) that runs E0 → S2 → S4 → L5 then composes; uploads a PRIVATE artifact by default (posture data is sensitive — same stance as S2). QBR template under docs/client-guides/.
  9. Tests + runbook: jest (composition, honest-missing-input, tier tagging, branding, never-fabricate, HTML self-containment); runbook docs/runbooks/test/V5.md (offline Parts A+B, mirroring L5.md/S4.md — no live phase). app-tests CI auto-discovers it.

J8 — Client Overview Dashboard (Tier 1) — implementation plan

  1. Dashboard-as-code: add modules/azure/grafana-dashboards/dashboards/snowops-client-overview.json — panels by deliverable (policy compliance %, Defender Secure Score, backup job status L1, last restore drill L4, open Sentinel incidents J3, budget vs. actual U1), reading the Azure Monitor datasource + the workspace template variable already established in J5's dashboards. Passes J5's existing offline gate (scripts/validate_dashboards.py) automatically.
  2. Client access: grant the client's AAD group Grafana Viewer via J5's existing grafana_viewers input (read-only). Add a small J5 addition for a dedicated "client" Grafana folder so the client sees only this dashboard, not the internal ops ones (folder-scoped Viewer); document the pattern in J5's README.
  3. No new module / no multi-tenant work — reuses the J5 instance, Monitoring Reader grant, gate, and az grafana dashboard create deploy script. Per-client J5 instance = already isolated.
  4. Tests + runbook: the J5 dashboards gate covers the new JSON; runbook docs/runbooks/test/J8.md (Part A offline gate; Part C live — client group sees only the client folder, read-only).

Open item: the incidents and cost sections need a clean data feed — incidents can reuse the K4 report; cost has no SnowOps producer yet (U4/U5 are postponed). Both degrade honestly (the section states "not yet wired") until a source exists; wiring them is a follow-on, not a blocker for D65.


Next 5 Selected (v0.67 — D66)

The two planned D65 items (V5 + J8) were taken together with the three postponed items that finish a near-complete series — the same depth-before-breadth (D36) + "finish near-complete series" lens D48/D51/D57/D60 used. After this batch the J series (J1–J8), the R series (R1–R4), and the K series (K1–K5) are all code-complete.

# Asset Rationale Status
1 V5 — Client Cloud Posture Report D65 flagship; the periodic exec/QBR posture artifact composing E0/S2/S4/L5/V2 (+K4) 🟦 code-complete (v0.67)
2 J8 — Client Overview Dashboard D65 Tier-1 live counterpart to V5; extends J5 (no new module) 🟦 code-complete (v0.67)
3 J7 — Cost-Controlled Log Strategy Finishes the J series; per-table Basic/Analytics plan + retention over a J1 workspace 🟦 code-complete (v0.67)
4 R3 — Emergency Change Workflow Finishes the R series; break-glass label → expedited CAB record via E7 + mandatory retro review 🟦 code-complete (v0.67)
5 K5 — Tabletop Exercise Pack Finishes the K series; five facilitated IR rehearsals mapped 1:1 to the K1 runbooks, feeding K4 🟦 code-complete (v0.67)

✅ D66 batch COMPLETE (all 5).

  • V5apps/posture-report/: offline composerender (+ jest, 27 tests) bundling the re-declared E0/S2/S4/L5/V2/K4 contracts into one branded, deliverable-organized HTML/markdown (+ optional Pandoc PDF) report; sections tagged Baseline/Advanced with upsell teasers for ungated/not-supplied Advanced sections; cost section is an honest U4/U5 roadmap note (never fabricated); self-contained HTML. Workflow posture-report.yml (monthly + dispatch, PRIVATE artifact); QBR guide docs/client-guides/qbr-posture-report.md. Runbook V5.md.
  • J8modules/azure/grafana-dashboards/dashboards/snowops-client-overview.json (passes the J5 offline gate) + a distinct client_grafana_viewers access hook + folder-aware deploy-dashboards.sh (client dashboards → "SnowOps Client" folder). Runbook J8.md.
  • J7modules/azure/log-analytics-cost/: per-table Basic/Analytics plan + retention via azurerm_log_analytics_workspace_table over an existing J1 workspace, curated overridable default strategy (security/audit → Analytics, high-volume telemetry → Basic), advisory daily-quota note. Offline TestLogAnalyticsCostValidate. Runbook J7.md.
  • R3.github/workflows/emergency-change.yml (label-gated; drives R4's apps/cab-automation in emergency mode via the E7 CLI, dry-run unless a tracker secret is set; posts a retrospective-review checklist) + tests/emergency-change/ stdlib validator (14 tests) + docs/runbooks/change/emergency-change.md. Runbook R3.md.
  • K5docs/runbooks/tabletop/: README + facilitation guide + scenario template + five Azure-flavored scenarios (account compromise / ransomware / data exfiltration / DDoS / vendor breach) cross-linked 1:1 to the K1 runbooks + after-action template feeding K4 + an offline validate.py gate. Runbook K5.md.

Next: runbook sign-offs in parallel; remaining M4 advanced (H4/H6 IAM, I4/I6/I7 vuln, M4/M5/M7 data, N1/N2/N7 net, O/P/Q/T series, U3/U4/U5 cost, V1/V4 docs); F9/F10/W5/U3 multi-cloud (M5); W1–W3 last (D35). 43 postponed items remain.


Next 5 Selected (v0.68 — D68)

With the J/R/K series closed (D66), the next 5 finish the two next-most-complete seriesI (vulnerability management) and U (cost governance) — under the same depth-before-breadth (D36) "finish a near-complete series" lens. The U items also close the cost-visibility gap V5/J8 flagged in D65.

# Asset Rationale Status
1 I4 — DAST (OWASP ZAP) The missing dynamic-analysis layer (I1 images / I3 SAST are at-rest); reusable workflow_call gate 🟦 code-complete (v0.68)
2 I6 — Azure Update Manager report Patch-compliance reporting; the OS-update arm of vuln management 🟦 code-complete (v0.68)
3 I7 — CVE triage + SLA dashboard Ties the scanners together with a triage process + SLA tracking — finishes the I series 🟦 code-complete (v0.68)
4 U4 — FinOps dashboard Cost-governance visibility (log-cost + tag governance); extends J5 🟦 code-complete (v0.68)
5 U5 — Cost anomaly detection Daily Cost Management anomaly alerts — finishes the U series 🟦 code-complete (v0.68)

✅ D68 batch COMPLETE (all 5).

  • I4.github/workflows/dast-scan.yml: reusable OWASP ZAP gate (baseline|full) against a deployed URL, fails on High web findings, uploads the report; tuned by a committed .zap/rules.tsv (+ .zap/README.md). Tight perms (contents: read; ZAP issue-writing off). Runbook I4.md.
  • I6apps/patch-compliance/: pure adapt→render (S4/L5 mold) turning an Azure Update Manager assessment into a patch-compliance report (coverage %, out-of-compliance machines, pending Critical/Security counts, SLA aging); self-contained HTML + optional Pandoc PDF; never fabricates a patch date. Jest suite. Runbook I6.md.
  • I7docs/runbooks/vuln/cve-triage.md (triage→severity→SLA Critical 7d/High 30d/Medium 90d→owner/E7→remediate or D5 waiver→verify) + snowops-vuln-triage.json Grafana dashboard (open Defender findings by severity via ARG + SLA aging from the exported SecurityRecommendation table). Runbook I7.md. Finishes the I vuln series.
  • U4snowops-finops.json Grafana dashboard (extends J5): daily billable log ingestion + top tables by ingestion (the J7 Basic-Logs lever) + tag governance / cost allocation via ARG; honest that $ spend needs a Cost Management export. Runbook U4.md.
  • U5modules/azure/cost-anomaly-alert/: Azure Cost Management daily anomaly alerts (azurerm_cost_anomaly_alert, for_each over an alerts map) → email recipients; the detection complement to U1 budgets. Offline TestCostAnomalyAlertValidate. Runbook U5.md. Finishes the U cost series.

Next: runbook sign-offs in parallel; remaining M4 advanced (H4/H6 IAM, M4/M5/M7 data, N1/N2/N7 net, O/P/Q/T series, V1/V4 docs); F9/F10/W5/U3 multi-cloud (M5); W1–W3 last (D35). 38 postponed items remain.


Next 5 Selected (v0.69 — D69)

With the I/U series closed (D68), the next 5 finish the two next-most-complete seriesN (network security) and V (documentation) — same depth-before-breadth (D36) lens. N1/N2 were scoped to be non-redundant with F2 (which already owns the hub-spoke + a Standard firewall): N1 adds the connectivity edge F2 lacks, N2 is the Premium deep-inspection policy layer.

# Asset Rationale Status
1 N1 — Landing-zone connectivity The Bastion/gateway/DNS-resolver edge F2 lacks 🟦 code-complete (v0.69)
2 N2 — Azure Firewall Premium IDPS + TLS-inspection policy layer over F2's Standard firewall 🟦 code-complete (v0.69)
3 N7 — Zero-trust reference architecture Ties the N/F/H/M/J/K/E/S/C/I/D assets into one ZT story — finishes N 🟦 code-complete (v0.69)
4 V1 — Policy repo template The document-control half (the 📋 Manual controls) the automated assets pair with 🟦 code-complete (v0.69)
5 V4 — Compliance manual generator Composes controls + evidence + policies into a framework manual — finishes V 🟦 code-complete (v0.69)

✅ D69 batch COMPLETE (all 5).

  • N1modules/azure/landing-zone-connectivity/: Azure Bastion (always) + optional VPN/ER gateway + optional Private DNS Resolver, attached to the existing F2 hub vNet by name; owns no F2 resource. Offline TestLandingZoneConnectivityValidate. Runbook N1.md.
  • N2modules/azure/firewall-premium-policy/: Premium azurerm_firewall_policy with IDPS (mode + signature overrides + traffic bypass) + optional TLS inspection (KV-cert + UserAssigned identity) + optional DNS proxy + overridable rule collection groups (deny-by-default). Offline TestFirewallPremiumPolicyValidate. Runbook N2.md.
  • N7docs/architecture/zero-trust-reference.md: the three ZT principles + five pillars + visibility spine mapped to SnowOps assets, with a maturity/gap table. Runbook N7.md. Finishes the N series.
  • V1templates/policies/: six ratifiable policy templates (InfoSec/AUP/IR/BC-DR/Change/Vendor), each cross-referencing its enforcing assets, + an offline validate.py (sections + placeholders + cross-link integrity). Runbook V1.md.
  • V4apps/compliance-manual/: pure adapt→render composing a manual spec (+ optional E0 snapshot) into a branded framework compliance manual (md/HTML/PDF); never invents an undocumented control. Runbook V4.md. Finishes the V series.

Next: runbook sign-offs in parallel; remaining M4 advanced (H4/H6 IAM, M4/M5/M7 data, O/P/Q/T series); F9/F10/W5/U3 multi-cloud (M5); W1–W3 last (D35). 33 postponed items remain.


Series Completion (v0.70 — D70): H (Identity & Access Management)

The two remaining H assets were completed to close the H series outright (H1–H7 all 🟦+). Both are azuread-provider modules in the H2/H3 mold.

# Asset Rationale Status
1 H4 — SCIM provisioning to SaaS Automates joiner/mover/leaver provisioning from Entra to SaaS apps over SCIM 🟦 code-complete (v0.70)
2 H6 — Access review automation Recurring Entra access reviews (recertification) via entitlement management — completes H 🟦 code-complete (v0.70)
  • H4modules/azure/scim-provisioning/: instantiates the SaaS gallery app (azuread_application_from_template), sets the SCIM endpoint + bearer token (azuread_synchronization_secret, sensitive), and starts the provisioning job (azuread_synchronization_job). Offline TestScimProvisioningValidate. Runbook H4.md.
  • H6modules/azure/access-reviews/: a catalog + access packages, each with an azuread_access_package_assignment_policy carrying assignment_review_settings (frequency / duration / reviewers / timeout behavior) — recurring recertification. Native-config counterpart to E6 (the evidence/reporting app). Offline TestAccessReviewsValidate. Runbook H6.md.

H series: H1✅ H2✅ H3✅ H4✅ H5✅ H6✅ H7✅ — complete.

Next: runbook sign-offs in parallel; remaining M4 advanced (M4/M5/M7 data, O/P/Q/T series); F9/F10/W5/U3 multi-cloud (M5); W1–W3 last (D35). 31 postponed items remain.


Series Completion (v0.71 — D71): M (Data Protection & Privacy)

The three remaining M assets were completed to close the M series outright (M1–M7 all 🟦+): M4 discovers + classifies, M5 prevents M365 egress, M7 proves you know your data and can answer for it — layered on the already-shipped M1/M2/M3/M6 encryption/TLS/residency enforcement.

# Asset Rationale Status
1 M4 — Microsoft Purview baseline The data-classification foundation (account + access via ARM; scans are data-plane Part C) 🟦 code-complete (v0.71)
2 M5 — DLP policies M365 content-inspection layer as policy-as-code (Terraform can't manage M365 DLP) 🟦 code-complete (v0.71)
3 M7 — GDPR/CCPA evidence RoPA register + DSAR workflow on the statutory clocks — completes M 🟦 code-complete (v0.71)
  • M4modules/azure/purview-baseline/: azurerm_purview_account + J1 diagnostics + Reader/Storage Blob Data Reader over scan_scopes. Offline TestPurviewBaselineValidate. Runbook M4.md.
  • M5policy/dlp/: three audit-first YAML DLP policies (PII-financial / PII-personal / PHI) + offline gate + unit tests + idempotent deploy-dlp.ps1 (Security & Compliance cmdlets). Cloud-storage half = N5/M1/M3/M6 (documented). Runbook M5.md.
  • M7compliance/data-inventory/ RoPA (template + fail-closed PyYAML gate: Art. 6 lawful-basis enum, retention-with-basis, DPA-per-processor, mandatory dsar_lookup) + docs/runbooks/privacy/ DSAR workflow (30/45-day clocks, verify-first, documented exemptions, honest backups statement) + compliance/dsar/ records. Runbook M7.md.

M series: M1✅ M2✅ M3✅ M4✅ M5✅ M6✅ M7✅ — complete.

Next: runbook sign-offs in parallel; remaining M4 advanced (O/P/Q/T series); F9/F10/W5/U3 multi-cloud (M5); W1–W3 last (D35). 28 postponed items remain.


Sequenced Full Roadmap (Track B — Sagar)

Priority Action Status Milestone
Next code K1 + K2 (IR + on-call) 🟦 external (merged) M2b
After K-series L1 + L2 + L4 (backup + DR + restore drill) M2b
After L-series D5 (policy waivers) 🟦 external (merged PR #13) M2b
After D5 F12 (brownfield imports) M3
After F12 B6 (self-service bootstrap) 🟦 v0.50 M3
After B6 F11 (module versioning) 🟦 v0.51 M3
Then C5, E7, W4 (ADO + ticket adapters + client offboarding) M3
Then Advanced package (E1–E6 full, J3, O, P, Q, T, V1, V4) 🟦 SIEM/IR/obs done (J3/K3/J5/K4/R4 v0.66); rest ⬜ M4
Next (D65) Client-facing posture visibility — V5 (Cloud Posture Report) + J8 (Client Overview Dashboard) ⬜ planned M4
Then Multi-cloud (F9, F10, W5, U3) M5
Last W1–W3 (multi-tenant) ⏸️ postponed after M2b/M3

GTM Track A — Status

Batch Assets Status Notes
A1 Y0, Y1, Y2, §3.8 🟦 drafted (v0.33) Awaiting Nidhi (Y1 claims) + Sagar (Y2 real numbers)
A2 Y3, Y4 🟦 drafted (v0.33) Awaiting Sagar's 50-account seed list
A3 Y5, Y6, Y7 🟦 drafted (v0.34)
A4 Y8, Y9 🟦 drafted (v0.34) Y8 needs brand assets; Y9 is synthetic
A5 Z0, Z1 🟦 drafted (v0.34)
A6 Y10, Y11, Y12, Y13 🟦 drafted (v0.34) Y12 needs counsel; Y13 needs HubSpot config
A7 Z2, Z3 🟦 drafted (v0.34) Unshipped delta assets flagged with milestone

Human prerequisites before going live with outbound: - Nidhi: compliance-claim review on Y1/Y5/Y7/Y9/Z2/Z3 + Y9 sanitization - Sagar: Y2 real numbers, Y3 50-account seed list, Y13 HubSpot pipeline config - Counsel: Y12 contract pack - Brand: Y8 deck design assets


DevSecOps Readiness Backlog (D72)

Status: Backlog — build on demand or when bandwidth allows. No items scheduled. Full plan: docs/context/12-devsecops-readiness.md

~70% of a DevSecOps engagement reuses existing assets (D1/D2/I1–I3 shift-left, D3/D4 policy-as-code, C2 container security, J3/K3 SIEM/SOAR, I5–I7 vuln mgmt, H1–H7 identity, E0–E6 evidence). The backlog covers the gaps:

Phase Items Trigger Effort
1 — GTM-ready DS1 (service package definition) + DS3 (threat modeling templates) Before first DevSecOps outreach ~2 days
2 — Pre-sales DS2 (DevSecOps maturity assessment tool) Before first signed engagement ~2–3 days
3 — Delivery DS4 (SLSA provenance) + DS6 (API scanning) + DS8 (security metrics) First signed engagement ~3 days
4 — Differentiators DS5 (Falco runtime) + DS7 (Dependency-Track) Mature client request ~4 days
5 — Advanced DS9 (pen test templates) + DS10 (security chaos engineering) On demand ~2 days
Tool-agnostic Scanner contract adapters (per-tool, per-category) Client mandates alternative tool ~0.5 day each

Tool-agnostic architecture (D72): Extend the F0/E1/E7 contract/adapter pattern to security tooling. CI tools normalize to SARIF (already the case); infrastructure tools (Kyverno↔Gatekeeper, Sentinel↔Splunk) swap at the module level. Don't pre-build adapters — build each when a client needs it.