Skip to main content

Custom Policies

Anvil evaluates custom rules written in OPA/Rego. This tutorial walks through creating, testing, and running a policy that limits file length.

Prerequisites

  • Anvil initialised in your project (anvil init)
  • OPA binary installed (install guide)

Verify OPA is available:

opa version

1. Create the Policies Directory

mkdir -p .anvil/policies

Anvil loads every .rego file in this directory automatically.

2. Write the Policy

Create .anvil/policies/max_file_length.rego:

package anvil.policies.max_file_length

import future.keywords.if

default max_lines := 300

max_lines := input.config.max_lines if {
input.config.max_lines
}

violation[msg] {
count(input.file.lines) > max_lines
msg := sprintf("%s exceeds %d lines (%d)",
[input.file.path, max_lines,
count(input.file.lines)])
}

How it works:

  • max_lines defaults to 300 but can be overridden via input.config
  • The violation rule fires when a file exceeds the threshold
  • Anvil treats every string in the violation set as a warning

3. Test the Policy

Run the built-in policy test harness:

anvil policy test
Testing policies...
.anvil/policies/max_file_length.rego
PASS violation fires when file exceeds max_lines
PASS no violation when file is within limit
PASS respects config override

All policy tests passed.
Add your own test cases in .anvil/policies/max_file_length_test.rego

using standard OPA test conventions. :::

4. Run the Policy

anvil check --all
Checking architecture... done
Checking anti-patterns... done
Checking policies...
[POLICY] max_file_length
src/services/legacy-handler.ts exceeds 300 lines (487)

1 policy warning found.

5. Customise the Threshold

Override the default in anvil.config.json:

{
"gates": {
"policies": {
"enabled": true,
"config": {
"max_file_length": {
"max_lines": 500
}
}
}
}
}

You can also set per-directory thresholds using gate-config.json files placed alongside the code they govern.

Ideas for More Policies

PolicyWhat it enforces
Naming conventionsRequire files in src/services/ to end with .service.ts
Import depthFlag import chains deeper than N levels
Test ratioRequire at least one test file per source file
Export countWarn when a module exports more than a threshold

Each policy is a standalone .rego file. Drop it into .anvil/policies/ and Anvil picks it up on the next run.


Next: Architecture Boundaries