CoursesPolicy-as-code at scaleCI parity with Conftest and opa eval

CI parity with Conftest and opa eval

Catch violations before the cluster sees them.

In short. If admission is the only enforcement point, developers discover policy when their deploy fails at 5 p.m. CI parity means the same rules (or faithful equivalents) fail the pull request earlier.

Advanced30 min · lesson 11 of 13

If admission is the only enforcement point, developers discover policy when their deploy fails at 5 p.m. CI parity means the same rules (or faithful equivalents) fail the pull request earlier. Conftest runs Rego against YAML/JSON in pipelines; opa eval and opa test catch unit issues; some teams render Helm/Kustomize first so CI sees the same shapes the cluster will see.

Parity is not identical binaries — it is identical decisions. When CI allows what admission denies, trust collapses. Version policy bundles and pin them in both places.

Conftest in CI

terminal
conftest test --policy policy/ k8s/deployment.yaml
echo exit=$?
output
FAIL - kubernetes/deployment.yaml - missing app label
exit=1
Shift-left policy
1Render manifests
helm template / kustomize
2conftest/opa
same deny rules
3unit opa test
fixtures
4admit in cluster
final PEP
Pin policy bundle version in CI and cluster to the same tag during a rollout wave.

Avoiding false confidence

Scanning only incomplete manifests (unrendered Helm) creates false greens. Feed CI the rendered output. For Gatekeeper, extract Rego into a tested package Conftest can import. For Kyverno, use kyverno apply in CI where possible.

Different rule copies
Two handwritten versions of "no privileged pods" will drift. One library, many PEPs.

Going deeper

Cache policy bundles in CI to keep PR feedback fast, but verify checksums against the pinned version. Stale caches that silently miss new denies are dangerous.

Monorepos should run policy tests only on affected rendered packages when possible, plus a nightly full estate run. Correctness of the full run matters more than micro-optimizing PR minutes.

Publish human-readable failure annotations on PRs (GitHub checks) quoting the deny message. A red X without the registry allowlist hint just trains people to rerun.

Mutating policies complicate CI parity — rendered fixtures must include the post-mutate shape or CI will allow what the cluster mutates-then-validates differently. Prefer validating the post-mutation object in both places when mutate is in play.

For pull requests that only change application code without manifests, skip heavy renders but still run opa unit tests on the policy library itself when policy files change. Selective gates must never skip policy self-tests.

Publish a green/red sample repository that demonstrates passing and failing manifests for every critical rule. Onboarding goes faster when engineers can clone a known-good pattern.

Keep a changelog of policy bundle versions consumed by CI pins so rollbacks are a one-line revert, not an archaeology exercise.

Try this

Run conftest against a bad Deployment fixture and a good one; wire exit codes into a sample CI job script.

terminal
conftest test --policy policy/ fixtures/bad.yaml || echo blocked
conftest test --policy policy/ fixtures/good.yaml && echo allowed
output
FAIL - …
blocked
PASS
allowed

Takeaway

CI policy gates give the same answer earlier. Render real manifests, pin bundle versions, and keep one rule library behind both CI and admission.

Next: distribute those bundles across many clusters without snowflake YAML.

Quick check
01CI parity means…
Incorrect — No — defense in depth.
Correct —
Incorrect — Insufficient.
Incorrect — Not parity.
02Why render Helm before conftest?
Incorrect — It can.
Correct —
Incorrect — No.
Incorrect — OPA needs JSON/YAML documents, not charts per se.

Related