From 761d11ef4871478ebdd1f16bbfec19549a756fa7 Mon Sep 17 00:00:00 2001 From: Anand Krishnamoorthi <35780660+anakrish@users.noreply.github.com> Date: Thu, 1 Feb 2024 13:47:27 -0800 Subject: [PATCH] Document bindings (#119) * Instructions for WASM/JS binding Signed-off-by: Anand Krishnamoorthi * Document Python, WASM/JS bindings Signed-off-by: Anand Krishnamoorthi --------- Signed-off-by: Anand Krishnamoorthi --- bindings/python/README.md | 67 +++++++++++++++++++++++++++++++++++++ bindings/python/building.md | 22 ++++++++++++ bindings/python/src/lib.rs | 29 ++++++++++++++-- bindings/python/test.py | 52 ++++++++++++++++++++++++++++ bindings/wasm/README.md | 6 +++- bindings/wasm/building.md | 34 +++++++++++++++++++ bindings/wasm/test.js | 47 ++++++++++++++++++++++++++ 7 files changed, 254 insertions(+), 3 deletions(-) create mode 100644 bindings/python/README.md create mode 100644 bindings/python/building.md create mode 100644 bindings/python/test.py create mode 100644 bindings/wasm/building.md create mode 100644 bindings/wasm/test.js diff --git a/bindings/python/README.md b/bindings/python/README.md new file mode 100644 index 00000000..2e91aa25 --- /dev/null +++ b/bindings/python/README.md @@ -0,0 +1,67 @@ +# regorus + +**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. + +Regorus can be used in Python via `regorus` package. (It is not yet available in PyPI, but can be manually built.) + +See [Repository](https://github.com/microsoft/regorus). + +To build this binding, see [building](https://github.com/microsoft/regorus/bindings/python/building.md) + +## Usage +```Python +import regorus + +# Create engine +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') + +# Add policy data +data = { + "metadata": { + "devices": { + "/run/layers/p0-layer0": "1b80f120dbd88e4355d6241b519c3e25290215c469516b49dece9cf07175a766", + "/run/layers/p0-layer1": "e769d7487cc314d3ee748a4440805317c19262c7acd2fdbdb0d47d2e4613a15c", + "/run/layers/p0-layer2": "eb36921e1f82af46dfe248ef8f1b3afb6a5230a64181d960d10237a08cd73c79", + "/run/layers/p0-layer3": "41d64cdeb347bf236b4c13b7403b633ff11f1cf94dbc7cf881a44d6da88c5156", + "/run/layers/p0-layer4": "4dedae42847c704da891a28c25d32201a1ae440bce2aecccfa8e6f03b97a6a6c", + "/run/layers/p0-layer5": "fe84c9d5bfddd07a2624d00333cf13c1a9c941f3a261f13ead44fc6a93bc0e7a" + } + } +} +engine.add_data(data) + +# Set input +input = { + "containerID": "container0", + "layerPaths": [ + "/run/layers/p0-layer0", + "/run/layers/p0-layer1", + "/run/layers/p0-layer2", + "/run/layers/p0-layer3", + "/run/layers/p0-layer4", + "/run/layers/p0-layer5" + ], + "target": "/run/gcs/c/container0/rootfs" +} +engine.set_input(input) + +# Eval query +results = engine.eval_query('data.framework.mount_overlay=x') + +# Print results +print(results['result'][0]) + +# Eval query as json +results_json = engine.eval_query_as_json('data.framework.mount_overlay=x') +print(results_json) +``` + diff --git a/bindings/python/building.md b/bindings/python/building.md new file mode 100644 index 00000000..77e4182f --- /dev/null +++ b/bindings/python/building.md @@ -0,0 +1,22 @@ +- Install maturin + ``` + pipx install maturin + ``` + See [Maturin User Guide](https://www.maturin.rs) + +- Build bindings for Python + ``` + cd bindings/python + maturin build --release --target-dir wheels + ``` + +- Install python wheel + ``` + pip3 install ../../target/wheels/regorus*.whl --force-reinstall + ``` + +- Run test script + ``` + python3 test.py + ``` + diff --git a/bindings/python/src/lib.rs b/bindings/python/src/lib.rs index eb816400..ee1dc93d 100644 --- a/bindings/python/src/lib.rs +++ b/bindings/python/src/lib.rs @@ -182,8 +182,16 @@ 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<()> { - self.engine.add_policy(path, rego)?; - Ok(()) + self.engine.add_policy(path, rego) + } + + /// Add a policy from given file. + /// + /// The policy is parsed into AST. + /// + /// * `path`: Path to the policy file. + pub fn add_policy_from_file(&mut self, path: String) -> Result<()> { + self.engine.add_policy_from_file(path) } /// Add policy data. @@ -203,6 +211,14 @@ impl Engine { self.engine.add_data(data) } + /// Add policy data from file. + /// + /// * `path`: Path to JSON policy data. + pub fn add_data_from_json_file(&mut self, path: String) -> Result<()> { + let data = Value::from_json_file(&path)?; + self.engine.add_data(data) + } + /// Clear policy data. pub fn clear_data(&mut self) -> Result<()> { self.engine.clear_data(); @@ -228,6 +244,15 @@ impl Engine { Ok(()) } + /// Set input. + /// + /// * `path`: Path to JSON input data. + pub fn set_input_from_json_file(&mut self, path: String) -> Result<()> { + let input = Value::from_json_file(&path)?; + self.engine.set_input(input); + Ok(()) + } + /// Evaluate query. /// /// * `query`: Rego expression to be evaluate. diff --git a/bindings/python/test.py b/bindings/python/test.py new file mode 100644 index 00000000..9cf0d592 --- /dev/null +++ b/bindings/python/test.py @@ -0,0 +1,52 @@ +# Copyright (c) Microsoft Corporation. +# Licensed under the MIT License. + +import regorus + +# Create engine +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') + +# Add policy data +data = { + "metadata": { + "devices": { + "/run/layers/p0-layer0": "1b80f120dbd88e4355d6241b519c3e25290215c469516b49dece9cf07175a766", + "/run/layers/p0-layer1": "e769d7487cc314d3ee748a4440805317c19262c7acd2fdbdb0d47d2e4613a15c", + "/run/layers/p0-layer2": "eb36921e1f82af46dfe248ef8f1b3afb6a5230a64181d960d10237a08cd73c79", + "/run/layers/p0-layer3": "41d64cdeb347bf236b4c13b7403b633ff11f1cf94dbc7cf881a44d6da88c5156", + "/run/layers/p0-layer4": "4dedae42847c704da891a28c25d32201a1ae440bce2aecccfa8e6f03b97a6a6c", + "/run/layers/p0-layer5": "fe84c9d5bfddd07a2624d00333cf13c1a9c941f3a261f13ead44fc6a93bc0e7a" + } + } +} +engine.add_data(data) + +# Set input +input = { + "containerID": "container0", + "layerPaths": [ + "/run/layers/p0-layer0", + "/run/layers/p0-layer1", + "/run/layers/p0-layer2", + "/run/layers/p0-layer3", + "/run/layers/p0-layer4", + "/run/layers/p0-layer5" + ], + "target": "/run/gcs/c/container0/rootfs" +} +engine.set_input(input) + +# Eval query +results = engine.eval_query('data.framework.mount_overlay=x') + +# Print results +print(results['result'][0]) + +# Eval query as json +results_json = engine.eval_query_as_json('data.framework.mount_overlay=x') +print(results_json) diff --git a/bindings/wasm/README.md b/bindings/wasm/README.md index b0dbd669..fb3e8703 100644 --- a/bindings/wasm/README.md +++ b/bindings/wasm/README.md @@ -6,9 +6,13 @@ interpreter written in Rust. - *Rigorous* - A rigorous enforcer of well-defined Rego semantics. +`regorusjs` is Regorus compiled into WASM. + See [Repository](https://github.com/microsoft/regorus). -`regorusjs` is Regorus compiled into WASM. +To build this binding, see [building](https://github.com/microsoft/regorus/bindings/wasm/building.md) + + ## Usage diff --git a/bindings/wasm/building.md b/bindings/wasm/building.md new file mode 100644 index 00000000..12fefbaa --- /dev/null +++ b/bindings/wasm/building.md @@ -0,0 +1,34 @@ + +- Install `wasm-pack` + ``` + cargo install wasm-pack + ``` + +- Build `regorusjs` for nodejs. + ``` + cd bindings/wasm + wasm-pack build --target nodejs --release + ``` + +- Install [nodejs](https://nodejs.org/en/download) + +- Run the test script + ``` + $ node test.js + \\{ + \\ "result": [ + \\ { + \\ "expressions": [ + \\ { + \\ "value": "Hello, World!", + \\ "text": "data.test.message", + \\ "location": { + \\ "row": 1, + \\ "col": 1 + \\ } + \\ } + \\ ] + \\ } + \\ ] + \\} + ``` diff --git a/bindings/wasm/test.js b/bindings/wasm/test.js new file mode 100644 index 00000000..bd2d7ddc --- /dev/null +++ b/bindings/wasm/test.js @@ -0,0 +1,47 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +var regorus = require('./pkg/regorusjs') + +// Create an engine. +var engine = new regorus.Engine(); + +// Add Rego policy. +engine.add_policy( + // Associate this file name with policy + 'hello.rego', + + // Rego policy +` + package test + + # Join messages + message = concat(", ", [input.message, data.message]) +`) + +// Set policy data +engine.add_data_json(` + { + "message" : "World!" + } +`) + +// Set policy input +engine.set_input_json(` + { + "message" : "Hello" + } +`) + +// Eval query +results = engine.eval_query('data.test.message') + +// Display +console.log(results) + +// Convert results to object +results = JSON.parse(results) + +// Process result +console.log(results.result[0].expressions[0].value) +