mirror of
https://github.com/microsoft/regorus.git
synced 2026-08-05 02:16:11 +00:00
Compare commits
64 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 |
@@ -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)
|
||||||
22
.github/workflows/pr.yml
vendored
22
.github/workflows/pr.yml
vendored
@@ -18,22 +18,26 @@ jobs:
|
|||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
- name: Format Check
|
- name: Format Check
|
||||||
run: cargo fmt --check
|
run: cargo fmt --check
|
||||||
|
- name: Fetch
|
||||||
|
run: cargo fetch
|
||||||
- name: Build (all features)
|
- name: Build (all features)
|
||||||
run: cargo build -r --all-features
|
run: cargo build -r --all-features --frozen
|
||||||
- name: Build
|
- name: Build
|
||||||
run: cargo build -r
|
run: cargo build -r --frozen
|
||||||
- name: Test no_std
|
- name: Test no_std
|
||||||
run: cargo test -r --no-default-features
|
run: cargo test -r --no-default-features --frozen
|
||||||
- name: Build only std
|
- name: Build only std
|
||||||
run: cargo build -r --example regorus --no-default-features --features "std"
|
run: cargo build -r --example regorus --no-default-features --features "std" --frozen
|
||||||
- name: Doc Tests
|
- name: Doc Tests
|
||||||
run: cargo test -r --doc
|
run: cargo test -r --doc --frozen
|
||||||
- name: Run tests
|
- name: Run tests
|
||||||
run: cargo test -r
|
run: cargo test -r --frozen
|
||||||
|
- name: Run example
|
||||||
|
run: cargo run --example regorus --frozen -- eval -d examples/server/allowed_server.rego -i examples/server/input.json data.example
|
||||||
- name: Run tests (ACI)
|
- name: Run tests (ACI)
|
||||||
run: cargo test -r --test aci
|
run: cargo test -r --test aci --frozen
|
||||||
- name: Run tests (KATA)
|
- name: Run tests (KATA)
|
||||||
run: cargo test -r --test 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,serde_json/arbitrary_precision -- $(tr '\n' ' ' < tests/opa.passing)
|
cargo test -r --test opa --frozen --features opa-testutil,serde_json/arbitrary_precision -- $(tr '\n' ' ' < tests/opa.passing)
|
||||||
|
|||||||
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
|
||||||
|
|||||||
45
.github/workflows/publish-python.yml
vendored
45
.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@63b75c597b83e247fbf4fb7719801cc4220ae9f3 # v1.43.0
|
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@63b75c597b83e247fbf4fb7719801cc4220ae9f3 # v1.43.0
|
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@63b75c597b83e247fbf4fb7719801cc4220ae9f3 # v1.43.0
|
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@63b75c597b83e247fbf4fb7719801cc4220ae9f3 # v1.43.0
|
|
||||||
with:
|
|
||||||
command: sdist
|
|
||||||
args: --out dist --manifest-path bindings/python/Cargo.toml
|
|
||||||
- name: Upload sdist
|
|
||||||
uses: actions/upload-artifact@v3
|
|
||||||
with:
|
|
||||||
name: wheels
|
|
||||||
path: dist
|
|
||||||
|
|
||||||
release:
|
release:
|
||||||
name: Release
|
name: Release
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
|||||||
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
|
||||||
|
|||||||
3
.github/workflows/test-c-cpp.yml
vendored
3
.github/workflows/test-c-cpp.yml
vendored
@@ -20,7 +20,8 @@ jobs:
|
|||||||
|
|
||||||
- name: Workaround to ensure that regorus.h is generated
|
- name: Workaround to ensure that regorus.h is generated
|
||||||
run: |
|
run: |
|
||||||
cargo build -r
|
cargo fetch
|
||||||
|
cargo build -r --frozen
|
||||||
working-directory: ./bindings/ffi
|
working-directory: ./bindings/ffi
|
||||||
|
|
||||||
- name: Test c binding
|
- name: Test c binding
|
||||||
|
|||||||
120
.github/workflows/test-csharp.yml
vendored
120
.github/workflows/test-csharp.yml
vendored
@@ -7,8 +7,104 @@ on:
|
|||||||
branches: [ "main" ]
|
branches: [ "main" ]
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
test:
|
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
|
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:
|
steps:
|
||||||
- name: Checkout repository
|
- name: Checkout repository
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v4
|
||||||
@@ -16,11 +112,21 @@ jobs:
|
|||||||
fetch-depth: 0
|
fetch-depth: 0
|
||||||
|
|
||||||
- uses: actions/setup-dotnet@v4
|
- uses: actions/setup-dotnet@v4
|
||||||
|
with:
|
||||||
|
global-json-file: ./bindings/csharp/global.json
|
||||||
|
|
||||||
- name: Build
|
- run: echo '${{ steps.stepid.outputs.dotnet-version }}'
|
||||||
run: dotnet build
|
|
||||||
working-directory: ./bindings/csharp/net8.0
|
|
||||||
|
|
||||||
- name: Run
|
- name: Download regorus nuget
|
||||||
run: LD_LIBRARY_PATH=. dotnet run
|
uses: actions/download-artifact@v4
|
||||||
working-directory: ./bindings/csharp/net8.0
|
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
|
||||||
28
.github/workflows/test-csharp40.yml
vendored
28
.github/workflows/test-csharp40.yml
vendored
@@ -1,28 +0,0 @@
|
|||||||
name: bindings/csharp40
|
|
||||||
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
branches: [ "main" ]
|
|
||||||
pull_request:
|
|
||||||
branches: [ "main" ]
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
test:
|
|
||||||
runs-on: windows-latest
|
|
||||||
steps:
|
|
||||||
- name: Checkout repository
|
|
||||||
uses: actions/checkout@v4
|
|
||||||
with:
|
|
||||||
fetch-depth: 0
|
|
||||||
|
|
||||||
- uses: actions/setup-dotnet@v1
|
|
||||||
with:
|
|
||||||
dotnet-version: "5.0.x"
|
|
||||||
|
|
||||||
- name: Build
|
|
||||||
run: dotnet build
|
|
||||||
working-directory: ./bindings/csharp/net40
|
|
||||||
|
|
||||||
- name: Run
|
|
||||||
run: dotnet run
|
|
||||||
working-directory: ./bindings/csharp/net40
|
|
||||||
3
.github/workflows/test-ffi.yml
vendored
3
.github/workflows/test-ffi.yml
vendored
@@ -17,6 +17,7 @@ jobs:
|
|||||||
|
|
||||||
- name: Test FFI
|
- name: Test FFI
|
||||||
run: |
|
run: |
|
||||||
cargo build -r
|
cargo fetch
|
||||||
|
cargo build -r --frozen
|
||||||
cargo clippy --all-targets --no-deps -- -Dwarnings
|
cargo clippy --all-targets --no-deps -- -Dwarnings
|
||||||
working-directory: ./bindings/ffi
|
working-directory: ./bindings/ffi
|
||||||
|
|||||||
3
.github/workflows/test-go.yml
vendored
3
.github/workflows/test-go.yml
vendored
@@ -18,7 +18,6 @@ jobs:
|
|||||||
|
|
||||||
- uses: actions/setup-go@v5
|
- uses: actions/setup-go@v5
|
||||||
with:
|
with:
|
||||||
python-version: ${{ env.PYTHON_VERSION }}
|
|
||||||
architecture: x64
|
architecture: x64
|
||||||
|
|
||||||
- name: Build ffi
|
- name: Build ffi
|
||||||
@@ -29,5 +28,5 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
go mod tidy
|
go mod tidy
|
||||||
go build
|
go build
|
||||||
LD_LIBRARY_PATH=../../target/release ./regorus_test
|
LD_LIBRARY_PATH=../ffi/target/release ./regorus_test
|
||||||
working-directory: ./bindings/go
|
working-directory: ./bindings/go
|
||||||
|
|||||||
4
.github/workflows/test-java.yml
vendored
4
.github/workflows/test-java.yml
vendored
@@ -24,7 +24,7 @@ jobs:
|
|||||||
- name: Building binding
|
- name: Building binding
|
||||||
run: |
|
run: |
|
||||||
cargo clippy --all-targets --no-deps -- -Dwarnings
|
cargo clippy --all-targets --no-deps -- -Dwarnings
|
||||||
cargo build --release --manifest-path bindings/java/Cargo.toml
|
cargo build --release --manifest-path bindings/java/Cargo.toml --locked
|
||||||
|
|
||||||
- name: Build jar
|
- name: Build jar
|
||||||
run: mvn package
|
run: mvn package
|
||||||
@@ -33,5 +33,5 @@ jobs:
|
|||||||
- name: Test jar
|
- name: Test jar
|
||||||
run: |
|
run: |
|
||||||
javac -cp target/regorus-java-0.2.2.jar Test.java
|
javac -cp target/regorus-java-0.2.2.jar Test.java
|
||||||
java -Djava.library.path=../../target/release -cp target/regorus-java-0.2.2.jar:. Test
|
java -Djava.library.path=target/release -cp target/regorus-java-0.2.2.jar:. Test
|
||||||
working-directory: ./bindings/java
|
working-directory: ./bindings/java
|
||||||
|
|||||||
12
.github/workflows/test-musl.yml
vendored
12
.github/workflows/test-musl.yml
vendored
@@ -20,14 +20,16 @@ jobs:
|
|||||||
run: rustup target add x86_64-unknown-linux-musl
|
run: rustup target add x86_64-unknown-linux-musl
|
||||||
- name: Install musl-gcc
|
- name: Install musl-gcc
|
||||||
run: sudo apt update && sudo apt install -y musl-tools
|
run: sudo apt update && sudo apt install -y musl-tools
|
||||||
|
- name: Fetch
|
||||||
|
run: cargo fetch
|
||||||
- name: Build (MUSL)
|
- name: Build (MUSL)
|
||||||
run: cargo build --verbose --all-targets --target x86_64-unknown-linux-musl
|
run: cargo build --verbose --all-targets --target x86_64-unknown-linux-musl --frozen
|
||||||
- name: Run tests (MUSL)
|
- name: Run tests (MUSL)
|
||||||
run: cargo test -r --verbose --target x86_64-unknown-linux-musl
|
run: cargo test -r --verbose --target x86_64-unknown-linux-musl --frozen
|
||||||
- name: Run tests (MUSL ACI)
|
- name: Run tests (MUSL ACI)
|
||||||
run: cargo test -r --test aci --target x86_64-unknown-linux-musl
|
run: cargo test -r --test aci --target x86_64-unknown-linux-musl --frozen
|
||||||
- name: Run tests (KATA ACI)
|
- name: Run tests (KATA ACI)
|
||||||
run: cargo test -r --test kata --target x86_64-unknown-linux-musl
|
run: cargo test -r --test kata --target x86_64-unknown-linux-musl --frozen
|
||||||
- name: Run tests (MUSL OPA Conformance)
|
- name: Run tests (MUSL OPA Conformance)
|
||||||
run: >-
|
run: >-
|
||||||
cargo test -r --test opa --features opa-testutil,serde_json/arbitrary_precision --target x86_64-unknown-linux-musl -- $(tr '\n' ' ' < tests/opa.passing)
|
cargo test -r --test opa --frozen --features opa-testutil,serde_json/arbitrary_precision --target x86_64-unknown-linux-musl -- $(tr '\n' ' ' < tests/opa.passing)
|
||||||
|
|||||||
4
.github/workflows/test-no-std.yml
vendored
4
.github/workflows/test-no-std.yml
vendored
@@ -18,7 +18,9 @@ jobs:
|
|||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v3
|
||||||
- name: Add no_std target
|
- name: Add no_std target
|
||||||
run: rustup target add thumbv7m-none-eabi
|
run: rustup target add thumbv7m-none-eabi
|
||||||
|
- name: Fetch
|
||||||
|
run: cargo fetch
|
||||||
- name: Build
|
- name: Build
|
||||||
run: cargo build -r --target thumbv7m-none-eabi
|
run: cargo build -r --target thumbv7m-none-eabi --frozen
|
||||||
working-directory: ./tests/ensure_no_std
|
working-directory: ./tests/ensure_no_std
|
||||||
|
|
||||||
|
|||||||
67
.github/workflows/test-python.yml
vendored
67
.github/workflows/test-python.yml
vendored
@@ -10,8 +10,15 @@ env:
|
|||||||
PYTHON_VERSION: "3.10"
|
PYTHON_VERSION: "3.10"
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
test:
|
build:
|
||||||
runs-on: ubuntu-latest
|
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:
|
steps:
|
||||||
- name: Checkout repository
|
- name: Checkout repository
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v4
|
||||||
@@ -23,16 +30,60 @@ jobs:
|
|||||||
python-version: ${{ env.PYTHON_VERSION }}
|
python-version: ${{ env.PYTHON_VERSION }}
|
||||||
architecture: x64
|
architecture: x64
|
||||||
|
|
||||||
- name: Build wheels
|
- name: Build Python extension
|
||||||
|
run: |
|
||||||
|
cargo fetch
|
||||||
|
cargo clippy --all-targets --no-deps -- -Dwarnings
|
||||||
|
cargo build --release --target ${{ matrix.host.target }} --frozen
|
||||||
|
working-directory: bindings/python
|
||||||
|
|
||||||
|
- name: Build Wheel
|
||||||
uses: PyO3/maturin-action@63b75c597b83e247fbf4fb7719801cc4220ae9f3 # v1.43.0
|
uses: PyO3/maturin-action@63b75c597b83e247fbf4fb7719801cc4220ae9f3 # v1.43.0
|
||||||
with:
|
with:
|
||||||
target: x86_64
|
target: x86_64
|
||||||
args: --release --out dist --manifest-path bindings/python/Cargo.toml
|
args: --release --out dist --manifest-path bindings/python/Cargo.toml --offline --strip
|
||||||
sccache: 'true'
|
sccache: 'true'
|
||||||
|
|
||||||
- name: Test wheel
|
- name: Upload Wheel
|
||||||
|
uses: actions/upload-artifact@v4
|
||||||
|
with:
|
||||||
|
name: regorus-wheel-${{ matrix.host.name }}
|
||||||
|
path: dist/regorus-*.whl
|
||||||
|
|
||||||
|
test:
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
python-version: ["3.10", "3.11", "3.12", "3.13"]
|
||||||
|
host:
|
||||||
|
- name: ubuntu-24.04
|
||||||
|
wheel: regorus-0.4.0-cp310-abi3-manylinux_2_34_x86_64.whl
|
||||||
|
- name: ubuntu-22.04
|
||||||
|
wheel: regorus-0.4.0-cp310-abi3-manylinux_2_34_x86_64.whl
|
||||||
|
- name: windows-latest
|
||||||
|
wheel: regorus-0.4.0-cp310-abi3-win_amd64.whl
|
||||||
|
|
||||||
|
needs: build
|
||||||
|
runs-on: ${{ matrix.host.name }}
|
||||||
|
steps:
|
||||||
|
- name: Checkout repository
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
fetch-depth: 0
|
||||||
|
|
||||||
|
- name: Download Regorus wheel
|
||||||
|
uses: actions/download-artifact@v4
|
||||||
|
with:
|
||||||
|
path: wheels
|
||||||
|
pattern: regorus-wheel-*
|
||||||
|
merge-multiple: true
|
||||||
|
|
||||||
|
- uses: actions/setup-python@v4
|
||||||
|
with:
|
||||||
|
python-version: ${{ matrix.python-version }}
|
||||||
|
architecture: x64
|
||||||
|
|
||||||
|
- name: Test Wheel
|
||||||
run: |
|
run: |
|
||||||
pip3 install dist/regorus-*.whl
|
pip3 install ../../wheels/${{ matrix.host.wheel }}
|
||||||
cd bindings/python
|
|
||||||
cargo clippy --all-targets --no-deps -- -Dwarnings
|
|
||||||
python3 test.py
|
python3 test.py
|
||||||
|
working-directory: bindings/python
|
||||||
6
.github/workflows/test-ruby.yml
vendored
6
.github/workflows/test-ruby.yml
vendored
@@ -18,7 +18,9 @@ jobs:
|
|||||||
- name: Setup Ruby and Rust
|
- name: Setup Ruby and Rust
|
||||||
uses: oxidize-rb/actions/setup-ruby-and-rust@7ca44a16e287e5ff7dd72ab53f4bd41cbf34a571 #v1.26
|
uses: oxidize-rb/actions/setup-ruby-and-rust@7ca44a16e287e5ff7dd72ab53f4bd41cbf34a571 #v1.26
|
||||||
with:
|
with:
|
||||||
ruby-version: "3.3.1"
|
bundler: 2.6.5
|
||||||
|
rubygems: 3.6.5
|
||||||
|
ruby-version: "3.4.2"
|
||||||
rustup-toolchain: "stable"
|
rustup-toolchain: "stable"
|
||||||
bundler-cache: true
|
bundler-cache: true
|
||||||
cargo-cache: true
|
cargo-cache: true
|
||||||
@@ -27,5 +29,7 @@ jobs:
|
|||||||
- name: Run ruby tests
|
- name: Run ruby tests
|
||||||
run: |
|
run: |
|
||||||
cd bindings/ruby
|
cd bindings/ruby
|
||||||
|
gem install bundler
|
||||||
|
bundle install
|
||||||
cargo clippy --all-targets --no-deps -- -Dwarnings
|
cargo clippy --all-targets --no-deps -- -Dwarnings
|
||||||
bundle exec rake
|
bundle exec rake
|
||||||
|
|||||||
5
.github/workflows/test-wasm.yml
vendored
5
.github/workflows/test-wasm.yml
vendored
@@ -26,7 +26,10 @@ jobs:
|
|||||||
- name: Test wasm binding
|
- name: Test wasm binding
|
||||||
run: |
|
run: |
|
||||||
cd bindings/wasm
|
cd bindings/wasm
|
||||||
|
cargo fetch
|
||||||
cargo clippy --all-targets --no-deps -- -Dwarnings
|
cargo clippy --all-targets --no-deps -- -Dwarnings
|
||||||
wasm-pack build --target nodejs --release
|
wasm-pack build --target nodejs --release
|
||||||
wasm-pack test --release --node
|
# Enable when upstream issue is fixed.
|
||||||
|
# https://github.com/microsoft/regorus/issues/371
|
||||||
|
# wasm-pack test --release --node
|
||||||
node test.js
|
node test.js
|
||||||
|
|||||||
20
.github/workflows/tests-debug.yml
vendored
20
.github/workflows/tests-debug.yml
vendored
@@ -16,22 +16,24 @@ jobs:
|
|||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
|
- name: Fetch
|
||||||
|
run: cargo fetch
|
||||||
- name: Build (all features)
|
- name: Build (all features)
|
||||||
run: cargo build --all-features
|
run: cargo build --all-features --frozen
|
||||||
- name: Build
|
- name: Build
|
||||||
run: cargo build
|
run: cargo build --frozen
|
||||||
- name: Test no_std
|
- name: Test no_std
|
||||||
run: cargo test --no-default-features
|
run: cargo test --no-default-features --frozen
|
||||||
- name: Build only std
|
- name: Build only std
|
||||||
run: cargo build --example regorus --no-default-features --features "std"
|
run: cargo build --example regorus --no-default-features --features "std" --frozen
|
||||||
- name: Doc Tests
|
- name: Doc Tests
|
||||||
run: cargo test --doc
|
run: cargo test --doc --frozen
|
||||||
- name: Run tests
|
- name: Run tests
|
||||||
run: cargo test
|
run: cargo test --frozen
|
||||||
- name: Run tests (ACI)
|
- name: Run tests (ACI)
|
||||||
run: cargo test --test aci
|
run: cargo test --test aci --frozen
|
||||||
- name: Run tests (KATA)
|
- name: Run tests (KATA)
|
||||||
run: cargo test --test kata
|
run: cargo test --test kata --frozen
|
||||||
- name: Run tests (OPA Conformance)
|
- name: Run tests (OPA Conformance)
|
||||||
run: >-
|
run: >-
|
||||||
cargo test --test opa --features opa-testutil,serde_json/arbitrary_precision -- $(tr '\n' ' ' < tests/opa.passing)
|
cargo test --test opa --frozen --features opa-testutil,serde_json/arbitrary_precision -- $(tr '\n' ' ' < tests/opa.passing)
|
||||||
|
|||||||
10
.gitignore
vendored
10
.gitignore
vendored
@@ -4,10 +4,6 @@
|
|||||||
**/wheels/
|
**/wheels/
|
||||||
**/__pycache__/
|
**/__pycache__/
|
||||||
|
|
||||||
# Remove Cargo.lock from gitignore if creating an executable, leave it for libraries
|
|
||||||
# More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html
|
|
||||||
Cargo.lock
|
|
||||||
|
|
||||||
# These are backup files generated by rustfmt
|
# These are backup files generated by rustfmt
|
||||||
**/*.rs.bk
|
**/*.rs.bk
|
||||||
|
|
||||||
@@ -26,3 +22,9 @@ worktrees/
|
|||||||
# Generated C, C++ headers
|
# Generated C, C++ headers
|
||||||
bindings/ffi/regorus.h
|
bindings/ffi/regorus.h
|
||||||
bindings/ffi/regorus.ffi.hpp
|
bindings/ffi/regorus.ffi.hpp
|
||||||
|
|
||||||
|
bindings/*/target
|
||||||
|
|
||||||
|
# C# build folders
|
||||||
|
**bin
|
||||||
|
**obj
|
||||||
91
CHANGELOG.md
91
CHANGELOG.md
@@ -6,6 +6,97 @@ 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
|
## [0.2.2](https://github.com/microsoft/regorus/compare/regorus-v0.2.1...regorus-v0.2.2) - 2024-07-28
|
||||||
|
|
||||||
### Added
|
### Added
|
||||||
|
|||||||
1778
Cargo.lock
generated
Normal file
1778
Cargo.lock
generated
Normal file
File diff suppressed because it is too large
Load Diff
54
Cargo.toml
54
Cargo.toml
@@ -1,18 +1,13 @@
|
|||||||
[workspace]
|
[workspace]
|
||||||
|
|
||||||
members = [
|
members = [
|
||||||
"bindings/ffi",
|
|
||||||
"bindings/python",
|
|
||||||
"bindings/wasm",
|
|
||||||
"bindings/java",
|
|
||||||
"bindings/ruby/ext/regorusrb",
|
|
||||||
"tests/ensure_no_std",
|
"tests/ensure_no_std",
|
||||||
]
|
]
|
||||||
|
|
||||||
[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.2.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"
|
||||||
@@ -31,14 +26,13 @@ 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 = []
|
||||||
glob = ["dep:wax"]
|
glob = ["dep:globset"]
|
||||||
graph = []
|
graph = []
|
||||||
jsonschema = ["dep:jsonschema"]
|
jsonschema = ["dep:jsonschema"]
|
||||||
jwt = ["dep:jsonwebtoken", "dep:data-encoding", "dep:itertools"]
|
|
||||||
no_std = ["lazy_static/spin_no_std"]
|
no_std = ["lazy_static/spin_no_std"]
|
||||||
opa-runtime = []
|
opa-runtime = []
|
||||||
regex = ["dep:regex"]
|
regex = ["dep:regex"]
|
||||||
@@ -58,7 +52,6 @@ full-opa = [
|
|||||||
"graph",
|
"graph",
|
||||||
"hex",
|
"hex",
|
||||||
"http",
|
"http",
|
||||||
"jwt",
|
|
||||||
"jsonschema",
|
"jsonschema",
|
||||||
"opa-runtime",
|
"opa-runtime",
|
||||||
"regex",
|
"regex",
|
||||||
@@ -67,7 +60,9 @@ full-opa = [
|
|||||||
"time",
|
"time",
|
||||||
"uuid",
|
"uuid",
|
||||||
"urlquery",
|
"urlquery",
|
||||||
"yaml"
|
"yaml",
|
||||||
|
|
||||||
|
#"rego-extensions"
|
||||||
]
|
]
|
||||||
|
|
||||||
# Features that can be used in no_std environments.
|
# Features that can be used in no_std environments.
|
||||||
@@ -89,6 +84,9 @@ opa-no-std = [
|
|||||||
"lazy_static/spin_no_std"
|
"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"]
|
rand = ["dep:rand"]
|
||||||
@@ -100,35 +98,33 @@ serde_json = { version = "1.0.89", default-features = false, features = ["alloc"
|
|||||||
lazy_static = { version = "1.4.0", default-features = false }
|
lazy_static = { version = "1.4.0", default-features = false }
|
||||||
|
|
||||||
# Crypto
|
# Crypto
|
||||||
constant_time_eq = {version = "0.3.0", optional = true, default-features = false }
|
constant_time_eq = {version = "0.4.0", optional = true, default-features = false }
|
||||||
hmac = {version = "0.12.1", optional = true, default-features = false}
|
hmac = {version = "0.12.1", optional = true, default-features = false}
|
||||||
sha2 = {version= "0.10.8", optional = true, default-features = false }
|
sha2 = {version= "0.10.8", optional = true, default-features = false }
|
||||||
hex = {version = "0.4.3", optional = true, default-features = false, features = ["alloc"] }
|
hex = {version = "0.4.3", optional = true, default-features = false, features = ["alloc"] }
|
||||||
sha1 = {version = "0.10.6", optional = true, default-features = false }
|
|
||||||
md-5 = {version = "0.10.6", optional = true, default-features = false }
|
md-5 = {version = "0.10.6", optional = true, default-features = false }
|
||||||
|
|
||||||
data-encoding = { version = "2.4.0", optional = true, default-features=false, features = ["alloc"] }
|
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, default-features = false }
|
globset = { version = "0.4.16", features = ["simd-accel"], default-features = false, optional = true }
|
||||||
semver = {version = "1.0.20", optional = true, default-features = false }
|
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", default-features = false, features = ["v4", "fast-rng"], optional = true }
|
uuid = { version = "1.15.1", default-features = false, features = ["v4", "fast-rng"], optional = true }
|
||||||
jsonschema = { version = "0.18.0", 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 }
|
||||||
jsonwebtoken = { version = "9.2.0", optional = true }
|
|
||||||
itertools = { version = "0.13.0", default-features = false, optional = true }
|
|
||||||
|
|
||||||
serde_yaml = {version = "0.9.16", default-features = false, optional = true }
|
serde_yaml = {version = "0.9.16", default-features = false, optional = true }
|
||||||
rand = { version = "0.8.5", default-features = false, optional = true }
|
# Specify thread_rng for in order to use random_range
|
||||||
|
rand = { version = "0.9.0", default-features = false, features = ["thread_rng"], optional = true }
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
anyhow = "1.0.45"
|
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"] }
|
||||||
prettydiff = { version = "0.7.0", default-features = false }
|
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"
|
||||||
@@ -138,6 +134,8 @@ anyhow = "1.0"
|
|||||||
|
|
||||||
[profile.release]
|
[profile.release]
|
||||||
debug = true
|
debug = true
|
||||||
|
lto = true
|
||||||
|
codegen-units = 1
|
||||||
|
|
||||||
[[test]]
|
[[test]]
|
||||||
name="opa"
|
name="opa"
|
||||||
|
|||||||
25
README.md
25
README.md
@@ -9,8 +9,8 @@
|
|||||||
Regorus is also
|
Regorus is also
|
||||||
- *cross-platform* - Written in platform-agnostic Rust.
|
- *cross-platform* - Written in platform-agnostic Rust.
|
||||||
- *no_std compatible* - Regorus can be used in `no_std` environments too. Most of the builtins are supported.
|
- *no_std compatible* - Regorus can be used in `no_std` environments too. Most of the builtins are supported.
|
||||||
- *current* - We strive to keep Regorus up to date with latest OPA release. Regorus supports `import rego.v1`.
|
- *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 v0.67.0](https://github.com/open-policy-agent/opa/releases/tag/v0.67.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.
|
- *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.
|
||||||
@@ -32,7 +32,6 @@ fn main() -> anyhow::Result<()> {
|
|||||||
let policy = String::from(
|
let policy = String::from(
|
||||||
r#"
|
r#"
|
||||||
package example
|
package example
|
||||||
import rego.v1
|
|
||||||
|
|
||||||
allow if {
|
allow if {
|
||||||
## All actions are allowed for admins.
|
## All actions are allowed for admins.
|
||||||
@@ -99,7 +98,7 @@ $ cargo build -r --example regorus --no-default-features; strip target/release/e
|
|||||||
-rwxr-xr-x 1 anand staff 1.9M May 11 22:04 target/release/examples/regorus*
|
-rwxr-xr-x 1 anand staff 1.9M May 11 22:04 target/release/examples/regorus*
|
||||||
```
|
```
|
||||||
|
|
||||||
Regorus passes the [OPA v0.67.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
|
||||||
@@ -108,11 +107,11 @@ Regorus can be used from a variety of languages:
|
|||||||
|
|
||||||
- *C*: C binding is generated using [cbindgen](https://github.com/mozilla/cbindgen).
|
- *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 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).
|
||||||
@@ -184,11 +183,11 @@ This produces the following output
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
Next, evaluate a sample [policy](https://github.com/microsoft/regorus/blob/main/examples/example.rego) and [input](https://github.com/microsoft/regorus/blob/main/examples/input.json)
|
Next, evaluate a sample [policy](https://github.com/microsoft/regorus/blob/main/examples/server/allowed_server.rego) and [input](https://github.com/microsoft/regorus/blob/main/examples/server/input.json)
|
||||||
(borrowed from [Rego tutorial](https://www.openpolicyagent.org/docs/latest/#2-try-opa-eval)):
|
(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)
|
||||||
@@ -204,7 +203,7 @@ Regorus allows determining which lines of a policy have been executed using the
|
|||||||
We can try it out using the `regorus` example program by passing in the `--coverage` flag.
|
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.
|
||||||
@@ -276,7 +275,7 @@ 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.67.0](https://github.com/open-policy-agent/opa/releases/tag/v0.67.0)
|
Regorus has been verified to be compliant with [OPA v1.2.0](https://github.com/open-policy-agent/opa/releases/tag/v1.2.0)
|
||||||
using a [test driver](https://github.com/microsoft/regorus/blob/main/tests/opa.rs) that loads and runs the OPA testsuite using Regorus, and verifies that expected outputs are produced.
|
using a [test driver](https://github.com/microsoft/regorus/blob/main/tests/opa.rs) that loads and runs the OPA testsuite using Regorus, and verifies that expected outputs are produced.
|
||||||
|
|
||||||
The test driver can be invoked by running:
|
The test driver can be invoked by running:
|
||||||
@@ -288,7 +287,7 @@ $ cargo test -r --test opa --features opa-testutil,serde_json/arbitrary_precisio
|
|||||||
Currently, Regorus passes all the non-builtin specific tests.
|
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`
|
||||||
@@ -299,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`
|
||||||
@@ -322,6 +324,7 @@ The following test suites don't pass fully due to mising builtins:
|
|||||||
|
|
||||||
They are captured in the following [github issues](https://github.com/microsoft/regorus/issues?q=is%3Aopen+is%3Aissue+label%3Alib).
|
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
|
||||||
|
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|
||||||
@@ -31,6 +32,8 @@ corrosion_import_crate(
|
|||||||
# See regorus/opa_no_std
|
# See regorus/opa_no_std
|
||||||
FEATURES "custom_allocator,regorus/semver"
|
FEATURES "custom_allocator,regorus/semver"
|
||||||
|
|
||||||
|
LOCKED
|
||||||
|
|
||||||
# Link statically
|
# Link statically
|
||||||
CRATE_TYPES staticlib FLAGS --crate-type=staticlib
|
CRATE_TYPES staticlib FLAGS --crate-type=staticlib
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ char* file_to_string(const char* file) {
|
|||||||
|
|
||||||
// If regorus is built with custom-allocator, then provide implementation.
|
// If regorus is built with custom-allocator, then provide implementation.
|
||||||
uint8_t* regorus_aligned_alloc(size_t alignment, size_t size) {
|
uint8_t* regorus_aligned_alloc(size_t alignment, size_t size) {
|
||||||
return aligned_alloc(alignment, size);
|
return (uint8_t*) aligned_alloc(alignment, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
void regorus_free(uint8_t* ptr) {
|
void regorus_free(uint8_t* ptr) {
|
||||||
@@ -41,6 +41,11 @@ int main() {
|
|||||||
RegorusResult r;
|
RegorusResult r;
|
||||||
char* buffer = NULL;
|
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.
|
// Load policies.
|
||||||
r = regorus_engine_add_policy(engine, "framework.rego", (buffer = file_to_string("../../../tests/aci/framework.rego")));
|
r = regorus_engine_add_policy(engine, "framework.rego", (buffer = file_to_string("../../../tests/aci/framework.rego")));
|
||||||
free(buffer);
|
free(buffer);
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|
||||||
@@ -24,6 +25,8 @@ corrosion_import_crate(
|
|||||||
# Select specific features in regorus.
|
# Select specific features in regorus.
|
||||||
FEATURES "regorus/semver"
|
FEATURES "regorus/semver"
|
||||||
|
|
||||||
|
LOCKED
|
||||||
|
|
||||||
# Link statically
|
# Link statically
|
||||||
CRATE_TYPES "cdylib"
|
CRATE_TYPES "cdylib"
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -6,6 +6,11 @@ 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)
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|
||||||
@@ -25,6 +26,8 @@ corrosion_import_crate(
|
|||||||
# Select specific features in regorus.
|
# Select specific features in regorus.
|
||||||
FEATURES "regorus/semver"
|
FEATURES "regorus/semver"
|
||||||
|
|
||||||
|
LOCKED
|
||||||
|
|
||||||
# Link statically
|
# Link statically
|
||||||
CRATE_TYPES "cdylib")
|
CRATE_TYPES "cdylib")
|
||||||
|
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ void example()
|
|||||||
// Create engine
|
// Create engine
|
||||||
regorus::Engine engine;
|
regorus::Engine engine;
|
||||||
|
|
||||||
|
engine.set_rego_v0(true);
|
||||||
engine.set_enable_coverage(true);
|
engine.set_enable_coverage(true);
|
||||||
|
|
||||||
// Add policies.
|
// Add policies.
|
||||||
@@ -83,6 +84,7 @@ int main() {
|
|||||||
|
|
||||||
// Create engine.
|
// Create engine.
|
||||||
regorus::Engine engine;
|
regorus::Engine engine;
|
||||||
|
engine.set_rego_v0(true);
|
||||||
|
|
||||||
|
|
||||||
// Load policies.
|
// Load policies.
|
||||||
|
|||||||
@@ -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));
|
||||||
|
|||||||
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}");
|
||||||
|
}
|
||||||
|
}
|
||||||
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
|
||||||
@@ -1,28 +1,25 @@
|
|||||||
//-----------------------------------------------------------------------
|
// Copyright (c) Microsoft Corporation.
|
||||||
// <copyright file="Program.cs" company="Microsoft">
|
// Licensed under the MIT License.
|
||||||
// Copyright (c)2012 Microsoft. All rights reserved.
|
|
||||||
// </copyright>
|
|
||||||
// <summary>
|
|
||||||
// Contains code to test the Regorus class for C#
|
|
||||||
// and .NET 8.0 bindings.
|
|
||||||
// </summary>
|
|
||||||
//-----------------------------------------------------------------------
|
|
||||||
|
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
|
|
||||||
long nanosecPerTick = (1000L*1000L*1000L) / Stopwatch.Frequency;
|
|
||||||
|
long nanosecPerTick = (1000L * 1000L * 1000L) / Stopwatch.Frequency;
|
||||||
var w = new Stopwatch();
|
var w = new Stopwatch();
|
||||||
|
|
||||||
|
|
||||||
// Force load of modules.
|
// Force load of modules.
|
||||||
{
|
{
|
||||||
var _e = new Regorus.Engine();
|
var _e = new Regorus.Engine();
|
||||||
|
#if NET8_0_OR_GREATER
|
||||||
var _j = System.Text.Json.JsonDocument.Parse("{}");
|
var _j = System.Text.Json.JsonDocument.Parse("{}");
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
w.Restart();
|
w.Restart();
|
||||||
|
|
||||||
var engine = new Regorus.Engine();
|
var engine = new Regorus.Engine();
|
||||||
|
engine.SetRegoV0(true);
|
||||||
|
|
||||||
w.Stop();
|
w.Stop();
|
||||||
var newEngineTicks = w.ElapsedTicks;
|
var newEngineTicks = w.ElapsedTicks;
|
||||||
@@ -45,18 +42,24 @@ w.Restart();
|
|||||||
|
|
||||||
// Set input and eval rule.
|
// Set input and eval rule.
|
||||||
engine.SetInputFromJsonFile("../../../tests/aci/input.json");
|
engine.SetInputFromJsonFile("../../../tests/aci/input.json");
|
||||||
var value = engine.EvalQuery("data.framework.mount_overlay");
|
var value = engine.EvalRule("data.framework.mount_overlay");
|
||||||
|
|
||||||
|
#if NET8_0_OR_GREATER
|
||||||
var valueDoc = System.Text.Json.JsonDocument.Parse(value);
|
var valueDoc = System.Text.Json.JsonDocument.Parse(value);
|
||||||
|
|
||||||
w.Stop();
|
w.Stop();
|
||||||
var evalTicks = w.ElapsedTicks;
|
var evalTicks = w.ElapsedTicks;
|
||||||
|
|
||||||
Console.WriteLine("{0}", valueDoc);
|
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("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("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));
|
Console.WriteLine("EvalRule took {0} msecs", (evalTicks * nanosecPerTick) / (1000.0 * 1000.0));
|
||||||
|
|
||||||
engine = new Regorus.Engine();
|
engine = new Regorus.Engine();
|
||||||
engine.AddPolicy(
|
engine.AddPolicy(
|
||||||
@@ -64,5 +67,16 @@ engine.AddPolicy(
|
|||||||
"package test\nx = 1\nmessage = `Hello`");
|
"package test\nx = 1\nmessage = `Hello`");
|
||||||
|
|
||||||
engine.SetEnableCoverage(true);
|
engine.SetEnableCoverage(true);
|
||||||
Console.WriteLine("{0}", engine.EvalRule("data.test.message"));
|
Console.WriteLine("data.test.message: {0}", engine.EvalRule("data.test.message"));
|
||||||
Console.WriteLine("{0}", engine.GetCoverageReportPretty());
|
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,65 +0,0 @@
|
|||||||
//-----------------------------------------------------------------------
|
|
||||||
// <copyright file="Program.cs" company="Microsoft">
|
|
||||||
// Copyright (c)2012 Microsoft. All rights reserved.
|
|
||||||
// </copyright>
|
|
||||||
// <summary>
|
|
||||||
// Contains code to test the Regorus Policy Engine base class for C#
|
|
||||||
// and .NET4.0 bindings. It can be built and tested in Windows only.
|
|
||||||
// </summary>
|
|
||||||
//-----------------------------------------------------------------------
|
|
||||||
using System;
|
|
||||||
using System.Text;
|
|
||||||
|
|
||||||
using System.Diagnostics;
|
|
||||||
using Microsoft.WindowsAzure.Regorus.IaaS;
|
|
||||||
|
|
||||||
namespace regoregorus_test
|
|
||||||
{
|
|
||||||
class Program
|
|
||||||
{
|
|
||||||
static void Main(string[] args)
|
|
||||||
{
|
|
||||||
long nanosecPerTick = (1000L * 1000L * 1000L) / Stopwatch.Frequency;
|
|
||||||
var w = new Stopwatch();
|
|
||||||
w.Restart();
|
|
||||||
|
|
||||||
var engine = new RegorusPolicyEngine();
|
|
||||||
|
|
||||||
w.Stop();
|
|
||||||
var newEngineTicks = w.ElapsedTicks;
|
|
||||||
|
|
||||||
|
|
||||||
w.Restart();
|
|
||||||
|
|
||||||
// Load policies and data.
|
|
||||||
engine.AddPolicyFromFile("../../../examples/extension_list/agent_extension_policy.rego");
|
|
||||||
engine.AddDataFromJsonFile("../../../examples/extension_list/agent-extension-data-allow-only.json");
|
|
||||||
|
|
||||||
|
|
||||||
w.Stop();
|
|
||||||
var loadPoliciesTicks = w.ElapsedTicks;
|
|
||||||
|
|
||||||
|
|
||||||
w.Restart();
|
|
||||||
|
|
||||||
// Set input and eval query.
|
|
||||||
engine.SetInputFromJsonFile("../../../examples/extension_list/agent-extension-input.json");
|
|
||||||
var results = engine.EvalQuery("data.agent_extension_policy.extensions_to_download=x");
|
|
||||||
Console.WriteLine("Download query test: \n {0}", results);
|
|
||||||
|
|
||||||
results = engine.EvalQuery("data.agent_extension_policy.extensions_validated");
|
|
||||||
|
|
||||||
Console.WriteLine("Signing validation test: \n {0}", results);
|
|
||||||
|
|
||||||
engine.Dispose();
|
|
||||||
|
|
||||||
w.Stop();
|
|
||||||
var evalTicks = w.ElapsedTicks;
|
|
||||||
|
|
||||||
Console.WriteLine("Engine creation took {0} msecs", (newEngineTicks * nanosecPerTick) / (1000.0 * 1000.0));
|
|
||||||
Console.WriteLine("Load policies and data took {0} msecs", (loadPoliciesTicks * nanosecPerTick) / (1000.0 * 1000.0));
|
|
||||||
Console.WriteLine("EvalQuery and print results took {0} msecs", (evalTicks * nanosecPerTick) / (1000.0 * 1000.0));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -1,4 +0,0 @@
|
|||||||
The Regorus C# binding library can be built via command "dotnet build". We can use the Regorus C# binding library built from this
|
|
||||||
directory to create a Nuget. This Nuget will contain the Regorus C# binding library with definitions that
|
|
||||||
work for .NET framework 4.0 (net40) and above. Note the Nuget can only be created after the binding library has been built.
|
|
||||||
RegorusCsharp-Lib-x64.nuspec is built for x64 architecture.
|
|
||||||
@@ -1,203 +0,0 @@
|
|||||||
//-----------------------------------------------------------------------
|
|
||||||
// <copyright file="Regorus.cs" company="Microsoft">
|
|
||||||
// Copyright (c)2012 Microsoft. All rights reserved.
|
|
||||||
// </copyright>
|
|
||||||
// <summary>
|
|
||||||
// Contains code for the Regorus Policy Engine base class for C# and
|
|
||||||
// .NET4.0 bindings. Currently this base class is not thread-safe. Make
|
|
||||||
// sure we use it in a signle-threaded environment or add additional
|
|
||||||
// protection when using it.
|
|
||||||
// </summary>
|
|
||||||
//-----------------------------------------------------------------------
|
|
||||||
|
|
||||||
|
|
||||||
using System;
|
|
||||||
using System.Text;
|
|
||||||
using System.IO;
|
|
||||||
using System.Threading;
|
|
||||||
|
|
||||||
namespace Microsoft.WindowsAzure.Regorus.IaaS
|
|
||||||
{
|
|
||||||
|
|
||||||
public class RegorusPolicyEngine : ICloneable, IDisposable
|
|
||||||
{
|
|
||||||
unsafe private RegorusFFI.RegorusEngine* E;
|
|
||||||
|
|
||||||
public RegorusPolicyEngine()
|
|
||||||
{
|
|
||||||
unsafe
|
|
||||||
{
|
|
||||||
E = RegorusFFI.API.regorus_engine_new();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public void Dispose()
|
|
||||||
{
|
|
||||||
unsafe
|
|
||||||
{
|
|
||||||
if (E != null)
|
|
||||||
{
|
|
||||||
RegorusFFI.API.regorus_engine_drop(E);
|
|
||||||
// to avoid Dispose() being called multiple times by mistake.
|
|
||||||
E = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public object Clone()
|
|
||||||
{
|
|
||||||
var clone = (RegorusPolicyEngine)this.MemberwiseClone();
|
|
||||||
unsafe
|
|
||||||
{
|
|
||||||
clone.E = RegorusFFI.API.regorus_engine_clone(E);
|
|
||||||
}
|
|
||||||
return clone;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public void AddPolicy(string path, string rego)
|
|
||||||
{
|
|
||||||
var pathBytes = Encoding.UTF8.GetBytes(path);
|
|
||||||
var regoBytes = Encoding.UTF8.GetBytes(rego);
|
|
||||||
|
|
||||||
unsafe
|
|
||||||
{
|
|
||||||
fixed (byte* pathPtr = pathBytes)
|
|
||||||
{
|
|
||||||
fixed(byte* regoPtr = regoBytes)
|
|
||||||
{
|
|
||||||
CheckAndDropResult(RegorusFFI.API.regorus_engine_add_policy(E, pathPtr, regoPtr));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void AddPolicyFromFile(string path)
|
|
||||||
{
|
|
||||||
var pathBytes = Encoding.UTF8.GetBytes(path);
|
|
||||||
|
|
||||||
unsafe
|
|
||||||
{
|
|
||||||
fixed (byte* pathPtr = pathBytes)
|
|
||||||
{
|
|
||||||
CheckAndDropResult(RegorusFFI.API.regorus_engine_add_policy_from_file(E, pathPtr));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void AddPolicyFromPath(string path)
|
|
||||||
{
|
|
||||||
if (!Directory.Exists(path))
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
string[] regoFiles = Directory.GetFiles(path, "*.rego", SearchOption.AllDirectories);
|
|
||||||
foreach (string file in regoFiles)
|
|
||||||
{
|
|
||||||
AddPolicyFromFile(file);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void AddDataJson(string data)
|
|
||||||
{
|
|
||||||
var dataBytes = Encoding.UTF8.GetBytes(data);
|
|
||||||
|
|
||||||
unsafe
|
|
||||||
{
|
|
||||||
fixed (byte* dataPtr = dataBytes)
|
|
||||||
{
|
|
||||||
CheckAndDropResult(RegorusFFI.API.regorus_engine_add_data_json(E, dataPtr));
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void AddDataFromJsonFile(string path)
|
|
||||||
{
|
|
||||||
var pathBytes = Encoding.UTF8.GetBytes(path);
|
|
||||||
|
|
||||||
unsafe
|
|
||||||
{
|
|
||||||
fixed (byte* pathPtr = pathBytes)
|
|
||||||
{
|
|
||||||
CheckAndDropResult(RegorusFFI.API.regorus_engine_add_data_from_json_file(E, pathPtr));
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void SetInputJson(string input)
|
|
||||||
{
|
|
||||||
var inputBytes = Encoding.UTF8.GetBytes(input);
|
|
||||||
|
|
||||||
unsafe
|
|
||||||
{
|
|
||||||
fixed (byte* inputPtr = inputBytes)
|
|
||||||
{
|
|
||||||
CheckAndDropResult(RegorusFFI.API.regorus_engine_set_input_json(E, inputPtr));
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void SetInputFromJsonFile(string path)
|
|
||||||
{
|
|
||||||
var pathBytes = Encoding.UTF8.GetBytes(path);
|
|
||||||
|
|
||||||
unsafe
|
|
||||||
{
|
|
||||||
fixed (byte* pathPtr = pathBytes)
|
|
||||||
{
|
|
||||||
CheckAndDropResult(RegorusFFI.API.regorus_engine_set_input_from_json_file(E, pathPtr));
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public string EvalQuery(string query)
|
|
||||||
{
|
|
||||||
var queryBytes = Encoding.UTF8.GetBytes(query);
|
|
||||||
|
|
||||||
var resultJson = "";
|
|
||||||
unsafe
|
|
||||||
{
|
|
||||||
fixed (byte* queryPtr = queryBytes)
|
|
||||||
{
|
|
||||||
var result = RegorusFFI.API.regorus_engine_eval_query(E, queryPtr);
|
|
||||||
if (result.status == RegorusFFI.RegorusStatus.RegorusStatusOk) {
|
|
||||||
if (result.output != null) {
|
|
||||||
resultJson = System.Runtime.InteropServices.Marshal.PtrToStringAnsi((IntPtr)result.output);
|
|
||||||
}
|
|
||||||
RegorusFFI.API.regorus_result_drop(result);
|
|
||||||
} else {
|
|
||||||
CheckAndDropResult(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (resultJson != null) {
|
|
||||||
return resultJson;
|
|
||||||
} else {
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void CheckAndDropResult(RegorusFFI.RegorusResult result)
|
|
||||||
{
|
|
||||||
if (result.status != RegorusFFI.RegorusStatus.RegorusStatusOk) {
|
|
||||||
unsafe {
|
|
||||||
var message = System.Runtime.InteropServices.Marshal.PtrToStringAnsi((IntPtr)result.error_message);
|
|
||||||
var ex = new Exception(message);
|
|
||||||
RegorusFFI.API.regorus_result_drop(result);
|
|
||||||
throw ex;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
RegorusFFI.API.regorus_result_drop(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,22 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8" ?>
|
|
||||||
<package>
|
|
||||||
<metadata>
|
|
||||||
<id>RegorusCsharp-Lib-x64</id>
|
|
||||||
<version>0.2.1</version>
|
|
||||||
<title>RegorusCsharp-Lib-x64</title>
|
|
||||||
<authors>yangjie@microsoft.com</authors>
|
|
||||||
<owners>yangjie@microsoft.com</owners>
|
|
||||||
<projectUrl>https://www.microsoft.com</projectUrl>
|
|
||||||
<requireLicenseAcceptance>false</requireLicenseAcceptance>
|
|
||||||
<description>Regorus C# library for x64</description>
|
|
||||||
<releaseNotes>remove Regorus.cs from Nuget</releaseNotes>
|
|
||||||
<copyright>Copyright (C) Microsoft Corp</copyright>
|
|
||||||
<summary></summary>
|
|
||||||
</metadata>
|
|
||||||
<files>
|
|
||||||
<file src="RegorusFFI.g.cs" target="RegorusFFI.g.cs"/>
|
|
||||||
<file src="regorus_ffi.dll" target="lib\regorusc.dll" />
|
|
||||||
<file src="README" target="README" />
|
|
||||||
<file src="..\..\..\LICENSE" target="LICENSE" />
|
|
||||||
</files>
|
|
||||||
</package>
|
|
||||||
@@ -1,24 +0,0 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk" InitialTargets="BuildRegorusFFI">
|
|
||||||
|
|
||||||
<Target Name="BuildRegorusFFI">
|
|
||||||
<Exec Command="cargo build -r --manifest-path ../../ffi/Cargo.toml" />
|
|
||||||
<Copy SourceFiles="../../ffi/RegorusFFI.g.cs" DestinationFolder="." />
|
|
||||||
<ItemGroup>
|
|
||||||
<RegorusDylib Include="..\..\..\target\release\*regorus_ffi*" />
|
|
||||||
</ItemGroup>
|
|
||||||
<Copy SourceFiles="@(RegorusDylib)" DestinationFolder="." />
|
|
||||||
</Target>
|
|
||||||
|
|
||||||
|
|
||||||
<PropertyGroup>
|
|
||||||
<OutputType>Exe</OutputType>
|
|
||||||
<TargetFramework>net40</TargetFramework>
|
|
||||||
<RootNamespace>regorus_test</RootNamespace>
|
|
||||||
<StartupObject>regoregorus_test.Program</StartupObject>
|
|
||||||
<ImplicitUsings>enable</ImplicitUsings>
|
|
||||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
|
||||||
</PropertyGroup>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
</Project>
|
|
||||||
@@ -1,220 +0,0 @@
|
|||||||
using System.Text;
|
|
||||||
|
|
||||||
namespace Regorus
|
|
||||||
{
|
|
||||||
public class Exception : System.Exception
|
|
||||||
{
|
|
||||||
public Exception(string? message) : base(message) {}
|
|
||||||
}
|
|
||||||
|
|
||||||
public class Engine : ICloneable
|
|
||||||
{
|
|
||||||
unsafe private RegorusFFI.RegorusEngine* E;
|
|
||||||
public Engine()
|
|
||||||
{
|
|
||||||
unsafe
|
|
||||||
{
|
|
||||||
E = RegorusFFI.API.regorus_engine_new();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public object Clone()
|
|
||||||
{
|
|
||||||
var clone = (Engine)this.MemberwiseClone();
|
|
||||||
unsafe
|
|
||||||
{
|
|
||||||
clone.E = RegorusFFI.API.regorus_engine_clone(E);
|
|
||||||
}
|
|
||||||
return clone;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public string AddPolicy(string path, string rego)
|
|
||||||
{
|
|
||||||
var pathBytes = Encoding.UTF8.GetBytes(path);
|
|
||||||
var regoBytes = Encoding.UTF8.GetBytes(rego);
|
|
||||||
|
|
||||||
unsafe
|
|
||||||
{
|
|
||||||
fixed (byte* pathPtr = pathBytes)
|
|
||||||
{
|
|
||||||
fixed(byte* regoPtr = regoBytes)
|
|
||||||
{
|
|
||||||
return CheckAndDropResult(RegorusFFI.API.regorus_engine_add_policy(E, pathPtr, regoPtr));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public string AddPolicyFromFile(string path)
|
|
||||||
{
|
|
||||||
var pathBytes = Encoding.UTF8.GetBytes(path);
|
|
||||||
|
|
||||||
unsafe
|
|
||||||
{
|
|
||||||
fixed (byte* pathPtr = pathBytes)
|
|
||||||
{
|
|
||||||
return CheckAndDropResult(RegorusFFI.API.regorus_engine_add_policy_from_file(E, pathPtr));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void AddDataJson(string data)
|
|
||||||
{
|
|
||||||
var dataBytes = Encoding.UTF8.GetBytes(data);
|
|
||||||
|
|
||||||
unsafe
|
|
||||||
{
|
|
||||||
fixed (byte* dataPtr = dataBytes)
|
|
||||||
{
|
|
||||||
CheckAndDropResult(RegorusFFI.API.regorus_engine_add_data_json(E, dataPtr));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void AddDataFromJsonFile(string path)
|
|
||||||
{
|
|
||||||
var pathBytes = Encoding.UTF8.GetBytes(path);
|
|
||||||
|
|
||||||
unsafe
|
|
||||||
{
|
|
||||||
fixed (byte* pathPtr = pathBytes)
|
|
||||||
{
|
|
||||||
CheckAndDropResult(RegorusFFI.API.regorus_engine_add_data_from_json_file(E, pathPtr));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void SetInputJson(string input)
|
|
||||||
{
|
|
||||||
var inputBytes = Encoding.UTF8.GetBytes(input);
|
|
||||||
|
|
||||||
unsafe
|
|
||||||
{
|
|
||||||
fixed (byte* inputPtr = inputBytes)
|
|
||||||
{
|
|
||||||
CheckAndDropResult(RegorusFFI.API.regorus_engine_set_input_json(E, inputPtr));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void SetInputFromJsonFile(string path)
|
|
||||||
{
|
|
||||||
var pathBytes = Encoding.UTF8.GetBytes(path);
|
|
||||||
|
|
||||||
unsafe
|
|
||||||
{
|
|
||||||
fixed (byte* pathPtr = pathBytes)
|
|
||||||
{
|
|
||||||
CheckAndDropResult(RegorusFFI.API.regorus_engine_set_input_from_json_file(E, pathPtr));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public string EvalQuery(string query)
|
|
||||||
{
|
|
||||||
var queryBytes = Encoding.UTF8.GetBytes(query);
|
|
||||||
|
|
||||||
unsafe
|
|
||||||
{
|
|
||||||
fixed (byte* queryPtr = queryBytes)
|
|
||||||
{
|
|
||||||
return CheckAndDropResult(RegorusFFI.API.regorus_engine_eval_query(E, queryPtr));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public string EvalRule(string rule)
|
|
||||||
{
|
|
||||||
var ruleBytes = Encoding.UTF8.GetBytes(rule);
|
|
||||||
|
|
||||||
unsafe
|
|
||||||
{
|
|
||||||
fixed (byte* rulePtr = ruleBytes)
|
|
||||||
{
|
|
||||||
return CheckAndDropResult(RegorusFFI.API.regorus_engine_eval_query(E, rulePtr));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void SetEnableCoverage(bool enable)
|
|
||||||
{
|
|
||||||
unsafe
|
|
||||||
{
|
|
||||||
CheckAndDropResult(RegorusFFI.API.regorus_engine_set_enable_coverage(E, enable));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void ClearCoverageData()
|
|
||||||
{
|
|
||||||
unsafe
|
|
||||||
{
|
|
||||||
CheckAndDropResult(RegorusFFI.API.regorus_engine_clear_coverage_data(E));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public string GetCoverageReport()
|
|
||||||
{
|
|
||||||
unsafe
|
|
||||||
{
|
|
||||||
return CheckAndDropResult(RegorusFFI.API.regorus_engine_get_coverage_report(E));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public string GetCoverageReportPretty()
|
|
||||||
{
|
|
||||||
unsafe
|
|
||||||
{
|
|
||||||
return CheckAndDropResult(RegorusFFI.API.regorus_engine_get_coverage_report_pretty(E));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void SetGatherPrints(bool enable)
|
|
||||||
{
|
|
||||||
unsafe
|
|
||||||
{
|
|
||||||
CheckAndDropResult(RegorusFFI.API.regorus_engine_set_gather_prints(E, enable));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public string TakePrints()
|
|
||||||
{
|
|
||||||
unsafe
|
|
||||||
{
|
|
||||||
return CheckAndDropResult(RegorusFFI.API.regorus_engine_take_prints(E));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
~Engine()
|
|
||||||
{
|
|
||||||
unsafe
|
|
||||||
{
|
|
||||||
RegorusFFI.API.regorus_engine_drop(E);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
string CheckAndDropResult(RegorusFFI.RegorusResult result)
|
|
||||||
{
|
|
||||||
if (result.status != RegorusFFI.RegorusStatus.RegorusStatusOk) {
|
|
||||||
unsafe {
|
|
||||||
var message = System.Runtime.InteropServices.Marshal.PtrToStringUTF8((IntPtr)result.error_message);
|
|
||||||
var ex = new Exception(message);
|
|
||||||
RegorusFFI.API.regorus_result_drop(result);
|
|
||||||
throw ex;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var resultString = "";
|
|
||||||
unsafe
|
|
||||||
{
|
|
||||||
if (result.output is not null) {
|
|
||||||
resultString = System.Runtime.InteropServices.Marshal.PtrToStringUTF8((IntPtr)result.output);
|
|
||||||
}
|
|
||||||
RegorusFFI.API.regorus_result_drop(result);
|
|
||||||
}
|
|
||||||
return resultString;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,24 +0,0 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk" InitialTargets="BuildRegorusFFI">
|
|
||||||
|
|
||||||
<Target Name="BuildRegorusFFI">
|
|
||||||
<Exec Command="cargo build -r --manifest-path ../../ffi/Cargo.toml" />
|
|
||||||
<Copy SourceFiles="../../ffi/RegorusFFI.g.cs" DestinationFolder="." />
|
|
||||||
<ItemGroup>
|
|
||||||
<RegorusDylib Include="..\..\..\target\release\*regorus_ffi*" />
|
|
||||||
</ItemGroup>
|
|
||||||
<Copy SourceFiles="@(RegorusDylib)" DestinationFolder="." />
|
|
||||||
</Target>
|
|
||||||
|
|
||||||
|
|
||||||
<PropertyGroup>
|
|
||||||
<OutputType>Exe</OutputType>
|
|
||||||
<TargetFramework>net8.0</TargetFramework>
|
|
||||||
<RootNamespace>regorus_test</RootNamespace>
|
|
||||||
<ImplicitUsings>enable</ImplicitUsings>
|
|
||||||
<Nullable>enable</Nullable>
|
|
||||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
|
||||||
</PropertyGroup>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
</Project>
|
|
||||||
1771
bindings/ffi/Cargo.lock
generated
Normal file
1771
bindings/ffi/Cargo.lock
generated
Normal file
File diff suppressed because it is too large
Load Diff
@@ -1,3 +1,5 @@
|
|||||||
|
[workspace]
|
||||||
|
|
||||||
[package]
|
[package]
|
||||||
name = "regorus-ffi"
|
name = "regorus-ffi"
|
||||||
version = "0.2.2"
|
version = "0.2.2"
|
||||||
@@ -10,7 +12,7 @@ crate-type = ["cdylib", "staticlib"]
|
|||||||
[dependencies]
|
[dependencies]
|
||||||
anyhow = "1.0"
|
anyhow = "1.0"
|
||||||
regorus = { path = "../..", default-features = false }
|
regorus = { path = "../..", default-features = false }
|
||||||
serde_json = "1.0.113"
|
serde_json = "1.0.140"
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
default = ["ast", "std", "coverage", "regorus/arc", "regorus/full-opa"]
|
default = ["ast", "std", "coverage", "regorus/arc", "regorus/full-opa"]
|
||||||
@@ -20,5 +22,5 @@ coverage = ["regorus/coverage"]
|
|||||||
custom_allocator = []
|
custom_allocator = []
|
||||||
|
|
||||||
[build-dependencies]
|
[build-dependencies]
|
||||||
cbindgen = "0.26.0"
|
cbindgen = "0.28.0"
|
||||||
csbindgen = "=1.9.0"
|
csbindgen = "=1.9.3"
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ fn main() {
|
|||||||
.input_extern_file("src/lib.rs")
|
.input_extern_file("src/lib.rs")
|
||||||
.csharp_dll_name("regorus_ffi")
|
.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();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -222,7 +222,7 @@ pub extern "C" fn regorus_engine_add_data_from_json_file(
|
|||||||
|
|
||||||
/// 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<()> {
|
||||||
@@ -233,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(
|
||||||
@@ -264,7 +264,7 @@ pub extern "C" fn regorus_engine_set_input_from_json_file(
|
|||||||
|
|
||||||
/// 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(
|
||||||
@@ -289,7 +289,7 @@ pub extern "C" fn regorus_engine_eval_query(
|
|||||||
|
|
||||||
/// Evaluate specified rule.
|
/// Evaluate specified rule.
|
||||||
///
|
///
|
||||||
/// See https://docs.rs/regorus/0.1.0-alpha.2/regorus/struct.Engine.html#method.eval_rule
|
/// See https://docs.rs/regorus/latest/regorus/struct.Engine.html#method.eval_rule
|
||||||
/// * `rule`: Path to the rule.
|
/// * `rule`: Path to the rule.
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub extern "C" fn regorus_engine_eval_rule(
|
pub extern "C" fn regorus_engine_eval_rule(
|
||||||
@@ -314,7 +314,7 @@ pub extern "C" fn regorus_engine_eval_rule(
|
|||||||
|
|
||||||
/// Enable/disable coverage.
|
/// Enable/disable coverage.
|
||||||
///
|
///
|
||||||
/// See https://docs.rs/regorus/0.1.0-alpha.2/regorus/struct.Engine.html#method.set_enable_coverage
|
/// See https://docs.rs/regorus/latest/regorus/struct.Engine.html#method.set_enable_coverage
|
||||||
/// * `enable`: Whether to enable or disable coverage.
|
/// * `enable`: Whether to enable or disable coverage.
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
#[cfg(feature = "coverage")]
|
#[cfg(feature = "coverage")]
|
||||||
@@ -330,7 +330,7 @@ pub extern "C" fn regorus_engine_set_enable_coverage(
|
|||||||
|
|
||||||
/// Get coverage report.
|
/// Get coverage report.
|
||||||
///
|
///
|
||||||
/// See https://docs.rs/regorus/0.1.0-alpha.2/regorus/struct.Engine.html#method.get_coverage_report
|
/// See https://docs.rs/regorus/latest/regorus/struct.Engine.html#method.get_coverage_report
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
#[cfg(feature = "coverage")]
|
#[cfg(feature = "coverage")]
|
||||||
pub extern "C" fn regorus_engine_get_coverage_report(engine: *mut RegorusEngine) -> RegorusResult {
|
pub extern "C" fn regorus_engine_get_coverage_report(engine: *mut RegorusEngine) -> RegorusResult {
|
||||||
@@ -375,7 +375,7 @@ pub extern "C" fn regorus_engine_get_coverage_report_pretty(
|
|||||||
|
|
||||||
/// Clear coverage data.
|
/// Clear coverage data.
|
||||||
///
|
///
|
||||||
/// See https://docs.rs/regorus/0.1.0-alpha.2/regorus/struct.Engine.html#method.clear_coverage_data
|
/// See https://docs.rs/regorus/latest/regorus/struct.Engine.html#method.clear_coverage_data
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
#[cfg(feature = "coverage")]
|
#[cfg(feature = "coverage")]
|
||||||
pub extern "C" fn regorus_engine_clear_coverage_data(engine: *mut RegorusEngine) -> RegorusResult {
|
pub extern "C" fn regorus_engine_clear_coverage_data(engine: *mut RegorusEngine) -> RegorusResult {
|
||||||
@@ -387,7 +387,7 @@ pub extern "C" fn regorus_engine_clear_coverage_data(engine: *mut RegorusEngine)
|
|||||||
|
|
||||||
/// Whether to gather output of print statements.
|
/// Whether to gather output of print statements.
|
||||||
///
|
///
|
||||||
/// See https://docs.rs/regorus/0.1.0-alpha.2/regorus/struct.Engine.html#method.set_gather_prints
|
/// See https://docs.rs/regorus/latest/regorus/struct.Engine.html#method.set_gather_prints
|
||||||
/// * `enable`: Whether to enable or disable gathering print statements.
|
/// * `enable`: Whether to enable or disable gathering print statements.
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub extern "C" fn regorus_engine_set_gather_prints(
|
pub extern "C" fn regorus_engine_set_gather_prints(
|
||||||
@@ -402,7 +402,7 @@ pub extern "C" fn regorus_engine_set_gather_prints(
|
|||||||
|
|
||||||
/// Take all the gathered print statements.
|
/// Take all the gathered print statements.
|
||||||
///
|
///
|
||||||
/// See https://docs.rs/regorus/0.1.0-alpha.2/regorus/struct.Engine.html#method.take_prints
|
/// See https://docs.rs/regorus/latest/regorus/struct.Engine.html#method.take_prints
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub extern "C" fn regorus_engine_take_prints(engine: *mut RegorusEngine) -> RegorusResult {
|
pub extern "C" fn regorus_engine_take_prints(engine: *mut RegorusEngine) -> RegorusResult {
|
||||||
let output = || -> Result<String> {
|
let output = || -> Result<String> {
|
||||||
@@ -437,6 +437,28 @@ pub extern "C" fn regorus_engine_get_ast_as_json(engine: *mut RegorusEngine) ->
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Enable/disable rego v1.
|
||||||
|
///
|
||||||
|
/// See https://docs.rs/regorus/latest/regorus/struct.Engine.html#method.set_rego_v0
|
||||||
|
#[no_mangle]
|
||||||
|
pub extern "C" fn regorus_engine_set_rego_v0(
|
||||||
|
engine: *mut RegorusEngine,
|
||||||
|
enable: bool,
|
||||||
|
) -> RegorusResult {
|
||||||
|
let output = || -> Result<()> {
|
||||||
|
to_ref(&engine)?.engine.set_rego_v0(enable);
|
||||||
|
Ok(())
|
||||||
|
}();
|
||||||
|
match output {
|
||||||
|
Ok(()) => RegorusResult {
|
||||||
|
status: RegorusStatus::RegorusStatusOk,
|
||||||
|
output: std::ptr::null_mut(),
|
||||||
|
error_message: std::ptr::null_mut(),
|
||||||
|
},
|
||||||
|
Err(e) => to_regorus_result(Err(e)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(feature = "custom_allocator")]
|
#[cfg(feature = "custom_allocator")]
|
||||||
extern "C" {
|
extern "C" {
|
||||||
fn regorus_aligned_alloc(alignment: usize, size: usize) -> *mut u8;
|
fn regorus_aligned_alloc(alignment: usize, size: usize) -> *mut u8;
|
||||||
|
|||||||
@@ -16,8 +16,11 @@ func main() {
|
|||||||
// Create new engine
|
// Create new engine
|
||||||
engine := regorus.NewEngine()
|
engine := regorus.NewEngine()
|
||||||
defer engine.Close()
|
defer engine.Close()
|
||||||
|
|
||||||
|
engine.SetRegoV0(true)
|
||||||
elapsed1 := time.Since(t)
|
elapsed1 := time.Since(t)
|
||||||
|
|
||||||
|
|
||||||
t = time.Now()
|
t = time.Now()
|
||||||
// Add policies and data.
|
// Add policies and data.
|
||||||
policies := []string{
|
policies := []string{
|
||||||
|
|||||||
@@ -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,6 +28,17 @@ func (e *Engine) Clone() *Engine {
|
|||||||
return c
|
return c
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (e *Engine) SetRegoV0(enable bool) error {
|
||||||
|
result := C.regorus_engine_set_rego_v0(e.e, C.bool(enable))
|
||||||
|
defer C.regorus_result_drop(result)
|
||||||
|
|
||||||
|
if result.status != C.RegorusStatusOk {
|
||||||
|
return fmt.Errorf("%s", C.GoString(result.error_message))
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func (e *Engine) AddPolicy(path string, rego string) (string, error) {
|
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))
|
||||||
@@ -73,7 +84,6 @@ func (e *Engine) GetPolicies() (string, error) {
|
|||||||
return C.GoString(result.output), nil
|
return C.GoString(result.output), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
func (e *Engine) AddDataJson(data string) error {
|
func (e *Engine) AddDataJson(data string) error {
|
||||||
data_c := C.CString(data)
|
data_c := C.CString(data)
|
||||||
defer C.free(unsafe.Pointer(data_c))
|
defer C.free(unsafe.Pointer(data_c))
|
||||||
|
|||||||
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.2.2"
|
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"
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ Afterwards, you can build native library for that target using:
|
|||||||
$ cargo build --release --target aarch64-apple-darwin
|
$ cargo build --release --target aarch64-apple-darwin
|
||||||
```
|
```
|
||||||
|
|
||||||
You will then have a native library at `../../target/aarch64-apple-darwin/release/libregorus_java.dylib` depending on your target.
|
You will then have a native library at `target/aarch64-apple-darwin/release/libregorus_java.dylib` depending on your target.
|
||||||
|
|
||||||
You then need to build Java bindings using:
|
You then need to build Java bindings using:
|
||||||
```bash
|
```bash
|
||||||
|
|||||||
@@ -4,39 +4,45 @@
|
|||||||
import com.microsoft.regorus.Engine;
|
import com.microsoft.regorus.Engine;
|
||||||
|
|
||||||
public class Test {
|
public class Test {
|
||||||
|
|
||||||
public static void main(String[] args) {
|
public static void main(String[] args) {
|
||||||
try (Engine engine = new Engine()) {
|
try (Engine engine = new Engine()) {
|
||||||
String pkg = engine.addPolicy(
|
String pkg = engine.addPolicy(
|
||||||
"hello.rego",
|
"hello.rego",
|
||||||
"package test\nx=1\nmessage = concat(\", \", [input.message, data.message])"
|
"package test\nx=1\nmessage = concat(\", \", [input.message, data.message])"
|
||||||
);
|
);
|
||||||
System.out.println("Loaded package " + pkg);
|
System.out.println("Loaded package " + pkg);
|
||||||
|
|
||||||
|
|
||||||
engine.addDataJson("{\"message\":\"World!\"}");
|
engine.addDataJson("{\"message\":\"World!\"}");
|
||||||
engine.setInputJson("{\"message\":\"Hello\"}");
|
engine.setInputJson("{\"message\":\"Hello\"}");
|
||||||
|
|
||||||
// Evaluate query.
|
// Evaluate query.
|
||||||
String resJson = engine.evalQuery("data.test.message");
|
String resJson = engine.evalQuery("data.test.message");
|
||||||
System.out.println(resJson);
|
System.out.println(resJson);
|
||||||
|
|
||||||
// Enable coverage.
|
// Enable coverage.
|
||||||
engine.setEnableCoverage(true);
|
engine.setEnableCoverage(true);
|
||||||
|
|
||||||
// Evaluate rule.
|
// Evaluate rule.
|
||||||
String valueJson = engine.evalRule("data.test.message");
|
String valueJson = engine.evalRule("data.test.message");
|
||||||
System.out.println(valueJson);
|
System.out.println(valueJson);
|
||||||
|
|
||||||
String coverageJson = engine.getCoverageReport();
|
String coverageJson = engine.getCoverageReport();
|
||||||
System.out.println(coverageJson);
|
System.out.println(coverageJson);
|
||||||
|
|
||||||
System.out.println(engine.getCoverageReportPretty());
|
System.out.println(engine.getCoverageReportPretty());
|
||||||
|
|
||||||
String packagesJson = engine.getPackages();
|
String packagesJson = engine.getPackages();
|
||||||
System.out.println(packagesJson);
|
System.out.println(packagesJson);
|
||||||
|
|
||||||
String policiesJson = engine.getPolicies();
|
String policiesJson = engine.getPolicies();
|
||||||
System.out.println(policiesJson);
|
System.out.println(policiesJson);
|
||||||
|
|
||||||
|
engine.setRegoV0(true);
|
||||||
|
engine.addPolicy(
|
||||||
|
"world.rego",
|
||||||
|
"package world\nx { true }"
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,6 +28,20 @@ pub extern "system" fn Java_com_microsoft_regorus_Engine_nativeClone(
|
|||||||
Box::into_raw(Box::new(c)) as jlong
|
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,
|
||||||
|
|||||||
@@ -8,10 +8,8 @@ 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.
|
||||||
@@ -23,6 +21,7 @@ public class Engine implements AutoCloseable, Cloneable {
|
|||||||
// 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 long nativeClone(long enginePtr);
|
private static native long nativeClone(long enginePtr);
|
||||||
|
private static native void nativeSetRegoV0(long enginePtr, boolean enable);
|
||||||
private static native String nativeAddPolicy(long enginePtr, String path, String rego);
|
private static native String nativeAddPolicy(long enginePtr, String path, String rego);
|
||||||
private static native String nativeAddPolicyFromFile(long enginePtr, String path);
|
private static native String nativeAddPolicyFromFile(long enginePtr, String path);
|
||||||
private static native String nativeGetPackages(long enginePtr);
|
private static native String nativeGetPackages(long enginePtr);
|
||||||
@@ -55,7 +54,7 @@ public class Engine implements AutoCloseable, Cloneable {
|
|||||||
|
|
||||||
|
|
||||||
Engine(long ptr) {
|
Engine(long ptr) {
|
||||||
enginePtr = ptr;
|
enginePtr = ptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -65,6 +64,16 @@ public class Engine implements AutoCloseable, Cloneable {
|
|||||||
return new Engine(nativeClone(enginePtr));
|
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.
|
||||||
*
|
*
|
||||||
|
|||||||
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.2.2"
|
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"
|
||||||
@@ -18,8 +20,8 @@ coverage = ["regorus/coverage"]
|
|||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
anyhow = "1.0"
|
anyhow = "1.0"
|
||||||
ordered-float = "4.2.0"
|
ordered-float = "5.0.0"
|
||||||
pyo3 = {version = "0.22.0", features = ["anyhow", "extension-module"] }
|
pyo3 = { version = "0.24.1", features = ["abi3-py310", "anyhow", "extension-module"] }
|
||||||
regorus = { path = "../..", default-features = false, features = ["arc"] }
|
regorus = { path = "../..", default-features = false, features = ["arc"] }
|
||||||
serde_json = "1.0.112"
|
serde_json = "1.0.140"
|
||||||
|
|
||||||
|
|||||||
@@ -13,4 +13,8 @@ classifiers = [
|
|||||||
dynamic = ["version"]
|
dynamic = ["version"]
|
||||||
|
|
||||||
[tool.maturin]
|
[tool.maturin]
|
||||||
|
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"]
|
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};
|
||||||
|
|
||||||
@@ -94,7 +95,7 @@ fn from(ob: &Bound<'_, 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)?);
|
||||||
@@ -108,49 +109,53 @@ fn from(ob: &Bound<'_, 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_bound(py);
|
let list = PyList::empty(py);
|
||||||
for v in std::mem::take(v.as_array_mut()?) {
|
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_bound(py)?;
|
let set = PySet::empty(py)?;
|
||||||
for v in std::mem::take(v.as_set_mut()?) {
|
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_bound(py);
|
let dict = PyDict::new(py);
|
||||||
for (k, v) in std::mem::take(v.as_object_mut()?) {
|
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]
|
||||||
@@ -163,6 +168,15 @@ impl Engine {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Turn on rego v0.
|
||||||
|
///
|
||||||
|
/// Regorus now defaults to v1.
|
||||||
|
///
|
||||||
|
/// * `enable`: Whether to enable/disable v0.
|
||||||
|
pub fn set_rego_v0(&mut self, enable: bool) {
|
||||||
|
self.engine.set_rego_v0(enable)
|
||||||
|
}
|
||||||
|
|
||||||
/// Add a policy
|
/// Add a policy
|
||||||
///
|
///
|
||||||
/// The policy is parsed into AST.
|
/// The policy is parsed into AST.
|
||||||
@@ -261,30 +275,30 @@ impl Engine {
|
|||||||
pub fn eval_query(&mut self, query: String, py: Python<'_>) -> Result<PyObject> {
|
pub fn eval_query(&mut self, query: String, py: Python<'_>) -> Result<PyObject> {
|
||||||
let results = self.engine.eval_query(query, false)?;
|
let results = self.engine.eval_query(query, false)?;
|
||||||
|
|
||||||
let rlist = PyList::empty_bound(py);
|
let rlist = PyList::empty(py);
|
||||||
for result in results.result.into_iter() {
|
for result in results.result.into_iter() {
|
||||||
let rdict = PyDict::new_bound(py);
|
let rdict = PyDict::new(py);
|
||||||
|
|
||||||
let elist = PyList::empty_bound(py);
|
let elist = PyList::empty(py);
|
||||||
for expr in result.expressions.into_iter() {
|
for expr in result.expressions.into_iter() {
|
||||||
let edict = PyDict::new_bound(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_bound(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_bound(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())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -6,6 +6,8 @@ import regorus
|
|||||||
# Create engine
|
# Create engine
|
||||||
engine = regorus.Engine()
|
engine = regorus.Engine()
|
||||||
|
|
||||||
|
engine.set_rego_v0(True)
|
||||||
|
|
||||||
# Load policies
|
# Load policies
|
||||||
pkg = engine.add_policy_from_file('../../tests/aci/framework.rego')
|
pkg = engine.add_policy_from_file('../../tests/aci/framework.rego')
|
||||||
print(' Loaded package %s' % pkg)
|
print(' Loaded package %s' % pkg)
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ require:
|
|||||||
- rubocop-rake
|
- rubocop-rake
|
||||||
|
|
||||||
AllCops:
|
AllCops:
|
||||||
TargetRubyVersion: 3.0
|
TargetRubyVersion: 3.4
|
||||||
NewCops: enable
|
NewCops: enable
|
||||||
|
|
||||||
Layout/LineLength:
|
Layout/LineLength:
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
ruby 3.3.1
|
ruby 3.4.2
|
||||||
|
|||||||
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
@@ -7,10 +7,10 @@ gemspec
|
|||||||
|
|
||||||
# These gems are required for local development and testing,
|
# These gems are required for local development and testing,
|
||||||
# but won't be included in the published gem
|
# but won't be included in the published gem
|
||||||
gem "minitest", "~> 5.23"
|
gem "minitest", "~> 5.25"
|
||||||
gem "rake", "~> 13.2"
|
gem "rake", "~> 13.2"
|
||||||
gem "rake-compiler"
|
gem "rake-compiler", "~> 1.2"
|
||||||
gem "rake-compiler-dock"
|
gem "rake-compiler-dock", "~> 1.9"
|
||||||
gem "rubocop", "~> 1.64", require: false
|
gem "rubocop", "~> 1.73", require: false
|
||||||
gem "rubocop-minitest", require: false
|
gem "rubocop-minitest", "~> 0.37.1", require: false
|
||||||
gem "rubocop-rake", require: false
|
gem "rubocop-rake", "~> 0.7.1", require: false
|
||||||
|
|||||||
@@ -1,65 +1,68 @@
|
|||||||
PATH
|
PATH
|
||||||
remote: .
|
remote: .
|
||||||
specs:
|
specs:
|
||||||
regorusrb (0.2.1)
|
regorusrb (0.3.0)
|
||||||
rb_sys (~> 0.9.97)
|
rb_sys (~> 0.9.111)
|
||||||
|
|
||||||
GEM
|
GEM
|
||||||
remote: https://rubygems.org/
|
remote: https://rubygems.org/
|
||||||
specs:
|
specs:
|
||||||
ast (2.4.2)
|
ast (2.4.2)
|
||||||
json (2.7.2)
|
json (2.10.2)
|
||||||
language_server-protocol (3.17.0.3)
|
language_server-protocol (3.17.0.4)
|
||||||
minitest (5.24.1)
|
lint_roller (1.1.0)
|
||||||
parallel (1.25.1)
|
minitest (5.25.4)
|
||||||
parser (3.3.4.0)
|
parallel (1.26.3)
|
||||||
|
parser (3.3.7.1)
|
||||||
ast (~> 2.4.1)
|
ast (~> 2.4.1)
|
||||||
racc
|
racc
|
||||||
racc (1.8.0)
|
racc (1.8.1)
|
||||||
rainbow (3.1.1)
|
rainbow (3.1.1)
|
||||||
rake (13.2.1)
|
rake (13.2.1)
|
||||||
rake-compiler (1.2.7)
|
rake-compiler (1.2.9)
|
||||||
rake
|
rake
|
||||||
rake-compiler-dock (1.5.1)
|
rake-compiler-dock (1.9.1)
|
||||||
rb_sys (0.9.99)
|
rb_sys (0.9.111)
|
||||||
regexp_parser (2.9.2)
|
rake-compiler-dock (= 1.9.1)
|
||||||
rexml (3.3.2)
|
regexp_parser (2.10.0)
|
||||||
strscan
|
rubocop (1.73.2)
|
||||||
rubocop (1.65.0)
|
|
||||||
json (~> 2.3)
|
json (~> 2.3)
|
||||||
language_server-protocol (>= 3.17.0)
|
language_server-protocol (~> 3.17.0.2)
|
||||||
|
lint_roller (~> 1.1.0)
|
||||||
parallel (~> 1.10)
|
parallel (~> 1.10)
|
||||||
parser (>= 3.3.0.2)
|
parser (>= 3.3.0.2)
|
||||||
rainbow (>= 2.2.2, < 4.0)
|
rainbow (>= 2.2.2, < 4.0)
|
||||||
regexp_parser (>= 2.4, < 3.0)
|
regexp_parser (>= 2.9.3, < 3.0)
|
||||||
rexml (>= 3.2.5, < 4.0)
|
rubocop-ast (>= 1.38.0, < 2.0)
|
||||||
rubocop-ast (>= 1.31.1, < 2.0)
|
|
||||||
ruby-progressbar (~> 1.7)
|
ruby-progressbar (~> 1.7)
|
||||||
unicode-display_width (>= 2.4.0, < 3.0)
|
unicode-display_width (>= 2.4.0, < 4.0)
|
||||||
rubocop-ast (1.31.3)
|
rubocop-ast (1.38.1)
|
||||||
parser (>= 3.3.1.0)
|
parser (>= 3.3.1.0)
|
||||||
rubocop-minitest (0.35.1)
|
rubocop-minitest (0.37.1)
|
||||||
rubocop (>= 1.61, < 2.0)
|
lint_roller (~> 1.1)
|
||||||
rubocop-ast (>= 1.31.1, < 2.0)
|
rubocop (>= 1.72.1, < 2.0)
|
||||||
rubocop-rake (0.6.0)
|
rubocop-ast (>= 1.38.0, < 2.0)
|
||||||
rubocop (~> 1.0)
|
rubocop-rake (0.7.1)
|
||||||
|
lint_roller (~> 1.1)
|
||||||
|
rubocop (>= 1.72.1)
|
||||||
ruby-progressbar (1.13.0)
|
ruby-progressbar (1.13.0)
|
||||||
strscan (3.1.0)
|
unicode-display_width (3.1.4)
|
||||||
unicode-display_width (2.5.0)
|
unicode-emoji (~> 4.0, >= 4.0.4)
|
||||||
|
unicode-emoji (4.0.4)
|
||||||
|
|
||||||
PLATFORMS
|
PLATFORMS
|
||||||
ruby
|
ruby
|
||||||
x86_64-linux
|
x86_64-linux
|
||||||
|
|
||||||
DEPENDENCIES
|
DEPENDENCIES
|
||||||
minitest (~> 5.23)
|
minitest (~> 5.25)
|
||||||
rake (~> 13.2)
|
rake (~> 13.2)
|
||||||
rake-compiler
|
rake-compiler (~> 1.2)
|
||||||
rake-compiler-dock
|
rake-compiler-dock (~> 1.9)
|
||||||
regorusrb!
|
regorusrb!
|
||||||
rubocop (~> 1.64)
|
rubocop (~> 1.73)
|
||||||
rubocop-minitest
|
rubocop-minitest (~> 0.37.1)
|
||||||
rubocop-rake
|
rubocop-rake (~> 0.7.1)
|
||||||
|
|
||||||
BUNDLED WITH
|
BUNDLED WITH
|
||||||
2.5.13
|
2.6.5
|
||||||
|
|||||||
@@ -43,6 +43,9 @@ require "regorus"
|
|||||||
|
|
||||||
engine = Regorus::Engine.new
|
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/framework.rego')
|
||||||
engine.add_policy_from_file('../../tests/aci/api.rego')
|
engine.add_policy_from_file('../../tests/aci/api.rego')
|
||||||
engine.add_policy_from_file('../../tests/aci/policy.rego')
|
engine.add_policy_from_file('../../tests/aci/policy.rego')
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "regorusrb"
|
name = "regorusrb"
|
||||||
version = "0.2.2"
|
version = "0.3.0"
|
||||||
edition = "2021"
|
edition = "2024"
|
||||||
description = "Ruby bindings for Regorus - a fast, lightweight Rego interpreter written in Rust"
|
description = "Ruby bindings for Regorus - a fast, lightweight Rego interpreter written in Rust"
|
||||||
publish = false
|
publish = false
|
||||||
|
|
||||||
@@ -15,7 +15,7 @@ ast = ["regorus/ast"]
|
|||||||
coverage = ["regorus/coverage"]
|
coverage = ["regorus/coverage"]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
magnus = { version = "0.6.4" }
|
magnus = { version = "0.7.1" }
|
||||||
regorus = { path = "../../../..", default-features = false, features = ["arc"] }
|
regorus = { path = "../../../..", default-features = false, features = ["arc"] }
|
||||||
serde_json = "1.0.117"
|
serde_json = "1.0.140"
|
||||||
serde_magnus = "0.8.1"
|
serde_magnus = "0.9.0"
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
use magnus::{exception::runtime_error, method, module, prelude::*, Error, Ruby};
|
use magnus::{Error, Ruby, exception::runtime_error, method, module, prelude::*};
|
||||||
use regorus::Engine as RegorusEngine;
|
use regorus::Engine as RegorusEngine;
|
||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
use std::cmp::Ordering;
|
use std::cmp::Ordering;
|
||||||
@@ -36,6 +36,11 @@ impl Engine {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn set_rego_v0(&self, enable: bool) -> Result<(), Error> {
|
||||||
|
self.engine.borrow_mut().set_rego_v0(enable);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
fn add_policy(&self, path: String, rego: String) -> Result<String, Error> {
|
fn add_policy(&self, path: String, rego: String) -> Result<String, Error> {
|
||||||
self.engine
|
self.engine
|
||||||
.borrow_mut()
|
.borrow_mut()
|
||||||
@@ -297,6 +302,9 @@ fn init(ruby: &Ruby) -> Result<(), Error> {
|
|||||||
// defines <, <=, >, >=, and == based on <=>
|
// defines <, <=, >, >=, and == based on <=>
|
||||||
engine_class.include_module(module::comparable())?;
|
engine_class.include_module(module::comparable())?;
|
||||||
|
|
||||||
|
// rego language configuration
|
||||||
|
engine_class.define_method("set_rego_v0", method!(Engine::set_rego_v0, 1))?;
|
||||||
|
|
||||||
// policy operations
|
// policy operations
|
||||||
engine_class.define_method("add_policy", method!(Engine::add_policy, 2))?;
|
engine_class.define_method("add_policy", method!(Engine::add_policy, 2))?;
|
||||||
engine_class.define_method(
|
engine_class.define_method(
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
# frozen_string_literal: true
|
# frozen_string_literal: true
|
||||||
|
|
||||||
module Regorus
|
module Regorus
|
||||||
VERSION = "0.2.1"
|
VERSION = "0.3.0"
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -10,8 +10,8 @@ Gem::Specification.new do |spec|
|
|||||||
spec.summary = "Ruby bindings for Regorus - a fast, lightweight Rego interpreter written in Rust"
|
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.homepage = "https://github.com/microsoft/regorus/blob/main/bindings/ruby"
|
||||||
spec.license = "MIT"
|
spec.license = "MIT"
|
||||||
spec.required_ruby_version = ">= 3.0.0"
|
spec.required_ruby_version = ">= 3.4.2"
|
||||||
spec.required_rubygems_version = ">= 3.3.11"
|
spec.required_rubygems_version = ">= 3.6.5"
|
||||||
|
|
||||||
spec.metadata["allowed_push_host"] = "TODO: Set to your gem server 'https://example.com'"
|
spec.metadata["allowed_push_host"] = "TODO: Set to your gem server 'https://example.com'"
|
||||||
|
|
||||||
@@ -26,5 +26,5 @@ Gem::Specification.new do |spec|
|
|||||||
spec.executables = spec.files.grep(%r{\Aexe/}) { |f| File.basename(f) }
|
spec.executables = spec.files.grep(%r{\Aexe/}) { |f| File.basename(f) }
|
||||||
spec.require_paths = ["lib"]
|
spec.require_paths = ["lib"]
|
||||||
spec.extensions = ["ext/regorusrb/extconf.rb"]
|
spec.extensions = ["ext/regorusrb/extconf.rb"]
|
||||||
spec.add_dependency "rb_sys", "~> 0.9.97"
|
spec.add_dependency "rb_sys", "~> 0.9.111"
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -17,11 +17,11 @@ class TestRegorus < Minitest::Test
|
|||||||
def example_policy
|
def example_policy
|
||||||
<<~REGO
|
<<~REGO
|
||||||
package regorus_test
|
package regorus_test
|
||||||
is_manager {
|
is_manager if {
|
||||||
input.name == data.managers[_]
|
input.name == data.managers[_]
|
||||||
}
|
}
|
||||||
|
|
||||||
is_employee {
|
is_employee if {
|
||||||
input.name == data.employees[_]
|
input.name == data.employees[_]
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -29,11 +29,11 @@ class TestRegorus < Minitest::Test
|
|||||||
default is_manager_bool = false
|
default is_manager_bool = false
|
||||||
default is_employee_bool = false
|
default is_employee_bool = false
|
||||||
|
|
||||||
is_manager_bool {
|
is_manager_bool if {
|
||||||
is_manager
|
is_manager
|
||||||
}
|
}
|
||||||
|
|
||||||
is_employee_bool {
|
is_employee_bool if {
|
||||||
is_employee
|
is_employee
|
||||||
}
|
}
|
||||||
REGO
|
REGO
|
||||||
|
|||||||
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.2.2"
|
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"
|
||||||
@@ -17,8 +19,17 @@ coverage = ["regorus/coverage"]
|
|||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
regorus = { path = "../..", default-features = false, features = ["arc"] }
|
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)'] }
|
||||||
|
|||||||
@@ -45,6 +45,15 @@ impl Engine {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Turn on rego v0.
|
||||||
|
///
|
||||||
|
/// Regorus defaults to rego v1.
|
||||||
|
///
|
||||||
|
/// * `enable`: Whether to enable or disable rego v0.
|
||||||
|
pub fn setRegoV0(&mut self, enable: bool) {
|
||||||
|
self.engine.set_rego_v0(enable)
|
||||||
|
}
|
||||||
|
|
||||||
/// Add a policy
|
/// Add a policy
|
||||||
///
|
///
|
||||||
/// The policy is parsed into AST.
|
/// The policy is parsed into AST.
|
||||||
@@ -191,6 +200,7 @@ mod tests {
|
|||||||
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);
|
engine.setEnableCoverage(true);
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -33,6 +33,7 @@ fn add_policy_from_file(engine: &mut regorus::Engine, path: String) -> Result<St
|
|||||||
engine.add_policy(path.clone(), read_file(&path)?)
|
engine.add_policy(path.clone(), read_file(&path)?)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(clippy::too_many_arguments)]
|
||||||
fn rego_eval(
|
fn rego_eval(
|
||||||
bundles: &[String],
|
bundles: &[String],
|
||||||
files: &[String],
|
files: &[String],
|
||||||
@@ -41,6 +42,7 @@ fn rego_eval(
|
|||||||
enable_tracing: bool,
|
enable_tracing: bool,
|
||||||
non_strict: bool,
|
non_strict: bool,
|
||||||
#[cfg(feature = "coverage")] coverage: bool,
|
#[cfg(feature = "coverage")] coverage: bool,
|
||||||
|
v0: bool,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
// Create engine.
|
// Create engine.
|
||||||
let mut engine = regorus::Engine::new();
|
let mut engine = regorus::Engine::new();
|
||||||
@@ -50,6 +52,8 @@ fn rego_eval(
|
|||||||
#[cfg(feature = "coverage")]
|
#[cfg(feature = "coverage")]
|
||||||
engine.set_enable_coverage(coverage);
|
engine.set_enable_coverage(coverage);
|
||||||
|
|
||||||
|
engine.set_rego_v0(v0);
|
||||||
|
|
||||||
// Load files from given bundles.
|
// Load files from given bundles.
|
||||||
for dir in bundles.iter() {
|
for dir in bundles.iter() {
|
||||||
let entries =
|
let entries =
|
||||||
@@ -233,6 +237,10 @@ enum RegorusCommand {
|
|||||||
#[cfg(feature = "coverage")]
|
#[cfg(feature = "coverage")]
|
||||||
#[arg(long, short)]
|
#[arg(long, short)]
|
||||||
coverage: bool,
|
coverage: bool,
|
||||||
|
|
||||||
|
/// Turn on Rego language v0.
|
||||||
|
#[arg(long)]
|
||||||
|
v0: bool,
|
||||||
},
|
},
|
||||||
|
|
||||||
/// Tokenize a Rego policy.
|
/// Tokenize a Rego policy.
|
||||||
@@ -274,6 +282,7 @@ fn main() -> Result<()> {
|
|||||||
non_strict,
|
non_strict,
|
||||||
#[cfg(feature = "coverage")]
|
#[cfg(feature = "coverage")]
|
||||||
coverage,
|
coverage,
|
||||||
|
v0,
|
||||||
} => rego_eval(
|
} => rego_eval(
|
||||||
&bundles,
|
&bundles,
|
||||||
&data,
|
&data,
|
||||||
@@ -283,6 +292,7 @@ fn main() -> Result<()> {
|
|||||||
non_strict,
|
non_strict,
|
||||||
#[cfg(feature = "coverage")]
|
#[cfg(feature = "coverage")]
|
||||||
coverage,
|
coverage,
|
||||||
|
v0,
|
||||||
),
|
),
|
||||||
RegorusCommand::Lex { file, verbose } => rego_lex(file, verbose),
|
RegorusCommand::Lex { file, verbose } => rego_lex(file, verbose),
|
||||||
RegorusCommand::Parse { file } => rego_parse(file),
|
RegorusCommand::Parse { file } => rego_parse(file),
|
||||||
|
|||||||
@@ -2,22 +2,22 @@ package example
|
|||||||
|
|
||||||
default allow := false # unless otherwise defined, allow is false
|
default allow := false # unless otherwise defined, allow is false
|
||||||
|
|
||||||
allow := true { # allow is true if...
|
allow := true if { # allow is true if...
|
||||||
count(violation) == 0 # there are zero violations.
|
count(violation) == 0 # there are zero violations.
|
||||||
}
|
}
|
||||||
|
|
||||||
violation[server.id] { # a server is in the violation set if...
|
violation[server.id] if { # a server is in the violation set if...
|
||||||
some server
|
some server
|
||||||
public_server[server] # it exists in the 'public_server' set and...
|
public_server[server] # it exists in the 'public_server' set and...
|
||||||
server.protocols[_] == "http" # it contains the insecure "http" protocol.
|
server.protocols[_] == "http" # it contains the insecure "http" protocol.
|
||||||
}
|
}
|
||||||
|
|
||||||
violation[server.id] { # a server is in the violation set if...
|
violation[server.id] if { # a server is in the violation set if...
|
||||||
server := input.servers[_] # it exists in the input.servers collection and...
|
server := input.servers[_] # it exists in the input.servers collection and...
|
||||||
server.protocols[_] == "telnet" # it contains the "telnet" protocol.
|
server.protocols[_] == "telnet" # it contains the "telnet" protocol.
|
||||||
}
|
}
|
||||||
|
|
||||||
public_server[server] { # a server exists in the public_server set if...
|
public_server[server]if { # a server exists in the public_server set if...
|
||||||
some i, j
|
some i, j
|
||||||
server := input.servers[_] # it exists in the input.servers collection and...
|
server := input.servers[_] # it exists in the input.servers collection and...
|
||||||
server.ports[_] == input.ports[i].id # it references a port in the input.ports collection and...
|
server.ports[_] == input.ports[i].id # it references a port in the input.ports collection and...
|
||||||
|
|||||||
@@ -30,6 +30,11 @@ if [ -f Cargo.toml ]; then
|
|||||||
cargo test -r --test aci
|
cargo test -r --test aci
|
||||||
cargo test -r --test kata
|
cargo test -r --test kata
|
||||||
|
|
||||||
|
# Ensure that all tests pass with extensions
|
||||||
|
cargo test -r --features rego-extensions
|
||||||
|
cargo test -r --test aci --features rego-extensions
|
||||||
|
cargo test -r --test kata --features rego-extensions
|
||||||
|
|
||||||
# Ensure that OPA conformance tests don't regress.
|
# Ensure that OPA conformance tests don't regress.
|
||||||
cargo test -r --features opa-testutil,serde_json/arbitrary_precision --test opa -- $(tr '\n' ' ' < tests/opa.passing)
|
cargo test -r --features opa-testutil,serde_json/arbitrary_precision,rego-extensions --test opa -- $(tr '\n' ' ' < tests/opa.passing)
|
||||||
fi
|
fi
|
||||||
|
|||||||
13
src/ast.rs
13
src/ast.rs
@@ -10,8 +10,8 @@ use core::{cmp, fmt, ops::Deref};
|
|||||||
#[derive(Debug, PartialEq, Eq, Clone)]
|
#[derive(Debug, PartialEq, Eq, Clone)]
|
||||||
#[cfg_attr(feature = "ast", derive(serde::Serialize))]
|
#[cfg_attr(feature = "ast", derive(serde::Serialize))]
|
||||||
pub enum BinOp {
|
pub enum BinOp {
|
||||||
And,
|
Intersection,
|
||||||
Or,
|
Union,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Eq, Clone)]
|
#[derive(Debug, PartialEq, Eq, Clone)]
|
||||||
@@ -209,6 +209,13 @@ pub enum Expr {
|
|||||||
value: Ref<Expr>,
|
value: Ref<Expr>,
|
||||||
collection: Ref<Expr>,
|
collection: Ref<Expr>,
|
||||||
},
|
},
|
||||||
|
|
||||||
|
#[cfg(feature = "rego-extensions")]
|
||||||
|
OrExpr {
|
||||||
|
span: Span,
|
||||||
|
lhs: Ref<Expr>,
|
||||||
|
rhs: Ref<Expr>,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Expr {
|
impl Expr {
|
||||||
@@ -232,6 +239,8 @@ impl Expr {
|
|||||||
| ArithExpr { span, .. }
|
| ArithExpr { span, .. }
|
||||||
| AssignExpr { span, .. }
|
| AssignExpr { span, .. }
|
||||||
| Membership { span, .. } => span,
|
| Membership { span, .. } => span,
|
||||||
|
#[cfg(feature = "rego-extensions")]
|
||||||
|
OrExpr { span, .. } => span,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,18 +11,15 @@ use anyhow::{bail, Result};
|
|||||||
use constant_time_eq::constant_time_eq;
|
use constant_time_eq::constant_time_eq;
|
||||||
use hmac::{Hmac, Mac};
|
use hmac::{Hmac, Mac};
|
||||||
use md5::{Digest, Md5};
|
use md5::{Digest, Md5};
|
||||||
use sha1::Sha1;
|
|
||||||
use sha2::{Sha256, Sha512};
|
use sha2::{Sha256, Sha512};
|
||||||
|
|
||||||
pub fn register(m: &mut builtins::BuiltinsMap<&'static str, builtins::BuiltinFcn>) {
|
pub fn register(m: &mut builtins::BuiltinsMap<&'static str, builtins::BuiltinFcn>) {
|
||||||
m.insert("crypto.hmac.equal", (hmac_equal_fixed_time, 2));
|
m.insert("crypto.hmac.equal", (hmac_equal_fixed_time, 2));
|
||||||
m.insert("crypto.hmac.md5", (hmac_md5, 2));
|
m.insert("crypto.hmac.md5", (hmac_md5, 2));
|
||||||
m.insert("crypto.hmac.sha1", (hmac_sha1, 2));
|
|
||||||
m.insert("crypto.hmac.sha256", (hmac_sha256, 2));
|
m.insert("crypto.hmac.sha256", (hmac_sha256, 2));
|
||||||
m.insert("crypto.hmac.sha512", (hmac_sha512, 2));
|
m.insert("crypto.hmac.sha512", (hmac_sha512, 2));
|
||||||
|
|
||||||
m.insert("crypto.md5", (crypto_md5, 1));
|
m.insert("crypto.md5", (crypto_md5, 1));
|
||||||
m.insert("crypto.sha1", (crypto_sha1, 1));
|
|
||||||
m.insert("crypto.sha256", (crypto_sha256, 1));
|
m.insert("crypto.sha256", (crypto_sha256, 1));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -60,22 +57,6 @@ fn hmac_md5(span: &Span, params: &[Ref<Expr>], args: &[Value], _strict: bool) ->
|
|||||||
Ok(Value::String(hex::encode(result.into_bytes()).into()))
|
Ok(Value::String(hex::encode(result.into_bytes()).into()))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn hmac_sha1(span: &Span, params: &[Ref<Expr>], args: &[Value], _strict: bool) -> Result<Value> {
|
|
||||||
let name = "crypto.hmac.sha1";
|
|
||||||
ensure_args_count(span, name, params, args, 2)?;
|
|
||||||
|
|
||||||
let x = ensure_string(name, ¶ms[0], &args[0])?;
|
|
||||||
let key = ensure_string(name, ¶ms[1], &args[1])?;
|
|
||||||
|
|
||||||
let mut hmac = Hmac::<Sha1>::new_from_slice(key.as_bytes())
|
|
||||||
.or_else(|_| bail!(span.error("failed to create hmac instance")))?;
|
|
||||||
|
|
||||||
hmac.update(x.as_bytes());
|
|
||||||
let result = hmac.finalize();
|
|
||||||
|
|
||||||
Ok(Value::String(hex::encode(result.into_bytes()).into()))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn hmac_sha256(span: &Span, params: &[Ref<Expr>], args: &[Value], _strict: bool) -> Result<Value> {
|
fn hmac_sha256(span: &Span, params: &[Ref<Expr>], args: &[Value], _strict: bool) -> Result<Value> {
|
||||||
let name = "crypto.hmac.sha256";
|
let name = "crypto.hmac.sha256";
|
||||||
ensure_args_count(span, name, params, args, 2)?;
|
ensure_args_count(span, name, params, args, 2)?;
|
||||||
@@ -122,20 +103,6 @@ fn crypto_md5(span: &Span, params: &[Ref<Expr>], args: &[Value], _strict: bool)
|
|||||||
Ok(Value::String(hex::encode(result).into()))
|
Ok(Value::String(hex::encode(result).into()))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn crypto_sha1(span: &Span, params: &[Ref<Expr>], args: &[Value], _strict: bool) -> Result<Value> {
|
|
||||||
let name = "crypto.sha1";
|
|
||||||
ensure_args_count(span, name, params, args, 1)?;
|
|
||||||
|
|
||||||
let x = ensure_string(name, ¶ms[0], &args[0])?;
|
|
||||||
|
|
||||||
let mut h = Sha1::new();
|
|
||||||
|
|
||||||
h.update(x.as_bytes());
|
|
||||||
let result = h.finalize();
|
|
||||||
|
|
||||||
Ok(Value::String(hex::encode(result).into()))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn crypto_sha256(
|
fn crypto_sha256(
|
||||||
span: &Span,
|
span: &Span,
|
||||||
params: &[Ref<Expr>],
|
params: &[Ref<Expr>],
|
||||||
|
|||||||
@@ -224,7 +224,7 @@ fn urlquery_decode(
|
|||||||
let mut query_str = "".to_owned();
|
let mut query_str = "".to_owned();
|
||||||
for (k, v) in url.query_pairs() {
|
for (k, v) in url.query_pairs() {
|
||||||
query_str += &k;
|
query_str += &k;
|
||||||
if v != "" {
|
if !v.is_empty() {
|
||||||
query_str += "=";
|
query_str += "=";
|
||||||
query_str += &v;
|
query_str += &v;
|
||||||
}
|
}
|
||||||
@@ -337,11 +337,11 @@ fn yaml_is_valid(
|
|||||||
fn yaml_marshal(span: &Span, params: &[Ref<Expr>], args: &[Value], _strict: bool) -> Result<Value> {
|
fn yaml_marshal(span: &Span, params: &[Ref<Expr>], args: &[Value], _strict: bool) -> Result<Value> {
|
||||||
let name = "yaml.marshal";
|
let name = "yaml.marshal";
|
||||||
ensure_args_count(span, name, params, args, 1)?;
|
ensure_args_count(span, name, params, args, 1)?;
|
||||||
Ok(Value::String(
|
|
||||||
serde_yaml::to_string(&args[0])
|
let serialized = serde_yaml::to_string(&args[0])
|
||||||
.with_context(|| span.error("could not serialize to yaml"))?
|
.map_err(|err| span.error(&format!("could not serialize to yaml: {}", err)))?;
|
||||||
.into(),
|
|
||||||
))
|
Ok(Value::String(serialized.into()))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "yaml")]
|
#[cfg(feature = "yaml")]
|
||||||
|
|||||||
@@ -9,8 +9,7 @@ use crate::value::Value;
|
|||||||
use crate::*;
|
use crate::*;
|
||||||
|
|
||||||
use anyhow::{bail, Result};
|
use anyhow::{bail, Result};
|
||||||
//use glob::{Pattern, MatchOptions};
|
use globset::{GlobBuilder, GlobMatcher};
|
||||||
use wax::{Glob, Pattern};
|
|
||||||
|
|
||||||
pub fn register(m: &mut builtins::BuiltinsMap<&'static str, builtins::BuiltinFcn>) {
|
pub fn register(m: &mut builtins::BuiltinsMap<&'static str, builtins::BuiltinFcn>) {
|
||||||
m.insert("glob.match", (glob_match, 3));
|
m.insert("glob.match", (glob_match, 3));
|
||||||
@@ -50,8 +49,12 @@ fn make_delimiters_unix_style(s: &str, delimiters: &[char]) -> Result<String> {
|
|||||||
Ok(s)
|
Ok(s)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn make_glob<'a>(pattern: &'a str, span: &'a Span) -> Result<Glob<'a>> {
|
fn make_glob(pattern: &str, span: &Span) -> Result<GlobMatcher> {
|
||||||
Glob::new(pattern).or_else(|_| bail!(span.error("invalid glob")))
|
Ok(GlobBuilder::new(pattern)
|
||||||
|
.literal_separator(true)
|
||||||
|
.build()
|
||||||
|
.or_else(|_| bail!(span.error("invalid glob")))?
|
||||||
|
.compile_matcher())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn glob_match(span: &Span, params: &[Ref<Expr>], args: &[Value], _strict: bool) -> Result<Value> {
|
fn glob_match(span: &Span, params: &[Ref<Expr>], args: &[Value], _strict: bool) -> Result<Value> {
|
||||||
|
|||||||
@@ -1,73 +0,0 @@
|
|||||||
// Copyright (c) Microsoft Corporation.
|
|
||||||
// Licensed under the MIT License.
|
|
||||||
|
|
||||||
use crate::ast::{Expr, Ref};
|
|
||||||
use crate::builtins;
|
|
||||||
use crate::builtins::utils::{ensure_args_count, ensure_string};
|
|
||||||
use crate::*;
|
|
||||||
|
|
||||||
use crate::lexer::Span;
|
|
||||||
use crate::value::Value;
|
|
||||||
|
|
||||||
use itertools::Itertools;
|
|
||||||
|
|
||||||
use anyhow::{bail, Result};
|
|
||||||
|
|
||||||
pub fn register(m: &mut builtins::BuiltinsMap<&'static str, builtins::BuiltinFcn>) {
|
|
||||||
m.insert("io.jwt.decode", (jwt_decode, 1));
|
|
||||||
m.insert("io.jwt.decode_verify", (jwt_decode_verify, 2));
|
|
||||||
}
|
|
||||||
|
|
||||||
fn decode(span: &Span, jwt: String, strict: bool) -> Result<Value> {
|
|
||||||
let Some((Ok(header), Ok(payload), Ok(signature))) = jwt
|
|
||||||
.split('.')
|
|
||||||
.map(|p| data_encoding::BASE64URL_NOPAD.decode(p.as_bytes()))
|
|
||||||
.collect_tuple()
|
|
||||||
else {
|
|
||||||
if strict {
|
|
||||||
bail!(span.error("invalid jwt token"));
|
|
||||||
}
|
|
||||||
return Ok(Value::Undefined);
|
|
||||||
};
|
|
||||||
|
|
||||||
let header = String::from_utf8_lossy(&header).to_string();
|
|
||||||
let payload = String::from_utf8_lossy(&payload).to_string();
|
|
||||||
let signature = data_encoding::HEXLOWER_PERMISSIVE.encode(&signature);
|
|
||||||
|
|
||||||
let signature = Value::String(signature.into());
|
|
||||||
let header = Value::from_json_str(&header)?;
|
|
||||||
|
|
||||||
if header["enc"] != Value::Undefined {
|
|
||||||
bail!(span.error("JWT is a JWE object, which is not supported"));
|
|
||||||
}
|
|
||||||
|
|
||||||
if header["cty"] == "JWT".into() {
|
|
||||||
if payload.len() <= 2 || !payload.starts_with('"') || !payload.ends_with('"') {
|
|
||||||
bail!(span.error("invalid nested JWT"));
|
|
||||||
}
|
|
||||||
// Ignore ""
|
|
||||||
decode(span, payload[1..payload.len() - 1].to_string(), strict)
|
|
||||||
} else {
|
|
||||||
let payload = Value::from_json_str(&payload)?;
|
|
||||||
Ok(Value::from_array([header, payload, signature].into()))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn jwt_decode(span: &Span, params: &[Ref<Expr>], args: &[Value], strict: bool) -> Result<Value> {
|
|
||||||
let name = "io.jwt.decode";
|
|
||||||
ensure_args_count(span, name, params, args, 1)?;
|
|
||||||
let jwt = ensure_string(name, ¶ms[0], &args[0])?;
|
|
||||||
|
|
||||||
decode(span, jwt.to_string(), strict) //header, payload, signature, strict)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn jwt_decode_verify(
|
|
||||||
span: &Span,
|
|
||||||
params: &[Ref<Expr>],
|
|
||||||
args: &[Value],
|
|
||||||
_strict: bool,
|
|
||||||
) -> Result<Value> {
|
|
||||||
let name = "io.jwt.decode_verify";
|
|
||||||
ensure_args_count(span, name, params, args, 2)?;
|
|
||||||
Ok(Value::Undefined)
|
|
||||||
}
|
|
||||||
@@ -18,8 +18,6 @@ mod glob;
|
|||||||
mod graph;
|
mod graph;
|
||||||
#[cfg(feature = "http")]
|
#[cfg(feature = "http")]
|
||||||
mod http;
|
mod http;
|
||||||
#[cfg(feature = "jwt")]
|
|
||||||
mod jwt;
|
|
||||||
pub mod numbers;
|
pub mod numbers;
|
||||||
mod objects;
|
mod objects;
|
||||||
#[cfg(feature = "opa-runtime")]
|
#[cfg(feature = "opa-runtime")]
|
||||||
@@ -83,8 +81,6 @@ lazy_static! {
|
|||||||
//units::register(&mut m);
|
//units::register(&mut m);
|
||||||
types::register(&mut m);
|
types::register(&mut m);
|
||||||
encoding::register(&mut m);
|
encoding::register(&mut m);
|
||||||
#[cfg(feature = "jwt")]
|
|
||||||
jwt::register(&mut m);
|
|
||||||
#[cfg(feature = "time")]
|
#[cfg(feature = "time")]
|
||||||
time::register(&mut m);
|
time::register(&mut m);
|
||||||
|
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ use crate::*;
|
|||||||
use anyhow::{bail, Result};
|
use anyhow::{bail, Result};
|
||||||
|
|
||||||
#[cfg(feature = "std")]
|
#[cfg(feature = "std")]
|
||||||
use rand::{thread_rng, Rng};
|
use rand::Rng;
|
||||||
|
|
||||||
pub fn register(m: &mut builtins::BuiltinsMap<&'static str, builtins::BuiltinFcn>) {
|
pub fn register(m: &mut builtins::BuiltinsMap<&'static str, builtins::BuiltinFcn>) {
|
||||||
m.insert("abs", (abs, 1));
|
m.insert("abs", (abs, 1));
|
||||||
@@ -169,8 +169,7 @@ fn intn(span: &Span, params: &[Ref<Expr>], args: &[Value], _strict: bool) -> Res
|
|||||||
Some(0) => Value::from(0u64),
|
Some(0) => Value::from(0u64),
|
||||||
Some(n) => {
|
Some(n) => {
|
||||||
// TODO: bounds checking; arbitrary precision
|
// TODO: bounds checking; arbitrary precision
|
||||||
let mut rng = thread_rng();
|
let v = rand::rng().random_range(0..n);
|
||||||
let v = rng.gen_range(0..n);
|
|
||||||
Value::from(v)
|
Value::from(v)
|
||||||
}
|
}
|
||||||
_ => Value::Undefined,
|
_ => Value::Undefined,
|
||||||
|
|||||||
@@ -391,14 +391,14 @@ fn object_union_n(
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "jsonschema")]
|
#[cfg(feature = "jsonschema")]
|
||||||
fn compile_json_schema(param: &Ref<Expr>, arg: &Value) -> Result<jsonschema::JSONSchema> {
|
fn compile_json_schema(param: &Ref<Expr>, arg: &Value) -> Result<jsonschema::Validator> {
|
||||||
let schema_str = match arg {
|
let schema_str = match arg {
|
||||||
Value::String(schema_str) => schema_str.as_ref().to_string(),
|
Value::String(schema_str) => schema_str.as_ref().to_string(),
|
||||||
_ => arg.to_json_str()?,
|
_ => arg.to_json_str()?,
|
||||||
};
|
};
|
||||||
|
|
||||||
if let Ok(schema) = serde_json::from_str(&schema_str) {
|
if let Ok(schema) = serde_json::from_str(&schema_str) {
|
||||||
match jsonschema::JSONSchema::compile(&schema) {
|
match jsonschema::validator_for(&schema) {
|
||||||
Ok(schema) => return Ok(schema),
|
Ok(schema) => return Ok(schema),
|
||||||
Err(e) => bail!(e.to_string()),
|
Err(e) => bail!(e.to_string()),
|
||||||
}
|
}
|
||||||
@@ -439,16 +439,14 @@ fn json_match_schema(
|
|||||||
ensure_args_count(span, name, params, args, 2)?;
|
ensure_args_count(span, name, params, args, 2)?;
|
||||||
|
|
||||||
// The following is expected to succeed.
|
// The following is expected to succeed.
|
||||||
let document: serde_json::Value = serde_json::from_str(&args[0].to_json_str()?)?;
|
let document: serde_json::Value = serde_json::from_str(&args[0].to_json_str()?)
|
||||||
|
.map_err(|err| span.error(&format!("Failed to parse JSON: {}", err)))?;
|
||||||
|
|
||||||
Ok(Value::from_array(
|
Ok(Value::from_array(
|
||||||
match compile_json_schema(¶ms[1], &args[1]) {
|
match compile_json_schema(¶ms[1], &args[1]) {
|
||||||
Ok(schema) => match schema.validate(&document) {
|
Ok(schema) => match schema.validate(&document) {
|
||||||
Ok(_) => [Value::Bool(true), Value::Null],
|
Ok(_) => [Value::Bool(true), Value::Null],
|
||||||
Err(e) => [
|
Err(e) => [Value::Bool(false), Value::from(e.to_string())],
|
||||||
Value::Bool(false),
|
|
||||||
Value::from_array(e.map(|e| Value::String(e.to_string().into())).collect()),
|
|
||||||
],
|
|
||||||
},
|
},
|
||||||
Err(e) if strict => bail!(params[1]
|
Err(e) if strict => bail!(params[1]
|
||||||
.span()
|
.span()
|
||||||
|
|||||||
@@ -67,8 +67,6 @@ fn opa_runtime(span: &Span, params: &[Ref<Expr>], args: &[Value], _strict: bool)
|
|||||||
"hex",
|
"hex",
|
||||||
#[cfg(feature = "http")]
|
#[cfg(feature = "http")]
|
||||||
"http",
|
"http",
|
||||||
#[cfg(feature = "jwt")]
|
|
||||||
"jwt",
|
|
||||||
#[cfg(feature = "jsonschema")]
|
#[cfg(feature = "jsonschema")]
|
||||||
"jsonschema",
|
"jsonschema",
|
||||||
#[cfg(feature = "opa-runtime")]
|
#[cfg(feature = "opa-runtime")]
|
||||||
|
|||||||
@@ -146,11 +146,18 @@ fn split(span: &Span, params: &[Ref<Expr>], args: &[Value], _strict: bool) -> Re
|
|||||||
let s = ensure_string(name, ¶ms[0], &args[0])?;
|
let s = ensure_string(name, ¶ms[0], &args[0])?;
|
||||||
let delimiter = ensure_string(name, ¶ms[1], &args[1])?;
|
let delimiter = ensure_string(name, ¶ms[1], &args[1])?;
|
||||||
|
|
||||||
Ok(Value::from_array(
|
// Handle https://github.com/microsoft/regorus/issues/291
|
||||||
|
let parts: Vec<Value> = if delimiter.as_ref() == "" {
|
||||||
|
// If delimiter is "", str::split returns a leading and trailing "" whereas Golang's split doesn't.
|
||||||
|
// Therefore avoid str::split and instead return each char as a Value::String.
|
||||||
|
s.chars().map(|c| Value::from(c.to_string())).collect()
|
||||||
|
} else {
|
||||||
s.split(delimiter.as_ref())
|
s.split(delimiter.as_ref())
|
||||||
.map(|s| Value::String(s.into()))
|
.map(|s| Value::String(s.into()))
|
||||||
.collect(),
|
.collect()
|
||||||
))
|
};
|
||||||
|
|
||||||
|
Ok(Value::from(parts))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn to_string(v: &Value, unescape: bool) -> String {
|
fn to_string(v: &Value, unescape: bool) -> String {
|
||||||
|
|||||||
@@ -25,7 +25,11 @@ fn sleep(span: &Span, params: &[Ref<Expr>], args: &[Value], _strict: bool) -> Re
|
|||||||
let dur = time::compat::parse_duration(val.as_ref())
|
let dur = time::compat::parse_duration(val.as_ref())
|
||||||
.map_err(|e| params[0].span().error(&format!("{e}")))?;
|
.map_err(|e| params[0].span().error(&format!("{e}")))?;
|
||||||
|
|
||||||
thread::sleep(dur.to_std()?);
|
let std_dur = dur
|
||||||
|
.to_std()
|
||||||
|
.map_err(|err| anyhow::anyhow!("Failed to convert to std::time::Duration: {err}"))?;
|
||||||
|
|
||||||
|
thread::sleep(std_dur);
|
||||||
|
|
||||||
Ok(Value::Null)
|
Ok(Value::Null)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -158,7 +158,8 @@ fn parse_ns(span: &Span, params: &[Ref<Expr>], args: &[Value], strict: bool) ->
|
|||||||
let layout = ensure_string(name, ¶ms[0], &args[0])?;
|
let layout = ensure_string(name, ¶ms[0], &args[0])?;
|
||||||
let value = ensure_string(name, ¶ms[1], &args[1])?;
|
let value = ensure_string(name, ¶ms[1], &args[1])?;
|
||||||
|
|
||||||
let datetime = compat::parse(layout_with_predefined_formats(&layout), &value)?;
|
let datetime = compat::parse(layout_with_predefined_formats(&layout), &value)
|
||||||
|
.map_err(|err| anyhow::anyhow!("Failed to parse datetime: {}", err))?;
|
||||||
safe_timestamp_nanos(span, strict, datetime.timestamp_nanos_opt())
|
safe_timestamp_nanos(span, strict, datetime.timestamp_nanos_opt())
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -173,7 +174,8 @@ fn parse_rfc3339_ns(
|
|||||||
|
|
||||||
let value = ensure_string(name, ¶ms[0], &args[0])?;
|
let value = ensure_string(name, ¶ms[0], &args[0])?;
|
||||||
|
|
||||||
let datetime = DateTime::parse_from_rfc3339(&value)?;
|
let datetime = DateTime::parse_from_rfc3339(&value)
|
||||||
|
.map_err(|err| anyhow::anyhow!("Failed to parse datetime: {}", err))?;
|
||||||
safe_timestamp_nanos(span, strict, datetime.timestamp_nanos_opt())
|
safe_timestamp_nanos(span, strict, datetime.timestamp_nanos_opt())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -266,7 +266,7 @@ struct GoTimeFormatItems<'a> {
|
|||||||
mode: GoTimeFormatItemsMode,
|
mode: GoTimeFormatItemsMode,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> GoTimeFormatItems<'a> {
|
impl GoTimeFormatItems<'_> {
|
||||||
fn parse(reminder: &str) -> GoTimeFormatItems {
|
fn parse(reminder: &str) -> GoTimeFormatItems {
|
||||||
GoTimeFormatItems {
|
GoTimeFormatItems {
|
||||||
reminder,
|
reminder,
|
||||||
|
|||||||
@@ -83,8 +83,8 @@ fn parse(span: &Span, params: &[Ref<Expr>], args: &[Value], _strict: bool) -> Re
|
|||||||
bail!(span.error("spaces not allowed in resource strings"));
|
bail!(span.error("spaces not allowed in resource strings"));
|
||||||
}
|
}
|
||||||
|
|
||||||
let (number_part, suffix) = match string.find(|c: char| c.is_alphabetic()) {
|
let (number_part, suffix) = match string.rfind(|c: char| c.is_ascii_digit()) {
|
||||||
Some(p) => (&string[0..p], &string[p..]),
|
Some(p) => (&string[0..p + 1], &string[p + 1..]),
|
||||||
_ => (string, ""),
|
_ => (string, ""),
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -161,8 +161,8 @@ fn parse_bytes(span: &Span, params: &[Ref<Expr>], args: &[Value], strict: bool)
|
|||||||
bail!(span.error("spaces not allowed in resource strings"));
|
bail!(span.error("spaces not allowed in resource strings"));
|
||||||
}
|
}
|
||||||
|
|
||||||
let (number_part, suffix) = match string.find(|c: char| c.is_alphabetic()) {
|
let (number_part, suffix) = match string.rfind(|c: char| c.is_ascii_digit()) {
|
||||||
Some(p) => (&string[0..p], &string[p..]),
|
Some(p) => (&string[0..p + 1], &string[p + 1..]),
|
||||||
_ => (string, ""),
|
_ => (string, ""),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -132,16 +132,16 @@ fn timestamp(uuid: &Uuid) -> Option<Timestamp> {
|
|||||||
const fn decode_rfc4122_timestamp(uuid: &Uuid) -> (u64, u16) {
|
const fn decode_rfc4122_timestamp(uuid: &Uuid) -> (u64, u16) {
|
||||||
let bytes = uuid.as_bytes();
|
let bytes = uuid.as_bytes();
|
||||||
|
|
||||||
let ticks: u64 = ((bytes[6] & 0x0F) as u64) << 56
|
let ticks: u64 = (((bytes[6] & 0x0F) as u64) << 56)
|
||||||
| (bytes[7] as u64) << 48
|
| ((bytes[7] as u64) << 48)
|
||||||
| (bytes[4] as u64) << 40
|
| ((bytes[4] as u64) << 40)
|
||||||
| (bytes[5] as u64) << 32
|
| ((bytes[5] as u64) << 32)
|
||||||
| (bytes[0] as u64) << 24
|
| ((bytes[0] as u64) << 24)
|
||||||
| (bytes[1] as u64) << 16
|
| ((bytes[1] as u64) << 16)
|
||||||
| (bytes[2] as u64) << 8
|
| ((bytes[2] as u64) << 8)
|
||||||
| (bytes[3] as u64);
|
| (bytes[3] as u64);
|
||||||
|
|
||||||
let counter: u16 = ((bytes[8] & 0x3F) as u16) << 8 | (bytes[9] as u16);
|
let counter: u16 = (((bytes[8] & 0x3F) as u16) << 8) | (bytes[9] as u16);
|
||||||
|
|
||||||
(ticks, counter)
|
(ticks, counter)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ pub struct Engine {
|
|||||||
modules: Vec<Ref<Module>>,
|
modules: Vec<Ref<Module>>,
|
||||||
interpreter: Interpreter,
|
interpreter: Interpreter,
|
||||||
prepared: bool,
|
prepared: bool,
|
||||||
|
rego_v1: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Create a default engine.
|
/// Create a default engine.
|
||||||
@@ -36,9 +37,39 @@ impl Engine {
|
|||||||
modules: vec![],
|
modules: vec![],
|
||||||
interpreter: Interpreter::new(),
|
interpreter: Interpreter::new(),
|
||||||
prepared: false,
|
prepared: false,
|
||||||
|
rego_v1: true,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Enable rego v0.
|
||||||
|
///
|
||||||
|
/// Note that regorus now defaults to v1.
|
||||||
|
/// ```
|
||||||
|
/// # use regorus::*;
|
||||||
|
/// # fn main() -> anyhow::Result<()> {
|
||||||
|
/// let mut engine = Engine::new();
|
||||||
|
///
|
||||||
|
/// // Enable v0 for old style policies.
|
||||||
|
/// engine.set_rego_v0(true);
|
||||||
|
///
|
||||||
|
/// engine.add_policy(
|
||||||
|
/// "test.rego".to_string(),
|
||||||
|
/// r#"
|
||||||
|
/// package test
|
||||||
|
///
|
||||||
|
/// allow { # v0 syntax does not require if keyword
|
||||||
|
/// 1 < 2
|
||||||
|
/// }
|
||||||
|
/// "#.to_string())?;
|
||||||
|
///
|
||||||
|
/// # Ok(())
|
||||||
|
/// # }
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
pub fn set_rego_v0(&mut self, rego_v0: bool) {
|
||||||
|
self.rego_v1 = !rego_v0;
|
||||||
|
}
|
||||||
|
|
||||||
/// Add a policy.
|
/// Add a policy.
|
||||||
///
|
///
|
||||||
/// The policy file will be parsed and converted to AST representation.
|
/// The policy file will be parsed and converted to AST representation.
|
||||||
@@ -67,7 +98,7 @@ impl Engine {
|
|||||||
///
|
///
|
||||||
pub fn add_policy(&mut self, path: String, rego: String) -> Result<String> {
|
pub fn add_policy(&mut self, path: String, rego: String) -> Result<String> {
|
||||||
let source = Source::from_contents(path, rego)?;
|
let source = Source::from_contents(path, rego)?;
|
||||||
let mut parser = Parser::new(&source)?;
|
let mut parser = self.make_parser(&source)?;
|
||||||
let module = Ref::new(parser.parse()?);
|
let module = Ref::new(parser.parse()?);
|
||||||
self.modules.push(module.clone());
|
self.modules.push(module.clone());
|
||||||
// if policies change, interpreter needs to be prepared again
|
// if policies change, interpreter needs to be prepared again
|
||||||
@@ -87,6 +118,8 @@ impl Engine {
|
|||||||
/// # use regorus::*;
|
/// # use regorus::*;
|
||||||
/// # fn main() -> anyhow::Result<()> {
|
/// # fn main() -> anyhow::Result<()> {
|
||||||
/// let mut engine = Engine::new();
|
/// let mut engine = Engine::new();
|
||||||
|
/// // framework.rego does not conform to v1.
|
||||||
|
/// engine.set_rego_v0(true);
|
||||||
///
|
///
|
||||||
/// let package = engine.add_policy_from_file("tests/aci/framework.rego")?;
|
/// let package = engine.add_policy_from_file("tests/aci/framework.rego")?;
|
||||||
///
|
///
|
||||||
@@ -98,7 +131,7 @@ impl Engine {
|
|||||||
#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
|
#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
|
||||||
pub fn add_policy_from_file<P: AsRef<std::path::Path>>(&mut self, path: P) -> Result<String> {
|
pub fn add_policy_from_file<P: AsRef<std::path::Path>>(&mut self, path: P) -> Result<String> {
|
||||||
let source = Source::from_file(path)?;
|
let source = Source::from_file(path)?;
|
||||||
let mut parser = Parser::new(&source)?;
|
let mut parser = self.make_parser(&source)?;
|
||||||
let module = Ref::new(parser.parse()?);
|
let module = Ref::new(parser.parse()?);
|
||||||
self.modules.push(module.clone());
|
self.modules.push(module.clone());
|
||||||
// if policies change, interpreter needs to be prepared again
|
// if policies change, interpreter needs to be prepared again
|
||||||
@@ -112,6 +145,8 @@ impl Engine {
|
|||||||
/// # use regorus::*;
|
/// # use regorus::*;
|
||||||
/// # fn main() -> anyhow::Result<()> {
|
/// # fn main() -> anyhow::Result<()> {
|
||||||
/// let mut engine = Engine::new();
|
/// let mut engine = Engine::new();
|
||||||
|
/// // framework.rego does not conform to v1.
|
||||||
|
/// engine.set_rego_v0(true);
|
||||||
///
|
///
|
||||||
/// let _ = engine.add_policy_from_file("tests/aci/framework.rego")?;
|
/// let _ = engine.add_policy_from_file("tests/aci/framework.rego")?;
|
||||||
///
|
///
|
||||||
@@ -239,7 +274,7 @@ impl Engine {
|
|||||||
/// # }
|
/// # }
|
||||||
/// ```
|
/// ```
|
||||||
pub fn clear_data(&mut self) {
|
pub fn clear_data(&mut self) {
|
||||||
self.interpreter.set_data(Value::new_object());
|
self.interpreter.set_init_data(Value::new_object());
|
||||||
self.prepared = false;
|
self.prepared = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -276,7 +311,40 @@ impl Engine {
|
|||||||
bail!("data must be object");
|
bail!("data must be object");
|
||||||
}
|
}
|
||||||
self.prepared = false;
|
self.prepared = false;
|
||||||
self.interpreter.get_data_mut().merge(data)
|
self.interpreter.get_init_data_mut().merge(data)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get the data document.
|
||||||
|
///
|
||||||
|
/// The returned value is the data document that has been constructed using
|
||||||
|
/// one or more calls to [`Engine::add_data`]. The values of policy rules are
|
||||||
|
/// not included in the returned document.
|
||||||
|
///
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// # use regorus::*;
|
||||||
|
/// # fn main() -> anyhow::Result<()> {
|
||||||
|
/// let mut engine = Engine::new();
|
||||||
|
///
|
||||||
|
/// // If not set, data document is empty.
|
||||||
|
/// assert_eq!(engine.get_data(), Value::new_object());
|
||||||
|
///
|
||||||
|
/// // Merge { "x" : 1, "y" : {} }
|
||||||
|
/// assert!(engine.add_data(Value::from_json_str(r#"{ "x" : 1, "y" : {}}"#)?).is_ok());
|
||||||
|
///
|
||||||
|
/// // Merge { "z" : 2 }
|
||||||
|
/// assert!(engine.add_data(Value::from_json_str(r#"{ "z" : 2 }"#)?).is_ok());
|
||||||
|
///
|
||||||
|
/// let data = engine.get_data();
|
||||||
|
/// assert_eq!(data["x"], Value::from(1));
|
||||||
|
/// assert_eq!(data["y"], Value::new_object());
|
||||||
|
/// assert_eq!(data["z"], Value::from(2));
|
||||||
|
///
|
||||||
|
/// # Ok(())
|
||||||
|
/// # }
|
||||||
|
/// ```
|
||||||
|
pub fn get_data(&self) -> Value {
|
||||||
|
self.interpreter.get_init_data().clone()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn add_data_json(&mut self, data_json: &str) -> Result<()> {
|
pub fn add_data_json(&mut self, data_json: &str) -> Result<()> {
|
||||||
@@ -354,6 +422,7 @@ impl Engine {
|
|||||||
/// let mut engine = Engine::new();
|
/// let mut engine = Engine::new();
|
||||||
///
|
///
|
||||||
/// // Add policies
|
/// // Add policies
|
||||||
|
/// engine.set_rego_v0(true);
|
||||||
/// engine.add_policy_from_file("tests/aci/framework.rego")?;
|
/// 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/api.rego")?;
|
||||||
/// engine.add_policy_from_file("tests/aci/policy.rego")?;
|
/// engine.add_policy_from_file("tests/aci/policy.rego")?;
|
||||||
@@ -395,7 +464,7 @@ impl Engine {
|
|||||||
|
|
||||||
// Parse the query.
|
// Parse the query.
|
||||||
let query_source = Source::from_contents("<query.rego>".to_string(), query)?;
|
let query_source = Source::from_contents("<query.rego>".to_string(), query)?;
|
||||||
let mut parser = Parser::new(&query_source)?;
|
let mut parser = self.make_parser(&query_source)?;
|
||||||
let query_node = parser.parse_user_query()?;
|
let query_node = parser.parse_user_query()?;
|
||||||
if query_node.span.text() == "data" {
|
if query_node.span.text() == "data" {
|
||||||
self.eval_modules(enable_tracing)?;
|
self.eval_modules(enable_tracing)?;
|
||||||
@@ -512,7 +581,7 @@ impl Engine {
|
|||||||
|
|
||||||
// Parse the query.
|
// Parse the query.
|
||||||
let query_source = Source::from_contents("<query.rego>".to_string(), query)?;
|
let query_source = Source::from_contents("<query.rego>".to_string(), query)?;
|
||||||
let mut parser = Parser::new(&query_source)?;
|
let mut parser = self.make_parser(&query_source)?;
|
||||||
let query_node = parser.parse_user_query()?;
|
let query_node = parser.parse_user_query()?;
|
||||||
let query_schedule = Analyzer::new().analyze_query_snippet(&self.modules, &query_node)?;
|
let query_schedule = Analyzer::new().analyze_query_snippet(&self.modules, &query_node)?;
|
||||||
self.interpreter.eval_user_query(
|
self.interpreter.eval_user_query(
|
||||||
@@ -537,11 +606,7 @@ impl Engine {
|
|||||||
self.interpreter.set_modules(&self.modules);
|
self.interpreter.set_modules(&self.modules);
|
||||||
|
|
||||||
self.interpreter.clear_builtins_cache();
|
self.interpreter.clear_builtins_cache();
|
||||||
// when the interpreter is prepared the initial data is saved
|
// clean_internal_evaluation_state will set data to an efficient clont of use supplied init_data
|
||||||
// the data will be reset to init_data each time clean_internal_evaluation_state is called
|
|
||||||
let init_data = self.interpreter.get_data_mut().clone();
|
|
||||||
self.interpreter.set_init_data(init_data);
|
|
||||||
|
|
||||||
// Initialize the with-document with initial data values.
|
// Initialize the with-document with initial data values.
|
||||||
// with-modifiers will be applied to this document.
|
// with-modifiers will be applied to this document.
|
||||||
self.interpreter.init_with_document()?;
|
self.interpreter.init_with_document()?;
|
||||||
@@ -683,7 +748,7 @@ impl Engine {
|
|||||||
/// engine.add_policy(
|
/// engine.add_policy(
|
||||||
/// "policy.rego".to_string(),
|
/// "policy.rego".to_string(),
|
||||||
/// r#"package invalid
|
/// r#"package invalid
|
||||||
/// x = y {
|
/// x = y if {
|
||||||
/// # y = do_magic(2)
|
/// # y = do_magic(2)
|
||||||
/// do_magic(2, y) # y is supplied as an out parameter.
|
/// do_magic(2, y) # y is supplied as an out parameter.
|
||||||
/// }
|
/// }
|
||||||
@@ -719,7 +784,7 @@ impl Engine {
|
|||||||
/// r#"
|
/// r#"
|
||||||
/// package test # Line 2
|
/// package test # Line 2
|
||||||
///
|
///
|
||||||
/// x = y { # Line 4
|
/// x = y if { # Line 4
|
||||||
/// input.a > 2 # Line 5
|
/// input.a > 2 # Line 5
|
||||||
/// y = 5 # Line 6
|
/// y = 5 # Line 6
|
||||||
/// }
|
/// }
|
||||||
@@ -841,4 +906,12 @@ impl Engine {
|
|||||||
|
|
||||||
serde_json::to_string_pretty(&ast).map_err(anyhow::Error::msg)
|
serde_json::to_string_pretty(&ast).map_err(anyhow::Error::msg)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn make_parser<'a>(&self, source: &'a Source) -> Result<Parser<'a>> {
|
||||||
|
let mut parser = Parser::new(source)?;
|
||||||
|
if self.rego_v1 {
|
||||||
|
parser.enable_rego_v1()?;
|
||||||
|
}
|
||||||
|
Ok(parser)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -216,18 +216,22 @@ impl Interpreter {
|
|||||||
self.modules = modules.to_vec();
|
self.modules = modules.to_vec();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_init_data(&mut self, init_data: Value) {
|
|
||||||
self.init_data = init_data;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn set_data(&mut self, data: Value) {
|
|
||||||
self.data = data;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get_data_mut(&mut self) -> &mut Value {
|
pub fn get_data_mut(&mut self) -> &mut Value {
|
||||||
&mut self.data
|
&mut self.data
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn set_init_data(&mut self, data: Value) {
|
||||||
|
self.init_data = data;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_init_data(&self) -> &Value {
|
||||||
|
&self.init_data
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_init_data_mut(&mut self) -> &mut Value {
|
||||||
|
&mut self.init_data
|
||||||
|
}
|
||||||
|
|
||||||
pub fn set_traces(&mut self, enable_tracing: bool) {
|
pub fn set_traces(&mut self, enable_tracing: bool) {
|
||||||
self.traces = match enable_tracing {
|
self.traces = match enable_tracing {
|
||||||
true => Some(vec![]),
|
true => Some(vec![]),
|
||||||
@@ -480,6 +484,12 @@ impl Interpreter {
|
|||||||
self.hoist_loops_impl(rhs, loops);
|
self.hoist_loops_impl(rhs, loops);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "rego-extensions")]
|
||||||
|
OrExpr { lhs, rhs, .. } => {
|
||||||
|
self.hoist_loops_impl(lhs, loops);
|
||||||
|
self.hoist_loops_impl(rhs, loops);
|
||||||
|
}
|
||||||
|
|
||||||
Membership {
|
Membership {
|
||||||
key,
|
key,
|
||||||
value,
|
value,
|
||||||
@@ -550,8 +560,8 @@ impl Interpreter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
match op {
|
match op {
|
||||||
BinOp::Or => builtins::sets::union(lhs, rhs, lhs_value, rhs_value),
|
BinOp::Union => builtins::sets::union(lhs, rhs, lhs_value, rhs_value),
|
||||||
BinOp::And => builtins::sets::intersection(lhs, rhs, lhs_value, rhs_value),
|
BinOp::Intersection => builtins::sets::intersection(lhs, rhs, lhs_value, rhs_value),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1554,6 +1564,10 @@ impl Interpreter {
|
|||||||
let mut obj = &mut self.data;
|
let mut obj = &mut self.data;
|
||||||
let len = path.len();
|
let len = path.len();
|
||||||
for (idx, p) in path.into_iter().enumerate() {
|
for (idx, p) in path.into_iter().enumerate() {
|
||||||
|
// Stop at the first undefined component in the path
|
||||||
|
if p == Value::Undefined {
|
||||||
|
break;
|
||||||
|
}
|
||||||
if idx == len - 1 {
|
if idx == len - 1 {
|
||||||
// last key.
|
// last key.
|
||||||
if is_set {
|
if is_set {
|
||||||
@@ -1688,6 +1702,7 @@ impl Interpreter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if output == Value::Undefined || !comps_defined {
|
if output == Value::Undefined || !comps_defined {
|
||||||
|
ctx.rule_value = Value::Undefined;
|
||||||
return Ok(false);
|
return Ok(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1867,14 +1882,14 @@ impl Interpreter {
|
|||||||
self.hoist_loops_impl(oe, &mut loops);
|
self.hoist_loops_impl(oe, &mut loops);
|
||||||
}
|
}
|
||||||
|
|
||||||
self.eval_output_expr_in_loop(&loops[..])?;
|
let r = self.eval_output_expr_in_loop(&loops[..])?;
|
||||||
|
|
||||||
let ctx = self.get_current_context()?;
|
let ctx = self.get_current_context()?;
|
||||||
if let Some(_oe) = &ctx.output_expr {
|
if let Some(_oe) = &ctx.output_expr {
|
||||||
// Ensure that at least one output was generated.
|
// Ensure that at least one output was generated.
|
||||||
Ok(ctx.value != Value::Undefined)
|
Ok(ctx.rule_value != Value::Undefined)
|
||||||
} else {
|
} else {
|
||||||
Ok(true)
|
Ok(r)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2274,15 +2289,8 @@ impl Interpreter {
|
|||||||
};
|
};
|
||||||
|
|
||||||
let mut param_values = Vec::with_capacity(params.len());
|
let mut param_values = Vec::with_capacity(params.len());
|
||||||
let mut error = None;
|
|
||||||
for p in params {
|
for p in params {
|
||||||
match self.eval_expr(p) {
|
param_values.push(self.eval_expr(p)?);
|
||||||
Ok(v) => param_values.push(v),
|
|
||||||
Err(e) => {
|
|
||||||
error = Some(Err(e));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let orig_fcn_path = fcn_path;
|
let orig_fcn_path = fcn_path;
|
||||||
@@ -2299,9 +2307,6 @@ impl Interpreter {
|
|||||||
if param_values.iter().any(|v| v == &Value::Undefined) {
|
if param_values.iter().any(|v| v == &Value::Undefined) {
|
||||||
return Ok(Value::Undefined);
|
return Ok(Value::Undefined);
|
||||||
}
|
}
|
||||||
if let Some(err) = error {
|
|
||||||
err?;
|
|
||||||
};
|
|
||||||
return Ok(v.clone());
|
return Ok(v.clone());
|
||||||
}
|
}
|
||||||
_ => orig_fcn_path.clone(),
|
_ => orig_fcn_path.clone(),
|
||||||
@@ -2832,6 +2837,15 @@ impl Interpreter {
|
|||||||
..
|
..
|
||||||
} => self.eval_membership(key, value, collection),
|
} => self.eval_membership(key, value, collection),
|
||||||
|
|
||||||
|
#[cfg(feature = "rego-extensions")]
|
||||||
|
Expr::OrExpr { lhs, rhs, .. } => {
|
||||||
|
let lhs = self.eval_expr(lhs)?;
|
||||||
|
match lhs {
|
||||||
|
Value::Bool(false) | Value::Null | Value::Undefined => self.eval_expr(rhs),
|
||||||
|
_ => Ok(lhs),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Creation expression
|
// Creation expression
|
||||||
Expr::Array { items, .. } => self.eval_array(items),
|
Expr::Array { items, .. } => self.eval_array(items),
|
||||||
Expr::Object { fields, .. } => self.eval_object(fields),
|
Expr::Object { fields, .. } => self.eval_object(fields),
|
||||||
@@ -2944,7 +2958,6 @@ impl Interpreter {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
result = self.eval_query(&body.query);
|
result = self.eval_query(&body.query);
|
||||||
|
|
||||||
if matches!(&result, Ok(true) | Err(_)) {
|
if matches!(&result, Ok(true) | Err(_)) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -2957,10 +2970,7 @@ impl Interpreter {
|
|||||||
_ => bail!("internal error: rule's context already popped"),
|
_ => bail!("internal error: rule's context already popped"),
|
||||||
};
|
};
|
||||||
|
|
||||||
let result = match result {
|
let result = result?;
|
||||||
Ok(r) => r,
|
|
||||||
Err(e) => return Err(e),
|
|
||||||
};
|
|
||||||
|
|
||||||
assert_eq!(self.scopes.len(), n_scopes);
|
assert_eq!(self.scopes.len(), n_scopes);
|
||||||
|
|
||||||
@@ -3128,6 +3138,8 @@ impl Interpreter {
|
|||||||
ArithExpr { span, .. } => ("arithexpr", span),
|
ArithExpr { span, .. } => ("arithexpr", span),
|
||||||
AssignExpr { span, .. } => ("assignexpr", span),
|
AssignExpr { span, .. } => ("assignexpr", span),
|
||||||
Membership { span, .. } => ("membership", span),
|
Membership { span, .. } => ("membership", span),
|
||||||
|
#[cfg(feature = "rego-extensions")]
|
||||||
|
OrExpr { span, .. } => ("orexpr", span),
|
||||||
};
|
};
|
||||||
|
|
||||||
Err(span.error(format!("invalid `{kind}` in default value").as_str()))
|
Err(span.error(format!("invalid `{kind}` in default value").as_str()))
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
// Copyright (c) Microsoft Corporation.
|
// Copyright (c) Microsoft Corporation.
|
||||||
// Licensed under the MIT License.
|
// Licensed under the MIT License.
|
||||||
|
|
||||||
|
#![cfg_attr(docsrs, feature(doc_cfg))]
|
||||||
#![allow(unknown_lints)]
|
#![allow(unknown_lints)]
|
||||||
#![allow(clippy::doc_lazy_continuation)]
|
#![allow(clippy::doc_lazy_continuation)]
|
||||||
// Use README.md as crate documentation.
|
// Use README.md as crate documentation.
|
||||||
@@ -357,7 +358,7 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Implement clone for a boxed extension using [`Extension::clone_box`].
|
/// Implement clone for a boxed extension using [`Extension::clone_box`].
|
||||||
impl<'a> Clone for Box<dyn 'a + Extension> {
|
impl Clone for Box<dyn '_ + Extension> {
|
||||||
fn clone(&self) -> Self {
|
fn clone(&self) -> Self {
|
||||||
(**self).clone_box()
|
(**self).clone_box()
|
||||||
}
|
}
|
||||||
@@ -404,7 +405,6 @@ pub mod coverage {
|
|||||||
/// Lines that are not covered are red.
|
/// Lines that are not covered are red.
|
||||||
///
|
///
|
||||||
/// <img src="https://github.com/microsoft/regorus/blob/main/docs/coverage.png?raw=true">
|
/// <img src="https://github.com/microsoft/regorus/blob/main/docs/coverage.png?raw=true">
|
||||||
|
|
||||||
pub fn to_string_pretty(&self) -> anyhow::Result<String> {
|
pub fn to_string_pretty(&self) -> anyhow::Result<String> {
|
||||||
let mut s = String::default();
|
let mut s = String::default();
|
||||||
s.push_str("COVERAGE REPORT:\n");
|
s.push_str("COVERAGE REPORT:\n");
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user