Compare commits

...

10 Commits

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

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

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

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

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

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

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

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


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

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

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

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

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

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

Implement IDisposable for Engine cleanup.

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

Signed-off-by: Anand Krishnamoorthi <anakrish@microsoft.com>
2025-03-25 11:31:13 -07:00
51 changed files with 11420 additions and 798 deletions

View File

@@ -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": [
// { // {

View File

@@ -18,24 +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 - name: Run example
run: cargo run --example regorus -- eval -d examples/server/allowed_server.rego -i examples/server/input.json data.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)

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

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

View File

@@ -17,6 +17,7 @@ jobs:
- name: Test FFI - 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

View File

@@ -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

View File

@@ -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)

View File

@@ -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

View File

@@ -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

View File

@@ -26,6 +26,7 @@ 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
# Enable when upstream issue is fixed. # Enable when upstream issue is fixed.

View File

@@ -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)

8
.gitignore vendored
View File

@@ -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
@@ -28,3 +24,7 @@ bindings/ffi/regorus.h
bindings/ffi/regorus.ffi.hpp bindings/ffi/regorus.ffi.hpp
bindings/*/target bindings/*/target
# C# build folders
**bin
**obj

1778
Cargo.lock generated Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -30,7 +30,7 @@ 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"]
no_std = ["lazy_static/spin_no_std"] no_std = ["lazy_static/spin_no_std"]
@@ -107,9 +107,9 @@ md-5 = {version = "0.10.6", optional = true, default-features = false }
data-encoding = { version = "2.8.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.3" } scientific = { version = "0.5.3" }
globset = { version = "0.4.16", features = ["simd-accel"], default-features = false, optional = true }
regex = {version = "1.11.1", optional = true, default-features = false } regex = {version = "1.11.1", optional = true, default-features = false }
semver = {version = "1.0.25", optional = true, default-features = false } semver = {version = "1.0.25", optional = true, default-features = false }
wax = { version = "0.6.0", features = [], default-features = false, optional = true }
url = { version = "2.5.4", optional = true } url = { version = "2.5.4", optional = true }
uuid = { version = "1.15.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.29.0", default-features = false, optional = true } jsonschema = { version = "0.29.0", default-features = false, optional = true }
@@ -123,7 +123,7 @@ rand = { version = "0.9.0", default-features = false, features = ["thread_rng"],
[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.8.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"

View File

@@ -107,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).

View File

@@ -32,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
) )

View File

@@ -25,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"
) )

View File

@@ -26,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")

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -1,23 +1,19 @@
//----------------------------------------------------------------------- // 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();
@@ -46,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(
@@ -65,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.");
}

View File

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

View File

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

View File

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

View File

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

View File

