conftest verify: Unit Test Conftest Policies
conftest verify executes the test_ rules inside your policy directory, confirming the policies behave before you gate real config on them.
Where conftest test checks config against policy, conftest verify checks the policy itself. It runs your Rego unit tests so a change to a deny rule cannot silently start passing or failing.
What it does
conftest verify loads the policy directory and evaluates every rule whose name begins with test_ , the same convention opa test uses. A test that evaluates to false or errors fails the run and produces a non-zero exit. It does not take input files; the tests supply their own data.
Common usage
# run policy unit tests in ./policy
conftest verify
# point at a specific policy directory
conftest verify --policy security/
# emit a coverage-style report
conftest verify -p policy/ --report fullOptions
| Flag | What it does |
|---|---|
| -p, --policy <path> | Policy directory containing test_ rules |
| --report <mode> | Report detail: full, notes, fails |
| -o, --output <fmt> | Output format: stdout, json, tap, table, junit |
| --data <path> | Additional data documents to load for the tests |
In CI
Run conftest verify in the policy repo on every change to the rules, and run conftest test in consumer repos against real manifests. Keeping the two separate means a policy regression fails in the policy repo, not mysteriously in a downstream service pipeline.
Common errors in CI
A failing assertion prints "FAIL - <package> - test_<name>" with a totals line and exit 1. "no policies found" means --policy is wrong or the directory has no .rego files. "rego_parse_error" means a policy file will not compile. If the summary shows 0 tests run, the rules are not prefixed test_ or live outside the given path.
Using this in CI
A runner has no kubeconfig, no cached context, and no interactive auth. Every kubectl invocation in CI needs the context supplied explicitly, and most confusing CI failures here are the command running against the wrong cluster or no cluster at all.
# never rely on the ambient context on a runner
kubectl --context "$KUBE_CONTEXT" -n "$NAMESPACE" get pods
# confirm what you are actually connected to before mutating anything
kubectl config current-context
kubectl cluster-info
# fail fast instead of hanging on an unreachable API server
kubectl --request-timeout=30s get nodes