Interbolt
Guides

CI

Checking a policy file with interbolt validate in CI or pre-commit.

CI

interbolt validate

interbolt validate policy.yaml

Performs schema and CEL checks only; see Policies: static validation for the full list. It never executes an agent and never observes live taint, and imports no consumer code, which is what lets it run anywhere a file can be read: CI, pre-commit, a developer's shell. It runs in milliseconds.

Problems come in two kinds, and the exit code follows the more serious one:

  • Errors (a schema violation, a CEL parse failure, an unreachable rule, a reference to an uncomputed trifecta leg or run. field, a policy declaring version: "1.0" or a sink entry written as a bare rule list) exit 1.
  • Warnings (a t.source comparison, a sink entry with no capabilities: key once another entry declares one) print but exit 0, so a policy that is valid with warnings does not fail the build.

The Python-level equivalent, for a custom CI script or a test. Warnings are prefixed warning: , so filter them out if you want the same behavior as the CLI:

from interbolt import Policy

problems = Policy.validate("policy.yaml")
errors = [p for p in problems if not p.startswith("warning: ")]
if errors:
    raise SystemExit("\n".join(errors))

Pre-commit

# .pre-commit-config.yaml
- repo: local
  hooks:
    - id: interbolt-validate
      name: interbolt validate
      entry: interbolt validate policy.yaml
      language: system
      pass_filenames: false

Pair it with decision tests

A clean validate means the policy is well-formed, not that it matches your agent. It cannot see a sink key that matches no guarded tool, an args.* reference that does not match a real signature, or a carve-out rule placed below the rule it was meant to except. See Policy evaluation internals: what it does not catch.

It also cannot tell you whether a specific agent's access silently changed: adding an agent to a group changes what fires for it with no rule edit at all. See Explain for the golden-file pattern that covers that gap.

Cover those with check()-based decision tests in the same job, so the static and dynamic checks land together:

interbolt validate policy.yaml && pytest tests/test_policy.py

See Testing for the test patterns.

The INTERBOLT_MODE escape hatch

interbolt validate is the static check. The dynamic counterpart is running your actual test suite with the policy enforced. If a known-noisy or in-progress policy is blocking an unrelated CI job, the INTERBOLT_MODE environment variable overrides both configure(mode=...) and the policy file's defaults.fail_mode:

INTERBOLT_MODE=monitor pytest

This downgrades evaluation errors to log-and-proceed without disabling real block decisions. The override logs a WARNING whenever it changes the effective mode, so it is meant as a visible, one-off operator action, not something to set as a CI configuration default.

See Auditing for running the laundering audit against a recorded workload in a staging job.

On this page