Fix bindings and add CI tests (#247)

Also update version numbers of binding Rust projects to match Regorus

Signed-off-by: Anand Krishnamoorthi <anakrish@microsoft.com>
This commit is contained in:
Anand Krishnamoorthi
2024-05-22 11:15:42 -04:00
committed by GitHub
parent 495e91c75a
commit 9894f00829
35 changed files with 448 additions and 107 deletions

View File

@@ -1,4 +1,4 @@
name: Rust
name: tests/release
on:
push:
@@ -10,26 +10,18 @@ env:
CARGO_TERM_COLOR: always
jobs:
build:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Add musl target
run: rustup target add x86_64-unknown-linux-musl
- name: Add no_std target
run: rustup target add thumbv7m-none-eabi
- name: Install musl-gcc
run: sudo apt update && sudo apt install -y musl-tools
- uses: actions/checkout@v4
- name: Format Check
run: cargo fmt --check
- name: Build (all features)
run: cargo build -r --all-features --verbose
run: cargo build -r --all-features
- name: Build
run: cargo build -r --verbose
- name: Build no_std
run: cd tests/ensure_no_std && cargo build -r --target thumbv7m-none-eabi
run: cargo build -r
- name: Test no_std
run: cargo test -r --no-default-features
- name: Build only std
@@ -37,7 +29,7 @@ jobs:
- name: Doc Tests
run: cargo test -r --doc
- name: Run tests
run: cargo test -r --verbose
run: cargo test -r
- name: Run tests (ACI)
run: cargo test -r --test aci
- name: Run tests (KATA)
@@ -45,14 +37,3 @@ jobs:
- name: Run tests (OPA Conformance)
run: >-
cargo test -r --test opa --features opa-testutil,serde_json/arbitrary_precision -- $(tr '\n' ' ' < tests/opa.passing)
- name: Build (MUSL)
run: cargo build --verbose --all-targets --target x86_64-unknown-linux-musl
- name: Run tests (MUSL)
run: cargo test -r --verbose --target x86_64-unknown-linux-musl
- name: Run tests (MUSL ACI)
run: cargo test -r --test aci --target x86_64-unknown-linux-musl
- name: Run tests (KATA ACI)
run: cargo test -r --test kata --target x86_64-unknown-linux-musl
- name: Run tests (MUSL OPA Conformance)
run: >-
cargo test -r --test opa --features opa-testutil,serde_json/arbitrary_precision --target x86_64-unknown-linux-musl -- $(tr '\n' ' ' < tests/opa.passing)

View File

@@ -23,7 +23,7 @@ jobs:
with:
python-version: '3.10'
- name: Build wheels
uses: PyO3/maturin-action@v1
uses: PyO3/maturin-action@63b75c597b83e247fbf4fb7719801cc4220ae9f3 # v1.43.0
with:
target: ${{ matrix.target }}
args: --release --out dist --find-interpreter --manifest-path bindings/python/Cargo.toml
@@ -47,7 +47,7 @@ jobs:
python-version: '3.10'
architecture: ${{ matrix.target }}
- name: Build wheels
uses: PyO3/maturin-action@v1
uses: PyO3/maturin-action@63b75c597b83e247fbf4fb7719801cc4220ae9f3 # v1.43.0
with:
target: ${{ matrix.target }}
args: --release --out dist --find-interpreter --manifest-path bindings/python/Cargo.toml
@@ -69,7 +69,7 @@ jobs:
with:
python-version: '3.10'
- name: Build wheels
uses: PyO3/maturin-action@v1
uses: PyO3/maturin-action@63b75c597b83e247fbf4fb7719801cc4220ae9f3 # v1.43.0
with:
target: ${{ matrix.target }}
args: --release --out dist --find-interpreter --manifest-path bindings/python/Cargo.toml
@@ -85,7 +85,7 @@ jobs:
steps:
- uses: actions/checkout@v3
- name: Build sdist
uses: PyO3/maturin-action@v1
uses: PyO3/maturin-action@63b75c597b83e247fbf4fb7719801cc4220ae9f3 # v1.43.0
with:
command: sdist
args: --out dist --manifest-path bindings/python/Cargo.toml
@@ -106,7 +106,7 @@ jobs:
with:
name: wheels
- name: Publish to PyPI
uses: PyO3/maturin-action@v1
uses: PyO3/maturin-action@63b75c597b83e247fbf4fb7719801cc4220ae9f3 # v1.43.0
env:
MATURIN_PYPI_TOKEN: ${{ secrets.PYPI_API_TOKEN }}
with:

View File

@@ -18,7 +18,7 @@ jobs:
- name: Install Rust toolchain
uses: dtolnay/rust-toolchain@stable
- name: Run release-plz
uses: MarcoIeni/release-plz-action@v0.5
uses: MarcoIeni/release-plz-action@a10be9933e46ab5005d79ce8b1eafca2ecdcd844 #v0.3.68
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_REGISTRY_TOKEN }}

