--fail-on and --exit-code.
The contract
Everything downstream of source acquisition degrades instead of failing. Detector
errors, unreadable files, and corrupt headers become
Unknown records in the output —
they never change the exit code. A partial inventory is still a successful scan.Turning on the gate
1
Scan and report (no gate)
Report only — always exits 0
2
Add a policy
--fail-on compiles an expression and evaluates it against the assembled
inventory after all output has been written. A match exits 1.Fail when a high-confidence hosted LLM is present
3
Choose the exit status
Match exits 3 instead of 1
--exit-code and --fail-on interact
--exit-code must be in [0,255]; anything else is a configuration error (exit 2).
The --fail-on grammar
Grammar
& binds tighter than |, so a|b&c reads as a | (b & c). Whitespace around tokens
is ignored. A dangling & or | is a configuration error (exit 2). A --fail-on that
is empty or all whitespace sets no policy at all — it is not an error, and it does not
gate.
Each clause must be satisfied by a single component
This is the rule that surprises people.hosted-llm&confidence>=0.9 means “some one
component is a hosted LLM and that same component has confidence ≥ 0.9.” It does
not mean “a hosted LLM exists somewhere and, separately, something else is
high-confidence.”
The
application root component — the scan target itself — is never eligible to match a
policy. It is the thing you scanned, not a finding.Terms
ComponentKind
A component kind —
hosted-llm, local-model-file,
embedding-model, framework, library, vector-db, prompt, dataset,
ai-config, infra, service, rag-pipeline, application.risk | risk:severity | risk:slug
Matches a component carrying an artifact risk.
risk matches any
risk; risk:high / risk:medium / risk:low match by severity; risk:<slug> matches
one catalog entry (pickle-import, keras-lambda, gguf-template, savedmodel-pyfunc,
unsafe-load). pickle-risk remains as a deprecated alias for risk:pickle-import.compliance | compliance:framework[:control]
Fires on a compliance gap (a manual control is not a failure;
a met is a pass).
compliance:gap — any gap; compliance:<framework> — a gap in that
framework; compliance:<framework>:<control> — that control is a gap. It is
inventory-level, so it cannot be &-combined with a component term (use |), and it
requires --compliance to have been given — gating on a framework you never evaluated is
a configuration error, not a silent pass. Like every selector it evaluates the full
assembly, so --min-confidence never relaxes it.comparison
Compares the component’s confidence against a bound in
[0,1]. Operators: >=, <=,
>, <, =. A bound outside [0,1] is a configuration error. Bare confidence
with no operator is rejected — it is almost always a typo.Worked examples
Shell notes
Quote the expression. Both& and | are shell metacharacters:
Always quote --fail-on
.airom.yaml:
Unknown keys and unknown
AIROM_* variables fail loudly with exit 2. A typo never
silently disables your gate.Next
GitHub Actions
A copy-pasteable workflow: scan, upload SARIF, gate.
CLI reference
Every command and global flag.