Start with the decision, not a wall of scanner logos
My acceptance contract separates application behavior, declared infrastructure intent and artifact contents. Node tests exercise HTTP routes and error behavior. Terraform validates provider schemas and six mock-plan assertions. OPA evaluates topology-specific guardrails against the extracted plan. Checkov inspects Terraform and the Dockerfile; Trivy inspects the filesystem and built image. These layers observe different failure modes and are not interchangeable.
I kept the demo application intentionally small: a static engineering dashboard, a health endpoint and a read-only controls inventory. There is no login, persistence or external API call. Adding those features just to make the example look larger would create untested operational obligations and distract from the delivery contract.
- Inputs: source revision, committed provider lockfile, Terraform test events and a locally built runtime image.
- Decisions: explicit pass/fail results for mandatory jobs; skipped optional tools remain visibly not run.
- Outputs: test logs, extracted mock plan, scanner reports and a CycloneDX software bill of materials, with seven-day artifact retention.
- Non-goals: cloud provisioning, production identity, compliance certification, automatic remediation and a proven scalable service.
Connect the policy to the plan actually generated
The subtle failure is not always a weak policy. It is a strong policy evaluating the wrong input. A hand-written passing fixture could remain green after the infrastructure changed. I therefore consume Terraform's verbose JSONL test stream, extract exactly one nonempty test_plan event and evaluate that object with OPA.
The extractor rejects malformed events, multiple plans, empty changes and an existing output file. Exclusive file creation prevents a local rerun from silently reusing stale output. This is a useful consistency boundary, not a cryptographic attestation. CI must also require Terraform to exit successfully before extraction.
mkdir -p reports
terraform -chdir=infra test -verbose -json > reports/terraform-test.jsonl &&
node scripts/extract-plan.js reports/terraform-test.jsonl reports/plan.json &&
.tools/opa eval --fail --data policy/terraform.rego \
--input reports/plan.json 'data.terraform.guardrails.allow == true'Refuse unknown and weakened intent
The Rego rules expect this reference topology's managed resource types and required security values. Missing or unknown settings are not permission to proceed. The rules reject deletions, unsupported managed types, mutable image references, missing tags, insecure transport, basic publishing authentication, weakened policy definitions and disabled assignment enforcement.
Twelve named OPA tests mutate a known-good plan, including several variants within individual tests. This is more useful than proving only that the happy-path fixture passes. It still does not make the rules a general Azure compliance engine: another topology needs a reviewed extension and corresponding refusal tests.
.tools/opa test policy -v
.tools/opa eval --format pretty --data policy/terraform.rego \
--input reports/plan.json 'data.terraform.guardrails.deny'The image scan found something the application audit could not
The application has no production npm dependencies. That did not make its image clean. The initial image scan found high-severity vulnerabilities in packages shipped with the base image's npm toolchain, including brace-expansion, http-cache-semantics and undici. The application audit and image scan were looking at different dependency inventories.
My fix was to remove npm and Yarn from the final runtime filesystem because this server does not need a package manager to execute. CI asserts that their launchers are absent, runs a non-root, read-only smoke test and scans the resulting image again. I did not suppress unfixed findings or claim to have patched the upstream base layers.
A separate first-run failure was a startup race: curl reached the container before its HTTP listener was ready. A bounded readiness retry handles that transient condition; it does not turn repeated connection failures into success. Both failures changed the implementation before the reference run passed.
Scan the artifact that will execute. A dependency-free package manifest says nothing about utilities inherited from its runtime image.
Make the aggregate gate explain every skip
The final required job rejects failed, cancelled or unexpectedly skipped mandatory jobs. Snyk is explicitly optional: it runs only when enabled for trusted non-PR events and requires a token. Enabling the variable without credentials fails; leaving it disabled means not run, not no vulnerabilities.
The workflow uses read-only repository permissions, pinned direct action revisions and no cloud credentials. It does not publish images, apply Terraform or configure repository administration. A green workflow does not stop a maintainer merging a failing branch unless the required job is separately enforced through branch protection or a ruleset.
Four Checkov exceptions are documented per resource with their rationale. Exceptions are part of the review surface, not proof that the corresponding operational risks disappeared. Scanner service or database failures remain failures rather than empty successful reports.
Evidence from one revision is not a permanent guarantee
At revision 4aefdf1de98fa4742ab42dee15c388f6e59cb90e on 2026-10-18, local validation passed 11 Node tests and 12 OPA tests; the linked GitHub Actions run passed every mandatory job. Snyk was intentionally skipped. Those are dated results, not a claim that the current branch or vulnerability database will always pass.
Reports expire after seven days. The run remains a useful execution record, but an expired artifact cannot be inspected as though it were retained evidence. Reproduce the commands against the revision being reviewed and inspect current findings before relying on it.
What I would require before a real deployment
Mocked planning cannot verify RBAC, Azure Policy alias behavior or propagation, regional capacity, image pulls, health probes or diagnostic delivery. The supplied image input is deliberately a digest-pinned base Node image, not the built application image; applying the template would not deploy this server.
The next stage needs an approved deployment design, a published and scanned application artifact, real identity and backend configuration, cost and capacity checks, runtime verification and a production security review. The example premium plan would incur charges. There is no apply job, and terraform apply is not a demo step.
I would keep proposal, authorization and execution separate as that stage grows. The project is strongest when its boundary is precise: reproducible checks of declared intent and runtime contents before deployment, not an invented story about live cloud enforcement.