A worked end-to-end example. We collect evidence from a fictional company’s cloud, seal it, map it to controls, and measure coverage — and follow a single risky account the whole way down, so you can see exactly what each tool hands to the next.
Northwind runs on AWS, GitHub, and Postgres. You’re gathering evidence for a SOC 2 Type II examination covering Q3 2026. Rather than trace every file, we’ll follow one account that turns out to matter — and watch it change shape at each handoff.
audit-tools runs read-only collectors against each platform and writes plain CSVs into one dated package directory — here, aws_audit_northwind_2026-07-29/. No judgments yet: just the facts as the systems report them, one file per procedure.
In iam_users.csv, most users are fine. One row isn’t: j.hale can log in to the console but has no second factor. That’s our thread.
# Interactive: pick platform, checks, credentials python audit_tui.py # → writes a package of CSVs output/aws_audit_northwind_2026-07-29/ iam_users.csv password_policy.csv account_security.csv open_security_groups.csv config_recorders.csv cloudtrail.csvaudit-tools on GitHub →
| user | console_password | mfa_enabled | oldest_key_age_days |
|---|---|---|---|
| a.okafor | True | True | 62 |
| j.hale | True | False | 404 |
| svc-deploy | False | — | 91 |
| r.mendez | True | True | 15 |
The moment collection finishes, seal the directory. evidence-seal hashes every file into a single Merkle root. Months later, verify proves the package is byte-for-byte what you collected — and names anything that moved.
If someone later edits j.hale’s row to look compliant, the root no longer matches and verify fails loudly. Re-seal each collection round with --prev to chain a Type II custody history.
# Seal, then (much later) verify
evidence-seal seal ./output/aws_audit_northwind_2026-07-29
evidence-seal verify ./output/aws_audit_northwind_2026-07-29
evidence-seal details →
audit-report reads the CSV package and applies a declarative ruleset. A rule names a table, a check, and the controls the signal is evidence for. The iam-console-no-mfa rule fails j.hale and maps it to SOC2:CC6.1, NIST:IA-2, and ISO:A.5.17.
JSON feeds the next stage; the same run also emits an auditor-ready HTML report. Add --baseline to diff against last quarter and flag drift.
# Machine-readable JSON for the next stage audit-report ./output/aws_audit_northwind_2026-07-29 \ --format json,html --out reports/ 12 checks · 3 exceptions → reports/aws.jsonaudit-report details →
Every earlier tool is evidence-first — it can only speak to what you collected. control-coverage supplies the missing denominator: the complete catalog of a framework’s controls. Feed it the report JSON(s) and it reports coverage %, the blind spots nothing touches, and a Statement of Applicability.
The payoff for our thread: CC6.1 is now addressed — even as an exception, the control is no longer a blind spot, because step 3 produced a finding mapped to it. The blind spots are the controls no collector reached at all.
# Fold all reports into one framework picture control-coverage reports/ --framework SOC2 \ --format md,html,soa --out out/ # Gate CI under a coverage floor control-coverage reports/ --fail-under 60control-coverage details →
Each tool cares only about the shape of the artifact it’s handed. That’s why you can run one step or the whole chain — and swap the collector without the rest noticing.
Swap the collector, free of charge. gh-attest is the continuous variant of step 1 — a read-only GitHub App that captures branch protection and access over time and exports the same CSV-package shape. It drops straight into steps 2–4 unchanged.