43
.github/workflows/test-c-cpp.yml vendored Normal file
View File

@@ -0,0 +1,43 @@
name: bindings/c-cpp
on:
push:
branches: [ "main" ]
pull_request:
branches: [ "main" ]
jobs:
test:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Setup gcc, g++, cmake, ninja
run: sudo apt update && sudo apt install -y gcc g++ cmake ninja-build
- name: Test c binding
run: |
mkdir bindings/c/build
cd bindings/c/build
cmake -G Ninja ..
ninja
./regorus_test
- name: Test c-nostd binding
run: |
mkdir bindings/c-nostd/build
cd bindings/c-nostd/build
cmake -G Ninja ..
ninja
./regorus_test
- name: Test cpp binding
run: |
mkdir bindings/cpp/build
cd bindings/cpp/build
cmake -G Ninja ..
ninja
./regorus_test

26
.github/workflows/test-csharp.yml vendored Normal file
View File

@@ -0,0 +1,26 @@
name: bindings/csharp
on:
push:
branches: [ "main" ]
pull_request:
branches: [ "main" ]
jobs:
test:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v4
with:
fetch-depth: 0
- uses: actions/setup-dotnet@v4
- name: Build
run: dotnet build
working-directory: ./bindings/csharp
- name: Run
run: LD_LIBRARY_PATH=. dotnet run
working-directory: ./bindings/csharp

33
.github/workflows/test-go.yml vendored Normal file
View File

@@ -0,0 +1,33 @@
name: bindings/go
on:
push:
branches: [ "main" ]
pull_request:
branches: [ "main" ]
jobs:
test:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v4
with:
fetch-depth: 0
- uses: actions/setup-go@v5
with:
python-version: ${{ env.PYTHON_VERSION }}
architecture: x64
- name: Build ffi
run: cargo build -r
working-directory: ./bindings/ffi
- name: Test go
run: |
go mod tidy
go build
LD_LIBRARY_PATH=../../target/release ./regorus_test
working-directory: ./bindings/go

35
.github/workflows/test-java.yml vendored Normal file
View File

@@ -0,0 +1,35 @@
name: bindings/java
on:
push:
branches: [ "main" ]
pull_request:
branches: [ "main" ]
jobs:
test:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v4
with:
fetch-depth: 0
- uses: actions/setup-java@v4
with:
java-version: 8
distribution: "corretto"
- uses: dtolnay/rust-toolchain@stable
- name: Building binding
run: cargo build --release --manifest-path bindings/java/Cargo.toml
- name: Build jar
run: mvn package
working-directory: ./bindings/java
- name: Test jar
run: |
javac -cp target/regorus-java-0.1.5.jar Test.java
java -Djava.library.path=../../target/release -cp target/regorus-java-0.1.5.jar:. Test
working-directory: ./bindings/java

33
.github/workflows/test-musl.yml vendored Normal file
View File

@@ -0,0 +1,33 @@
name: musl
on:
push:
branches: [ "main" ]
pull_request:
branches: [ "main" ]
env:
CARGO_TERM_COLOR: always
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Add musl target
run: rustup target add x86_64-unknown-linux-musl
- name: Install musl-gcc
run: sudo apt update && sudo apt install -y musl-tools
- name: Build (MUSL)
run: cargo build --verbose --all-targets --target x86_64-unknown-linux-musl
- name: Run tests (MUSL)
run: cargo test -r --verbose --target x86_64-unknown-linux-musl
- name: Run tests (MUSL ACI)
run: cargo test -r --test aci --target x86_64-unknown-linux-musl
- name: Run tests (KATA ACI)
run: cargo test -r --test kata --target x86_64-unknown-linux-musl
- name: Run tests (MUSL OPA Conformance)
run: >-
cargo test -r --test opa --features opa-testutil,serde_json/arbitrary_precision --target x86_64-unknown-linux-musl -- $(tr '\n' ' ' < tests/opa.passing)

