mirror of
https://github.com/microsoft/regorus.git
synced 2026-08-05 02:16:11 +00:00
Compare commits
131 Commits
regorus-v0
...
ant/cs_tes
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0c789ba125 | ||
|
|
667cb0d90f | ||
|
|
f46ab5b697 | ||
|
|
757edcc8fb | ||
|
|
77cdac0fef | ||
|
|
ab93c07773 | ||
|
|
2749e820c4 | ||
|
|
a164f342bf | ||
|
|
c28bde3f56 | ||
|
|
2858b63cd4 | ||
|
|
c7bf460bc1 | ||
|
|
4d2b205ef4 | ||
|
|
4f7b9a4292 | ||
|
|
4a2df93ae2 | ||
|
|
c6a5f1d852 | ||
|
|
2901481c51 | ||
|
|
c963e477a3 | ||
|
|
cbd772623a | ||
|
|
a07beca983 | ||
|
|
a3edb6c88c | ||
|
|
a1777fb7d3 | ||
|
|
11aaa555aa | ||
|
|
f1580a55a3 | ||
|
|
6174af1781 | ||
|
|
5fa55d7274 | ||
|
|
748c11cfa1 | ||
|
|
fb035d3d93 | ||
|
|
ba3a128e84 | ||
|
|
d955ae10a5 | ||
|
|
cabd086619 | ||
|
|
4ec25f37a1 | ||
|
|
c281d28474 | ||
|
|
1bfe38f9af | ||
|
|
5bf7cd7cc8 | ||
|
|
c56da34843 | ||
|
|
61f82d1b34 | ||
|
|
00f45c70fe | ||
|
|
df73b20192 | ||
|
|
992b202f60 | ||
|
|
ce6ecd6fd6 | ||
|
|
37262ccf8f | ||
|
|
dcd040cf40 | ||
|
|
f0a3cf26a0 | ||
|
|
13d8289a58 | ||
|
|
d2b27ee512 | ||
|
|
adb9da0c0c | ||
|
|
dc0f48f6bc | ||
|
|
334db3d6ce | ||
|
|
7565ec3ecf | ||
|
|
8498274356 | ||
|
|
ecd341bbcc | ||
|
|
b6935d1add | ||
|
|
502b830c19 | ||
|
|
8003cfc5b7 | ||
|
|
a4a80d7fc6 | ||
|
|
af5071446b | ||
|
|
edd0ccca5b | ||
|
|
fec6f8f8b4 | ||
|
|
dff65f0329 | ||
|
|
6bf40c7394 | ||
|
|
a488a84969 | ||
|
|
e4a58ad1dc | ||
|
|
430a453fde | ||
|
|
ef549a6528 | ||
|
|
52afcbe5c5 | ||
|
|
f0576cef77 | ||
|
|
20eece58ed | ||
|
|
6599ce6001 | ||
|
|
7095e269b7 | ||
|
|
6e1f8cdb36 | ||
|
|
fb5151e0e4 | ||
|
|
37d283cb38 | ||
|
|
25dbd27d82 | ||
|
|
292948a694 | ||
|
|
5a0048cd64 | ||
|
|
4a2a724a80 | ||
|
|
46e28b36f8 | ||
|
|
ee898e112e | ||
|
|
e6f2ec825d | ||
|
|
45627aa64a | ||
|
|
df98c8d168 | ||
|
|
25902bab57 | ||
|
|
e62bfdf161 | ||
|
|
658f34753b | ||
|
|
5eda76fd00 | ||
|
|
97914d5596 | ||
|
|
ffb79f1b30 | ||
|
|
536c6ede5c | ||
|
|
ff0adf054e | ||
|
|
2b82f2842f | ||
|
|
d09c445add | ||
|
|
33fe9d5039 | ||
|
|
3d08f6eef9 | ||
|
|
3ac9b1121e | ||
|
|
9894f00829 | ||
|
|
495e91c75a | ||
|
|
25ac1b6c95 | ||
|
|
209ece9dee | ||
|
|
0952d42432 | ||
|
|
56bd8841d0 | ||
|
|
67f65c0561 | ||
|
|
5422bde391 | ||
|
|
68a0f8fcce | ||
|
|
97b70a1c1b | ||
|
|
e86b590f91 | ||
|
|
01fc234a33 | ||
|
|
e9cd6d6afc | ||
|
|
69d6426663 | ||
|
|
0a39e434db | ||
|
|
9832a297ed | ||
|
|
c6fb8cf044 | ||
|
|
55abbb2b42 | ||
|
|
3743f32edc | ||
|
|
744dad6126 | ||
|
|
7fde3382f6 | ||
|
|
316f3a7692 | ||
|
|
de56cce7cb | ||
|
|
72ced23366 | ||
|
|
3fa2847e6f | ||
|
|
82c86437cb | ||
|
|
05e91da06e | ||
|
|
8c69dd491b | ||
|
|
6a167143cb | ||
|
|
d2049d07f3 | ||
|
|
e326f3c629 | ||
|
|
3c7674e7c2 | ||
|
|
947c9490fa | ||
|
|
0ebcb568cc | ||
|
|
e86801bdd9 | ||
|
|
3d98c3b12e | ||
|
|
330a6dff72 |
@@ -4,11 +4,20 @@
|
|||||||
"name": "Rust",
|
"name": "Rust",
|
||||||
// Or use a Dockerfile or Docker Compose file. More info: https://containers.dev/guide/dockerfile
|
// Or use a Dockerfile or Docker Compose file. More info: https://containers.dev/guide/dockerfile
|
||||||
"image": "mcr.microsoft.com/devcontainers/rust:1-1-bullseye",
|
"image": "mcr.microsoft.com/devcontainers/rust:1-1-bullseye",
|
||||||
|
"customizations": {
|
||||||
|
"vscode": {
|
||||||
|
"extensions": [
|
||||||
|
"ms-dotnettools.csharp",
|
||||||
|
"ms-dotnettools.csdevkit"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
"features": {
|
"features": {
|
||||||
"ghcr.io/devcontainers/features/dotnet:2": {},
|
"ghcr.io/devcontainers/features/dotnet:2": {
|
||||||
|
"version": "8.0"
|
||||||
|
},
|
||||||
"ghcr.io/devcontainers/features/python:1": {}
|
"ghcr.io/devcontainers/features/python:1": {}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Use 'mounts' to make the cargo cache persistent in a Docker Volume.
|
// Use 'mounts' to make the cargo cache persistent in a Docker Volume.
|
||||||
// "mounts": [
|
// "mounts": [
|
||||||
// {
|
// {
|
||||||
|
|||||||
33
.github/workflows/pr-extensions.yml
vendored
Normal file
33
.github/workflows/pr-extensions.yml
vendored
Normal 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)
|
||||||
41
.github/workflows/pr.yml
vendored
41
.github/workflows/pr.yml
vendored
@@ -1,4 +1,4 @@
|
|||||||
name: Rust
|
name: tests/release
|
||||||
|
|
||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
@@ -10,35 +10,34 @@ env:
|
|||||||
CARGO_TERM_COLOR: always
|
CARGO_TERM_COLOR: always
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
build:
|
test:
|
||||||
|
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v4
|
||||||
- name: Add musl target
|
|
||||||
run: rustup target add x86_64-unknown-linux-musl
|
|
||||||
- name: Install musl-gcc
|
|
||||||
run: sudo apt update && sudo apt install -y musl-tools
|
|
||||||
- name: Format Check
|
- name: Format Check
|
||||||
run: cargo fmt --check
|
run: cargo fmt --check
|
||||||
|
- name: Fetch
|
||||||
|
run: cargo fetch
|
||||||
|
- name: Build (all features)
|
||||||
|
run: cargo build -r --all-features --frozen
|
||||||
- name: Build
|
- name: Build
|
||||||
run: cargo build -r --verbose
|
run: cargo build -r --frozen
|
||||||
|
- name: Test no_std
|
||||||
|
run: cargo test -r --no-default-features --frozen
|
||||||
|
- name: Build only std
|
||||||
|
run: cargo build -r --example regorus --no-default-features --features "std" --frozen
|
||||||
- name: Doc Tests
|
- name: Doc Tests
|
||||||
run: cargo test -r --doc
|
run: cargo test -r --doc --frozen
|
||||||
- name: Run tests
|
- name: Run tests
|
||||||
run: cargo test -r --verbose
|
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)
|
- 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 --frozen
|
||||||
- name: Run tests (OPA Conformance)
|
- name: Run tests (OPA Conformance)
|
||||||
run: >-
|
run: >-
|
||||||
cargo test -r --test opa --features opa-testutil -- $(tr '\n' ' ' < tests/opa.passing)
|
cargo test -r --test opa --frozen --features opa-testutil,serde_json/arbitrary_precision -- $(tr '\n' ' ' < tests/opa.passing)
|
||||||
- name: Build (MUSL)
|
|
||||||
run: cargo build --verbose --all-targets --target x86_64-unknown-linux-musl
|
|
||||||
- name: Run tests (MUSL)
|
|
||||||
run: cargo test -r --verbose --target x86_64-unknown-linux-musl
|
|
||||||
- name: Run tests (MUSL ACI)
|
|
||||||
run: cargo test -r --test aci --target x86_64-unknown-linux-musl
|
|
||||||
- name: Run tests (MUSL OPA Conformance)
|
|
||||||
run: >-
|
|
||||||
cargo test -r --test opa --features opa-testutil --target x86_64-unknown-linux-musl -- $(tr '\n' ' ' < tests/opa.passing)
|
|
||||||
|
|||||||
3
.github/workflows/publish-java.yml
vendored
3
.github/workflows/publish-java.yml
vendored
@@ -48,7 +48,8 @@ jobs:
|
|||||||
python-version: "3.11"
|
python-version: "3.11"
|
||||||
- if: ${{ matrix.build_cmd == 'zigbuild' }}
|
- if: ${{ matrix.build_cmd == 'zigbuild' }}
|
||||||
run: pip install cargo-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: mkdir -p native/${{ matrix.target }}
|
||||||
- run: mv target/${{ matrix.target }}/release/*.${{ matrix.extension }} ./native/${{ matrix.target }}/
|
- run: mv target/${{ matrix.target }}/release/*.${{ matrix.extension }} ./native/${{ matrix.target }}/
|
||||||
- uses: actions/upload-artifact@v4
|
- uses: actions/upload-artifact@v4
|
||||||
|
|||||||
53
.github/workflows/publish-python.yml
vendored
53
.github/workflows/publish-python.yml
vendored
@@ -22,11 +22,19 @@ jobs:
|
|||||||
- uses: actions/setup-python@v4
|
- uses: actions/setup-python@v4
|
||||||
with:
|
with:
|
||||||
python-version: '3.10'
|
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
|
- name: Build wheels
|
||||||
uses: PyO3/maturin-action@v1
|
uses: PyO3/maturin-action@63b75c597b83e247fbf4fb7719801cc4220ae9f3 # v1.43.0
|
||||||
with:
|
with:
|
||||||
target: ${{ matrix.target }}
|
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'
|
sccache: 'true'
|
||||||
manylinux: auto
|
manylinux: auto
|
||||||
- name: Upload wheels
|
- name: Upload wheels
|
||||||
@@ -46,11 +54,19 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
python-version: '3.10'
|
python-version: '3.10'
|
||||||
architecture: ${{ matrix.target }}
|
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
|
- name: Build wheels
|
||||||
uses: PyO3/maturin-action@v1
|
uses: PyO3/maturin-action@63b75c597b83e247fbf4fb7719801cc4220ae9f3 # v1.43.0
|
||||||
with:
|
with:
|
||||||
target: ${{ matrix.target }}
|
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'
|
sccache: 'true'
|
||||||
- name: Upload wheels
|
- name: Upload wheels
|
||||||
uses: actions/upload-artifact@v3
|
uses: actions/upload-artifact@v3
|
||||||
@@ -68,11 +84,19 @@ jobs:
|
|||||||
- uses: actions/setup-python@v4
|
- uses: actions/setup-python@v4
|
||||||
with:
|
with:
|
||||||
python-version: '3.10'
|
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
|
- name: Build wheels
|
||||||
uses: PyO3/maturin-action@v1
|
uses: PyO3/maturin-action@63b75c597b83e247fbf4fb7719801cc4220ae9f3 # v1.43.0
|
||||||
with:
|
with:
|
||||||
target: ${{ matrix.target }}
|
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'
|
sccache: 'true'
|
||||||
- name: Upload wheels
|
- name: Upload wheels
|
||||||
uses: actions/upload-artifact@v3
|
uses: actions/upload-artifact@v3
|
||||||
@@ -80,21 +104,6 @@ jobs:
|
|||||||
name: wheels
|
name: wheels
|
||||||
path: dist
|
path: dist
|
||||||
|
|
||||||
sdist:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v3
|
|
||||||
- name: Build sdist
|
|
||||||
uses: PyO3/maturin-action@v1
|
|
||||||
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:
|
release:
|
||||||
name: Release
|
name: Release
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
@@ -106,7 +115,7 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
name: wheels
|
name: wheels
|
||||||
- name: Publish to PyPI
|
- name: Publish to PyPI
|
||||||
uses: PyO3/maturin-action@v1
|
uses: PyO3/maturin-action@63b75c597b83e247fbf4fb7719801cc4220ae9f3 # v1.43.0
|
||||||
env:
|
env:
|
||||||
MATURIN_PYPI_TOKEN: ${{ secrets.PYPI_API_TOKEN }}
|
MATURIN_PYPI_TOKEN: ${{ secrets.PYPI_API_TOKEN }}
|
||||||
with:
|
with:
|
||||||
|
|||||||
2
.github/workflows/release-plz.yml
vendored
2
.github/workflows/release-plz.yml
vendored
@@ -18,7 +18,7 @@ jobs:
|
|||||||
- name: Install Rust toolchain
|
- name: Install Rust toolchain
|
||||||
uses: dtolnay/rust-toolchain@stable
|
uses: dtolnay/rust-toolchain@stable
|
||||||
- name: Run release-plz
|
- name: Run release-plz
|
||||||
uses: MarcoIeni/release-plz-action@v0.5
|
uses: MarcoIeni/release-plz-action@98b2b45b090aadf18cb662caaf3de6222d98822a #v0.5.60
|
||||||
env:
|
env:
|
||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_REGISTRY_TOKEN }}
|
CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_REGISTRY_TOKEN }}
|
||||||
|
|||||||
4
.github/workflows/rust-clippy.yml
vendored
4
.github/workflows/rust-clippy.yml
vendored
@@ -40,11 +40,15 @@ jobs:
|
|||||||
- name: Install required cargo
|
- name: Install required cargo
|
||||||
run: cargo install clippy-sarif sarif-fmt
|
run: cargo install clippy-sarif sarif-fmt
|
||||||
|
|
||||||
|
- name: Fetch
|
||||||
|
run: cargo fetch
|
||||||
|
|
||||||
- name: Run rust-clippy
|
- name: Run rust-clippy
|
||||||
run:
|
run:
|
||||||
cargo clippy
|
cargo clippy
|
||||||
--all-features
|
--all-features
|
||||||
--message-format=json | clippy-sarif | tee rust-clippy-results.sarif | sarif-fmt
|
--message-format=json | clippy-sarif | tee rust-clippy-results.sarif | sarif-fmt
|
||||||
|
--frozen
|
||||||
continue-on-error: true
|
continue-on-error: true
|
||||||
|
|
||||||
- name: Upload analysis results to GitHub
|
- name: Upload analysis results to GitHub
|
||||||
|
|||||||
49
.github/workflows/test-c-cpp.yml
vendored
Normal file
49
.github/workflows/test-c-cpp.yml
vendored
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
name: bindings/c-cpp
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches: [ "main" ]
|
||||||
|
pull_request:
|
||||||
|
branches: [ "main" ]
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
test:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Checkout repository
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
fetch-depth: 0
|
||||||
|
|
||||||
|
- name: Setup gcc, g++, cmake, ninja
|
||||||
|
run: sudo apt update && sudo apt install -y gcc g++ cmake ninja-build
|
||||||
|
|
||||||
|
- name: Workaround to ensure that regorus.h is generated
|
||||||
|
run: |
|
||||||
|
cargo fetch
|
||||||
|
cargo build -r --frozen
|
||||||
|
working-directory: ./bindings/ffi
|
||||||
|
|
||||||
|
- name: Test c binding
|
||||||
|
run: |
|
||||||
|
mkdir bindings/c/build
|
||||||
|
cd bindings/c/build
|
||||||
|
cmake -G Ninja ..
|
||||||
|
ninja
|
||||||
|
./regorus_test
|
||||||
|
|
||||||
|
- name: Test c-nostd binding
|
||||||
|
run: |
|
||||||
|
mkdir bindings/c-nostd/build
|
||||||
|
cd bindings/c-nostd/build
|
||||||
|
cmake -G Ninja ..
|
||||||
|
ninja
|
||||||
|
./regorus_test
|
||||||
|
|
||||||
|
- name: Test cpp binding
|
||||||
|
run: |
|
||||||
|
mkdir bindings/cpp/build
|
||||||
|
cd bindings/cpp/build
|
||||||
|
cmake -G Ninja ..
|
||||||
|
ninja
|
||||||
|
./regorus_test
|
||||||
132
.github/workflows/test-csharp.yml
vendored
Normal file
132
.github/workflows/test-csharp.yml
vendored
Normal file
@@ -0,0 +1,132 @@
|
|||||||
|
name: bindings/csharp
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches: [ "main" ]
|
||||||
|
pull_request:
|
||||||
|
branches: [ "main" ]
|
||||||
|
|
||||||
|
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
|
||||||
|
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 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
|
||||||
23
.github/workflows/test-ffi.yml
vendored
Normal file
23
.github/workflows/test-ffi.yml
vendored
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
name: bindings/ffi
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches: [ "main" ]
|
||||||
|
pull_request:
|
||||||
|
branches: [ "main" ]
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
test:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Checkout repository
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
fetch-depth: 0
|
||||||
|
|
||||||
|
- name: Test FFI
|
||||||
|
run: |
|
||||||
|
cargo fetch
|
||||||
|
cargo build -r --frozen
|
||||||
|
cargo clippy --all-targets --no-deps -- -Dwarnings
|
||||||
|
working-directory: ./bindings/ffi
|
||||||
32
.github/workflows/test-go.yml
vendored
Normal file
32
.github/workflows/test-go.yml
vendored
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
name: bindings/go
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches: [ "main" ]
|
||||||
|
pull_request:
|
||||||
|
branches: [ "main" ]
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
test:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Checkout repository
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
fetch-depth: 0
|
||||||
|
|
||||||
|
|
||||||
|
- uses: actions/setup-go@v5
|
||||||
|
with:
|
||||||
|
architecture: x64
|
||||||
|
|
||||||
|
- name: Build ffi
|
||||||
|
run: cargo build -r
|
||||||
|
working-directory: ./bindings/ffi
|
||||||
|
|
||||||
|
- name: Test go
|
||||||
|
run: |
|
||||||
|
go mod tidy
|
||||||
|
go build
|
||||||
|
LD_LIBRARY_PATH=../ffi/target/release ./regorus_test
|
||||||
|
working-directory: ./bindings/go
|
||||||
37
.github/workflows/test-java.yml
vendored
Normal file
37
.github/workflows/test-java.yml
vendored
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
name: bindings/java
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches: [ "main" ]
|
||||||
|
pull_request:
|
||||||
|
branches: [ "main" ]
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
test:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Checkout repository
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
fetch-depth: 0
|
||||||
|
|
||||||
|
- uses: actions/setup-java@v4
|
||||||
|
with:
|
||||||
|
java-version: 8
|
||||||
|
distribution: "corretto"
|
||||||
|
- uses: dtolnay/rust-toolchain@stable
|
||||||
|
|
||||||
|
- name: Building binding
|
||||||
|
run: |
|
||||||
|
cargo clippy --all-targets --no-deps -- -Dwarnings
|
||||||
|
cargo build --release --manifest-path bindings/java/Cargo.toml --locked
|
||||||
|
|
||||||
|
- name: Build jar
|
||||||
|
run: mvn package
|
||||||
|
working-directory: ./bindings/java
|
||||||
|
|
||||||
|
- 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
|
||||||
|
working-directory: ./bindings/java
|
||||||
35
.github/workflows/test-musl.yml
vendored
Normal file
35
.github/workflows/test-musl.yml
vendored
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
name: musl
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches: [ "main" ]
|
||||||
|
pull_request:
|
||||||
|
branches: [ "main" ]
|
||||||
|
|
||||||
|
env:
|
||||||
|
CARGO_TERM_COLOR: always
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
test:
|
||||||
|
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v3
|
||||||
|
- name: Add musl target
|
||||||
|
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 --frozen
|
||||||
|
- name: Run tests (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 --frozen
|
||||||
|
- name: Run tests (KATA ACI)
|
||||||
|
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 --frozen --features opa-testutil,serde_json/arbitrary_precision --target x86_64-unknown-linux-musl -- $(tr '\n' ' ' < tests/opa.passing)
|
||||||
26
.github/workflows/test-no-std.yml
vendored
Normal file
26
.github/workflows/test-no-std.yml
vendored
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
name: bindings/no-std
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches: [ "main" ]
|
||||||
|
pull_request:
|
||||||
|
branches: [ "main" ]
|
||||||
|
|
||||||
|
env:
|
||||||
|
CARGO_TERM_COLOR: always
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- 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 --frozen
|
||||||
|
working-directory: ./tests/ensure_no_std
|
||||||
|
|
||||||
89
.github/workflows/test-python.yml
vendored
Normal file
89
.github/workflows/test-python.yml
vendored
Normal file
@@ -0,0 +1,89 @@
|
|||||||
|
name: bindings/python
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches: [ "main" ]
|
||||||
|
pull_request:
|
||||||
|
branches: [ "main" ]
|
||||||
|
|
||||||
|
env:
|
||||||
|
PYTHON_VERSION: "3.10"
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
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
|
||||||
|
with:
|
||||||
|
fetch-depth: 0
|
||||||
|
|
||||||
|
- uses: actions/setup-python@v4
|
||||||
|
with:
|
||||||
|
python-version: ${{ env.PYTHON_VERSION }}
|
||||||
|
architecture: x64
|
||||||
|
|
||||||
|
- 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 --offline --strip
|
||||||
|
sccache: 'true'
|
||||||
|
|
||||||
|
- 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 ../../wheels/${{ matrix.host.wheel }}
|
||||||
|
python3 test.py
|
||||||
|
working-directory: bindings/python
|
||||||
35
.github/workflows/test-ruby.yml
vendored
Normal file
35
.github/workflows/test-ruby.yml
vendored
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
name: bindings/ruby
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches: [ "main" ]
|
||||||
|
pull_request:
|
||||||
|
branches: [ "main" ]
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
test:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Checkout repository
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
fetch-depth: 0
|
||||||
|
|
||||||
|
- name: Setup Ruby and Rust
|
||||||
|
uses: oxidize-rb/actions/setup-ruby-and-rust@7ca44a16e287e5ff7dd72ab53f4bd41cbf34a571 #v1.26
|
||||||
|
with:
|
||||||
|
bundler: 2.6.5
|
||||||
|
rubygems: 3.6.5
|
||||||
|
ruby-version: "3.4.2"
|
||||||
|
rustup-toolchain: "stable"
|
||||||
|
bundler-cache: true
|
||||||
|
cargo-cache: true
|
||||||
|
working-directory: "bindings/ruby"
|
||||||
|
|
||||||
|
- name: Run ruby tests
|
||||||
|
run: |
|
||||||
|
cd bindings/ruby
|
||||||
|
gem install bundler
|
||||||
|
bundle install
|
||||||
|
cargo clippy --all-targets --no-deps -- -Dwarnings
|
||||||
|
bundle exec rake
|
||||||
35
.github/workflows/test-wasm.yml
vendored
Normal file
35
.github/workflows/test-wasm.yml
vendored
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
name: bindings/wasm
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches: [ "main" ]
|
||||||
|
pull_request:
|
||||||
|
branches: [ "main" ]
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
test:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Checkout repository
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
fetch-depth: 0
|
||||||
|
|
||||||
|
- name: Setup Node
|
||||||
|
uses: actions/setup-node@v4
|
||||||
|
with:
|
||||||
|
node-version: 18
|
||||||
|
|
||||||
|
- name: Install wasmlpack
|
||||||
|
run: cargo install wasm-pack
|
||||||
|
|
||||||
|
- name: Test wasm binding
|
||||||
|
run: |
|
||||||
|
cd bindings/wasm
|
||||||
|
cargo fetch
|
||||||
|
cargo clippy --all-targets --no-deps -- -Dwarnings
|
||||||
|
wasm-pack build --target nodejs --release
|
||||||
|
# Enable when upstream issue is fixed.
|
||||||
|
# https://github.com/microsoft/regorus/issues/371
|
||||||
|
# wasm-pack test --release --node
|
||||||
|
node test.js
|
||||||
39
.github/workflows/tests-debug.yml
vendored
Normal file
39
.github/workflows/tests-debug.yml
vendored
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
name: tests/debug
|
||||||
|
|
||||||
|
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: Fetch
|
||||||
|
run: cargo fetch
|
||||||
|
- name: Build (all features)
|
||||||
|
run: cargo build --all-features --frozen
|
||||||
|
- name: Build
|
||||||
|
run: cargo build --frozen
|
||||||
|
- name: Test no_std
|
||||||
|
run: cargo test --no-default-features --frozen
|
||||||
|
- name: Build only std
|
||||||
|
run: cargo build --example regorus --no-default-features --features "std" --frozen
|
||||||
|
- name: Doc Tests
|
||||||
|
run: cargo test --doc --frozen
|
||||||
|
- name: Run tests
|
||||||
|
run: cargo test --frozen
|
||||||
|
- name: Run tests (ACI)
|
||||||
|
run: cargo test --test aci --frozen
|
||||||
|
- name: Run tests (KATA)
|
||||||
|
run: cargo test --test kata --frozen
|
||||||
|
- name: Run tests (OPA Conformance)
|
||||||
|
run: >-
|
||||||
|
cargo test --test opa --frozen --features opa-testutil,serde_json/arbitrary_precision -- $(tr '\n' ' ' < tests/opa.passing)
|
||||||
24
.gitignore
vendored
24
.gitignore
vendored
@@ -1,10 +1,8 @@
|
|||||||
# Generated by Cargo
|
# Generated by Cargo
|
||||||
# will have compiled files and executables
|
# will have compiled files and executables
|
||||||
/target/
|
/target/
|
||||||
|
**/wheels/
|
||||||
# Remove Cargo.lock from gitignore if creating an executable, leave it for libraries
|
**/__pycache__/
|
||||||
# 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
|
# These are backup files generated by rustfmt
|
||||||
**/*.rs.bk
|
**/*.rs.bk
|
||||||
@@ -13,4 +11,20 @@ Cargo.lock
|
|||||||
.vscode/
|
.vscode/
|
||||||
|
|
||||||
# worktrees
|
# worktrees
|
||||||
worktrees/
|
worktrees/
|
||||||
|
|
||||||
|
# build folders
|
||||||
|
**/build
|
||||||
|
|
||||||
|
# Generated C# bindings
|
||||||
|
**/*.g.cs
|
||||||
|
|
||||||
|
# Generated C, C++ headers
|
||||||
|
bindings/ffi/regorus.h
|
||||||
|
bindings/ffi/regorus.ffi.hpp
|
||||||
|
|
||||||
|
bindings/*/target
|
||||||
|
|
||||||
|
# C# build folders
|
||||||
|
**bin
|
||||||
|
**obj
|
||||||
186
CHANGELOG.md
186
CHANGELOG.md
@@ -6,6 +6,191 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||||||
|
|
||||||
## [Unreleased]
|
## [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
|
||||||
|
- OPA v0.68.0. Engine::set_rego_v1 ([#305](https://github.com/microsoft/regorus/pull/305))
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
- Handle parsing corner cases ([#309](https://github.com/microsoft/regorus/pull/309))
|
||||||
|
- Propagate errors encountered in argument evaluation ([#308](https://github.com/microsoft/regorus/pull/308))
|
||||||
|
- Issues [#302](https://github.com/microsoft/regorus/pull/302), [#303](https://github.com/microsoft/regorus/pull/303) ([#304](https://github.com/microsoft/regorus/pull/304))
|
||||||
|
|
||||||
|
## [0.2.3](https://github.com/microsoft/regorus/compare/regorus-v0.2.2...regorus-v0.2.3) - 2024-08-16
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
- Match OPA behavior for split ([#295](https://github.com/microsoft/regorus/pull/295))
|
||||||
|
- Merge data to init document ([#293](https://github.com/microsoft/regorus/pull/293))
|
||||||
|
|
||||||
|
### Other
|
||||||
|
- Update cbindgen requirement from 0.26.0 to 0.27.0 ([#296](https://github.com/microsoft/regorus/pull/296))
|
||||||
|
- Bump rexml in /bindings/ruby in the bundler group across 1 directory ([#294](https://github.com/microsoft/regorus/pull/294))
|
||||||
|
- Update csbindgen requirement from =1.9.0 to =1.9.3 ([#292](https://github.com/microsoft/regorus/pull/292))
|
||||||
|
|
||||||
|
## [0.2.2](https://github.com/microsoft/regorus/compare/regorus-v0.2.1...regorus-v0.2.2) - 2024-07-28
|
||||||
|
|
||||||
|
### Added
|
||||||
|
- Update to opa v0.67.0 ([#286](https://github.com/microsoft/regorus/pull/286))
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
- Handle aliases in scheduler ([#285](https://github.com/microsoft/regorus/pull/285))
|
||||||
|
|
||||||
|
### Other
|
||||||
|
- Update readme ([#288](https://github.com/microsoft/regorus/pull/288))
|
||||||
|
- Update binding versions ([#287](https://github.com/microsoft/regorus/pull/287))
|
||||||
|
- build.rs create hooks dir if not exists ([#283](https://github.com/microsoft/regorus/pull/283))
|
||||||
|
- add extension_list example ([#281](https://github.com/microsoft/regorus/pull/281))
|
||||||
|
- Fix build break ([#278](https://github.com/microsoft/regorus/pull/278))
|
||||||
|
- Update pyo3 requirement from 0.21.0 to 0.22.0 ([#275](https://github.com/microsoft/regorus/pull/275))
|
||||||
|
- Update to OPA v0.66.0 ([#274](https://github.com/microsoft/regorus/pull/274))
|
||||||
|
|
||||||
|
## [0.2.1](https://github.com/microsoft/regorus/compare/regorus-v0.2.0...regorus-v0.2.1) - 2024-06-19
|
||||||
|
|
||||||
|
### Added
|
||||||
|
- get_policies: Way to obtain policy files and content ([#267](https://github.com/microsoft/regorus/pull/267))
|
||||||
|
|
||||||
|
### Other
|
||||||
|
- Fix c,cpp,no-std binding examples ([#272](https://github.com/microsoft/regorus/pull/272))
|
||||||
|
- Update binding versions for next release ([#270](https://github.com/microsoft/regorus/pull/270))
|
||||||
|
- rename method from 'Clone' to 'clone' in 'Engine' class to match the java naming convention and definiont in the of java.lang.Object. ([#268](https://github.com/microsoft/regorus/pull/268))
|
||||||
|
- Suppress clippy unused warning ([#269](https://github.com/microsoft/regorus/pull/269))
|
||||||
|
- Provide ability to get JSON representation of policy AST ([#266](https://github.com/microsoft/regorus/pull/266))
|
||||||
|
- Update OPA tests to v0.65.0 ([#264](https://github.com/microsoft/regorus/pull/264))
|
||||||
|
- Allow lexer to be used for other policy languages ([#262](https://github.com/microsoft/regorus/pull/262))
|
||||||
|
|
||||||
|
## [0.2.0](https://github.com/microsoft/regorus/compare/regorus-v0.1.5...regorus-v0.2.0) - 2024-05-30
|
||||||
|
|
||||||
|
### Other
|
||||||
|
- Add release-plz config to publish only regorus package ([#259](https://github.com/microsoft/regorus/pull/259))
|
||||||
|
- Revert "chore: release v0.2.0 ([#257](https://github.com/microsoft/regorus/pull/257))" ([#258](https://github.com/microsoft/regorus/pull/258))
|
||||||
|
- release v0.2.0 ([#257](https://github.com/microsoft/regorus/pull/257))
|
||||||
|
- Fix release-plz hash ([#256](https://github.com/microsoft/regorus/pull/256))
|
||||||
|
- non collections should evaluate to false ([#253](https://github.com/microsoft/regorus/pull/253))
|
||||||
|
- Fix merge issue ([#252](https://github.com/microsoft/regorus/pull/252))
|
||||||
|
- Update bindings to include newer APIs ([#250](https://github.com/microsoft/regorus/pull/250))
|
||||||
|
- update ruby bindings version to 0.1.5, bump deps ([#251](https://github.com/microsoft/regorus/pull/251))
|
||||||
|
- Use correct docsrs feature annotation ([#248](https://github.com/microsoft/regorus/pull/248))
|
||||||
|
- Lockdown kata test prints as well as prints of various values ([#249](https://github.com/microsoft/regorus/pull/249))
|
||||||
|
- Fix bindings and add CI tests ([#247](https://github.com/microsoft/regorus/pull/247))
|
||||||
|
- Add test-ruby CI for github actions ([#244](https://github.com/microsoft/regorus/pull/244))
|
||||||
|
- Update `README.md` for Java bindings to mention we don't publish to ([#246](https://github.com/microsoft/regorus/pull/246))
|
||||||
|
- Update itertools requirement from 0.12.1 to 0.13.0 ([#245](https://github.com/microsoft/regorus/pull/245))
|
||||||
|
- Update ruby bindings for add_policy and add_policy_from_file to return package name ([#240](https://github.com/microsoft/regorus/pull/240))
|
||||||
|
- Provide a way to obtain package names of loaded policies ([#239](https://github.com/microsoft/regorus/pull/239))
|
||||||
|
- `c_no_std` binding to show use in C freestanding environments. ([#238](https://github.com/microsoft/regorus/pull/238))
|
||||||
|
- Bump rexml in /bindings/ruby in the bundler group across 1 directory ([#236](https://github.com/microsoft/regorus/pull/236))
|
||||||
|
- Update prettydiff requirement from 0.6.4 to 0.7.0 ([#234](https://github.com/microsoft/regorus/pull/234))
|
||||||
|
- Update jsonschema requirement from 0.17.1 to 0.18.0 ([#235](https://github.com/microsoft/regorus/pull/235))
|
||||||
|
- no_std support ([#232](https://github.com/microsoft/regorus/pull/232))
|
||||||
|
- add `std` feature ([#231](https://github.com/microsoft/regorus/pull/231))
|
||||||
|
- Tests from MSFT fork of kata-containers ([#230](https://github.com/microsoft/regorus/pull/230))
|
||||||
|
- Use alloc, core instead of std ([#225](https://github.com/microsoft/regorus/pull/225))
|
||||||
|
|
||||||
|
## [0.1.5](https://github.com/microsoft/regorus/compare/regorus-v0.1.4...regorus-v0.1.5) - 2024-05-07
|
||||||
|
|
||||||
|
### Added
|
||||||
|
- Support policy files greater than 64KB in size ([#217](https://github.com/microsoft/regorus/pull/217))
|
||||||
|
- Add tests for kata containers policies ([#221](https://github.com/microsoft/regorus/pull/221))
|
||||||
|
- Support for OPA v0.64.0 ([#219](https://github.com/microsoft/regorus/pull/219))
|
||||||
|
- New builtin `json.marshal_with_options`
|
||||||
|
### Changed
|
||||||
|
- Improve example in readme ([#224](https://github.com/microsoft/regorus/pull/224))
|
||||||
|
### Fixed
|
||||||
|
- OPA Conformance: Do not interpret # within regular string ([#216](https://github.com/microsoft/regorus/pull/216))
|
||||||
|
|
||||||
|
## [0.1.4](https://github.com/microsoft/regorus/compare/regorus-v0.1.3...regorus-v0.1.4) - 2024-04-22
|
||||||
|
|
||||||
|
### Other
|
||||||
|
- early return ([#189](https://github.com/microsoft/regorus/pull/189))
|
||||||
|
- Fix anyhow dependency issues ([#208](https://github.com/microsoft/regorus/pull/208))
|
||||||
|
- remove unused compact-rc dependency ([#207](https://github.com/microsoft/regorus/pull/207))
|
||||||
|
|
||||||
|
## [0.1.3](https://github.com/microsoft/regorus/compare/regorus-v0.1.2...regorus-v0.1.3) - 2024-04-11
|
||||||
|
|
||||||
|
### Other
|
||||||
|
- Add a note in example to prefer eval_rule over eval_query ([#204](https://github.com/microsoft/regorus/pull/204))
|
||||||
|
- Do not enable serde_json/arbitrary_precision by default ([#203](https://github.com/microsoft/regorus/pull/203))
|
||||||
|
- Rewrite so that code compiles with chrono_tz 0.8.5 and 0.9.0 ([#201](https://github.com/microsoft/regorus/pull/201))
|
||||||
|
- update ruby bindings ([#200](https://github.com/microsoft/regorus/pull/200))
|
||||||
|
- Store Value instances in AST for strings, numbers and idents ([#197](https://github.com/microsoft/regorus/pull/197))
|
||||||
|
- :Value> and From<serde_yaml::Value> ([#196](https://github.com/microsoft/regorus/pull/196))
|
||||||
|
- Build dependency on git only if opa.runtime feature is enabled. ([#194](https://github.com/microsoft/regorus/pull/194))
|
||||||
|
- Update to opa v0.63.0 ([#192](https://github.com/microsoft/regorus/pull/192))
|
||||||
|
- Update pyo3 requirement from 0.20.2 to 0.21.0 ([#190](https://github.com/microsoft/regorus/pull/190))
|
||||||
|
- Ruby bindings for existing FFI methods, plus eval_rule() ([#188](https://github.com/microsoft/regorus/pull/188))
|
||||||
|
- Evaluate rules directly instead of queries ([#186](https://github.com/microsoft/regorus/pull/186))
|
||||||
|
- Remove cruft. ([#184](https://github.com/microsoft/regorus/pull/184))
|
||||||
|
|
||||||
## [0.1.2](https://github.com/microsoft/regorus/compare/regorus-v0.1.1...regorus-v0.1.2) - 2024-03-22
|
## [0.1.2](https://github.com/microsoft/regorus/compare/regorus-v0.1.1...regorus-v0.1.2) - 2024-03-22
|
||||||
|
|
||||||
### Other
|
### Other
|
||||||
@@ -277,3 +462,4 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||||||
- LICENSE committed
|
- LICENSE committed
|
||||||
- CODE_OF_CONDUCT.md committed
|
- CODE_OF_CONDUCT.md committed
|
||||||
- Initial commit
|
- Initial commit
|
||||||
|
|
||||||
|
|||||||
1778
Cargo.lock
generated
Normal file
1778
Cargo.lock
generated
Normal file
File diff suppressed because it is too large
Load Diff
119
Cargo.toml
119
Cargo.toml
@@ -1,20 +1,17 @@
|
|||||||
[workspace]
|
[workspace]
|
||||||
|
|
||||||
members = [
|
members = [
|
||||||
"bindings/ffi",
|
"tests/ensure_no_std",
|
||||||
"bindings/python",
|
|
||||||
"bindings/wasm",
|
|
||||||
"bindings/java",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
[package]
|
[package]
|
||||||
name = "regorus"
|
name = "regorus"
|
||||||
description = "A fast, lightweight Rego (OPA policy language) interpreter"
|
description = "A fast, lightweight Rego (OPA policy language) interpreter"
|
||||||
version = "0.1.2"
|
version = "0.4.0"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
license-file = "LICENSE"
|
license-file = "LICENSE"
|
||||||
repository = "https://github.com/microsoft/regorus"
|
repository = "https://github.com/microsoft/regorus"
|
||||||
keywords = ["interpreter", "opa", "policy-as-code", "rego"]
|
keywords = ["interpreter", "no_std", "opa", "policy-as-code", "rego"]
|
||||||
|
|
||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
@@ -25,23 +22,25 @@ doctest = false
|
|||||||
default = ["full-opa", "arc"]
|
default = ["full-opa", "arc"]
|
||||||
|
|
||||||
arc = ["scientific/arc"]
|
arc = ["scientific/arc"]
|
||||||
|
ast = []
|
||||||
base64 = ["dep:data-encoding"]
|
base64 = ["dep:data-encoding"]
|
||||||
base64url = ["dep:data-encoding"]
|
base64url = ["dep:data-encoding"]
|
||||||
coverage = []
|
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 = []
|
deprecated = []
|
||||||
hex = ["dep:data-encoding"]
|
hex = ["dep:data-encoding"]
|
||||||
http = []
|
http = []
|
||||||
jwt = ["dep:jsonwebtoken", "dep:data-encoding"]
|
glob = ["dep:globset"]
|
||||||
glob = ["dep:wax"]
|
|
||||||
graph = []
|
graph = []
|
||||||
jsonschema = ["dep:jsonschema"]
|
jsonschema = ["dep:jsonschema"]
|
||||||
|
no_std = ["lazy_static/spin_no_std"]
|
||||||
opa-runtime = []
|
opa-runtime = []
|
||||||
regex = ["dep:regex"]
|
regex = ["dep:regex"]
|
||||||
semver = ["dep:semver"]
|
semver = ["dep:semver"]
|
||||||
|
std = ["rand/std", "rand/std_rng", "serde_json/std"]
|
||||||
|
time = ["dep:chrono", "dep:chrono-tz"]
|
||||||
uuid = ["dep:uuid"]
|
uuid = ["dep:uuid"]
|
||||||
urlquery = ["dep:url"]
|
urlquery = ["dep:url"]
|
||||||
time = ["dep:chrono", "dep:chrono-tz"]
|
|
||||||
yaml = ["serde_yaml"]
|
yaml = ["serde_yaml"]
|
||||||
full-opa = [
|
full-opa = [
|
||||||
"base64",
|
"base64",
|
||||||
@@ -53,67 +52,90 @@ full-opa = [
|
|||||||
"graph",
|
"graph",
|
||||||
"hex",
|
"hex",
|
||||||
"http",
|
"http",
|
||||||
"jwt",
|
|
||||||
"jsonschema",
|
"jsonschema",
|
||||||
"opa-runtime",
|
"opa-runtime",
|
||||||
"regex",
|
"regex",
|
||||||
"semver",
|
"semver",
|
||||||
|
"std",
|
||||||
"time",
|
"time",
|
||||||
"uuid",
|
"uuid",
|
||||||
"urlquery",
|
"urlquery",
|
||||||
"yaml"
|
"yaml",
|
||||||
|
|
||||||
|
#"rego-extensions"
|
||||||
]
|
]
|
||||||
|
|
||||||
|
# Features that can be used in no_std environments.
|
||||||
|
# Note that: the spin_no_std feature in lazy_static must be specified.
|
||||||
|
opa-no-std = [
|
||||||
|
"arc",
|
||||||
|
"base64",
|
||||||
|
"base64url",
|
||||||
|
"coverage",
|
||||||
|
"crypto",
|
||||||
|
"deprecated",
|
||||||
|
"graph",
|
||||||
|
"hex",
|
||||||
|
"no_std",
|
||||||
|
"opa-runtime",
|
||||||
|
"regex",
|
||||||
|
"semver",
|
||||||
|
# Configure lazy_static to use spinlocks.
|
||||||
|
"lazy_static/spin_no_std"
|
||||||
|
]
|
||||||
|
|
||||||
|
# Rego language extensions
|
||||||
|
rego-extensions = []
|
||||||
|
|
||||||
# This feature enables some testing utils for OPA tests.
|
# This feature enables some testing utils for OPA tests.
|
||||||
opa-testutil = []
|
opa-testutil = []
|
||||||
|
rand = ["dep:rand"]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
anyhow = {version = "1.0.66", features = ["backtrace"] }
|
anyhow = { version = "1.0.45", default-features = false }
|
||||||
serde = {version = "1.0.150", features = ["derive", "rc"] }
|
serde = {version = "1.0.150", default-features = false, features = ["derive", "rc"] }
|
||||||
serde_json = {version = "1.0.89", features = ["arbitrary_precision"] }
|
serde_json = { version = "1.0.89", default-features = false, features = ["alloc"] }
|
||||||
serde_yaml = {version = "0.9.16", optional = true }
|
lazy_static = { version = "1.4.0", default-features = false }
|
||||||
log = "0.4.17"
|
|
||||||
env_logger="0.11.1"
|
|
||||||
lazy_static = "1.4.0"
|
|
||||||
rand = "0.8.5"
|
|
||||||
num = "0.4.1"
|
|
||||||
|
|
||||||
# Crypto
|
# Crypto
|
||||||
constant_time_eq = {version = "0.3.0", optional = true}
|
constant_time_eq = {version = "0.4.0", optional = true, default-features = false }
|
||||||
hmac = {version = "0.12.1", optional = true}
|
hmac = {version = "0.12.1", optional = true, default-features = false}
|
||||||
sha2 = {version= "0.10.8", optional = true}
|
sha2 = {version= "0.10.8", optional = true, default-features = false }
|
||||||
hex = {version = "0.4.3", optional = true}
|
hex = {version = "0.4.3", optional = true, default-features = false, features = ["alloc"] }
|
||||||
sha1 = {version = "0.10.6", optional = true}
|
md-5 = {version = "0.10.6", optional = true, default-features = false }
|
||||||
md-5 = {version = "0.10.6", optional = true}
|
|
||||||
|
|
||||||
data-encoding = { version = "2.4.0", optional = true }
|
data-encoding = { version = "2.8.0", optional = true, default-features=false, features = ["alloc"] }
|
||||||
scientific = { version = "0.5.2" }
|
scientific = { version = "0.5.3" }
|
||||||
|
|
||||||
regex = {version = "1.10.2", optional = true}
|
globset = { version = "0.4.16", features = ["simd-accel"], default-features = false, optional = true }
|
||||||
semver = {version = "1.0.20", optional = true}
|
regex = {version = "1.11.1", optional = true, default-features = false }
|
||||||
wax = { version = "0.6.0", features = [], default-features = false, optional = true }
|
semver = {version = "1.0.25", optional = true, default-features = false }
|
||||||
url = { version = "2.5.0", optional = true }
|
url = { version = "2.5.4", optional = true }
|
||||||
uuid = { version = "1.6.1", features = ["v4", "fast-rng"], optional = true }
|
uuid = { version = "1.15.1", default-features = false, features = ["v4", "fast-rng"], optional = true }
|
||||||
jsonschema = { version = "0.17.1", default-features = false, optional = true }
|
jsonschema = { version = "0.29.0", default-features = false, optional = true }
|
||||||
chrono = { version = "0.4.31", optional = true }
|
chrono = { version = "0.4.40", optional = true }
|
||||||
chrono-tz = { version = "0.8.5", optional = true }
|
chrono-tz = { version = "0.10.1", optional = true }
|
||||||
compact-rc = "0.5.2"
|
|
||||||
jsonwebtoken = { version = "9.2.0", optional = true }
|
serde_yaml = {version = "0.9.16", default-features = false, optional = true }
|
||||||
itertools = "0.12.1"
|
# 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]
|
[dev-dependencies]
|
||||||
|
anyhow = "1.0.45"
|
||||||
cfg-if = "1.0.0"
|
cfg-if = "1.0.0"
|
||||||
clap = { version = "4.4.7", features = ["derive"] }
|
clap = { version = "4.5.36", features = ["derive"] }
|
||||||
colored-diff = "0.2.3"
|
prettydiff = { version = "0.8.0", default-features = false }
|
||||||
serde_yaml = "0.9.16"
|
serde_yaml = "0.9.16"
|
||||||
test-generator = "0.3.1"
|
test-generator = "0.3.1"
|
||||||
walkdir = "2.3.2"
|
walkdir = "2.3.2"
|
||||||
|
|
||||||
[build-dependencies]
|
[build-dependencies]
|
||||||
anyhow = "1.0.66"
|
anyhow = "1.0"
|
||||||
|
|
||||||
[profile.release]
|
[profile.release]
|
||||||
debug = true
|
debug = true
|
||||||
|
lto = true
|
||||||
|
codegen-units = 1
|
||||||
|
|
||||||
[[test]]
|
[[test]]
|
||||||
name="opa"
|
name="opa"
|
||||||
@@ -126,6 +148,17 @@ name="aci"
|
|||||||
harness=false
|
harness=false
|
||||||
test=false
|
test=false
|
||||||
|
|
||||||
|
[[test]]
|
||||||
|
name="kata"
|
||||||
|
harness=false
|
||||||
|
test=false
|
||||||
|
|
||||||
|
[[example]]
|
||||||
|
name="regorus"
|
||||||
|
harness=false
|
||||||
|
test=false
|
||||||
|
doctest=false
|
||||||
|
|
||||||
[package.metadata.docs.rs]
|
[package.metadata.docs.rs]
|
||||||
# To build locally:
|
# To build locally:
|
||||||
# RUSTDOCFLAGS="--cfg docsrs" cargo +nightly doc --all-features --no-deps
|
# RUSTDOCFLAGS="--cfg docsrs" cargo +nightly doc --all-features --no-deps
|
||||||
|
|||||||
115
README.md
115
README.md
@@ -8,12 +8,13 @@
|
|||||||
|
|
||||||
Regorus is also
|
Regorus is also
|
||||||
- *cross-platform* - Written in platform-agnostic Rust.
|
- *cross-platform* - Written in platform-agnostic Rust.
|
||||||
- *current* - We strive to keep Regorus up to date with latest OPA release. Regorus supports `import rego.v1`.
|
- *no_std compatible* - Regorus can be used in `no_std` environments too. Most of the builtins are supported.
|
||||||
- *compliant* - Regorus is mostly compliant with the latest [OPA release v0.62.0](https://github.com/open-policy-agent/opa/releases/tag/v0.62.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.
|
- *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).
|
See [add_extension](https://github.com/microsoft/regorus/blob/fc68bf9c8bea36427dae9401a7d1f6ada771f7ab/src/engine.rs#L352).
|
||||||
Support for extensibility using other languages coming soon.
|
Support for extensibility using other languages coming soon.
|
||||||
- *polyglot* - In addition to Rust, Regorus can be used from *C*, *C++*, *C#*, *Golang*, *Java*, *Javascript* and *Python*.
|
- *polyglot* - In addition to Rust, Regorus can be used from *C*, *C++*, *C#*, *Golang*, *Java*, *Javascript*, *Python*, and *Ruby*.
|
||||||
This is made possible by the excellent FFI tools available in the Rust ecosystem. See [bindings](#bindings) for information on how to use Regorus from different languages.
|
This is made possible by the excellent FFI tools available in the Rust ecosystem. See [bindings](#bindings) for information on how to use Regorus from different languages.
|
||||||
|
|
||||||
To try out a *Javascript(WASM)* compiled version of Regorus from your browser, visit [Regorus Playground](https://anakrish.github.io/regorus-playground/).
|
To try out a *Javascript(WASM)* compiled version of Regorus from your browser, visit [Regorus Playground](https://anakrish.github.io/regorus-playground/).
|
||||||
@@ -24,31 +25,59 @@ Regorus is available as a library that can be easily integrated into your Rust p
|
|||||||
Here is an example of evaluating a simple Rego policy:
|
Here is an example of evaluating a simple Rego policy:
|
||||||
|
|
||||||
```rust
|
```rust
|
||||||
use anyhow::Result;
|
fn main() -> anyhow::Result<()> {
|
||||||
use regorus::*;
|
// Create an engine for evaluating Rego policies.
|
||||||
use serde_json;
|
let mut engine = regorus::Engine::new();
|
||||||
|
|
||||||
fn main() -> Result<()> {
|
let policy = String::from(
|
||||||
// Create an engine for evaluating Rego policies.
|
r#"
|
||||||
let mut engine = Engine::new();
|
package example
|
||||||
|
|
||||||
// Add policy to the engine.
|
allow if {
|
||||||
engine.add_policy(
|
## All actions are allowed for admins.
|
||||||
// Filename to be associated with the policy.
|
input.principal == "admin"
|
||||||
"hello.rego".to_string(),
|
} else if {
|
||||||
|
## Check if action is allowed for given user.
|
||||||
|
input.action in data.allowed_actions[input.principal]
|
||||||
|
}
|
||||||
|
"#,
|
||||||
|
);
|
||||||
|
|
||||||
// Rego policy that just sets a message.
|
// Add policy to the engine.
|
||||||
r#"
|
engine.add_policy(String::from("policy.rego"), policy)?;
|
||||||
package test
|
|
||||||
message = "Hello, World!"
|
|
||||||
"#.to_string()
|
|
||||||
)?;
|
|
||||||
|
|
||||||
// Evaluate the policy, fetch the message and print it.
|
// Add data to engine.
|
||||||
let results = engine.eval_query("data.test.message".to_string(), false)?;
|
engine.add_data(regorus::Value::from_json_str(
|
||||||
println!("{}", serde_json::to_string_pretty(&results)?);
|
r#"{
|
||||||
|
"allowed_actions": {
|
||||||
|
"user1" : ["read", "write"],
|
||||||
|
"user2" : ["read"]
|
||||||
|
}}"#,
|
||||||
|
)?)?;
|
||||||
|
|
||||||
Ok(())
|
// Set input and evaluate whether user1 can write.
|
||||||
|
engine.set_input(regorus::Value::from_json_str(
|
||||||
|
r#"{
|
||||||
|
"principal": "user1",
|
||||||
|
"action": "write"
|
||||||
|
}"#,
|
||||||
|
)?);
|
||||||
|
|
||||||
|
let r = engine.eval_rule(String::from("data.example.allow"))?;
|
||||||
|
assert_eq!(r, regorus::Value::from(true));
|
||||||
|
|
||||||
|
// Set input and evaluate whether user2 can write.
|
||||||
|
engine.set_input(regorus::Value::from_json_str(
|
||||||
|
r#"{
|
||||||
|
"principal": "user2",
|
||||||
|
"action": "write"
|
||||||
|
}"#,
|
||||||
|
)?);
|
||||||
|
|
||||||
|
let r = engine.eval_rule(String::from("data.example.allow"))?;
|
||||||
|
assert_eq!(r, regorus::Value::Undefined);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -56,20 +85,20 @@ Regorus is designed with [Confidential Computing](https://confidentialcomputing.
|
|||||||
it is important to be able to control exactly what is being run. Regorus allows enabling and disabling various components using cargo
|
it is important to be able to control exactly what is being run. Regorus allows enabling and disabling various components using cargo
|
||||||
features. By default all features are enabled.
|
features. By default all features are enabled.
|
||||||
|
|
||||||
The default build of regorus example program is 6.4M:
|
The default build of regorus example program is 6.3M:
|
||||||
```bash
|
```bash
|
||||||
$ cargo build -r --example regorus; strip target/release/examples/regorus; ls -lh target/release/examples/regorus
|
$ cargo build -r --example regorus; strip target/release/examples/regorus; ls -lh target/release/examples/regorus
|
||||||
-rwxr-xr-x 1 anand staff 6.4M Jan 19 11:23 target/release/examples/regorus*
|
-rwxr-xr-x 1 anand staff 6.3M May 11 22:03 target/release/examples/regorus*
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
When all features except for `yaml` are disabled, the binary size drops down to 2.9M.
|
When all default features are disabled, the binary size drops down to 1.9M.
|
||||||
```bash
|
```bash
|
||||||
$ cargo build -r --example regorus --features "yaml" --no-default-features; strip target/release/examples/regorus; ls -lh target/release/examples/regorus
|
$ cargo build -r --example regorus --no-default-features; strip target/release/examples/regorus; ls -lh target/release/examples/regorus
|
||||||
-rwxr-xr-x 1 anand staff 2.9M Jan 19 11:26 target/release/examples/regorus*
|
-rwxr-xr-x 1 anand staff 1.9M May 11 22:04 target/release/examples/regorus*
|
||||||
```
|
```
|
||||||
|
|
||||||
Regorus passes the [OPA v0.61.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.
|
builtins. See [OPA Conformance](#opa-conformance) below.
|
||||||
|
|
||||||
## Bindings
|
## Bindings
|
||||||
@@ -78,10 +107,11 @@ Regorus can be used from a variety of languages:
|
|||||||
|
|
||||||
- *C*: C binding is generated using [cbindgen](https://github.com/mozilla/cbindgen).
|
- *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
|
[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).
|
- *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
|
[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.
|
- *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.
|
- *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).
|
- *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).
|
||||||
@@ -90,6 +120,8 @@ Regorus can be used from a variety of languages:
|
|||||||
- *Javascript*: Regorus is compiled to WASM using [wasmpack](https://github.com/rustwasm/wasm-pack).
|
- *Javascript*: Regorus is compiled to WASM using [wasmpack](https://github.com/rustwasm/wasm-pack).
|
||||||
See [bindings/wasm](https://github.com/microsoft/regorus/tree/main/bindings/wasm) for an example of using Regorus from nodejs.
|
See [bindings/wasm](https://github.com/microsoft/regorus/tree/main/bindings/wasm) for an example of using Regorus from nodejs.
|
||||||
To try out a *Javascript(WASM)* compiled version of Regorus from your browser, visit [Regorus Playground](https://anakrish.github.io/regorus-playground/).
|
To try out a *Javascript(WASM)* compiled version of Regorus from your browser, visit [Regorus Playground](https://anakrish.github.io/regorus-playground/).
|
||||||
|
- *Ruby*: Ruby bindings are developed using [magnus](https://github.com/matsadler/magnus).
|
||||||
|
See [bindings/ruby](https://github.com/microsoft/regorus/tree/main/bindings/ruby).
|
||||||
|
|
||||||
To avoid operational overhead, we currently don't publish these bindings to various repositories.
|
To avoid operational overhead, we currently don't publish these bindings to various repositories.
|
||||||
It is straight-forward to build these bindings yourself.
|
It is straight-forward to build these bindings yourself.
|
||||||
@@ -151,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)):
|
(borrowed from [Rego tutorial](https://www.openpolicyagent.org/docs/latest/#2-try-opa-eval)):
|
||||||
|
|
||||||
```bash
|
```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)
|
Finally, evaluate real-world [policies](tests/aci/) used in Azure Container Instances (ACI)
|
||||||
@@ -171,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.
|
We can try it out using the `regorus` example program by passing in the `--coverage` flag.
|
||||||
|
|
||||||
```shell
|
```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.
|
It produces the following coverage report which shows that all lines are executed except the line that sets `allow` to true.
|
||||||
@@ -179,7 +211,7 @@ It produces the following coverage report which shows that all lines are execute
|
|||||||

|

|
||||||
|
|
||||||
See [Engine::get_coverage_report](https://docs.rs/regorus/latest/regorus/struct.Engine.html#method.get_coverage_report) for details.
|
See [Engine::get_coverage_report](https://docs.rs/regorus/latest/regorus/struct.Engine.html#method.get_coverage_report) for details.
|
||||||
Policy coverage information is useful for debugging your policy as well as to write tests for your policy so that all
|
Policy coverage information is useful for debugging your policy as well as to write tests for your policy so that all
|
||||||
lines of the policy are exercised by the tests.
|
lines of the policy are exercised by the tests.
|
||||||
|
|
||||||
## ACI Policies
|
## ACI Policies
|
||||||
@@ -243,20 +275,19 @@ Benchmark 1: opa eval -b tests/aci -d tests/aci/data.json -i tests/aci/input.jso
|
|||||||
```
|
```
|
||||||
## OPA Conformance
|
## OPA Conformance
|
||||||
|
|
||||||
Regorus has been verified to be compliant with [OPA v0.61.0](https://github.com/open-policy-agent/opa/releases/tag/v0.61.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
|
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.
|
||||||
are produced.
|
|
||||||
|
|
||||||
The test driver can be invoked by running:
|
The test driver can be invoked by running:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
$ cargo test -r --test opa
|
$ cargo test -r --test opa --features opa-testutil,serde_json/arbitrary_precision
|
||||||
```
|
```
|
||||||
|
|
||||||
Currently, Regorus passes all the non-builtin specific tests.
|
Currently, Regorus passes all the non-builtin specific tests.
|
||||||
See [passing tests suites](https://github.com/microsoft/regorus/blob/main/tests/opa.passing).
|
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`
|
- `cryptoparsersaprivatekeys`
|
||||||
- `cryptox509parseandverifycertificates`
|
- `cryptox509parseandverifycertificates`
|
||||||
- `cryptox509parsecertificaterequest`
|
- `cryptox509parsecertificaterequest`
|
||||||
@@ -267,8 +298,11 @@ The following test suites don't pass fully due to mising builtins:
|
|||||||
- `graphql`
|
- `graphql`
|
||||||
- `invalidkeyerror`
|
- `invalidkeyerror`
|
||||||
- `jsonpatch`
|
- `jsonpatch`
|
||||||
|
- `jwtbuiltins`
|
||||||
- `jwtdecodeverify`
|
- `jwtdecodeverify`
|
||||||
- `jwtencodesign`
|
- `jwtencodesign`
|
||||||
|
- `jwtencodesignheadererrors`
|
||||||
|
- `jwtencodesignpayloaderrors`
|
||||||
- `jwtencodesignraw`
|
- `jwtencodesignraw`
|
||||||
- `jwtverifyhs256`
|
- `jwtverifyhs256`
|
||||||
- `jwtverifyhs384`
|
- `jwtverifyhs384`
|
||||||
@@ -290,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).
|
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
|
### Grammar
|
||||||
|
|
||||||
|
|||||||
44
bindings/c-nostd/CMakeLists.txt
Normal file
44
bindings/c-nostd/CMakeLists.txt
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
# Copyright (c) Microsoft
|
||||||
|
# Licensed under the MIT License.
|
||||||
|
|
||||||
|
cmake_minimum_required(VERSION 3.12 FATAL_ERROR)
|
||||||
|
include(FetchContent)
|
||||||
|
|
||||||
|
FetchContent_Declare(
|
||||||
|
Corrosion
|
||||||
|
GIT_REPOSITORY https://github.com/corrosion-rs/corrosion.git
|
||||||
|
# Use a tag that has a fix for https://github.com/corrosion-rs/corrosion/issues/590
|
||||||
|
GIT_TAG 6be991bb34c348dfb8344be22f3606288ea5c7fd
|
||||||
|
)
|
||||||
|
FetchContent_MakeAvailable(Corrosion)
|
||||||
|
|
||||||
|
project("regorus-test")
|
||||||
|
|
||||||
|
corrosion_import_crate(
|
||||||
|
# Path to <regorus-source-folder>/bindings/ffi/Cargo.toml
|
||||||
|
MANIFEST_PATH "../ffi/Cargo.toml"
|
||||||
|
# Always build regorus in Release mode.
|
||||||
|
PROFILE "release"
|
||||||
|
# Only build the "regorus-ffi" crate.
|
||||||
|
CRATES "regorus-ffi"
|
||||||
|
|
||||||
|
# Turn off std support in regorus-ffi.
|
||||||
|
NO_DEFAULT_FEATURES
|
||||||
|
NO_STD
|
||||||
|
|
||||||
|
# custom_allocator allows using a custom memory allocator.
|
||||||
|
# To use malloc/free remove custom_allocator below.
|
||||||
|
# Additionally, select specific features in regorus.
|
||||||
|
# See regorus/opa_no_std
|
||||||
|
FEATURES "custom_allocator,regorus/semver"
|
||||||
|
|
||||||
|
LOCKED
|
||||||
|
|
||||||
|
# Link statically
|
||||||
|
CRATE_TYPES staticlib FLAGS --crate-type=staticlib
|
||||||
|
)
|
||||||
|
|
||||||
|
add_executable(regorus_test main.c)
|
||||||
|
# Add path to <regorus-source-folder>/bindings/ffi
|
||||||
|
target_include_directories(regorus_test PRIVATE "../ffi")
|
||||||
|
target_link_libraries(regorus_test regorus_ffi)
|
||||||
103
bindings/c-nostd/main.c
Normal file
103
bindings/c-nostd/main.c
Normal file
@@ -0,0 +1,103 @@
|
|||||||
|
#include <stdio.h>
|
||||||
|
#include "regorus.h"
|
||||||
|
|
||||||
|
|
||||||
|
// Regorus has been built for no_std and cannot access files.
|
||||||
|
char* file_to_string(const char* file) {
|
||||||
|
char * buffer = 0;
|
||||||
|
long length;
|
||||||
|
FILE * f = fopen (file, "rb");
|
||||||
|
|
||||||
|
if (f)
|
||||||
|
{
|
||||||
|
fseek (f, 0, SEEK_END);
|
||||||
|
length = ftell (f);
|
||||||
|
fseek (f, 0, SEEK_SET);
|
||||||
|
buffer = malloc (length + 1);
|
||||||
|
buffer[length] = '\0';
|
||||||
|
if (buffer)
|
||||||
|
{
|
||||||
|
fread (buffer, 1, length, f);
|
||||||
|
}
|
||||||
|
fclose (f);
|
||||||
|
}
|
||||||
|
|
||||||
|
return buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If regorus is built with custom-allocator, then provide implementation.
|
||||||
|
uint8_t* regorus_aligned_alloc(size_t alignment, size_t size) {
|
||||||
|
return (uint8_t*) aligned_alloc(alignment, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
void regorus_free(uint8_t* ptr) {
|
||||||
|
free(ptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
// Create engine.
|
||||||
|
RegorusEngine* engine = regorus_engine_new();
|
||||||
|
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);
|
||||||
|
if (r.status != RegorusStatusOk)
|
||||||
|
goto error;
|
||||||
|
printf("Loaded package %s\n", r.output);
|
||||||
|
regorus_result_drop(r);
|
||||||
|
|
||||||
|
r = regorus_engine_add_policy(engine, "api.rego", (buffer = file_to_string("../../../tests/aci/api.rego")));
|
||||||
|
free(buffer);
|
||||||
|
if (r.status != RegorusStatusOk)
|
||||||
|
goto error;
|
||||||
|
printf("Loaded package %s\n", r.output);
|
||||||
|
regorus_result_drop(r);
|
||||||
|
|
||||||
|
r = regorus_engine_add_policy(engine, "policy.rego", (buffer = file_to_string("../../../tests/aci/policy.rego")));
|
||||||
|
free(buffer);
|
||||||
|
if (r.status != RegorusStatusOk)
|
||||||
|
goto error;
|
||||||
|
printf("Loaded package %s\n", r.output);
|
||||||
|
regorus_result_drop(r);
|
||||||
|
|
||||||
|
// Add data
|
||||||
|
r = regorus_engine_add_data_json(engine, (buffer = file_to_string("../../../tests/aci/data.json")));
|
||||||
|
free(buffer);
|
||||||
|
if (r.status != RegorusStatusOk)
|
||||||
|
goto error;
|
||||||
|
regorus_result_drop(r);
|
||||||
|
|
||||||
|
// Set input
|
||||||
|
r = regorus_engine_set_input_json(engine, (buffer = file_to_string("../../../tests/aci/input.json")));
|
||||||
|
free(buffer);
|
||||||
|
if (r.status != RegorusStatusOk)
|
||||||
|
goto error;
|
||||||
|
regorus_result_drop(r);
|
||||||
|
|
||||||
|
// Eval rule.
|
||||||
|
r = regorus_engine_eval_rule(engine, "data.framework.mount_overlay");
|
||||||
|
if (r.status != RegorusStatusOk)
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
// Print output
|
||||||
|
printf("%s", r.output);
|
||||||
|
regorus_result_drop(r);
|
||||||
|
|
||||||
|
|
||||||
|
// Free the engine.
|
||||||
|
regorus_engine_drop(engine);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
error:
|
||||||
|
printf("%s", r.error_message);
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
@@ -7,7 +7,8 @@ include(FetchContent)
|
|||||||
FetchContent_Declare(
|
FetchContent_Declare(
|
||||||
Corrosion
|
Corrosion
|
||||||
GIT_REPOSITORY https://github.com/corrosion-rs/corrosion.git
|
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)
|
FetchContent_MakeAvailable(Corrosion)
|
||||||
|
|
||||||
@@ -18,10 +19,19 @@ corrosion_import_crate(
|
|||||||
MANIFEST_PATH "../ffi/Cargo.toml"
|
MANIFEST_PATH "../ffi/Cargo.toml"
|
||||||
# Always build regorus in Release mode.
|
# Always build regorus in Release mode.
|
||||||
PROFILE "release"
|
PROFILE "release"
|
||||||
# Only build the "regorusc" crate.
|
# Only build the "regorus-ffi" crate.
|
||||||
CRATES "regorus-ffi")
|
CRATES "regorus-ffi"
|
||||||
|
|
||||||
|
# Select specific features in regorus.
|
||||||
|
FEATURES "regorus/semver"
|
||||||
|
|
||||||
|
LOCKED
|
||||||
|
|
||||||
|
# Link statically
|
||||||
|
CRATE_TYPES "cdylib"
|
||||||
|
)
|
||||||
|
|
||||||
add_executable(regorus_test main.c)
|
add_executable(regorus_test main.c)
|
||||||
# Add path to <regorus-source-folder>/bindings/ffi
|
# Add path to <regorus-source-folder>/bindings/ffi
|
||||||
target_include_directories(regorus_test PRIVATE "../ffi")
|
target_include_directories(regorus_test PRIVATE "../ffi")
|
||||||
target_link_libraries(regorus_test regorus-ffi)
|
target_link_libraries(regorus_test regorus_ffi)
|
||||||
|
|||||||
@@ -6,20 +6,28 @@ int main() {
|
|||||||
RegorusEngine* engine = regorus_engine_new();
|
RegorusEngine* engine = regorus_engine_new();
|
||||||
RegorusResult r;
|
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.
|
// Load policies.
|
||||||
r = regorus_engine_add_policy_from_file(engine, "../../../tests/aci/framework.rego");
|
r = regorus_engine_add_policy_from_file(engine, "../../../tests/aci/framework.rego");
|
||||||
if (r.status != RegorusStatusOk)
|
if (r.status != RegorusStatusOk)
|
||||||
goto error;
|
goto error;
|
||||||
|
printf("Loaded package %s\n", r.output);
|
||||||
regorus_result_drop(r);
|
regorus_result_drop(r);
|
||||||
|
|
||||||
r = regorus_engine_add_policy_from_file(engine, "../../../tests/aci/api.rego");
|
r = regorus_engine_add_policy_from_file(engine, "../../../tests/aci/api.rego");
|
||||||
if (r.status != RegorusStatusOk)
|
if (r.status != RegorusStatusOk)
|
||||||
goto error;
|
goto error;
|
||||||
|
printf("Loaded package %s\n", r.output);
|
||||||
regorus_result_drop(r);
|
regorus_result_drop(r);
|
||||||
|
|
||||||
r = regorus_engine_add_policy_from_file(engine, "../../../tests/aci/policy.rego");
|
r = regorus_engine_add_policy_from_file(engine, "../../../tests/aci/policy.rego");
|
||||||
if (r.status != RegorusStatusOk)
|
if (r.status != RegorusStatusOk)
|
||||||
goto error;
|
goto error;
|
||||||
|
printf("Loaded package %s\n", r.output);
|
||||||
regorus_result_drop(r);
|
regorus_result_drop(r);
|
||||||
|
|
||||||
// Add data
|
// Add data
|
||||||
@@ -34,22 +42,61 @@ int main() {
|
|||||||
goto error;
|
goto error;
|
||||||
regorus_result_drop(r);
|
regorus_result_drop(r);
|
||||||
|
|
||||||
// Eval query
|
// Eval rule.
|
||||||
r = regorus_engine_eval_query(engine, "data.framework.mount_overlay=x");
|
r = regorus_engine_eval_query(engine, "data.framework.mount_overlay");
|
||||||
if (r.status != RegorusStatusOk)
|
if (r.status != RegorusStatusOk)
|
||||||
goto error;
|
goto error;
|
||||||
|
|
||||||
// Print output
|
// Print output
|
||||||
printf("%s", r.output);
|
printf("%s\n", r.output);
|
||||||
regorus_result_drop(r);
|
regorus_result_drop(r);
|
||||||
|
|
||||||
|
|
||||||
// Free the engine.
|
// Free the engine.
|
||||||
regorus_engine_drop(engine);
|
regorus_engine_drop(engine);
|
||||||
|
|
||||||
|
// Create another engine.
|
||||||
|
engine = regorus_engine_new();
|
||||||
|
|
||||||
|
r = regorus_engine_add_policy(
|
||||||
|
engine,
|
||||||
|
"test.rego",
|
||||||
|
"package test\n"
|
||||||
|
"x = 1\n"
|
||||||
|
"message = `Hello`"
|
||||||
|
);
|
||||||
|
|
||||||
|
// Evaluate rule.
|
||||||
|
if (r.status != RegorusStatusOk)
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
r = regorus_engine_set_enable_coverage(engine, true);
|
||||||
|
regorus_result_drop(r);
|
||||||
|
|
||||||
|
r = regorus_engine_eval_query(engine, "data.test.message");
|
||||||
|
if (r.status != RegorusStatusOk)
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
// Print output
|
||||||
|
printf("%s\n", r.output);
|
||||||
|
regorus_result_drop(r);
|
||||||
|
|
||||||
|
// Print pretty coverage report.
|
||||||
|
r = regorus_engine_get_coverage_report_pretty(engine);
|
||||||
|
if (r.status != RegorusStatusOk)
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
printf("%s\n", r.output);
|
||||||
|
regorus_result_drop(r);
|
||||||
|
|
||||||
|
// Free the engine.
|
||||||
|
regorus_engine_drop(engine);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
error:
|
error:
|
||||||
printf("%s", r.error_message);
|
printf("%s", r.error_message);
|
||||||
|
regorus_result_drop(r);
|
||||||
|
regorus_engine_drop(engine);
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,7 +7,8 @@ include(FetchContent)
|
|||||||
FetchContent_Declare(
|
FetchContent_Declare(
|
||||||
Corrosion
|
Corrosion
|
||||||
GIT_REPOSITORY https://github.com/corrosion-rs/corrosion.git
|
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)
|
FetchContent_MakeAvailable(Corrosion)
|
||||||
|
|
||||||
@@ -19,10 +20,18 @@ corrosion_import_crate(
|
|||||||
MANIFEST_PATH "../ffi/Cargo.toml"
|
MANIFEST_PATH "../ffi/Cargo.toml"
|
||||||
# Always build regorus in Release mode.
|
# Always build regorus in Release mode.
|
||||||
PROFILE "release"
|
PROFILE "release"
|
||||||
# Only build the "regorusc" crate.
|
# Only build the "regorus-ffi" crate.
|
||||||
CRATES "regorus-ffi")
|
CRATES "regorus-ffi"
|
||||||
|
|
||||||
|
# Select specific features in regorus.
|
||||||
|
FEATURES "regorus/semver"
|
||||||
|
|
||||||
|
LOCKED
|
||||||
|
|
||||||
|
# Link statically
|
||||||
|
CRATE_TYPES "cdylib")
|
||||||
|
|
||||||
add_executable(regorus_test main.cpp)
|
add_executable(regorus_test main.cpp)
|
||||||
# Add path to <regorus-source-folder>/bindings/ffi
|
# Add path to <regorus-source-folder>/bindings/ffi
|
||||||
target_include_directories(regorus_test PRIVATE "../ffi")
|
target_include_directories(regorus_test PRIVATE "../ffi")
|
||||||
target_link_libraries(regorus_test regorus-ffi)
|
target_link_libraries(regorus_test regorus_ffi)
|
||||||
|
|||||||
@@ -6,6 +6,9 @@ void example()
|
|||||||
// Create engine
|
// Create engine
|
||||||
regorus::Engine engine;
|
regorus::Engine engine;
|
||||||
|
|
||||||
|
engine.set_rego_v0(true);
|
||||||
|
engine.set_enable_coverage(true);
|
||||||
|
|
||||||
// Add policies.
|
// Add policies.
|
||||||
engine.add_policy("objects.rego",R"(package objects
|
engine.add_policy("objects.rego",R"(package objects
|
||||||
|
|
||||||
@@ -67,12 +70,21 @@ f := e["dev"])");
|
|||||||
} else {
|
} else {
|
||||||
std::cerr<<result.error()<<std::endl;
|
std::cerr<<result.error()<<std::endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Print coverage report
|
||||||
|
auto result1 = engine.get_coverage_report_pretty();
|
||||||
|
if (result1) {
|
||||||
|
std::cout<<result1.output()<<std::endl;
|
||||||
|
} else {
|
||||||
|
std::cerr<<result1.error()<<std::endl;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int main() {
|
int main() {
|
||||||
|
|
||||||
// Create engine.
|
// Create engine.
|
||||||
regorus::Engine engine;
|
regorus::Engine engine;
|
||||||
|
engine.set_rego_v0(true);
|
||||||
|
|
||||||
|
|
||||||
// Load policies.
|
// Load policies.
|
||||||
@@ -89,6 +101,7 @@ int main() {
|
|||||||
std::cerr<<result.error()<<std::endl;
|
std::cerr<<result.error()<<std::endl;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
std::cout<<"Loaded package "<<result.output()<< std::endl;
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
auto result = engine.add_data_from_json_file("../../../tests/aci/data.json");
|
auto result = engine.add_data_from_json_file("../../../tests/aci/data.json");
|
||||||
@@ -98,7 +111,7 @@ int main() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set input and eval query.
|
// Set input and eval rule.
|
||||||
{
|
{
|
||||||
auto result = engine.set_input_from_json_file("../../../tests/aci/input.json");
|
auto result = engine.set_input_from_json_file("../../../tests/aci/input.json");
|
||||||
if (!result) {
|
if (!result) {
|
||||||
@@ -106,13 +119,13 @@ int main() {
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
auto result = engine.eval_query("data.framework.mount_overlay = x");
|
auto result = engine.eval_rule("data.framework.mount_overlay");
|
||||||
if (!result) {
|
if (!result) {
|
||||||
std::cerr<<result.error()<<std::endl;
|
std::cerr<<result.error()<<std::endl;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::cout<<result.output()<<std::endl;
|
std::cout<<result.output()<<std::endl;
|
||||||
|
|
||||||
example();
|
example();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -54,6 +54,9 @@ namespace regorus {
|
|||||||
return std::unique_ptr<Engine>(new Engine(regorus_engine_clone(engine)));
|
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) {
|
Result add_policy(const char* path, const char* policy) {
|
||||||
return Result(regorus_engine_add_policy(engine, path, policy));
|
return Result(regorus_engine_add_policy(engine, path, policy));
|
||||||
@@ -83,6 +86,26 @@ namespace regorus {
|
|||||||
return Result(regorus_engine_eval_query(engine, query));
|
return Result(regorus_engine_eval_query(engine, query));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Result eval_rule(const char* rule) {
|
||||||
|
return Result(regorus_engine_eval_rule(engine, rule));
|
||||||
|
}
|
||||||
|
|
||||||
|
Result set_enable_coverage(bool enable) {
|
||||||
|
return Result(regorus_engine_set_enable_coverage(engine, enable));
|
||||||
|
}
|
||||||
|
|
||||||
|
Result clear_coverage_data() {
|
||||||
|
return Result(regorus_engine_clear_coverage_data(engine));
|
||||||
|
}
|
||||||
|
|
||||||
|
Result get_coverage_report() {
|
||||||
|
return Result(regorus_engine_get_coverage_report(engine));
|
||||||
|
}
|
||||||
|
|
||||||
|
Result get_coverage_report_pretty() {
|
||||||
|
return Result(regorus_engine_get_coverage_report_pretty(engine));
|
||||||
|
}
|
||||||
|
|
||||||
~Engine() {
|
~Engine() {
|
||||||
regorus_engine_drop(engine);
|
regorus_engine_drop(engine);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,51 +0,0 @@
|
|||||||
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 query.
|
|
||||||
engine.SetInputFromJsonFile("../../tests/aci/input.json");
|
|
||||||
var results = engine.EvalQuery("data.framework.mount_overlay = x");
|
|
||||||
var resultsDoc = System.Text.Json.JsonDocument.Parse(results);
|
|
||||||
|
|
||||||
w.Stop();
|
|
||||||
var evalTicks = w.ElapsedTicks;
|
|
||||||
|
|
||||||
Console.WriteLine("{0}", results);
|
|
||||||
|
|
||||||
|
|
||||||
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));
|
|
||||||
|
|
||||||
|
|
||||||
22
bindings/csharp/Regorus.Tests/Regorus.Tests.csproj
Normal file
22
bindings/csharp/Regorus.Tests/Regorus.Tests.csproj
Normal 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>
|
||||||
176
bindings/csharp/Regorus.Tests/RegorusTests.cs
Normal file
176
bindings/csharp/Regorus.Tests/RegorusTests.cs
Normal 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}");
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,169 +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 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 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 is not null) {
|
|
||||||
resultJson = System.Runtime.InteropServices.Marshal.PtrToStringUTF8((IntPtr)result.output);
|
|
||||||
}
|
|
||||||
RegorusFFI.API.regorus_result_drop(result);
|
|
||||||
} else {
|
|
||||||
CheckAndDropResult(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (resultJson is not null) {
|
|
||||||
return resultJson;
|
|
||||||
} else {
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
~Engine()
|
|
||||||
{
|
|
||||||
unsafe
|
|
||||||
{
|
|
||||||
RegorusFFI.API.regorus_engine_drop(E);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void 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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
RegorusFFI.API.regorus_result_drop(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
240
bindings/csharp/Regorus/Regorus.cs
Normal file
240
bindings/csharp/Regorus/Regorus.cs
Normal 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
51
bindings/csharp/Regorus/Regorus.csproj
Normal file
51
bindings/csharp/Regorus/Regorus.csproj
Normal 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>
|
||||||
219
bindings/csharp/Regorus/RegorusFFI.cs
Normal file
219
bindings/csharp/Regorus/RegorusFFI.cs
Normal 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,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
1
bindings/csharp/Regorus/docs/README.md
Normal file
1
bindings/csharp/Regorus/docs/README.md
Normal file
@@ -0,0 +1 @@
|
|||||||
|
C# Bindings for Regorus
|
||||||
82
bindings/csharp/TestApp/Program.cs
Normal file
82
bindings/csharp/TestApp/Program.cs
Normal file
@@ -0,0 +1,82 @@
|
|||||||
|
// 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.");
|
||||||
|
}
|
||||||
|
|
||||||
16
bindings/csharp/TestApp/TestApp.csproj
Normal file
16
bindings/csharp/TestApp/TestApp.csproj
Normal 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>
|
||||||
10
bindings/csharp/global.json
Normal file
10
bindings/csharp/global.json
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
{
|
||||||
|
"msbuild-sdks": {
|
||||||
|
"Microsoft.Build.NoTargets": "3.7.56"
|
||||||
|
},
|
||||||
|
"sdk": {
|
||||||
|
"allowPrerelease": false,
|
||||||
|
"version": "8.0.408",
|
||||||
|
"rollForward": "disable"
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,24 +0,0 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
|
||||||
|
|
||||||
<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
1771
bindings/ffi/Cargo.lock
generated
Normal file
File diff suppressed because it is too large
Load Diff
@@ -1,17 +1,26 @@
|
|||||||
|
[workspace]
|
||||||
|
|
||||||
[package]
|
[package]
|
||||||
name = "regorus-ffi"
|
name = "regorus-ffi"
|
||||||
version = "0.1.0"
|
version = "0.2.2"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
|
|
||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
[lib]
|
[lib]
|
||||||
crate-type = ["cdylib"]
|
crate-type = ["cdylib", "staticlib"]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
anyhow = "1.0.79"
|
anyhow = "1.0"
|
||||||
regorus = { path = "../.." }
|
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"]
|
||||||
|
ast = ["regorus/ast"]
|
||||||
|
std = ["regorus/std"]
|
||||||
|
coverage = ["regorus/coverage"]
|
||||||
|
custom_allocator = []
|
||||||
|
|
||||||
[build-dependencies]
|
[build-dependencies]
|
||||||
cbindgen = "0.26.0"
|
cbindgen = "0.28.0"
|
||||||
csbindgen = "1.9.0"
|
csbindgen = "=1.9.3"
|
||||||
|
|||||||
@@ -1,88 +0,0 @@
|
|||||||
// <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 RegorusFFI
|
|
||||||
{
|
|
||||||
internal static unsafe partial class API
|
|
||||||
{
|
|
||||||
const string __DllName = "regorusc";
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/// <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)]
|
|
||||||
public 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)]
|
|
||||||
public 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)]
|
|
||||||
public static extern RegorusEngine* regorus_engine_clone(RegorusEngine* engine);
|
|
||||||
|
|
||||||
[DllImport(__DllName, EntryPoint = "regorus_engine_drop", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
|
|
||||||
public 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)]
|
|
||||||
public 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)]
|
|
||||||
public 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)]
|
|
||||||
public static extern RegorusResult regorus_engine_add_data_json(RegorusEngine* engine, byte* data);
|
|
||||||
|
|
||||||
[DllImport(__DllName, EntryPoint = "regorus_engine_add_data_from_json_file", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
|
|
||||||
public static extern RegorusResult regorus_engine_add_data_from_json_file(RegorusEngine* engine, byte* path);
|
|
||||||
|
|
||||||
/// <summary>Clear policy data. See https://docs.rs/regorus/0.1.0-alpha.2/regorus/struct.Engine.html#method.clear_data</summary>
|
|
||||||
[DllImport(__DllName, EntryPoint = "regorus_engine_clear_data", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
|
|
||||||
public static extern RegorusResult regorus_engine_clear_data(RegorusEngine* engine);
|
|
||||||
|
|
||||||
/// <summary>Set input. See https://docs.rs/regorus/0.1.0-alpha.2/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)]
|
|
||||||
public 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)]
|
|
||||||
public static extern RegorusResult regorus_engine_set_input_from_json_file(RegorusEngine* engine, byte* path);
|
|
||||||
|
|
||||||
/// <summary>Evaluate query. See https://docs.rs/regorus/0.1.0-alpha.2/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)]
|
|
||||||
public static extern RegorusResult regorus_engine_eval_query(RegorusEngine* engine, byte* query);
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
[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,
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -24,9 +24,9 @@ fn main() {
|
|||||||
|
|
||||||
csbindgen::Builder::default()
|
csbindgen::Builder::default()
|
||||||
.input_extern_file("src/lib.rs")
|
.input_extern_file("src/lib.rs")
|
||||||
.csharp_dll_name("regorusc")
|
.csharp_dll_name("regorus_ffi")
|
||||||
.csharp_class_name("API")
|
.csharp_class_name("API")
|
||||||
.csharp_namespace("RegorusFFI")
|
.csharp_namespace("Regorus.Internal")
|
||||||
.generate_csharp_file("./RegorusFFI.g.cs")
|
.generate_csharp_file("./RegorusFFI.g.cs")
|
||||||
.unwrap();
|
.unwrap();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -137,9 +137,6 @@ bitflags = false
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
############## Options for How Your Rust library Should Be Parsed ##############
|
############## Options for How Your Rust library Should Be Parsed ##############
|
||||||
|
|
||||||
[parse]
|
[parse]
|
||||||
@@ -154,5 +151,5 @@ extra_bindings = []
|
|||||||
[parse.expand]
|
[parse.expand]
|
||||||
crates = []
|
crates = []
|
||||||
all_features = false
|
all_features = false
|
||||||
default_features = true
|
default_features = false
|
||||||
features = []
|
features = []
|
||||||
@@ -1,95 +0,0 @@
|
|||||||
#ifndef REGORUS_FFI_HPP
|
|
||||||
#define REGORUS_FFI_HPP
|
|
||||||
|
|
||||||
#include <cstdarg>
|
|
||||||
#include <cstdint>
|
|
||||||
#include <cstdlib>
|
|
||||||
#include <ostream>
|
|
||||||
#include <new>
|
|
||||||
|
|
||||||
/// Status of a call on `RegorusEngine`.
|
|
||||||
enum class RegorusStatus {
|
|
||||||
/// The operation was successful.
|
|
||||||
RegorusStatusOk,
|
|
||||||
/// The operation was unsuccessful.
|
|
||||||
RegorusStatusError,
|
|
||||||
};
|
|
||||||
|
|
||||||
/// Wrapper for `regorus::Engine`.
|
|
||||||
struct RegorusEngine;
|
|
||||||
|
|
||||||
/// Result of a call on `RegorusEngine`.
|
|
||||||
///
|
|
||||||
/// Must be freed using `regorus_result_drop`.
|
|
||||||
struct RegorusResult {
|
|
||||||
/// Status
|
|
||||||
RegorusStatus status;
|
|
||||||
/// Output produced by the call.
|
|
||||||
/// Owned by Rust.
|
|
||||||
char *output;
|
|
||||||
/// Errors produced by the call.
|
|
||||||
/// Owned by Rust.
|
|
||||||
char *error_message;
|
|
||||||
};
|
|
||||||
|
|
||||||
extern "C" {
|
|
||||||
|
|
||||||
/// Drop a `RegorusResult`.
|
|
||||||
///
|
|
||||||
/// `output` and `error_message` strings are not valid after drop.
|
|
||||||
void regorus_result_drop(RegorusResult r);
|
|
||||||
|
|
||||||
/// Construct a new Engine
|
|
||||||
///
|
|
||||||
/// See https://docs.rs/regorus/latest/regorus/struct.Engine.html
|
|
||||||
RegorusEngine *regorus_engine_new();
|
|
||||||
|
|
||||||
/// Clone a [`RegorusEngine`]
|
|
||||||
///
|
|
||||||
/// To avoid having to parse same policy again, the engine can be cloned
|
|
||||||
/// after policies and data have been added.
|
|
||||||
RegorusEngine *regorus_engine_clone(RegorusEngine *engine);
|
|
||||||
|
|
||||||
void regorus_engine_drop(RegorusEngine *engine);
|
|
||||||
|
|
||||||
/// 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.
|
|
||||||
RegorusResult regorus_engine_add_policy(RegorusEngine *engine, const char *path, const char *rego);
|
|
||||||
|
|
||||||
RegorusResult regorus_engine_add_policy_from_file(RegorusEngine *engine, const char *path);
|
|
||||||
|
|
||||||
/// 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.
|
|
||||||
RegorusResult regorus_engine_add_data_json(RegorusEngine *engine, const char *data);
|
|
||||||
|
|
||||||
RegorusResult regorus_engine_add_data_from_json_file(RegorusEngine *engine, const char *path);
|
|
||||||
|
|
||||||
/// Clear policy data.
|
|
||||||
///
|
|
||||||
/// See https://docs.rs/regorus/0.1.0-alpha.2/regorus/struct.Engine.html#method.clear_data
|
|
||||||
RegorusResult regorus_engine_clear_data(RegorusEngine *engine);
|
|
||||||
|
|
||||||
/// Set input.
|
|
||||||
///
|
|
||||||
/// See https://docs.rs/regorus/0.1.0-alpha.2/regorus/struct.Engine.html#method.set_input
|
|
||||||
/// * `input`: JSON encoded value to be used as input to query.
|
|
||||||
RegorusResult regorus_engine_set_input_json(RegorusEngine *engine, const char *input);
|
|
||||||
|
|
||||||
RegorusResult regorus_engine_set_input_from_json_file(RegorusEngine *engine, const char *path);
|
|
||||||
|
|
||||||
/// Evaluate query.
|
|
||||||
///
|
|
||||||
/// See https://docs.rs/regorus/0.1.0-alpha.2/regorus/struct.Engine.html#method.eval_query
|
|
||||||
/// * `query`: Rego expression to be evaluate.
|
|
||||||
RegorusResult regorus_engine_eval_query(RegorusEngine *engine, const char *query);
|
|
||||||
|
|
||||||
} // extern "C"
|
|
||||||
|
|
||||||
#endif // REGORUS_FFI_HPP
|
|
||||||
@@ -1,127 +0,0 @@
|
|||||||
#ifndef REGORUS_H
|
|
||||||
#define REGORUS_H
|
|
||||||
|
|
||||||
#include <stdarg.h>
|
|
||||||
#include <stdbool.h>
|
|
||||||
#include <stdint.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Status of a call on `RegorusEngine`.
|
|
||||||
*/
|
|
||||||
typedef enum RegorusStatus {
|
|
||||||
/**
|
|
||||||
* The operation was successful.
|
|
||||||
*/
|
|
||||||
RegorusStatusOk,
|
|
||||||
/**
|
|
||||||
* The operation was unsuccessful.
|
|
||||||
*/
|
|
||||||
RegorusStatusError,
|
|
||||||
} RegorusStatus;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Wrapper for `regorus::Engine`.
|
|
||||||
*/
|
|
||||||
typedef struct RegorusEngine RegorusEngine;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Result of a call on `RegorusEngine`.
|
|
||||||
*
|
|
||||||
* Must be freed using `regorus_result_drop`.
|
|
||||||
*/
|
|
||||||
typedef struct RegorusResult {
|
|
||||||
/**
|
|
||||||
* Status
|
|
||||||
*/
|
|
||||||
enum RegorusStatus status;
|
|
||||||
/**
|
|
||||||
* Output produced by the call.
|
|
||||||
* Owned by Rust.
|
|
||||||
*/
|
|
||||||
char *output;
|
|
||||||
/**
|
|
||||||
* Errors produced by the call.
|
|
||||||
* Owned by Rust.
|
|
||||||
*/
|
|
||||||
char *error_message;
|
|
||||||
} RegorusResult;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Drop a `RegorusResult`.
|
|
||||||
*
|
|
||||||
* `output` and `error_message` strings are not valid after drop.
|
|
||||||
*/
|
|
||||||
void regorus_result_drop(struct RegorusResult r);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Construct a new Engine
|
|
||||||
*
|
|
||||||
* See https://docs.rs/regorus/latest/regorus/struct.Engine.html
|
|
||||||
*/
|
|
||||||
struct RegorusEngine *regorus_engine_new(void);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Clone a [`RegorusEngine`]
|
|
||||||
*
|
|
||||||
* To avoid having to parse same policy again, the engine can be cloned
|
|
||||||
* after policies and data have been added.
|
|
||||||
*/
|
|
||||||
struct RegorusEngine *regorus_engine_clone(struct RegorusEngine *engine);
|
|
||||||
|
|
||||||
void regorus_engine_drop(struct RegorusEngine *engine);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 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.
|
|
||||||
*/
|
|
||||||
struct RegorusResult regorus_engine_add_policy(struct RegorusEngine *engine,
|
|
||||||
const char *path,
|
|
||||||
const char *rego);
|
|
||||||
|
|
||||||
struct RegorusResult regorus_engine_add_policy_from_file(struct RegorusEngine *engine,
|
|
||||||
const char *path);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 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.
|
|
||||||
*/
|
|
||||||
struct RegorusResult regorus_engine_add_data_json(struct RegorusEngine *engine, const char *data);
|
|
||||||
|
|
||||||
struct RegorusResult regorus_engine_add_data_from_json_file(struct RegorusEngine *engine,
|
|
||||||
const char *path);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Clear policy data.
|
|
||||||
*
|
|
||||||
* See https://docs.rs/regorus/0.1.0-alpha.2/regorus/struct.Engine.html#method.clear_data
|
|
||||||
*/
|
|
||||||
struct RegorusResult regorus_engine_clear_data(struct RegorusEngine *engine);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set input.
|
|
||||||
*
|
|
||||||
* See https://docs.rs/regorus/0.1.0-alpha.2/regorus/struct.Engine.html#method.set_input
|
|
||||||
* * `input`: JSON encoded value to be used as input to query.
|
|
||||||
*/
|
|
||||||
struct RegorusResult regorus_engine_set_input_json(struct RegorusEngine *engine, const char *input);
|
|
||||||
|
|
||||||
struct RegorusResult regorus_engine_set_input_from_json_file(struct RegorusEngine *engine,
|
|
||||||
const char *path);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Evaluate query.
|
|
||||||
*
|
|
||||||
* See https://docs.rs/regorus/0.1.0-alpha.2/regorus/struct.Engine.html#method.eval_query
|
|
||||||
* * `query`: Rego expression to be evaluate.
|
|
||||||
*/
|
|
||||||
struct RegorusResult regorus_engine_eval_query(struct RegorusEngine *engine, const char *query);
|
|
||||||
|
|
||||||
#endif /* REGORUS_H */
|
|
||||||
@@ -39,14 +39,14 @@ fn to_c_str(s: String) -> *mut c_char {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn from_c_str(s: *const c_char) -> Result<String> {
|
fn from_c_str(name: &str, s: *const c_char) -> Result<String> {
|
||||||
if s.is_null() {
|
if s.is_null() {
|
||||||
bail!("null pointer");
|
bail!("null pointer");
|
||||||
}
|
}
|
||||||
unsafe {
|
unsafe {
|
||||||
CStr::from_ptr(s)
|
CStr::from_ptr(s)
|
||||||
.to_str()
|
.to_str()
|
||||||
.map_err(|_| anyhow!("`path`: invalid utf8"))
|
.map_err(|e| anyhow!("`{name}`: invalid utf8.\n{e}"))
|
||||||
.map(|s| s.to_string())
|
.map(|s| s.to_string())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -70,6 +70,21 @@ fn to_regorus_result(r: Result<()>) -> RegorusResult {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn to_regorus_string_result(r: Result<String>) -> RegorusResult {
|
||||||
|
match r {
|
||||||
|
Ok(s) => RegorusResult {
|
||||||
|
status: RegorusStatus::RegorusStatusOk,
|
||||||
|
output: to_c_str(s),
|
||||||
|
error_message: std::ptr::null_mut(),
|
||||||
|
},
|
||||||
|
Err(e) => RegorusResult {
|
||||||
|
status: RegorusStatus::RegorusStatusError,
|
||||||
|
output: std::ptr::null_mut(),
|
||||||
|
error_message: to_c_str(format!("{e}")),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Wrapper for `regorus::Engine`.
|
/// Wrapper for `regorus::Engine`.
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct RegorusEngine {
|
pub struct RegorusEngine {
|
||||||
@@ -81,10 +96,13 @@ pub struct RegorusEngine {
|
|||||||
/// `output` and `error_message` strings are not valid after drop.
|
/// `output` and `error_message` strings are not valid after drop.
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub extern "C" fn regorus_result_drop(r: RegorusResult) {
|
pub extern "C" fn regorus_result_drop(r: RegorusResult) {
|
||||||
if !r.error_message.is_null() {
|
unsafe {
|
||||||
unsafe {
|
if !r.error_message.is_null() {
|
||||||
let _ = CString::from_raw(r.error_message);
|
let _ = CString::from_raw(r.error_message);
|
||||||
}
|
}
|
||||||
|
if !r.output.is_null() {
|
||||||
|
let _ = CString::from_raw(r.output);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -101,21 +119,20 @@ pub extern "C" fn regorus_engine_new() -> *mut RegorusEngine {
|
|||||||
///
|
///
|
||||||
/// To avoid having to parse same policy again, the engine can be cloned
|
/// To avoid having to parse same policy again, the engine can be cloned
|
||||||
/// after policies and data have been added.
|
/// after policies and data have been added.
|
||||||
|
///
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub extern "C" fn regorus_engine_clone(engine: *mut RegorusEngine) -> *mut RegorusEngine {
|
pub extern "C" fn regorus_engine_clone(engine: *mut RegorusEngine) -> *mut RegorusEngine {
|
||||||
unsafe {
|
match to_ref(&engine) {
|
||||||
if engine.is_null() {
|
Ok(e) => Box::into_raw(Box::new(e.clone())),
|
||||||
return std::ptr::null_mut();
|
_ => std::ptr::null_mut(),
|
||||||
}
|
|
||||||
Box::into_raw(Box::new((*engine).clone()))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub extern "C" fn regorus_engine_drop(engine: *mut RegorusEngine) {
|
pub extern "C" fn regorus_engine_drop(engine: *mut RegorusEngine) {
|
||||||
if !engine.is_null() {
|
if let Ok(e) = to_ref(&engine) {
|
||||||
unsafe {
|
unsafe {
|
||||||
let _ = Box::from_raw(engine);
|
let _ = Box::from_raw(std::ptr::from_mut(e));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -127,29 +144,29 @@ pub extern "C" fn regorus_engine_drop(engine: *mut RegorusEngine) {
|
|||||||
///
|
///
|
||||||
/// * `path`: A filename to be associated with the policy.
|
/// * `path`: A filename to be associated with the policy.
|
||||||
/// * `rego`: Rego policy.
|
/// * `rego`: Rego policy.
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub extern "C" fn regorus_engine_add_policy(
|
pub extern "C" fn regorus_engine_add_policy(
|
||||||
engine: *mut RegorusEngine,
|
engine: *mut RegorusEngine,
|
||||||
path: *const c_char,
|
path: *const c_char,
|
||||||
rego: *const c_char,
|
rego: *const c_char,
|
||||||
) -> RegorusResult {
|
) -> RegorusResult {
|
||||||
to_regorus_result(|| -> Result<()> {
|
to_regorus_string_result(|| -> Result<String> {
|
||||||
to_ref(&engine)?
|
to_ref(&engine)?
|
||||||
.engine
|
.engine
|
||||||
.add_policy(from_c_str(path)?, from_c_str(rego)?)
|
.add_policy(from_c_str("path", path)?, from_c_str("rego", rego)?)
|
||||||
}())
|
}())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "std")]
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub extern "C" fn regorus_engine_add_policy_from_file(
|
pub extern "C" fn regorus_engine_add_policy_from_file(
|
||||||
engine: *mut RegorusEngine,
|
engine: *mut RegorusEngine,
|
||||||
path: *const c_char,
|
path: *const c_char,
|
||||||
) -> RegorusResult {
|
) -> RegorusResult {
|
||||||
to_regorus_result(|| -> Result<()> {
|
to_regorus_string_result(|| -> Result<String> {
|
||||||
to_ref(&engine)?
|
to_ref(&engine)?
|
||||||
.engine
|
.engine
|
||||||
.add_policy_from_file(from_c_str(path)?)
|
.add_policy_from_file(from_c_str("path", path)?)
|
||||||
}())
|
}())
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -165,10 +182,32 @@ pub extern "C" fn regorus_engine_add_data_json(
|
|||||||
to_regorus_result(|| -> Result<()> {
|
to_regorus_result(|| -> Result<()> {
|
||||||
to_ref(&engine)?
|
to_ref(&engine)?
|
||||||
.engine
|
.engine
|
||||||
.add_data(regorus::Value::from_json_str(&from_c_str(data)?)?)
|
.add_data(regorus::Value::from_json_str(&from_c_str("data", data)?)?)
|
||||||
}())
|
}())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get list of loaded Rego packages as JSON.
|
||||||
|
///
|
||||||
|
/// See https://docs.rs/regorus/latest/regorus/struct.Engine.html#method.get_packages
|
||||||
|
#[no_mangle]
|
||||||
|
pub extern "C" fn regorus_engine_get_packages(engine: *mut RegorusEngine) -> RegorusResult {
|
||||||
|
to_regorus_string_result(|| -> Result<String> {
|
||||||
|
serde_json::to_string_pretty(&to_ref(&engine)?.engine.get_packages()?)
|
||||||
|
.map_err(anyhow::Error::msg)
|
||||||
|
}())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get list of policies as JSON.
|
||||||
|
///
|
||||||
|
/// See https://docs.rs/regorus/latest/regorus/struct.Engine.html#method.get_policies
|
||||||
|
#[no_mangle]
|
||||||
|
pub extern "C" fn regorus_engine_get_policies(engine: *mut RegorusEngine) -> RegorusResult {
|
||||||
|
to_regorus_string_result(|| -> Result<String> {
|
||||||
|
to_ref(&engine)?.engine.get_policies_as_json()
|
||||||
|
}())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "std")]
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub extern "C" fn regorus_engine_add_data_from_json_file(
|
pub extern "C" fn regorus_engine_add_data_from_json_file(
|
||||||
engine: *mut RegorusEngine,
|
engine: *mut RegorusEngine,
|
||||||
@@ -177,13 +216,13 @@ pub extern "C" fn regorus_engine_add_data_from_json_file(
|
|||||||
to_regorus_result(|| -> Result<()> {
|
to_regorus_result(|| -> Result<()> {
|
||||||
to_ref(&engine)?
|
to_ref(&engine)?
|
||||||
.engine
|
.engine
|
||||||
.add_data(regorus::Value::from_json_file(&from_c_str(path)?)?)
|
.add_data(regorus::Value::from_json_file(from_c_str("path", path)?)?)
|
||||||
}())
|
}())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Clear policy data.
|
/// 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]
|
#[no_mangle]
|
||||||
pub extern "C" fn regorus_engine_clear_data(engine: *mut RegorusEngine) -> RegorusResult {
|
pub extern "C" fn regorus_engine_clear_data(engine: *mut RegorusEngine) -> RegorusResult {
|
||||||
to_regorus_result(|| -> Result<()> {
|
to_regorus_result(|| -> Result<()> {
|
||||||
@@ -194,7 +233,7 @@ pub extern "C" fn regorus_engine_clear_data(engine: *mut RegorusEngine) -> Regor
|
|||||||
|
|
||||||
/// Set input.
|
/// 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.
|
/// * `input`: JSON encoded value to be used as input to query.
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub extern "C" fn regorus_engine_set_input_json(
|
pub extern "C" fn regorus_engine_set_input_json(
|
||||||
@@ -204,11 +243,12 @@ pub extern "C" fn regorus_engine_set_input_json(
|
|||||||
to_regorus_result(|| -> Result<()> {
|
to_regorus_result(|| -> Result<()> {
|
||||||
to_ref(&engine)?
|
to_ref(&engine)?
|
||||||
.engine
|
.engine
|
||||||
.set_input(regorus::Value::from_json_str(&from_c_str(input)?)?);
|
.set_input(regorus::Value::from_json_str(&from_c_str("input", input)?)?);
|
||||||
Ok(())
|
Ok(())
|
||||||
}())
|
}())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "std")]
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub extern "C" fn regorus_engine_set_input_from_json_file(
|
pub extern "C" fn regorus_engine_set_input_from_json_file(
|
||||||
engine: *mut RegorusEngine,
|
engine: *mut RegorusEngine,
|
||||||
@@ -217,14 +257,14 @@ pub extern "C" fn regorus_engine_set_input_from_json_file(
|
|||||||
to_regorus_result(|| -> Result<()> {
|
to_regorus_result(|| -> Result<()> {
|
||||||
to_ref(&engine)?
|
to_ref(&engine)?
|
||||||
.engine
|
.engine
|
||||||
.set_input(regorus::Value::from_json_file(&from_c_str(path)?)?);
|
.set_input(regorus::Value::from_json_file(from_c_str("path", path)?)?);
|
||||||
Ok(())
|
Ok(())
|
||||||
}())
|
}())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Evaluate query.
|
/// 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.
|
/// * `query`: Rego expression to be evaluate.
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub extern "C" fn regorus_engine_eval_query(
|
pub extern "C" fn regorus_engine_eval_query(
|
||||||
@@ -234,7 +274,7 @@ pub extern "C" fn regorus_engine_eval_query(
|
|||||||
let output = || -> Result<String> {
|
let output = || -> Result<String> {
|
||||||
let results = to_ref(&engine)?
|
let results = to_ref(&engine)?
|
||||||
.engine
|
.engine
|
||||||
.eval_query(from_c_str(query)?, false)?;
|
.eval_query(from_c_str("query", query)?, false)?;
|
||||||
Ok(serde_json::to_string_pretty(&results)?)
|
Ok(serde_json::to_string_pretty(&results)?)
|
||||||
}();
|
}();
|
||||||
match output {
|
match output {
|
||||||
@@ -246,3 +286,204 @@ pub extern "C" fn regorus_engine_eval_query(
|
|||||||
Err(e) => to_regorus_result(Err(e)),
|
Err(e) => to_regorus_result(Err(e)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Evaluate specified 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(
|
||||||
|
engine: *mut RegorusEngine,
|
||||||
|
rule: *const c_char,
|
||||||
|
) -> RegorusResult {
|
||||||
|
let output = || -> Result<String> {
|
||||||
|
to_ref(&engine)?
|
||||||
|
.engine
|
||||||
|
.eval_rule(from_c_str("rule", rule)?)?
|
||||||
|
.to_json_str()
|
||||||
|
}();
|
||||||
|
match output {
|
||||||
|
Ok(out) => RegorusResult {
|
||||||
|
status: RegorusStatus::RegorusStatusOk,
|
||||||
|
output: to_c_str(out),
|
||||||
|
error_message: std::ptr::null_mut(),
|
||||||
|
},
|
||||||
|
Err(e) => to_regorus_result(Err(e)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Enable/disable 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")]
|
||||||
|
pub extern "C" fn regorus_engine_set_enable_coverage(
|
||||||
|
engine: *mut RegorusEngine,
|
||||||
|
enable: bool,
|
||||||
|
) -> RegorusResult {
|
||||||
|
to_regorus_result(|| -> Result<()> {
|
||||||
|
to_ref(&engine)?.engine.set_enable_coverage(enable);
|
||||||
|
Ok(())
|
||||||
|
}())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 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 {
|
||||||
|
let output = || -> Result<String> {
|
||||||
|
Ok(serde_json::to_string_pretty(
|
||||||
|
&to_ref(&engine)?.engine.get_coverage_report()?,
|
||||||
|
)?)
|
||||||
|
}();
|
||||||
|
match output {
|
||||||
|
Ok(out) => RegorusResult {
|
||||||
|
status: RegorusStatus::RegorusStatusOk,
|
||||||
|
output: to_c_str(out),
|
||||||
|
error_message: std::ptr::null_mut(),
|
||||||
|
},
|
||||||
|
Err(e) => to_regorus_result(Err(e)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get pretty printed coverage report.
|
||||||
|
///
|
||||||
|
/// See https://docs.rs/regorus/latest/regorus/coverage/struct.Report.html#method.to_string_pretty
|
||||||
|
#[no_mangle]
|
||||||
|
#[cfg(feature = "coverage")]
|
||||||
|
pub extern "C" fn regorus_engine_get_coverage_report_pretty(
|
||||||
|
engine: *mut RegorusEngine,
|
||||||
|
) -> RegorusResult {
|
||||||
|
let output = || -> Result<String> {
|
||||||
|
to_ref(&engine)?
|
||||||
|
.engine
|
||||||
|
.get_coverage_report()?
|
||||||
|
.to_string_pretty()
|
||||||
|
}();
|
||||||
|
match output {
|
||||||
|
Ok(out) => RegorusResult {
|
||||||
|
status: RegorusStatus::RegorusStatusOk,
|
||||||
|
output: to_c_str(out),
|
||||||
|
error_message: std::ptr::null_mut(),
|
||||||
|
},
|
||||||
|
Err(e) => to_regorus_result(Err(e)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 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 {
|
||||||
|
to_regorus_result(|| -> Result<()> {
|
||||||
|
to_ref(&engine)?.engine.clear_coverage_data();
|
||||||
|
Ok(())
|
||||||
|
}())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 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.
|
||||||
|
#[no_mangle]
|
||||||
|
pub extern "C" fn regorus_engine_set_gather_prints(
|
||||||
|
engine: *mut RegorusEngine,
|
||||||
|
enable: bool,
|
||||||
|
) -> RegorusResult {
|
||||||
|
to_regorus_result(|| -> Result<()> {
|
||||||
|
to_ref(&engine)?.engine.set_gather_prints(enable);
|
||||||
|
Ok(())
|
||||||
|
}())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Take all the gathered print statements.
|
||||||
|
///
|
||||||
|
/// 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> {
|
||||||
|
Ok(serde_json::to_string_pretty(
|
||||||
|
&to_ref(&engine)?.engine.take_prints()?,
|
||||||
|
)?)
|
||||||
|
}();
|
||||||
|
match output {
|
||||||
|
Ok(out) => RegorusResult {
|
||||||
|
status: RegorusStatus::RegorusStatusOk,
|
||||||
|
output: to_c_str(out),
|
||||||
|
error_message: std::ptr::null_mut(),
|
||||||
|
},
|
||||||
|
Err(e) => to_regorus_result(Err(e)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get AST of policies.
|
||||||
|
///
|
||||||
|
/// See https://docs.rs/regorus/latest/regorus/coverage/struct.Engine.html#method.get_ast_as_json
|
||||||
|
#[no_mangle]
|
||||||
|
#[cfg(feature = "ast")]
|
||||||
|
pub extern "C" fn regorus_engine_get_ast_as_json(engine: *mut RegorusEngine) -> RegorusResult {
|
||||||
|
let output = || -> Result<String> { to_ref(&engine)?.engine.get_ast_as_json() }();
|
||||||
|
match output {
|
||||||
|
Ok(out) => RegorusResult {
|
||||||
|
status: RegorusStatus::RegorusStatusOk,
|
||||||
|
output: to_c_str(out),
|
||||||
|
error_message: std::ptr::null_mut(),
|
||||||
|
},
|
||||||
|
Err(e) => to_regorus_result(Err(e)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 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;
|
||||||
|
fn regorus_free(ptr: *mut u8);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "custom_allocator")]
|
||||||
|
mod allocator {
|
||||||
|
use std::alloc::{GlobalAlloc, Layout};
|
||||||
|
|
||||||
|
struct RegorusAllocator {}
|
||||||
|
|
||||||
|
unsafe impl GlobalAlloc for RegorusAllocator {
|
||||||
|
unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
|
||||||
|
let size = layout.size();
|
||||||
|
let align = layout.align();
|
||||||
|
|
||||||
|
crate::regorus_aligned_alloc(align, size)
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe fn dealloc(&self, ptr: *mut u8, _layout: Layout) {
|
||||||
|
crate::regorus_free(ptr)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[global_allocator]
|
||||||
|
static ALLOCATOR: RegorusAllocator = RegorusAllocator {};
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,3 +1,3 @@
|
|||||||
module regorus-test
|
module regorus_test
|
||||||
|
|
||||||
go 1.21.5
|
go 1.21.5
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ package main
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
"regorus-test/pkg/regorus"
|
"regorus_test/pkg/regorus"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -12,12 +12,15 @@ func main() {
|
|||||||
var err error
|
var err error
|
||||||
|
|
||||||
t := time.Now();
|
t := time.Now();
|
||||||
|
|
||||||
// Create new engine
|
// Create new engine
|
||||||
engine := regorus.NewEngine()
|
engine := regorus.NewEngine()
|
||||||
defer engine.Close()
|
defer engine.Close()
|
||||||
elapsed1 := time.Since(t)
|
|
||||||
|
|
||||||
|
engine.SetRegoV0(true)
|
||||||
|
elapsed1 := time.Since(t)
|
||||||
|
|
||||||
|
|
||||||
t = time.Now()
|
t = time.Now()
|
||||||
// Add policies and data.
|
// Add policies and data.
|
||||||
policies := []string{
|
policies := []string{
|
||||||
@@ -26,10 +29,12 @@ func main() {
|
|||||||
"../../tests/aci/policy.rego",
|
"../../tests/aci/policy.rego",
|
||||||
}
|
}
|
||||||
for _, policy := range policies {
|
for _, policy := range policies {
|
||||||
if err := engine.AddPolicyFromFile(policy); err != nil {
|
var pkg string
|
||||||
|
if pkg, err = engine.AddPolicyFromFile(policy); err != nil {
|
||||||
fmt.Fprintf(os.Stderr, "error: %v\n", err)
|
fmt.Fprintf(os.Stderr, "error: %v\n", err)
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
|
fmt.Printf("Loaded package %s\n", pkg);
|
||||||
}
|
}
|
||||||
if err = engine.AddDataFromJsonFile("../../tests/aci/data.json"); err != nil {
|
if err = engine.AddDataFromJsonFile("../../tests/aci/data.json"); err != nil {
|
||||||
fmt.Fprintf(os.Stderr, "error: %v\n", err)
|
fmt.Fprintf(os.Stderr, "error: %v\n", err)
|
||||||
@@ -38,21 +43,61 @@ func main() {
|
|||||||
elapsed2 := time.Since(t)
|
elapsed2 := time.Since(t)
|
||||||
|
|
||||||
t = time.Now()
|
t = time.Now()
|
||||||
// Set input and eval query.
|
// Set input.
|
||||||
if err = engine.SetInputFromJsonFile("../../tests/aci/input.json"); err != nil {
|
if err = engine.SetInputFromJsonFile("../../tests/aci/input.json"); err != nil {
|
||||||
fmt.Fprintf(os.Stderr, "error: %v\n", err)
|
fmt.Fprintf(os.Stderr, "error: %v\n", err)
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Eval Rule
|
||||||
if output, err = engine.EvalQuery("data.framework.mount_overlay = x"); err != nil {
|
if output, err = engine.EvalRule("data.framework.mount_overlay"); err != nil {
|
||||||
fmt.Fprintf(os.Stderr, "error: %v\n", err)
|
fmt.Fprintf(os.Stderr, "error: %v\n", err)
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
elapsed3 := time.Since(t)
|
elapsed3 := time.Since(t)
|
||||||
|
|
||||||
fmt.Println("{%s}", output)
|
fmt.Printf("%s\n", output)
|
||||||
fmt.Printf("NewEngine took %v\n", elapsed1)
|
fmt.Printf("NewEngine took %v\n", elapsed1)
|
||||||
fmt.Printf("Add policies and data took %v\n", elapsed2)
|
fmt.Printf("Add policies and data took %v\n", elapsed2)
|
||||||
fmt.Printf("Set input and eval query took %v\n", elapsed3)
|
fmt.Printf("Set input and eval query took %v\n", elapsed3)
|
||||||
|
|
||||||
|
// Create new engine.
|
||||||
|
engine1 := regorus.NewEngine()
|
||||||
|
defer engine1.Close()
|
||||||
|
|
||||||
|
// Enable coverage
|
||||||
|
engine1.SetEnableCoverage(true)
|
||||||
|
|
||||||
|
var pkg string
|
||||||
|
pkg, err = engine1.AddPolicy("test.rego", "package test\nx = 1\nmessage = `Hello`")
|
||||||
|
fmt.Printf("Loaded package %s\n", pkg)
|
||||||
|
|
||||||
|
// Eval Rule
|
||||||
|
if output, err = engine1.EvalRule("data.test.message"); err != nil {
|
||||||
|
fmt.Fprintf(os.Stderr, "error: %v\n", err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Printf("%s\n", output)
|
||||||
|
|
||||||
|
// Print pretty coverage report.
|
||||||
|
if output, err = engine1.GetCoverageReportPretty(); err != nil {
|
||||||
|
fmt.Fprintf(os.Stderr, "error: %v\n", err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
fmt.Printf("%s\n", output)
|
||||||
|
|
||||||
|
// Print packages
|
||||||
|
if output, err = engine1.GetPackages(); err != nil {
|
||||||
|
fmt.Fprintf(os.Stderr, "error: %v\n", err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
fmt.Printf("%s\n", output)
|
||||||
|
|
||||||
|
// Print policies
|
||||||
|
if output, err = engine1.GetPolicies(); err != nil {
|
||||||
|
fmt.Fprintf(os.Stderr, "error: %v\n", err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
fmt.Printf("%s\n", output)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
package regorus
|
package regorus
|
||||||
|
|
||||||
// #cgo LDFLAGS: -L ../../../../target/release -lregorus_ffi
|
// #cgo LDFLAGS: -L ../../../ffi/target/release -lregorus_ffi
|
||||||
// #include "../../../ffi/regorus.h"
|
// #include "../../../ffi/regorus.h"
|
||||||
import "C"
|
import "C"
|
||||||
import (
|
import (
|
||||||
@@ -28,7 +28,18 @@ func (e *Engine) Clone() *Engine {
|
|||||||
return c
|
return c
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *Engine) AddPolicy(path string, rego string) error {
|
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)
|
path_c := C.CString(path)
|
||||||
defer C.free(unsafe.Pointer(path_c))
|
defer C.free(unsafe.Pointer(path_c))
|
||||||
|
|
||||||
@@ -38,21 +49,39 @@ func (e *Engine) AddPolicy(path string, rego string) error {
|
|||||||
result := C.regorus_engine_add_policy(e.e, path_c, rego_c)
|
result := C.regorus_engine_add_policy(e.e, path_c, rego_c)
|
||||||
defer C.regorus_result_drop(result)
|
defer C.regorus_result_drop(result)
|
||||||
if result.status != C.RegorusStatusOk {
|
if result.status != C.RegorusStatusOk {
|
||||||
return fmt.Errorf("%s", C.GoString(result.error_message))
|
return "", fmt.Errorf("%s", C.GoString(result.error_message))
|
||||||
}
|
}
|
||||||
return nil
|
return C.GoString(result.output), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *Engine) AddPolicyFromFile(path string) error {
|
func (e *Engine) AddPolicyFromFile(path string) (string, error) {
|
||||||
path_c := C.CString(path)
|
path_c := C.CString(path)
|
||||||
defer C.free(unsafe.Pointer(path_c))
|
defer C.free(unsafe.Pointer(path_c))
|
||||||
|
|
||||||
result := C.regorus_engine_add_policy_from_file(e.e, path_c)
|
result := C.regorus_engine_add_policy_from_file(e.e, path_c)
|
||||||
defer C.regorus_result_drop(result)
|
defer C.regorus_result_drop(result)
|
||||||
if result.status != C.RegorusStatusOk {
|
if result.status != C.RegorusStatusOk {
|
||||||
return fmt.Errorf("%s", C.GoString(result.error_message))
|
return "", fmt.Errorf("%s", C.GoString(result.error_message))
|
||||||
}
|
}
|
||||||
return nil
|
return C.GoString(result.output), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *Engine) GetPackages() (string, error) {
|
||||||
|
result := C.regorus_engine_get_packages(e.e)
|
||||||
|
defer C.regorus_result_drop(result)
|
||||||
|
if result.status != C.RegorusStatusOk {
|
||||||
|
return "", fmt.Errorf("%s", C.GoString(result.error_message))
|
||||||
|
}
|
||||||
|
return C.GoString(result.output), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *Engine) GetPolicies() (string, error) {
|
||||||
|
result := C.regorus_engine_get_policies(e.e)
|
||||||
|
defer C.regorus_result_drop(result)
|
||||||
|
if result.status != C.RegorusStatusOk {
|
||||||
|
return "", fmt.Errorf("%s", C.GoString(result.error_message))
|
||||||
|
}
|
||||||
|
return C.GoString(result.output), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *Engine) AddDataJson(data string) error {
|
func (e *Engine) AddDataJson(data string) error {
|
||||||
@@ -115,3 +144,73 @@ func (e *Engine) EvalQuery(query string) (string, error) {
|
|||||||
|
|
||||||
return C.GoString(result.output), nil
|
return C.GoString(result.output), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (e *Engine) EvalRule(rule string) (string, error) {
|
||||||
|
rule_c := C.CString(rule)
|
||||||
|
defer C.free(unsafe.Pointer(rule_c))
|
||||||
|
|
||||||
|
result := C.regorus_engine_eval_rule(e.e, rule_c)
|
||||||
|
defer C.regorus_result_drop(result)
|
||||||
|
if result.status != C.RegorusStatusOk {
|
||||||
|
return "", fmt.Errorf("%s", C.GoString(result.error_message))
|
||||||
|
}
|
||||||
|
|
||||||
|
return C.GoString(result.output), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *Engine) SetEnableCoverage(enable bool) error {
|
||||||
|
result := C.regorus_engine_set_enable_coverage(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) ClearCoverageData() error {
|
||||||
|
result := C.regorus_engine_clear_coverage_data(e.e)
|
||||||
|
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) GetCoverageReport() (string, error) {
|
||||||
|
result := C.regorus_engine_get_coverage_report(e.e)
|
||||||
|
defer C.regorus_result_drop(result)
|
||||||
|
if result.status != C.RegorusStatusOk {
|
||||||
|
return "", fmt.Errorf("%s", C.GoString(result.error_message))
|
||||||
|
}
|
||||||
|
|
||||||
|
return C.GoString(result.output), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *Engine) GetCoverageReportPretty() (string, error) {
|
||||||
|
result := C.regorus_engine_get_coverage_report_pretty(e.e)
|
||||||
|
defer C.regorus_result_drop(result)
|
||||||
|
if result.status != C.RegorusStatusOk {
|
||||||
|
return "", fmt.Errorf("%s", C.GoString(result.error_message))
|
||||||
|
}
|
||||||
|
|
||||||
|
return C.GoString(result.output), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *Engine) SetGatherPrints(b bool) error {
|
||||||
|
result := C.regorus_engine_set_gather_prints(e.e, C.bool(b))
|
||||||
|
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) TakePrints() (string, error) {
|
||||||
|
result := C.regorus_engine_take_prints(e.e)
|
||||||
|
defer C.regorus_result_drop(result)
|
||||||
|
if result.status != C.RegorusStatusOk {
|
||||||
|
return "", fmt.Errorf("%s", C.GoString(result.error_message))
|
||||||
|
}
|
||||||
|
|
||||||
|
return C.GoString(result.output), nil
|
||||||
|
}
|
||||||
|
|||||||
1692
bindings/java/Cargo.lock
generated
Normal file
1692
bindings/java/Cargo.lock
generated
Normal file
File diff suppressed because it is too large
Load Diff
@@ -1,6 +1,8 @@
|
|||||||
|
[workspace]
|
||||||
|
|
||||||
[package]
|
[package]
|
||||||
name = "regorus-java"
|
name = "regorus-java"
|
||||||
version = "0.1.0"
|
version = "0.3.0"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
repository = "https://github.com/microsoft/regorus/bindings/java"
|
repository = "https://github.com/microsoft/regorus/bindings/java"
|
||||||
description = "Java bindings for Regorus - a fast, lightweight Rego interpreter written in Rust"
|
description = "Java bindings for Regorus - a fast, lightweight Rego interpreter written in Rust"
|
||||||
@@ -10,8 +12,13 @@ keywords = ["interpreter", "opa", "policy-as-code", "rego"]
|
|||||||
[lib]
|
[lib]
|
||||||
crate-type = ["cdylib"]
|
crate-type = ["cdylib"]
|
||||||
|
|
||||||
|
[features]
|
||||||
|
default = ["ast", "coverage", "regorus/std", "regorus/full-opa"]
|
||||||
|
coverage = ["regorus/coverage"]
|
||||||
|
ast = ["regorus/ast"]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
anyhow = "1.0.79"
|
anyhow = "1.0"
|
||||||
serde_json = "1.0.112"
|
serde_json = "1.0.112"
|
||||||
jni = "0.21.1"
|
jni = "0.21.1"
|
||||||
regorus = { path = "../.." }
|
regorus = { path = "../..", default-features = false, features = ["arc"] }
|
||||||
|
|||||||
@@ -8,38 +8,33 @@
|
|||||||
|
|
||||||
See main [Regorus page](https://github.com/microsoft/regorus) for more details about the project.
|
See main [Regorus page](https://github.com/microsoft/regorus) for more details about the project.
|
||||||
|
|
||||||
|
## Building
|
||||||
|
|
||||||
|
Due to operational overhead we don't publish Java bindings to Maven Central
|
||||||
|
currently (see https://github.com/microsoft/regorus/issues/237) and you need to build from source to use it.
|
||||||
|
|
||||||
|
In order to build Regorus Java for a target platform, you need to install Rust target for that platform first:
|
||||||
|
```bash
|
||||||
|
$ rustup target add aarch64-apple-darwin
|
||||||
|
```
|
||||||
|
|
||||||
|
Afterwards, you can build native library for that target using:
|
||||||
|
```bash
|
||||||
|
$ 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 then need to build Java bindings using:
|
||||||
|
```bash
|
||||||
|
$ mvn package
|
||||||
|
```
|
||||||
|
|
||||||
|
And you will have a JAR at `./target/regorus-java-0.1.5.jar`.
|
||||||
|
|
||||||
## Usage
|
## Usage
|
||||||
|
|
||||||
Regorus Java is published to Maven Central with native libraries for the following:
|
You can use Regorus Java bindings as:
|
||||||
|
|
||||||
- 64-bit Linux (kernel 3.2+, glibc 2.17+)
|
|
||||||
- ARM64 Linux (kernel 4.1, glibc 2.17+)
|
|
||||||
- 64-bit macOS (10.12+, Sierra+)
|
|
||||||
- ARM64 macOS (11.0+, Big Sur+)
|
|
||||||
- 64-bit MSVC (Windows 7+)
|
|
||||||
|
|
||||||
If you need to run it in a different OS or an architecture you need to manually [build it](#Building).
|
|
||||||
|
|
||||||
If you're on one of the supported platforms, you can just pull prebuilt JAR from Maven Central by declaring a dependency on `com.microsoft.regorus:regorus-java`.
|
|
||||||
|
|
||||||
With [Maven](https://maven.apache.org/):
|
|
||||||
```xml
|
|
||||||
<dependencies>
|
|
||||||
<dependency>
|
|
||||||
<groupId>com.microsoft.regorus</groupId>
|
|
||||||
<artifactId>regorus-java</artifactId>
|
|
||||||
<version>0.0.1</version>
|
|
||||||
</dependency>
|
|
||||||
</dependencies>
|
|
||||||
```
|
|
||||||
|
|
||||||
With [Gradle](https://gradle.org/):
|
|
||||||
```kotlin
|
|
||||||
// build.gradle.kts
|
|
||||||
implementation("com.microsoft.regorus:regorus-java:0.0.1")
|
|
||||||
```
|
|
||||||
|
|
||||||
Afterwards you can use it as follows:
|
|
||||||
|
|
||||||
```java
|
```java
|
||||||
import com.microsoft.regorus.Engine;
|
import com.microsoft.regorus.Engine;
|
||||||
@@ -61,37 +56,14 @@ public class Test {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
And you can see the following output once you run it:
|
You need to ensure artifacts built in [previous section](#building) are in Java's classpath.
|
||||||
```shell
|
|
||||||
{"result":[{"expressions":[{"value":"Hello, World!","text":"data.test.message","location":{"row":1,"col":1}}]}]}
|
|
||||||
```
|
|
||||||
|
|
||||||
## Building
|
|
||||||
|
|
||||||
In order to build Regorus Java for a target platform, you need to install Rust target
|
|
||||||
for that target platform first:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
$ rustup target add aarch64-apple-darwin
|
|
||||||
```
|
|
||||||
|
|
||||||
Afterwards, you can build native library for that target using:
|
|
||||||
```bash
|
|
||||||
$ 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 can then build a JAR from source using:
|
|
||||||
```bash
|
|
||||||
$ mvn package
|
|
||||||
```
|
|
||||||
|
|
||||||
And you will have a JAR at `./target/regorus-java-0.0.1.jar`.
|
|
||||||
|
|
||||||
You need to make sure both of the artifacts in Java's classpath.
|
|
||||||
For example with `java` CLI:
|
For example with `java` CLI:
|
||||||
```bash
|
```bash
|
||||||
$ java -Djava.library.path=../../target/aarch64-apple-darwin/release/ -cp target/regorus-java-0.0.1.jar Test.java
|
$ java -Djava.library.path=../../target/aarch64-apple-darwin/release/ -cp target/regorus-java-0.1.5.jar Test.java
|
||||||
```
|
```
|
||||||
|
|
||||||
|
should gave you the output:
|
||||||
|
```
|
||||||
|
{"result":[{"expressions":[{"value":"Hello, World!","text":"data.test.message","location":{"row":1,"col":1}}]}]}
|
||||||
|
```
|
||||||
|
|||||||
48
bindings/java/Test.java
Normal file
48
bindings/java/Test.java
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
// Copyright (c) Microsoft Corporation.
|
||||||
|
// Licensed under the MIT License.
|
||||||
|
|
||||||
|
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])"
|
||||||
|
);
|
||||||
|
System.out.println("Loaded package " + pkg);
|
||||||
|
|
||||||
|
engine.addDataJson("{\"message\":\"World!\"}");
|
||||||
|
engine.setInputJson("{\"message\":\"Hello\"}");
|
||||||
|
|
||||||
|
// Evaluate query.
|
||||||
|
String resJson = engine.evalQuery("data.test.message");
|
||||||
|
System.out.println(resJson);
|
||||||
|
|
||||||
|
// Enable coverage.
|
||||||
|
engine.setEnableCoverage(true);
|
||||||
|
|
||||||
|
// Evaluate rule.
|
||||||
|
String valueJson = engine.evalRule("data.test.message");
|
||||||
|
System.out.println(valueJson);
|
||||||
|
|
||||||
|
String coverageJson = engine.getCoverageReport();
|
||||||
|
System.out.println(coverageJson);
|
||||||
|
|
||||||
|
System.out.println(engine.getCoverageReportPretty());
|
||||||
|
|
||||||
|
String packagesJson = engine.getPackages();
|
||||||
|
System.out.println(packagesJson);
|
||||||
|
|
||||||
|
String policiesJson = engine.getPolicies();
|
||||||
|
System.out.println(policiesJson);
|
||||||
|
|
||||||
|
engine.setRegoV0(true);
|
||||||
|
engine.addPolicy(
|
||||||
|
"world.rego",
|
||||||
|
"package world\nx { true }"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -17,18 +17,26 @@ JNIEXPORT jlong JNICALL Java_com_microsoft_regorus_Engine_nativeNewEngine
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* Class: com_microsoft_regorus_Engine
|
* Class: com_microsoft_regorus_Engine
|
||||||
* Method: nativeAddPolicy
|
* Method: nativeClone
|
||||||
* Signature: (JLjava/lang/String;Ljava/lang/String;)V
|
* Signature: (J)J
|
||||||
*/
|
*/
|
||||||
JNIEXPORT void JNICALL Java_com_microsoft_regorus_Engine_nativeAddPolicy
|
JNIEXPORT jlong JNICALL Java_com_microsoft_regorus_Engine_nativeClone
|
||||||
|
(JNIEnv *, jclass, jlong);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Class: com_microsoft_regorus_Engine
|
||||||
|
* Method: nativeAddPolicy
|
||||||
|
* Signature: (JLjava/lang/String;Ljava/lang/String;)Ljava/lang/String;
|
||||||
|
*/
|
||||||
|
JNIEXPORT jstring JNICALL Java_com_microsoft_regorus_Engine_nativeAddPolicy
|
||||||
(JNIEnv *, jclass, jlong, jstring, jstring);
|
(JNIEnv *, jclass, jlong, jstring, jstring);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Class: com_microsoft_regorus_Engine
|
* Class: com_microsoft_regorus_Engine
|
||||||
* Method: nativeAddPolicyFromFile
|
* Method: nativeAddPolicyFromFile
|
||||||
* Signature: (JLjava/lang/String;)V
|
* Signature: (JLjava/lang/String;)Ljava/lang/String;
|
||||||
*/
|
*/
|
||||||
JNIEXPORT void JNICALL Java_com_microsoft_regorus_Engine_nativeAddPolicyFromFile
|
JNIEXPORT jstring JNICALL Java_com_microsoft_regorus_Engine_nativeAddPolicyFromFile
|
||||||
(JNIEnv *, jclass, jlong, jstring);
|
(JNIEnv *, jclass, jlong, jstring);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -79,6 +87,62 @@ JNIEXPORT void JNICALL Java_com_microsoft_regorus_Engine_nativeSetInputJsonFromF
|
|||||||
JNIEXPORT jstring JNICALL Java_com_microsoft_regorus_Engine_nativeEvalQuery
|
JNIEXPORT jstring JNICALL Java_com_microsoft_regorus_Engine_nativeEvalQuery
|
||||||
(JNIEnv *, jclass, jlong, jstring);
|
(JNIEnv *, jclass, jlong, jstring);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Class: com_microsoft_regorus_Engine
|
||||||
|
* Method: nativeEvalRule
|
||||||
|
* Signature: (JLjava/lang/String;)Ljava/lang/String;
|
||||||
|
*/
|
||||||
|
JNIEXPORT jstring JNICALL Java_com_microsoft_regorus_Engine_nativeEvalRule
|
||||||
|
(JNIEnv *, jclass, jlong, jstring);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Class: com_microsoft_regorus_Engine
|
||||||
|
* Method: nativeSetEnableCoverage
|
||||||
|
* Signature: (JZ)V
|
||||||
|
*/
|
||||||
|
JNIEXPORT void JNICALL Java_com_microsoft_regorus_Engine_nativeSetEnableCoverage
|
||||||
|
(JNIEnv *, jclass, jlong, jboolean);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Class: com_microsoft_regorus_Engine
|
||||||
|
* Method: nativeGetCoverageReport
|
||||||
|
* Signature: (J)Ljava/lang/String;
|
||||||
|
*/
|
||||||
|
JNIEXPORT jstring JNICALL Java_com_microsoft_regorus_Engine_nativeGetCoverageReport
|
||||||
|
(JNIEnv *, jclass, jlong);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Class: com_microsoft_regorus_Engine
|
||||||
|
* Method: nativeGetCoverageReportAsColoredString
|
||||||
|
* Signature: (J)Ljava/lang/String;
|
||||||
|
*/
|
||||||
|
JNIEXPORT jstring JNICALL Java_com_microsoft_regorus_Engine_nativeGetCoverageReportAsColoredString
|
||||||
|
(JNIEnv *, jclass, jlong);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Class: com_microsoft_regorus_Engine
|
||||||
|
* Method: nativeClearCoverageData
|
||||||
|
* Signature: (J)V
|
||||||
|
*/
|
||||||
|
JNIEXPORT void JNICALL Java_com_microsoft_regorus_Engine_nativeClearCoverageData
|
||||||
|
(JNIEnv *, jclass, jlong);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Class: com_microsoft_regorus_Engine
|
||||||
|
* Method: nativeSetGatherPrints
|
||||||
|
* Signature: (JZ)V
|
||||||
|
*/
|
||||||
|
JNIEXPORT void JNICALL Java_com_microsoft_regorus_Engine_nativeSetGatherPrints
|
||||||
|
(JNIEnv *, jclass, jlong, jboolean);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Class: com_microsoft_regorus_Engine
|
||||||
|
* Method: nativeTakePrints
|
||||||
|
* Signature: (J)Ljava/lang/String;
|
||||||
|
*/
|
||||||
|
JNIEXPORT jstring JNICALL Java_com_microsoft_regorus_Engine_nativeTakePrints
|
||||||
|
(JNIEnv *, jclass, jlong);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Class: com_microsoft_regorus_Engine
|
* Class: com_microsoft_regorus_Engine
|
||||||
* Method: nativeDestroyEngine
|
* Method: nativeDestroyEngine
|
||||||
|
|||||||
@@ -9,7 +9,7 @@
|
|||||||
|
|
||||||
<groupId>com.microsoft.regorus</groupId>
|
<groupId>com.microsoft.regorus</groupId>
|
||||||
<artifactId>regorus-java</artifactId>
|
<artifactId>regorus-java</artifactId>
|
||||||
<version>0.0.1</version>
|
<version>0.2.2</version>
|
||||||
|
|
||||||
<name>Regorus Java</name>
|
<name>Regorus Java</name>
|
||||||
<description>Java bindings for Regorus - a fast, lightweight Rego interpreter written in Rust</description>
|
<description>Java bindings for Regorus - a fast, lightweight Rego interpreter written in Rust</description>
|
||||||
|
|||||||
@@ -17,6 +17,31 @@ pub extern "system" fn Java_com_microsoft_regorus_Engine_nativeNewEngine(
|
|||||||
Box::into_raw(Box::new(engine)) as jlong
|
Box::into_raw(Box::new(engine)) as jlong
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
pub extern "system" fn Java_com_microsoft_regorus_Engine_nativeClone(
|
||||||
|
_env: JNIEnv,
|
||||||
|
_class: JClass,
|
||||||
|
engine_ptr: jlong,
|
||||||
|
) -> jlong {
|
||||||
|
let engine = unsafe { &mut *(engine_ptr as *mut Engine) };
|
||||||
|
let c = engine.clone();
|
||||||
|
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]
|
#[no_mangle]
|
||||||
pub extern "system" fn Java_com_microsoft_regorus_Engine_nativeAddPolicy(
|
pub extern "system" fn Java_com_microsoft_regorus_Engine_nativeAddPolicy(
|
||||||
env: JNIEnv,
|
env: JNIEnv,
|
||||||
@@ -24,14 +49,19 @@ pub extern "system" fn Java_com_microsoft_regorus_Engine_nativeAddPolicy(
|
|||||||
engine_ptr: jlong,
|
engine_ptr: jlong,
|
||||||
path: JString,
|
path: JString,
|
||||||
rego: JString,
|
rego: JString,
|
||||||
) {
|
) -> jstring {
|
||||||
let _ = throw_err(env, |env| {
|
let res = throw_err(env, |env| {
|
||||||
let engine = unsafe { &mut *(engine_ptr as *mut Engine) };
|
let engine = unsafe { &mut *(engine_ptr as *mut Engine) };
|
||||||
let path: String = env.get_string(&path)?.into();
|
let path: String = env.get_string(&path)?.into();
|
||||||
let rego: String = env.get_string(®o)?.into();
|
let rego: String = env.get_string(®o)?.into();
|
||||||
engine.add_policy(path, rego)?;
|
let pkg = env.new_string(engine.add_policy(path, rego)?)?;
|
||||||
Ok(())
|
Ok(pkg.into_raw())
|
||||||
});
|
});
|
||||||
|
|
||||||
|
match res {
|
||||||
|
Ok(val) => val,
|
||||||
|
Err(_) => JObject::null().into_raw(),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
@@ -40,13 +70,56 @@ pub extern "system" fn Java_com_microsoft_regorus_Engine_nativeAddPolicyFromFile
|
|||||||
_class: JClass,
|
_class: JClass,
|
||||||
engine_ptr: jlong,
|
engine_ptr: jlong,
|
||||||
path: JString,
|
path: JString,
|
||||||
) {
|
) -> jstring {
|
||||||
let _ = throw_err(env, |env| {
|
let res = throw_err(env, |env| {
|
||||||
let engine = unsafe { &mut *(engine_ptr as *mut Engine) };
|
let engine = unsafe { &mut *(engine_ptr as *mut Engine) };
|
||||||
let path: String = env.get_string(&path)?.into();
|
let path: String = env.get_string(&path)?.into();
|
||||||
engine.add_policy_from_file(path)?;
|
let pkg = env.new_string(engine.add_policy_from_file(path)?)?;
|
||||||
Ok(())
|
Ok(pkg.into_raw())
|
||||||
});
|
});
|
||||||
|
|
||||||
|
match res {
|
||||||
|
Ok(val) => val,
|
||||||
|
Err(_) => JObject::null().into_raw(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
pub extern "system" fn Java_com_microsoft_regorus_Engine_nativeGetPackages(
|
||||||
|
env: JNIEnv,
|
||||||
|
_class: JClass,
|
||||||
|
engine_ptr: jlong,
|
||||||
|
) -> jstring {
|
||||||
|
let res = throw_err(env, |env| {
|
||||||
|
let engine = unsafe { &mut *(engine_ptr as *mut Engine) };
|
||||||
|
let packages = engine.get_packages()?;
|
||||||
|
let packages_json = env.new_string(serde_json::to_string_pretty(&packages)?)?;
|
||||||
|
Ok(packages_json.into_raw())
|
||||||
|
});
|
||||||
|
|
||||||
|
match res {
|
||||||
|
Ok(val) => val,
|
||||||
|
Err(_) => JObject::null().into_raw(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
pub extern "system" fn Java_com_microsoft_regorus_Engine_nativeGetPolicies(
|
||||||
|
env: JNIEnv,
|
||||||
|
_class: JClass,
|
||||||
|
engine_ptr: jlong,
|
||||||
|
) -> jstring {
|
||||||
|
let res = throw_err(env, |env| {
|
||||||
|
let engine = unsafe { &mut *(engine_ptr as *mut Engine) };
|
||||||
|
let policies = engine.get_policies_as_json()?;
|
||||||
|
let policies_json = env.new_string(&policies)?;
|
||||||
|
Ok(policies_json.into_raw())
|
||||||
|
});
|
||||||
|
|
||||||
|
match res {
|
||||||
|
Ok(val) => val,
|
||||||
|
Err(_) => JObject::null().into_raw(),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
@@ -117,7 +190,7 @@ pub extern "system" fn Java_com_microsoft_regorus_Engine_nativeSetInputJsonFromF
|
|||||||
let _ = throw_err(env, |env| {
|
let _ = throw_err(env, |env| {
|
||||||
let engine = unsafe { &mut *(engine_ptr as *mut Engine) };
|
let engine = unsafe { &mut *(engine_ptr as *mut Engine) };
|
||||||
let path: String = env.get_string(&path)?.into();
|
let path: String = env.get_string(&path)?.into();
|
||||||
engine.set_input(Value::from_json_file(&path)?);
|
engine.set_input(Value::from_json_file(path)?);
|
||||||
Ok(())
|
Ok(())
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -144,12 +217,157 @@ pub extern "system" fn Java_com_microsoft_regorus_Engine_nativeEvalQuery(
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub unsafe extern "system" fn Java_com_microsoft_regorus_Engine_nativeDestroyEngine(
|
pub extern "system" fn Java_com_microsoft_regorus_Engine_nativeEvalRule(
|
||||||
|
env: JNIEnv,
|
||||||
|
_class: JClass,
|
||||||
|
engine_ptr: jlong,
|
||||||
|
rule: JString,
|
||||||
|
) -> jstring {
|
||||||
|
let res = throw_err(env, |env| {
|
||||||
|
let engine = unsafe { &mut *(engine_ptr as *mut Engine) };
|
||||||
|
let rule: String = env.get_string(&rule)?.into();
|
||||||
|
let value = engine.eval_rule(rule)?;
|
||||||
|
let output = env.new_string(value.to_json_str()?)?;
|
||||||
|
Ok(output.into_raw())
|
||||||
|
});
|
||||||
|
|
||||||
|
match res {
|
||||||
|
Ok(val) => val,
|
||||||
|
Err(_) => JObject::null().into_raw(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
#[cfg(feature = "coverage")]
|
||||||
|
pub extern "system" fn Java_com_microsoft_regorus_Engine_nativeSetEnableCoverage(
|
||||||
|
env: JNIEnv,
|
||||||
|
_class: JClass,
|
||||||
|
engine_ptr: jlong,
|
||||||
|
enable: bool,
|
||||||
|
) {
|
||||||
|
let _ = throw_err(env, |_| {
|
||||||
|
let engine = unsafe { &mut *(engine_ptr as *mut Engine) };
|
||||||
|
engine.set_enable_coverage(enable);
|
||||||
|
Ok(())
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
#[cfg(feature = "coverage")]
|
||||||
|
pub extern "system" fn Java_com_microsoft_regorus_Engine_nativeGetCoverageReport(
|
||||||
|
env: JNIEnv,
|
||||||
|
_class: JClass,
|
||||||
|
engine_ptr: jlong,
|
||||||
|
) -> jstring {
|
||||||
|
let res = throw_err(env, |env| {
|
||||||
|
let engine = unsafe { &mut *(engine_ptr as *mut Engine) };
|
||||||
|
let report = engine.get_coverage_report()?;
|
||||||
|
let output = env.new_string(serde_json::to_string_pretty(&report)?)?;
|
||||||
|
Ok(output.into_raw())
|
||||||
|
});
|
||||||
|
|
||||||
|
match res {
|
||||||
|
Ok(val) => val,
|
||||||
|
Err(_) => JObject::null().into_raw(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
#[cfg(feature = "coverage")]
|
||||||
|
pub extern "system" fn Java_com_microsoft_regorus_Engine_nativeGetCoverageReportPretty(
|
||||||
|
env: JNIEnv,
|
||||||
|
_class: JClass,
|
||||||
|
engine_ptr: jlong,
|
||||||
|
) -> jstring {
|
||||||
|
let res = throw_err(env, |env| {
|
||||||
|
let engine = unsafe { &mut *(engine_ptr as *mut Engine) };
|
||||||
|
let report = engine.get_coverage_report()?.to_string_pretty()?;
|
||||||
|
let output = env.new_string(&report)?;
|
||||||
|
Ok(output.into_raw())
|
||||||
|
});
|
||||||
|
|
||||||
|
match res {
|
||||||
|
Ok(val) => val,
|
||||||
|
Err(_) => JObject::null().into_raw(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
#[cfg(feature = "coverage")]
|
||||||
|
pub extern "system" fn Java_com_microsoft_regorus_Engine_nativeClearCoverageData(
|
||||||
|
env: JNIEnv,
|
||||||
|
_class: JClass,
|
||||||
|
engine_ptr: jlong,
|
||||||
|
) {
|
||||||
|
let _ = throw_err(env, |_| {
|
||||||
|
let engine = unsafe { &mut *(engine_ptr as *mut Engine) };
|
||||||
|
engine.clear_coverage_data();
|
||||||
|
Ok(())
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
pub extern "system" fn Java_com_microsoft_regorus_Engine_nativeSetGatherPrints(
|
||||||
|
env: JNIEnv,
|
||||||
|
_class: JClass,
|
||||||
|
engine_ptr: jlong,
|
||||||
|
b: bool,
|
||||||
|
) {
|
||||||
|
let _ = throw_err(env, |_| {
|
||||||
|
let engine = unsafe { &mut *(engine_ptr as *mut Engine) };
|
||||||
|
engine.set_gather_prints(b);
|
||||||
|
Ok(())
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
pub extern "system" fn Java_com_microsoft_regorus_Engine_nativeTakePrints(
|
||||||
|
env: JNIEnv,
|
||||||
|
_class: JClass,
|
||||||
|
engine_ptr: jlong,
|
||||||
|
) -> jstring {
|
||||||
|
let res = throw_err(env, |env| {
|
||||||
|
let engine = unsafe { &mut *(engine_ptr as *mut Engine) };
|
||||||
|
let prints = engine.take_prints()?;
|
||||||
|
let output = env.new_string(serde_json::to_string_pretty(&prints)?)?;
|
||||||
|
Ok(output.into_raw())
|
||||||
|
});
|
||||||
|
|
||||||
|
match res {
|
||||||
|
Ok(val) => val,
|
||||||
|
Err(_) => JObject::null().into_raw(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
#[cfg(feature = "ast")]
|
||||||
|
pub extern "system" fn Java_com_microsoft_regorus_Engine_getAstAsJson(
|
||||||
|
env: JNIEnv,
|
||||||
|
_class: JClass,
|
||||||
|
engine_ptr: jlong,
|
||||||
|
) -> jstring {
|
||||||
|
let res = throw_err(env, |env| {
|
||||||
|
let engine = unsafe { &mut *(engine_ptr as *mut Engine) };
|
||||||
|
let ast = engine.get_ast_as_json()?;
|
||||||
|
let output = env.new_string(&ast)?;
|
||||||
|
Ok(output.into_raw())
|
||||||
|
});
|
||||||
|
|
||||||
|
match res {
|
||||||
|
Ok(val) => val,
|
||||||
|
Err(_) => JObject::null().into_raw(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
pub extern "system" fn Java_com_microsoft_regorus_Engine_nativeDestroyEngine(
|
||||||
_env: JNIEnv,
|
_env: JNIEnv,
|
||||||
_class: JClass,
|
_class: JClass,
|
||||||
engine_ptr: jlong,
|
engine_ptr: jlong,
|
||||||
) {
|
) {
|
||||||
let _engine = Box::from_raw(engine_ptr as *mut Engine);
|
unsafe {
|
||||||
|
let _engine = Box::from_raw(engine_ptr as *mut Engine);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn throw_err<T>(mut env: JNIEnv, mut f: impl FnMut(&mut JNIEnv) -> Result<T>) -> Result<T> {
|
fn throw_err<T>(mut env: JNIEnv, mut f: impl FnMut(&mut JNIEnv) -> Result<T>) -> Result<T> {
|
||||||
|
|||||||
@@ -8,28 +8,37 @@ package com.microsoft.regorus;
|
|||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.io.UncheckedIOException;
|
|
||||||
import java.nio.file.Files;
|
import java.nio.file.Files;
|
||||||
import java.nio.file.StandardCopyOption;
|
import java.nio.file.StandardCopyOption;
|
||||||
import java.util.concurrent.atomic.AtomicReference;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Regorus Engine.
|
* Regorus Engine.
|
||||||
*/
|
*/
|
||||||
public class Engine implements AutoCloseable {
|
public class Engine implements AutoCloseable, Cloneable {
|
||||||
// Methods exposed from Rust side, you can run
|
// Methods exposed from Rust side, you can run
|
||||||
// `javac -h . src/main/java/com/microsoft/regorus/Engine.java` to update
|
// `javac -h . src/main/java/com/microsoft/regorus/Engine.java` to update
|
||||||
// expected native header at `bindings/java/com_microsoft_regorus_Engine.h`
|
// expected native header at `bindings/java/com_microsoft_regorus_Engine.h`
|
||||||
// if you update the native API.
|
// if you update the native API.
|
||||||
private static native long nativeNewEngine();
|
private static native long nativeNewEngine();
|
||||||
private static native void nativeAddPolicy(long enginePtr, String path, String rego);
|
private static native long nativeClone(long enginePtr);
|
||||||
private static native void nativeAddPolicyFromFile(long enginePtr, String path);
|
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);
|
||||||
|
private static native String nativeGetPolicies(long enginePtr);
|
||||||
private static native void nativeClearData(long enginePtr);
|
private static native void nativeClearData(long enginePtr);
|
||||||
private static native void nativeAddDataJson(long enginePtr, String data);
|
private static native void nativeAddDataJson(long enginePtr, String data);
|
||||||
private static native void nativeAddDataJsonFromFile(long enginePtr, String path);
|
private static native void nativeAddDataJsonFromFile(long enginePtr, String path);
|
||||||
private static native void nativeSetInputJson(long enginePtr, String input);
|
private static native void nativeSetInputJson(long enginePtr, String input);
|
||||||
private static native void nativeSetInputJsonFromFile(long enginePtr, String path);
|
private static native void nativeSetInputJsonFromFile(long enginePtr, String path);
|
||||||
private static native String nativeEvalQuery(long enginePtr, String query);
|
private static native String nativeEvalQuery(long enginePtr, String query);
|
||||||
|
private static native String nativeEvalRule(long enginePtr, String qrule);
|
||||||
|
private static native void nativeSetEnableCoverage(long enginePtr, boolean enable);
|
||||||
|
private static native String nativeGetCoverageReport(long enginePtr);
|
||||||
|
private static native String nativeGetCoverageReportPretty(long enginePtr);
|
||||||
|
private static native void nativeClearCoverageData(long enginePtr);
|
||||||
|
private static native void nativeSetGatherPrints(long enginePtr, boolean b);
|
||||||
|
private static native String nativeTakePrints(long enginePtr);
|
||||||
private static native void nativeDestroyEngine(long enginePtr);
|
private static native void nativeDestroyEngine(long enginePtr);
|
||||||
|
|
||||||
// Pointer to Engine allocated on Rust's heap, all native methods works on
|
// Pointer to Engine allocated on Rust's heap, all native methods works on
|
||||||
@@ -43,25 +52,69 @@ public class Engine implements AutoCloseable {
|
|||||||
enginePtr = nativeNewEngine();
|
enginePtr = nativeNewEngine();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Engine(long ptr) {
|
||||||
|
enginePtr = ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Efficiently clones an Engine.
|
||||||
|
*/
|
||||||
|
public Engine clone() {
|
||||||
|
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.
|
* Adds an inline Rego policy.
|
||||||
*
|
*
|
||||||
* @param filename Filename of this Rego policy.
|
* @param filename Filename of this Rego policy.
|
||||||
* @param rego Rego policy.
|
* @param rego Rego policy.
|
||||||
|
*
|
||||||
|
* @return Rego package defined in the policy.
|
||||||
*/
|
*/
|
||||||
public void addPolicy(String filename, String rego) {
|
public String addPolicy(String filename, String rego) {
|
||||||
nativeAddPolicy(enginePtr, filename, rego);
|
return nativeAddPolicy(enginePtr, filename, rego);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Adds a Rego policy from given path.
|
* Adds a Rego policy from given path.
|
||||||
*
|
*
|
||||||
* @param path Path of the Rego policy.
|
* @param path Path of the Rego policy.
|
||||||
|
*
|
||||||
|
* @return Rego package defined in the policy.
|
||||||
*/
|
*/
|
||||||
public void addPolicyFromFile(String path) {
|
public String addPolicyFromFile(String path) {
|
||||||
nativeAddPolicyFromFile(enginePtr, path);
|
return nativeAddPolicyFromFile(enginePtr, path);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get list of loaded Rego packages.
|
||||||
|
*
|
||||||
|
* @return List of Rego packages as a JSON array of strings.
|
||||||
|
*/
|
||||||
|
public String getPackages() {
|
||||||
|
return nativeGetPackages(enginePtr);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get list of loaded policies.
|
||||||
|
*
|
||||||
|
* @return List of Rego policies as a JSON array of sources.
|
||||||
|
*/
|
||||||
|
public String getPolicies() {
|
||||||
|
return nativeGetPolicies(enginePtr);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Clears the data document.
|
* Clears the data document.
|
||||||
*/
|
*/
|
||||||
@@ -137,6 +190,70 @@ public class Engine implements AutoCloseable {
|
|||||||
return nativeEvalQuery(enginePtr, query);
|
return nativeEvalQuery(enginePtr, query);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Evaluates given Rego rule and returns a JSON string as a result.
|
||||||
|
*
|
||||||
|
* @param rule Path of the Rego rule.
|
||||||
|
*
|
||||||
|
* @return Value of the rule as a JSON string.
|
||||||
|
*/
|
||||||
|
public String evalRule(String rule) {
|
||||||
|
return nativeEvalRule(enginePtr, rule);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Enable/disable coverage.
|
||||||
|
*
|
||||||
|
* @param enable Whether to enable coverage or not.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public void setEnableCoverage(boolean enable) {
|
||||||
|
nativeSetEnableCoverage(enginePtr, enable);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clear coverage data.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public void clearCoverageData() {
|
||||||
|
nativeClearCoverageData(enginePtr);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get coverage report as json string.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public String getCoverageReport() {
|
||||||
|
return nativeGetCoverageReport(enginePtr);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get coverage report as ANSI color coded string.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public String getCoverageReportPretty() {
|
||||||
|
return nativeGetCoverageReportPretty(enginePtr);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Enable/disable gathering prints.
|
||||||
|
*
|
||||||
|
* @param b Whether to gather prints or not.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public void setGatherPrints(boolean b) {
|
||||||
|
nativeSetGatherPrints(enginePtr, b);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Take gathered prints.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public String takePrints() {
|
||||||
|
return nativeTakePrints(enginePtr);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void close() {
|
public void close() {
|
||||||
nativeDestroyEngine(enginePtr);
|
nativeDestroyEngine(enginePtr);
|
||||||
|
|||||||
1672
bindings/python/Cargo.lock
generated
Normal file
1672
bindings/python/Cargo.lock
generated
Normal file
File diff suppressed because it is too large
Load Diff
@@ -1,6 +1,8 @@
|
|||||||
|
[workspace]
|
||||||
|
|
||||||
[package]
|
[package]
|
||||||
name = "regoruspy"
|
name = "regoruspy"
|
||||||
version = "0.1.0"
|
version = "0.4.0"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
repository = "https://github.com/microsoft/regorus/bindings/python"
|
repository = "https://github.com/microsoft/regorus/bindings/python"
|
||||||
description = "Python bindings for Regorus - a fast, lightweight Rego interpreter written in Rust"
|
description = "Python bindings for Regorus - a fast, lightweight Rego interpreter written in Rust"
|
||||||
@@ -11,10 +13,15 @@ keywords = ["interpreter", "opa", "policy-as-code", "rego"]
|
|||||||
[lib]
|
[lib]
|
||||||
crate-type = ["cdylib"]
|
crate-type = ["cdylib"]
|
||||||
|
|
||||||
[dependencies]
|
[features]
|
||||||
anyhow = "1.0.79"
|
default = ["ast", "coverage", "regorus/std", "regorus/full-opa"]
|
||||||
ordered-float = "4.2.0"
|
ast = ["regorus/ast"]
|
||||||
pyo3 = {version = "0.20.2", features = ["anyhow", "extension-module"] }
|
coverage = ["regorus/coverage"]
|
||||||
regorus = { path = "../.." }
|
|
||||||
serde_json = "1.0.112"
|
[dependencies]
|
||||||
|
anyhow = "1.0"
|
||||||
|
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.140"
|
||||||
|
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ Regorus can be used in Python via `regorus` package. (It is not yet available in
|
|||||||
|
|
||||||
See [Repository](https://github.com/microsoft/regorus).
|
See [Repository](https://github.com/microsoft/regorus).
|
||||||
|
|
||||||
To build this binding, see [building](https://github.com/microsoft/regorus/bindings/python/building.md)
|
To build this binding, see [building](https://github.com/microsoft/regorus/blob/main/bindings/python/building.md)
|
||||||
|
|
||||||
## Usage
|
## Usage
|
||||||
```Python
|
```Python
|
||||||
@@ -54,14 +54,11 @@ input = {
|
|||||||
}
|
}
|
||||||
engine.set_input(input)
|
engine.set_input(input)
|
||||||
|
|
||||||
# Eval query
|
# Eval rule
|
||||||
results = engine.eval_query('data.framework.mount_overlay=x')
|
value = engine.eval_rule('data.framework.mount_overlay')
|
||||||
|
|
||||||
# Print results
|
# Print value
|
||||||
print(results['result'][0])
|
print(value)
|
||||||
|
|
||||||
# Eval query as json
|
|
||||||
results_json = engine.eval_query_as_json('data.framework.mount_overlay=x')
|
|
||||||
print(results_json)
|
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|||||||
@@ -13,4 +13,8 @@ classifiers = [
|
|||||||
dynamic = ["version"]
|
dynamic = ["version"]
|
||||||
|
|
||||||
[tool.maturin]
|
[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"]
|
||||||
@@ -4,6 +4,7 @@ use anyhow::{anyhow, Result};
|
|||||||
use pyo3::exceptions::PyTypeError;
|
use pyo3::exceptions::PyTypeError;
|
||||||
use pyo3::prelude::*;
|
use pyo3::prelude::*;
|
||||||
use pyo3::types::*;
|
use pyo3::types::*;
|
||||||
|
use pyo3::IntoPyObjectExt;
|
||||||
|
|
||||||
use std::collections::{BTreeMap, BTreeSet};
|
use std::collections::{BTreeMap, BTreeSet};
|
||||||
|
|
||||||
@@ -21,24 +22,12 @@ impl Default for Engine {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Clone for Engine {
|
fn from(ob: &Bound<'_, PyAny>) -> Result<Value, PyErr> {
|
||||||
/// Clone a [`Engine`]
|
|
||||||
///
|
|
||||||
/// To avoid having to parse same policy again, the engine can be cloned
|
|
||||||
/// after policies and data have been added.
|
|
||||||
fn clone(&self) -> Self {
|
|
||||||
Self {
|
|
||||||
engine: self.engine.clone(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn from<'source>(ob: &'source PyAny) -> Result<Value, PyErr> {
|
|
||||||
// dicts
|
// dicts
|
||||||
Ok(if let Ok(dict) = ob.downcast::<PyDict>() {
|
Ok(if let Ok(dict) = ob.downcast::<PyDict>() {
|
||||||
let mut map = BTreeMap::new();
|
let mut map = BTreeMap::new();
|
||||||
for (k, v) in dict {
|
for (k, v) in dict {
|
||||||
map.insert(from(k)?, from(v)?);
|
map.insert(from(&k)?, from(&v)?);
|
||||||
}
|
}
|
||||||
map.into()
|
map.into()
|
||||||
}
|
}
|
||||||
@@ -46,7 +35,7 @@ fn from<'source>(ob: &'source PyAny) -> Result<Value, PyErr> {
|
|||||||
else if let Ok(pset) = ob.downcast::<PySet>() {
|
else if let Ok(pset) = ob.downcast::<PySet>() {
|
||||||
let mut set = BTreeSet::new();
|
let mut set = BTreeSet::new();
|
||||||
for v in pset {
|
for v in pset {
|
||||||
set.insert(from(v)?);
|
set.insert(from(&v)?);
|
||||||
}
|
}
|
||||||
set.into()
|
set.into()
|
||||||
}
|
}
|
||||||
@@ -55,7 +44,7 @@ fn from<'source>(ob: &'source PyAny) -> Result<Value, PyErr> {
|
|||||||
//
|
//
|
||||||
let mut set = BTreeSet::new();
|
let mut set = BTreeSet::new();
|
||||||
for v in pfset {
|
for v in pfset {
|
||||||
set.insert(from(v)?);
|
set.insert(from(&v)?);
|
||||||
}
|
}
|
||||||
set.into()
|
set.into()
|
||||||
}
|
}
|
||||||
@@ -63,30 +52,30 @@ fn from<'source>(ob: &'source PyAny) -> Result<Value, PyErr> {
|
|||||||
else if let Ok(plist) = ob.downcast::<PyList>() {
|
else if let Ok(plist) = ob.downcast::<PyList>() {
|
||||||
let mut array = Vec::new();
|
let mut array = Vec::new();
|
||||||
for v in plist {
|
for v in plist {
|
||||||
array.push(from(v)?);
|
array.push(from(&v)?);
|
||||||
}
|
}
|
||||||
array.into()
|
array.into()
|
||||||
} else if let Ok(ptuple) = ob.downcast::<PyTuple>() {
|
} else if let Ok(ptuple) = ob.downcast::<PyTuple>() {
|
||||||
let mut array = Vec::new();
|
let mut array = Vec::new();
|
||||||
for v in ptuple {
|
for v in ptuple {
|
||||||
array.push(from(v)?);
|
array.push(from(&v)?);
|
||||||
}
|
}
|
||||||
array.into()
|
array.into()
|
||||||
}
|
}
|
||||||
// String
|
// String
|
||||||
else if let Ok(s) = String::extract(ob) {
|
else if let Ok(s) = ob.extract::<String>() {
|
||||||
s.into()
|
s.into()
|
||||||
}
|
}
|
||||||
// Numeric
|
// Numeric
|
||||||
else if let Ok(v) = i64::extract(ob) {
|
else if let Ok(v) = ob.extract::<i64>() {
|
||||||
v.into()
|
v.into()
|
||||||
} else if let Ok(v) = u64::extract(ob) {
|
} else if let Ok(v) = ob.extract::<u64>() {
|
||||||
v.into()
|
v.into()
|
||||||
} else if let Ok(v) = f64::extract(ob) {
|
} else if let Ok(v) = ob.extract::<f64>() {
|
||||||
v.into()
|
v.into()
|
||||||
}
|
}
|
||||||
// Boolean
|
// Boolean
|
||||||
else if let Ok(b) = bool::extract(ob) {
|
else if let Ok(b) = ob.extract::<bool>() {
|
||||||
b.into()
|
b.into()
|
||||||
}
|
}
|
||||||
// None
|
// None
|
||||||
@@ -97,7 +86,7 @@ fn from<'source>(ob: &'source PyAny) -> Result<Value, PyErr> {
|
|||||||
else if let Ok(pseq) = ob.downcast::<PySequence>() {
|
else if let Ok(pseq) = ob.downcast::<PySequence>() {
|
||||||
let mut array = Vec::new();
|
let mut array = Vec::new();
|
||||||
for i in 0..pseq.len()? {
|
for i in 0..pseq.len()? {
|
||||||
array.push(from(pseq.get_item(i)?)?);
|
array.push(from(&pseq.get_item(i)?)?);
|
||||||
}
|
}
|
||||||
array.into()
|
array.into()
|
||||||
}
|
}
|
||||||
@@ -106,10 +95,10 @@ fn from<'source>(ob: &'source PyAny) -> Result<Value, PyErr> {
|
|||||||
let mut map = BTreeMap::new();
|
let mut map = BTreeMap::new();
|
||||||
let keys = pmap.keys()?;
|
let keys = pmap.keys()?;
|
||||||
let values = pmap.values()?;
|
let values = pmap.values()?;
|
||||||
for i in 0..keys.len()? {
|
for i in 0..keys.len() {
|
||||||
let key = keys.get_item(i)?;
|
let key = keys.get_item(i)?;
|
||||||
let value = values.get_item(i)?;
|
let value = values.get_item(i)?;
|
||||||
map.insert(from(key)?, from(value)?);
|
map.insert(from(&key)?, from(&value)?);
|
||||||
}
|
}
|
||||||
map.into()
|
map.into()
|
||||||
} else {
|
} else {
|
||||||
@@ -120,49 +109,53 @@ fn from<'source>(ob: &'source PyAny) -> Result<Value, PyErr> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn to(mut v: Value, py: Python<'_>) -> Result<PyObject> {
|
fn to(mut v: Value, py: Python<'_>) -> Result<PyObject> {
|
||||||
Ok(match v {
|
let obj = match v {
|
||||||
Value::Null => None::<u64>.to_object(py),
|
Value::Null => None::<u64>.into_bound_py_any(py),
|
||||||
|
|
||||||
// TODO: Revisit this mapping
|
// 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::Bool(b) => b.into_bound_py_any(py),
|
||||||
Value::String(s) => s.to_object(py),
|
Value::String(s) => s.into_bound_py_any(py),
|
||||||
|
|
||||||
Value::Number(_) => {
|
Value::Number(_) => {
|
||||||
if let Ok(f) = v.as_f64() {
|
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() {
|
} else if let Ok(u) = v.as_u64() {
|
||||||
u.to_object(py)
|
u.into_bound_py_any(py)
|
||||||
} else {
|
} else {
|
||||||
v.as_i64()?.to_object(py)
|
v.as_i64()?.into_bound_py_any(py)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Value::Array(_) => {
|
Value::Array(_) => {
|
||||||
let list = PyList::empty(py);
|
let list = PyList::empty(py);
|
||||||
for v in std::mem::replace(v.as_array_mut()?, Vec::new()) {
|
for v in std::mem::take(v.as_array_mut()?) {
|
||||||
list.append(to(v, py)?)?;
|
list.append(to(v, py)?)?;
|
||||||
}
|
}
|
||||||
list.into()
|
list.into_bound_py_any(py)
|
||||||
}
|
}
|
||||||
|
|
||||||
Value::Set(_) => {
|
Value::Set(_) => {
|
||||||
let set = PySet::empty(py)?;
|
let set = PySet::empty(py)?;
|
||||||
for v in std::mem::replace(v.as_set_mut()?, BTreeSet::new()) {
|
for v in std::mem::take(v.as_set_mut()?) {
|
||||||
set.add(to(v, py)?)?;
|
set.add(to(v, py)?)?;
|
||||||
}
|
}
|
||||||
set.into()
|
set.into_bound_py_any(py)
|
||||||
}
|
}
|
||||||
|
|
||||||
Value::Object(_) => {
|
Value::Object(_) => {
|
||||||
let dict = PyDict::new(py);
|
let dict = PyDict::new(py);
|
||||||
for (k, v) in std::mem::replace(v.as_object_mut()?, BTreeMap::new()) {
|
for (k, v) in std::mem::take(v.as_object_mut()?) {
|
||||||
dict.set_item(to(k, py)?, to(v, py)?)?;
|
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]
|
#[pymethods]
|
||||||
@@ -175,13 +168,22 @@ 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
|
/// Add a policy
|
||||||
///
|
///
|
||||||
/// The policy is parsed into AST.
|
/// The policy is parsed into AST.
|
||||||
///
|
///
|
||||||
/// * `path`: A filename to be associated with the policy.
|
/// * `path`: A filename to be associated with the policy.
|
||||||
/// * `rego`: Rego policy.
|
/// * `rego`: Rego policy.
|
||||||
pub fn add_policy(&mut self, path: String, rego: String) -> Result<()> {
|
pub fn add_policy(&mut self, path: String, rego: String) -> Result<String> {
|
||||||
self.engine.add_policy(path, rego)
|
self.engine.add_policy(path, rego)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -190,15 +192,29 @@ impl Engine {
|
|||||||
/// The policy is parsed into AST.
|
/// The policy is parsed into AST.
|
||||||
///
|
///
|
||||||
/// * `path`: Path to the policy file.
|
/// * `path`: Path to the policy file.
|
||||||
pub fn add_policy_from_file(&mut self, path: String) -> Result<()> {
|
pub fn add_policy_from_file(&mut self, path: String) -> Result<String> {
|
||||||
self.engine.add_policy_from_file(path)
|
self.engine.add_policy_from_file(path)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get the list of packages defined by loaded policies.
|
||||||
|
///
|
||||||
|
pub fn get_packages(&self) -> Result<Vec<String>> {
|
||||||
|
self.engine.get_packages()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get the list of policies.
|
||||||
|
///
|
||||||
|
pub fn get_policies(&self) -> Result<String> {
|
||||||
|
Ok(serde_json::to_string_pretty(
|
||||||
|
&self.engine.get_policies_as_json()?,
|
||||||
|
)?)
|
||||||
|
}
|
||||||
|
|
||||||
/// Add policy data.
|
/// Add policy data.
|
||||||
///
|
///
|
||||||
/// * `data`: Rego value. A Rego value is a number, bool, string, None
|
/// * `data`: Rego value. A Rego value is a number, bool, string, None
|
||||||
/// or a list/set/map whose items themselves are Rego values.
|
/// or a list/set/map whose items themselves are Rego values.
|
||||||
pub fn add_data(&mut self, data: &PyAny) -> Result<()> {
|
pub fn add_data(&mut self, data: &Bound<'_, PyAny>) -> Result<()> {
|
||||||
let data = from(data)?;
|
let data = from(data)?;
|
||||||
self.engine.add_data(data)
|
self.engine.add_data(data)
|
||||||
}
|
}
|
||||||
@@ -215,7 +231,7 @@ impl Engine {
|
|||||||
///
|
///
|
||||||
/// * `path`: Path to JSON policy data.
|
/// * `path`: Path to JSON policy data.
|
||||||
pub fn add_data_from_json_file(&mut self, path: String) -> Result<()> {
|
pub fn add_data_from_json_file(&mut self, path: String) -> Result<()> {
|
||||||
let data = Value::from_json_file(&path)?;
|
let data = Value::from_json_file(path)?;
|
||||||
self.engine.add_data(data)
|
self.engine.add_data(data)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -229,7 +245,7 @@ impl Engine {
|
|||||||
///
|
///
|
||||||
/// * `input`: Rego value. A Rego value is a number, bool, string, None
|
/// * `input`: Rego value. A Rego value is a number, bool, string, None
|
||||||
/// or a list/set/map whose items themselves are Rego values.
|
/// or a list/set/map whose items themselves are Rego values.
|
||||||
pub fn set_input(&mut self, input: &PyAny) -> Result<()> {
|
pub fn set_input(&mut self, input: &Bound<'_, PyAny>) -> Result<()> {
|
||||||
let input = from(input)?;
|
let input = from(input)?;
|
||||||
self.engine.set_input(input);
|
self.engine.set_input(input);
|
||||||
Ok(())
|
Ok(())
|
||||||
@@ -248,7 +264,7 @@ impl Engine {
|
|||||||
///
|
///
|
||||||
/// * `path`: Path to JSON input data.
|
/// * `path`: Path to JSON input data.
|
||||||
pub fn set_input_from_json_file(&mut self, path: String) -> Result<()> {
|
pub fn set_input_from_json_file(&mut self, path: String) -> Result<()> {
|
||||||
let input = Value::from_json_file(&path)?;
|
let input = Value::from_json_file(path)?;
|
||||||
self.engine.set_input(input);
|
self.engine.set_input(input);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@@ -266,23 +282,23 @@ impl Engine {
|
|||||||
let elist = PyList::empty(py);
|
let elist = PyList::empty(py);
|
||||||
for expr in result.expressions.into_iter() {
|
for expr in result.expressions.into_iter() {
|
||||||
let edict = PyDict::new(py);
|
let edict = PyDict::new(py);
|
||||||
edict.set_item("value".to_object(py), to(expr.value, py)?)?;
|
edict.set_item("value", to(expr.value, py)?)?;
|
||||||
edict.set_item("text".to_object(py), expr.text.as_ref().to_object(py))?;
|
edict.set_item("text", expr.text.as_ref())?;
|
||||||
|
|
||||||
let ldict = PyDict::new(py);
|
let ldict = PyDict::new(py);
|
||||||
ldict.set_item("row".to_object(py), expr.location.row.to_object(py))?;
|
ldict.set_item("row", expr.location.row)?;
|
||||||
ldict.set_item("col".to_object(py), expr.location.col.to_object(py))?;
|
ldict.set_item("col", expr.location.col)?;
|
||||||
|
|
||||||
edict.set_item("location".to_object(py), ldict)?;
|
edict.set_item("location", ldict)?;
|
||||||
elist.append(edict)?;
|
elist.append(edict)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
rdict.set_item("expressions".to_object(py), elist)?;
|
rdict.set_item("expressions", elist)?;
|
||||||
rdict.set_item("bindings".to_object(py), to(result.bindings, py)?)?;
|
rdict.set_item("bindings", to(result.bindings, py)?)?;
|
||||||
rlist.append(rdict)?;
|
rlist.append(rdict)?;
|
||||||
}
|
}
|
||||||
let dict = PyDict::new(py);
|
let dict = PyDict::new(py);
|
||||||
dict.set_item("result".to_object(py), rlist)?;
|
dict.set_item("result", rlist)?;
|
||||||
Ok(dict.into())
|
Ok(dict.into())
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -293,9 +309,82 @@ impl Engine {
|
|||||||
let results = self.engine.eval_query(query, false)?;
|
let results = self.engine.eval_query(query, false)?;
|
||||||
serde_json::to_string_pretty(&results).map_err(|e| anyhow!("{e}"))
|
serde_json::to_string_pretty(&results).map_err(|e| anyhow!("{e}"))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Evaluate rule.
|
||||||
|
///
|
||||||
|
/// * `rule`: Full path to the rule.
|
||||||
|
pub fn eval_rule(&mut self, rule: String, py: Python<'_>) -> Result<PyObject> {
|
||||||
|
to(self.engine.eval_rule(rule)?, py)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Evaluate rule and return value as json.
|
||||||
|
///
|
||||||
|
/// * `rule`: Full path to the rule.
|
||||||
|
pub fn eval_rule_as_json(&mut self, rule: String) -> Result<String> {
|
||||||
|
let v = self.engine.eval_rule(rule)?;
|
||||||
|
v.to_json_str()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Enable code coverage
|
||||||
|
///
|
||||||
|
/// * `enable`: Whether to enable coverage or not.
|
||||||
|
pub fn set_enable_coverage(&mut self, enable: bool) {
|
||||||
|
self.engine.set_enable_coverage(enable)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get coverage report as json.
|
||||||
|
///
|
||||||
|
#[cfg(feature = "coverage")]
|
||||||
|
pub fn get_coverage_report_as_json(&self) -> Result<String> {
|
||||||
|
let report = self.engine.get_coverage_report()?;
|
||||||
|
serde_json::to_string_pretty(&report).map_err(|e| anyhow!("{e}"))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get coverage report as pretty printable string.
|
||||||
|
///
|
||||||
|
#[cfg(feature = "coverage")]
|
||||||
|
pub fn get_coverage_report_pretty(&self) -> Result<String> {
|
||||||
|
self.engine.get_coverage_report()?.to_string_pretty()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Clear coverage data.
|
||||||
|
///
|
||||||
|
#[cfg(feature = "coverage")]
|
||||||
|
pub fn clear_coverage_data(&mut self) {
|
||||||
|
self.engine.clear_coverage_data();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Gather print statements instead of printing to stderr.
|
||||||
|
///
|
||||||
|
pub fn set_gather_prints(&mut self, b: bool) {
|
||||||
|
self.engine.set_gather_prints(b)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Take gathered prints.
|
||||||
|
///
|
||||||
|
pub fn take_prints(&mut self) -> Result<Vec<String>> {
|
||||||
|
self.engine.take_prints()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Clone a [`Engine`]
|
||||||
|
///
|
||||||
|
/// To avoid having to parse same policy again, the engine can be cloned
|
||||||
|
/// after policies and data have been added.
|
||||||
|
fn clone(&self) -> Self {
|
||||||
|
Self {
|
||||||
|
engine: self.engine.clone(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get AST of policies.
|
||||||
|
///
|
||||||
|
#[cfg(feature = "ast")]
|
||||||
|
pub fn get_ast_as_json(&self) -> Result<String> {
|
||||||
|
self.engine.get_ast_as_json()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[pymodule]
|
#[pymodule]
|
||||||
pub fn regorus(_py: Python<'_>, m: &PyModule) -> PyResult<()> {
|
pub fn regorus(_py: Python<'_>, m: &Bound<'_, PyModule>) -> PyResult<()> {
|
||||||
m.add_class::<crate::Engine>()
|
m.add_class::<crate::Engine>()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,10 +6,17 @@ import regorus
|
|||||||
# Create engine
|
# Create engine
|
||||||
engine = regorus.Engine()
|
engine = regorus.Engine()
|
||||||
|
|
||||||
|
engine.set_rego_v0(True)
|
||||||
|
|
||||||
# Load policies
|
# Load policies
|
||||||
engine.add_policy_from_file('../../tests/aci/framework.rego')
|
pkg = engine.add_policy_from_file('../../tests/aci/framework.rego')
|
||||||
engine.add_policy_from_file('../../tests/aci/api.rego')
|
print(' Loaded package %s' % pkg)
|
||||||
engine.add_policy_from_file('../../tests/aci/policy.rego')
|
|
||||||
|
pkg = engine.add_policy_from_file('../../tests/aci/api.rego')
|
||||||
|
print(' Loaded package %s' % pkg)
|
||||||
|
|
||||||
|
pkg = engine.add_policy_from_file('../../tests/aci/policy.rego')
|
||||||
|
print(' Loaded package %s' % pkg)
|
||||||
|
|
||||||
# Add policy data
|
# Add policy data
|
||||||
data = {
|
data = {
|
||||||
@@ -50,3 +57,40 @@ print(results['result'][0])
|
|||||||
# Eval query as json
|
# Eval query as json
|
||||||
results_json = engine.eval_query_as_json('data.framework.mount_overlay=x')
|
results_json = engine.eval_query_as_json('data.framework.mount_overlay=x')
|
||||||
print(results_json)
|
print(results_json)
|
||||||
|
|
||||||
|
# Eval rule
|
||||||
|
v = engine.eval_rule('data.framework.mount_overlay')
|
||||||
|
print(v)
|
||||||
|
|
||||||
|
# Eval rule as json
|
||||||
|
v = engine.eval_rule_as_json('data.framework.mount_overlay')
|
||||||
|
print(v)
|
||||||
|
|
||||||
|
# Enable coverage
|
||||||
|
engine.set_enable_coverage(True)
|
||||||
|
engine.eval_rule('data.framework.mount_overlay')
|
||||||
|
|
||||||
|
# Print coverage
|
||||||
|
report_json = engine.get_coverage_report_as_json()
|
||||||
|
print(report_json)
|
||||||
|
|
||||||
|
# Pretty coverage report
|
||||||
|
report = engine.get_coverage_report_pretty()
|
||||||
|
print(report)
|
||||||
|
|
||||||
|
# Clone engine
|
||||||
|
engine1 = engine.clone()
|
||||||
|
|
||||||
|
|
||||||
|
# Clear coverage data
|
||||||
|
engine.clear_coverage_data();
|
||||||
|
|
||||||
|
print(engine1.get_coverage_report_pretty())
|
||||||
|
|
||||||
|
# Enable gathering prints
|
||||||
|
engine1.set_gather_prints(True)
|
||||||
|
|
||||||
|
# Gather prints
|
||||||
|
engine1.eval_query('print("Hello")')
|
||||||
|
ps = engine1.take_prints()
|
||||||
|
print(ps)
|
||||||
|
|||||||
214
bindings/python/test_extensions.py
Normal file
214
bindings/python/test_extensions.py
Normal file
@@ -0,0 +1,214 @@
|
|||||||
|
# Copyright (c) Microsoft Corporation.
|
||||||
|
# Licensed under the MIT License.
|
||||||
|
import json
|
||||||
|
import pytest
|
||||||
|
import regorus
|
||||||
|
|
||||||
|
TEST_EXT_NAME = "Microsoft.Azure.ActiveDirectory.AADSSHLoginForLinux"
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture(name="engine", scope="function")
|
||||||
|
def engine_fixture():
|
||||||
|
"""
|
||||||
|
Fixture to handle creation and cleanup of a default policy engine.
|
||||||
|
New engine is created for each test case.
|
||||||
|
"""
|
||||||
|
engine = regorus.Engine()
|
||||||
|
engine.add_policy_from_file('../../examples/extension_list/agent_extension_policy.rego')
|
||||||
|
yield engine
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture(name="input_data")
|
||||||
|
def input_data_fixture():
|
||||||
|
"""
|
||||||
|
Fixture to handle creation and cleanup of a default input data.
|
||||||
|
New input data is created for each test case.
|
||||||
|
"""
|
||||||
|
input_data = {
|
||||||
|
"extensions": {
|
||||||
|
TEST_EXT_NAME: {
|
||||||
|
"signingInfo": {
|
||||||
|
"extensionSigned": False
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
input_json = json.dumps(input_data)
|
||||||
|
yield input_json
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture(name="default_data")
|
||||||
|
def default_data_fixture():
|
||||||
|
"""Fixture for default data"""
|
||||||
|
data_json = {
|
||||||
|
"azureGuestAgentPolicy": {
|
||||||
|
"policyVersion": "0.1.0",
|
||||||
|
"signingRules": {
|
||||||
|
"extensionSigned": False
|
||||||
|
},
|
||||||
|
"allowListOnly": False
|
||||||
|
}
|
||||||
|
}
|
||||||
|
data_json = json.dumps(data_json)
|
||||||
|
yield data_json
|
||||||
|
|
||||||
|
|
||||||
|
def test_default_data_json(engine, input_data):
|
||||||
|
"""Test the default data in json format for extension policy."""
|
||||||
|
data_json = {
|
||||||
|
"azureGuestAgentPolicy": {
|
||||||
|
"policyVersion": "0.1.0",
|
||||||
|
"signingRules": {
|
||||||
|
"extensionSigned": False
|
||||||
|
},
|
||||||
|
"allowListOnly": False
|
||||||
|
}
|
||||||
|
}
|
||||||
|
data_json = json.dumps(data_json)
|
||||||
|
engine.add_data_json(data_json)
|
||||||
|
engine.set_input_json(input_data)
|
||||||
|
# Eval query
|
||||||
|
results = engine.eval_query('data.agent_extension_policy')
|
||||||
|
assert results['result'][0]['expressions'][0]['value']['extensions_to_download'][TEST_EXT_NAME]['downloadAllowed']
|
||||||
|
|
||||||
|
|
||||||
|
def test_default_data_file(engine, input_data):
|
||||||
|
"""Test the default data in file format for extension policy."""
|
||||||
|
data_default_path = "../../examples/extension_list/agent-extension-default-data.json"
|
||||||
|
engine.add_data_from_json_file(data_default_path)
|
||||||
|
engine.set_input_json(input_data)
|
||||||
|
# Eval query
|
||||||
|
results = engine.eval_query('data.agent_extension_policy')
|
||||||
|
assert results['result'][0]['expressions'][0]['value']['extensions_to_download'][TEST_EXT_NAME]['downloadAllowed']
|
||||||
|
|
||||||
|
|
||||||
|
def test_allow_all(engine, input_data):
|
||||||
|
"""Test the policy engine with allow all policy."""
|
||||||
|
data_json = {
|
||||||
|
"azureGuestAgentPolicy": {
|
||||||
|
"policyVersion": "0.1.0",
|
||||||
|
"signingRules": {
|
||||||
|
"extensionSigned": False
|
||||||
|
},
|
||||||
|
"allowListOnly": False
|
||||||
|
}
|
||||||
|
}
|
||||||
|
data_json = json.dumps(data_json)
|
||||||
|
engine.add_data_json(data_json)
|
||||||
|
engine.set_input_json(input_data)
|
||||||
|
# Eval query
|
||||||
|
results = engine.eval_query('data.agent_extension_policy')
|
||||||
|
assert results['result'][0]['expressions'][0]['value']['extensions_to_download'][TEST_EXT_NAME]['downloadAllowed']
|
||||||
|
|
||||||
|
|
||||||
|
def test_name_only_input(engine, default_data):
|
||||||
|
"""Test input with only the extension name."""
|
||||||
|
input_data = {
|
||||||
|
"extensions": {
|
||||||
|
TEST_EXT_NAME: {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
input_json = json.dumps(input_data)
|
||||||
|
engine.add_data_json(default_data)
|
||||||
|
engine.set_input_json(input_json)
|
||||||
|
# Eval query
|
||||||
|
results = engine.eval_query('data.agent_extension_policy')
|
||||||
|
assert results['result'][0]['expressions'][0]['value']['extensions_to_download'][TEST_EXT_NAME]['downloadAllowed']
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize("input_signed, extension_signed", [
|
||||||
|
(True, True),
|
||||||
|
(True, False),
|
||||||
|
(False, True),
|
||||||
|
(False, False)
|
||||||
|
])
|
||||||
|
def test_extension_signed_rule(engine, input_signed, extension_signed):
|
||||||
|
"""
|
||||||
|
Test extension signing rule. Engine should be able to handle
|
||||||
|
both signed and unsigned extensions, with extensionSigned rule set
|
||||||
|
to either true or false.
|
||||||
|
"""
|
||||||
|
data_json = {
|
||||||
|
"azureGuestAgentPolicy": {
|
||||||
|
"policyVersion": "0.1.0",
|
||||||
|
"signingRules": {
|
||||||
|
"extensionSigned": extension_signed
|
||||||
|
},
|
||||||
|
"allowListOnly": False
|
||||||
|
}
|
||||||
|
}
|
||||||
|
input_data = {
|
||||||
|
"extensions": {
|
||||||
|
TEST_EXT_NAME: {
|
||||||
|
"signingInfo": {
|
||||||
|
"extensionSigned": input_signed
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
data_json = json.dumps(data_json)
|
||||||
|
input_data = json.dumps(input_data)
|
||||||
|
engine.add_data_json(data_json)
|
||||||
|
engine.set_input_json(input_data)
|
||||||
|
# Eval query
|
||||||
|
results = engine.eval_query('data.agent_extension_policy')
|
||||||
|
|
||||||
|
# assert results
|
||||||
|
if extension_signed:
|
||||||
|
assert results['result'][0]['expressions'][0]['value']['extensions_validated'][TEST_EXT_NAME]['signingValidated'] == input_signed
|
||||||
|
else:
|
||||||
|
assert results['result'][0]['expressions'][0]['value']['extensions_validated'][TEST_EXT_NAME]['signingValidated']
|
||||||
|
assert results['result'][0]['expressions'][0]['value']['extensions_to_download'][TEST_EXT_NAME]['downloadAllowed']
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize("ext_allowed, allow_rule", [
|
||||||
|
(True, True),
|
||||||
|
(True, False),
|
||||||
|
(False, True),
|
||||||
|
(False, False)
|
||||||
|
])
|
||||||
|
def test_allowlist_rule(engine, ext_allowed, allow_rule):
|
||||||
|
"""
|
||||||
|
Test allowListOnly rule. Engine should be able to handle
|
||||||
|
both allowed and disallowed extensions, with allowListOnly rule
|
||||||
|
set to either true or false.
|
||||||
|
"""
|
||||||
|
if ext_allowed:
|
||||||
|
ext_name = TEST_EXT_NAME
|
||||||
|
else:
|
||||||
|
ext_name = "random_disallowed_extension"
|
||||||
|
|
||||||
|
input_json = {
|
||||||
|
"extensions": {
|
||||||
|
ext_name: {
|
||||||
|
"signingInfo": {
|
||||||
|
"extensionSigned": False
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
data_json = {
|
||||||
|
"azureGuestAgentPolicy": {
|
||||||
|
"signingRules": {
|
||||||
|
"extensionSigned": False
|
||||||
|
},
|
||||||
|
"allowListOnly": allow_rule
|
||||||
|
},
|
||||||
|
"azureGuestExtensionsPolicy": {
|
||||||
|
"Microsoft.CPlat.Core.RunCommandLinux": {
|
||||||
|
},
|
||||||
|
TEST_EXT_NAME: {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
input_json = json.dumps(input_json)
|
||||||
|
data_json = json.dumps(data_json)
|
||||||
|
engine.add_data_json(data_json)
|
||||||
|
engine.set_input_json(input_json)
|
||||||
|
# Eval query
|
||||||
|
results = engine.eval_query('data.agent_extension_policy')
|
||||||
|
if allow_rule:
|
||||||
|
assert results['result'][0]['expressions'][0]['value']['extensions_to_download'][ext_name]['downloadAllowed'] == ext_allowed
|
||||||
|
else:
|
||||||
|
assert results['result'][0]['expressions'][0]['value']['extensions_to_download'][ext_name]['downloadAllowed']
|
||||||
14
bindings/ruby/.gitignore
vendored
Normal file
14
bindings/ruby/.gitignore
vendored
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
/.bundle/
|
||||||
|
/.yardoc
|
||||||
|
/_yardoc/
|
||||||
|
/coverage/
|
||||||
|
/doc/
|
||||||
|
/pkg/
|
||||||
|
/spec/reports/
|
||||||
|
/tmp/
|
||||||
|
*.bundle
|
||||||
|
*.so
|
||||||
|
*.o
|
||||||
|
*.a
|
||||||
|
mkmf.log
|
||||||
|
target/
|
||||||
29
bindings/ruby/.rubocop.yml
Normal file
29
bindings/ruby/.rubocop.yml
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
require:
|
||||||
|
- rubocop-minitest
|
||||||
|
- rubocop-rake
|
||||||
|
|
||||||
|
AllCops:
|
||||||
|
TargetRubyVersion: 3.4
|
||||||
|
NewCops: enable
|
||||||
|
|
||||||
|
Layout/LineLength:
|
||||||
|
Max: 180
|
||||||
|
|
||||||
|
Lint/EmptyClass:
|
||||||
|
Enabled: false
|
||||||
|
|
||||||
|
Metrics/ClassLength:
|
||||||
|
Exclude:
|
||||||
|
- 'test/**/*.rb'
|
||||||
|
|
||||||
|
Metrics/MethodLength:
|
||||||
|
Enabled: false
|
||||||
|
|
||||||
|
Style/StringLiterals:
|
||||||
|
EnforcedStyle: double_quotes
|
||||||
|
|
||||||
|
Style/StringLiteralsInInterpolation:
|
||||||
|
EnforcedStyle: double_quotes
|
||||||
|
|
||||||
|
Style/WordArray:
|
||||||
|
Enabled: false
|
||||||
1
bindings/ruby/.tool-versions
Normal file
1
bindings/ruby/.tool-versions
Normal file
@@ -0,0 +1 @@
|
|||||||
|
ruby 3.4.2
|
||||||
5
bindings/ruby/CHANGELOG.md
Normal file
5
bindings/ruby/CHANGELOG.md
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
## [Unreleased]
|
||||||
|
|
||||||
|
## [0.1.0] - 2024-03-29
|
||||||
|
|
||||||
|
- Initial release
|
||||||
1706
bindings/ruby/Cargo.lock
generated
Normal file
1706
bindings/ruby/Cargo.lock
generated
Normal file
File diff suppressed because it is too large
Load Diff
3
bindings/ruby/Cargo.toml
Normal file
3
bindings/ruby/Cargo.toml
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
[workspace]
|
||||||
|
members = ["ext/regorusrb"]
|
||||||
|
resolver = "2"
|
||||||
16
bindings/ruby/Gemfile
Normal file
16
bindings/ruby/Gemfile
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
source "https://rubygems.org"
|
||||||
|
|
||||||
|
# Specify your gem's dependencies in regorusrb.gemspec
|
||||||
|
gemspec
|
||||||
|
|
||||||
|
# These gems are required for local development and testing,
|
||||||
|
# but won't be included in the published gem
|
||||||
|
gem "minitest", "~> 5.25"
|
||||||
|
gem "rake", "~> 13.2"
|
||||||
|
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
|
||||||
68
bindings/ruby/Gemfile.lock
Normal file
68
bindings/ruby/Gemfile.lock
Normal file
@@ -0,0 +1,68 @@
|
|||||||
|
PATH
|
||||||
|
remote: .
|
||||||
|
specs:
|
||||||
|
regorusrb (0.3.0)
|
||||||
|
rb_sys (~> 0.9.111)
|
||||||
|
|
||||||
|
GEM
|
||||||
|
remote: https://rubygems.org/
|
||||||
|
specs:
|
||||||
|
ast (2.4.2)
|
||||||
|
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.1)
|
||||||
|
rainbow (3.1.1)
|
||||||
|
rake (13.2.1)
|
||||||
|
rake-compiler (1.2.9)
|
||||||
|
rake
|
||||||
|
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.2)
|
||||||
|
lint_roller (~> 1.1.0)
|
||||||
|
parallel (~> 1.10)
|
||||||
|
parser (>= 3.3.0.2)
|
||||||
|
rainbow (>= 2.2.2, < 4.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, < 4.0)
|
||||||
|
rubocop-ast (1.38.1)
|
||||||
|
parser (>= 3.3.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)
|
||||||
|
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.25)
|
||||||
|
rake (~> 13.2)
|
||||||
|
rake-compiler (~> 1.2)
|
||||||
|
rake-compiler-dock (~> 1.9)
|
||||||
|
regorusrb!
|
||||||
|
rubocop (~> 1.73)
|
||||||
|
rubocop-minitest (~> 0.37.1)
|
||||||
|
rubocop-rake (~> 0.7.1)
|
||||||
|
|
||||||
|
BUNDLED WITH
|
||||||
|
2.6.5
|
||||||
21
bindings/ruby/LICENSE.txt
Normal file
21
bindings/ruby/LICENSE.txt
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) Microsoft Corporation.
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE
|
||||||
102
bindings/ruby/README.md
Normal file
102
bindings/ruby/README.md
Normal file
@@ -0,0 +1,102 @@
|
|||||||
|
# Regorusrb
|
||||||
|
|
||||||
|
**Regorus** is
|
||||||
|
|
||||||
|
- *Rego*-*Rus(t)* - A fast, light-weight [Rego](https://www.openpolicyagent.org/docs/latest/policy-language/)
|
||||||
|
interpreter written in Rust.
|
||||||
|
- *Rigorous* - A rigorous enforcer of well-defined Rego semantics.
|
||||||
|
|
||||||
|
## Installation
|
||||||
|
|
||||||
|
Regorus can be used in Ruby by configuring bundler to build from the remote git source.
|
||||||
|
|
||||||
|
If using [Bundler](https://bundler.io/) to manage gems (recommended), edit your gemfile to include the following
|
||||||
|
`
|
||||||
|
gem "regorusrb", git: "https://github.com/microsoft/regorus/", glob: "bindings/ruby/*.gemspec"
|
||||||
|
`
|
||||||
|
|
||||||
|
or manually install checkout the source and build the gem
|
||||||
|
|
||||||
|
`
|
||||||
|
git clone https://github.com/microsoft/regorus/
|
||||||
|
cd regorus/bindings/ruby
|
||||||
|
rake && rake build # should eventually output 'regorusrb 0.1.0 built to pkg/regorusrb-0.1.0.gem.'
|
||||||
|
gem install --local ./pkg/regorusrb-0.1.0.gem
|
||||||
|
`
|
||||||
|
|
||||||
|
It is not yet available in rubygems.
|
||||||
|
|
||||||
|
See [Repository](https://github.com/microsoft/regorus).
|
||||||
|
|
||||||
|
To build this gem locally without bundler,
|
||||||
|
|
||||||
|
`rake build`
|
||||||
|
|
||||||
|
then to install the gem and build the native extensions
|
||||||
|
|
||||||
|
`gem install --local ./pkg/regorusrb-0.1.0.gem`
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
```ruby
|
||||||
|
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')
|
||||||
|
|
||||||
|
|
||||||
|
# can be strings or symbols
|
||||||
|
data = {
|
||||||
|
metadata: {
|
||||||
|
devices: {
|
||||||
|
"/run/layers/p0-layer0": "1b80f120dbd88e4355d6241b519c3e25290215c469516b49dece9cf07175a766",
|
||||||
|
"/run/layers/p0-layer1": "e769d7487cc314d3ee748a4440805317c19262c7acd2fdbdb0d47d2e4613a15c",
|
||||||
|
"/run/layers/p0-layer2": "eb36921e1f82af46dfe248ef8f1b3afb6a5230a64181d960d10237a08cd73c79",
|
||||||
|
"/run/layers/p0-layer3": "41d64cdeb347bf236b4c13b7403b633ff11f1cf94dbc7cf881a44d6da88c5156",
|
||||||
|
"/run/layers/p0-layer4": "4dedae42847c704da891a28c25d32201a1ae440bce2aecccfa8e6f03b97a6a6c",
|
||||||
|
"/run/layers/p0-layer5": "fe84c9d5bfddd07a2624d00333cf13c1a9c941f3a261f13ead44fc6a93bc0e7a"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
engine.add_data(data)
|
||||||
|
input = {
|
||||||
|
"containerID": "container0",
|
||||||
|
"layerPaths": [
|
||||||
|
"/run/layers/p0-layer0",
|
||||||
|
"/run/layers/p0-layer1",
|
||||||
|
"/run/layers/p0-layer2",
|
||||||
|
"/run/layers/p0-layer3",
|
||||||
|
"/run/layers/p0-layer4",
|
||||||
|
"/run/layers/p0-layer5"
|
||||||
|
],
|
||||||
|
"target": "/run/gcs/c/container0/rootfs"
|
||||||
|
}
|
||||||
|
|
||||||
|
engine.set_input(input)
|
||||||
|
|
||||||
|
# Evaluate a specife rule
|
||||||
|
rule_results = engine.eval_rule('data.framework.mount_overlay')
|
||||||
|
puts rule_results # { "allowed" => true, "metadata" => [...]}
|
||||||
|
|
||||||
|
# Or evalute a full policy document
|
||||||
|
query_results = engine.eval_query('data.framework')
|
||||||
|
puts query_results[:result][0]
|
||||||
|
|
||||||
|
# Query results can can also be returned as JSON strings instead of Ruby Hash structure
|
||||||
|
results_json = engine.eval_query_as_json('data.framework.mount_overlay=x')
|
||||||
|
puts results_json
|
||||||
|
```
|
||||||
|
|
||||||
|
## Development
|
||||||
|
|
||||||
|
To update the gem version or dependencies within `bindings/ruby/Gemfile.lock`, run `bundle update --gemfile=bindings/ruby/Gemfile` from the project directory, or `cd bindings/ruby && bundle update`
|
||||||
|
|
||||||
|
After checking out the repo, `cd bindings/ruby` and run `bin/setup` to install dependencies. Then, run `rake test` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
|
||||||
|
|
||||||
29
bindings/ruby/Rakefile
Normal file
29
bindings/ruby/Rakefile
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
require "bundler/gem_tasks"
|
||||||
|
require "minitest/test_task"
|
||||||
|
require "rake/extensiontask"
|
||||||
|
require "rubocop/rake_task"
|
||||||
|
require "rb_sys/extensiontask"
|
||||||
|
|
||||||
|
Minitest::TestTask.create
|
||||||
|
|
||||||
|
RuboCop::RakeTask.new
|
||||||
|
|
||||||
|
desc "build the .gem file, including native extensions, according to the .gemspec"
|
||||||
|
task build: :compile
|
||||||
|
|
||||||
|
GEMSPEC = Gem::Specification.load("regorusrb.gemspec")
|
||||||
|
|
||||||
|
RbSys::ExtensionTask.new("regorusrb", GEMSPEC) do |ext|
|
||||||
|
ext.lib_dir = "lib/regorus"
|
||||||
|
ext.cross_compile = true
|
||||||
|
ext.cross_platform = %w[x86-mingw32 x64-mingw-ucrt x64-mingw32 x86-linux x86_64-linux x86_64-darwin arm64-darwin]
|
||||||
|
end
|
||||||
|
|
||||||
|
task default: %i[compile test rubocop]
|
||||||
|
|
||||||
|
desc "Build native extension for a given platform (i.e. rake 'native[x86_64-linux]')"
|
||||||
|
task :native, [:platform] do |_t, platform:|
|
||||||
|
sh "bundle", "exec", "rb-sys-dock", "--platform", platform, "--build"
|
||||||
|
end
|
||||||
11
bindings/ruby/bin/console
Executable file
11
bindings/ruby/bin/console
Executable file
@@ -0,0 +1,11 @@
|
|||||||
|
#!/usr/bin/env ruby
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
require "bundler/setup"
|
||||||
|
require "regorus"
|
||||||
|
|
||||||
|
# You can add fixtures and/or initialization code here to make experimenting
|
||||||
|
# with your gem easier. You can also use a different console, if you like.
|
||||||
|
|
||||||
|
require "irb"
|
||||||
|
IRB.start(__FILE__)
|
||||||
8
bindings/ruby/bin/setup
Executable file
8
bindings/ruby/bin/setup
Executable file
@@ -0,0 +1,8 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
set -euo pipefail
|
||||||
|
IFS=$'\n\t'
|
||||||
|
set -vx
|
||||||
|
|
||||||
|
bundle install
|
||||||
|
|
||||||
|
# Do any other automated setup that you need to do here
|
||||||
21
bindings/ruby/ext/regorusrb/Cargo.toml
Normal file
21
bindings/ruby/ext/regorusrb/Cargo.toml
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
[package]
|
||||||
|
name = "regorusrb"
|
||||||
|
version = "0.3.0"
|
||||||
|
edition = "2024"
|
||||||
|
description = "Ruby bindings for Regorus - a fast, lightweight Rego interpreter written in Rust"
|
||||||
|
publish = false
|
||||||
|
|
||||||
|
[lib]
|
||||||
|
crate-type = ["cdylib"]
|
||||||
|
path = "src/lib.rs"
|
||||||
|
|
||||||
|
[features]
|
||||||
|
default = ["ast", "coverage", "regorus/std", "regorus/full-opa"]
|
||||||
|
ast = ["regorus/ast"]
|
||||||
|
coverage = ["regorus/coverage"]
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
magnus = { version = "0.7.1" }
|
||||||
|
regorus = { path = "../../../..", default-features = false, features = ["arc"] }
|
||||||
|
serde_json = "1.0.140"
|
||||||
|
serde_magnus = "0.9.0"
|
||||||
8
bindings/ruby/ext/regorusrb/extconf.rb
Normal file
8
bindings/ruby/ext/regorusrb/extconf.rb
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
require "mkmf"
|
||||||
|
require "rb_sys/mkmf"
|
||||||
|
|
||||||
|
create_rust_makefile("regorus/regorusrb") do |r|
|
||||||
|
r.auto_install_rust_toolchain = true
|
||||||
|
end
|
||||||
367
bindings/ruby/ext/regorusrb/src/lib.rs
Normal file
367
bindings/ruby/ext/regorusrb/src/lib.rs
Normal file
@@ -0,0 +1,367 @@
|
|||||||
|
use magnus::{Error, Ruby, exception::runtime_error, method, module, prelude::*};
|
||||||
|
use regorus::Engine as RegorusEngine;
|
||||||
|
use std::cell::RefCell;
|
||||||
|
use std::cmp::Ordering;
|
||||||
|
|
||||||
|
// `Value` exists under magnus, regorus, and serde_json, so be explicit
|
||||||
|
|
||||||
|
#[derive(Default)]
|
||||||
|
#[magnus::wrap(class = "Regorus::Engine")]
|
||||||
|
pub struct Engine {
|
||||||
|
engine: RefCell<RegorusEngine>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Clone for Engine {
|
||||||
|
fn clone(&self) -> Self {
|
||||||
|
Self {
|
||||||
|
engine: self.engine.clone(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Engine {
|
||||||
|
fn initialize(&self) {
|
||||||
|
let engine = RegorusEngine::new();
|
||||||
|
*self.engine.borrow_mut() = engine;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn compare(&self, other: &Self) -> Result<i32, Error> {
|
||||||
|
let self_ptr: *const _ = &*self.engine.borrow();
|
||||||
|
let other_ptr: *const _ = &*other.engine.borrow();
|
||||||
|
match self_ptr.partial_cmp(&other_ptr) {
|
||||||
|
Some(Ordering::Less) => Ok(-1),
|
||||||
|
Some(Ordering::Equal) => Ok(0),
|
||||||
|
Some(Ordering::Greater) => Ok(1),
|
||||||
|
None => Err(Error::new(runtime_error(), "Comparison failed")),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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()
|
||||||
|
.add_policy(path, rego)
|
||||||
|
.map_err(|e| Error::new(runtime_error(), format!("Failed to add policy: {}", e)))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn add_policy_from_file(&self, path: String) -> Result<String, Error> {
|
||||||
|
self.engine
|
||||||
|
.borrow_mut()
|
||||||
|
.add_policy_from_file(path)
|
||||||
|
.map_err(|e| Error::new(runtime_error(), format!("Failed to add policy: {}", e)))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn add_data(&self, ruby_hash: magnus::RHash) -> Result<(), Error> {
|
||||||
|
let data_value: regorus::Value = serde_magnus::deserialize(ruby_hash).map_err(|e| {
|
||||||
|
Error::new(
|
||||||
|
runtime_error(),
|
||||||
|
format!("Failed to deserialize Ruby value: {}", e),
|
||||||
|
)
|
||||||
|
})?;
|
||||||
|
|
||||||
|
self.engine
|
||||||
|
.borrow_mut()
|
||||||
|
.add_data(data_value)
|
||||||
|
.map_err(|e| Error::new(runtime_error(), format!("Failed to add data: {}", e)))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn add_data_json(&self, json_string: String) -> Result<(), Error> {
|
||||||
|
self.engine
|
||||||
|
.borrow_mut()
|
||||||
|
.add_data_json(&json_string)
|
||||||
|
.map_err(|e| Error::new(runtime_error(), format!("Failed to add data json: {}", e)))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn add_data_from_json_file(&self, path: String) -> Result<(), Error> {
|
||||||
|
let json_data = regorus::Value::from_json_file(path).map_err(|e| {
|
||||||
|
Error::new(
|
||||||
|
runtime_error(),
|
||||||
|
format!("Failed to parse JSON data file: {}", e),
|
||||||
|
)
|
||||||
|
})?;
|
||||||
|
|
||||||
|
self.engine.borrow_mut().add_data(json_data).map_err(|e| {
|
||||||
|
Error::new(
|
||||||
|
runtime_error(),
|
||||||
|
format!("Failed to add data from file: {}", e),
|
||||||
|
)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn clear_data(&self) -> Result<(), Error> {
|
||||||
|
self.engine.borrow_mut().clear_data();
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_packages(&self) -> Result<Vec<String>, Error> {
|
||||||
|
self.engine
|
||||||
|
.borrow()
|
||||||
|
.get_packages()
|
||||||
|
.map_err(|e| Error::new(runtime_error(), format!("Failed to get packages: {e}")))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_policies(&self) -> Result<String, Error> {
|
||||||
|
self.engine
|
||||||
|
.borrow()
|
||||||
|
.get_policies_as_json()
|
||||||
|
.map_err(|e| Error::new(runtime_error(), format!("Failed to get policies: {e}")))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_input(&self, ruby_hash: magnus::RHash) -> Result<(), Error> {
|
||||||
|
let input_value: regorus::Value = serde_magnus::deserialize(ruby_hash).map_err(|e| {
|
||||||
|
Error::new(
|
||||||
|
runtime_error(),
|
||||||
|
format!("Failed to deserialize Ruby value: {}", e),
|
||||||
|
)
|
||||||
|
})?;
|
||||||
|
|
||||||
|
self.engine.borrow_mut().set_input(input_value);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_input_json(&self, json_string: String) -> Result<(), Error> {
|
||||||
|
self.engine
|
||||||
|
.borrow_mut()
|
||||||
|
.set_input_json(&json_string)
|
||||||
|
.map_err(|e| Error::new(runtime_error(), format!("Failed to set input JSON: {}", e)))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn add_input_from_json_file(&self, path: String) -> Result<(), Error> {
|
||||||
|
let json_data = regorus::Value::from_json_file(path).map_err(|e| {
|
||||||
|
Error::new(
|
||||||
|
runtime_error(),
|
||||||
|
format!("Failed to parse JSON input file: {}", e),
|
||||||
|
)
|
||||||
|
})?;
|
||||||
|
|
||||||
|
self.engine.borrow_mut().set_input(json_data);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn eval_query(&self, query: String) -> Result<magnus::Value, Error> {
|
||||||
|
let results = self
|
||||||
|
.engine
|
||||||
|
.borrow_mut()
|
||||||
|
.eval_query(query, false)
|
||||||
|
.map_err(|e| Error::new(runtime_error(), format!("Failed to evaluate query: {}", e)))?;
|
||||||
|
|
||||||
|
serde_magnus::serialize(&results).map_err(|e| {
|
||||||
|
Error::new(
|
||||||
|
runtime_error(),
|
||||||
|
format!("Failed to serailzie query results: {}", e),
|
||||||
|
)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn eval_query_as_json(&self, query: String) -> Result<String, Error> {
|
||||||
|
let results = self
|
||||||
|
.engine
|
||||||
|
.borrow_mut()
|
||||||
|
.eval_query(query, false)
|
||||||
|
.map_err(|e| {
|
||||||
|
Error::new(
|
||||||
|
runtime_error(),
|
||||||
|
format!("Failed to evaluate query as json: {}", e),
|
||||||
|
)
|
||||||
|
})?;
|
||||||
|
|
||||||
|
serde_json::to_string(&results).map_err(|e| {
|
||||||
|
Error::new(
|
||||||
|
runtime_error(),
|
||||||
|
format!("Failed to serialize query results: {}", e),
|
||||||
|
)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn eval_rule(&self, query: String) -> Result<Option<magnus::Value>, Error> {
|
||||||
|
let result =
|
||||||
|
self.engine.borrow_mut().eval_rule(query).map_err(|e| {
|
||||||
|
Error::new(runtime_error(), format!("Failed to evaluate rule: {}", e))
|
||||||
|
})?;
|
||||||
|
|
||||||
|
match result {
|
||||||
|
regorus::Value::Undefined => Ok(None), // Convert undefined to Ruby's nil
|
||||||
|
_ => serde_magnus::serialize(&result) // Serialize other results normally
|
||||||
|
.map(Some)
|
||||||
|
.map_err(|e| {
|
||||||
|
magnus::Error::new(
|
||||||
|
runtime_error(),
|
||||||
|
format!("Failed to serialize the rule evaluation result: {}", e),
|
||||||
|
)
|
||||||
|
}),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn eval_bool_query(&self, query: String) -> Result<bool, Error> {
|
||||||
|
self.engine
|
||||||
|
.borrow_mut()
|
||||||
|
.eval_bool_query(query, false)
|
||||||
|
.map_err(|e| Error::new(runtime_error(), format!("Failed to evaluate query: {}", e)))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn eval_allow_query(&self, query: String) -> Result<bool, Error> {
|
||||||
|
Ok(self.engine.borrow_mut().eval_allow_query(query, false))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn eval_deny_query(&self, query: String) -> Result<bool, Error> {
|
||||||
|
Ok(self.engine.borrow_mut().eval_deny_query(query, false))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "coverage")]
|
||||||
|
fn set_enable_coverage(&self, enable: bool) -> Result<(), Error> {
|
||||||
|
self.engine.borrow_mut().set_enable_coverage(enable);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "coverage")]
|
||||||
|
fn get_coverage_report_as_json(&self) -> Result<String, Error> {
|
||||||
|
let report = self
|
||||||
|
.engine
|
||||||
|
.borrow_mut()
|
||||||
|
.get_coverage_report()
|
||||||
|
.map_err(|e| {
|
||||||
|
Error::new(
|
||||||
|
runtime_error(),
|
||||||
|
format!("Failed to get coverage report as json: {}", e),
|
||||||
|
)
|
||||||
|
})?;
|
||||||
|
|
||||||
|
serde_json::to_string(&report).map_err(|e| {
|
||||||
|
Error::new(
|
||||||
|
runtime_error(),
|
||||||
|
format!("Failed to serialize coverage report: {}", e),
|
||||||
|
)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "coverage")]
|
||||||
|
fn get_coverage_report_pretty(&self) -> Result<String, Error> {
|
||||||
|
let report = self
|
||||||
|
.engine
|
||||||
|
.borrow_mut()
|
||||||
|
.get_coverage_report()
|
||||||
|
.map_err(|e| {
|
||||||
|
Error::new(
|
||||||
|
runtime_error(),
|
||||||
|
format!("Failed to get coverage report: {}", e),
|
||||||
|
)
|
||||||
|
})?;
|
||||||
|
|
||||||
|
report.to_string_pretty().map_err(|e| {
|
||||||
|
Error::new(
|
||||||
|
runtime_error(),
|
||||||
|
format!("Failed to convert report to colored string: {}", e),
|
||||||
|
)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "coverage")]
|
||||||
|
fn clear_coverage_data(&self) -> Result<(), Error> {
|
||||||
|
self.engine.borrow_mut().clear_coverage_data();
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
// Print statements can be gathered async instead of printing to stderr
|
||||||
|
fn set_gather_prints(&self, enable: bool) -> Result<(), Error> {
|
||||||
|
self.engine.borrow_mut().set_gather_prints(enable);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn take_prints(&self) -> Result<Vec<String>, Error> {
|
||||||
|
self.engine.borrow_mut().take_prints().map_err(|e| {
|
||||||
|
Error::new(
|
||||||
|
runtime_error(),
|
||||||
|
format!("Failed to gather print statement: {}", e),
|
||||||
|
)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "ast")]
|
||||||
|
fn get_ast_as_json(&self) -> Result<String, Error> {
|
||||||
|
self.engine
|
||||||
|
.borrow()
|
||||||
|
.get_ast_as_json()
|
||||||
|
.map_err(|e| Error::new(runtime_error(), format!("Failed to get ast: {e}")))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[magnus::init]
|
||||||
|
fn init(ruby: &Ruby) -> Result<(), Error> {
|
||||||
|
let regorus_module = ruby.define_module("Regorus")?;
|
||||||
|
let engine_class = regorus_module.define_class("Engine", ruby.class_object())?;
|
||||||
|
|
||||||
|
// ruby object methods
|
||||||
|
engine_class.define_alloc_func::<Engine>();
|
||||||
|
engine_class.define_method("initialize", method!(Engine::initialize, 0))?;
|
||||||
|
engine_class.define_method("clone", method!(Engine::clone, 0))?;
|
||||||
|
engine_class.define_method("<=>", method!(Engine::compare, 1))?;
|
||||||
|
// 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(
|
||||||
|
"add_policy_from_file",
|
||||||
|
method!(Engine::add_policy_from_file, 1),
|
||||||
|
)?;
|
||||||
|
engine_class.define_method("get_packages", method!(Engine::get_packages, 0))?;
|
||||||
|
engine_class.define_method("get_policies", method!(Engine::get_policies, 0))?;
|
||||||
|
|
||||||
|
// data operations
|
||||||
|
engine_class.define_method("add_data", method!(Engine::add_data, 1))?;
|
||||||
|
engine_class.define_method("add_data_json", method!(Engine::add_data_json, 1))?;
|
||||||
|
engine_class.define_method(
|
||||||
|
"add_data_from_json_file",
|
||||||
|
method!(Engine::add_data_from_json_file, 1),
|
||||||
|
)?;
|
||||||
|
engine_class.define_method("clear_data", method!(Engine::clear_data, 0))?;
|
||||||
|
|
||||||
|
// input operations
|
||||||
|
engine_class.define_method("set_input", method!(Engine::set_input, 1))?;
|
||||||
|
engine_class.define_method("set_input_json", method!(Engine::set_input_json, 1))?;
|
||||||
|
engine_class.define_method(
|
||||||
|
"add_input_from_json_file",
|
||||||
|
method!(Engine::add_input_from_json_file, 1),
|
||||||
|
)?;
|
||||||
|
|
||||||
|
// query operations
|
||||||
|
engine_class.define_method("eval_query", method!(Engine::eval_query, 1))?;
|
||||||
|
engine_class.define_method("eval_query_as_json", method!(Engine::eval_query_as_json, 1))?;
|
||||||
|
engine_class.define_method("eval_rule", method!(Engine::eval_rule, 1))?;
|
||||||
|
engine_class.define_method("eval_bool_query", method!(Engine::eval_bool_query, 1))?;
|
||||||
|
engine_class.define_method("eval_allow_query", method!(Engine::eval_allow_query, 1))?;
|
||||||
|
engine_class.define_method("eval_deny_query", method!(Engine::eval_deny_query, 1))?;
|
||||||
|
|
||||||
|
// coverage operations
|
||||||
|
engine_class.define_method(
|
||||||
|
"set_enable_coverage",
|
||||||
|
method!(Engine::set_enable_coverage, 1),
|
||||||
|
)?;
|
||||||
|
engine_class.define_method(
|
||||||
|
"get_coverage_report_as_json",
|
||||||
|
method!(Engine::get_coverage_report_as_json, 0),
|
||||||
|
)?;
|
||||||
|
engine_class.define_method(
|
||||||
|
"get_coverage_report_pretty",
|
||||||
|
method!(Engine::get_coverage_report_pretty, 0),
|
||||||
|
)?;
|
||||||
|
engine_class.define_method(
|
||||||
|
"clear_coverage_data",
|
||||||
|
method!(Engine::clear_coverage_data, 0),
|
||||||
|
)?;
|
||||||
|
|
||||||
|
// print statements
|
||||||
|
engine_class.define_method("set_gather_prints", method!(Engine::set_gather_prints, 1))?;
|
||||||
|
engine_class.define_method("take_prints", method!(Engine::take_prints, 0))?;
|
||||||
|
|
||||||
|
// ast
|
||||||
|
engine_class.define_method("get_ast_as_json", method!(Engine::get_ast_as_json, 0))?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
8
bindings/ruby/lib/regorus.rb
Normal file
8
bindings/ruby/lib/regorus.rb
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
require_relative "regorus/version"
|
||||||
|
require_relative "regorus/regorusrb"
|
||||||
|
|
||||||
|
module Regorus
|
||||||
|
class Engine; end
|
||||||
|
end
|
||||||
5
bindings/ruby/lib/regorus/version.rb
Normal file
5
bindings/ruby/lib/regorus/version.rb
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
module Regorus
|
||||||
|
VERSION = "0.3.0"
|
||||||
|
end
|
||||||
30
bindings/ruby/regorusrb.gemspec
Normal file
30
bindings/ruby/regorusrb.gemspec
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
require_relative "lib/regorus/version"
|
||||||
|
|
||||||
|
Gem::Specification.new do |spec|
|
||||||
|
spec.name = "regorusrb"
|
||||||
|
spec.version = Regorus::VERSION
|
||||||
|
spec.authors = ["David Marshall"]
|
||||||
|
|
||||||
|
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.4.2"
|
||||||
|
spec.required_rubygems_version = ">= 3.6.5"
|
||||||
|
|
||||||
|
spec.metadata["allowed_push_host"] = "TODO: Set to your gem server 'https://example.com'"
|
||||||
|
|
||||||
|
spec.metadata["homepage_uri"] = spec.homepage
|
||||||
|
spec.metadata["source_code_uri"] = spec.homepage
|
||||||
|
spec.metadata["changelog_uri"] = "#{spec.homepage}/blob/main/bindings/ruby/CHANGELOG.md"
|
||||||
|
spec.metadata["rubygems_mfa_required"] = "true"
|
||||||
|
|
||||||
|
spec.files = Dir["lib/*.rb", "lib/regorus/*.rb", "ext/**/*.{rs,rb,lock,toml}", "Cargo.{lock,toml}", "LICENSE.txt", "README.md"]
|
||||||
|
|
||||||
|
spec.bindir = "exe"
|
||||||
|
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.111"
|
||||||
|
end
|
||||||
4
bindings/ruby/sig/regorusrb.rbs
Normal file
4
bindings/ruby/sig/regorusrb.rbs
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
module Regorus
|
||||||
|
VERSION: String
|
||||||
|
# See the writing guide of rbs: https://github.com/ruby/rbs#guides
|
||||||
|
end
|
||||||
6
bindings/ruby/test/test_helper.rb
Normal file
6
bindings/ruby/test/test_helper.rb
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
$LOAD_PATH.unshift File.expand_path("../lib", __dir__)
|
||||||
|
require "regorus"
|
||||||
|
|
||||||
|
require "minitest/autorun"
|
||||||
232
bindings/ruby/test/test_regorus.rb
Normal file
232
bindings/ruby/test/test_regorus.rb
Normal file
@@ -0,0 +1,232 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
require "test_helper"
|
||||||
|
require "json"
|
||||||
|
|
||||||
|
class TestRegorus < Minitest::Test
|
||||||
|
ALICE = "Alice"
|
||||||
|
BOB = "Bob"
|
||||||
|
CARLOS = "Carlos"
|
||||||
|
|
||||||
|
def setup
|
||||||
|
@engine = ::Regorus::Engine.new
|
||||||
|
@engine.add_policy("regorus_test.rego", example_policy)
|
||||||
|
@engine.add_data(example_data)
|
||||||
|
end
|
||||||
|
|
||||||
|
def example_policy
|
||||||
|
<<~REGO
|
||||||
|
package regorus_test
|
||||||
|
is_manager if {
|
||||||
|
input.name == data.managers[_]
|
||||||
|
}
|
||||||
|
|
||||||
|
is_employee if {
|
||||||
|
input.name == data.employees[_]
|
||||||
|
}
|
||||||
|
|
||||||
|
# Set a default value for to return false instead of nil
|
||||||
|
default is_manager_bool = false
|
||||||
|
default is_employee_bool = false
|
||||||
|
|
||||||
|
is_manager_bool if {
|
||||||
|
is_manager
|
||||||
|
}
|
||||||
|
|
||||||
|
is_employee_bool if {
|
||||||
|
is_employee
|
||||||
|
}
|
||||||
|
REGO
|
||||||
|
end
|
||||||
|
|
||||||
|
def example_data
|
||||||
|
{
|
||||||
|
"managers" => [ALICE],
|
||||||
|
"employees" => [ALICE, BOB]
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
def input_for(name)
|
||||||
|
{ "name" => name }
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_version_number_presence
|
||||||
|
refute_nil ::Regorus::VERSION
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_engine_creation
|
||||||
|
assert_instance_of ::Regorus::Engine, ::Regorus::Engine.new
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_policy_addition
|
||||||
|
# returns the package name from the REGO, not the filename
|
||||||
|
assert_equal "data.regorus_test", @engine.add_policy("example.rego", example_policy)
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_object_creation_with_new
|
||||||
|
refute_same ::Regorus::Engine.new, ::Regorus::Engine.new
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_data_addition
|
||||||
|
assert_silent { @engine.add_data(example_data) }
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_data_addition_as_json
|
||||||
|
assert_silent { @engine.add_data_json(example_data.to_json) }
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_query_evaluation_for_alice
|
||||||
|
@engine.set_input(input_for(ALICE))
|
||||||
|
|
||||||
|
assert_equal alice_results, @engine.eval_query("data.regorus_test")
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_query_evaluation_for_bob
|
||||||
|
@engine.set_input(input_for(BOB))
|
||||||
|
|
||||||
|
assert_equal bob_results, @engine.eval_query("data.regorus_test")
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_query_evaluation_as_json
|
||||||
|
@engine.set_input(input_for(ALICE))
|
||||||
|
|
||||||
|
assert_equal alice_results.to_json, @engine.eval_query_as_json("data.regorus_test")
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_rule_evaluation_for_alice
|
||||||
|
@engine.set_input(input_for(ALICE))
|
||||||
|
|
||||||
|
assert @engine.eval_rule("data.regorus_test.is_employee")
|
||||||
|
assert @engine.eval_rule("data.regorus_test.is_employee_bool")
|
||||||
|
assert @engine.eval_rule("data.regorus_test.is_manager")
|
||||||
|
assert @engine.eval_rule("data.regorus_test.is_manager_bool")
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_rule_evaluation_for_bob
|
||||||
|
@engine.set_input(input_for(BOB))
|
||||||
|
|
||||||
|
assert @engine.eval_rule("data.regorus_test.is_employee")
|
||||||
|
assert @engine.eval_rule("data.regorus_test.is_employee_bool")
|
||||||
|
assert_nil @engine.eval_rule("data.regorus_test.is_manager")
|
||||||
|
refute @engine.eval_rule("data.regorus_test.is_manager_bool")
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_rule_evaluation_for_carlos
|
||||||
|
@engine.set_input(input_for(CARLOS))
|
||||||
|
|
||||||
|
assert_nil @engine.eval_rule("data.regorus_test.is_employee")
|
||||||
|
refute @engine.eval_rule("data.regorus_test.is_employee_bool")
|
||||||
|
assert_nil @engine.eval_rule("data.regorus_test.is_manager")
|
||||||
|
refute @engine.eval_rule("data.regorus_test.is_manager_bool")
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_eval_bool_query
|
||||||
|
assert @engine.eval_bool_query("1 < 2")
|
||||||
|
refute @engine.eval_bool_query("1 > 2")
|
||||||
|
assert_raises(RuntimeError) { @engine.eval_bool_query("1 + 1") }
|
||||||
|
assert_raises(RuntimeError) { @engine.eval_bool_query("true; true") }
|
||||||
|
assert_raises(RuntimeError) { @engine.eval_bool_query("true; false; true") }
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_eval_allow_query
|
||||||
|
assert @engine.eval_allow_query("1 < 2")
|
||||||
|
refute @engine.eval_allow_query("1 > 2")
|
||||||
|
refute @engine.eval_allow_query("1 + 1")
|
||||||
|
refute @engine.eval_allow_query("true; true")
|
||||||
|
refute @engine.eval_allow_query("true; false; true")
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_eval_deny_query
|
||||||
|
assert @engine.eval_deny_query("1 < 2")
|
||||||
|
refute @engine.eval_deny_query("1 > 2")
|
||||||
|
assert @engine.eval_deny_query("1 + 1")
|
||||||
|
assert @engine.eval_deny_query("true; true")
|
||||||
|
assert @engine.eval_deny_query("true; false; true")
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_missing_rules_handling
|
||||||
|
@engine.set_input(input_for(ALICE))
|
||||||
|
assert_raises(RuntimeError) { @engine.eval_rule("data.regorus_test.not_a_rule") }
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_engine_cloning
|
||||||
|
cloned_engine = @engine.clone
|
||||||
|
|
||||||
|
assert_instance_of ::Regorus::Engine, cloned_engine
|
||||||
|
refute_same @engine, cloned_engine
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_coverage_printing_json
|
||||||
|
@engine.set_input(input_for(ALICE))
|
||||||
|
@engine.set_enable_coverage(true)
|
||||||
|
@engine.eval_rule("data.regorus_test.is_employee")
|
||||||
|
|
||||||
|
assert_match(/covered":\[7\],"not_covered":\[3,11,12,15,19\]/, @engine.get_coverage_report_as_json)
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_coverage_printing_pretty
|
||||||
|
@engine.set_input(input_for(ALICE))
|
||||||
|
@engine.set_enable_coverage(true)
|
||||||
|
@engine.eval_rule("data.regorus_test.is_employee")
|
||||||
|
|
||||||
|
# to see the colors in the ruby terminal, use `puts @engine.get_coverage_report``
|
||||||
|
pretty_coverage_report = @engine.get_coverage_report_pretty
|
||||||
|
|
||||||
|
assert_match(/\e\[31m 3 input.name == data.managers\[_\]/, pretty_coverage_report)
|
||||||
|
assert_match(/\e\[32m 7 input.name == data.employees\[_\]/, pretty_coverage_report)
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_gather_print_statements
|
||||||
|
@engine.set_gather_prints(true)
|
||||||
|
@engine.eval_query('print("Hello")')
|
||||||
|
|
||||||
|
assert_equal ["<query.rego>:1: Hello"], @engine.take_prints
|
||||||
|
end
|
||||||
|
|
||||||
|
def alice_results
|
||||||
|
{
|
||||||
|
result: [
|
||||||
|
{
|
||||||
|
expressions: [
|
||||||
|
{
|
||||||
|
value: {
|
||||||
|
"is_employee" => true,
|
||||||
|
"is_employee_bool" => true,
|
||||||
|
"is_manager" => true,
|
||||||
|
"is_manager_bool" => true
|
||||||
|
},
|
||||||
|
text: "data.regorus_test",
|
||||||
|
location: {
|
||||||
|
row: 1,
|
||||||
|
col: 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
def bob_results
|
||||||
|
{
|
||||||
|
result: [
|
||||||
|
{
|
||||||
|
expressions: [
|
||||||
|
{
|
||||||
|
value: {
|
||||||
|
"is_employee" => true,
|
||||||
|
"is_employee_bool" => true,
|
||||||
|
"is_manager_bool" => false
|
||||||
|
},
|
||||||
|
text: "data.regorus_test",
|
||||||
|
location: {
|
||||||
|
row: 1,
|
||||||
|
col: 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
end
|
||||||
|
end
|
||||||
2
bindings/wasm/.cargo/config.toml
Normal file
2
bindings/wasm/.cargo/config.toml
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
[target.wasm32-unknown-unknown]
|
||||||
|
rustflags = ["--cfg", "getrandom_backend=\"wasm_js\""]
|
||||||
1628
bindings/wasm/Cargo.lock
generated
Normal file
1628
bindings/wasm/Cargo.lock
generated
Normal file
File diff suppressed because it is too large
Load Diff
@@ -1,6 +1,8 @@
|
|||||||
|
[workspace]
|
||||||
|
|
||||||
[package]
|
[package]
|
||||||
name = "regorusjs"
|
name = "regorusjs"
|
||||||
version = "0.1.0"
|
version = "0.3.0"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
repository = "https://github.com/microsoft/regorus/bindings/wasm"
|
repository = "https://github.com/microsoft/regorus/bindings/wasm"
|
||||||
description = "WASM bindings for Regorus - a fast, lightweight Rego interpreter written in Rust"
|
description = "WASM bindings for Regorus - a fast, lightweight Rego interpreter written in Rust"
|
||||||
@@ -10,10 +12,24 @@ keywords = ["interpreter", "opa", "policy-as-code", "rego"]
|
|||||||
[lib]
|
[lib]
|
||||||
crate-type = ["cdylib"]
|
crate-type = ["cdylib"]
|
||||||
|
|
||||||
|
[features]
|
||||||
|
default = ["ast", "coverage", "regorus/std", "regorus/full-opa"]
|
||||||
|
ast = ["regorus/ast"]
|
||||||
|
coverage = ["regorus/coverage"]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
regorus = { path = "../.." }
|
regorus = { path = "../..", default-features = false, features = ["arc"] }
|
||||||
serde_json = "1.0.111"
|
serde_json = "1.0.140"
|
||||||
wasm-bindgen = "0.2.90"
|
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]
|
[dev-dependencies]
|
||||||
wasm-bindgen-test = "0.3.40"
|
wasm-bindgen-test = "0.3.40"
|
||||||
|
|
||||||
|
[lints.rust]
|
||||||
|
unexpected_cfgs = { level = "warn", check-cfg = ['cfg(wasm_bindgen_unstable_test_coverage)'] }
|
||||||
|
|||||||
@@ -10,72 +10,10 @@
|
|||||||
|
|
||||||
See [Repository](https://github.com/microsoft/regorus).
|
See [Repository](https://github.com/microsoft/regorus).
|
||||||
|
|
||||||
To build this binding, see [building](https://github.com/microsoft/regorus/bindings/wasm/building.md)
|
To build this binding, see [building.md](https://github.com/microsoft/regorus/blob/main/bindings/wasm/building.md)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## Usage
|
## Usage
|
||||||
|
|
||||||
```javascript
|
See [test.js](https://github.com/microsoft/regorus/blob/main/bindings/wasm/test.js) for example usage.
|
||||||
|
|
||||||
var regorus = require('regorusjs')
|
|
||||||
|
|
||||||
// Create an engine.
|
|
||||||
var engine = new regorus.Engine();
|
|
||||||
|
|
||||||
// Add Rego policy.
|
|
||||||
engine.add_policy(
|
|
||||||
// Associate this file name with policy
|
|
||||||
'hello.rego',
|
|
||||||
|
|
||||||
// Rego policy
|
|
||||||
`
|
|
||||||
package test
|
|
||||||
|
|
||||||
# Join messages
|
|
||||||
message = concat(", ", [input.message, data.message])
|
|
||||||
`)
|
|
||||||
|
|
||||||
// Set policy data
|
|
||||||
engine.add_data_json(`
|
|
||||||
{
|
|
||||||
"message" : "World!"
|
|
||||||
}
|
|
||||||
`)
|
|
||||||
|
|
||||||
// Set policy input
|
|
||||||
engine.set_input_json(`
|
|
||||||
{
|
|
||||||
"message" : "Hello"
|
|
||||||
}
|
|
||||||
`)
|
|
||||||
|
|
||||||
// Eval query
|
|
||||||
results = engine.eval_query('data.test.message')
|
|
||||||
|
|
||||||
// Display
|
|
||||||
console.log(results)
|
|
||||||
// {
|
|
||||||
// "result": [
|
|
||||||
// {
|
|
||||||
// "expressions": [
|
|
||||||
// {
|
|
||||||
// "value": "Hello, World!",
|
|
||||||
// "text": "data.test.message",
|
|
||||||
// "location": {
|
|
||||||
// "row": 1,
|
|
||||||
// "col": 1
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// ]
|
|
||||||
// }
|
|
||||||
// ]
|
|
||||||
// }
|
|
||||||
|
|
||||||
// Convert results to object
|
|
||||||
results = JSON.parse(results)
|
|
||||||
|
|
||||||
// Process result
|
|
||||||
console.log(results.result[0].expressions[0].value)
|
|
||||||
// Hello, World!
|
|
||||||
```
|
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
// Copyright (c) Microsoft Corporation.
|
// Copyright (c) Microsoft Corporation.
|
||||||
// Licensed under the MIT License.
|
// Licensed under the MIT License.
|
||||||
|
|
||||||
|
#![allow(non_snake_case)]
|
||||||
|
|
||||||
use wasm_bindgen::prelude::*;
|
use wasm_bindgen::prelude::*;
|
||||||
|
|
||||||
#[wasm_bindgen]
|
#[wasm_bindgen]
|
||||||
@@ -43,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
|
/// Add a policy
|
||||||
///
|
///
|
||||||
/// The policy is parsed into AST.
|
/// The policy is parsed into AST.
|
||||||
@@ -50,7 +61,7 @@ impl Engine {
|
|||||||
///
|
///
|
||||||
/// * `path`: A filename to be associated with the policy.
|
/// * `path`: A filename to be associated with the policy.
|
||||||
/// * `rego`: Rego policy.
|
/// * `rego`: Rego policy.
|
||||||
pub fn add_policy(&mut self, path: String, rego: String) -> Result<(), JsValue> {
|
pub fn addPolicy(&mut self, path: String, rego: String) -> Result<String, JsValue> {
|
||||||
self.engine.add_policy(path, rego).map_err(error_to_jsvalue)
|
self.engine.add_policy(path, rego).map_err(error_to_jsvalue)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -58,15 +69,29 @@ impl Engine {
|
|||||||
///
|
///
|
||||||
/// See https://docs.rs/regorus/latest/regorus/struct.Engine.html#method.add_data
|
/// See https://docs.rs/regorus/latest/regorus/struct.Engine.html#method.add_data
|
||||||
/// * `data`: JSON encoded value to be used as policy data.
|
/// * `data`: JSON encoded value to be used as policy data.
|
||||||
pub fn add_data_json(&mut self, data: String) -> Result<(), JsValue> {
|
pub fn addDataJson(&mut self, data: String) -> Result<(), JsValue> {
|
||||||
let data = regorus::Value::from_json_str(&data).map_err(error_to_jsvalue)?;
|
let data = regorus::Value::from_json_str(&data).map_err(error_to_jsvalue)?;
|
||||||
self.engine.add_data(data).map_err(error_to_jsvalue)
|
self.engine.add_data(data).map_err(error_to_jsvalue)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get the list of packages defined by loaded policies.
|
||||||
|
///
|
||||||
|
/// See https://docs.rs/regorus/latest/regorus/struct.Engine.html#method.get_packages
|
||||||
|
pub fn getPackages(&self) -> Result<Vec<String>, JsValue> {
|
||||||
|
self.engine.get_packages().map_err(error_to_jsvalue)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get the list of policies.
|
||||||
|
///
|
||||||
|
/// See https://docs.rs/regorus/latest/regorus/struct.Engine.html#method.get_policies
|
||||||
|
pub fn getPolicies(&self) -> Result<String, JsValue> {
|
||||||
|
self.engine.get_policies_as_json().map_err(error_to_jsvalue)
|
||||||
|
}
|
||||||
|
|
||||||
/// Clear policy data.
|
/// 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/0.1.0-alpha.2/regorus/struct.Engine.html#method.clear_data
|
||||||
pub fn clear_data(&mut self) -> Result<(), JsValue> {
|
pub fn clearData(&mut self) -> Result<(), JsValue> {
|
||||||
self.engine.clear_data();
|
self.engine.clear_data();
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@@ -75,7 +100,7 @@ impl Engine {
|
|||||||
///
|
///
|
||||||
/// See https://docs.rs/regorus/0.1.0-alpha.2/regorus/struct.Engine.html#method.set_input
|
/// See https://docs.rs/regorus/0.1.0-alpha.2/regorus/struct.Engine.html#method.set_input
|
||||||
/// * `input`: JSON encoded value to be used as input to query.
|
/// * `input`: JSON encoded value to be used as input to query.
|
||||||
pub fn set_input_json(&mut self, input: String) -> Result<(), JsValue> {
|
pub fn setInputJson(&mut self, input: String) -> Result<(), JsValue> {
|
||||||
let input = regorus::Value::from_json_str(&input).map_err(error_to_jsvalue)?;
|
let input = regorus::Value::from_json_str(&input).map_err(error_to_jsvalue)?;
|
||||||
self.engine.set_input(input);
|
self.engine.set_input(input);
|
||||||
Ok(())
|
Ok(())
|
||||||
@@ -85,26 +110,103 @@ impl Engine {
|
|||||||
///
|
///
|
||||||
/// See https://docs.rs/regorus/0.1.0-alpha.2/regorus/struct.Engine.html#method.eval_query
|
/// See https://docs.rs/regorus/0.1.0-alpha.2/regorus/struct.Engine.html#method.eval_query
|
||||||
/// * `query`: Rego expression to be evaluate.
|
/// * `query`: Rego expression to be evaluate.
|
||||||
pub fn eval_query(&mut self, query: String) -> Result<String, JsValue> {
|
pub fn evalQuery(&mut self, query: String) -> Result<String, JsValue> {
|
||||||
let results = self
|
let results = self
|
||||||
.engine
|
.engine
|
||||||
.eval_query(query, false)
|
.eval_query(query, false)
|
||||||
.map_err(error_to_jsvalue)?;
|
.map_err(error_to_jsvalue)?;
|
||||||
serde_json::to_string_pretty(&results).map_err(error_to_jsvalue)
|
serde_json::to_string_pretty(&results).map_err(error_to_jsvalue)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Evaluate rule(s) at given path.
|
||||||
|
///
|
||||||
|
/// See https://docs.rs/regorus/latest/regorus/struct.Engine.html#method.eval_rule
|
||||||
|
///
|
||||||
|
/// * `path`: The full path to the rule(s).
|
||||||
|
pub fn evalRule(&mut self, path: String) -> Result<String, JsValue> {
|
||||||
|
let v = self.engine.eval_rule(path).map_err(error_to_jsvalue)?;
|
||||||
|
v.to_json_str().map_err(error_to_jsvalue)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Gather output from print statements instead of emiting to stderr.
|
||||||
|
///
|
||||||
|
/// See https://docs.rs/regorus/latest/regorus/struct.Engine.html#method.set_gather_prints
|
||||||
|
/// * `b`: Whether to enable gathering prints or not.
|
||||||
|
pub fn setGatherPrints(&mut self, b: bool) {
|
||||||
|
self.engine.set_gather_prints(b)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Take the gathered output of print statements.
|
||||||
|
///
|
||||||
|
/// See https://docs.rs/regorus/latest/regorus/struct.Engine.html#method.take_prints
|
||||||
|
pub fn takePrints(&mut self) -> Result<Vec<String>, JsValue> {
|
||||||
|
self.engine.take_prints().map_err(error_to_jsvalue)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Enable/disable policy coverage.
|
||||||
|
///
|
||||||
|
/// See https://docs.rs/regorus/latest/regorus/struct.Engine.html#method.set_enable_coverage
|
||||||
|
/// * `b`: Whether to enable gathering coverage or not.
|
||||||
|
#[cfg(feature = "coverage")]
|
||||||
|
pub fn setEnableCoverage(&mut self, enable: bool) {
|
||||||
|
self.engine.set_enable_coverage(enable)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get the coverage report as json.
|
||||||
|
///
|
||||||
|
/// See https://docs.rs/regorus/latest/regorus/struct.Engine.html#method.get_coverage_report
|
||||||
|
#[cfg(feature = "coverage")]
|
||||||
|
pub fn getCoverageReport(&self) -> Result<String, JsValue> {
|
||||||
|
let report = self
|
||||||
|
.engine
|
||||||
|
.get_coverage_report()
|
||||||
|
.map_err(error_to_jsvalue)?;
|
||||||
|
serde_json::to_string_pretty(&report).map_err(error_to_jsvalue)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Clear gathered coverage data.
|
||||||
|
///
|
||||||
|
/// See https://docs.rs/regorus/latest/regorus/struct.Engine.html#method.clear_coverage_data
|
||||||
|
#[cfg(feature = "coverage")]
|
||||||
|
pub fn clearCoverageData(&mut self) {
|
||||||
|
self.engine.clear_coverage_data()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get ANSI color coded coverage report.
|
||||||
|
///
|
||||||
|
/// See https://docs.rs/regorus/latest/regorus/coverage/struct.Report.html#method.to_string_pretty
|
||||||
|
#[cfg(feature = "coverage")]
|
||||||
|
pub fn getCoverageReportPretty(&self) -> Result<String, JsValue> {
|
||||||
|
let report = self
|
||||||
|
.engine
|
||||||
|
.get_coverage_report()
|
||||||
|
.map_err(error_to_jsvalue)?;
|
||||||
|
report.to_string_pretty().map_err(error_to_jsvalue)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get AST of policies.
|
||||||
|
///
|
||||||
|
/// See https://docs.rs/regorus/latest/regorus/struct.Engine.html#method.get_ast_as_json
|
||||||
|
#[cfg(feature = "ast")]
|
||||||
|
pub fn getAstAsJson(&self) -> Result<String, JsValue> {
|
||||||
|
self.engine.get_ast_as_json().map_err(error_to_jsvalue)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
|
use crate::error_to_jsvalue;
|
||||||
use wasm_bindgen::prelude::*;
|
use wasm_bindgen::prelude::*;
|
||||||
use wasm_bindgen_test::wasm_bindgen_test;
|
use wasm_bindgen_test::wasm_bindgen_test;
|
||||||
|
|
||||||
#[wasm_bindgen_test]
|
#[wasm_bindgen_test]
|
||||||
|
#[allow(dead_code)]
|
||||||
pub fn basic() -> Result<(), JsValue> {
|
pub fn basic() -> Result<(), JsValue> {
|
||||||
let mut engine = crate::Engine::new();
|
let mut engine = crate::Engine::new();
|
||||||
|
engine.setEnableCoverage(true);
|
||||||
|
|
||||||
// Exercise all APIs.
|
// Exercise all APIs.
|
||||||
engine.add_data_json(
|
engine.addDataJson(
|
||||||
r#"
|
r#"
|
||||||
{
|
{
|
||||||
"foo" : "bar"
|
"foo" : "bar"
|
||||||
@@ -113,7 +215,7 @@ mod tests {
|
|||||||
.to_string(),
|
.to_string(),
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
engine.set_input_json(
|
engine.setInputJson(
|
||||||
r#"
|
r#"
|
||||||
{
|
{
|
||||||
"message" : "Hello"
|
"message" : "Hello"
|
||||||
@@ -122,16 +224,17 @@ mod tests {
|
|||||||
.to_string(),
|
.to_string(),
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
engine.add_policy(
|
let pkg = engine.addPolicy(
|
||||||
"hello.rego".to_string(),
|
"hello.rego".to_string(),
|
||||||
r#"
|
r#"
|
||||||
package test
|
package test
|
||||||
message = input.message"#
|
message = input.message"#
|
||||||
.to_string(),
|
.to_string(),
|
||||||
)?;
|
)?;
|
||||||
|
assert_eq!(pkg, "data.test");
|
||||||
|
|
||||||
let results = engine.eval_query("data".to_string())?;
|
let results = engine.evalQuery("data".to_string())?;
|
||||||
let r = regorus::Value::from_json_str(&results).map_err(crate::error_to_jsvalue)?;
|
let r = regorus::Value::from_json_str(&results).map_err(error_to_jsvalue)?;
|
||||||
|
|
||||||
let v = &r["result"][0]["expressions"][0]["value"];
|
let v = &r["result"][0]["expressions"][0]["value"];
|
||||||
|
|
||||||
@@ -141,6 +244,45 @@ mod tests {
|
|||||||
// Test that data was set.
|
// Test that data was set.
|
||||||
assert_eq!(v["foo"], regorus::Value::from("bar"));
|
assert_eq!(v["foo"], regorus::Value::from("bar"));
|
||||||
|
|
||||||
|
// Use eval_rule to perform same query.
|
||||||
|
let v = engine.evalRule("data.test.message".to_owned())?;
|
||||||
|
let v = regorus::Value::from_json_str(&v).map_err(error_to_jsvalue)?;
|
||||||
|
|
||||||
|
// Ensure that input and policy were evaluated.
|
||||||
|
assert_eq!(v, regorus::Value::from("Hello"));
|
||||||
|
|
||||||
|
let pkgs = engine.getPackages()?;
|
||||||
|
assert_eq!(pkgs, vec!["data.test"]);
|
||||||
|
|
||||||
|
engine.setGatherPrints(true);
|
||||||
|
let _ = engine.evalQuery("print(\"Hello\")".to_owned());
|
||||||
|
let prints = engine.takePrints()?;
|
||||||
|
assert_eq!(prints, vec!["<query.rego>:1: Hello"]);
|
||||||
|
|
||||||
|
// Test clone.
|
||||||
|
let mut engine1 = engine.clone();
|
||||||
|
|
||||||
|
// Test code coverage.
|
||||||
|
let report = engine1.getCoverageReport()?;
|
||||||
|
let r = regorus::Value::from_json_str(&report).map_err(error_to_jsvalue)?;
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
r["files"][0]["covered"]
|
||||||
|
.as_array()
|
||||||
|
.map_err(crate::error_to_jsvalue)?,
|
||||||
|
&vec![regorus::Value::from(3)]
|
||||||
|
);
|
||||||
|
|
||||||
|
println!("{}", engine1.getCoverageReportPretty()?);
|
||||||
|
|
||||||
|
engine1.clearCoverageData();
|
||||||
|
|
||||||
|
let policies = engine1.getPolicies()?;
|
||||||
|
let v = regorus::Value::from_json_str(&policies).map_err(error_to_jsvalue)?;
|
||||||
|
assert_eq!(
|
||||||
|
v[0]["path"].as_string().map_err(error_to_jsvalue)?.as_ref(),
|
||||||
|
"hello.rego"
|
||||||
|
);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,47 +1,87 @@
|
|||||||
// Copyright (c) Microsoft Corporation.
|
// Copyright (c) Microsoft Corporation.
|
||||||
// Licensed under the MIT License.
|
// Licensed under the MIT License.
|
||||||
|
|
||||||
var regorus = require('./pkg/regorusjs')
|
var regorus = require('./pkg/regorusjs');
|
||||||
|
|
||||||
// Create an engine.
|
// Create an engine.
|
||||||
var engine = new regorus.Engine();
|
var engine = new regorus.Engine();
|
||||||
|
|
||||||
|
// Enable code coverage
|
||||||
|
engine.setEnableCoverage(true);
|
||||||
|
|
||||||
// Add Rego policy.
|
// Add Rego policy.
|
||||||
engine.add_policy(
|
var pkg = engine.addPolicy(
|
||||||
// Associate this file name with policy
|
// Associate this file name with policy
|
||||||
'hello.rego',
|
'hello.rego',
|
||||||
|
|
||||||
// Rego policy
|
// Rego policy
|
||||||
`
|
`
|
||||||
package test
|
package test
|
||||||
|
|
||||||
|
x = 10
|
||||||
|
|
||||||
# Join messages
|
# Join messages
|
||||||
message = concat(", ", [input.message, data.message])
|
message = concat(", ", [input.message, data.message])
|
||||||
`)
|
`);
|
||||||
|
|
||||||
|
console.log(pkg);
|
||||||
|
// data.test
|
||||||
|
|
||||||
// Set policy data
|
// Set policy data
|
||||||
engine.add_data_json(`
|
engine.addDataJson(`
|
||||||
{
|
{
|
||||||
"message" : "World!"
|
"message" : "World!"
|
||||||
}
|
}
|
||||||
`)
|
`);
|
||||||
|
|
||||||
// Set policy input
|
// Set policy input
|
||||||
engine.set_input_json(`
|
engine.setInputJson(`
|
||||||
{
|
{
|
||||||
"message" : "Hello"
|
"message" : "Hello"
|
||||||
}
|
}
|
||||||
`)
|
`);
|
||||||
|
|
||||||
|
// Eval rule as json
|
||||||
|
var value = engine.evalRule('data.test.message');
|
||||||
|
value = JSON.parse(value);
|
||||||
|
|
||||||
|
// Display value
|
||||||
|
console.log(value);
|
||||||
|
// Hello, World!
|
||||||
|
|
||||||
// Eval query
|
// Eval query
|
||||||
results = engine.eval_query('data.test.message')
|
results = engine.evalQuery('data.test.message');
|
||||||
|
|
||||||
// Display
|
// Display
|
||||||
console.log(results)
|
console.log(results);
|
||||||
|
// {
|
||||||
|
// "result": [
|
||||||
|
// {
|
||||||
|
// "expressions": [
|
||||||
|
// {
|
||||||
|
// "value": "Hello, World!",
|
||||||
|
// "text": "data.test.message",
|
||||||
|
// "location": {
|
||||||
|
// "row": 1,
|
||||||
|
// "col": 1
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// ]
|
||||||
|
// }
|
||||||
|
// ]
|
||||||
|
// }
|
||||||
|
|
||||||
// Convert results to object
|
// Convert results to object
|
||||||
results = JSON.parse(results)
|
results = JSON.parse(results);
|
||||||
|
|
||||||
// Process result
|
// Process result
|
||||||
console.log(results.result[0].expressions[0].value)
|
console.log(results.result[0].expressions[0].value);
|
||||||
|
// Hello, World!
|
||||||
|
|
||||||
|
// Print coverage report
|
||||||
|
report = engine.getCoverageReport();
|
||||||
|
console.log(report);
|
||||||
|
|
||||||
|
// Print pretty report.
|
||||||
|
report = engine.getCoverageReportPretty();
|
||||||
|
console.log(report);
|
||||||
|
|||||||
19
build.rs
19
build.rs
@@ -3,23 +3,28 @@
|
|||||||
|
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
use std::process::Command;
|
|
||||||
|
|
||||||
fn main() -> Result<()> {
|
fn main() -> Result<()> {
|
||||||
// Copy hooks to appropriate location so that git will run them.
|
// Copy hooks to appropriate location so that git will run them.
|
||||||
// In git worktrees, .git is a symlink and the following commands fail.
|
// In git worktrees, .git is a symlink and the following commands fail.
|
||||||
if Path::new(".git").is_dir() {
|
if Path::new(".git").is_dir() {
|
||||||
|
if !Path::new("./.git/hooks").exists() {
|
||||||
|
std::fs::create_dir_all("./.git/hooks")?;
|
||||||
|
}
|
||||||
std::fs::copy("./scripts/pre-commit", "./.git/hooks/pre-commit")?;
|
std::fs::copy("./scripts/pre-commit", "./.git/hooks/pre-commit")?;
|
||||||
std::fs::copy("./scripts/pre-push", "./.git/hooks/pre-push")?;
|
std::fs::copy("./scripts/pre-push", "./.git/hooks/pre-push")?;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Supply information as compile-time environment variables.
|
// Supply information as compile-time environment variables.
|
||||||
let output = Command::new("git")
|
#[cfg(feature = "opa-runtime")]
|
||||||
.args(["rev-parse", "HEAD"])
|
{
|
||||||
.output()
|
let output = std::process::Command::new("git")
|
||||||
.unwrap();
|
.args(["rev-parse", "HEAD"])
|
||||||
let git_hash = String::from_utf8(output.stdout).unwrap();
|
.output()
|
||||||
println!("cargo:rustc-env=GIT_HASH={}", git_hash);
|
.expect("`git rev-parse HEAD` failed.");
|
||||||
|
let git_hash = String::from_utf8(output.stdout).unwrap();
|
||||||
|
println!("cargo:rustc-env=GIT_HASH={}", git_hash);
|
||||||
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -159,24 +159,25 @@ In future, each builtin will be associated with a feature (many builtins could b
|
|||||||
| [type_name](https://www.openpolicyagent.org/docs/latest/policy-reference/#builtin-types-type_name) | _ |
|
| [type_name](https://www.openpolicyagent.org/docs/latest/policy-reference/#builtin-types-type_name) | _ |
|
||||||
|
|
||||||
- [Encoding](https://www.openpolicyagent.org/docs/latest/policy-reference/#encoding)
|
- [Encoding](https://www.openpolicyagent.org/docs/latest/policy-reference/#encoding)
|
||||||
| Builtin | Feature |
|
| Builtin | Feature |
|
||||||
|----------------------------------------------------------------------------------------------------------------------------------|-------------|
|
|--------------------------------------------------------------------------------------------------------------------------------------|-------------|
|
||||||
| [base64.is_valid](https://www.openpolicyagent.org/docs/latest/policy-reference/#builtin-encoding-base64is_valid) | `base64` |
|
| [base64.is_valid](https://www.openpolicyagent.org/docs/latest/policy-reference/#builtin-encoding-base64is_valid) | `base64` |
|
||||||
| [base64url.decode](https://www.openpolicyagent.org/docs/latest/policy-reference/#builtin-encoding-base64urldecode) | `base64` |
|
| [base64url.decode](https://www.openpolicyagent.org/docs/latest/policy-reference/#builtin-encoding-base64urldecode) | `base64` |
|
||||||
| [base64url.encode](https://www.openpolicyagent.org/docs/latest/policy-reference/#builtin-encoding-base64urlencode) | `base64url` |
|
| [base64url.encode](https://www.openpolicyagent.org/docs/latest/policy-reference/#builtin-encoding-base64urlencode) | `base64url` |
|
||||||
| [base64url.encode_no_pad](https://www.openpolicyagent.org/docs/latest/policy-reference/#builtin-encoding-base64urlencode_no_pad) | `base64url` |
|
| [base64url.encode_no_pad](https://www.openpolicyagent.org/docs/latest/policy-reference/#builtin-encoding-base64urlencode_no_pad) | `base64url` |
|
||||||
| [hex.decode](https://www.openpolicyagent.org/docs/latest/policy-reference/#builtin-encoding-hexdecode) | `hex` |
|
| [hex.decode](https://www.openpolicyagent.org/docs/latest/policy-reference/#builtin-encoding-hexdecode) | `hex` |
|
||||||
| [hex.encode](https://www.openpolicyagent.org/docs/latest/policy-reference/#builtin-encoding-hexencode) | `hex` |
|
| [hex.encode](https://www.openpolicyagent.org/docs/latest/policy-reference/#builtin-encoding-hexencode) | `hex` |
|
||||||
| [json.is_valid](https://www.openpolicyagent.org/docs/latest/policy-reference/#builtin-encoding-jsonis_valid) | _ |
|
| [json.is_valid](https://www.openpolicyagent.org/docs/latest/policy-reference/#builtin-encoding-jsonis_valid) | _ |
|
||||||
| [json.marshal](https://www.openpolicyagent.org/docs/latest/policy-reference/#builtin-encoding-jsonmarshal) | _ |
|
| [json.marshal](https://www.openpolicyagent.org/docs/latest/policy-reference/#builtin-encoding-jsonmarshal) | _ |
|
||||||
| [json.unmarshal](https://www.openpolicyagent.org/docs/latest/policy-reference/#builtin-encoding-jsonunmarshal) | _ |
|
| [json.marshal_with_options](https://www.openpolicyagent.org/docs/latest/policy-reference/#builtin-encoding-jsonmarshal_with_options) | _ |
|
||||||
| [urlquery.decode](https://www.openpolicyagent.org/docs/latest/policy-reference/#builtin-encoding-urlquerydecode) | `urlquery` |
|
| [json.unmarshal](https://www.openpolicyagent.org/docs/latest/policy-reference/#builtin-encoding-jsonunmarshal) | _ |
|
||||||
| [urlquery.decode_object](https://www.openpolicyagent.org/docs/latest/policy-reference/#builtin-encoding-urlquerydecode_object) | `urlquery` |
|
| [urlquery.decode](https://www.openpolicyagent.org/docs/latest/policy-reference/#builtin-encoding-urlquerydecode) | `urlquery` |
|
||||||
| [urlquery.encode](https://www.openpolicyagent.org/docs/latest/policy-reference/#builtin-encoding-urlqueryencode) | `urlquery` |
|
| [urlquery.decode_object](https://www.openpolicyagent.org/docs/latest/policy-reference/#builtin-encoding-urlquerydecode_object) | `urlquery` |
|
||||||
| [urlquery.encode_object](https://www.openpolicyagent.org/docs/latest/policy-reference/#builtin-encoding-urlqueryencode_object) | `urlquery` |
|
| [urlquery.encode](https://www.openpolicyagent.org/docs/latest/policy-reference/#builtin-encoding-urlqueryencode) | `urlquery` |
|
||||||
| [yaml.is_valid](https://www.openpolicyagent.org/docs/latest/policy-reference/#builtin-encoding-yamlis_valid) | `yaml` |
|
| [urlquery.encode_object](https://www.openpolicyagent.org/docs/latest/policy-reference/#builtin-encoding-urlqueryencode_object) | `urlquery` |
|
||||||
| [yaml.marshal](https://www.openpolicyagent.org/docs/latest/policy-reference/#builtin-encoding-yamlmarshal) | `yaml` |
|
| [yaml.is_valid](https://www.openpolicyagent.org/docs/latest/policy-reference/#builtin-encoding-yamlis_valid) | `yaml` |
|
||||||
| [yaml.unmarshal](https://www.openpolicyagent.org/docs/latest/policy-reference/#builtin-encoding-yamlunmarshal) | `yaml` |
|
| [yaml.marshal](https://www.openpolicyagent.org/docs/latest/policy-reference/#builtin-encoding-yamlmarshal) | `yaml` |
|
||||||
|
| [yaml.unmarshal](https://www.openpolicyagent.org/docs/latest/policy-reference/#builtin-encoding-yamlunmarshal) | `yaml` |
|
||||||
|
|
||||||
- [Time](https://www.openpolicyagent.org/docs/latest/policy-reference/#time)
|
- [Time](https://www.openpolicyagent.org/docs/latest/policy-reference/#time)
|
||||||
| Builtin | Feature |
|
| Builtin | Feature |
|
||||||
|
|||||||
@@ -61,9 +61,9 @@ in-expr ::= in-expr 'in' bool-expr
|
|||||||
bool-expr ::= bool-expr bool-op or-expr
|
bool-expr ::= bool-expr bool-op or-expr
|
||||||
| or-expr
|
| or-expr
|
||||||
bool-op ::= '<' | '<=' | '==' | '>=' | '>' | '!='
|
bool-op ::= '<' | '<=' | '==' | '>=' | '>' | '!='
|
||||||
or-expr ::= or-expr '|' and-expr
|
set-union-expr ::= set-union-expr '|' set-intersection-expr
|
||||||
| and-expr
|
| set-intersection-expr
|
||||||
and-expr ::= and-expr '&' arith-expr
|
set-intersection-expr ::= set-intersection-expr '&' arith-expr
|
||||||
| arith-expr
|
| arith-expr
|
||||||
arith-expr ::= arith-expr ('+' | '-') mul-div-expr
|
arith-expr ::= arith-expr ('+' | '-') mul-div-expr
|
||||||
| mul-div-expr
|
| mul-div-expr
|
||||||
|
|||||||
19
examples/extension_list/agent-extension-data-allow-only.json
Normal file
19
examples/extension_list/agent-extension-data-allow-only.json
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
{
|
||||||
|
"azureGuestAgentPolicy": {
|
||||||
|
"signingRules": {
|
||||||
|
"extensionSigned": true
|
||||||
|
},
|
||||||
|
"allowListOnly": true
|
||||||
|
},
|
||||||
|
"azureGuestExtensionsPolicy": {
|
||||||
|
"test3": {
|
||||||
|
"runtimeRules": {}
|
||||||
|
},
|
||||||
|
"test2": {
|
||||||
|
"signingRules": {
|
||||||
|
"extensionSigned": false
|
||||||
|
},
|
||||||
|
"runtimeRules": {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user