Skip to content

V5 — Client Cloud Posture Report — Test Runbook

Asset: V5 (apps/posture-report/) — offline composer that bundles E0/S2/S4/L5/V2 (+ optional K4) into one branded, deliverable-organized client posture report (markdown + HTML, optional PDF). Owner: SH · Milestone: M4 · Cloud cost: $0 (offline-only).

V5 is a pure composition tool — it never touches Azure. This runbook is offline-only (Parts A + B); there is no live phase, mirroring S4.md / L5.md.


Part A — Offline build + test gate (~3 min, $0)

Proves the composer builds, typechecks, and its pure core passes its suite.

cd apps/posture-report
npm ci
npm run typecheck         # tsc over src + tests, --noEmit
npm test                  # jest: compose + render suites

Acceptance: - [ ] npm run typecheck exits 0. - [ ] npm test is green — composition, honest-missing-input, tier tagging, grade-source (S4 scorecard preferred, E0 fallback), the never-fabricate cost section, trend-sign derivation, HTML self-containment + injection safety, and determinism. - [ ] The app is auto-discovered by .github/workflows/app-tests.yml (it has a package.json with a test script), so CI runs the same suite on PRs.


Part B — Worked composition (~4 min, $0)

Compose the report from the committed example fixtures (the same data the posture-report.yml workflow uses for its offline demo).

cd apps/posture-report
npm run build
node dist/index.js \
  --client-name "Acme Corp" \
  --branding  examples/branding.json \
  --scorecard examples/scorecard.json \
  --snapshot  examples/snapshot.json \
  --dashboard examples/dashboard.json \
  --rto-rpo   examples/rto-rpo.json \
  --incidents examples/incidents.json \
  --diagram   examples/architecture.d2 \
  --out-dir   /tmp/posture \
  --now 2026-06-09T12:00:00.000Z

Acceptance — composition is re-presentation, never fabrication: - [ ] Writes posture-report.md, posture-report.html, and model.json to /tmp/posture. Stdout reports grade B for Acme Corp. - [ ] Headline grade comes from the S4 scorecard verbatim — the derivation line begins "From the S4 scorecard:". Re-run without --scorecard and confirm the grade is instead derived from the E0 snapshot (derivation says "derived here from the E0 snapshot"). - [ ] Sections are organized by deliverable and tagged: Executive summary [Baseline], Your guardrails [Baseline], Your data is protected [Baseline], Your compliance posture [Advanced], Incidents we handled [Advanced], Cost governance [Baseline], Architecture [Baseline]. - [ ] Honest missing inputs: re-run with only --snapshot + --client-name + --out-dir. The compliance-posture and incidents sections render a "not supplied / Advanced package" note, and an upsell teasers section ("What else SnowOps can light up") appears. - [ ] Cost governance is never fabricated — it always renders as a roadmap note referencing the not-yet-wired U4/U5 FinOps feed, even when every other input is supplied. - [ ] HTML is self-containedgrep -c 'http' /tmp/posture/posture-report.html returns 0 when no logoUrl is set (inline CSS, no JS, no network refs; safe to upload as a CI artifact). The d2 diagram is HTML-escaped into a <pre> (no markup injection); an .svg diagram is embedded inline. - [ ] Optional: --pdf renders posture-report.pdf via Pandoc where available; a Pandoc failure is logged but never fails the run.

Delivery: .github/workflows/posture-report.yml (monthly + dispatch) runs this composition and uploads a PRIVATE artifact (14-day retention) — posture data is sensitive. The QBR delivery guide is under docs/client-guides/.


Notes

  • No cross-package imports (D37/D40/D49): V5 re-declares the E0/S2/S4/L5/K4 input contracts and the V2 diagram shape; it depends on the versioned artifact shapes, not the producing packages.
  • Cost + incidents data feeds: incidents reuse the K4 report when supplied; cost has no SnowOps producer yet (U4/U5 postponed), so it degrades honestly. Wiring them is a follow-on, not a blocker (D65).