Compare commits

...

52 Commits

Author SHA1 Message Date
Anthony Martin
0c789ba125 Add C# test examples 2025-04-16 18:28:25 +00:00
dependabot[bot]
667cb0d90f build(deps): bump clap from 4.5.35 to 4.5.36 (#395)
Bumps [clap](https://github.com/clap-rs/clap) from 4.5.35 to 4.5.36.
- [Release notes](https://github.com/clap-rs/clap/releases)
- [Changelog](https://github.com/clap-rs/clap/blob/master/CHANGELOG.md)
- [Commits](https://github.com/clap-rs/clap/compare/clap_complete-v4.5.35...clap_complete-v4.5.36)

---
updated-dependencies:
- dependency-name: clap
  dependency-version: 4.5.36
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-04-15 08:33:41 -07:00
Anand Krishnamoorthi
f46ab5b697 fix!: Fix glob.match behavior in presence of : (#390)
glob.match("api://*/appId", null, "api://foo.com/appId") wasn't
being handled correctly. Switch to globset crate.

Signed-off-by: Anand Krishnamoorthi <anakrish@microsoft.com>
2025-04-09 11:11:57 -07:00
Anand Krishnamoorthi
757edcc8fb build: Python binding portability (#388)
- Specify compatibility = linux in pyproject.toml to ensure
  manylinux compatibility.
- Use abi-py310 pyo3 feature to ensure compatibility with python
  3.10 and later.

Signed-off-by: Anand Krishnamoorthi <anakrish@microsoft.com>
2025-04-07 13:18:01 -07:00
dependabot[bot]
77cdac0fef build(deps): bump clap from 4.5.34 to 4.5.35 (#389)
Bumps [clap](https://github.com/clap-rs/clap) from 4.5.34 to 4.5.35.
- [Release notes](https://github.com/clap-rs/clap/releases)
- [Changelog](https://github.com/clap-rs/clap/blob/master/CHANGELOG.md)
- [Commits](https://github.com/clap-rs/clap/compare/clap_complete-v4.5.34...clap_complete-v4.5.35)

---
updated-dependencies:
- dependency-name: clap
  dependency-version: 4.5.35
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-04-06 21:14:33 -07:00
Anand Krishnamoorthi
ab93c07773 fix: C# EvalRule (#387)
- Fix EvalRule to call EvalRule instead of EvalQuery
- Also fix clippy errors

Signed-off-by: Anand Krishnamoorthi <anakrish@microsoft.com>
2025-04-04 15:44:16 -07:00
dependabot[bot]
2749e820c4 build(deps): bump pyo3 (#386)
Bumps the cargo group with 1 update in the /bindings/python directory: [pyo3](https://github.com/pyo3/pyo3).


Updates `pyo3` from 0.24.0 to 0.24.1
- [Release notes](https://github.com/pyo3/pyo3/releases)
- [Changelog](https://github.com/PyO3/pyo3/blob/v0.24.1/CHANGELOG.md)
- [Commits](https://github.com/pyo3/pyo3/compare/v0.24.0...v0.24.1)

---
updated-dependencies:
- dependency-name: pyo3
  dependency-type: direct:production
  dependency-group: cargo
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-04-02 07:13:48 -07:00
Anand Krishnamoorthi
a164f342bf build: Use VersionPrefix and VersionSuffix (#385)
The suffix can be customised during dotnet pack.

Signed-off-by: Anand Krishnamoorthi <anakrish@microsoft.com>
2025-03-31 18:24:59 -07:00
Anand Krishnamoorthi
c28bde3f56 build: Check-in Cargo.lock files and lockdown .net (#384)
Use frozen and locked builds

Signed-off-by: Anand Krishnamoorthi <anakrish@microsoft.com>
2025-03-31 07:55:47 -07:00
Anand Krishnamoorthi
2858b63cd4 feat: Regorus nuget package (#383)
Organize C# binding example into separate Regorus nuget package and
a test app.

The nuget package targets netstandard 2.0 and 2.1.
The test app is tested for netframework 8.0.

Implement IDisposable for Engine cleanup.

Also remove net40 example. Can be added back later if needed.

Signed-off-by: Anand Krishnamoorthi <anakrish@microsoft.com>
2025-03-25 11:31:13 -07:00
Anand Krishnamoorthi
c7bf460bc1 chore: release (#382)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2025-03-14 14:56:25 -07:00
Anand Krishnamoorthi
4d2b205ef4 fix!: Update ruby json dependency (#381)
Previous version has Out-of-bounds Read in Ruby JSON Parser

Signed-off-by: Anand Krishnamoorthi <anakrish@microsoft.com>
2025-03-14 13:31:12 -07:00
Anand Krishnamoorthi
4f7b9a4292 fix!: Remove ring dependency (#380)
Remove dependency on jsonwebtoken which brings in the ring crate.
Ring crate triggers governance violations.

Support for JWT will be implemented in future using a more governance
compliant crate.

BREAKING CHANGE

Prior to this PR, support for jwt builtins was minimially implemented.
Only io.jwt.decode and io.jwt.decode_verify was implemented.
With this PR, those builtins will no longer be available. They are
planned to be implemented in the future. In the meantime, they can be
brought back in via Engine::add_extension.

Signed-off-by: Anand Krishnamoorthi <anakrish@microsoft.com>
2025-03-14 10:49:57 -07:00
Anand Krishnamoorthi
4a2df93ae2 fix!: Remove sha1 dependency (#379)
Removed cryptographically insecure sha1. This existed only for OPA
compatibility.

Also exclude bindings from main workspace

Signed-off-by: Anand Krishnamoorthi <anakrish@microsoft.com>
2025-03-13 12:34:11 -07:00
Anand Krishnamoorthi
c6a5f1d852 build: Specify optimization flags (#378)
In release profile, enable lto and codgen-units = 1 to enable more
optimizations.

Signed-off-by: Anand Krishnamoorthi <anakrish@microsoft.com>
2025-03-10 17:50:31 -07:00
Anand Krishnamoorthi
2901481c51 chore: release (#376)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2025-03-10 12:33:59 -07:00
Anand Krishnamoorthi
c963e477a3 feat: Update to OPA v1.2.0 (#373)
Regorus now defaults to rego v1. `import rego.v1` is no longer needed.
Additionally, `future` keywords are automatically imported.

See
https://www.openpolicyagent.org/docs/latest/v0-upgrade/#changes-to-rego-in-opa-v10
to understand the differences between rego v1 and v0.

BREAKING CHANGE:

v0 style policies will error out by default. To enable v0 behavior, call engine.set_rego_v0(true) before
loading policies.

Signed-off-by: Anand Krishnamoorthi <anakrish@microsoft.com>
2025-03-10 11:56:01 -07:00
dependabot[bot]
cbd772623a build(deps): update pyo3 requirement from 0.23.5 to 0.24.0 (#375)
Updates the requirements on [pyo3](https://github.com/pyo3/pyo3) to permit the latest version.
- [Release notes](https://github.com/pyo3/pyo3/releases)
- [Changelog](https://github.com/PyO3/pyo3/blob/main/CHANGELOG.md)
- [Commits](https://github.com/pyo3/pyo3/compare/v0.23.5...v0.24.0)

---
updated-dependencies:
- dependency-name: pyo3
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-03-09 20:25:44 -07:00
thedavemarshall
a07beca983 Update ruby binding deps, ruby gem version 0.2.3 (#374)
* Update ruby binding deps, ruby gem version 0.2.3

* and gem version to 0.2.3

* specify bunlder and rubygems version for CI
2025-03-07 16:24:29 -08:00
Anand Krishnamoorthi
a3edb6c88c build(deps): update pyo3 requirement from 0.22.0 to 0.23.5 (#372)
Signed-off-by: Anand Krishnamoorthi <anakrish@microsoft.com>
2025-03-04 15:44:24 -08:00
Anand Krishnamoorthi
a1777fb7d3 build(deps): update rand requirement from 0.8.5 to 0.9.0 (#370)
Signed-off-by: Anand Krishnamoorthi <anakrish@microsoft.com>
2025-03-04 07:06:43 -08:00
dependabot[bot]
11aaa555aa build(deps): update cbindgen requirement from 0.27.0 to 0.28.0 (#361)
Updates the requirements on [cbindgen](https://github.com/mozilla/cbindgen) to permit the latest version.
- [Release notes](https://github.com/mozilla/cbindgen/releases)
- [Changelog](https://github.com/mozilla/cbindgen/blob/master/CHANGES)
- [Commits](https://github.com/mozilla/cbindgen/compare/v0.27.0...0.28.0)

---
updated-dependencies:
- dependency-name: cbindgen
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-03-03 16:23:44 -08:00
Amaury Chamayou
f1580a55a3 Fix typo in README.md (#366)
Force merging since it is only a typo fix.

Signed-off-by: Amaury Chamayou <amaury@xargs.fr>
2025-03-03 15:58:31 -08:00
Anand Krishnamoorthi
6174af1781 Update dependencies (#369)
Specify `js` feature for `uuid` when building wasm by
specifying it as a non-optional dependency in wasm binding's Cargo.toml.

Signed-off-by: Anand Krishnamoorthi <anakrish@microsoft.com>
2025-03-03 15:53:47 -08:00
thedavemarshall
5fa55d7274 Fix clippy warning for result? (#362) 2025-01-21 08:37:54 -08:00
dependabot[bot]
748c11cfa1 build(deps): update itertools requirement from 0.13.0 to 0.14.0 (#357)
Updates the requirements on [itertools](https://github.com/rust-itertools/itertools) to permit the latest version.
- [Changelog](https://github.com/rust-itertools/itertools/blob/master/CHANGELOG.md)
- [Commits](https://github.com/rust-itertools/itertools/compare/v0.13.0...v0.14.0)

---
updated-dependencies:
- dependency-name: itertools
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-01-06 10:35:00 -08:00
dependabot[bot]
fb035d3d93 build(deps): update jsonschema requirement from 0.26.1 to 0.28.1 (#356)
Updates the requirements on [jsonschema](https://github.com/Stranger6667/jsonschema) to permit the latest version.
- [Release notes](https://github.com/Stranger6667/jsonschema/releases)
- [Changelog](https://github.com/Stranger6667/jsonschema/blob/master/CHANGELOG.md)
- [Commits](https://github.com/Stranger6667/jsonschema/compare/rust-v0.26.1...rust-v0.28.1)

---
updated-dependencies:
- dependency-name: jsonschema
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-01-06 10:01:06 -08:00
thedavemarshall
ba3a128e84 resolve anyhow compile errors (#355) 2025-01-06 09:13:01 -08:00
dependabot[bot]
d955ae10a5 build(deps): update prettydiff requirement from 0.7.0 to 0.8.0 (#348)
---
updated-dependencies:
- dependency-name: prettydiff
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-11-25 09:39:27 -08:00
Anand Krishnamoorthi
cabd086619 chore: release (#344)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2024-11-06 13:28:25 -08:00
Anand Krishnamoorthi
4ec25f37a1 build(deps): update jsonschema requirement from 0.24.0 to 0.26.1 (#343)
Signed-off-by: Anand Krishnamoorthi <anakrish@microsoft.com>
2024-11-06 13:05:48 -08:00
Anand Krishnamoorthi
c281d28474 chore: Update to OPA v0.70.0 (#341)
Signed-off-by: Anand Krishnamoorthi <anakrish@microsoft.com>
2024-11-06 12:20:11 -08:00
Anand Krishnamoorthi
1bfe38f9af fix: Lock wasm-bindgen version to 0.2.94 (#342)
v0.2.95 causes a crash with wasm tests in CI

Signed-off-by: Anand Krishnamoorthi <anakrish@microsoft.com>
2024-11-06 12:04:59 -08:00
dependabot[bot]
5bf7cd7cc8 build(deps): bump rexml (#337)
Bumps the bundler group with 1 update in the /bindings/ruby directory: [rexml](https://github.com/ruby/rexml).


Updates `rexml` from 3.3.6 to 3.3.9
- [Release notes](https://github.com/ruby/rexml/releases)
- [Changelog](https://github.com/ruby/rexml/blob/master/NEWS.md)
- [Commits](https://github.com/ruby/rexml/compare/v3.3.6...v3.3.9)

---
updated-dependencies:
- dependency-name: rexml
  dependency-type: indirect
  dependency-group: bundler
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-11-04 08:53:08 -08:00
Anand Krishnamoorthi
c56da34843 chore: release (#335)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2024-10-22 14:05:26 -07:00
Anand Krishnamoorthi
61f82d1b34 fix: docs failing to build (#334)
Added #![cfg_attr(docsrs, feature(doc_cfg))]

fixes #333
Signed-off-by: Anand Krishnamoorthi <anakrish@microsoft.com>
2024-10-22 13:37:31 -07:00
dependabot[bot]
00f45c70fe build(deps): update jsonschema requirement from 0.23.0 to 0.24.0 (#332)
Updates the requirements on [jsonschema](https://github.com/Stranger6667/jsonschema-rs) to permit the latest version.
- [Release notes](https://github.com/Stranger6667/jsonschema-rs/releases)
- [Changelog](https://github.com/Stranger6667/jsonschema-rs/blob/master/CHANGELOG.md)
- [Commits](https://github.com/Stranger6667/jsonschema-rs/compare/rust-v0.23.0...rust-v0.24.0)

---
updated-dependencies:
- dependency-name: jsonschema
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-10-21 07:30:12 -07:00
Anand Krishnamoorthi
df73b20192 build(deps): update jsonschema requirement from 0.22.3 to 0.23.0 (#331) 2024-10-15 10:29:41 -07:00
Anand Krishnamoorthi
992b202f60 chore: release (#329)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2024-10-09 12:52:25 -07:00
Anand Krishnamoorthi
ce6ecd6fd6 feat: integer conversion functions for Value (#328)
closes #324

Signed-off-by: Anand Krishnamoorthi <anakrish@microsoft.com>
2024-10-09 12:19:54 -07:00
Anand Krishnamoorthi
37262ccf8f chore: update to OPA v0.69.0 (#327)
Also fix CRLF vs LF related test failures in two doc tests on Windows

Signed-off-by: Anand Krishnamoorthi <anakrish@microsoft.com>
2024-10-09 10:57:09 -07:00
dependabot[bot]
dcd040cf40 build(deps): update jsonschema requirement from 0.21.0 to 0.22.3 (#326)
Updates the requirements on [jsonschema](https://github.com/Stranger6667/jsonschema-rs) to permit the latest version.
- [Release notes](https://github.com/Stranger6667/jsonschema-rs/releases)
- [Changelog](https://github.com/Stranger6667/jsonschema-rs/blob/master/CHANGELOG.md)
- [Commits](https://github.com/Stranger6667/jsonschema-rs/compare/rust-v0.21.0...rust-v0.22.3)

---
updated-dependencies:
- dependency-name: jsonschema
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-10-07 13:30:05 -07:00
dependabot[bot]
f0a3cf26a0 build(deps): update jsonschema requirement from 0.20.0 to 0.21.0 (#325)
Updates the requirements on [jsonschema](https://github.com/Stranger6667/jsonschema-rs) to permit the latest version.
- [Release notes](https://github.com/Stranger6667/jsonschema-rs/releases)
- [Changelog](https://github.com/Stranger6667/jsonschema-rs/blob/master/CHANGELOG.md)
- [Commits](https://github.com/Stranger6667/jsonschema-rs/compare/rust-v0.20.0...rust-v0.21.0)

---
updated-dependencies:
- dependency-name: jsonschema
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-09-30 08:34:48 -07:00
Anand Krishnamoorthi
13d8289a58 chore: update to jsonschema 0.20.0 (#323) 2024-09-23 13:01:24 -07:00
Anand Krishnamoorthi
d2b27ee512 chore: release (#320)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2024-09-18 14:17:17 -07:00
Anand Krishnamoorthi
adb9da0c0c fix: Null terminate C# strings in Rust boundary (#318)
Signed-off-by: Anand Krishnamoorthi <anakrish@microsoft.com>
2024-09-18 13:58:51 -07:00
dependabot[bot]
dc0f48f6bc Update jsonschema requirement from 0.18.0 to 0.19.1 (#317)
Updates the requirements on [jsonschema](https://github.com/Stranger6667/jsonschema-rs) to permit the latest version.
- [Release notes](https://github.com/Stranger6667/jsonschema-rs/releases)
- [Changelog](https://github.com/Stranger6667/jsonschema-rs/blob/master/CHANGELOG.md)
- [Commits](https://github.com/Stranger6667/jsonschema-rs/compare/rust-v0.18.0...rust-v0.19.1)

---
updated-dependencies:
- dependency-name: jsonschema
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-09-16 09:12:00 -07:00
dependabot[bot]
334db3d6ce Update chrono-tz requirement from 0.8.5 to 0.10.0 (#316)
Updates the requirements on [chrono-tz](https://github.com/chronotope/chrono-tz) to permit the latest version.
- [Release notes](https://github.com/chronotope/chrono-tz/releases)
- [Commits](https://github.com/chronotope/chrono-tz/compare/v0.8.5...v0.10.0)

---
updated-dependencies:
- dependency-name: chrono-tz
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-09-16 08:42:19 -07:00
Anand Krishnamoorthi
7565ec3ecf feat: or keyword (#315)
Add `or` operator to Rego languages. Available via `rego-extensions`
Cargo feature.

If the evaluated lhs value is not false, null or undefined it is returned.
Otherwise rhs is evaluated and returned.

or operator has least precedence, and is left-associative.

closes #314
2024-09-13 16:39:19 -07:00
Sumedh Alok Sharma
8498274356 Add tests for builtin strings::lower method (#313)
Signed-off-by: Sumedh Alok Sharma <sumsharma@microsoft.com>
2024-09-11 09:15:28 -07:00
Sumedh Alok Sharma
ecd341bbcc Add tests for builtin strings::indexof method (#311)
Signed-off-by: Sumedh Alok Sharma <sumsharma@microsoft.com>
2024-09-11 09:14:21 -07:00
Anand Krishnamoorthi
b6935d1add fix: Update readme with correct path to example policy (#312)
Also add test to lock down example policy path.
Also Fix clippy warning by using unwrap_or_default

Signed-off-by: Anand Krishnamoorthi <anakrish@microsoft.com>
2024-09-10 11:47:46 -07:00
115 changed files with 12523 additions and 1162 deletions

View File

@@ -4,11 +4,20 @@
"name": "Rust",
// Or use a Dockerfile or Docker Compose file. More info: https://containers.dev/guide/dockerfile
"image": "mcr.microsoft.com/devcontainers/rust:1-1-bullseye",
"customizations": {
"vscode": {
"extensions": [
"ms-dotnettools.csharp",
"ms-dotnettools.csdevkit"
]
}
},
"features": {
"ghcr.io/devcontainers/features/dotnet:2": {},
"ghcr.io/devcontainers/features/dotnet:2": {
"version": "8.0"
},
"ghcr.io/devcontainers/features/python:1": {}
}
// Use 'mounts' to make the cargo cache persistent in a Docker Volume.
// "mounts": [
// {

33
.github/workflows/pr-extensions.yml vendored Normal file
View File

@@ -0,0 +1,33 @@
name: tests/release-extensions
on:
push:
branches: [ "main" ]
pull_request:
branches: [ "main" ]
env:
CARGO_TERM_COLOR: always
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Build only std
run: cargo build -r --example regorus --no-default-features --features "std,rego-extensions"
- name: Doc Tests
run: cargo test -r --doc --features rego-extensions
- name: Run tests
run: cargo test -r --features rego-extensions
- name: Run example
run: cargo run --example regorus --features rego-extensions -- eval -d examples/server/allowed_server.rego -i examples/server/input.json data.example
- name: Run tests (ACI)
run: cargo test -r --test aci --features rego-extensions
- name: Run tests (KATA)
run: cargo test -r --test kata --features rego-extensions
- name: Run tests (OPA Conformance)
run: >-
cargo test -r --test opa --features opa-testutil,serde_json/arbitrary_precision,rego-extensions -- $(tr '\n' ' ' < tests/opa.passing)

View File

@@ -18,22 +18,26 @@ jobs:
- uses: actions/checkout@v4
- name: Format Check
run: cargo fmt --check
- name: Fetch
run: cargo fetch
- name: Build (all features)
run: cargo build -r --all-features
run: cargo build -r --all-features --frozen
- name: Build
run: cargo build -r
run: cargo build -r --frozen
- name: Test no_std
run: cargo test -r --no-default-features
run: cargo test -r --no-default-features --frozen
- name: Build only std
run: cargo build -r --example regorus --no-default-features --features "std"
run: cargo build -r --example regorus --no-default-features --features "std" --frozen
- name: Doc Tests
run: cargo test -r --doc
run: cargo test -r --doc --frozen
- name: Run tests
run: cargo test -r
run: cargo test -r --frozen
- name: Run example
run: cargo run --example regorus --frozen -- eval -d examples/server/allowed_server.rego -i examples/server/input.json data.example
- name: Run tests (ACI)
run: cargo test -r --test aci
run: cargo test -r --test aci --frozen
- name: Run tests (KATA)
run: cargo test -r --test kata
run: cargo test -r --test kata --frozen
- name: Run tests (OPA Conformance)
run: >-
cargo test -r --test opa --features opa-testutil,serde_json/arbitrary_precision -- $(tr '\n' ' ' < tests/opa.passing)
cargo test -r --test opa --frozen --features opa-testutil,serde_json/arbitrary_precision -- $(tr '\n' ' ' < tests/opa.passing)

View File

@@ -48,7 +48,8 @@ jobs:
python-version: "3.11"
- if: ${{ matrix.build_cmd == 'zigbuild' }}
run: pip install cargo-zigbuild
- run: cargo ${{ matrix.build_cmd || 'build' }} --release --target ${{ matrix.target }}${{ matrix.glibc && format('.{0}', matrix.glibc) || '' }} --manifest-path ./bindings/java/Cargo.toml
- run: cargo fetch
- run: cargo ${{ matrix.build_cmd || 'build' }} --release --frozen --target ${{ matrix.target }}${{ matrix.glibc && format('.{0}', matrix.glibc) || '' }} --manifest-path ./bindings/java/Cargo.toml
- run: mkdir -p native/${{ matrix.target }}
- run: mv target/${{ matrix.target }}/release/*.${{ matrix.extension }} ./native/${{ matrix.target }}/
- uses: actions/upload-artifact@v4

View File

@@ -22,11 +22,19 @@ jobs:
- uses: actions/setup-python@v4
with:
python-version: '3.10'
- name: Build Python extension
run: |
cargo fetch
cargo clippy --all-targets --no-deps -- -Dwarnings
cargo build --release --target ${{ matrix.target }} --frozen
working-directory: bindings/python
- name: Build wheels
uses: PyO3/maturin-action@63b75c597b83e247fbf4fb7719801cc4220ae9f3 # v1.43.0
with:
target: ${{ matrix.target }}
args: --release --out dist --find-interpreter --manifest-path bindings/python/Cargo.toml
args: --release --out dist --manifest-path bindings/python/Cargo.toml --offline --strip
sccache: 'true'
manylinux: auto
- name: Upload wheels
@@ -46,11 +54,19 @@ jobs:
with:
python-version: '3.10'
architecture: ${{ matrix.target }}
- name: Build Python extension
run: |
cargo fetch
cargo clippy --all-targets --no-deps -- -Dwarnings
cargo build --release --target ${{ matrix.host.target }} --frozen
working-directory: bindings/python
- name: Build wheels
uses: PyO3/maturin-action@63b75c597b83e247fbf4fb7719801cc4220ae9f3 # v1.43.0
with:
target: ${{ matrix.target }}
args: --release --out dist --find-interpreter --manifest-path bindings/python/Cargo.toml
args: --release --out dist --manifest-path bindings/python/Cargo.toml --frozen --strip
sccache: 'true'
- name: Upload wheels
uses: actions/upload-artifact@v3
@@ -68,11 +84,19 @@ jobs:
- uses: actions/setup-python@v4
with:
python-version: '3.10'
- name: Build Python extension
run: |
cargo fetch
cargo clippy --all-targets --no-deps -- -Dwarnings
cargo build --release --target ${{ matrix.host.target }} --frozen
working-directory: bindings/python
- name: Build wheels
uses: PyO3/maturin-action@63b75c597b83e247fbf4fb7719801cc4220ae9f3 # v1.43.0
with:
target: ${{ matrix.target }}
args: --release --out dist --find-interpreter --manifest-path bindings/python/Cargo.toml
args: --release --out dist --manifest-path bindings/python/Cargo.toml --offline --strip
sccache: 'true'
- name: Upload wheels
uses: actions/upload-artifact@v3
@@ -80,21 +104,6 @@ jobs:
name: wheels
path: dist
sdist:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Build sdist
uses: PyO3/maturin-action@63b75c597b83e247fbf4fb7719801cc4220ae9f3 # v1.43.0
with:
command: sdist
args: --out dist --manifest-path bindings/python/Cargo.toml
- name: Upload sdist
uses: actions/upload-artifact@v3
with:
name: wheels
path: dist
release:
name: Release
runs-on: ubuntu-latest

View File

@@ -40,11 +40,15 @@ jobs:
- name: Install required cargo
run: cargo install clippy-sarif sarif-fmt
- name: Fetch
run: cargo fetch
- name: Run rust-clippy
run:
cargo clippy
--all-features
--message-format=json | clippy-sarif | tee rust-clippy-results.sarif | sarif-fmt
--frozen
continue-on-error: true
- name: Upload analysis results to GitHub

View File

@@ -20,7 +20,8 @@ jobs:
- name: Workaround to ensure that regorus.h is generated
run: |
cargo build -r
cargo fetch
cargo build -r --frozen
working-directory: ./bindings/ffi
- name: Test c binding

View File

@@ -6,9 +6,105 @@ on:
pull_request:
branches: [ "main" ]
jobs:
test:
jobs:
build-ffi:
name: 'Build Regorus FFI: (${{ matrix.runtime.target }})'
runs-on: ${{ matrix.runtime.os }}
strategy:
# let us get failures from other jobs even if one fails
fail-fast: false
matrix:
runtime:
- os: windows-latest
target: x86_64-pc-windows-msvc
libpath: |
**/release/regorus_ffi.dll
**/release/regorus_ffi.pdb
- os: ubuntu-latest
target: x86_64-unknown-linux-gnu
libpath: |
**/release/libregorus_ffi.so
# Disabled for now
#- os: macos-latest
# target: aarch64-apple-darwin
# libpath: |
# **/release/libregorus_ffi.dylib
steps:
- name: Checkout repository
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Build Regorus binding
run: cargo build -r --target ${{ matrix.runtime.target }} --locked
working-directory: ./bindings/ffi
- name: Upload regorus ffi shared library
uses: actions/upload-artifact@v4
with:
name: regorus-ffi-artifacts-${{ matrix.runtime.target }}
# Note: The full path of each artifact relative to . is preserved.
path: ${{ matrix.runtime.libpath }}
if-no-files-found: error
retention-days: 1
build-nuget:
name: 'Build Regorus nuget'
runs-on: ubuntu-latest
needs: build-ffi
steps:
- name: Checkout repository
uses: actions/checkout@v4
with:
fetch-depth: 0
- uses: actions/setup-dotnet@v4
with:
global-json-file: ./bindings/csharp/global.json
- run: echo '${{ steps.stepid.outputs.dotnet-version }}'
- name: Download regorus ffi shared libraries
uses: actions/download-artifact@v4
with:
pattern: regorus-ffi-artifacts-*
merge-multiple: true
path: ./bindings/csharp/Regorus/tmp
- name: Display regorus ffi artifacts
run: ls -R ./bindings/csharp/Regorus/tmp
# Note that we need to supply the target folder within the folder where artifacts are downloaded.
- name: Build Regorus binding
run: dotnet build /p:Configuration=Release /p:RegorusFFIArtifactsDir=./tmp/bindings/ffi/target
working-directory: ./bindings/csharp/Regorus
- name: Pack
run: dotnet pack /p:RegorusFFIArtifactsDir=./tmp/bindings/ffi/target
working-directory: ./bindings/csharp/Regorus
- name: Upload Regorus nuget
uses: actions/upload-artifact@v4
with:
name: regorus-nuget
path: bindings/csharp/Regorus/bin/Release/Regorus*.nupkg
if-no-files-found: error
retention-days: 1
test-nuget:
name: 'Test Regorus Nuget: (${{ matrix.runtime.target }})'
needs: build-nuget
runs-on: ${{ matrix.runtime.os }}
strategy:
# let us get failures from other jobs even if one fails
fail-fast: false
matrix:
runtime:
- os: windows-latest
target: x86_64-pc-windows-msvc
- os: ubuntu-latest
target: x86_64-unknown-linux-gnu
#- os: macos-latest
# target: aarch64-apple-darwin
steps:
- name: Checkout repository
uses: actions/checkout@v4
@@ -16,11 +112,21 @@ jobs:
fetch-depth: 0
- uses: actions/setup-dotnet@v4
with:
global-json-file: ./bindings/csharp/global.json
- name: Build
run: dotnet build
working-directory: ./bindings/csharp/net8.0
- run: echo '${{ steps.stepid.outputs.dotnet-version }}'
- name: Run
run: LD_LIBRARY_PATH=. dotnet run
working-directory: ./bindings/csharp/net8.0
- name: Download regorus nuget
uses: actions/download-artifact@v4
with:
name: regorus-nuget
path: ./bindings/csharp/Regorus.Tests/regorus-nuget/
- name: Restore Regorus.Tests
run: dotnet restore /p:RestoreAdditionalProjectSources=./regorus-nuget
working-directory: ./bindings/csharp/Regorus.Tests
- name: Run Regorus.Tests
run: dotnet test --no-restore
working-directory: ./bindings/csharp/Regorus.Tests

View File

@@ -1,28 +0,0 @@
name: bindings/csharp40
on:
push:
branches: [ "main" ]
pull_request:
branches: [ "main" ]
jobs:
test:
runs-on: windows-latest
steps:
- name: Checkout repository
uses: actions/checkout@v4
with:
fetch-depth: 0
- uses: actions/setup-dotnet@v1
with:
dotnet-version: "5.0.x"
- name: Build
run: dotnet build
working-directory: ./bindings/csharp/net40
- name: Run
run: dotnet run
working-directory: ./bindings/csharp/net40

View File

@@ -17,6 +17,7 @@ jobs:
- name: Test FFI
run: |
cargo build -r
cargo fetch
cargo build -r --frozen
cargo clippy --all-targets --no-deps -- -Dwarnings
working-directory: ./bindings/ffi

View File

@@ -18,7 +18,6 @@ jobs:
- uses: actions/setup-go@v5
with:
python-version: ${{ env.PYTHON_VERSION }}
architecture: x64
- name: Build ffi
@@ -29,5 +28,5 @@ jobs:
run: |
go mod tidy
go build
LD_LIBRARY_PATH=../../target/release ./regorus_test
LD_LIBRARY_PATH=../ffi/target/release ./regorus_test
working-directory: ./bindings/go

View File

@@ -24,7 +24,7 @@ jobs:
- name: Building binding
run: |
cargo clippy --all-targets --no-deps -- -Dwarnings
cargo build --release --manifest-path bindings/java/Cargo.toml
cargo build --release --manifest-path bindings/java/Cargo.toml --locked
- name: Build jar
run: mvn package
@@ -33,5 +33,5 @@ jobs:
- name: Test jar
run: |
javac -cp target/regorus-java-0.2.2.jar Test.java
java -Djava.library.path=../../target/release -cp target/regorus-java-0.2.2.jar:. Test
java -Djava.library.path=target/release -cp target/regorus-java-0.2.2.jar:. Test
working-directory: ./bindings/java

View File

@@ -20,14 +20,16 @@ jobs:
run: rustup target add x86_64-unknown-linux-musl
- name: Install musl-gcc
run: sudo apt update && sudo apt install -y musl-tools
- name: Fetch
run: cargo fetch
- name: Build (MUSL)
run: cargo build --verbose --all-targets --target x86_64-unknown-linux-musl
run: cargo build --verbose --all-targets --target x86_64-unknown-linux-musl --frozen
- name: Run tests (MUSL)
run: cargo test -r --verbose --target x86_64-unknown-linux-musl
run: cargo test -r --verbose --target x86_64-unknown-linux-musl --frozen
- name: Run tests (MUSL ACI)
run: cargo test -r --test aci --target x86_64-unknown-linux-musl
run: cargo test -r --test aci --target x86_64-unknown-linux-musl --frozen
- name: Run tests (KATA ACI)
run: cargo test -r --test kata --target x86_64-unknown-linux-musl
run: cargo test -r --test kata --target x86_64-unknown-linux-musl --frozen
- name: Run tests (MUSL OPA Conformance)
run: >-
cargo test -r --test opa --features opa-testutil,serde_json/arbitrary_precision --target x86_64-unknown-linux-musl -- $(tr '\n' ' ' < tests/opa.passing)
cargo test -r --test opa --frozen --features opa-testutil,serde_json/arbitrary_precision --target x86_64-unknown-linux-musl -- $(tr '\n' ' ' < tests/opa.passing)

View File

@@ -18,7 +18,9 @@ jobs:
- uses: actions/checkout@v3
- name: Add no_std target
run: rustup target add thumbv7m-none-eabi
- name: Fetch
run: cargo fetch
- name: Build
run: cargo build -r --target thumbv7m-none-eabi
run: cargo build -r --target thumbv7m-none-eabi --frozen
working-directory: ./tests/ensure_no_std

View File

@@ -8,10 +8,17 @@ on:
env:
PYTHON_VERSION: "3.10"
jobs:
test:
runs-on: ubuntu-latest
build:
strategy:
matrix:
host:
- name: ubuntu-22.04
target: x86_64-unknown-linux-gnu
- name: windows-latest
target: x86_64-pc-windows-msvc
runs-on: ${{ matrix.host.name }}
steps:
- name: Checkout repository
uses: actions/checkout@v4
@@ -23,16 +30,60 @@ jobs:
python-version: ${{ env.PYTHON_VERSION }}
architecture: x64
- name: Build wheels
- name: Build Python extension
run: |
cargo fetch
cargo clippy --all-targets --no-deps -- -Dwarnings
cargo build --release --target ${{ matrix.host.target }} --frozen
working-directory: bindings/python
- name: Build Wheel
uses: PyO3/maturin-action@63b75c597b83e247fbf4fb7719801cc4220ae9f3 # v1.43.0
with:
target: x86_64
args: --release --out dist --manifest-path bindings/python/Cargo.toml
args: --release --out dist --manifest-path bindings/python/Cargo.toml --offline --strip
sccache: 'true'
- name: Test wheel
- name: Upload Wheel
uses: actions/upload-artifact@v4
with:
name: regorus-wheel-${{ matrix.host.name }}
path: dist/regorus-*.whl
test:
strategy:
matrix:
python-version: ["3.10", "3.11", "3.12", "3.13"]
host:
- name: ubuntu-24.04
wheel: regorus-0.4.0-cp310-abi3-manylinux_2_34_x86_64.whl
- name: ubuntu-22.04
wheel: regorus-0.4.0-cp310-abi3-manylinux_2_34_x86_64.whl
- name: windows-latest
wheel: regorus-0.4.0-cp310-abi3-win_amd64.whl
needs: build
runs-on: ${{ matrix.host.name }}
steps:
- name: Checkout repository
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Download Regorus wheel
uses: actions/download-artifact@v4
with:
path: wheels
pattern: regorus-wheel-*
merge-multiple: true
- uses: actions/setup-python@v4
with:
python-version: ${{ matrix.python-version }}
architecture: x64
- name: Test Wheel
run: |
pip3 install dist/regorus-*.whl
cd bindings/python
cargo clippy --all-targets --no-deps -- -Dwarnings
python3 test.py
pip3 install ../../wheels/${{ matrix.host.wheel }}
python3 test.py
working-directory: bindings/python

View File

@@ -18,7 +18,9 @@ jobs:
- name: Setup Ruby and Rust
uses: oxidize-rb/actions/setup-ruby-and-rust@7ca44a16e287e5ff7dd72ab53f4bd41cbf34a571 #v1.26
with:
ruby-version: "3.3.1"
bundler: 2.6.5
rubygems: 3.6.5
ruby-version: "3.4.2"
rustup-toolchain: "stable"
bundler-cache: true
cargo-cache: true
@@ -27,5 +29,7 @@ jobs:
- name: Run ruby tests
run: |
cd bindings/ruby
gem install bundler
bundle install
cargo clippy --all-targets --no-deps -- -Dwarnings
bundle exec rake

View File

@@ -26,7 +26,10 @@ jobs:
- name: Test wasm binding
run: |
cd bindings/wasm
cargo fetch
cargo clippy --all-targets --no-deps -- -Dwarnings
wasm-pack build --target nodejs --release
wasm-pack test --release --node
# Enable when upstream issue is fixed.
# https://github.com/microsoft/regorus/issues/371
# wasm-pack test --release --node
node test.js

View File

@@ -16,22 +16,24 @@ jobs:
steps:
- uses: actions/checkout@v4
- name: Fetch
run: cargo fetch
- name: Build (all features)
run: cargo build --all-features
run: cargo build --all-features --frozen
- name: Build
run: cargo build
run: cargo build --frozen
- name: Test no_std
run: cargo test --no-default-features
run: cargo test --no-default-features --frozen
- name: Build only std
run: cargo build --example regorus --no-default-features --features "std"
run: cargo build --example regorus --no-default-features --features "std" --frozen
- name: Doc Tests
run: cargo test --doc
run: cargo test --doc --frozen
- name: Run tests
run: cargo test
run: cargo test --frozen
- name: Run tests (ACI)
run: cargo test --test aci
run: cargo test --test aci --frozen
- name: Run tests (KATA)
run: cargo test --test kata
run: cargo test --test kata --frozen
- name: Run tests (OPA Conformance)
run: >-
cargo test --test opa --features opa-testutil,serde_json/arbitrary_precision -- $(tr '\n' ' ' < tests/opa.passing)
cargo test --test opa --frozen --features opa-testutil,serde_json/arbitrary_precision -- $(tr '\n' ' ' < tests/opa.passing)

12
.gitignore vendored
View File

@@ -4,10 +4,6 @@
**/wheels/
**/__pycache__/
# Remove Cargo.lock from gitignore if creating an executable, leave it for libraries
# More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html
Cargo.lock
# These are backup files generated by rustfmt
**/*.rs.bk
@@ -25,4 +21,10 @@ worktrees/
# Generated C, C++ headers
bindings/ffi/regorus.h
bindings/ffi/regorus.ffi.hpp
bindings/ffi/regorus.ffi.hpp
bindings/*/target
# C# build folders
**bin
**obj

View File

@@ -6,6 +6,76 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## [Unreleased]
## [0.4.0](https://github.com/microsoft/regorus/compare/regorus-v0.3.0...regorus-v0.4.0) - 2025-03-14
### Fixed
- [**breaking**] Update ruby json dependency ([#381](https://github.com/microsoft/regorus/pull/381))
- [**breaking**] Remove ring dependency ([#380](https://github.com/microsoft/regorus/pull/380))
- [**breaking**] Remove sha1 dependency ([#379](https://github.com/microsoft/regorus/pull/379))
### Other
- Specify optimization flags ([#378](https://github.com/microsoft/regorus/pull/378))
## [0.3.0](https://github.com/microsoft/regorus/compare/regorus-v0.2.8...regorus-v0.3.0) - 2025-03-10
### Added
- [**breaking**] Update to OPA v1.2.0 ([#373](https://github.com/microsoft/regorus/pull/373))
### Other
- *(deps)* update pyo3 requirement from 0.23.5 to 0.24.0 ([#375](https://github.com/microsoft/regorus/pull/375))
- Update ruby binding deps, ruby gem version 0.2.3 ([#374](https://github.com/microsoft/regorus/pull/374))
- *(deps)* update pyo3 requirement from 0.22.0 to 0.23.5 ([#372](https://github.com/microsoft/regorus/pull/372))
- *(deps)* update rand requirement from 0.8.5 to 0.9.0 ([#370](https://github.com/microsoft/regorus/pull/370))
- *(deps)* update cbindgen requirement from 0.27.0 to 0.28.0 ([#361](https://github.com/microsoft/regorus/pull/361))
- Fix typo in README.md ([#366](https://github.com/microsoft/regorus/pull/366))
- Update dependencies ([#369](https://github.com/microsoft/regorus/pull/369))
- Fix clippy warning for result? ([#362](https://github.com/microsoft/regorus/pull/362))
- *(deps)* update itertools requirement from 0.13.0 to 0.14.0 ([#357](https://github.com/microsoft/regorus/pull/357))
- *(deps)* update jsonschema requirement from 0.26.1 to 0.28.1 ([#356](https://github.com/microsoft/regorus/pull/356))
- resolve anyhow compile errors ([#355](https://github.com/microsoft/regorus/pull/355))
- *(deps)* update prettydiff requirement from 0.7.0 to 0.8.0 ([#348](https://github.com/microsoft/regorus/pull/348))
## [0.2.8](https://github.com/microsoft/regorus/compare/regorus-v0.2.7...regorus-v0.2.8) - 2024-11-06
### Other
- *(deps)* update jsonschema requirement from 0.24.0 to 0.26.1 ([#343](https://github.com/microsoft/regorus/pull/343))
- Update to OPA v0.70.0 ([#341](https://github.com/microsoft/regorus/pull/341))
## [0.2.7](https://github.com/microsoft/regorus/compare/regorus-v0.2.6...regorus-v0.2.7) - 2024-10-22
### Fixed
- docs failing to build ([#334](https://github.com/microsoft/regorus/pull/334))
### Other
- *(deps)* update jsonschema requirement from 0.23.0 to 0.24.0 ([#332](https://github.com/microsoft/regorus/pull/332))
- *(deps)* update jsonschema requirement from 0.22.3 to 0.23.0 ([#331](https://github.com/microsoft/regorus/pull/331))
## [0.2.6](https://github.com/microsoft/regorus/compare/regorus-v0.2.5...regorus-v0.2.6) - 2024-10-09
### Added
- integer conversion functions for Value ([#328](https://github.com/microsoft/regorus/pull/328))
### Other
- update to OPA v0.69.0 ([#327](https://github.com/microsoft/regorus/pull/327))
- *(deps)* update jsonschema requirement from 0.21.0 to 0.22.3 ([#326](https://github.com/microsoft/regorus/pull/326))
- *(deps)* update jsonschema requirement from 0.20.0 to 0.21.0 ([#325](https://github.com/microsoft/regorus/pull/325))
- update to jsonschema 0.20.0 ([#323](https://github.com/microsoft/regorus/pull/323))
## [0.2.5](https://github.com/microsoft/regorus/compare/regorus-v0.2.4...regorus-v0.2.5) - 2024-09-18
### Added
- or keyword ([#315](https://github.com/microsoft/regorus/pull/315))
### Fixed
- Null terminate C# strings in Rust boundary ([#318](https://github.com/microsoft/regorus/pull/318))
- Update readme with correct path to example policy ([#312](https://github.com/microsoft/regorus/pull/312))
### Other
- Update jsonschema requirement from 0.18.0 to 0.19.1 ([#317](https://github.com/microsoft/regorus/pull/317))
- Update chrono-tz requirement from 0.8.5 to 0.10.0 ([#316](https://github.com/microsoft/regorus/pull/316))
- Add tests for builtin strings::lower method ([#313](https://github.com/microsoft/regorus/pull/313))
- Add tests for builtin strings::indexof method ([#311](https://github.com/microsoft/regorus/pull/311))
## [0.2.4](https://github.com/microsoft/regorus/compare/regorus-v0.2.3...regorus-v0.2.4) - 2024-09-04
### Added

1778
Cargo.lock generated Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -1,18 +1,13 @@
[workspace]
members = [
"bindings/ffi",
"bindings/python",
"bindings/wasm",
"bindings/java",
"bindings/ruby/ext/regorusrb",
"tests/ensure_no_std",
]
[package]
name = "regorus"
description = "A fast, lightweight Rego (OPA policy language) interpreter"
version = "0.2.4"
version = "0.4.0"
edition = "2021"
license-file = "LICENSE"
repository = "https://github.com/microsoft/regorus"
@@ -31,14 +26,13 @@ ast = []
base64 = ["dep:data-encoding"]
base64url = ["dep:data-encoding"]
coverage = []
crypto = ["dep:constant_time_eq", "dep:hmac", "dep:hex", "dep:md-5", "dep:sha1", "dep:sha2"]
crypto = ["dep:constant_time_eq", "dep:hmac", "dep:hex", "dep:md-5", "dep:sha2"]
deprecated = []
hex = ["dep:data-encoding"]
http = []
glob = ["dep:wax"]
glob = ["dep:globset"]
graph = []
jsonschema = ["dep:jsonschema"]
jwt = ["dep:jsonwebtoken", "dep:data-encoding", "dep:itertools"]
no_std = ["lazy_static/spin_no_std"]
opa-runtime = []
regex = ["dep:regex"]
@@ -58,7 +52,6 @@ full-opa = [
"graph",
"hex",
"http",
"jwt",
"jsonschema",
"opa-runtime",
"regex",
@@ -67,7 +60,9 @@ full-opa = [
"time",
"uuid",
"urlquery",
"yaml"
"yaml",
#"rego-extensions"
]
# Features that can be used in no_std environments.
@@ -89,6 +84,9 @@ opa-no-std = [
"lazy_static/spin_no_std"
]
# Rego language extensions
rego-extensions = []
# This feature enables some testing utils for OPA tests.
opa-testutil = []
rand = ["dep:rand"]
@@ -100,35 +98,33 @@ serde_json = { version = "1.0.89", default-features = false, features = ["alloc"
lazy_static = { version = "1.4.0", default-features = false }
# Crypto
constant_time_eq = {version = "0.3.0", optional = true, default-features = false }
constant_time_eq = {version = "0.4.0", optional = true, default-features = false }
hmac = {version = "0.12.1", optional = true, default-features = false}
sha2 = {version= "0.10.8", optional = true, default-features = false }
hex = {version = "0.4.3", optional = true, default-features = false, features = ["alloc"] }
sha1 = {version = "0.10.6", optional = true, default-features = false }
md-5 = {version = "0.10.6", optional = true, default-features = false }
data-encoding = { version = "2.4.0", optional = true, default-features=false, features = ["alloc"] }
scientific = { version = "0.5.2" }
data-encoding = { version = "2.8.0", optional = true, default-features=false, features = ["alloc"] }
scientific = { version = "0.5.3" }
regex = {version = "1.10.2", optional = true, default-features = false }
semver = {version = "1.0.20", optional = true, default-features = false }
wax = { version = "0.6.0", features = [], default-features = false, optional = true }
url = { version = "2.5.0", optional = true }
uuid = { version = "1.6.1", default-features = false, features = ["v4", "fast-rng"], optional = true }
jsonschema = { version = "0.18.0", default-features = false, optional = true }
chrono = { version = "0.4.31", optional = true }
chrono-tz = { version = "0.8.5", optional = true }
jsonwebtoken = { version = "9.2.0", optional = true }
itertools = { version = "0.13.0", default-features = false, optional = true }
globset = { version = "0.4.16", features = ["simd-accel"], default-features = false, optional = true }
regex = {version = "1.11.1", optional = true, default-features = false }
semver = {version = "1.0.25", optional = true, default-features = false }
url = { version = "2.5.4", optional = true }
uuid = { version = "1.15.1", default-features = false, features = ["v4", "fast-rng"], optional = true }
jsonschema = { version = "0.29.0", default-features = false, optional = true }
chrono = { version = "0.4.40", optional = true }
chrono-tz = { version = "0.10.1", optional = true }
serde_yaml = {version = "0.9.16", default-features = false, optional = true }
rand = { version = "0.8.5", default-features = false, optional = true }
# Specify thread_rng for in order to use random_range
rand = { version = "0.9.0", default-features = false, features = ["thread_rng"], optional = true }
[dev-dependencies]
anyhow = "1.0.45"
cfg-if = "1.0.0"
clap = { version = "4.4.7", features = ["derive"] }
prettydiff = { version = "0.7.0", default-features = false }
clap = { version = "4.5.36", features = ["derive"] }
prettydiff = { version = "0.8.0", default-features = false }
serde_yaml = "0.9.16"
test-generator = "0.3.1"
walkdir = "2.3.2"
@@ -138,6 +134,8 @@ anyhow = "1.0"
[profile.release]
debug = true
lto = true
codegen-units = 1
[[test]]
name="opa"

View File

@@ -9,8 +9,8 @@
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 supports `import rego.v1`.
- *compliant* - Regorus is mostly compliant with the latest [OPA release v0.68.0](https://github.com/open-policy-agent/opa/releases/tag/v0.68.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.
- *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.
@@ -32,7 +32,6 @@ fn main() -> anyhow::Result<()> {
let policy = String::from(
r#"
package example
import rego.v1
allow if {
## All actions are allowed for admins.
@@ -99,7 +98,7 @@ $ cargo build -r --example regorus --no-default-features; strip target/release/e
-rwxr-xr-x 1 anand staff 1.9M May 11 22:04 target/release/examples/regorus*
```
Regorus passes the [OPA v0.68.0 test-suite](https://www.openpolicyagent.org/docs/latest/ir/#test-suite) barring a few
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
@@ -108,11 +107,11 @@ 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).
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).
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).
@@ -184,11 +183,11 @@ This produces the following output
}
```
Next, evaluate a sample [policy](https://github.com/microsoft/regorus/blob/main/examples/example.rego) and [input](https://github.com/microsoft/regorus/blob/main/examples/input.json)
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/example.rego -i examples/input.json data.example
$ 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)
@@ -204,7 +203,7 @@ Regorus allows determining which lines of a policy have been executed using the
We can try it out using the `regorus` example program by passing in the `--coverage` flag.
```shell
$ regorus eval -d examples/example.rego -i examples/input.json data.example --coverage
$ 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.
@@ -276,7 +275,7 @@ Benchmark 1: opa eval -b tests/aci -d tests/aci/data.json -i tests/aci/input.jso
```
## OPA Conformance
Regorus has been verified to be compliant with [OPA v0.68.0](https://github.com/open-policy-agent/opa/releases/tag/v0.68.0)
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:
@@ -288,7 +287,7 @@ $ cargo test -r --test opa --features opa-testutil,serde_json/arbitrary_precisio
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 mising builtins:
The following test suites don't pass fully due to missing builtins:
- `cryptoparsersaprivatekeys`
- `cryptox509parseandverifycertificates`
- `cryptox509parsecertificaterequest`
@@ -299,8 +298,11 @@ The following test suites don't pass fully due to mising builtins:
- `graphql`
- `invalidkeyerror`
- `jsonpatch`
- `jwtbuiltins`
- `jwtdecodeverify`
- `jwtencodesign`
- `jwtencodesignheadererrors`
- `jwtencodesignpayloaderrors`
- `jwtencodesignraw`
- `jwtverifyhs256`
- `jwtverifyhs384`
@@ -322,6 +324,7 @@ The following test suites don't pass fully due to mising builtins:
They are captured in the following [github issues](https://github.com/microsoft/regorus/issues?q=is%3Aopen+is%3Aissue+label%3Alib).
Cryptographically insecure `sha1` related builtins are intentionally not supported to discourage their use.
### Grammar

View File

@@ -7,7 +7,8 @@ include(FetchContent)
FetchContent_Declare(
Corrosion
GIT_REPOSITORY https://github.com/corrosion-rs/corrosion.git
GIT_TAG v0.4 # Optionally specify a commit hash, version tag or branch here
# Use a tag that has a fix for https://github.com/corrosion-rs/corrosion/issues/590
GIT_TAG 6be991bb34c348dfb8344be22f3606288ea5c7fd
)
FetchContent_MakeAvailable(Corrosion)
@@ -31,6 +32,8 @@ corrosion_import_crate(
# See regorus/opa_no_std
FEATURES "custom_allocator,regorus/semver"
LOCKED
# Link statically
CRATE_TYPES staticlib FLAGS --crate-type=staticlib
)

View File

@@ -27,7 +27,7 @@ char* file_to_string(const char* file) {
// If regorus is built with custom-allocator, then provide implementation.
uint8_t* regorus_aligned_alloc(size_t alignment, size_t size) {
return aligned_alloc(alignment, size);
return (uint8_t*) aligned_alloc(alignment, size);
}
void regorus_free(uint8_t* ptr) {
@@ -41,6 +41,11 @@ int main() {
RegorusResult r;
char* buffer = NULL;
// Turn on rego v0 since policy uses v0.
r = regorus_engine_set_rego_v0(engine, true);
if (r.status != RegorusStatusOk)
goto error;
// Load policies.
r = regorus_engine_add_policy(engine, "framework.rego", (buffer = file_to_string("../../../tests/aci/framework.rego")));
free(buffer);

View File

@@ -7,7 +7,8 @@ include(FetchContent)
FetchContent_Declare(
Corrosion
GIT_REPOSITORY https://github.com/corrosion-rs/corrosion.git
GIT_TAG v0.4 # Optionally specify a commit hash, version tag or branch here
# Use a tag that has a fix for https://github.com/corrosion-rs/corrosion/issues/590
GIT_TAG 6be991bb34c348dfb8344be22f3606288ea5c7fd
)
FetchContent_MakeAvailable(Corrosion)
@@ -24,6 +25,8 @@ corrosion_import_crate(
# Select specific features in regorus.
FEATURES "regorus/semver"
LOCKED
# Link statically
CRATE_TYPES "cdylib"
)

View File

@@ -6,6 +6,11 @@ int main() {
RegorusEngine* engine = regorus_engine_new();
RegorusResult r;
// Turn on rego v0 since policy uses v0.
r = regorus_engine_set_rego_v0(engine, true);
if (r.status != RegorusStatusOk)
goto error;
// Load policies.
r = regorus_engine_add_policy_from_file(engine, "../../../tests/aci/framework.rego");
if (r.status != RegorusStatusOk)

View File

@@ -7,7 +7,8 @@ include(FetchContent)
FetchContent_Declare(
Corrosion
GIT_REPOSITORY https://github.com/corrosion-rs/corrosion.git
GIT_TAG v0.4 # Optionally specify a commit hash, version tag or branch here
# Use a tag that has a fix for https://github.com/corrosion-rs/corrosion/issues/590
GIT_TAG 6be991bb34c348dfb8344be22f3606288ea5c7fd
)
FetchContent_MakeAvailable(Corrosion)
@@ -25,6 +26,8 @@ corrosion_import_crate(
# Select specific features in regorus.
FEATURES "regorus/semver"
LOCKED
# Link statically
CRATE_TYPES "cdylib")

View File

@@ -6,6 +6,7 @@ void example()
// Create engine
regorus::Engine engine;
engine.set_rego_v0(true);
engine.set_enable_coverage(true);
// Add policies.
@@ -83,6 +84,7 @@ int main() {
// Create engine.
regorus::Engine engine;
engine.set_rego_v0(true);
// Load policies.

View File

@@ -54,6 +54,9 @@ namespace regorus {
return std::unique_ptr<Engine>(new Engine(regorus_engine_clone(engine)));
}
Result set_rego_v0(bool enable) {
return Result(regorus_engine_set_rego_v0(engine, enable));
}
Result add_policy(const char* path, const char* policy) {
return Result(regorus_engine_add_policy(engine, path, policy));

View File

@@ -0,0 +1,22 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<Nullable>Enable</Nullable>
<TargetFramework>net8.0</TargetFramework>
<EnableMSTestRunner>true</EnableMSTestRunner>
<!-- More info about dotnet test integration https://learn.microsoft.com/dotnet/core/testing/unit-testing-platform-integration-dotnet-test -->
<TestingPlatformDotnetTestSupport>true</TestingPlatformDotnetTestSupport>
<TestingPlatformShowTestsFailure>true</TestingPlatformShowTestsFailure>
</PropertyGroup>
<ItemGroup>
<None Include="../../../tests/**/*.*" Link="tests/%(RecursiveDir)%(Filename)%(Extension)" CopyToOutputDirectory="PreserveNewest" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="MSTest" Version="3.8.2" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Regorus" Version="0.5.0"/>
</ItemGroup>
</Project>

View File

@@ -0,0 +1,176 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
namespace Regorus.Tests;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System.Text.Json.Nodes;
[TestClass]
public class RegorusTests
{
[TestMethod]
public void Basic_evaluation_succeeds()
{
using var engine = new Engine();
engine.AddPolicy(
"test.rego",
"package test\nx = 1\nmessage = `Hello`");
var result = engine.EvalRule("data.test.message");
Assert.AreEqual("\"Hello\"", result);
}
[TestMethod]
public void Evaluation_using_file_policies_succeeds()
{
using var engine = new Engine();
engine.SetRegoV0(true);
// Load policies and data.
engine.AddPolicyFromFile("tests/aci/framework.rego");
engine.AddPolicyFromFile("tests/aci/api.rego");
engine.AddPolicyFromFile("tests/aci/policy.rego");
engine.AddDataFromJsonFile("tests/aci/data.json");
// Set input and eval rule.
engine.SetInputFromJsonFile("tests/aci/input.json");
var result = engine.EvalRule("data.framework.mount_overlay");
var expected = """
{
"allowed": true,
"metadata": [
{
"action": "add",
"key": "container0",
"name": "matches",
"value": [
{
"allow_elevated": true,
"allow_stdio_access": false,
"capabilities": {
"ambient": [
"CAP_SYS_ADMIN"
],
"bounding": [
"CAP_SYS_ADMIN"
],
"effective": [
"CAP_SYS_ADMIN"
],
"inheritable": [
"CAP_SYS_ADMIN"
],
"permitted": [
"CAP_SYS_ADMIN"
]
},
"command": [
"rustc",
"--help"
],
"env_rules": [
{
"pattern": "PATH=/usr/local/cargo/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
"required": true,
"strategy": "string"
},
{
"pattern": "RUSTUP_HOME=/usr/local/rustup",
"required": true,
"strategy": "string"
},
{
"pattern": "CARGO_HOME=/usr/local/cargo",
"required": true,
"strategy": "string"
},
{
"pattern": "RUST_VERSION=1.52.1",
"required": true,
"strategy": "string"
},
{
"pattern": "TERM=xterm",
"required": false,
"strategy": "string"
},
{
"pattern": "PREFIX_.+=.+",
"required": false,
"strategy": "re2"
}
],
"exec_processes": [
{
"command": [
"top"
],
"signals": []
}
],
"layers": [
"fe84c9d5bfddd07a2624d00333cf13c1a9c941f3a261f13ead44fc6a93bc0e7a",
"4dedae42847c704da891a28c25d32201a1ae440bce2aecccfa8e6f03b97a6a6c",
"41d64cdeb347bf236b4c13b7403b633ff11f1cf94dbc7cf881a44d6da88c5156",
"eb36921e1f82af46dfe248ef8f1b3afb6a5230a64181d960d10237a08cd73c79",
"e769d7487cc314d3ee748a4440805317c19262c7acd2fdbdb0d47d2e4613a15c",
"1b80f120dbd88e4355d6241b519c3e25290215c469516b49dece9cf07175a766"
],
"mounts": [
{
"destination": "/container/path/one",
"options": [
"rbind",
"rshared",
"rw"
],
"source": "sandbox:///host/path/one",
"type": "bind"
},
{
"destination": "/container/path/two",
"options": [
"rbind",
"rshared",
"ro"
],
"source": "sandbox:///host/path/two",
"type": "bind"
}
],
"no_new_privileges": true,
"seccomp_profile_sha256": "",
"signals": [],
"user": {
"group_idnames": [
{
"pattern": "",
"strategy": "any"
}
],
"umask": "0022",
"user_idname": {
"pattern": "",
"strategy": "any"
}
},
"working_dir": "/home/user"
}
]
},
{
"action": "add",
"key": "/run/gcs/c/container0/rootfs",
"name": "overlayTargets",
"value": true
}
]
}
""";
Assert.IsTrue(JsonNode.DeepEquals(JsonNode.Parse(expected), JsonNode.Parse(result!)), $"Actual: {result}");
}
}

View File

@@ -0,0 +1,240 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
using System;
using System.Runtime.InteropServices;
using System.Text;
#nullable enable
namespace Regorus
{
public unsafe sealed class Engine : System.IDisposable
{
private Regorus.Internal.RegorusEngine* E;
// Detect redundant Dispose() calls in a thread-safe manner.
// _isDisposed == 0 means Dispose(bool) has not been called yet.
// _isDisposed == 1 means Dispose(bool) has been already called.
private int isDisposed;
public Engine()
{
E = Regorus.Internal.API.regorus_engine_new();
}
public void Dispose()
{
Dispose(disposing: true);
// This object will be cleaned up by the Dispose method.
// Therefore, call GC.SuppressFinalize to
// take this object off the finalization queue
// and prevent finalization code for this object
// from executing a second time.
GC.SuppressFinalize(this);
}
// Dispose(bool disposing) executes in two distinct scenarios.
// If disposing equals true, the method has been called directly
// or indirectly by a user's code. Managed and unmanaged resources
// can be disposed.
// If disposing equals false, the method has been called by the
// runtime from inside the finalizer and you should not reference
// other objects. Only unmanaged resources can be disposed.
void Dispose(bool disposing)
{
// In case _isDisposed is 0, atomically set it to 1.
// Enter the branch only if the original value is 0.
if (System.Threading.Interlocked.CompareExchange(ref isDisposed, 1, 0) == 0)
{
// If disposing equals true, dispose all managed
// and unmanaged resources.
if (disposing)
{
// No managed resource to dispose.
}
// Call the appropriate methods to clean up
// unmanaged resources here.
// If disposing is false,
// only the following code is executed.
if (E != null)
{
Regorus.Internal.API.regorus_engine_drop(E);
E = null;
}
}
}
// Use C# finalizer syntax for finalization code.
// This finalizer will run only if the Dispose method
// does not get called.
~Engine() => Dispose(disposing: false);
// Helper for implementing Clone
private Engine(Internal.RegorusEngine* engine)
{
this.E = engine;
}
public Engine Clone() => new(Internal.API.regorus_engine_clone(E));
byte[] NullTerminatedUTF8Bytes(string s)
{
return Encoding.UTF8.GetBytes(s + char.MinValue);
}
public string? AddPolicy(string path, string rego)
{
var pathBytes = NullTerminatedUTF8Bytes(path);
var regoBytes = NullTerminatedUTF8Bytes(rego);
fixed (byte* pathPtr = pathBytes)
{
fixed (byte* regoPtr = regoBytes)
{
return CheckAndDropResult(Regorus.Internal.API.regorus_engine_add_policy(E, pathPtr, regoPtr));
}
}
}
public void SetRegoV0(bool enable)
{
CheckAndDropResult(Regorus.Internal.API.regorus_engine_set_rego_v0(E, enable));
}
public string? AddPolicyFromFile(string path)
{
var pathBytes = NullTerminatedUTF8Bytes(path);
fixed (byte* pathPtr = pathBytes)
{
return CheckAndDropResult(Regorus.Internal.API.regorus_engine_add_policy_from_file(E, pathPtr));
}
}
public void AddDataJson(string data)
{
var dataBytes = NullTerminatedUTF8Bytes(data);
fixed (byte* dataPtr = dataBytes)
{
CheckAndDropResult(Regorus.Internal.API.regorus_engine_add_data_json(E, dataPtr));
}
}
public void AddDataFromJsonFile(string path)
{
var pathBytes = NullTerminatedUTF8Bytes(path);
fixed (byte* pathPtr = pathBytes)
{
CheckAndDropResult(Regorus.Internal.API.regorus_engine_add_data_from_json_file(E, pathPtr));
}
}
public void SetInputJson(string input)
{
var inputBytes = NullTerminatedUTF8Bytes(input);
fixed (byte* inputPtr = inputBytes)
{
CheckAndDropResult(Regorus.Internal.API.regorus_engine_set_input_json(E, inputPtr));
}
}
public void SetInputFromJsonFile(string path)
{
var pathBytes = NullTerminatedUTF8Bytes(path);
fixed (byte* pathPtr = pathBytes)
{
CheckAndDropResult(Regorus.Internal.API.regorus_engine_set_input_from_json_file(E, pathPtr));
}
}
public string? EvalQuery(string query)
{
var queryBytes = NullTerminatedUTF8Bytes(query);
fixed (byte* queryPtr = queryBytes)
{
return CheckAndDropResult(Regorus.Internal.API.regorus_engine_eval_query(E, queryPtr));
}
}
public string? EvalRule(string rule)
{
var ruleBytes = NullTerminatedUTF8Bytes(rule);
fixed (byte* rulePtr = ruleBytes)
{
return CheckAndDropResult(Regorus.Internal.API.regorus_engine_eval_rule(E, rulePtr));
}
}
public void SetEnableCoverage(bool enable)
{
CheckAndDropResult(Regorus.Internal.API.regorus_engine_set_enable_coverage(E, enable));
}
public void ClearCoverageData()
{
CheckAndDropResult(Regorus.Internal.API.regorus_engine_clear_coverage_data(E));
}
public string? GetCoverageReport()
{
return CheckAndDropResult(Regorus.Internal.API.regorus_engine_get_coverage_report(E));
}
public string? GetCoverageReportPretty()
{
return CheckAndDropResult(Regorus.Internal.API.regorus_engine_get_coverage_report_pretty(E));
}
public void SetGatherPrints(bool enable)
{
CheckAndDropResult(Regorus.Internal.API.regorus_engine_set_gather_prints(E, enable));
}
public string? TakePrints()
{
return CheckAndDropResult(Regorus.Internal.API.regorus_engine_take_prints(E));
}
string? StringFromUTF8(IntPtr ptr)
{
#if NETSTANDARD2_1
return System.Runtime.InteropServices.Marshal.PtrToStringUTF8(ptr);
#else
int len = 0;
while (Marshal.ReadByte(ptr, len) != 0) { ++len; }
byte[] buffer = new byte[len];
Marshal.Copy(ptr, buffer, 0, buffer.Length);
return Encoding.UTF8.GetString(buffer);
#endif
}
string? CheckAndDropResult(Regorus.Internal.RegorusResult result)
{
if (result.status != Regorus.Internal.RegorusStatus.RegorusStatusOk)
{
var message = StringFromUTF8((IntPtr)result.error_message);
var ex = new Exception(message);
Regorus.Internal.API.regorus_result_drop(result);
throw ex;
}
var resultString = "";
if (result.output is not null)
{
resultString = StringFromUTF8((IntPtr)result.output);
}
Regorus.Internal.API.regorus_result_drop(result);
return resultString;
}
}
}

View File

@@ -0,0 +1,51 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Library</OutputType>
<RootNamespace>Microsoft.Regorus</RootNamespace>
<TargetFrameworks>netstandard2.0;netstandard2.1</TargetFrameworks>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<LangVersion>10.0</LangVersion>
<!-- See https://learn.microsoft.com/en-us/dotnet/core/tools/dotnet-pack -->
<VersionPrefix>0.5.0</VersionPrefix>
<VersionSuffix>$(VersionSuffix)</VersionSuffix>
<PackageReadmeFile>README.md</PackageReadmeFile>
</PropertyGroup>
<!--
$(RegorusFFIArtifactsDir) is the location where regorus shared libraries have been
built for various platforms and copied to. RegorusFFIArtifactsDir is passed in
by the publishing pipeline.
For each target triple, `Pack` expects the regorus ffi shared library
to be found in $(RegorusFFIArtifactsDir)/<target-triple>/release.
-->
<Target Name="ChecksRegorusFFIArtifactsDir" BeforeTargets="Pack">
<Error Text="RegorusFFIArtifactsDir must be supplied." Condition="$(RegorusFFIArtifactsDir) == ''" />
<!-- Ensure that the binaries for officially supported platforms exists. -->
<Error Text="$(RegorusFFIArtifactsDir)/x86_64-pc-windows-msvc/release/regorus_ffi.dll missing."
Condition="!Exists('$(RegorusFFIArtifactsDir)/x86_64-pc-windows-msvc/release/regorus_ffi.dll')" />
<Error Text="$(RegorusFFIArtifactsDir)/x86_64-pc-windows-msvc/release/regorus_ffi.pdb missing."
Condition="!Exists('$(RegorusFFIArtifactsDir)/x86_64-pc-windows-msvc/release/regorus_ffi.pdb')" />
<Error Text="$(RegorusFFIArtifactsDir)/x86_64-unknown-linux-gnu/release/libregorus_ffi.so missing."
Condition="!Exists('$(RegorusFFIArtifactsDir)/x86_64-unknown-linux-gnu/release/libregorus_ffi.so')" />
</Target>
<ItemGroup>
<None Include="docs/README.md" Pack="true" PackagePath="/" />
<!-- Copy each binary to expected location within the package -->
<None Include="$(RegorusFFIArtifactsDir)/x86_64-pc-windows-msvc/release/*.dll" Pack="true" PackagePath="runtimes/win-x64/native/" />
<None Include="$(RegorusFFIArtifactsDir)/x86_64-pc-windows-msvc/release/*.pdb" Pack="true" PackagePath="runtimes/win-x64/native/" />
<None Include="$(RegorusFFIArtifactsDir)/aarch64-pc-windows-msvc/release/*.dll" Pack="true" PackagePath="runtimes/win-arm64/native/" />
<None Include="$(RegorusFFIArtifactsDir)/aarch64-pc-windows-msvc/release/*.pdb" Pack="true" PackagePath="runtimes/win-arm64/native/" />
<None Include="$(RegorusFFIArtifactsDir)/x86_64-unknown-linux-gnu/release/lib*.so" Pack="true" PackagePath="runtimes/linux-x64/native/" />
<None Include="$(RegorusFFIArtifactsDir)/aarch64-apple-darwin/release/lib*.dylib" Pack="true" PackagePath="runtimes/osx-arm64/native/" />
</ItemGroup>
</Project>

View File

@@ -0,0 +1,219 @@
// <auto-generated>
// This code is generated by csbindgen.
// DON'T CHANGE THIS DIRECTLY.
// </auto-generated>
#pragma warning disable CS8500
#pragma warning disable CS8981
using System;
using System.Runtime.InteropServices;
namespace Regorus.Internal
{
internal static unsafe partial class API
{
const string __DllName = "regorus_ffi";
/// <summary>
/// Drop a `RegorusResult`.
///
/// `output` and `error_message` strings are not valid after drop.
/// </summary>
[DllImport(__DllName, EntryPoint = "regorus_result_drop", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
internal static extern void regorus_result_drop(RegorusResult r);
/// <summary>
/// Construct a new Engine
///
/// See https://docs.rs/regorus/latest/regorus/struct.Engine.html
/// </summary>
[DllImport(__DllName, EntryPoint = "regorus_engine_new", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
internal static extern RegorusEngine* regorus_engine_new();
/// <summary>
/// Clone a [`RegorusEngine`]
///
/// To avoid having to parse same policy again, the engine can be cloned
/// after policies and data have been added.
///
/// </summary>
[DllImport(__DllName, EntryPoint = "regorus_engine_clone", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
internal static extern RegorusEngine* regorus_engine_clone(RegorusEngine* engine);
[DllImport(__DllName, EntryPoint = "regorus_engine_drop", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
internal static extern void regorus_engine_drop(RegorusEngine* engine);
/// <summary>
/// Add a policy
///
/// The policy is parsed into AST.
/// See https://docs.rs/regorus/latest/regorus/struct.Engine.html#method.add_policy
///
/// * `path`: A filename to be associated with the policy.
/// * `rego`: Rego policy.
/// </summary>
[DllImport(__DllName, EntryPoint = "regorus_engine_add_policy", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
internal static extern RegorusResult regorus_engine_add_policy(RegorusEngine* engine, byte* path, byte* rego);
[DllImport(__DllName, EntryPoint = "regorus_engine_add_policy_from_file", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
internal static extern RegorusResult regorus_engine_add_policy_from_file(RegorusEngine* engine, byte* path);
/// <summary>
/// Add policy data.
///
/// See https://docs.rs/regorus/latest/regorus/struct.Engine.html#method.add_data
/// * `data`: JSON encoded value to be used as policy data.
/// </summary>
[DllImport(__DllName, EntryPoint = "regorus_engine_add_data_json", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
internal static extern RegorusResult regorus_engine_add_data_json(RegorusEngine* engine, byte* data);
/// <summary>
/// Get list of loaded Rego packages as JSON.
///
/// See https://docs.rs/regorus/latest/regorus/struct.Engine.html#method.get_packages
/// </summary>
[DllImport(__DllName, EntryPoint = "regorus_engine_get_packages", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
internal static extern RegorusResult regorus_engine_get_packages(RegorusEngine* engine);
/// <summary>
/// Get list of policies as JSON.
///
/// See https://docs.rs/regorus/latest/regorus/struct.Engine.html#method.get_policies
/// </summary>
[DllImport(__DllName, EntryPoint = "regorus_engine_get_policies", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
internal static extern RegorusResult regorus_engine_get_policies(RegorusEngine* engine);
[DllImport(__DllName, EntryPoint = "regorus_engine_add_data_from_json_file", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
internal static extern RegorusResult regorus_engine_add_data_from_json_file(RegorusEngine* engine, byte* path);
/// <summary>
/// Clear policy data.
///
/// See https://docs.rs/regorus/latest/regorus/struct.Engine.html#method.clear_data
/// </summary>
[DllImport(__DllName, EntryPoint = "regorus_engine_clear_data", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
internal static extern RegorusResult regorus_engine_clear_data(RegorusEngine* engine);
/// <summary>
/// Set input.
///
/// See https://docs.rs/regorus/latest/regorus/struct.Engine.html#method.set_input
/// * `input`: JSON encoded value to be used as input to query.
/// </summary>
[DllImport(__DllName, EntryPoint = "regorus_engine_set_input_json", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
internal static extern RegorusResult regorus_engine_set_input_json(RegorusEngine* engine, byte* input);
[DllImport(__DllName, EntryPoint = "regorus_engine_set_input_from_json_file", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
internal static extern RegorusResult regorus_engine_set_input_from_json_file(RegorusEngine* engine, byte* path);
/// <summary>
/// Evaluate query.
///
/// See https://docs.rs/regorus/latest/regorus/struct.Engine.html#method.eval_query
/// * `query`: Rego expression to be evaluate.
/// </summary>
[DllImport(__DllName, EntryPoint = "regorus_engine_eval_query", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
internal static extern RegorusResult regorus_engine_eval_query(RegorusEngine* engine, byte* query);
/// <summary>
/// Evaluate specified rule.
///
/// See https://docs.rs/regorus/latest/regorus/struct.Engine.html#method.eval_rule
/// * `rule`: Path to the rule.
/// </summary>
[DllImport(__DllName, EntryPoint = "regorus_engine_eval_rule", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
internal static extern RegorusResult regorus_engine_eval_rule(RegorusEngine* engine, byte* rule);
/// <summary>
/// Enable/disable coverage.
///
/// See https://docs.rs/regorus/latest/regorus/struct.Engine.html#method.set_enable_coverage
/// * `enable`: Whether to enable or disable coverage.
/// </summary>
[DllImport(__DllName, EntryPoint = "regorus_engine_set_enable_coverage", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
internal static extern RegorusResult regorus_engine_set_enable_coverage(RegorusEngine* engine, [MarshalAs(UnmanagedType.U1)] bool enable);
/// <summary>
/// Get coverage report.
///
/// See https://docs.rs/regorus/latest/regorus/struct.Engine.html#method.get_coverage_report
/// </summary>
[DllImport(__DllName, EntryPoint = "regorus_engine_get_coverage_report", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
internal static extern RegorusResult regorus_engine_get_coverage_report(RegorusEngine* engine);
/// <summary>
/// Get pretty printed coverage report.
///
/// See https://docs.rs/regorus/latest/regorus/coverage/struct.Report.html#method.to_string_pretty
/// </summary>
[DllImport(__DllName, EntryPoint = "regorus_engine_get_coverage_report_pretty", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
internal static extern RegorusResult regorus_engine_get_coverage_report_pretty(RegorusEngine* engine);
/// <summary>
/// Clear coverage data.
///
/// See https://docs.rs/regorus/latest/regorus/struct.Engine.html#method.clear_coverage_data
/// </summary>
[DllImport(__DllName, EntryPoint = "regorus_engine_clear_coverage_data", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
internal static extern RegorusResult regorus_engine_clear_coverage_data(RegorusEngine* engine);
/// <summary>
/// Whether to gather output of print statements.
///
/// See https://docs.rs/regorus/latest/regorus/struct.Engine.html#method.set_gather_prints
/// * `enable`: Whether to enable or disable gathering print statements.
/// </summary>
[DllImport(__DllName, EntryPoint = "regorus_engine_set_gather_prints", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
internal static extern RegorusResult regorus_engine_set_gather_prints(RegorusEngine* engine, [MarshalAs(UnmanagedType.U1)] bool enable);
/// <summary>
/// Take all the gathered print statements.
///
/// See https://docs.rs/regorus/latest/regorus/struct.Engine.html#method.take_prints
/// </summary>
[DllImport(__DllName, EntryPoint = "regorus_engine_take_prints", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
internal static extern RegorusResult regorus_engine_take_prints(RegorusEngine* engine);
/// <summary>
/// Get AST of policies.
///
/// See https://docs.rs/regorus/latest/regorus/coverage/struct.Engine.html#method.get_ast_as_json
/// </summary>
[DllImport(__DllName, EntryPoint = "regorus_engine_get_ast_as_json", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
internal static extern RegorusResult regorus_engine_get_ast_as_json(RegorusEngine* engine);
/// <summary>
/// Enable/disable rego v1.
///
/// See https://docs.rs/regorus/latest/regorus/struct.Engine.html#method.set_rego_v0
/// </summary>
[DllImport(__DllName, EntryPoint = "regorus_engine_set_rego_v0", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
internal static extern RegorusResult regorus_engine_set_rego_v0(RegorusEngine* engine, [MarshalAs(UnmanagedType.U1)] bool enable);
}
[StructLayout(LayoutKind.Sequential)]
internal unsafe partial struct RegorusResult
{
public RegorusStatus status;
public byte* output;
public byte* error_message;
}
[StructLayout(LayoutKind.Sequential)]
internal unsafe partial struct RegorusEngine
{
}
internal enum RegorusStatus : uint
{
RegorusStatusOk,
RegorusStatusError,
}
}

View File

@@ -0,0 +1 @@
C# Bindings for Regorus

View File

@@ -1,68 +1,82 @@
//-----------------------------------------------------------------------
// <copyright file="Program.cs" company="Microsoft">
// Copyright (c)2012 Microsoft. All rights reserved.
// </copyright>
// <summary>
// Contains code to test the Regorus class for C#
// and .NET 8.0 bindings.
// </summary>
//-----------------------------------------------------------------------
using System.Diagnostics;
long nanosecPerTick = (1000L*1000L*1000L) / Stopwatch.Frequency;
var w = new Stopwatch();
// Force load of modules.
{
var _e = new Regorus.Engine();
var _j = System.Text.Json.JsonDocument.Parse("{}");
}
w.Restart();
var engine = new Regorus.Engine();
w.Stop();
var newEngineTicks = w.ElapsedTicks;
w.Restart();
// Load policies and data.
engine.AddPolicyFromFile("../../../tests/aci/framework.rego");
engine.AddPolicyFromFile("../../../tests/aci/api.rego");
engine.AddPolicyFromFile("../../../tests/aci/policy.rego");
engine.AddDataFromJsonFile("../../../tests/aci/data.json");
w.Stop();
var loadPoliciesTicks = w.ElapsedTicks;
w.Restart();
// Set input and eval rule.
engine.SetInputFromJsonFile("../../../tests/aci/input.json");
var value = engine.EvalQuery("data.framework.mount_overlay");
var valueDoc = System.Text.Json.JsonDocument.Parse(value);
w.Stop();
var evalTicks = w.ElapsedTicks;
Console.WriteLine("{0}", valueDoc);
Console.WriteLine("Engine creation took {0} msecs", (newEngineTicks*nanosecPerTick)/(1000.0*1000.0));
Console.WriteLine("Load policies and data took {0} msecs", (loadPoliciesTicks*nanosecPerTick)/(1000.0*1000.0));
Console.WriteLine("EvalQuery took {0} msecs", (evalTicks*nanosecPerTick)/(1000.0*1000.0));
engine = new Regorus.Engine();
engine.AddPolicy(
"test.rego",
"package test\nx = 1\nmessage = `Hello`");
engine.SetEnableCoverage(true);
Console.WriteLine("{0}", engine.EvalRule("data.test.message"));
Console.WriteLine("{0}", engine.GetCoverageReportPretty());
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
using System.Diagnostics;
long nanosecPerTick = (1000L * 1000L * 1000L) / Stopwatch.Frequency;
var w = new Stopwatch();
// Force load of modules.
{
var _e = new Regorus.Engine();
#if NET8_0_OR_GREATER
var _j = System.Text.Json.JsonDocument.Parse("{}");
#endif
}
w.Restart();
var engine = new Regorus.Engine();
engine.SetRegoV0(true);
w.Stop();
var newEngineTicks = w.ElapsedTicks;
w.Restart();
// Load policies and data.
engine.AddPolicyFromFile("../../../tests/aci/framework.rego");
engine.AddPolicyFromFile("../../../tests/aci/api.rego");
engine.AddPolicyFromFile("../../../tests/aci/policy.rego");
engine.AddDataFromJsonFile("../../../tests/aci/data.json");
w.Stop();
var loadPoliciesTicks = w.ElapsedTicks;
w.Restart();
// Set input and eval rule.
engine.SetInputFromJsonFile("../../../tests/aci/input.json");
var value = engine.EvalRule("data.framework.mount_overlay");
#if NET8_0_OR_GREATER
var valueDoc = System.Text.Json.JsonDocument.Parse(value);
w.Stop();
var evalTicks = w.ElapsedTicks;
Console.WriteLine("{0}", valueDoc);
#else
w.Stop();
var evalTicks = w.ElapsedTicks;
#endif
Console.WriteLine("Engine creation took {0} msecs", (newEngineTicks * nanosecPerTick) / (1000.0 * 1000.0));
Console.WriteLine("Load policies and data took {0} msecs", (loadPoliciesTicks * nanosecPerTick) / (1000.0 * 1000.0));
Console.WriteLine("EvalRule took {0} msecs", (evalTicks * nanosecPerTick) / (1000.0 * 1000.0));
engine = new Regorus.Engine();
engine.AddPolicy(
"test.rego",
"package test\nx = 1\nmessage = `Hello`");
engine.SetEnableCoverage(true);
Console.WriteLine("data.test.message: {0}", engine.EvalRule("data.test.message"));
Console.WriteLine("Coverage Report:\n{0}", engine.GetCoverageReportPretty());
if (engine.EvalRule("data.test.message") != "\"Hello\"")
{
Console.WriteLine("Failure.");
System.Environment.Exit(1);
}
else
{
Console.WriteLine("Success.");
}

View File

@@ -0,0 +1,16 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFrameworks>net8.0</TargetFrameworks>
<RootNamespace>TestApp</RootNamespace>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<LangVersion>10.0</LangVersion>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="regorus" Version="0.5.0"/>
</ItemGroup>
</Project>

View File

@@ -0,0 +1,10 @@
{
"msbuild-sdks": {
"Microsoft.Build.NoTargets": "3.7.56"
},
"sdk": {
"allowPrerelease": false,
"version": "8.0.408",
"rollForward": "disable"
}
}

View File

@@ -1,65 +0,0 @@
//-----------------------------------------------------------------------
// <copyright file="Program.cs" company="Microsoft">
// Copyright (c)2012 Microsoft. All rights reserved.
// </copyright>
// <summary>
// Contains code to test the Regorus Policy Engine base class for C#
// and .NET4.0 bindings. It can be built and tested in Windows only.
// </summary>
//-----------------------------------------------------------------------
using System;
using System.Text;
using System.Diagnostics;
using Microsoft.WindowsAzure.Regorus.IaaS;
namespace regoregorus_test
{
class Program
{
static void Main(string[] args)
{
long nanosecPerTick = (1000L * 1000L * 1000L) / Stopwatch.Frequency;
var w = new Stopwatch();
w.Restart();
var engine = new RegorusPolicyEngine();
w.Stop();
var newEngineTicks = w.ElapsedTicks;
w.Restart();
// Load policies and data.
engine.AddPolicyFromFile("../../../examples/extension_list/agent_extension_policy.rego");
engine.AddDataFromJsonFile("../../../examples/extension_list/agent-extension-data-allow-only.json");
w.Stop();
var loadPoliciesTicks = w.ElapsedTicks;
w.Restart();
// Set input and eval query.
engine.SetInputFromJsonFile("../../../examples/extension_list/agent-extension-input.json");
var results = engine.EvalQuery("data.agent_extension_policy.extensions_to_download=x");
Console.WriteLine("Download query test: \n {0}", results);
results = engine.EvalQuery("data.agent_extension_policy.extensions_validated");
Console.WriteLine("Signing validation test: \n {0}", results);
engine.Dispose();
w.Stop();
var evalTicks = w.ElapsedTicks;
Console.WriteLine("Engine creation took {0} msecs", (newEngineTicks * nanosecPerTick) / (1000.0 * 1000.0));
Console.WriteLine("Load policies and data took {0} msecs", (loadPoliciesTicks * nanosecPerTick) / (1000.0 * 1000.0));
Console.WriteLine("EvalQuery and print results took {0} msecs", (evalTicks * nanosecPerTick) / (1000.0 * 1000.0));
}
}
}

View File

@@ -1,4 +0,0 @@
The Regorus C# binding library can be built via command "dotnet build". We can use the Regorus C# binding library built from this
directory to create a Nuget. This Nuget will contain the Regorus C# binding library with definitions that
work for .NET framework 4.0 (net40) and above. Note the Nuget can only be created after the binding library has been built.
RegorusCsharp-Lib-x64.nuspec is built for x64 architecture.

View File

@@ -1,203 +0,0 @@
//-----------------------------------------------------------------------
// <copyright file="Regorus.cs" company="Microsoft">
// Copyright (c)2012 Microsoft. All rights reserved.
// </copyright>
// <summary>
// Contains code for the Regorus Policy Engine base class for C# and
// .NET4.0 bindings. Currently this base class is not thread-safe. Make
// sure we use it in a signle-threaded environment or add additional
// protection when using it.
// </summary>
//-----------------------------------------------------------------------
using System;
using System.Text;
using System.IO;
using System.Threading;
namespace Microsoft.WindowsAzure.Regorus.IaaS
{
public class RegorusPolicyEngine : ICloneable, IDisposable
{
unsafe private RegorusFFI.RegorusEngine* E;
public RegorusPolicyEngine()
{
unsafe
{
E = RegorusFFI.API.regorus_engine_new();
}
}
public void Dispose()
{
unsafe
{
if (E != null)
{
RegorusFFI.API.regorus_engine_drop(E);
// to avoid Dispose() being called multiple times by mistake.
E = null;
}
}
}
public object Clone()
{
var clone = (RegorusPolicyEngine)this.MemberwiseClone();
unsafe
{
clone.E = RegorusFFI.API.regorus_engine_clone(E);
}
return clone;
}
public void AddPolicy(string path, string rego)
{
var pathBytes = Encoding.UTF8.GetBytes(path);
var regoBytes = Encoding.UTF8.GetBytes(rego);
unsafe
{
fixed (byte* pathPtr = pathBytes)
{
fixed(byte* regoPtr = regoBytes)
{
CheckAndDropResult(RegorusFFI.API.regorus_engine_add_policy(E, pathPtr, regoPtr));
}
}
}
}
public void AddPolicyFromFile(string path)
{
var pathBytes = Encoding.UTF8.GetBytes(path);
unsafe
{
fixed (byte* pathPtr = pathBytes)
{
CheckAndDropResult(RegorusFFI.API.regorus_engine_add_policy_from_file(E, pathPtr));
}
}
}
public void AddPolicyFromPath(string path)
{
if (!Directory.Exists(path))
{
return;
}
string[] regoFiles = Directory.GetFiles(path, "*.rego", SearchOption.AllDirectories);
foreach (string file in regoFiles)
{
AddPolicyFromFile(file);
}
}
public void AddDataJson(string data)
{
var dataBytes = Encoding.UTF8.GetBytes(data);
unsafe
{
fixed (byte* dataPtr = dataBytes)
{
CheckAndDropResult(RegorusFFI.API.regorus_engine_add_data_json(E, dataPtr));
}
}
}
public void AddDataFromJsonFile(string path)
{
var pathBytes = Encoding.UTF8.GetBytes(path);
unsafe
{
fixed (byte* pathPtr = pathBytes)
{
CheckAndDropResult(RegorusFFI.API.regorus_engine_add_data_from_json_file(E, pathPtr));
}
}
}
public void SetInputJson(string input)
{
var inputBytes = Encoding.UTF8.GetBytes(input);
unsafe
{
fixed (byte* inputPtr = inputBytes)
{
CheckAndDropResult(RegorusFFI.API.regorus_engine_set_input_json(E, inputPtr));
}
}
}
public void SetInputFromJsonFile(string path)
{
var pathBytes = Encoding.UTF8.GetBytes(path);
unsafe
{
fixed (byte* pathPtr = pathBytes)
{
CheckAndDropResult(RegorusFFI.API.regorus_engine_set_input_from_json_file(E, pathPtr));
}
}
}
public string EvalQuery(string query)
{
var queryBytes = Encoding.UTF8.GetBytes(query);
var resultJson = "";
unsafe
{
fixed (byte* queryPtr = queryBytes)
{
var result = RegorusFFI.API.regorus_engine_eval_query(E, queryPtr);
if (result.status == RegorusFFI.RegorusStatus.RegorusStatusOk) {
if (result.output != null) {
resultJson = System.Runtime.InteropServices.Marshal.PtrToStringAnsi((IntPtr)result.output);
}
RegorusFFI.API.regorus_result_drop(result);
} else {
CheckAndDropResult(result);
}
}
}
if (resultJson != null) {
return resultJson;
} else {
return "";
}
}
void CheckAndDropResult(RegorusFFI.RegorusResult result)
{
if (result.status != RegorusFFI.RegorusStatus.RegorusStatusOk) {
unsafe {
var message = System.Runtime.InteropServices.Marshal.PtrToStringAnsi((IntPtr)result.error_message);
var ex = new Exception(message);
RegorusFFI.API.regorus_result_drop(result);
throw ex;
}
}
RegorusFFI.API.regorus_result_drop(result);
}
}
}

View File

@@ -1,22 +0,0 @@
<?xml version="1.0" encoding="utf-8" ?>
<package>
<metadata>
<id>RegorusCsharp-Lib-x64</id>
<version>0.2.1</version>
<title>RegorusCsharp-Lib-x64</title>
<authors>yangjie@microsoft.com</authors>
<owners>yangjie@microsoft.com</owners>
<projectUrl>https://www.microsoft.com</projectUrl>
<requireLicenseAcceptance>false</requireLicenseAcceptance>
<description>Regorus C# library for x64</description>
<releaseNotes>remove Regorus.cs from Nuget</releaseNotes>
<copyright>Copyright (C) Microsoft Corp</copyright>
<summary></summary>
</metadata>
<files>
<file src="RegorusFFI.g.cs" target="RegorusFFI.g.cs"/>
<file src="regorus_ffi.dll" target="lib\regorusc.dll" />
<file src="README" target="README" />
<file src="..\..\..\LICENSE" target="LICENSE" />
</files>
</package>

View File

@@ -1,24 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk" InitialTargets="BuildRegorusFFI">
<Target Name="BuildRegorusFFI">
<Exec Command="cargo build -r --manifest-path ../../ffi/Cargo.toml" />
<Copy SourceFiles="../../ffi/RegorusFFI.g.cs" DestinationFolder="." />
<ItemGroup>
<RegorusDylib Include="..\..\..\target\release\*regorus_ffi*" />
</ItemGroup>
<Copy SourceFiles="@(RegorusDylib)" DestinationFolder="." />
</Target>
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net40</TargetFramework>
<RootNamespace>regorus_test</RootNamespace>
<StartupObject>regoregorus_test.Program</StartupObject>
<ImplicitUsings>enable</ImplicitUsings>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
</PropertyGroup>
</Project>

View File

@@ -1,220 +0,0 @@
using System.Text;
namespace Regorus
{
public class Exception : System.Exception
{
public Exception(string? message) : base(message) {}
}
public class Engine : ICloneable
{
unsafe private RegorusFFI.RegorusEngine* E;
public Engine()
{
unsafe
{
E = RegorusFFI.API.regorus_engine_new();
}
}
public object Clone()
{
var clone = (Engine)this.MemberwiseClone();
unsafe
{
clone.E = RegorusFFI.API.regorus_engine_clone(E);
}
return clone;
}
public string AddPolicy(string path, string rego)
{
var pathBytes = Encoding.UTF8.GetBytes(path);
var regoBytes = Encoding.UTF8.GetBytes(rego);
unsafe
{
fixed (byte* pathPtr = pathBytes)
{
fixed(byte* regoPtr = regoBytes)
{
return CheckAndDropResult(RegorusFFI.API.regorus_engine_add_policy(E, pathPtr, regoPtr));
}
}
}
}
public string AddPolicyFromFile(string path)
{
var pathBytes = Encoding.UTF8.GetBytes(path);
unsafe
{
fixed (byte* pathPtr = pathBytes)
{
return CheckAndDropResult(RegorusFFI.API.regorus_engine_add_policy_from_file(E, pathPtr));
}
}
}
public void AddDataJson(string data)
{
var dataBytes = Encoding.UTF8.GetBytes(data);
unsafe
{
fixed (byte* dataPtr = dataBytes)
{
CheckAndDropResult(RegorusFFI.API.regorus_engine_add_data_json(E, dataPtr));
}
}
}
public void AddDataFromJsonFile(string path)
{
var pathBytes = Encoding.UTF8.GetBytes(path);
unsafe
{
fixed (byte* pathPtr = pathBytes)
{
CheckAndDropResult(RegorusFFI.API.regorus_engine_add_data_from_json_file(E, pathPtr));
}
}
}
public void SetInputJson(string input)
{
var inputBytes = Encoding.UTF8.GetBytes(input);
unsafe
{
fixed (byte* inputPtr = inputBytes)
{
CheckAndDropResult(RegorusFFI.API.regorus_engine_set_input_json(E, inputPtr));
}
}
}
public void SetInputFromJsonFile(string path)
{
var pathBytes = Encoding.UTF8.GetBytes(path);
unsafe
{
fixed (byte* pathPtr = pathBytes)
{
CheckAndDropResult(RegorusFFI.API.regorus_engine_set_input_from_json_file(E, pathPtr));
}
}
}
public string EvalQuery(string query)
{
var queryBytes = Encoding.UTF8.GetBytes(query);
unsafe
{
fixed (byte* queryPtr = queryBytes)
{
return CheckAndDropResult(RegorusFFI.API.regorus_engine_eval_query(E, queryPtr));
}
}
}
public string EvalRule(string rule)
{
var ruleBytes = Encoding.UTF8.GetBytes(rule);
unsafe
{
fixed (byte* rulePtr = ruleBytes)
{
return CheckAndDropResult(RegorusFFI.API.regorus_engine_eval_query(E, rulePtr));
}
}
}
public void SetEnableCoverage(bool enable)
{
unsafe
{
CheckAndDropResult(RegorusFFI.API.regorus_engine_set_enable_coverage(E, enable));
}
}
public void ClearCoverageData()
{
unsafe
{
CheckAndDropResult(RegorusFFI.API.regorus_engine_clear_coverage_data(E));
}
}
public string GetCoverageReport()
{
unsafe
{
return CheckAndDropResult(RegorusFFI.API.regorus_engine_get_coverage_report(E));
}
}
public string GetCoverageReportPretty()
{
unsafe
{
return CheckAndDropResult(RegorusFFI.API.regorus_engine_get_coverage_report_pretty(E));
}
}
public void SetGatherPrints(bool enable)
{
unsafe
{
CheckAndDropResult(RegorusFFI.API.regorus_engine_set_gather_prints(E, enable));
}
}
public string TakePrints()
{
unsafe
{
return CheckAndDropResult(RegorusFFI.API.regorus_engine_take_prints(E));
}
}
~Engine()
{
unsafe
{
RegorusFFI.API.regorus_engine_drop(E);
}
}
string CheckAndDropResult(RegorusFFI.RegorusResult result)
{
if (result.status != RegorusFFI.RegorusStatus.RegorusStatusOk) {
unsafe {
var message = System.Runtime.InteropServices.Marshal.PtrToStringUTF8((IntPtr)result.error_message);
var ex = new Exception(message);
RegorusFFI.API.regorus_result_drop(result);
throw ex;
}
}
var resultString = "";
unsafe
{
if (result.output is not null) {
resultString = System.Runtime.InteropServices.Marshal.PtrToStringUTF8((IntPtr)result.output);
}
RegorusFFI.API.regorus_result_drop(result);
}
return resultString;
}
}
}

View File

@@ -1,24 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk" InitialTargets="BuildRegorusFFI">
<Target Name="BuildRegorusFFI">
<Exec Command="cargo build -r --manifest-path ../../ffi/Cargo.toml" />
<Copy SourceFiles="../../ffi/RegorusFFI.g.cs" DestinationFolder="." />
<ItemGroup>
<RegorusDylib Include="..\..\..\target\release\*regorus_ffi*" />
</ItemGroup>
<Copy SourceFiles="@(RegorusDylib)" DestinationFolder="." />
</Target>
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net8.0</TargetFramework>
<RootNamespace>regorus_test</RootNamespace>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
</PropertyGroup>
</Project>

1771
bindings/ffi/Cargo.lock generated Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -1,3 +1,5 @@
[workspace]
[package]
name = "regorus-ffi"
version = "0.2.2"
@@ -10,7 +12,7 @@ crate-type = ["cdylib", "staticlib"]
[dependencies]
anyhow = "1.0"
regorus = { path = "../..", default-features = false }
serde_json = "1.0.113"
serde_json = "1.0.140"
[features]
default = ["ast", "std", "coverage", "regorus/arc", "regorus/full-opa"]
@@ -20,5 +22,5 @@ coverage = ["regorus/coverage"]
custom_allocator = []
[build-dependencies]
cbindgen = "0.27.0"
cbindgen = "0.28.0"
csbindgen = "=1.9.3"

View File

@@ -26,7 +26,7 @@ fn main() {
.input_extern_file("src/lib.rs")
.csharp_dll_name("regorus_ffi")
.csharp_class_name("API")
.csharp_namespace("RegorusFFI")
.csharp_namespace("Regorus.Internal")
.generate_csharp_file("./RegorusFFI.g.cs")
.unwrap();
}

View File

@@ -222,7 +222,7 @@ pub extern "C" fn regorus_engine_add_data_from_json_file(
/// Clear policy data.
///
/// See https://docs.rs/regorus/0.1.0-alpha.2/regorus/struct.Engine.html#method.clear_data
/// See https://docs.rs/regorus/latest/regorus/struct.Engine.html#method.clear_data
#[no_mangle]
pub extern "C" fn regorus_engine_clear_data(engine: *mut RegorusEngine) -> RegorusResult {
to_regorus_result(|| -> Result<()> {
@@ -233,7 +233,7 @@ pub extern "C" fn regorus_engine_clear_data(engine: *mut RegorusEngine) -> Regor
/// Set input.
///
/// See https://docs.rs/regorus/0.1.0-alpha.2/regorus/struct.Engine.html#method.set_input
/// See https://docs.rs/regorus/latest/regorus/struct.Engine.html#method.set_input
/// * `input`: JSON encoded value to be used as input to query.
#[no_mangle]
pub extern "C" fn regorus_engine_set_input_json(
@@ -264,7 +264,7 @@ pub extern "C" fn regorus_engine_set_input_from_json_file(
/// Evaluate query.
///
/// See https://docs.rs/regorus/0.1.0-alpha.2/regorus/struct.Engine.html#method.eval_query
/// See https://docs.rs/regorus/latest/regorus/struct.Engine.html#method.eval_query
/// * `query`: Rego expression to be evaluate.
#[no_mangle]
pub extern "C" fn regorus_engine_eval_query(
@@ -289,7 +289,7 @@ pub extern "C" fn regorus_engine_eval_query(
/// Evaluate specified rule.
///
/// See https://docs.rs/regorus/0.1.0-alpha.2/regorus/struct.Engine.html#method.eval_rule
/// See https://docs.rs/regorus/latest/regorus/struct.Engine.html#method.eval_rule
/// * `rule`: Path to the rule.
#[no_mangle]
pub extern "C" fn regorus_engine_eval_rule(
@@ -314,7 +314,7 @@ pub extern "C" fn regorus_engine_eval_rule(
/// Enable/disable coverage.
///
/// See https://docs.rs/regorus/0.1.0-alpha.2/regorus/struct.Engine.html#method.set_enable_coverage
/// See https://docs.rs/regorus/latest/regorus/struct.Engine.html#method.set_enable_coverage
/// * `enable`: Whether to enable or disable coverage.
#[no_mangle]
#[cfg(feature = "coverage")]
@@ -330,7 +330,7 @@ pub extern "C" fn regorus_engine_set_enable_coverage(
/// Get coverage report.
///
/// See https://docs.rs/regorus/0.1.0-alpha.2/regorus/struct.Engine.html#method.get_coverage_report
/// See https://docs.rs/regorus/latest/regorus/struct.Engine.html#method.get_coverage_report
#[no_mangle]
#[cfg(feature = "coverage")]
pub extern "C" fn regorus_engine_get_coverage_report(engine: *mut RegorusEngine) -> RegorusResult {
@@ -375,7 +375,7 @@ pub extern "C" fn regorus_engine_get_coverage_report_pretty(
/// Clear coverage data.
///
/// See https://docs.rs/regorus/0.1.0-alpha.2/regorus/struct.Engine.html#method.clear_coverage_data
/// See https://docs.rs/regorus/latest/regorus/struct.Engine.html#method.clear_coverage_data
#[no_mangle]
#[cfg(feature = "coverage")]
pub extern "C" fn regorus_engine_clear_coverage_data(engine: *mut RegorusEngine) -> RegorusResult {
@@ -387,7 +387,7 @@ pub extern "C" fn regorus_engine_clear_coverage_data(engine: *mut RegorusEngine)
/// Whether to gather output of print statements.
///
/// See https://docs.rs/regorus/0.1.0-alpha.2/regorus/struct.Engine.html#method.set_gather_prints
/// See https://docs.rs/regorus/latest/regorus/struct.Engine.html#method.set_gather_prints
/// * `enable`: Whether to enable or disable gathering print statements.
#[no_mangle]
pub extern "C" fn regorus_engine_set_gather_prints(
@@ -402,7 +402,7 @@ pub extern "C" fn regorus_engine_set_gather_prints(
/// Take all the gathered print statements.
///
/// See https://docs.rs/regorus/0.1.0-alpha.2/regorus/struct.Engine.html#method.take_prints
/// See https://docs.rs/regorus/latest/regorus/struct.Engine.html#method.take_prints
#[no_mangle]
pub extern "C" fn regorus_engine_take_prints(engine: *mut RegorusEngine) -> RegorusResult {
let output = || -> Result<String> {
@@ -437,6 +437,28 @@ pub extern "C" fn regorus_engine_get_ast_as_json(engine: *mut RegorusEngine) ->
}
}
/// Enable/disable rego v1.
///
/// See https://docs.rs/regorus/latest/regorus/struct.Engine.html#method.set_rego_v0
#[no_mangle]
pub extern "C" fn regorus_engine_set_rego_v0(
engine: *mut RegorusEngine,
enable: bool,
) -> RegorusResult {
let output = || -> Result<()> {
to_ref(&engine)?.engine.set_rego_v0(enable);
Ok(())
}();
match output {
Ok(()) => RegorusResult {
status: RegorusStatus::RegorusStatusOk,
output: std::ptr::null_mut(),
error_message: std::ptr::null_mut(),
},
Err(e) => to_regorus_result(Err(e)),
}
}
#[cfg(feature = "custom_allocator")]
extern "C" {
fn regorus_aligned_alloc(alignment: usize, size: usize) -> *mut u8;

View File

@@ -16,8 +16,11 @@ func main() {
// Create new engine
engine := regorus.NewEngine()
defer engine.Close()
elapsed1 := time.Since(t)
engine.SetRegoV0(true)
elapsed1 := time.Since(t)
t = time.Now()
// Add policies and data.
policies := []string{

View File

@@ -1,6 +1,6 @@
package regorus
// #cgo LDFLAGS: -L ../../../../target/release -lregorus_ffi
// #cgo LDFLAGS: -L ../../../ffi/target/release -lregorus_ffi
// #include "../../../ffi/regorus.h"
import "C"
import (
@@ -28,6 +28,17 @@ func (e *Engine) Clone() *Engine {
return c
}
func (e *Engine) SetRegoV0(enable bool) error {
result := C.regorus_engine_set_rego_v0(e.e, C.bool(enable))
defer C.regorus_result_drop(result)
if result.status != C.RegorusStatusOk {
return fmt.Errorf("%s", C.GoString(result.error_message))
}
return nil
}
func (e *Engine) AddPolicy(path string, rego string) (string, error) {
path_c := C.CString(path)
defer C.free(unsafe.Pointer(path_c))
@@ -73,7 +84,6 @@ func (e *Engine) GetPolicies() (string, error) {
return C.GoString(result.output), nil
}
func (e *Engine) AddDataJson(data string) error {
data_c := C.CString(data)
defer C.free(unsafe.Pointer(data_c))

1692
bindings/java/Cargo.lock generated Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -1,6 +1,8 @@
[workspace]
[package]
name = "regorus-java"
version = "0.2.2"
version = "0.3.0"
edition = "2021"
repository = "https://github.com/microsoft/regorus/bindings/java"
description = "Java bindings for Regorus - a fast, lightweight Rego interpreter written in Rust"

View File

@@ -23,7 +23,7 @@ Afterwards, you can build native library for that target using:
$ cargo build --release --target aarch64-apple-darwin
```
You will then have a native library at `../../target/aarch64-apple-darwin/release/libregorus_java.dylib` depending on your target.
You will then have a native library at `target/aarch64-apple-darwin/release/libregorus_java.dylib` depending on your target.
You then need to build Java bindings using:
```bash

View File

@@ -4,39 +4,45 @@
import com.microsoft.regorus.Engine;
public class Test {
public static void main(String[] args) {
try (Engine engine = new Engine()) {
String pkg = engine.addPolicy(
"hello.rego",
"package test\nx=1\nmessage = concat(\", \", [input.message, data.message])"
"hello.rego",
"package test\nx=1\nmessage = concat(\", \", [input.message, data.message])"
);
System.out.println("Loaded package " + pkg);
System.out.println("Loaded package " + pkg);
engine.addDataJson("{\"message\":\"World!\"}");
engine.setInputJson("{\"message\":\"Hello\"}");
// Evaluate query.
String resJson = engine.evalQuery("data.test.message");
// Evaluate query.
String resJson = engine.evalQuery("data.test.message");
System.out.println(resJson);
// Enable coverage.
engine.setEnableCoverage(true);
// Enable coverage.
engine.setEnableCoverage(true);
// Evaluate rule.
String valueJson = engine.evalRule("data.test.message");
// Evaluate rule.
String valueJson = engine.evalRule("data.test.message");
System.out.println(valueJson);
String coverageJson = engine.getCoverageReport();
System.out.println(coverageJson);
String coverageJson = engine.getCoverageReport();
System.out.println(coverageJson);
System.out.println(engine.getCoverageReportPretty());
System.out.println(engine.getCoverageReportPretty());
String packagesJson = engine.getPackages();
System.out.println(packagesJson);
String packagesJson = engine.getPackages();
System.out.println(packagesJson);
String policiesJson = engine.getPolicies();
System.out.println(policiesJson);
String policiesJson = engine.getPolicies();
System.out.println(policiesJson);
engine.setRegoV0(true);
engine.addPolicy(
"world.rego",
"package world\nx { true }"
);
}
}
}

View File

@@ -28,6 +28,20 @@ pub extern "system" fn Java_com_microsoft_regorus_Engine_nativeClone(
Box::into_raw(Box::new(c)) as jlong
}
#[no_mangle]
pub extern "system" fn Java_com_microsoft_regorus_Engine_nativeSetRegoV0(
env: JNIEnv,
_class: JClass,
engine_ptr: jlong,
enable: bool,
) {
let _ = throw_err(env, |_env| {
let engine = unsafe { &mut *(engine_ptr as *mut Engine) };
engine.set_rego_v0(enable);
Ok(())
});
}
#[no_mangle]
pub extern "system" fn Java_com_microsoft_regorus_Engine_nativeAddPolicy(
env: JNIEnv,

View File

@@ -8,10 +8,8 @@ package com.microsoft.regorus;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.UncheckedIOException;
import java.nio.file.Files;
import java.nio.file.StandardCopyOption;
import java.util.concurrent.atomic.AtomicReference;
/**
* Regorus Engine.
@@ -23,6 +21,7 @@ public class Engine implements AutoCloseable, Cloneable {
// if you update the native API.
private static native long nativeNewEngine();
private static native long nativeClone(long enginePtr);
private static native void nativeSetRegoV0(long enginePtr, boolean enable);
private static native String nativeAddPolicy(long enginePtr, String path, String rego);
private static native String nativeAddPolicyFromFile(long enginePtr, String path);
private static native String nativeGetPackages(long enginePtr);
@@ -55,7 +54,7 @@ public class Engine implements AutoCloseable, Cloneable {
Engine(long ptr) {
enginePtr = ptr;
enginePtr = ptr;
}
/**
@@ -65,6 +64,16 @@ public class Engine implements AutoCloseable, Cloneable {
return new Engine(nativeClone(enginePtr));
}
/**
* Enable/disable Rego v0.
*
* @param enable Whether to enable v0 or not.
*
*/
public void setRegoV0(boolean enable) {
nativeSetRegoV0(enginePtr, enable);
}
/**
* Adds an inline Rego policy.
*

1672
bindings/python/Cargo.lock generated Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -1,6 +1,8 @@
[workspace]
[package]
name = "regoruspy"
version = "0.2.2"
version = "0.4.0"
edition = "2021"
repository = "https://github.com/microsoft/regorus/bindings/python"
description = "Python bindings for Regorus - a fast, lightweight Rego interpreter written in Rust"
@@ -18,8 +20,8 @@ coverage = ["regorus/coverage"]
[dependencies]
anyhow = "1.0"
ordered-float = "4.2.0"
pyo3 = {version = "0.22.0", features = ["anyhow", "extension-module"] }
ordered-float = "5.0.0"
pyo3 = { version = "0.24.1", features = ["abi3-py310", "anyhow", "extension-module"] }
regorus = { path = "../..", default-features = false, features = ["arc"] }
serde_json = "1.0.112"
serde_json = "1.0.140"

View File

@@ -13,4 +13,8 @@ classifiers = [
dynamic = ["version"]
[tool.maturin]
features = ["pyo3/extension-module"]
binding = ["cffi"]
# See https://github.com/mayeut/pep600_compliance?tab=readme-ov-file#distro-compatibility
# GLIBC releases: https://www.sourceware.org/glibc/wiki/Glibc%20Timeline
compatibility = "manylinux_2_34"
features = ["pyo3/extension-module"]

View File

@@ -4,6 +4,7 @@ use anyhow::{anyhow, Result};
use pyo3::exceptions::PyTypeError;
use pyo3::prelude::*;
use pyo3::types::*;
use pyo3::IntoPyObjectExt;
use std::collections::{BTreeMap, BTreeSet};
@@ -94,7 +95,7 @@ fn from(ob: &Bound<'_, PyAny>) -> Result<Value, PyErr> {
let mut map = BTreeMap::new();
let keys = pmap.keys()?;
let values = pmap.values()?;
for i in 0..keys.len()? {
for i in 0..keys.len() {
let key = keys.get_item(i)?;
let value = values.get_item(i)?;
map.insert(from(&key)?, from(&value)?);
@@ -108,49 +109,53 @@ fn from(ob: &Bound<'_, PyAny>) -> Result<Value, PyErr> {
}
fn to(mut v: Value, py: Python<'_>) -> Result<PyObject> {
Ok(match v {
Value::Null => None::<u64>.to_object(py),
let obj = match v {
Value::Null => None::<u64>.into_bound_py_any(py),
// TODO: Revisit this mapping
Value::Undefined => None::<u64>.to_object(py),
Value::Undefined => None::<u64>.into_bound_py_any(py),
Value::Bool(b) => b.to_object(py),
Value::String(s) => s.to_object(py),
Value::Bool(b) => b.into_bound_py_any(py),
Value::String(s) => s.into_bound_py_any(py),
Value::Number(_) => {
if let Ok(f) = v.as_f64() {
f.to_object(py)
f.into_bound_py_any(py)
} else if let Ok(u) = v.as_u64() {
u.to_object(py)
u.into_bound_py_any(py)
} else {
v.as_i64()?.to_object(py)
v.as_i64()?.into_bound_py_any(py)
}
}
Value::Array(_) => {
let list = PyList::empty_bound(py);
let list = PyList::empty(py);
for v in std::mem::take(v.as_array_mut()?) {
list.append(to(v, py)?)?;
}
list.into()
list.into_bound_py_any(py)
}
Value::Set(_) => {
let set = PySet::empty_bound(py)?;
let set = PySet::empty(py)?;
for v in std::mem::take(v.as_set_mut()?) {
set.add(to(v, py)?)?;
}
set.into()
set.into_bound_py_any(py)
}
Value::Object(_) => {
let dict = PyDict::new_bound(py);
let dict = PyDict::new(py);
for (k, v) in std::mem::take(v.as_object_mut()?) {
dict.set_item(to(k, py)?, to(v, py)?)?;
}
dict.into()
dict.into_bound_py_any(py)
}
})
};
match obj {
Ok(v) => Ok(v.into()),
Err(e) => Err(anyhow!("{e}")),
}
}
#[pymethods]
@@ -163,6 +168,15 @@ impl Engine {
}
}
/// Turn on rego v0.
///
/// Regorus now defaults to v1.
///
/// * `enable`: Whether to enable/disable v0.
pub fn set_rego_v0(&mut self, enable: bool) {
self.engine.set_rego_v0(enable)
}
/// Add a policy
///
/// The policy is parsed into AST.
@@ -261,30 +275,30 @@ impl Engine {
pub fn eval_query(&mut self, query: String, py: Python<'_>) -> Result<PyObject> {
let results = self.engine.eval_query(query, false)?;
let rlist = PyList::empty_bound(py);
let rlist = PyList::empty(py);
for result in results.result.into_iter() {
let rdict = PyDict::new_bound(py);
let rdict = PyDict::new(py);
let elist = PyList::empty_bound(py);
let elist = PyList::empty(py);
for expr in result.expressions.into_iter() {
let edict = PyDict::new_bound(py);
edict.set_item("value".to_object(py), to(expr.value, py)?)?;
edict.set_item("text".to_object(py), expr.text.as_ref().to_object(py))?;
let edict = PyDict::new(py);
edict.set_item("value", to(expr.value, py)?)?;
edict.set_item("text", expr.text.as_ref())?;
let ldict = PyDict::new_bound(py);
ldict.set_item("row".to_object(py), expr.location.row.to_object(py))?;
ldict.set_item("col".to_object(py), expr.location.col.to_object(py))?;
let ldict = PyDict::new(py);
ldict.set_item("row", expr.location.row)?;
ldict.set_item("col", expr.location.col)?;
edict.set_item("location".to_object(py), ldict)?;
edict.set_item("location", ldict)?;
elist.append(edict)?;
}
rdict.set_item("expressions".to_object(py), elist)?;
rdict.set_item("bindings".to_object(py), to(result.bindings, py)?)?;
rdict.set_item("expressions", elist)?;
rdict.set_item("bindings", to(result.bindings, py)?)?;
rlist.append(rdict)?;
}
let dict = PyDict::new_bound(py);
dict.set_item("result".to_object(py), rlist)?;
let dict = PyDict::new(py);
dict.set_item("result", rlist)?;
Ok(dict.into())
}

View File

@@ -6,6 +6,8 @@ import regorus
# Create engine
engine = regorus.Engine()
engine.set_rego_v0(True)
# Load policies
pkg = engine.add_policy_from_file('../../tests/aci/framework.rego')
print(' Loaded package %s' % pkg)

View File

@@ -3,7 +3,7 @@ require:
- rubocop-rake
AllCops:
TargetRubyVersion: 3.0
TargetRubyVersion: 3.4
NewCops: enable
Layout/LineLength:

View File

@@ -1 +1 @@
ruby 3.3.1
ruby 3.4.2

1706
bindings/ruby/Cargo.lock generated Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -7,10 +7,10 @@ gemspec
# These gems are required for local development and testing,
# but won't be included in the published gem
gem "minitest", "~> 5.23"
gem "minitest", "~> 5.25"
gem "rake", "~> 13.2"
gem "rake-compiler"
gem "rake-compiler-dock"
gem "rubocop", "~> 1.64", require: false
gem "rubocop-minitest", require: false
gem "rubocop-rake", require: false
gem "rake-compiler", "~> 1.2"
gem "rake-compiler-dock", "~> 1.9"
gem "rubocop", "~> 1.73", require: false
gem "rubocop-minitest", "~> 0.37.1", require: false
gem "rubocop-rake", "~> 0.7.1", require: false

View File

@@ -1,65 +1,68 @@
PATH
remote: .
specs:
regorusrb (0.2.1)
rb_sys (~> 0.9.97)
regorusrb (0.3.0)
rb_sys (~> 0.9.111)
GEM
remote: https://rubygems.org/
specs:
ast (2.4.2)
json (2.7.2)
language_server-protocol (3.17.0.3)
minitest (5.24.1)
parallel (1.25.1)
parser (3.3.4.0)
json (2.10.2)
language_server-protocol (3.17.0.4)
lint_roller (1.1.0)
minitest (5.25.4)
parallel (1.26.3)
parser (3.3.7.1)
ast (~> 2.4.1)
racc
racc (1.8.0)
racc (1.8.1)
rainbow (3.1.1)
rake (13.2.1)
rake-compiler (1.2.7)
rake-compiler (1.2.9)
rake
rake-compiler-dock (1.5.1)
rb_sys (0.9.99)
regexp_parser (2.9.2)
rexml (3.3.6)
strscan
rubocop (1.65.0)
rake-compiler-dock (1.9.1)
rb_sys (0.9.111)
rake-compiler-dock (= 1.9.1)
regexp_parser (2.10.0)
rubocop (1.73.2)
json (~> 2.3)
language_server-protocol (>= 3.17.0)
language_server-protocol (~> 3.17.0.2)
lint_roller (~> 1.1.0)
parallel (~> 1.10)
parser (>= 3.3.0.2)
rainbow (>= 2.2.2, < 4.0)
regexp_parser (>= 2.4, < 3.0)
rexml (>= 3.2.5, < 4.0)
rubocop-ast (>= 1.31.1, < 2.0)
regexp_parser (>= 2.9.3, < 3.0)
rubocop-ast (>= 1.38.0, < 2.0)
ruby-progressbar (~> 1.7)
unicode-display_width (>= 2.4.0, < 3.0)
rubocop-ast (1.31.3)
unicode-display_width (>= 2.4.0, < 4.0)
rubocop-ast (1.38.1)
parser (>= 3.3.1.0)
rubocop-minitest (0.35.1)
rubocop (>= 1.61, < 2.0)
rubocop-ast (>= 1.31.1, < 2.0)
rubocop-rake (0.6.0)
rubocop (~> 1.0)
rubocop-minitest (0.37.1)
lint_roller (~> 1.1)
rubocop (>= 1.72.1, < 2.0)
rubocop-ast (>= 1.38.0, < 2.0)
rubocop-rake (0.7.1)
lint_roller (~> 1.1)
rubocop (>= 1.72.1)
ruby-progressbar (1.13.0)
strscan (3.1.0)
unicode-display_width (2.5.0)
unicode-display_width (3.1.4)
unicode-emoji (~> 4.0, >= 4.0.4)
unicode-emoji (4.0.4)
PLATFORMS
ruby
x86_64-linux
DEPENDENCIES
minitest (~> 5.23)
minitest (~> 5.25)
rake (~> 13.2)
rake-compiler
rake-compiler-dock
rake-compiler (~> 1.2)
rake-compiler-dock (~> 1.9)
regorusrb!
rubocop (~> 1.64)
rubocop-minitest
rubocop-rake
rubocop (~> 1.73)
rubocop-minitest (~> 0.37.1)
rubocop-rake (~> 0.7.1)
BUNDLED WITH
2.5.13
2.6.5

View File

@@ -43,6 +43,9 @@ require "regorus"
engine = Regorus::Engine.new
# Policy is old-style.
engine.set_rego_v0(true)
engine.add_policy_from_file('../../tests/aci/framework.rego')
engine.add_policy_from_file('../../tests/aci/api.rego')
engine.add_policy_from_file('../../tests/aci/policy.rego')

View File

@@ -1,7 +1,7 @@
[package]
name = "regorusrb"
version = "0.2.2"
edition = "2021"
version = "0.3.0"
edition = "2024"
description = "Ruby bindings for Regorus - a fast, lightweight Rego interpreter written in Rust"
publish = false
@@ -15,7 +15,7 @@ ast = ["regorus/ast"]
coverage = ["regorus/coverage"]
[dependencies]
magnus = { version = "0.6.4" }
magnus = { version = "0.7.1" }
regorus = { path = "../../../..", default-features = false, features = ["arc"] }
serde_json = "1.0.117"
serde_magnus = "0.8.1"
serde_json = "1.0.140"
serde_magnus = "0.9.0"

View File

@@ -1,4 +1,4 @@
use magnus::{exception::runtime_error, method, module, prelude::*, Error, Ruby};
use magnus::{Error, Ruby, exception::runtime_error, method, module, prelude::*};
use regorus::Engine as RegorusEngine;
use std::cell::RefCell;
use std::cmp::Ordering;
@@ -36,6 +36,11 @@ impl Engine {
}
}
fn set_rego_v0(&self, enable: bool) -> Result<(), Error> {
self.engine.borrow_mut().set_rego_v0(enable);
Ok(())
}
fn add_policy(&self, path: String, rego: String) -> Result<String, Error> {
self.engine
.borrow_mut()
@@ -297,6 +302,9 @@ fn init(ruby: &Ruby) -> Result<(), Error> {
// defines <, <=, >, >=, and == based on <=>
engine_class.include_module(module::comparable())?;
// rego language configuration
engine_class.define_method("set_rego_v0", method!(Engine::set_rego_v0, 1))?;
// policy operations
engine_class.define_method("add_policy", method!(Engine::add_policy, 2))?;
engine_class.define_method(

View File

@@ -1,5 +1,5 @@
# frozen_string_literal: true
module Regorus
VERSION = "0.2.1"
VERSION = "0.3.0"
end

View File

@@ -10,8 +10,8 @@ Gem::Specification.new do |spec|
spec.summary = "Ruby bindings for Regorus - a fast, lightweight Rego interpreter written in Rust"
spec.homepage = "https://github.com/microsoft/regorus/blob/main/bindings/ruby"
spec.license = "MIT"
spec.required_ruby_version = ">= 3.0.0"
spec.required_rubygems_version = ">= 3.3.11"
spec.required_ruby_version = ">= 3.4.2"
spec.required_rubygems_version = ">= 3.6.5"
spec.metadata["allowed_push_host"] = "TODO: Set to your gem server 'https://example.com'"
@@ -26,5 +26,5 @@ Gem::Specification.new do |spec|
spec.executables = spec.files.grep(%r{\Aexe/}) { |f| File.basename(f) }
spec.require_paths = ["lib"]
spec.extensions = ["ext/regorusrb/extconf.rb"]
spec.add_dependency "rb_sys", "~> 0.9.97"
spec.add_dependency "rb_sys", "~> 0.9.111"
end

View File

@@ -17,11 +17,11 @@ class TestRegorus < Minitest::Test
def example_policy
<<~REGO
package regorus_test
is_manager {
is_manager if {
input.name == data.managers[_]
}
is_employee {
is_employee if {
input.name == data.employees[_]
}
@@ -29,11 +29,11 @@ class TestRegorus < Minitest::Test
default is_manager_bool = false
default is_employee_bool = false
is_manager_bool {
is_manager_bool if {
is_manager
}
is_employee_bool {
is_employee_bool if {
is_employee
}
REGO

View File

@@ -0,0 +1,2 @@
[target.wasm32-unknown-unknown]
rustflags = ["--cfg", "getrandom_backend=\"wasm_js\""]

1628
bindings/wasm/Cargo.lock generated Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -1,6 +1,8 @@
[workspace]
[package]
name = "regorusjs"
version = "0.2.2"
version = "0.3.0"
edition = "2021"
repository = "https://github.com/microsoft/regorus/bindings/wasm"
description = "WASM bindings for Regorus - a fast, lightweight Rego interpreter written in Rust"
@@ -17,8 +19,17 @@ coverage = ["regorus/coverage"]
[dependencies]
regorus = { path = "../..", default-features = false, features = ["arc"] }
serde_json = "1.0.111"
wasm-bindgen = "0.2.90"
serde_json = "1.0.140"
wasm-bindgen = "0.2.100"
# Specify uuid as a mandatory dependency so as to enable `js` feature which is now required
# when targeting wasm32-unknown-unknown.
uuid = { version = "1.15.1", default-features = false, features = ["v4", "fast-rng", "js"]}
# Enable wasm_js. See https://docs.rs/getrandom/latest/getrandom/#webassembly-support
getrandom_for_jsonschema = { package = "getrandom", version = "0.2.15", features = ["std", "js"] }
getrandom = { version = "0.3.1", features = ["std", "wasm_js"] }
[dev-dependencies]
wasm-bindgen-test = "0.3.40"
[lints.rust]
unexpected_cfgs = { level = "warn", check-cfg = ['cfg(wasm_bindgen_unstable_test_coverage)'] }

View File

@@ -45,6 +45,15 @@ impl Engine {
}
}
/// Turn on rego v0.
///
/// Regorus defaults to rego v1.
///
/// * `enable`: Whether to enable or disable rego v0.
pub fn setRegoV0(&mut self, enable: bool) {
self.engine.set_rego_v0(enable)
}
/// Add a policy
///
/// The policy is parsed into AST.
@@ -191,6 +200,7 @@ mod tests {
use wasm_bindgen_test::wasm_bindgen_test;
#[wasm_bindgen_test]
#[allow(dead_code)]
pub fn basic() -> Result<(), JsValue> {
let mut engine = crate::Engine::new();
engine.setEnableCoverage(true);

View File

@@ -61,9 +61,9 @@ in-expr ::= in-expr 'in' bool-expr
bool-expr ::= bool-expr bool-op or-expr
| or-expr
bool-op ::= '<' | '<=' | '==' | '>=' | '>' | '!='
or-expr ::= or-expr '|' and-expr
| and-expr
and-expr ::= and-expr '&' arith-expr
set-union-expr ::= set-union-expr '|' set-intersection-expr
| set-intersection-expr
set-intersection-expr ::= set-intersection-expr '&' arith-expr
| arith-expr
arith-expr ::= arith-expr ('+' | '-') mul-div-expr
| mul-div-expr

View File

@@ -42,7 +42,7 @@ fn rego_eval(
enable_tracing: bool,
non_strict: bool,
#[cfg(feature = "coverage")] coverage: bool,
v1: bool,
v0: bool,
) -> Result<()> {
// Create engine.
let mut engine = regorus::Engine::new();
@@ -52,7 +52,7 @@ fn rego_eval(
#[cfg(feature = "coverage")]
engine.set_enable_coverage(coverage);
engine.set_rego_v1(v1);
engine.set_rego_v0(v0);
// Load files from given bundles.
for dir in bundles.iter() {
@@ -238,9 +238,9 @@ enum RegorusCommand {
#[arg(long, short)]
coverage: bool,
/// Turn on rego.v1
/// Turn on Rego language v0.
#[arg(long)]
v1: bool,
v0: bool,
},
/// Tokenize a Rego policy.
@@ -282,7 +282,7 @@ fn main() -> Result<()> {
non_strict,
#[cfg(feature = "coverage")]
coverage,
v1,
v0,
} => rego_eval(
&bundles,
&data,
@@ -292,7 +292,7 @@ fn main() -> Result<()> {
non_strict,
#[cfg(feature = "coverage")]
coverage,
v1,
v0,
),
RegorusCommand::Lex { file, verbose } => rego_lex(file, verbose),
RegorusCommand::Parse { file } => rego_parse(file),

View File

@@ -2,22 +2,22 @@ package example
default allow := false # unless otherwise defined, allow is false
allow := true { # allow is true if...
allow := true if { # allow is true if...
count(violation) == 0 # there are zero violations.
}
violation[server.id] { # a server is in the violation set if...
violation[server.id] if { # a server is in the violation set if...
some server
public_server[server] # it exists in the 'public_server' set and...
server.protocols[_] == "http" # it contains the insecure "http" protocol.
}
violation[server.id] { # a server is in the violation set if...
violation[server.id] if { # a server is in the violation set if...
server := input.servers[_] # it exists in the input.servers collection and...
server.protocols[_] == "telnet" # it contains the "telnet" protocol.
}
public_server[server] { # a server exists in the public_server set if...
public_server[server]if { # a server exists in the public_server set if...
some i, j
server := input.servers[_] # it exists in the input.servers collection and...
server.ports[_] == input.ports[i].id # it references a port in the input.ports collection and...

View File

@@ -30,6 +30,11 @@ if [ -f Cargo.toml ]; then
cargo test -r --test aci
cargo test -r --test kata
# Ensure that all tests pass with extensions
cargo test -r --features rego-extensions
cargo test -r --test aci --features rego-extensions
cargo test -r --test kata --features rego-extensions
# Ensure that OPA conformance tests don't regress.
cargo test -r --features opa-testutil,serde_json/arbitrary_precision --test opa -- $(tr '\n' ' ' < tests/opa.passing)
cargo test -r --features opa-testutil,serde_json/arbitrary_precision,rego-extensions --test opa -- $(tr '\n' ' ' < tests/opa.passing)
fi

View File

@@ -10,8 +10,8 @@ use core::{cmp, fmt, ops::Deref};
#[derive(Debug, PartialEq, Eq, Clone)]
#[cfg_attr(feature = "ast", derive(serde::Serialize))]
pub enum BinOp {
And,
Or,
Intersection,
Union,
}
#[derive(Debug, PartialEq, Eq, Clone)]
@@ -209,6 +209,13 @@ pub enum Expr {
value: Ref<Expr>,
collection: Ref<Expr>,
},
#[cfg(feature = "rego-extensions")]
OrExpr {
span: Span,
lhs: Ref<Expr>,
rhs: Ref<Expr>,
},
}
impl Expr {
@@ -232,6 +239,8 @@ impl Expr {
| ArithExpr { span, .. }
| AssignExpr { span, .. }
| Membership { span, .. } => span,
#[cfg(feature = "rego-extensions")]
OrExpr { span, .. } => span,
}
}
}

View File

@@ -11,18 +11,15 @@ use anyhow::{bail, Result};
use constant_time_eq::constant_time_eq;
use hmac::{Hmac, Mac};
use md5::{Digest, Md5};
use sha1::Sha1;
use sha2::{Sha256, Sha512};
pub fn register(m: &mut builtins::BuiltinsMap<&'static str, builtins::BuiltinFcn>) {
m.insert("crypto.hmac.equal", (hmac_equal_fixed_time, 2));
m.insert("crypto.hmac.md5", (hmac_md5, 2));
m.insert("crypto.hmac.sha1", (hmac_sha1, 2));
m.insert("crypto.hmac.sha256", (hmac_sha256, 2));
m.insert("crypto.hmac.sha512", (hmac_sha512, 2));
m.insert("crypto.md5", (crypto_md5, 1));
m.insert("crypto.sha1", (crypto_sha1, 1));
m.insert("crypto.sha256", (crypto_sha256, 1));
}
@@ -60,22 +57,6 @@ fn hmac_md5(span: &Span, params: &[Ref<Expr>], args: &[Value], _strict: bool) ->
Ok(Value::String(hex::encode(result.into_bytes()).into()))
}
fn hmac_sha1(span: &Span, params: &[Ref<Expr>], args: &[Value], _strict: bool) -> Result<Value> {
let name = "crypto.hmac.sha1";
ensure_args_count(span, name, params, args, 2)?;
let x = ensure_string(name, &params[0], &args[0])?;
let key = ensure_string(name, &params[1], &args[1])?;
let mut hmac = Hmac::<Sha1>::new_from_slice(key.as_bytes())
.or_else(|_| bail!(span.error("failed to create hmac instance")))?;
hmac.update(x.as_bytes());
let result = hmac.finalize();
Ok(Value::String(hex::encode(result.into_bytes()).into()))
}
fn hmac_sha256(span: &Span, params: &[Ref<Expr>], args: &[Value], _strict: bool) -> Result<Value> {
let name = "crypto.hmac.sha256";
ensure_args_count(span, name, params, args, 2)?;
@@ -122,20 +103,6 @@ fn crypto_md5(span: &Span, params: &[Ref<Expr>], args: &[Value], _strict: bool)
Ok(Value::String(hex::encode(result).into()))
}
fn crypto_sha1(span: &Span, params: &[Ref<Expr>], args: &[Value], _strict: bool) -> Result<Value> {
let name = "crypto.sha1";
ensure_args_count(span, name, params, args, 1)?;
let x = ensure_string(name, &params[0], &args[0])?;
let mut h = Sha1::new();
h.update(x.as_bytes());
let result = h.finalize();
Ok(Value::String(hex::encode(result).into()))
}
fn crypto_sha256(
span: &Span,
params: &[Ref<Expr>],

View File

@@ -224,7 +224,7 @@ fn urlquery_decode(
let mut query_str = "".to_owned();
for (k, v) in url.query_pairs() {
query_str += &k;
if v != "" {
if !v.is_empty() {
query_str += "=";
query_str += &v;
}
@@ -337,11 +337,11 @@ fn yaml_is_valid(
fn yaml_marshal(span: &Span, params: &[Ref<Expr>], args: &[Value], _strict: bool) -> Result<Value> {
let name = "yaml.marshal";
ensure_args_count(span, name, params, args, 1)?;
Ok(Value::String(
serde_yaml::to_string(&args[0])
.with_context(|| span.error("could not serialize to yaml"))?
.into(),
))
let serialized = serde_yaml::to_string(&args[0])
.map_err(|err| span.error(&format!("could not serialize to yaml: {}", err)))?;
Ok(Value::String(serialized.into()))
}
#[cfg(feature = "yaml")]

View File

@@ -9,8 +9,7 @@ use crate::value::Value;
use crate::*;
use anyhow::{bail, Result};
//use glob::{Pattern, MatchOptions};
use wax::{Glob, Pattern};
use globset::{GlobBuilder, GlobMatcher};
pub fn register(m: &mut builtins::BuiltinsMap<&'static str, builtins::BuiltinFcn>) {
m.insert("glob.match", (glob_match, 3));
@@ -50,8 +49,12 @@ fn make_delimiters_unix_style(s: &str, delimiters: &[char]) -> Result<String> {
Ok(s)
}
fn make_glob<'a>(pattern: &'a str, span: &'a Span) -> Result<Glob<'a>> {
Glob::new(pattern).or_else(|_| bail!(span.error("invalid glob")))
fn make_glob(pattern: &str, span: &Span) -> Result<GlobMatcher> {
Ok(GlobBuilder::new(pattern)
.literal_separator(true)
.build()
.or_else(|_| bail!(span.error("invalid glob")))?
.compile_matcher())
}
fn glob_match(span: &Span, params: &[Ref<Expr>], args: &[Value], _strict: bool) -> Result<Value> {

View File

@@ -1,73 +0,0 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
use crate::ast::{Expr, Ref};
use crate::builtins;
use crate::builtins::utils::{ensure_args_count, ensure_string};
use crate::*;
use crate::lexer::Span;
use crate::value::Value;
use itertools::Itertools;
use anyhow::{bail, Result};
pub fn register(m: &mut builtins::BuiltinsMap<&'static str, builtins::BuiltinFcn>) {
m.insert("io.jwt.decode", (jwt_decode, 1));
m.insert("io.jwt.decode_verify", (jwt_decode_verify, 2));
}
fn decode(span: &Span, jwt: String, strict: bool) -> Result<Value> {
let Some((Ok(header), Ok(payload), Ok(signature))) = jwt
.split('.')
.map(|p| data_encoding::BASE64URL_NOPAD.decode(p.as_bytes()))
.collect_tuple()
else {
if strict {
bail!(span.error("invalid jwt token"));
}
return Ok(Value::Undefined);
};
let header = String::from_utf8_lossy(&header).to_string();
let payload = String::from_utf8_lossy(&payload).to_string();
let signature = data_encoding::HEXLOWER_PERMISSIVE.encode(&signature);
let signature = Value::String(signature.into());
let header = Value::from_json_str(&header)?;
if header["enc"] != Value::Undefined {
bail!(span.error("JWT is a JWE object, which is not supported"));
}
if header["cty"] == "JWT".into() {
if payload.len() <= 2 || !payload.starts_with('"') || !payload.ends_with('"') {
bail!(span.error("invalid nested JWT"));
}
// Ignore ""
decode(span, payload[1..payload.len() - 1].to_string(), strict)
} else {
let payload = Value::from_json_str(&payload)?;
Ok(Value::from_array([header, payload, signature].into()))
}
}
fn jwt_decode(span: &Span, params: &[Ref<Expr>], args: &[Value], strict: bool) -> Result<Value> {
let name = "io.jwt.decode";
ensure_args_count(span, name, params, args, 1)?;
let jwt = ensure_string(name, &params[0], &args[0])?;
decode(span, jwt.to_string(), strict) //header, payload, signature, strict)
}
fn jwt_decode_verify(
span: &Span,
params: &[Ref<Expr>],
args: &[Value],
_strict: bool,
) -> Result<Value> {
let name = "io.jwt.decode_verify";
ensure_args_count(span, name, params, args, 2)?;
Ok(Value::Undefined)
}

View File

@@ -18,8 +18,6 @@ mod glob;
mod graph;
#[cfg(feature = "http")]
mod http;
#[cfg(feature = "jwt")]
mod jwt;
pub mod numbers;
mod objects;
#[cfg(feature = "opa-runtime")]
@@ -83,8 +81,6 @@ lazy_static! {
//units::register(&mut m);
types::register(&mut m);
encoding::register(&mut m);
#[cfg(feature = "jwt")]
jwt::register(&mut m);
#[cfg(feature = "time")]
time::register(&mut m);

View File

@@ -12,7 +12,7 @@ use crate::*;
use anyhow::{bail, Result};
#[cfg(feature = "std")]
use rand::{thread_rng, Rng};
use rand::Rng;
pub fn register(m: &mut builtins::BuiltinsMap<&'static str, builtins::BuiltinFcn>) {
m.insert("abs", (abs, 1));
@@ -169,8 +169,7 @@ fn intn(span: &Span, params: &[Ref<Expr>], args: &[Value], _strict: bool) -> Res
Some(0) => Value::from(0u64),
Some(n) => {
// TODO: bounds checking; arbitrary precision
let mut rng = thread_rng();
let v = rng.gen_range(0..n);
let v = rand::rng().random_range(0..n);
Value::from(v)
}
_ => Value::Undefined,

View File

@@ -391,14 +391,14 @@ fn object_union_n(
}
#[cfg(feature = "jsonschema")]
fn compile_json_schema(param: &Ref<Expr>, arg: &Value) -> Result<jsonschema::JSONSchema> {
fn compile_json_schema(param: &Ref<Expr>, arg: &Value) -> Result<jsonschema::Validator> {
let schema_str = match arg {
Value::String(schema_str) => schema_str.as_ref().to_string(),
_ => arg.to_json_str()?,
};
if let Ok(schema) = serde_json::from_str(&schema_str) {
match jsonschema::JSONSchema::compile(&schema) {
match jsonschema::validator_for(&schema) {
Ok(schema) => return Ok(schema),
Err(e) => bail!(e.to_string()),
}
@@ -439,16 +439,14 @@ fn json_match_schema(
ensure_args_count(span, name, params, args, 2)?;
// The following is expected to succeed.
let document: serde_json::Value = serde_json::from_str(&args[0].to_json_str()?)?;
let document: serde_json::Value = serde_json::from_str(&args[0].to_json_str()?)
.map_err(|err| span.error(&format!("Failed to parse JSON: {}", err)))?;
Ok(Value::from_array(
match compile_json_schema(&params[1], &args[1]) {
Ok(schema) => match schema.validate(&document) {
Ok(_) => [Value::Bool(true), Value::Null],
Err(e) => [
Value::Bool(false),
Value::from_array(e.map(|e| Value::String(e.to_string().into())).collect()),
],
Err(e) => [Value::Bool(false), Value::from(e.to_string())],
},
Err(e) if strict => bail!(params[1]
.span()

View File

@@ -67,8 +67,6 @@ fn opa_runtime(span: &Span, params: &[Ref<Expr>], args: &[Value], _strict: bool)
"hex",
#[cfg(feature = "http")]
"http",
#[cfg(feature = "jwt")]
"jwt",
#[cfg(feature = "jsonschema")]
"jsonschema",
#[cfg(feature = "opa-runtime")]

View File

@@ -25,7 +25,11 @@ fn sleep(span: &Span, params: &[Ref<Expr>], args: &[Value], _strict: bool) -> Re
let dur = time::compat::parse_duration(val.as_ref())
.map_err(|e| params[0].span().error(&format!("{e}")))?;
thread::sleep(dur.to_std()?);
let std_dur = dur
.to_std()
.map_err(|err| anyhow::anyhow!("Failed to convert to std::time::Duration: {err}"))?;
thread::sleep(std_dur);
Ok(Value::Null)
}

View File

@@ -158,7 +158,8 @@ fn parse_ns(span: &Span, params: &[Ref<Expr>], args: &[Value], strict: bool) ->
let layout = ensure_string(name, &params[0], &args[0])?;
let value = ensure_string(name, &params[1], &args[1])?;
let datetime = compat::parse(layout_with_predefined_formats(&layout), &value)?;
let datetime = compat::parse(layout_with_predefined_formats(&layout), &value)
.map_err(|err| anyhow::anyhow!("Failed to parse datetime: {}", err))?;
safe_timestamp_nanos(span, strict, datetime.timestamp_nanos_opt())
}
@@ -173,7 +174,8 @@ fn parse_rfc3339_ns(
let value = ensure_string(name, &params[0], &args[0])?;
let datetime = DateTime::parse_from_rfc3339(&value)?;
let datetime = DateTime::parse_from_rfc3339(&value)
.map_err(|err| anyhow::anyhow!("Failed to parse datetime: {}", err))?;
safe_timestamp_nanos(span, strict, datetime.timestamp_nanos_opt())
}

View File

@@ -266,7 +266,7 @@ struct GoTimeFormatItems<'a> {
mode: GoTimeFormatItemsMode,
}
impl<'a> GoTimeFormatItems<'a> {
impl GoTimeFormatItems<'_> {
fn parse(reminder: &str) -> GoTimeFormatItems {
GoTimeFormatItems {
reminder,

View File

@@ -83,8 +83,8 @@ fn parse(span: &Span, params: &[Ref<Expr>], args: &[Value], _strict: bool) -> Re
bail!(span.error("spaces not allowed in resource strings"));
}
let (number_part, suffix) = match string.find(|c: char| c.is_alphabetic()) {
Some(p) => (&string[0..p], &string[p..]),
let (number_part, suffix) = match string.rfind(|c: char| c.is_ascii_digit()) {
Some(p) => (&string[0..p + 1], &string[p + 1..]),
_ => (string, ""),
};
@@ -161,8 +161,8 @@ fn parse_bytes(span: &Span, params: &[Ref<Expr>], args: &[Value], strict: bool)
bail!(span.error("spaces not allowed in resource strings"));
}
let (number_part, suffix) = match string.find(|c: char| c.is_alphabetic()) {
Some(p) => (&string[0..p], &string[p..]),
let (number_part, suffix) = match string.rfind(|c: char| c.is_ascii_digit()) {
Some(p) => (&string[0..p + 1], &string[p + 1..]),
_ => (string, ""),
};

View File

@@ -132,16 +132,16 @@ fn timestamp(uuid: &Uuid) -> Option<Timestamp> {
const fn decode_rfc4122_timestamp(uuid: &Uuid) -> (u64, u16) {
let bytes = uuid.as_bytes();
let ticks: u64 = ((bytes[6] & 0x0F) as u64) << 56
| (bytes[7] as u64) << 48
| (bytes[4] as u64) << 40
| (bytes[5] as u64) << 32
| (bytes[0] as u64) << 24
| (bytes[1] as u64) << 16
| (bytes[2] as u64) << 8
let ticks: u64 = (((bytes[6] & 0x0F) as u64) << 56)
| ((bytes[7] as u64) << 48)
| ((bytes[4] as u64) << 40)
| ((bytes[5] as u64) << 32)
| ((bytes[0] as u64) << 24)
| ((bytes[1] as u64) << 16)
| ((bytes[2] as u64) << 8)
| (bytes[3] as u64);
let counter: u16 = ((bytes[8] & 0x3F) as u16) << 8 | (bytes[9] as u16);
let counter: u16 = (((bytes[8] & 0x3F) as u16) << 8) | (bytes[9] as u16);
(ticks, counter)
}

View File

@@ -37,33 +37,37 @@ impl Engine {
modules: vec![],
interpreter: Interpreter::new(),
prepared: false,
rego_v1: false,
rego_v1: true,
}
}
/// Turn rego.v1 on/off for subsequently added policies.
///
/// Explicit import rego.v1 is not needed if set.
/// Enable rego v0.
///
/// Note that regorus now defaults to v1.
/// ```
/// # use regorus::*;
/// # fn main() -> anyhow::Result<()> {
/// let mut engine = Engine::new();
///
/// engine.set_rego_v1(true);
/// // Enable v0 for old style policies.
/// engine.set_rego_v0(true);
///
/// engine.add_policy(
/// "test.rego".to_string(),
/// r#"
/// package test
/// allow if true # if keyword is automatically imported
///
/// allow { # v0 syntax does not require if keyword
/// 1 < 2
/// }
/// "#.to_string())?;
///
/// # Ok(())
/// # }
/// ```
///
pub fn set_rego_v1(&mut self, rego_v1: bool) {
self.rego_v1 = rego_v1;
pub fn set_rego_v0(&mut self, rego_v0: bool) {
self.rego_v1 = !rego_v0;
}
/// Add a policy.
@@ -114,6 +118,8 @@ impl Engine {
/// # use regorus::*;
/// # fn main() -> anyhow::Result<()> {
/// let mut engine = Engine::new();
/// // framework.rego does not conform to v1.
/// engine.set_rego_v0(true);
///
/// let package = engine.add_policy_from_file("tests/aci/framework.rego")?;
///
@@ -139,6 +145,8 @@ impl Engine {
/// # use regorus::*;
/// # fn main() -> anyhow::Result<()> {
/// let mut engine = Engine::new();
/// // framework.rego does not conform to v1.
/// engine.set_rego_v0(true);
///
/// let _ = engine.add_policy_from_file("tests/aci/framework.rego")?;
///
@@ -414,6 +422,7 @@ impl Engine {
/// let mut engine = Engine::new();
///
/// // Add policies
/// engine.set_rego_v0(true);
/// engine.add_policy_from_file("tests/aci/framework.rego")?;
/// engine.add_policy_from_file("tests/aci/api.rego")?;
/// engine.add_policy_from_file("tests/aci/policy.rego")?;
@@ -739,7 +748,7 @@ impl Engine {
/// engine.add_policy(
/// "policy.rego".to_string(),
/// r#"package invalid
/// x = y {
/// x = y if {
/// # y = do_magic(2)
/// do_magic(2, y) # y is supplied as an out parameter.
/// }
@@ -775,7 +784,7 @@ impl Engine {
/// r#"
/// package test # Line 2
///
/// x = y { # Line 4
/// x = y if { # Line 4
/// input.a > 2 # Line 5
/// y = 5 # Line 6
/// }

View File

@@ -484,6 +484,12 @@ impl Interpreter {
self.hoist_loops_impl(rhs, loops);
}
#[cfg(feature = "rego-extensions")]
OrExpr { lhs, rhs, .. } => {
self.hoist_loops_impl(lhs, loops);
self.hoist_loops_impl(rhs, loops);
}
Membership {
key,
value,
@@ -554,8 +560,8 @@ impl Interpreter {
}
match op {
BinOp::Or => builtins::sets::union(lhs, rhs, lhs_value, rhs_value),
BinOp::And => builtins::sets::intersection(lhs, rhs, lhs_value, rhs_value),
BinOp::Union => builtins::sets::union(lhs, rhs, lhs_value, rhs_value),
BinOp::Intersection => builtins::sets::intersection(lhs, rhs, lhs_value, rhs_value),
}
}
@@ -2831,6 +2837,15 @@ impl Interpreter {
..
} => self.eval_membership(key, value, collection),
#[cfg(feature = "rego-extensions")]
Expr::OrExpr { lhs, rhs, .. } => {
let lhs = self.eval_expr(lhs)?;
match lhs {
Value::Bool(false) | Value::Null | Value::Undefined => self.eval_expr(rhs),
_ => Ok(lhs),
}
}
// Creation expression
Expr::Array { items, .. } => self.eval_array(items),
Expr::Object { fields, .. } => self.eval_object(fields),
@@ -2955,10 +2970,7 @@ impl Interpreter {
_ => bail!("internal error: rule's context already popped"),
};
let result = match result {
Ok(r) => r,
Err(e) => return Err(e),
};
let result = result?;
assert_eq!(self.scopes.len(), n_scopes);
@@ -3126,6 +3138,8 @@ impl Interpreter {
ArithExpr { span, .. } => ("arithexpr", span),
AssignExpr { span, .. } => ("assignexpr", span),
Membership { span, .. } => ("membership", span),
#[cfg(feature = "rego-extensions")]
OrExpr { span, .. } => ("orexpr", span),
};
Err(span.error(format!("invalid `{kind}` in default value").as_str()))

View File

@@ -1,6 +1,7 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
#![cfg_attr(docsrs, feature(doc_cfg))]
#![allow(unknown_lints)]
#![allow(clippy::doc_lazy_continuation)]
// Use README.md as crate documentation.
@@ -357,7 +358,7 @@ where
}
/// Implement clone for a boxed extension using [`Extension::clone_box`].
impl<'a> Clone for Box<dyn 'a + Extension> {
impl Clone for Box<dyn '_ + Extension> {
fn clone(&self) -> Self {
(**self).clone_box()
}
@@ -404,7 +405,6 @@ pub mod coverage {
/// Lines that are not covered are red.
///
/// <img src="https://github.com/microsoft/regorus/blob/main/docs/coverage.png?raw=true">
pub fn to_string_pretty(&self) -> anyhow::Result<String> {
let mut s = String::default();
s.push_str("COVERAGE REPORT:\n");

View File

@@ -135,40 +135,28 @@ impl From<f64> for Number {
impl Number {
pub fn as_u128(&self) -> Option<u128> {
match self {
Big(b) if b.is_integer() => match u128::try_from(&b.d) {
Ok(v) => Some(v),
_ => None,
},
Big(b) if b.is_integer() => u128::try_from(&b.d).ok(),
_ => None,
}
}
pub fn as_i128(&self) -> Option<i128> {
match self {
Big(b) if b.is_integer() => match i128::try_from(&b.d) {
Ok(v) => Some(v),
_ => None,
},
Big(b) if b.is_integer() => i128::try_from(&b.d).ok(),
_ => None,
}
}
pub fn as_u64(&self) -> Option<u64> {
match self {
Big(b) if b.is_integer() => match u64::try_from(&b.d) {
Ok(v) => Some(v),
_ => None,
},
Big(b) if b.is_integer() => u64::try_from(&b.d).ok(),
_ => None,
}
}
pub fn as_i64(&self) -> Option<i64> {
match self {
Big(b) if b.is_integer() => match i64::try_from(&b.d) {
Ok(v) => Some(v),
_ => None,
},
Big(b) if b.is_integer() => i64::try_from(&b.d).ok(),
_ => None,
}
}
@@ -317,10 +305,7 @@ impl Number {
fn ensure_integer(&self) -> Option<BigInt> {
match self {
Big(a) if a.is_integer() => match BigInt::try_from(&a.d) {
Ok(v) => Some(v),
_ => None,
},
Big(a) if a.is_integer() => BigInt::try_from(&a.d).ok(),
_ => None,
}
}

Some files were not shown because too many files have changed in this diff Show More