Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 10 additions & 2 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ ergo is a Rego library that turns policy evaluation into a structured report. Us
- `ergo.rego` is the whole library.
- `ergo_test.rego` holds its tests.
- `custom_op_test.rego` defines custom operators that only the tests use.
- `spec/` is the spec ergo implements: what each check means as named rules, the syntax, JSON Schemas for a policy and a report, and cases that pin the rules down. `spec/README.md` explains it.
- `spec_test.rego` runs every case in `spec/cases` against `ergo.rego`.
- `README.md` walks a new user through a first policy.
- `REFERENCE.md` describes every field, operator, cause and report entry.
- `CONTRIBUTING.md` tells people how to report bugs and send changes, and points them here for the rules.
Expand All @@ -24,8 +26,12 @@ opa fmt --list .
opa test . --ignore .github --timeout 120s
opa eval --strict-builtin-errors --ignore .github -d . --format raw 'count(data) > 0'
regal lint --disable-all --enable-category bugs --disable redundant-existence-check --ignore-files '.github/**' .
python3 spec/check_rules.py
python3 -m venv /tmp/ergo-venv && /tmp/ergo-venv/bin/pip install --quiet jsonschema==4.26.0 && /tmp/ergo-venv/bin/python .github/spec-schemas.py
```

Run them from the repo root. The last line puts `jsonschema` in a virtual environment outside the repo, because some Pythons, like Homebrew's, refuse `pip install` outside one.

`opa fmt --list .` should print nothing. If it prints file names, run `opa fmt -w .`.

The `opa eval` command runs every test again with `--strict-builtin-errors`, which turns a built-in given the wrong type into an error, and should print `true`. If it prints an error, check the value's type before the built-in on that line, so that ergo gives the same report with or without the flag.
Expand All @@ -50,6 +56,8 @@ docker run --rm -v "$PWD":/src:ro -w /src openpolicyagent/opa:1.19.0 test . --ig

CI also runs every test with OPA's JavaScript runtime, `@open-policy-agent/opa-wasm` (`.github/wasm-js.cjs`), because that runtime brings its own versions of some built-ins, like a `sprintf` that formats lists and objects differently, and lacks others. The script compiles each test as a Wasm entrypoint, fails if ergo uses a built-in the runtime doesn't have (apart from `time.parse_rfc3339_ns`, which it passes in, as `REFERENCE.md` tells Wasm users to), and then runs every test. It also fails if `ergo.report` or `ergo.violations` needs any built-in that OPA's Wasm build runs outside the module. OPA reads the arguments of those built-ins back as Rego, so a string holding a byte-order mark fails the whole evaluation. `time.parse_rfc3339_ns` is allowed because ergo only passes it strings that already match the RFC 3339 pattern. If you add a function for users to call, add it to the entrypoint the script writes, so the check covers it. `sprintf` is one of them, so build text with `concat` instead. `concat` takes only strings, so write anything else with `_text` first. Last, it builds one report on 100 deployments and fails if that uses more than 20 MB of Wasm memory. Wasm doesn't cache function calls and frees nothing until the report is done, so something worked out again for every row shows up there long before it slows down `opa eval`.

A `spec` job checks the spec. `python3 spec/check_rules.py` fails when a case cites a rule that doesn't exist, or when a rule has no case and isn't listed under "Rules without cases" in `spec/OPEN.md`. `.github/spec-schemas.py` builds the report for every case and fails when a report doesn't match `spec/report/schema.json`, or when ergo reads a policy as written correctly but it doesn't match `spec/policy/schema.json`.

CI also fails when a line of Rego isn't reached by any test. To list those lines yourself:

```sh
Expand Down Expand Up @@ -84,7 +92,7 @@ The report must stay byte-identical for the same policy and input, whatever orde

## Docs

When behaviour changes, update `REFERENCE.md` in the same change. When it affects the getting-started example, update `README.md` too.
When behaviour changes, update its rule in `spec/` and add or change cases for it, so `spec_test.rego` fails when one no longer matches. When a policy or a report changes shape, update `spec/policy/schema.json` or `spec/report/schema.json` too. Update `REFERENCE.md` in the same change. When it affects the getting-started example, update `README.md` too.

Every output shown in the docs must come from actually running it, not from memory.

Expand Down Expand Up @@ -119,7 +127,7 @@ The first line names the part of the repo that changed, then says what the chang

For example, `core: fail compare when either side is missing`.

One area per commit. A `core:` change that updates `REFERENCE.md` with it stays `core:`.
One area per commit. A `core:` change that updates `REFERENCE.md` or `spec/` with it stays `core:`.

When a `core:` change alters the report for an existing policy, say so in the body, on a line starting with `Changes the report:`.

Expand Down
Loading