skip to content

What file formats can conftest test, and how does a CI job learn it failed?

level: juniorimportance: should knowfreq 58%

answer

  1. one binary, many parsers
  2. the file extension picks the parser
  3. everything becomes one generic document
  4. CI reads the exit status, not the text
  5. warnings do not fail by default

basics

~20 s

conftest parses structured configuration - YAML, JSON, HCL, Dockerfiles, TOML, INI and more - into one JSON-like document and evaluates policies against it. Failures print to the console and the process exits non-zero, which is the signal CI acts on.

solid answer

~40 s

conftest is a single binary that tests configuration files against policies written in Rego. It picks a parser from the file extension - YAML, JSON, HCL/HCL2, Dockerfile, TOML, INI and others - and turns each file into one generic document, so the same policy engine covers a Kubernetes manifest, a Terraform file and a Dockerfile. You can force a parser with `--parser` when the extension is unhelpful. By default it evaluates each file separately and prints per-file results plus a summary of passes, warnings and failures. The exit code is the contract with CI: failures exit non-zero and fail the step, while warnings exit zero unless you pass `--fail-on-warn`. `--output` can emit JSON, TAP or JUnit for reporting, but the pass/fail decision the pipeline makes still comes from the exit status.

go deeper

for a junior

Be ready to say what conftest is, name a few formats it parses, and state plainly that CI fails the step because the process exits non-zero. Knowing that warnings do not fail by default already puts you ahead.

for a middle

Explain parser selection by extension and the --parser override, and that policies see a parsed data structure rather than file text. Distinguish a policy failure from an error such as an unparseable file or a policy that will not compile.

for a senior

Show that you treat a green run sceptically: know the ways a run can exit zero having evaluated nothing, and describe how you prove a control actually executed rather than trusting the badge.

for a principal

Own the question of where in the delivery path this binary runs and what its exit code is allowed to block, so that the same rules give a developer the same answer locally that the pipeline gives them later.

## The idea Most policy tools are welded to one input. A Kubernetes admission controller only ever sees Kubernetes objects; a Terraform-specific scanner only understands Terraform. conftest takes the opposite approach: it is one binary that knows how to **parse many configuration formats into a single generic document model**, and then evaluates the same kind of policy over whatever came out. That is why a platform team can run one engine across dozens of repositories that hold a mix of manifests, pipeline definitions, Dockerfiles and infrastructure code. ## Parsing conftest ships parsers for, among others, YAML (including multi-document files), JSON, HCL and HCL2, Dockerfile, TOML, INI, CUE, Jsonnet, XML and properties files. The parser is selected from the file extension. Two consequences follow immediately: - A file with an unusual extension will not be parsed the way you expect. `--parser yaml` (or `dockerfile`, `hcl2`, and so on) forces the choice, which is also how you evaluate content piped in on stdin. - Parsing is **structural, not textual**. Policies never see the original text, indentation or comments; they see the data structure the parser produced. A rule that tries to reason about the raw file contents is written against the wrong thing. A multi-document YAML file is handled as multiple documents rather than one, so a file holding a Deployment and a Service is not a two-element object you have to index into. ## Where policies live Policies are Rego files in a policy directory, `./policy` by default, overridable with `-p/--policy` (repeatable). Each file declares a package, and conftest calls that package the rule's **namespace**. By default it evaluates only the `main` namespace; `-n/--namespace` selects others and `--all-namespaces` evaluates everything it loaded. That selection is how one shared rule library can hold Kubernetes rules, Dockerfile rules and pipeline rules side by side while a given repository only runs the subset that applies to it. ## The run loop Without extra flags, conftest evaluates **each input file independently**: file in, document out, policy evaluated, results collected, next file. So results are naturally per-file and a failure message can be attributed to the file that caused it. (The `--combine` flag changes this to a single evaluation over all files at once, which is a different mode with different rule semantics.) ## Results and the exit code The run prints each finding and then a summary line counting tests, passes, warnings and failures. What matters for automation is the process exit status: - **Failures present -> non-zero exit.** The CI step fails and, if that step is a required check, the change is blocked. - **Only warnings -> exit zero**, unless you pass `--fail-on-warn`. Warnings exist precisely so a rule can be visible before it is enforced. - **An error** - a policy that will not compile, a file conftest cannot parse, a policy directory that contains no policies at all - is also a non-zero exit, and it is a different situation from a policy failure even though CI sees the same red. `--output` controls the human/machine formatting (table, JSON, TAP, JUnit and similar) for dashboards and test reports. It does not change the verdict; the pipeline's decision still rests on the exit code, so never wrap the invocation in something that swallows it. ## What a green run does and does not mean This is where beginners get burned. Exit zero means *no rule in the selected namespaces produced a failure for the files you passed*. It does not mean the file is safe, and it does not even mean any rule ran. If the glob missed the file, if the extension has no parser attached, if the rules live in a namespace you did not select, or if the policy package was renamed, the run is green and empty. Treating a green conftest step as evidence that a control was enforced is exactly the claim an auditor will ask you to substantiate, and "the job passed" is not enough on its own. ## Where it sits Because it is a static binary reading files off disk, conftest runs anywhere the files are: a pre-commit hook, a pull-request check, a build step before an image is pushed, or a pre-deploy step over rendered manifests. Running the same binary and the same rules in more than one of those places is normal, and it means a developer sees the same message locally that the pipeline will produce.

  • Your team stores Kubernetes manifests in files named with a `.k8s` extension. Will conftest parse them?
    Not on its own - the parser is chosen from the extension, so an unrecognised one either fails or is not handled the way you want. Pass `--parser yaml` to force the right parser. The same flag is how you evaluate content piped in on stdin, where there is no filename to inspect at all.
  • Does a zero exit code prove the configuration is compliant?
    No. It proves that no rule in the namespaces you selected produced a failure for the files you actually passed. Zero matching rules also exits zero. To claim enforcement you need evidence that rules ran - a canary fixture that must fail, or asserting on the machine-readable output's counts - not just a green step.
  • How would you make a new rule visible without breaking anyone's build?
    Emit it as a warning rather than a failure. Warnings print in the results and are counted in the summary but exit zero, so the pipeline stays green while teams see the message. When adoption is good enough, promote it to a failure - or turn on `--fail-on-warn` - as a deliberate, announced step.

Like a universal power adapter: many different plugs on the input side, one standard socket on the other, so the appliance behind it never has to care which country the cable came from.

saying these in an interview costs you the question

  • Thinks conftest only works on Kubernetes YAML
  • Assumes warnings fail the build by default
  • Says CI parses the printed output instead of reading the exit code
  • Believes a green run proves a rule actually ran
  • Expects policies to see raw file text, comments included

context