Git, CI/CD & GitOpsCXVI · Governance Without BureaucracyCompliance
Continuous compliance — the automated audit
What you'll learn
- Explain what continuous compliance is and how it differs from a point-in-time audit
- Identify the evidence sources - PR pipeline, image scan, drift report, attestations - and the cadence each contributes
- Wire a compliance control into the same PR pipeline as a governance control with the same branch-protection gate
- Produce an audit-evidence bundle that an external auditor can review without bespoke queries
Prerequisites
Verified against Git 2.55.x teaching target; 2.40+ minimum · GitHub Actions continuous service; Aug 2026 documentation baseline · Argo CD v3.5.x teaching target; v3.0+ minimum · Flux v2.9.x · Sigstore Cosign v3.1.x · SLSA v1.2 · OCI Distribution Specification v1.1 · Git LFS v3.7.1 · Kubernetes (cross-course target) 1.36.x
Continuous compliance is the conversion of a point-in-time audit into an automated evidence pipeline. The audit moves from “once a year an auditor arrives” to “every PR produces evidence that the auditor can review on demand”. This lesson teaches the evidence sources, the cadence, and the audit-evidence bundle that makes the difference.
The point-in-time audit
The traditional compliance programme is a point-in- time event. An auditor arrives once a year. The auditor asks for evidence: who approved this change, who reviewed this deploy, when was this access last reviewed, what was the state of this control on March 15. The team gathers the evidence manually - exports from GitHub, screenshots from cloud consoles, PDFs of policy documents. The evidence is assembled for the audit window; outside the window, the same evidence is not collected.
flowchart LR
A["Auditor arrives\nonce a year"] --> G["Team gathers\nevidence manually"]
G --> E["PDFs, screenshots,\nexports"]
E --> AUDIT["Audit passes\n(or fails)"]
AUDIT -->|"outside window"| GAP["No evidence:\nthe rest of the year"]
The point-in-time audit is a ceremony. The cost is paid by the team in the weeks before the auditor arrives; the evidence is collected for a window that is narrower than the year. The auditor sees a snapshot; the snapshot is incomplete; the team’s actual day-to-day compliance posture is unknown to the auditor.
The continuous evidence pipeline
A continuous compliance programme replaces the ceremony with an evidence pipeline that runs every day. The pipeline produces the same artefacts the auditor would have asked for, on a continuous cadence, indexed by time. The auditor (internal or external) queries the bundle instead of asking for screenshots.
The evidence sources:
- The PR pipeline produces approval evidence. Who opened the PR, who reviewed, who approved, which CI checks ran, which policy verdicts were issued. The GitHub API returns the PR object as a JSON artefact.
- The image scan produces vulnerability evidence. Trivy or Grype output is JSON; the JSON is stored alongside the image digest.
- The drift report produces configuration evidence. Argo CD or Flux exports the live state versus the desired state; the diff is JSON.
- The in-toto attestation produces supply-chain evidence. The attestation names the builder, the materials, and the steps. The attestation is signed.
- The access report produces IAM evidence. The cloud API exports the IAM roles and their last-used timestamp; the export is JSON.
flowchart TB
subgraph SOURCES["Evidence sources"]
PR["PR pipeline:\napprovals, reviews, checks"]
IMG["Image scan:\nTrivy / Grype JSON"]
DRIFT["Drift report:\nGitOps controller export"]
ATT["in-toto attestation:\nsigned build record"]
IAM["Access report:\nIAM roles + last-used"]
end
subgraph BUNDLE["Evidence bundle:\nindexed by time"]
E1["PR @ 2026-03-15T09:23"]
E2["Scan @ 2026-03-15T09:25"]
E3["Drift @ 2026-03-15T09:30"]
E4["Attestation @ 2026-03-15T09:35"]
E5["IAM @ 2026-03-15T00:00"]
end
SOURCES --> BUNDLE
BUNDLE --> Q["Auditor query:\n'who approved the\ndeploy at 09:23?'"]
The auditor’s query becomes a database query against the bundle, not a request for a screenshot. The bundle is queryable; the bundle is durable; the bundle covers the entire year, not the audit window.
Wiring compliance into the PR pipeline
A compliance control is a governance control with a specific audit mapping. The wiring is identical: the check runs in the PR pipeline; the verdict is a required status check; the branch-protection rule disables the merge button until the check passes. The only difference is that the check is annotated with a control identifier (the SOC 2 criterion number, the CIS Benchmark section, the NIST 800-53 control) so that the verdict can be mapped to the audit framework.
# Conftest evaluates the manifest against the policy
conftest test --policy policy/ manifests.yaml
# The policy file maps each rule to a control
# a Rego annotation can carry the mapping
package policy
# SOC 2 CC6.1 - logical access controls
deny[msg] {
input.kind == "Deployment"
not input.spec.template.spec.containers[_].securityContext.runAsNonRoot
msg := "SOC 2 CC6.1: containers must runAsNonRoot"
}
flowchart LR
P["PR opened"] --> CI["CI:\npolicy + control mapping"]
CI --> V["Verdict:\nallow / deny"]
V -->|"deny"| BP["Branch protection:\nmerge blocked"]
V -->|"allow"| M["Merge allowed"]
M --> E["Evidence:\nverdict + mapping in CI log"]
E --> BUNDLE["Bundle:\nindexed by SHA + time"]
The mapping is what turns a governance check into a compliance check. The check’s verdict is the evidence; the mapping names the control the verdict satisfies. The auditor can query “show me every deployment that failed SOC 2 CC6.1 in Q1” and the bundle answers in seconds.
The evidence bundle
The bundle is the artefact the auditor reviews. The bundle has four properties:
- Indexed by time. Every event has a timestamp. The auditor’s queries are time-windowed.
- Indexed by SHA. Every artefact references the Git commit that produced it. The auditor can trace a verdict to a PR to a commit.
- Indexed by control identifier. Every event carries the control identifier (SOC 2 CC6.1, CIS Benchmark 1.4, NIST AU-2) it satisfies.
- Signed. The bundle is signed by the pipeline that produced it. The signature is verifiable; tampering is detectable.
flowchart LR
E["Event:\nverdict / attestation / drift / IAM"] --> T["Timestamp"]
E --> S["SHA reference"]
E --> C["Control identifier"]
E --> SIG["Signature"]
T --> B["Bundle"]
S --> B
C --> B
SIG --> B
B --> Q["Auditor query"]
Production discipline
- Map every governance check to a control identifier. The mapping is in the policy file alongside the rule.
- Collect evidence on every PR. The PR pipeline records the verdict and the mapping.
- Index the bundle by time, SHA, and control. The auditor’s queries are answered in seconds.
- Sign the bundle. The signature is verifiable by the auditor without out-of-band trust.
Cross-course references
- This course, Part CXVI-03 covers the policy-as- code engines that produce the compliance verdicts.
- This course, Part CVII (ProductionArch) names the seven components whose state the bundle records.
- Terraform for Production Sysadmins - Part XII (State) covers the Terraform-plan JSON that populates the bundle for cloud-resource compliance.
Quiz
Knowledge check · 4 questions
Q1. An external auditor asks the team to demonstrate that every production deploy in Q1 was reviewed by someone other than the author. The team gathers this evidence manually by reading PR threads. What is the continuous-compliance fix?
Q2. Duplicating an existing governance check is not a structural control by itself, because duplication does not guarantee that the audit mapping is satisfied.
Q3. Name the four indices of a continuous-compliance evidence bundle.
Q4. Design the continuous-compliance programme for the team, including the evidence sources, the bundle schema, and the auditor query interface.
Team T is preparing for a SOC 2 Type II audit covering a six-month window. The audit asks for evidence on: (a) every production change was approved by a non-author; (b) every container image was scanned for critical vulnerabilities; (c) every IAM role was reviewed in the last 90 days; (d) every deploy was reconciled from a Git commit (no manual cluster changes). The team has a PR pipeline, an image-scan step, a GitOps controller, and an IAM role inventory.
Passing score: 75%. Answers are checked in this browser.