mirror of
https://github.com/microsoft/regorus.git
synced 2026-08-05 02:16:11 +00:00
Adds the YAML test runner that exercises the companion test data PRs, plus several compiler fixes surfaced during testing: - Removed parameter register caching that produced wrong results inside short-circuiting allOf/anyOf blocks; added literal-index caching for parameter defaults to avoid repeated O(n) literal-table scans - Simplified cross-resource effect details to only emit roleDefinitionIds and type (deployment templates are not evaluated for compliance) - Replaced guid/uniqueString builtins with clear "unsupported" errors - Normalized datetime output to ISO 8601 with Z suffix - Added azure_policy parser MAX_COL constant (8192) for long template expressions, keeping the global DEFAULT_MAX_COL at 1024 - Added rvm to azure_policy feature dependencies since the compiler targets RVM bytecode Also restructures the example binary into examples/regorus/ with new azure-policy-eval and azure-policy-aliases subcommands, adds C# alias normalization tests, and documents Azure Policy support in the README. Signed-off-by: Anand Krishnamoorthi <anakrish@microsoft.com> Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
407 lines
18 KiB
Markdown
407 lines
18 KiB
Markdown
# Regorus
|
||
|
||
**Regorus** is
|
||
|
||
- *Rego*-*Rus(t)* - A fast, light-weight [Rego](https://www.openpolicyagent.org/docs/latest/policy-language/)
|
||
interpreter written in Rust.
|
||
- *Rigorous* - A rigorous enforcer of well-defined Rego semantics.
|
||
|
||
Regorus is also
|
||
- *cross-platform* - Written in platform-agnostic Rust.
|
||
- *no_std compatible* - Regorus can be used in `no_std` environments too. Most of the builtins are supported.
|
||
- *current* - We strive to keep Regorus up to date with latest OPA release. Regorus defaults to `v1` of the Rego language.
|
||
- *compliant* - Regorus is mostly compliant with the latest [OPA release v1.2.0](https://github.com/open-policy-agent/opa/releases/tag/v1.2.0). See [OPA Conformance](#opa-conformance) for details. Note that while we behaviorally produce the same results, we don't yet support all the builtins.
|
||
- *extensible* - Extend the Rego language by implementing custom stateful builtins in Rust.
|
||
See [add_extension](https://github.com/microsoft/regorus/blob/fc68bf9c8bea36427dae9401a7d1f6ada771f7ab/src/engine.rs#L352).
|
||
Support for extensibility using other languages coming soon.
|
||
- *polyglot* - In addition to Rust, Regorus can be used from *C*, *C++*, *C#*, *Golang*, *Java*, *Javascript*, *Python*, and *Ruby*.
|
||
This is made possible by the excellent FFI tools available in the Rust ecosystem. See [bindings](#bindings) for information on how to use Regorus from different languages.
|
||
|
||
To try out a *Javascript(WASM)* compiled version of Regorus from your browser, visit [Regorus Playground](https://anakrish.github.io/regorus-playground/).
|
||
|
||
|
||
|
||
Regorus is available as a library that can be easily integrated into your Rust projects.
|
||
Here is an example of evaluating a simple Rego policy:
|
||
|
||
```rust
|
||
fn main() -> anyhow::Result<()> {
|
||
// Create an engine for evaluating Rego policies.
|
||
let mut engine = regorus::Engine::new();
|
||
|
||
let policy = String::from(
|
||
r#"
|
||
package example
|
||
|
||
allow if {
|
||
## All actions are allowed for admins.
|
||
input.principal == "admin"
|
||
} else if {
|
||
## Check if action is allowed for given user.
|
||
input.action in data.allowed_actions[input.principal]
|
||
}
|
||
"#,
|
||
);
|
||
|
||
// Add policy to the engine.
|
||
engine.add_policy(String::from("policy.rego"), policy)?;
|
||
|
||
// Add data to engine.
|
||
engine.add_data(regorus::Value::from_json_str(
|
||
r#"{
|
||
"allowed_actions": {
|
||
"user1" : ["read", "write"],
|
||
"user2" : ["read"]
|
||
}}"#,
|
||
)?)?;
|
||
|
||
// Set input and evaluate whether user1 can write.
|
||
engine.set_input(regorus::Value::from_json_str(
|
||
r#"{
|
||
"principal": "user1",
|
||
"action": "write"
|
||
}"#,
|
||
)?);
|
||
|
||
let r = engine.eval_rule(String::from("data.example.allow"))?;
|
||
assert_eq!(r, regorus::Value::from(true));
|
||
|
||
// Set input and evaluate whether user2 can write.
|
||
engine.set_input(regorus::Value::from_json_str(
|
||
r#"{
|
||
"principal": "user2",
|
||
"action": "write"
|
||
}"#,
|
||
)?);
|
||
|
||
let r = engine.eval_rule(String::from("data.example.allow"))?;
|
||
assert_eq!(r, regorus::Value::Undefined);
|
||
|
||
Ok(())
|
||
}
|
||
```
|
||
|
||
Regorus is designed with [Confidential Computing](https://confidentialcomputing.io/about/) in mind. In Confidential Computing environments,
|
||
it is important to be able to control exactly what is being run. Regorus allows enabling and disabling various components using cargo
|
||
features. By default all features are enabled.
|
||
|
||
The default build of regorus example program is 6.3M:
|
||
```bash
|
||
$ cargo build -r --example regorus; strip target/release/examples/regorus; ls -lh target/release/examples/regorus
|
||
-rwxr-xr-x 1 anand staff 6.3M May 11 22:03 target/release/examples/regorus*
|
||
```
|
||
|
||
|
||
When all default features are disabled, the binary size drops down to 1.9M.
|
||
```bash
|
||
$ cargo build -r --example regorus --no-default-features; strip target/release/examples/regorus; ls -lh target/release/examples/regorus
|
||
-rwxr-xr-x 1 anand staff 1.9M May 11 22:04 target/release/examples/regorus*
|
||
```
|
||
|
||
Regorus passes the [OPA v1.2.0 test-suite](https://www.openpolicyagent.org/docs/latest/ir/#test-suite) barring a few
|
||
builtins. See [OPA Conformance](#opa-conformance) below.
|
||
|
||
## Bindings
|
||
|
||
Regorus can be used from a variety of languages:
|
||
|
||
- *C*: C binding is generated using [cbindgen](https://github.com/mozilla/cbindgen).
|
||
[corrosion-rs](https://github.com/corrosion-rs/corrosion) can be used to seamlessly use Regorous
|
||
in your CMake based projects. See [bindings/c](https://github.com/microsoft/regorus/tree/main/bindings/c).
|
||
- *C freestanding*: [bindings/c_no_std](https://github.com/microsoft/regorus/tree/main/bindings/c_no_std) shows how to use Regorus from C environments without a libc.
|
||
- *C++*: C++ binding is generated using [cbindgen](https://github.com/mozilla/cbindgen).
|
||
[corrosion-rs](https://github.com/corrosion-rs/corrosion) can be used to seamlessly use Regorous
|
||
in your CMake based projects. See [bindings/cpp](https://github.com/microsoft/regorus/tree/main/bindings/cpp).
|
||
- *C#*: C# binding is generated using [csbindgen](https://github.com/Cysharp/csbindgen). See [bindings/csharp](https://github.com/microsoft/regorus/tree/main/bindings/csharp) for an example of how to build and use Regorus in your C# projects.
|
||
- *Golang*: The C bindings are exposed to Golang via [CGo](https://pkg.go.dev/cmd/cgo). See [bindings/go](https://github.com/microsoft/regorus/tree/main/bindings/go) for an example of how to build and use Regorus in your Go projects.
|
||
- *Python*: Python bindings are generated using [pyo3](https://github.com/PyO3/pyo3). Wheels are created using [maturin](https://github.com/PyO3/maturin). See [bindings/python](https://github.com/microsoft/regorus/tree/main/bindings/python).
|
||
- *Java*: Java bindings are developed using [jni-rs](https://github.com/jni-rs/jni-rs).
|
||
See [bindings/java](https://github.com/microsoft/regorus/tree/main/bindings/java).
|
||
- *Javascript*: Regorus is compiled to WASM using [wasmpack](https://github.com/rustwasm/wasm-pack).
|
||
See [bindings/wasm](https://github.com/microsoft/regorus/tree/main/bindings/wasm) for an example of using Regorus from nodejs.
|
||
To try out a *Javascript(WASM)* compiled version of Regorus from your browser, visit [Regorus Playground](https://anakrish.github.io/regorus-playground/).
|
||
- *Ruby*: Ruby bindings are developed using [magnus](https://github.com/matsadler/magnus).
|
||
See [bindings/ruby](https://github.com/microsoft/regorus/tree/main/bindings/ruby).
|
||
|
||
To avoid operational overhead, we currently don't publish these bindings to various repositories.
|
||
It is straight-forward to build these bindings yourself.
|
||
|
||
|
||
## Getting Started
|
||
|
||
[examples/regorus](https://github.com/microsoft/regorus/blob/main/examples/regorus/main.rs) is an example program that
|
||
shows how to integrate Regorus into your project and evaluate Rego policies.
|
||
|
||
To build and install it, do
|
||
|
||
```bash
|
||
$ cargo install --example regorus --path .
|
||
```
|
||
|
||
Check that the regorus example program is working
|
||
|
||
```bash
|
||
$ regorus
|
||
Usage: regorus <COMMAND>
|
||
|
||
Commands:
|
||
ast Parse a Rego policy and dump AST
|
||
eval Evaluate a Rego Query
|
||
lex Tokenize a Rego policy
|
||
parse Parse a Rego policy
|
||
help Print this message or the help of the given subcommand(s)
|
||
|
||
Options:
|
||
-h, --help Print help
|
||
-V, --version Print version
|
||
```
|
||
|
||
|
||
First, let's evaluate a simple Rego expression `1*2+3`
|
||
|
||
```bash
|
||
$ regorus eval "1*2+3"
|
||
```
|
||
|
||
This produces the following output
|
||
|
||
```json
|
||
{
|
||
"result": [
|
||
{
|
||
"expressions": [
|
||
{
|
||
"value": 5,
|
||
"text": "1*2+3",
|
||
"location": {
|
||
"row": 1,
|
||
"col": 1
|
||
}
|
||
}
|
||
]
|
||
}
|
||
]
|
||
}
|
||
```
|
||
|
||
Next, evaluate a sample [policy](https://github.com/microsoft/regorus/blob/main/examples/server/allowed_server.rego) and [input](https://github.com/microsoft/regorus/blob/main/examples/server/input.json)
|
||
(borrowed from [Rego tutorial](https://www.openpolicyagent.org/docs/latest/#2-try-opa-eval)):
|
||
|
||
```bash
|
||
$ regorus eval -d examples/server/allowed_server.rego -i examples/server/input.json data.example
|
||
```
|
||
|
||
Finally, evaluate real-world [policies](tests/aci/) used in Azure Container Instances (ACI)
|
||
|
||
```bash
|
||
$ regorus eval -b tests/aci -d tests/aci/data.json -i tests/aci/input.json data.policy.mount_overlay=x
|
||
```
|
||
|
||
## Policy coverage
|
||
|
||
Regorus allows determining which lines of a policy have been executed using the `coverage` feature (enabled by default).
|
||
|
||
We can try it out using the `regorus` example program by passing in the `--coverage` flag.
|
||
|
||
```shell
|
||
$ regorus eval -d examples/server/allowed_server.rego -i examples/server/input.json data.example --coverage
|
||
```
|
||
|
||
It produces the following coverage report which shows that all lines are executed except the line that sets `allow` to true.
|
||
|
||

|
||
|
||
See [Engine::get_coverage_report](https://docs.rs/regorus/latest/regorus/struct.Engine.html#method.get_coverage_report) for details.
|
||
Policy coverage information is useful for debugging your policy as well as to write tests for your policy so that all
|
||
lines of the policy are exercised by the tests.
|
||
|
||
## ACI Policies
|
||
|
||
Regorus successfully passes the ACI policy test-suite. It is fast and can run each of the tests in a few milliseconds.
|
||
|
||
```bash
|
||
$ cargo test -r --test aci
|
||
Finished release [optimized + debuginfo] target(s) in 0.05s
|
||
Running tests/aci/main.rs (target/release/deps/aci-2cd8d21a893a2450)
|
||
aci/mount_device passed 3.863292ms
|
||
aci/mount_overlay passed 3.6905ms
|
||
aci/scratch_mount passed 3.643041ms
|
||
aci/create_container passed 5.046333ms
|
||
aci/shutdown_container passed 3.632ms
|
||
aci/scratch_unmount passed 3.631333ms
|
||
aci/unmount_overlay passed 3.609916ms
|
||
aci/unmount_device passed 3.626875ms
|
||
aci/load_fragment passed 4.045167ms
|
||
```
|
||
|
||
Run the ACI policies in the `tests/aci` directory, using data `tests/aci/data.json` and input `tests/aci/input.json`:
|
||
|
||
```bash
|
||
$ regorus eval -b tests/aci -d tests/aci/data.json -i tests/aci/input.json data.policy.mount_overlay=x
|
||
```
|
||
|
||
Verify that [OPA](https://github.com/open-policy-agent/opa/releases) produces the same output
|
||
|
||
```bash
|
||
$ diff <(regorus eval -b tests/aci -d tests/aci/data.json -i tests/aci/input.json data.framework.mount_overlay=x) \
|
||
<(opa eval -b tests/aci -d tests/aci/data.json -i tests/aci/input.json data.framework.mount_overlay=x)
|
||
```
|
||
|
||
|
||
## Azure Policy (Preview)
|
||
|
||
Regorus can evaluate [Azure Policy](https://learn.microsoft.com/en-us/azure/governance/policy/overview)
|
||
definitions natively. A dedicated compiler translates Azure Policy JSON
|
||
directly into RVM (Regorus Virtual Machine) bytecode — the same VM that
|
||
powers Rego evaluation — so you don't have to rewrite policies in Rego.
|
||
Enable it with the `azure_policy` cargo feature.
|
||
|
||
Most of the policy language is supported: conditions with `field`, `count`,
|
||
and `value`; logical connectives (`allOf`, `anyOf`, `not`); comparison
|
||
operators; template expressions like `parameters()`, `concat()`,
|
||
`dateTimeAdd()`, and `utcNow()`; and effects including Deny, Audit, Modify,
|
||
Append, AuditIfNotExists, and DeployIfNotExists. An alias registry handles
|
||
the translation from fully-qualified alias names to the flattened ARM resource
|
||
shape expected by the engine.
|
||
|
||
### Quick start
|
||
|
||
```bash
|
||
cargo install --example regorus --features azure_policy --path .
|
||
|
||
# Evaluate a policy against a non-compliant storage account (→ Deny)
|
||
regorus azure-policy-eval \
|
||
--policy-definition examples/regorus/azure_policy_data/require_https_storage.json \
|
||
--resource examples/regorus/azure_policy_data/non_compliant_storage.json \
|
||
--aliases tests/azure_policy/aliases/test_aliases.json
|
||
|
||
# Same policy against a compliant resource (→ undefined, no effect)
|
||
regorus azure-policy-eval \
|
||
--policy-definition examples/regorus/azure_policy_data/require_https_storage.json \
|
||
--resource examples/regorus/azure_policy_data/compliant_storage.json \
|
||
--aliases tests/azure_policy/aliases/test_aliases.json
|
||
|
||
# List aliases for a resource type
|
||
regorus azure-policy-aliases \
|
||
--aliases tests/azure_policy/aliases/test_aliases.json \
|
||
--resource-type Microsoft.Storage
|
||
```
|
||
|
||
The test suite covers conditions, effects, template functions, alias
|
||
resolution, and end-to-end scenarios across YAML-driven test files:
|
||
|
||
```bash
|
||
cargo test --features azure_policy -- azure_policy
|
||
```
|
||
|
||
## Performance
|
||
|
||
To check how fast Regorus runs on your system, first install a tool like [hyperfine](https://github.com/sharkdp/hyperfine).
|
||
|
||
```bash
|
||
$ cargo install hyperfine
|
||
```
|
||
|
||
Then benchmark evaluation of the ACI policies,
|
||
|
||
```bash
|
||
$ hyperfine "regorus eval -b tests/aci -d tests/aci/data.json -i tests/aci/input.json data.framework.mount_overlay=x"
|
||
Benchmark 1: regorus eval -b tests/aci -d tests/aci/data.json -i tests/aci/input.json data.framework.mount_overlay=x
|
||
Time (mean ± σ): 4.6 ms ± 0.2 ms [User: 4.1 ms, System: 0.4 ms]
|
||
Range (min … max): 4.4 ms … 6.0 ms 422 runs
|
||
```
|
||
|
||
Compare it with OPA
|
||
|
||
```bash
|
||
$ hyperfine "opa eval -b tests/aci -d tests/aci/data.json -i tests/aci/input.json data.framework.mount_overlay=x"
|
||
Benchmark 1: opa eval -b tests/aci -d tests/aci/data.json -i tests/aci/input.json data.framework.mount_overlay=x
|
||
Time (mean ± σ): 45.2 ms ± 0.6 ms [User: 68.8 ms, System: 5.1 ms]
|
||
Range (min … max): 43.8 ms … 46.7 ms 62 runs
|
||
|
||
```
|
||
|
||
## Contributor Workflow
|
||
|
||
Regorus uses a small companion CLI under the `xtask` package to keep CI and local development in sync.
|
||
The commands mirror our GitHub Actions jobs, making it easy to dry-run CI steps before sending a pull request.
|
||
|
||
- Run the full release pipeline with `cargo xtask ci-release` and the debug checks with `cargo xtask ci-debug`.
|
||
- Exercise language bindings through focused helpers such as `cargo xtask test-java --release --frozen` or `cargo xtask test-go`.
|
||
- Use `cargo xtask test-musl --release --frozen` for the cross-compilation matrix and `cargo xtask test-no-std` for embedded targets.
|
||
- Formatting (`cargo xtask fmt`) and linting (`cargo xtask clippy --sarif`) wrap the usual Cargo tooling while matching CI defaults.
|
||
|
||
The workflows in `.github/workflows` invoke the same commands, so keeping local runs green is usually enough to satisfy the checks enforced on `main`.
|
||
|
||
## OPA Conformance
|
||
|
||
Regorus has been verified to be compliant with [OPA v1.2.0](https://github.com/open-policy-agent/opa/releases/tag/v1.2.0)
|
||
using a [test driver](https://github.com/microsoft/regorus/blob/main/tests/opa.rs) that loads and runs the OPA testsuite using Regorus, and verifies that expected outputs are produced.
|
||
|
||
The test driver can be invoked by running:
|
||
|
||
```bash
|
||
$ cargo test -r --test opa --features opa-testutil,serde_json/arbitrary_precision
|
||
```
|
||
|
||
Currently, Regorus passes all the non-builtin specific tests.
|
||
See [passing tests suites](https://github.com/microsoft/regorus/blob/main/tests/opa.passing).
|
||
|
||
The following test suites don't pass fully due to missing builtins:
|
||
- `globsmatch`
|
||
- `graphql`
|
||
- `invalidkeyerror`
|
||
- `jsonpatch`
|
||
- `jwtbuiltins`
|
||
- `jwtdecodeverify`
|
||
- `jwtencodesign`
|
||
- `jwtencodesignheadererrors`
|
||
- `jwtencodesignpayloaderrors`
|
||
- `jwtencodesignraw`
|
||
- `jwtverifyhs256`
|
||
- `jwtverifyhs384`
|
||
- `jwtverifyhs512`
|
||
- `jwtverifyrsa`
|
||
- `netcidrcontainsmatches`
|
||
- `netcidrintersects`
|
||
- `netcidrmerge`
|
||
- `netcidroverlap`
|
||
- `netlookupipaddr`
|
||
- `providers-aws`
|
||
- `regometadatachain`
|
||
- `regometadatarule`
|
||
- `regoparsemodule`
|
||
- `rendertemplate`
|
||
|
||
They are captured in the following [github issues](https://github.com/microsoft/regorus/issues?q=is%3Aopen+is%3Aissue+label%3Alib).
|
||
|
||
Cryptographic builtins are not supported by design. Users that need cryptographic builtins are encouraged to use [extensions](https://docs.rs/regorus/latest/regorus/struct.Engine.html#method.add_extension).
|
||
|
||
### Grammar
|
||
|
||
The grammar used by Regorus to parse Rego policies is described in [grammar.md](https://github.com/microsoft/regorus/blob/main/docs/grammar.md)
|
||
in both [W3C EBNF](https://www.w3.org/Notation.html) and [RailRoad Diagram](https://en.wikipedia.org/wiki/Syntax_diagram) formats.
|
||
|
||
|
||
## Contributing
|
||
|
||
This project welcomes contributions and suggestions. Most contributions require you to agree to a
|
||
Contributor License Agreement (CLA) declaring that you have the right to, and actually do, grant us
|
||
the rights to use your contribution. For details, visit <https://cla.opensource.microsoft.com>.
|
||
|
||
When you submit a pull request, a CLA bot will automatically determine whether you need to provide
|
||
a CLA and decorate the PR appropriately (e.g., status check, comment). Simply follow the instructions
|
||
provided by the bot. You will only need to do this once across all repos using our CLA.
|
||
|
||
This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/).
|
||
For more information see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or
|
||
contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional questions or comments.
|
||
|
||
## Trademarks
|
||
|
||
This project may contain trademarks or logos for projects, products, or services. Authorized use of Microsoft
|
||
trademarks or logos is subject to and must follow
|
||
[Microsoft's Trademark & Brand Guidelines](https://www.microsoft.com/en-us/legal/intellectualproperty/trademarks/usage/general).
|
||
Use of Microsoft trademarks or logos in modified versions of this project must not cause confusion or imply Microsoft sponsorship.
|
||
Any use of third-party trademarks or logos are subject to those third-party's policies.
|