24
.github/workflows/test-no-std.yml vendored Normal file
View File

@@ -0,0 +1,24 @@
name: bindings/no-std
on:
push:
branches: [ "main" ]
pull_request:
branches: [ "main" ]
env:
CARGO_TERM_COLOR: always
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Add no_std target
run: rustup target add thumbv7m-none-eabi
- name: Build
run: cargo build -r --target thumbv7m-none-eabi
working-directory: ./tests/ensure_no_std

37
.github/workflows/test-python.yml vendored Normal file
View File

@@ -0,0 +1,37 @@
name: bindings/python
on:
push:
branches: [ "main" ]
pull_request:
branches: [ "main" ]
env:
PYTHON_VERSION: "3.10"
jobs:
test:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v4
with:
fetch-depth: 0
- uses: actions/setup-python@v4
with:
python-version: ${{ env.PYTHON_VERSION }}
architecture: x64
- name: Build wheels
uses: PyO3/maturin-action@63b75c597b83e247fbf4fb7719801cc4220ae9f3 # v1.43.0
with:
target: x86_64
args: --release --out dist --manifest-path bindings/python/Cargo.toml
sccache: 'true'
- name: Test wheel
run: |
pip3 install dist/regorus-*.whl
cd bindings/python
python3 test.py

View File

@@ -1,4 +1,4 @@
name: test-ruby
name: bindings/ruby
on:
push:
@@ -7,7 +7,7 @@ on:
branches: [ "main" ]
jobs:
setup:
test:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
@@ -16,7 +16,7 @@ jobs:
fetch-depth: 0
- name: Setup Ruby and Rust
uses: oxidize-rb/actions/setup-ruby-and-rust@v1
uses: oxidize-rb/actions/setup-ruby-and-rust@7ca44a16e287e5ff7dd72ab53f4bd41cbf34a571 #v1.26
with:
ruby-version: "3.3.1"
rustup-toolchain: "stable"

30
.github/workflows/test-wasm.yml vendored Normal file
View File

@@ -0,0 +1,30 @@
name: bindings/wasm
on:
push:
branches: [ "main" ]
pull_request:
branches: [ "main" ]
jobs:
test:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Setup Node
uses: actions/setup-node@v4
with:
node-version: 18
- name: Install wasmlpack
run: cargo install wasm-pack
- name: Test wasm binding
run: |
cd bindings/wasm
wasm-pack build --target nodejs --release
node test.js

37
.github/workflows/tests-debug.yml vendored Normal file
View File

@@ -0,0 +1,37 @@
name: tests/debug
on:
push:
branches: [ "main" ]
pull_request:
branches: [ "main" ]
env:
CARGO_TERM_COLOR: always
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Build (all features)
run: cargo build --all-features
- name: Build
run: cargo build
- name: Test no_std
run: cargo test --no-default-features
- name: Build only std
run: cargo build --example regorus --no-default-features --features "std"
- name: Doc Tests
run: cargo test --doc
- name: Run tests
run: cargo test
- name: Run tests (ACI)
run: cargo test --test aci
- name: Run tests (KATA)
run: cargo test --test kata
- name: Run tests (OPA Conformance)
run: >-
cargo test --test opa --features opa-testutil,serde_json/arbitrary_precision -- $(tr '\n' ' ' < tests/opa.passing)

View File

@@ -35,7 +35,7 @@ corrosion_import_crate(
CRATE_TYPES staticlib FLAGS --crate-type=staticlib
)
add_executable(regorus_test_nostd main.c)
add_executable(regorus_test main.c)
# Add path to <regorus-source-folder>/bindings/ffi
target_include_directories(regorus_test_nostd PRIVATE "../ffi")
target_link_libraries(regorus_test_nostd regorus-ffi)
target_include_directories(regorus_test PRIVATE "../ffi")
target_link_libraries(regorus_test regorus-ffi)

View File

