Experimental. The ergo command runs the Rust engine of Ergo. It reads a policy, an input and params from files and prints the report or the violations as JSON. It gives the same report as ergo.rego, apart from engine, which says which one made it. What a policy can say, and what a report holds, is the same for both engines, so it is in the README and the reference.
This page follows the latest release of the CLI.
Install the ergo CLI from crates.io. You need Rust, which rustup installs:
cargo install --locked ergo-policy-cliOr download it, without Rust, for Linux (x86_64) or macOS (arm64) from the latest release of the CLI, unpack it and put ergo on your PATH:
curl -L https://github.com/kosli-dev/ergo/releases/download/rust-v0.4.0/ergo-0.4.0-macos-arm64.tar.gz | tar xz
./ergo --versionOn Linux, the file is ergo-0.4.0-linux-x86_64.tar.gz.
To build it from this repo with Docker instead, see engines/rust/README.md.
Write the policy of the README in policy.yaml, and its input in deployments.json. ergo reads the policy, the input and the params from files, each one .json, .yaml or .yml. Ask for the report, or only for what went wrong:
ergo report --policy policy.yaml --input deployments.json
ergo violations --policy policy.yaml --input deployments.jsonThe report is the one the README shows, apart from engine, which says {"name": "ergo-rust", "version": "0.4.0"}. The violations are the same too.
--params <file> gives the policy its params. The file holds the params themselves, like limit: 9, without a params: key around them, and without --params they are {}. The output has sorted keys and two-space indents, like opa eval --format=pretty, and --compact prints one line. ergo --version prints the version.
Without --fail, the command exits 0 whenever it printed the output, even when compliant is false. With --fail it still prints all of it, then exits with a code that says how the policy did, so a CI job can stop on it:
| Code | When |
|---|---|
| 0 | The output was printed, and the policy is met or --fail isn't given. |
| 1 | With --fail: a check failed. Input Ergo can't read, like a missing field, counts as a failed check. |
| 2 | The command line is wrong, a file can't be read or parsed, or the output couldn't be written, so it may be cut short. |
| 3 | With --fail: the policy is written wrong, so a $well_formed row failed, or it has no requirements, so no check ran. This wins over 1. |
When the command line or a file is wrong, the command says why on one line of stderr.
YAML is read the way OPA 1.21 and later read it. OPA 1.20 reads some of it differently, yes, no, on and off as booleans for one, so with OPA 1.20 ergo.rego can give another report on the same YAML file. Only true and false are booleans, so yes, no, on and off are strings: with approved: yes, approved is true fails, so write approved: true. 010 is 8, 0x10 is 16, dates stay strings, and a date tagged !!timestamp is written out in full, like 2001-12-14T00:00:00Z. << merges, and a key written in the mapping wins over a merged one, wherever the << is. A tag YAML doesn't define, like !custom 5, keeps the text, "5", and a bare ! reads a plain value as if it had no tag, so ! 5 is 5. Only the first document counts, but the others must still be valid YAML. ergo also refuses most files OPA refuses, like one with a control character, a directive other than %YAML 1.1 and %TAG, a tag that doesn't fit its value like !!int 1.5 or !!bool yes, the same alias twice as a key of one mapping, more than 10,000 levels of nesting, or too many aliases.
These differences are known:
ergokeeps a number as it was written, and OPA turns it into a 64-bit float, so1.10stays1.10where OPA reads 1.1. Outside the range of a float this changes more than the digits: OPA reads1e400as the string"1e400"and1e-400as 0, andergoreads both as the numbers written. So withsize: 1e400,size is at least 5passes inergoand fails inergo.rego, and withsize: 1e-400,size is more than 0does the same.ergoreads some malformed files that OPA refuses, so a check can pass on a fileergo.regonever reads. These are a line that starts with a tab, or a blank line holding one, a tab after the dash of a list item, like-<tab>a, whichergoreads as["a"], a file of only..., an escape YAML 1.1 doesn't have like\/, a plain key over two lines or longer than 1,024 characters inside{}, like{aandb: 1}on two lines, whichergoreads as{"a b": 1}(written as akey: valueline, both refuse it),{aand: 1}on separate lines,&x:written without a space, an anchor name with a character other than a letter, a digit,-and_, like&a.b,&a/b,&éor an emoji, in any document, and a byte order mark at the start of a line after..., likea: 1,...and<BOM>b: 2, whichergoreads as{"a": 1}. That last one includes a byte order mark before---,%YAML 1.2,%TAGor%FOO, soergodoesn't check the directive after it.ergorefuses some files OPA reads. These are a tab after a colon, UTF-16, a byte order mark inside a value or right after---at the start of a later document, flow collections nested more than 255 levels, in the first document or a later one, a quoted value whose next line starts with a tab,*a: vwith no space before the colon,%YAML 1.1#cwith no space before the comment, and a directive inside a document with no...before it, likea: 1,%YAML 1.1,---andb: 2on four lines, which OPA reads as{"a": 1}. The same goes for%TAGthere, and for a list as the first document.ergoreads LS and PS (U+2028 and U+2029) as ordinary characters, and OPA reads them as line breaks. Soa: 1<LS>b: 2is{"a": 1, "b": 2}in OPA and refused byergo,a: x<LS>yis refused by OPA and read byergoas text that holds the LS, and in quoted text OPA drops the spaces around one, so"x <LS> y"is"x<LS>y"in OPA and keeps the spaces inergo.- The U+FFFD characters for bad UTF-8 in a
!!binarydiffer.
Run cargo install --locked ergo-policy-cli again, or download the newest release of the CLI. engines/rust/CHANGELOG.md says what each release changed, and which spec version it follows.