mirror of
https://github.com/microsoft/regorus.git
synced 2026-08-05 02:16:11 +00:00
WASM binding (#114)
Signed-off-by: Anand Krishnamoorthi <anakrish@microsoft.com>
This commit is contained in:
committed by
GitHub
parent
0af97840f7
commit
055bdd295f
23
.github/workflows/publish-wasm.yml
vendored
Normal file
23
.github/workflows/publish-wasm.yml
vendored
Normal file
@@ -0,0 +1,23 @@
|
||||
name: publish-wasm
|
||||
|
||||
permissions:
|
||||
pull-requests: write
|
||||
contents: write
|
||||
|
||||
on: workflow_dispatch
|
||||
|
||||
jobs:
|
||||
publish-wasm:
|
||||
name: publish
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- name: Install wasm-pack
|
||||
run: curl https://rustwasm.github.io/wasm-pack/installer/init.sh -sSf | sh
|
||||
- name: Build
|
||||
run: wasm-pack build --target nodejs -r
|
||||
- name: Publish
|
||||
run: # TODO
|
||||
8
.github/workflows/rust.yml
vendored
8
.github/workflows/rust.yml
vendored
@@ -37,3 +37,11 @@ jobs:
|
||||
- name: Run tests (OPA Conformance)
|
||||
run: >-
|
||||
cargo test -r --test opa -- $(tr '\n' ' ' < tests/opa.passing)
|
||||
|
||||
- name: Install wasm-pack
|
||||
run: curl https://rustwasm.github.io/wasm-pack/installer/init.sh -sSf | sh
|
||||
|
||||
- name: Run wasm binding tests
|
||||
run: |
|
||||
cd bindings/wasm
|
||||
wasm-pack test --node -r
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
workspace = { members = ["bindings/wasm"] }
|
||||
[package]
|
||||
name = "regorus"
|
||||
description = "A fast, lightweight Rego (OPA policy language) interpreter"
|
||||
|
||||
@@ -61,6 +61,12 @@ $ cargo build -r --example regorus --features "yaml" --no-default-features; stri
|
||||
Regorus passes the [OPA v0.60.0 test-suite](https://www.openpolicyagent.org/docs/latest/ir/#test-suite) barring a few
|
||||
builtins. See [OPA Conformance](#opa-conformance) below.
|
||||
|
||||
## Bindings
|
||||
|
||||
Regorus can be used from a variety of languages:
|
||||
|
||||
- Javascript (nodejs): Via npm package `regorus-wasm`. This package is Regorus compiled into WASM.
|
||||
|
||||
## Getting Started
|
||||
|
||||
[examples/regorus](https://github.com/microsoft/regorus/blob/main/examples/regorus.rs) is an example program that
|
||||
|
||||
19
bindings/wasm/Cargo.toml
Normal file
19
bindings/wasm/Cargo.toml
Normal file
@@ -0,0 +1,19 @@
|
||||
[package]
|
||||
name = "regorus-wasm"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
repository = "https://github.com/microsoft/regorus/bindings/wasm"
|
||||
description = "WASM bindings for Regorus - a fast, lightweight Rego interpreter written in Rust"
|
||||
keywords = ["interpreter", "opa", "policy-as-code", "rego"]
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
[lib]
|
||||
crate-type = ["cdylib"]
|
||||
|
||||
[dependencies]
|
||||
regorus = { path = "../.." }
|
||||
serde_json = "1.0.111"
|
||||
wasm-bindgen = "0.2.90"
|
||||
|
||||
[dev-dependencies]
|
||||
wasm-bindgen-test = "0.3.40"
|
||||
28
bindings/wasm/README.md
Normal file
28
bindings/wasm/README.md
Normal file
@@ -0,0 +1,28 @@
|
||||
# regorus-wasm
|
||||
|
||||
**Regorus** is
|
||||
|
||||
- *Rego*-*Rus(t)* - A fast, light-weight [Rego](https://www.openpolicyagent.org/docs/latest/policy-language/)
|
||||
interpreter written in Rust.
|
||||
- *Rigorous* - A rigorous enforcer of well-defined Rego semantics.
|
||||
|
||||
See [Repository](https://github.com/microsoft/regorus).
|
||||
|
||||
`regorus-wasm` is Regorus compiled into WASM.
|
||||
|
||||
## Usage
|
||||
|
||||
In nodejs,
|
||||
|
||||
``javascript
|
||||
|
||||
var regorus = require('regorus-wasm')
|
||||
|
||||
// Create an engine.
|
||||
var engine = new regorus.Engine();
|
||||
|
||||
// Add Rego policy.
|
||||
engine.add_policy()
|
||||
|
||||
|
||||
```
|
||||
138
bindings/wasm/src/lib.rs
Normal file
138
bindings/wasm/src/lib.rs
Normal file
@@ -0,0 +1,138 @@
|
||||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
use wasm_bindgen::prelude::*;
|
||||
|
||||
#[wasm_bindgen]
|
||||
/// WASM wrapper for [`regorus::Engine`]
|
||||
pub struct Engine {
|
||||
engine: regorus::Engine,
|
||||
}
|
||||
|
||||
fn error_to_jsvalue<E: std::fmt::Display>(e: E) -> JsValue {
|
||||
JsValue::from_str(&format!("{e}"))
|
||||
}
|
||||
|
||||
impl Default for Engine {
|
||||
fn default() -> Self {
|
||||
Self::new()
|
||||
}
|
||||
}
|
||||
|
||||
impl Clone for Engine {
|
||||
/// Clone a [`Engine`]
|
||||
///
|
||||
/// To avoid having to parse same policy again, the engine can be cloned
|
||||
/// after policies and data have been added.
|
||||
fn clone(&self) -> Self {
|
||||
Self {
|
||||
engine: self.engine.clone(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[wasm_bindgen]
|
||||
impl Engine {
|
||||
#[wasm_bindgen(constructor)]
|
||||
/// Construct a new Engine
|
||||
///
|
||||
/// See https://docs.rs/regorus/latest/regorus/struct.Engine.html
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
engine: regorus::Engine::new(),
|
||||
}
|
||||
}
|
||||
|
||||
/// 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.
|
||||
pub fn add_policy(&mut self, path: String, rego: String) -> Result<(), JsValue> {
|
||||
self.engine.add_policy(path, rego).map_err(error_to_jsvalue)
|
||||
}
|
||||
|
||||
/// 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.
|
||||
pub fn add_data_json(&mut self, data: String) -> Result<(), JsValue> {
|
||||
let data = regorus::Value::from_json_str(&data).map_err(error_to_jsvalue)?;
|
||||
self.engine.add_data(data).map_err(error_to_jsvalue)
|
||||
}
|
||||
|
||||
/// Set input.
|
||||
///
|
||||
/// See https://docs.rs/regorus/0.1.0-alpha.2/regorus/struct.Engine.html#method.set_input
|
||||
/// * `input`: JSON encoded value to be used as input to query.
|
||||
pub fn set_input_json(&mut self, input: String) -> Result<(), JsValue> {
|
||||
let input = regorus::Value::from_json_str(&input).map_err(error_to_jsvalue)?;
|
||||
self.engine.set_input(input);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Evaluate query.
|
||||
///
|
||||
/// See https://docs.rs/regorus/0.1.0-alpha.2/regorus/struct.Engine.html#method.eval_query
|
||||
/// * `query`: Rego expression to be evaluate.
|
||||
pub fn eval_query(&mut self, query: String) -> Result<String, JsValue> {
|
||||
let results = self
|
||||
.engine
|
||||
.eval_query(query, false)
|
||||
.map_err(error_to_jsvalue)?;
|
||||
serde_json::to_string_pretty(&results).map_err(error_to_jsvalue)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use wasm_bindgen::prelude::*;
|
||||
use wasm_bindgen_test::wasm_bindgen_test;
|
||||
|
||||
#[wasm_bindgen_test]
|
||||
pub fn basic() -> Result<(), JsValue> {
|
||||
let mut engine = crate::Engine::new();
|
||||
|
||||
// Exercise all APIs.
|
||||
engine.add_data_json(
|
||||
r#"
|
||||
{
|
||||
"foo" : "bar"
|
||||
}
|
||||
"#
|
||||
.to_string(),
|
||||
)?;
|
||||
|
||||
engine.set_input_json(
|
||||
r#"
|
||||
{
|
||||
"message" : "Hello"
|
||||
}
|
||||
"#
|
||||
.to_string(),
|
||||
)?;
|
||||
|
||||
engine.add_policy(
|
||||
"hello.rego".to_string(),
|
||||
r#"
|
||||
package test
|
||||
message = input.message"#
|
||||
.to_string(),
|
||||
)?;
|
||||
|
||||
let results = engine.eval_query("data".to_string())?;
|
||||
let r = regorus::Value::from_json_str(&results).map_err(crate::error_to_jsvalue)?;
|
||||
|
||||
let v = &r["result"][0]["expressions"][0]["value"];
|
||||
|
||||
// Ensure that input and policy were evaluated.
|
||||
assert_eq!(v["test"]["message"], regorus::Value::from("Hello"));
|
||||
|
||||
// Test that data was set.
|
||||
assert_eq!(v["foo"], regorus::Value::from("bar"));
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user