@@ -7,13 +7,14 @@ char* file_to_string(const char* file) {
char * buffer = 0;
long length;
FILE * f = fopen (file, "rb");
if (f)
{
fseek (f, 0, SEEK_END);
length = ftell (f);
fseek (f, 0, SEEK_SET);
buffer = malloc (length);
buffer = malloc (length + 1);
buffer[length] = '\0';
if (buffer)
{
fread (buffer, 1, length, f);
@@ -26,8 +27,6 @@ char* file_to_string(const char* file) {
// If regorus is built with custom-allocator, then provide implementation.
uint8_t* regorus_aligned_alloc(size_t alignment, size_t size) {
printf("%ld %ld\n", size, alignment);
fflush(stdout);
return aligned_alloc(alignment, size);
}
@@ -47,18 +46,21 @@ int main() {
free(buffer);
if (r.status != RegorusStatusOk)
goto error;
printf("Loaded policy %s\n", r.output);
regorus_result_drop(r);
r = regorus_engine_add_policy(engine, "api.rego", (buffer = file_to_string("../../../tests/aci/api.rego")));
free(buffer);
if (r.status != RegorusStatusOk)
goto error;
printf("Loaded policy %s\n", r.output);
regorus_result_drop(r);
r = regorus_engine_add_policy(engine, "policy.rego", (buffer = file_to_string("../../../tests/aci/policy.rego")));
free(buffer);
if (r.status != RegorusStatusOk)
goto error;
printf("Loaded policy %s\n", r.output);
regorus_result_drop(r);
// Add data
@@ -83,14 +85,14 @@ int main() {
// Print output
printf("%s", r.output);
regorus_result_drop(r);
// Free the engine.
regorus_engine_drop(engine);
return 0;
error:
printf("%s", r.error_message);
return 1;
}

View File

@@ -10,16 +10,19 @@ int main() {
r = regorus_engine_add_policy_from_file(engine, "../../../tests/aci/framework.rego");
if (r.status != RegorusStatusOk)
goto error;
printf("Loaded policy %s\n", r.output);
regorus_result_drop(r);
r = regorus_engine_add_policy_from_file(engine, "../../../tests/aci/api.rego");
if (r.status != RegorusStatusOk)
goto error;
printf("Loaded policy %s\n", r.output);
regorus_result_drop(r);
r = regorus_engine_add_policy_from_file(engine, "../../../tests/aci/policy.rego");
if (r.status != RegorusStatusOk)
goto error;
printf("Loaded policy %s\n", r.output);
regorus_result_drop(r);
// Add data

View File

@@ -19,8 +19,14 @@ corrosion_import_crate(
MANIFEST_PATH "../ffi/Cargo.toml"
# Always build regorus in Release mode.
PROFILE "release"
# Only build the "regorusc" crate.
CRATES "regorus-ffi")
# Only build the "regorus-ffi" crate.
CRATES "regorus-ffi"
# Select specific features in regorus.
FEATURES "regorus/semver"
# Link statically
CRATE_TYPES "staticlib")
add_executable(regorus_test main.cpp)
# Add path to <regorus-source-folder>/bindings/ffi

View File

@@ -89,6 +89,7 @@ int main() {
std::cerr<<result.error()<<std::endl;
return -1;
}
std::cout<<"Loaded policy "<<result.output()<< std::endl;
}
{
auto result = engine.add_data_from_json_file("../../../tests/aci/data.json");

View File

@@ -1,4 +1,4 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Microsoft.NET.Sdk" InitialTargets="BuildRegorusFFI">
<Target Name="BuildRegorusFFI">
<Exec Command="cargo build -r --manifest-path ../ffi/Cargo.toml" />

View File

@@ -1,6 +1,6 @@
[package]
name = "regorus-ffi"
version = "0.1.0"
version = "0.1.5"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
@@ -13,7 +13,7 @@ regorus = { path = "../..", default-features = false }
serde_json = "1.0.113"
[features]
default = ["std"]
default = ["std", "regorus/full-opa"]
std = ["regorus/std"]
custom_allocator = []

View File

@@ -24,7 +24,7 @@ fn main() {
csbindgen::Builder::default()
.input_extern_file("src/lib.rs")
.csharp_dll_name("regorusc")
.csharp_dll_name("regorus_ffi")
.csharp_class_name("API")
.csharp_namespace("RegorusFFI")
.generate_csharp_file("./RegorusFFI.g.cs")

View File

@@ -39,14 +39,14 @@ fn to_c_str(s: String) -> *mut c_char {
}
}
fn from_c_str(s: *const c_char) -> Result<String> {
fn from_c_str(name: &str, s: *const c_char) -> Result<String> {
if s.is_null() {
bail!("null pointer");
}
unsafe {
CStr::from_ptr(s)
.to_str()
.map_err(|_| anyhow!("`path`: invalid utf8"))
.map_err(|e| anyhow!("`{name}`: invalid utf8.\n{e}"))
.map(|s| s.to_string())
}
}
@@ -70,6 +70,21 @@ fn to_regorus_result(r: Result<()>) -> RegorusResult {
}
}
fn to_regorus_string_result(r: Result<String>) -> RegorusResult {
match r {
Ok(s) => RegorusResult {
status: RegorusStatus::RegorusStatusOk,
output: to_c_str(s),
error_message: std::ptr::null_mut(),
},
Err(e) => RegorusResult {
status: RegorusStatus::RegorusStatusError,
output: std::ptr::null_mut(),
error_message: to_c_str(format!("{e}")),
},
}
}
/// Wrapper for `regorus::Engine`.
#[derive(Clone)]
pub struct RegorusEngine {
@@ -81,10 +96,13 @@ pub struct RegorusEngine {
/// `output` and `error_message` strings are not valid after drop.
#[no_mangle]
pub extern "C" fn regorus_result_drop(r: RegorusResult) {
if !r.error_message.is_null() {
unsafe {
unsafe {
if !r.error_message.is_null() {
let _ = CString::from_raw(r.error_message);
}
if !r.output.is_null() {
let _ = CString::from_raw(r.output);
}
}
}
@@ -133,10 +151,10 @@ pub extern "C" fn regorus_engine_add_policy(
path: *const c_char,
rego: *const c_char,
) -> RegorusResult {
to_regorus_result(|| -> Result<()> {
to_regorus_string_result(|| -> Result<String> {
to_ref(&engine)?
.engine
.add_policy(from_c_str(path)?, from_c_str(rego)?)
.add_policy(from_c_str("path", path)?, from_c_str("rego", rego)?)
}())
}
@@ -146,10 +164,10 @@ pub extern "C" fn regorus_engine_add_policy_from_file(
engine: *mut RegorusEngine,
path: *const c_char,
) -> RegorusResult {
to_regorus_result(|| -> Result<()> {
to_regorus_string_result(|| -> Result<String> {
to_ref(&engine)?
.engine
.add_policy_from_file(from_c_str(path)?)
.add_policy_from_file(from_c_str("path", path)?)
}())
}
@@ -165,7 +183,7 @@ pub extern "C" fn regorus_engine_add_data_json(
to_regorus_result(|| -> Result<()> {
to_ref(&engine)?
.engine
.add_data(regorus::Value::from_json_str(&from_c_str(data)?)?)
.add_data(regorus::Value::from_json_str(&from_c_str("data", data)?)?)
}())
}
@@ -178,7 +196,7 @@ pub extern "C" fn regorus_engine_add_data_from_json_file(
to_regorus_result(|| -> Result<()> {
to_ref(&engine)?
.engine
.add_data(regorus::Value::from_json_file(&from_c_str(path)?)?)
.add_data(regorus::Value::from_json_file(&from_c_str("path", path)?)?)
}())
}
@@ -205,7 +223,7 @@ pub extern "C" fn regorus_engine_set_input_json(
to_regorus_result(|| -> Result<()> {
to_ref(&engine)?
.engine
.set_input(regorus::Value::from_json_str(&from_c_str(input)?)?);
.set_input(regorus::Value::from_json_str(&from_c_str("input", input)?)?);
Ok(())
}())
}
@@ -219,7 +237,7 @@ pub extern "C" fn regorus_engine_set_input_from_json_file(
to_regorus_result(|| -> Result<()> {
to_ref(&engine)?
.engine
.set_input(regorus::Value::from_json_file(&from_c_str(path)?)?);
.set_input(regorus::Value::from_json_file(&from_c_str("path", path)?)?);
Ok(())
}())
}
@@ -236,7 +254,7 @@ pub extern "C" fn regorus_engine_eval_query(
let output = || -> Result<String> {
let results = to_ref(&engine)?
.engine
.eval_query(from_c_str(query)?, false)?;
.eval_query(from_c_str("query", query)?, false)?;
Ok(serde_json::to_string_pretty(&results)?)
}();
match output {

View File

@@ -1,3 +1,3 @@
module regorus-test
module regorus_test
go 1.21.5

View File

@@ -3,7 +3,7 @@ package main
import (
"fmt"
"os"
"regorus-test/pkg/regorus"
"regorus_test/pkg/regorus"
"time"
)

View File

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

View File

@@ -30,7 +30,7 @@ You then need to build Java bindings using:
$ mvn package
```
And you will have a JAR at `./target/regorus-java-0.0.1.jar`.
And you will have a JAR at `./target/regorus-java-0.1.5.jar`.
## Usage
@@ -60,10 +60,10 @@ You need to ensure artifacts built in [previous section](#building) are in Java'
For example with `java` CLI:
```bash
$ java -Djava.library.path=../../target/aarch64-apple-darwin/release/ -cp target/regorus-java-0.0.1.jar Test.java
$ java -Djava.library.path=../../target/aarch64-apple-darwin/release/ -cp target/regorus-java-0.1.5.jar Test.java
```
should gave you the output:
```
{"result":[{"expressions":[{"value":"Hello, World!","text":"data.test.message","location":{"row":1,"col":1}}]}]}
```
```

20
bindings/java/Test.java Normal file
View File

@@ -0,0 +1,20 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
import com.microsoft.regorus.Engine;
public class Test {
public static void main(String[] args) {
try (Engine engine = new Engine()) {
engine.addPolicy(
"hello.rego",
"package test\nmessage = concat(\", \", [input.message, data.message])"
);
engine.addDataJson("{\"message\":\"World!\"}");
engine.setInputJson("{\"message\":\"Hello\"}");
String resJson = engine.evalQuery("data.test.message");
System.out.println(resJson);
}
}
}

View File

@@ -9,7 +9,7 @@
<groupId>com.microsoft.regorus</groupId>
<artifactId>regorus-java</artifactId>
<version>0.0.1</version>
<version>0.1.5</version>
<name>Regorus Java</name>
<description>Java bindings for Regorus - a fast, lightweight Rego interpreter written in Rust</description>

View File

@@ -1,6 +1,6 @@
[package]
name = "regoruspy"
version = "0.1.0"
version = "0.1.5"
edition = "2021"
repository = "https://github.com/microsoft/regorus/bindings/python"
description = "Python bindings for Regorus - a fast, lightweight Rego interpreter written in Rust"

View File

@@ -33,12 +33,12 @@ impl Clone for Engine {
}
}
fn from<'source>(ob: &'source PyAny) -> Result<Value, PyErr> {
fn from<'source>(ob: &Bound<'_, PyAny>) -> Result<Value, PyErr> {
// dicts
Ok(if let Ok(dict) = ob.downcast::<PyDict>() {
let mut map = BTreeMap::new();
for (k, v) in dict {
map.insert(from(k)?, from(v)?);
map.insert(from(&k)?, from(&v)?);
}
map.into()
}
@@ -46,7 +46,7 @@ fn from<'source>(ob: &'source PyAny) -> Result<Value, PyErr> {
else if let Ok(pset) = ob.downcast::<PySet>() {
let mut set = BTreeSet::new();
for v in pset {
set.insert(from(v)?);
set.insert(from(&v)?);
}
set.into()
}
@@ -55,7 +55,7 @@ fn from<'source>(ob: &'source PyAny) -> Result<Value, PyErr> {
//
let mut set = BTreeSet::new();
for v in pfset {
set.insert(from(v)?);
set.insert(from(&v)?);
}
set.into()
}
@@ -63,30 +63,30 @@ fn from<'source>(ob: &'source PyAny) -> Result<Value, PyErr> {
else if let Ok(plist) = ob.downcast::<PyList>() {
let mut array = Vec::new();
for v in plist {
array.push(from(v)?);
array.push(from(&v)?);
}
array.into()
} else if let Ok(ptuple) = ob.downcast::<PyTuple>() {
let mut array = Vec::new();
for v in ptuple {
array.push(from(v)?);
array.push(from(&v)?);
}
array.into()
}
// String
else if let Ok(s) = String::extract(ob) {
else if let Ok(s) = ob.extract::<String>() {
s.into()
}
// Numeric
else if let Ok(v) = i64::extract(ob) {
else if let Ok(v) = ob.extract::<i64>() {
v.into()
} else if let Ok(v) = u64::extract(ob) {
} else if let Ok(v) = ob.extract::<u64>() {
v.into()
} else if let Ok(v) = f64::extract(ob) {
} else if let Ok(v) = ob.extract::<f64>() {
v.into()
}
// Boolean
else if let Ok(b) = bool::extract(ob) {
else if let Ok(b) = ob.extract::<bool>() {
b.into()
}
// None
@@ -97,7 +97,7 @@ fn from<'source>(ob: &'source PyAny) -> Result<Value, PyErr> {
else if let Ok(pseq) = ob.downcast::<PySequence>() {
let mut array = Vec::new();
for i in 0..pseq.len()? {
array.push(from(pseq.get_item(i)?)?);
array.push(from(&pseq.get_item(i)?)?);
}
array.into()
}
@@ -109,7 +109,7 @@ fn from<'source>(ob: &'source PyAny) -> Result<Value, PyErr> {
for i in 0..keys.len()? {
let key = keys.get_item(i)?;
let value = values.get_item(i)?;
map.insert(from(key)?, from(value)?);
map.insert(from(&key)?, from(&value)?);
}
map.into()
} else {
@@ -140,7 +140,7 @@ fn to(mut v: Value, py: Python<'_>) -> Result<PyObject> {
}
Value::Array(_) => {
let list = PyList::empty(py);
let list = PyList::empty_bound(py);
for v in std::mem::replace(v.as_array_mut()?, Vec::new()) {
list.append(to(v, py)?)?;
}
@@ -148,7 +148,7 @@ fn to(mut v: Value, py: Python<'_>) -> Result<PyObject> {
}
Value::Set(_) => {
let set = PySet::empty(py)?;
let set = PySet::empty_bound(py)?;
for v in std::mem::replace(v.as_set_mut()?, BTreeSet::new()) {
set.add(to(v, py)?)?;
}
@@ -156,7 +156,7 @@ fn to(mut v: Value, py: Python<'_>) -> Result<PyObject> {
}
Value::Object(_) => {
let dict = PyDict::new(py);
let dict = PyDict::new_bound(py);
for (k, v) in std::mem::replace(v.as_object_mut()?, BTreeMap::new()) {
dict.set_item(to(k, py)?, to(v, py)?)?;
}
@@ -181,7 +181,7 @@ impl Engine {
///
/// * `path`: A filename to be associated with the policy.
/// * `rego`: Rego policy.
pub fn add_policy(&mut self, path: String, rego: String) -> Result<()> {
pub fn add_policy(&mut self, path: String, rego: String) -> Result<String> {
self.engine.add_policy(path, rego)
}
@@ -190,15 +190,21 @@ impl Engine {
/// The policy is parsed into AST.
///
/// * `path`: Path to the policy file.
pub fn add_policy_from_file(&mut self, path: String) -> Result<()> {
pub fn add_policy_from_file(&mut self, path: String) -> Result<String> {
self.engine.add_policy_from_file(path)
}
/// Get the list of packages defined by loaded policies.
///
pub fn get_packages(&mut self) -> Result<Vec<String>> {
self.engine.get_packages()
}
/// Add policy data.
///
/// * `data`: Rego value. A Rego value is a number, bool, string, None
/// or a list/set/map whose items themselves are Rego values.
pub fn add_data(&mut self, data: &PyAny) -> Result<()> {
pub fn add_data(&mut self, data: &Bound<'_, PyAny>) -> Result<()> {
let data = from(data)?;
self.engine.add_data(data)
}
@@ -229,7 +235,7 @@ impl Engine {
///
/// * `input`: Rego value. A Rego value is a number, bool, string, None
/// or a list/set/map whose items themselves are Rego values.
pub fn set_input(&mut self, input: &PyAny) -> Result<()> {
pub fn set_input(&mut self, input: &Bound<'_, PyAny>) -> Result<()> {
let input = from(input)?;
self.engine.set_input(input);
Ok(())
@@ -259,17 +265,17 @@ impl Engine {
pub fn eval_query(&mut self, query: String, py: Python<'_>) -> Result<PyObject> {
let results = self.engine.eval_query(query, false)?;
let rlist = PyList::empty(py);
let rlist = PyList::empty_bound(py);
for result in results.result.into_iter() {
let rdict = PyDict::new(py);
let rdict = PyDict::new_bound(py);
let elist = PyList::empty(py);
let elist = PyList::empty_bound(py);
for expr in result.expressions.into_iter() {
let edict = PyDict::new(py);
let edict = PyDict::new_bound(py);
edict.set_item("value".to_object(py), to(expr.value, py)?)?;
edict.set_item("text".to_object(py), expr.text.as_ref().to_object(py))?;
let ldict = PyDict::new(py);
let ldict = PyDict::new_bound(py);
ldict.set_item("row".to_object(py), expr.location.row.to_object(py))?;
ldict.set_item("col".to_object(py), expr.location.col.to_object(py))?;
@@ -281,7 +287,7 @@ impl Engine {
rdict.set_item("bindings".to_object(py), to(result.bindings, py)?)?;
rlist.append(rdict)?;
}
let dict = PyDict::new(py);
let dict = PyDict::new_bound(py);
dict.set_item("result".to_object(py), rlist)?;
Ok(dict.into())
}
@@ -296,6 +302,6 @@ impl Engine {
}
#[pymodule]
pub fn regorus(_py: Python<'_>, m: &PyModule) -> PyResult<()> {
pub fn regorus(_py: Python<'_>, m: &Bound<'_, PyModule>) -> PyResult<()> {
m.add_class::<crate::Engine>()
}

View File

@@ -7,9 +7,14 @@ import regorus
engine = regorus.Engine()
# Load policies
engine.add_policy_from_file('../../tests/aci/framework.rego')
engine.add_policy_from_file('../../tests/aci/api.rego')
engine.add_policy_from_file('../../tests/aci/policy.rego')
pkg = engine.add_policy_from_file('../../tests/aci/framework.rego')
print(' Loaded Policy %s' % pkg)
pkg = engine.add_policy_from_file('../../tests/aci/api.rego')
print(' Loaded Policy %s' % pkg)
pkg = engine.add_policy_from_file('../../tests/aci/policy.rego')
print(' Loaded Policy %s' % pkg)
# Add policy data
data = {

View File

@@ -1,6 +1,6 @@
[package]
name = "regorusrb"
version = "0.1.0"
version = "0.1.5"
edition = "2021"
description = "Ruby bindings for Regorus - a fast, lightweight Rego interpreter written in Rust"
publish = false

View File

@@ -1,6 +1,6 @@
[package]
name = "regorusjs"
version = "0.1.0"
version = "0.1.5"
edition = "2021"
repository = "https://github.com/microsoft/regorus/bindings/wasm"
description = "WASM bindings for Regorus - a fast, lightweight Rego interpreter written in Rust"

View File

@@ -50,7 +50,7 @@ impl Engine {
///
/// * `path`: A filename to be associated with the policy.
/// * `rego`: Rego policy.
pub fn add_policy(&mut self, path: String, rego: String) -> Result<(), JsValue> {
pub fn add_policy(&mut self, path: String, rego: String) -> Result<String, JsValue> {
self.engine.add_policy(path, rego).map_err(error_to_jsvalue)
}

View File

@@ -7,7 +7,7 @@ var regorus = require('./pkg/regorusjs')
var engine = new regorus.Engine();
// Add Rego policy.
engine.add_policy(
var pkg = engine.add_policy(
// Associate this file name with policy
'hello.rego',
@@ -18,6 +18,7 @@ engine.add_policy(
# Join messages
message = concat(", ", [input.message, data.message])
`)
console.log("Loaded policy " + pkg)
// Set policy data
engine.add_data_json(`
@@ -34,7 +35,7 @@ engine.set_input_json(`
`)
// Eval query
results = engine.eval_query('data.test.message')
var results = engine.eval_query('data.test.message')
// Display
console.log(results)