@@ -1,220 +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;
}
byte[] NullTerminatedUTF8Bytes(string s)
{
return Encoding.UTF8.GetBytes(s + char.MinValue);
}
public void SetRegoV0(bool enable)
{
unsafe
{
CheckAndDropResult(RegorusFFI.API.regorus_engine_set_rego_v0(E, enable));
}
}
public void AddPolicy(string path, string rego)
{
var pathBytes = NullTerminatedUTF8Bytes(path);
var regoBytes = NullTerminatedUTF8Bytes(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 = NullTerminatedUTF8Bytes(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 = NullTerminatedUTF8Bytes(data);
unsafe
{
fixed (byte* dataPtr = dataBytes)
{
CheckAndDropResult(RegorusFFI.API.regorus_engine_add_data_json(E, dataPtr));
}
}
}
public void AddDataFromJsonFile(string path)
{
var pathBytes = NullTerminatedUTF8Bytes(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 = NullTerminatedUTF8Bytes(input);
unsafe
{
fixed (byte* inputPtr = inputBytes)
{
CheckAndDropResult(RegorusFFI.API.regorus_engine_set_input_json(E, inputPtr));
}
}
}
public void SetInputFromJsonFile(string path)
{
var pathBytes = NullTerminatedUTF8Bytes(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 = NullTerminatedUTF8Bytes(query);
var resultJson = "";
unsafe
{
fixed (byte* queryPtr = queryBytes)
{
var result = RegorusFFI.API.regorus_engine_eval_query(E, queryPtr);
if (result.status == RegorusFFI.RegorusStatus.RegorusStatusOk)
{
if (result.output != null)
{
resultJson = System.Runtime.InteropServices.Marshal.PtrToStringAnsi((IntPtr)result.output);
}
RegorusFFI.API.regorus_result_drop(result);
}
else
{
CheckAndDropResult(result);
}
}
}
if (resultJson != null)
{
return resultJson;
}
else
{
return "";
}
}
void CheckAndDropResult(RegorusFFI.RegorusResult result)
{
if (result.status != RegorusFFI.RegorusStatus.RegorusStatusOk)
{
unsafe
{
var message = System.Runtime.InteropServices.Marshal.PtrToStringAnsi((IntPtr)result.error_message);
var ex = new Exception(message);
RegorusFFI.API.regorus_result_drop(result);
throw ex;
}
}
RegorusFFI.API.regorus_result_drop(result);
}
}
}

View File

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

View File

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

View File

@@ -1,236 +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;
}
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);
unsafe
{
fixed (byte* pathPtr = pathBytes)
{
fixed (byte* regoPtr = regoBytes)
{
return CheckAndDropResult(RegorusFFI.API.regorus_engine_add_policy(E, pathPtr, regoPtr));
}
}
}
}
public void SetRegoV0(bool enable)
{
unsafe
{
CheckAndDropResult(RegorusFFI.API.regorus_engine_set_rego_v0(E, enable));
}
}
public string AddPolicyFromFile(string path)
{
var pathBytes = NullTerminatedUTF8Bytes(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 = NullTerminatedUTF8Bytes(data);
unsafe
{
fixed (byte* dataPtr = dataBytes)
{
CheckAndDropResult(RegorusFFI.API.regorus_engine_add_data_json(E, dataPtr));
}
}
}
public void AddDataFromJsonFile(string path)
{
var pathBytes = NullTerminatedUTF8Bytes(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 = NullTerminatedUTF8Bytes(input);
unsafe
{
fixed (byte* inputPtr = inputBytes)
{
CheckAndDropResult(RegorusFFI.API.regorus_engine_set_input_json(E, inputPtr));
}
}
}
public void SetInputFromJsonFile(string path)
{
var pathBytes = NullTerminatedUTF8Bytes(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 = NullTerminatedUTF8Bytes(query);
unsafe
{
fixed (byte* queryPtr = queryBytes)
{
return CheckAndDropResult(RegorusFFI.API.regorus_engine_eval_query(E, queryPtr));
}
}
}
public string EvalRule(string rule)
{
var ruleBytes = NullTerminatedUTF8Bytes(rule);
unsafe
{
fixed (byte* rulePtr = ruleBytes)
{
return CheckAndDropResult(RegorusFFI.API.regorus_engine_eval_query(E, rulePtr));
}
}
}
public void SetEnableCoverage(bool enable)
{
unsafe
{
CheckAndDropResult(RegorusFFI.API.regorus_engine_set_enable_coverage(E, enable));
}
}
public void ClearCoverageData()
{
unsafe
{
CheckAndDropResult(RegorusFFI.API.regorus_engine_clear_coverage_data(E));
}
}
public string GetCoverageReport()
{
unsafe
{
return CheckAndDropResult(RegorusFFI.API.regorus_engine_get_coverage_report(E));
}
}
public string GetCoverageReportPretty()
{
unsafe
{
return CheckAndDropResult(RegorusFFI.API.regorus_engine_get_coverage_report_pretty(E));
}
}
public void SetGatherPrints(bool enable)
{
unsafe
{
CheckAndDropResult(RegorusFFI.API.regorus_engine_set_gather_prints(E, enable));
}
}
public string TakePrints()
{
unsafe
{
return CheckAndDropResult(RegorusFFI.API.regorus_engine_take_prints(E));
}
}
~Engine()
{
unsafe
{
RegorusFFI.API.regorus_engine_drop(E);
}
}
string CheckAndDropResult(RegorusFFI.RegorusResult result)
{
if (result.status != RegorusFFI.RegorusStatus.RegorusStatusOk)
{
unsafe
{
var message = System.Runtime.InteropServices.Marshal.PtrToStringUTF8((IntPtr)result.error_message);
var ex = new Exception(message);
RegorusFFI.API.regorus_result_drop(result);
throw ex;
}
}
var resultString = "";
unsafe
{
if (result.output is not null)
{
resultString = System.Runtime.InteropServices.Marshal.PtrToStringUTF8((IntPtr)result.output);
}
RegorusFFI.API.regorus_result_drop(result);
}
return resultString;
}
}
}

View File

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

1771
bindings/ffi/Cargo.lock generated Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -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();
} }

