Skip to Content
ReferenceRule CLI

Rule CLI

trustacks rule is the command-line tool for TruStacks policy. It writes, tests, lints and signs rules in a local checkout, with no control plane and no account. It is the local alternative to Propose as PR in the app: use it to write a rule by hand, or to land a rule drafted by /rule new from your own checkout. See Add your own rule.

Running it

There is no standalone CLI package. Run it from the runner image, which also carries opa, oras, and cosign:

docker run --rm --user "$(id -u):$(id -g)" \ -v "$PWD:/work" -w /work \ ghcr.io/trustacks/runner:<version> \ trustacks --help

If you work from a source checkout of the runner, uv run trustacks does the same.

From 0.2.17, rule test, lint and sign run opa with the same restricted builtins the runner uses (no network, environment or schema $ref fetching), so a rule that passes locally compiles on the runner too. The runner image carries a matching opa. If you use your own opa from a source checkout and it is much older, you may need to upgrade it.

Conventions

  • Exit code 0 on success, 1 on any failure.
  • Output is for people (Rich formatting). There is no JSON output mode.
  • There is no config file and no login command: trustacks rule works on local files only.

Overlay rules: trustacks rule

Every rule command takes --overlay PATH, a local checkout of your overlay repo. It defaults to the current directory and must contain environment-profile.yaml at its root. Rules live in rules/<rule_id>/.

trustacks rule new

trustacks rule new <rule_id> [--description TEXT] [--package NAME]

Scaffolds rules/<rule_id>/<rule_id>.rego and <rule_id>_test.rego. The rule ID must meet the naming standard. The package defaults to overlay.<namespace>_<name>. A --package you pass must start with overlay.; anything else is refused, because the runner rejects overlay rules outside data.overlay (details).

The stub’s deny condition is false, so it never fires until you replace it. The test file ships one passing baseline test and a commented template for the real one. Refuses to overwrite an existing rule directory.

trustacks rule new acme.requires_runbook_link \ --description "Every service ships a runbook link"

The stub declares every rule metadata field, as a structural rule that applies everywhere:

rule_metadata := { "acme.requires_runbook_link": { "description": "Every service ships a runbook link", "kind": "structural", "required_tooling_categories": [], "practice_dimensions": [], "tier_scope": ["any"], "target_kinds": ["any"], }, } rule_index := rule_metadata

Change kind to "behavior" and name at least one practice in practice_dimensions if the rule judges how a change’s files behave. Add "subjects": ["proposal", "repo"] to include it in the repo audit. Without --description, the description is a TODO placeholder.

trustacks rule test

trustacks rule test [rule_id] [-v | --verbose]

Runs opa test on one rule’s directory, or on all of rules/. --verbose prints each test name. Exits with opa’s status. An overlay with no rules/ directory exits 0.

trustacks rule lint

trustacks rule lint [rule_id]

Checks rule ID validity, that both files exist, that the rule declares a package and a rule_metadata map keyed by its ID, then runs opa check, the overlay confinement check (every package under overlay., data only in data.overlay, no symlinks, allowlisted file types) and the rule metadata check: every required field declared, with values in the schema. Without opa on your PATH, it skips opa check, the package part of confinement and the metadata check. See Policy linter for the full list and what it does not check.

trustacks rule sign

trustacks rule sign [--bundle-ref REF] [--registry HOST:PORT] [--tag TAG] [--key PATH] [--signing-config PATH] [--insecure | --no-insecure]

Builds an OPA bundle from rules/ (with a rule_inventory.json), pushes it with oras, and signs the pushed digest with cosign. Every rule ID is checked against the naming standard first, and the overlay confinement check runs before the build: an overlay that reaches outside data.overlay is refused, not signed. It does not run the rest of lint, or test.

FlagDefault
--bundle-ref<registry>/trustacks/policy/overlay/<profile name>:<tag>, where the profile name is name: in environment-profile.yaml
--registryzot.localtest.me:8080
--tagdev
--key.policy-keys/cosign.key
--signing-config.policy-keys/signing-config.json (offline, no transparency log)
--insecure / --no-insecure--insecure (plain HTTP)

The defaults target the local development registry and a local key, and per-customer signing keys are not built. A hosted runner (0.2.17 and later) does not need a bundle: it loads your rules from rules/ in your platform repo. See the constitution page.

Not in the CLI

These appeared in earlier versions of this page and do not exist: rule list, rule show, env declare, env validate, env diff, login, status, version, --output json, and ~/.trustacks/config.yaml. Browse rules on the Rules page instead.

Where to go next

Last updated on