1692
bindings/java/Cargo.lock generated Normal file

File diff suppressed because it is too large Load Diff

1672
bindings/python/Cargo.lock generated Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -2,7 +2,7 @@
[package] [package]
name = "regoruspy" name = "regoruspy"
version = "0.3.0" version = "0.4.0"
edition = "2021" edition = "2021"
repository = "https://github.com/microsoft/regorus/bindings/python" repository = "https://github.com/microsoft/regorus/bindings/python"
description = "Python bindings for Regorus - a fast, lightweight Rego interpreter written in Rust" description = "Python bindings for Regorus - a fast, lightweight Rego interpreter written in Rust"
@@ -21,7 +21,7 @@ coverage = ["regorus/coverage"]
[dependencies] [dependencies]
anyhow = "1.0" anyhow = "1.0"
ordered-float = "5.0.0" ordered-float = "5.0.0"
pyo3 = {version = "0.24.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.140" serde_json = "1.0.140"

View File

@@ -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"]

1706
bindings/ruby/Cargo.lock generated Normal file

File diff suppressed because it is too large Load Diff

1628
bindings/wasm/Cargo.lock generated Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -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;
} }

View File

@@ -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> {

View File

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

View File

@@ -292,6 +292,7 @@ fn yaml_test_impl(file: &str) -> Result<()> {
"compare.yaml", "compare.yaml",
"diff.yaml", "diff.yaml",
"format.yaml", "format.yaml",
"globmatch.yaml",
"now_ns.yaml", "now_ns.yaml",
"parse_duration_ns.yaml", "parse_duration_ns.yaml",
"parse_ns.yaml", "parse_ns.yaml",

View File

@@ -0,0 +1,60 @@
# Copyright (c) Microsoft Corporation.
# Licensed under the MIT License.
cases:
- note: all
data: {}
modules:
- |
package play
import rego.v1
# Examples from MS Graph
m1:= glob.match("api://*/appId", null, "api://foo.com/appId")
# Examples from https://www.openpolicyagent.org/docs/latest/policy-reference/#glob
m2 := glob.match("*.github.com", [], "api.github.com") # true
m3 := glob.match("*.github.com", [], "api.cdn.github.com") # false
m4 := glob.match("*hub.com", null, "api.cdn.github.com")
m5 := glob.match("*:github:com", [":"], "api:github:com")
m6 := glob.match("api.**.com", [], "api.github.com")
m7 := glob.match("api.**.com", [], "api.cdn.github.com")
m8 := glob.match("?at", [], "cat")
m9 := glob.match("?at", [], "at")
m10 := glob.match("[abc]at", [], "bat")
m11 := glob.match("[abc]at", [], "cat")
m12 := glob.match("[abc]at", [], "lat")
m13 := glob.match("[!abc]at", [], "cat")
m14 := glob.match("[!a-c]at", [], "lat")
m15 := glob.match("{cat,bat,[fr]at}", [], "cat")
m16 := glob.match("{cat,bat,[fr]at}", [], "bat")
m17 := glob.match("{cat,bat,[fr]at}", [], "rat")
m18 := glob.match("{cat,bat,[fr]at}", [], "at")
matches := [
m1 == true,
m2 == true,
m3 == false,
m4 == true,
m5 == true,
m6 == true,
m7 == true,
m8 == true,
m9 == false,
m10 == true,
m11 == true,
m12 == false,
m13 == false,
m14 == true,
m15 == true,
m16 == true,
m17 == true,
m18 == false,
]
pass if {
every m in matches {
m == true
}
}
query: data.play.pass
want_result: true