KEMBAR78
Engine in regorus - Rust

Engine

Struct Engine 

Source
pub struct Engine { /* private fields */ }
Expand description

The Rego evaluation engine.

Implementations§

Source§

impl Engine

Source

pub fn new() -> Self

Create an instance of Engine.

Source

pub fn set_rego_v0(&mut self, rego_v0: bool)

Enable rego v0.

Note that regorus now defaults to v1.

let mut engine = Engine::new();

// Enable v0 for old style policies.
engine.set_rego_v0(true);

engine.add_policy(
   "test.rego".to_string(),
   r#"
   package test

   allow { # v0 syntax does not require if keyword
      1 < 2
   }
   "#.to_string())?;
Source

pub fn add_policy(&mut self, path: String, rego: String) -> Result<String>

Add a policy.

The policy file will be parsed and converted to AST representation. Multiple policy files may be added to the engine. Returns the Rego package name declared in the policy.

  • path: A filename to be associated with the policy.
  • rego: The rego policy code.
let mut engine = Engine::new();

let package = engine.add_policy(
   "test.rego".to_string(),
   r#"
   package test
   allow = input.user == "root"
   "#.to_string())?;

assert_eq!(package, "data.test");
Source

pub fn add_policy_from_file<P: AsRef<Path>>( &mut self, path: P, ) -> Result<String>

Available on crate feature std only.

Add a policy from a given file.

The policy file will be parsed and converted to AST representation. Multiple policy files may be added to the engine. Returns the Rego package name declared in the policy.

  • path: Path to the policy file (.rego).
let mut engine = Engine::new();
// framework.rego does not conform to v1.
engine.set_rego_v0(true);

let package = engine.add_policy_from_file("tests/aci/framework.rego")?;

assert_eq!(package, "data.framework");
Source

pub fn get_packages(&self) -> Result<Vec<String>>

Get the list of packages defined by loaded policies.

let mut engine = Engine::new();
// framework.rego does not conform to v1.
engine.set_rego_v0(true);

let _ = engine.add_policy_from_file("tests/aci/framework.rego")?;

// Package names can be different from file names.
let _ = engine.add_policy("policy.rego".into(), "package hello.world".into())?;

assert_eq!(engine.get_packages()?, vec!["data.framework", "data.hello.world"]);
Source

pub fn get_policies(&self) -> Result<Vec<Source>>

Get the list of policy files.


let pkg = engine.add_policy("hello.rego".to_string(), "package test".to_string())?;
assert_eq!(pkg, "data.test");

let policies = engine.get_policies()?;

assert_eq!(policies[0].get_path(), "hello.rego");
assert_eq!(policies[0].get_contents(), "package test");
Source

pub fn get_policies_as_json(&self) -> Result<String>

Get the list of policy files as a JSON object.


let pkg = engine.add_policy("hello.rego".to_string(), "package test".to_string())?;
assert_eq!(pkg, "data.test");

let policies = engine.get_policies_as_json()?;

let v = Value::from_json_str(&policies)?;
assert_eq!(v[0]["path"].as_string()?.as_ref(), "hello.rego");
assert_eq!(v[0]["contents"].as_string()?.as_ref(), "package test");
Source

pub fn set_input(&mut self, input: Value)

Set the input document.

  • input: Input documented. Typically this Value is constructed from JSON or YAML.
let mut engine = Engine::new();

let input = Value::from_json_str(r#"
{
  "role" : "admin",
  "action": "delete"
}"#)?;

engine.set_input(input);
Source

pub fn set_input_json(&mut self, input_json: &str) -> Result<()>

Source

pub fn clear_data(&mut self)

Clear the data document.

The data document will be reset to an empty object.

let mut engine = Engine::new();

engine.clear_data();

// Evaluate data.
let results = engine.eval_query("data".to_string(), false)?;

// Assert that it is empty object.
assert_eq!(results.result.len(), 1);
assert_eq!(results.result[0].expressions.len(), 1);
assert_eq!(results.result[0].expressions[0].value, Value::new_object());
Source

pub fn add_data(&mut self, data: Value) -> Result<()>

Add data document.

The specified data document is merged into existing data document.

let mut engine = Engine::new();

// Only objects can be added.
assert!(engine.add_data(Value::from_json_str("[]")?).is_err());

// Merge { "x" : 1, "y" : {} }
assert!(engine.add_data(Value::from_json_str(r#"{ "x" : 1, "y" : {}}"#)?).is_ok());

// Merge { "z" : 2 }
assert!(engine.add_data(Value::from_json_str(r#"{ "z" : 2 }"#)?).is_ok());

// Merge { "z" : 3 }. Conflict error.
assert!(engine.add_data(Value::from_json_str(r#"{ "z" : 3 }"#)?).is_err());

assert_eq!(
  engine.eval_query("data".to_string(), false)?.result[0].expressions[0].value,
  Value::from_json_str(r#"{ "x": 1, "y": {}, "z": 2}"#)?
);
Source

pub fn get_data(&self) -> Value

Get the data document.

The returned value is the data document that has been constructed using one or more calls to [Engine::pre]. The values of policy rules are not included in the returned document.

let mut engine = Engine::new();

// If not set, data document is empty.
assert_eq!(engine.get_data(), Value::new_object());

// Merge { "x" : 1, "y" : {} }
assert!(engine.add_data(Value::from_json_str(r#"{ "x" : 1, "y" : {}}"#)?).is_ok());

// Merge { "z" : 2 }
assert!(engine.add_data(Value::from_json_str(r#"{ "z" : 2 }"#)?).is_ok());

let data = engine.get_data();
assert_eq!(data["x"], Value::from(1));
assert_eq!(data["y"], Value::new_object());
assert_eq!(data["z"], Value::from(2));
Source

pub fn add_data_json(&mut self, data_json: &str) -> Result<()>

Source

pub fn set_strict_builtin_errors(&mut self, b: bool)

Set whether builtins should raise errors strictly or not.

Regorus differs from OPA in that by default builtins will raise errors instead of returning Undefined.


§NOTE: Currently not all builtins honor this flag and will always strictly raise errors.
Source

pub fn compile_for_target(&mut self) -> Result<CompiledPolicy>

Available on crate feature azure_policy only.

Compiles a target-aware policy from the current engine state.

This method creates a compiled policy that can work with Azure Policy targets, enabling resource type inference and target-specific evaluation. The compiled policy will automatically detect and handle __target__ declarations in the loaded modules.

The engine must have been prepared with:

§Returns

Returns a CompiledPolicy that can be used for efficient policy evaluation with target support, including resource type inference capabilities.

§Examples
§Basic Target-Aware Compilation
use regorus::*;

let mut engine = Engine::new();
engine.add_data(Value::from_json_str(r#"{"allowed_sizes": ["small", "medium"]}"#)?)?;
engine.add_policy("policy.rego".to_string(), r#"
    package policy.test
    import rego.v1
    __target__ := "target.tests.sample_test_target"
     
    default allow := false
    allow if {
        input.type == "vm"
        input.size in data.allowed_sizes
    }
"#.to_string())?;

let compiled = engine.compile_for_target()?;
let result = compiled.eval_with_input(Value::from_json_str(r#"{"type": "vm", "size": "small"}"#)?)?;
§Target Registration and Usage
use regorus::*;
use regorus::registry::targets;
use regorus::target::Target;
use std::sync::Arc;

// Register a target first
let target_json = r#"
{
  "name": "target.example.vm_policy",
  "description": "Simple VM validation target",
  "version": "1.0.0",
  "resource_schema_selector": "type",
  "resource_schemas": [
    {
      "type": "object",
      "properties": {
        "name": { "type": "string" },
        "type": { "const": "vm" },
        "size": { "enum": ["small", "medium", "large"] }
      },
      "required": ["name", "type", "size"]
    }
  ],
  "effects": {
    "allow": { "type": "boolean" },
    "deny": { "type": "boolean" }
  }
}
"#;

let target = Target::from_json_str(target_json)?;
targets::register(Arc::new(target))?;

// Use the target in a policy
let mut engine = Engine::new();
engine.add_data(Value::from_json_str(r#"{"allowed_locations": ["us-east"]}"#)?)?;
engine.add_policy("vm_policy.rego".to_string(), r#"
    package vm.validation
    import rego.v1
    __target__ := "target.example.vm_policy"
     
    default allow := false
    allow if {
        input.type == "vm"
        input.size in ["small", "medium"]
    }
"#.to_string())?;

let compiled = engine.compile_for_target()?;
let result = compiled.eval_with_input(Value::from_json_str(r#"
{
  "name": "test-vm",
  "type": "vm",
  "size": "small"
}"#)?)?;
assert_eq!(result, Value::from(true));
§Notes
  • This method is only available when the azure_policy feature is enabled
  • Automatically enables print gathering for debugging purposes
  • Requires that at least one module contains a __target__ declaration
  • The target referenced must be registered in the target registry
§See Also
Source

pub fn compile_with_entrypoint( &mut self, rule: &Rc<str>, ) -> Result<CompiledPolicy>

Compiles a policy with a specific entry point rule.

This method creates a compiled policy that evaluates a specific rule as the entry point. Unlike Engine::compile_for_target, this method requires you to explicitly specify which rule should be evaluated and does not automatically handle target-specific features.

The engine must have been prepared with:

§Arguments
  • rule - The specific rule path to evaluate (e.g., “data.policy.allow”)
§Returns

Returns a CompiledPolicy that can be used for efficient policy evaluation focused on the specified entry point rule.

§Examples
§Basic Usage
use regorus::*;
use std::rc::Rc;

let mut engine = Engine::new();
engine.add_data(Value::from_json_str(r#"{"allowed_users": ["alice", "bob"]}"#)?)?;
engine.add_policy("authz.rego".to_string(), r#"
    package authz
    import rego.v1
     
    default allow := false
    allow if {
        input.user in data.allowed_users
        input.action == "read"
    }
     
    deny if {
        input.user == "guest"
    }
"#.to_string())?;

let compiled = engine.compile_with_entrypoint(&"data.authz.allow".into())?;
let result = compiled.eval_with_input(Value::from_json_str(r#"{"user": "alice", "action": "read"}"#)?)?;
assert_eq!(result, Value::from(true));
§Multi-Module Policy
use regorus::*;
use std::rc::Rc;

let mut engine = Engine::new();
engine.add_data(Value::from_json_str(r#"{"departments": {"engineering": ["alice"], "hr": ["bob"]}}"#)?)?;

engine.add_policy("users.rego".to_string(), r#"
    package users
    import rego.v1
     
    user_department(user) := dept if {
        dept := [d | data.departments[d][_] == user][0]
    }
"#.to_string())?;

engine.add_policy("permissions.rego".to_string(), r#"
    package permissions
    import rego.v1
    import data.users
     
    default allow := false
    allow if {
        users.user_department(input.user) == "engineering"
        input.resource.type == "code"
    }
     
    allow if {
        users.user_department(input.user) == "hr"
        input.resource.type == "personnel_data"
    }
"#.to_string())?;

let compiled = engine.compile_with_entrypoint(&"data.permissions.allow".into())?;

// Test engineering access to code
let result = compiled.eval_with_input(Value::from_json_str(r#"
{
  "user": "alice",
  "resource": {"type": "code", "name": "main.rs"}
}"#)?)?;
assert_eq!(result, Value::from(true));
§Entry Point Rule Format

The rule parameter should follow the Rego rule path format:

  • "data.package.rule" - For rules in a specific package
  • "data.package.subpackage.rule" - For nested packages
  • "allow" - For rules in the default package (though this is not recommended)
§Notes
  • Automatically enables print gathering for debugging purposes
  • If you need target-aware compilation with automatic __target__ handling, consider using Engine::compile_for_target instead (requires azure_policy feature)
§See Also
Source

pub fn eval_rule(&mut self, rule: String) -> Result<Value>

Evaluate specified rule(s).

Engine::eval_rule is often faster than Engine::eval_query and should be preferred if OPA style QueryResults are not needed.

let mut engine = Engine::new();

// Add policy
engine.add_policy(
  "policy.rego".to_string(),
  r#"
  package example
  import rego.v1

  x = [1, 2]

  y := 5 if input.a > 2
  "#.to_string())?;

// Evaluate rule.
let v = engine.eval_rule("data.example.x".to_string())?;
assert_eq!(v, Value::from(vec![Value::from(1), Value::from(2)]));

// y evaluates to undefined.
let v = engine.eval_rule("data.example.y".to_string())?;
assert_eq!(v, Value::Undefined);

// Evaluating a non-existent rule is an error.
let r = engine.eval_rule("data.exaample.x".to_string());
assert!(r.is_err());

// Path must be valid rule paths.
assert!( engine.eval_rule("data".to_string()).is_err());
assert!( engine.eval_rule("data.example".to_string()).is_err());
Source

pub fn eval_query( &mut self, query: String, enable_tracing: bool, ) -> Result<QueryResults>

Evaluate a Rego query.

let mut engine = Engine::new();

// Add policies
engine.set_rego_v0(true);
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 data document (if any).
// If multiple data documents can be added, they will be merged together.
engine.add_data(Value::from_json_file("tests/aci/data.json")?)?;

// At this point the policies and data have been loaded.
// Either the same engine can be used to make multiple queries or the engine
// can be cloned to avoid having the reload the policies and data.
let _clone = engine.clone();

// Evaluate a query.
// Load input and make query.
engine.set_input(Value::new_object());
let results = engine.eval_query("data.framework.mount_overlay.allowed".to_string(), false)?;
assert_eq!(results.result[0].expressions[0].value, Value::from(false));

// Evaluate query with different inputs.
engine.set_input(Value::from_json_file("tests/aci/input.json")?);
let results = engine.eval_query("data.framework.mount_overlay.allowed".to_string(), false)?;
assert_eq!(results.result[0].expressions[0].value, Value::from(true));
Source

pub fn eval_bool_query( &mut self, query: String, enable_tracing: bool, ) -> Result<bool>

Evaluate a Rego query that produces a boolean value.

This function should be preferred over Engine::eval_query if just a true/false value is desired instead of QueryResults.


let enable_tracing = false;
assert_eq!(engine.eval_bool_query("1 > 2".to_string(), enable_tracing)?, false);
assert_eq!(engine.eval_bool_query("1 < 2".to_string(), enable_tracing)?, true);

// Non boolean queries will raise an error.
assert!(engine.eval_bool_query("1+1".to_string(), enable_tracing).is_err());

// Queries producing multiple values will raise an error.
assert!(engine.eval_bool_query("true; true".to_string(), enable_tracing).is_err());

// Queries producing no values will raise an error.
assert!(engine.eval_bool_query("true; false; true".to_string(), enable_tracing).is_err());
Source

pub fn eval_allow_query(&mut self, query: String, enable_tracing: bool) -> bool

Evaluate an allow query.

This is a wrapper over Engine::eval_bool_query that returns true only if the boolean query succeed and produced a true value.


let enable_tracing = false;
assert_eq!(engine.eval_allow_query("1 > 2".to_string(), enable_tracing), false);
assert_eq!(engine.eval_allow_query("1 < 2".to_string(), enable_tracing), true);

assert_eq!(engine.eval_allow_query("1+1".to_string(), enable_tracing), false);
assert_eq!(engine.eval_allow_query("true; true".to_string(), enable_tracing), false);
assert_eq!(engine.eval_allow_query("true; false; true".to_string(), enable_tracing), false);
Source

pub fn eval_deny_query(&mut self, query: String, enable_tracing: bool) -> bool

Evaluate a deny query.

This is a wrapper over Engine::eval_bool_query that returns false only if the boolean query succeed and produced a false value.


let enable_tracing = false;
assert_eq!(engine.eval_deny_query("1 > 2".to_string(), enable_tracing), false);
assert_eq!(engine.eval_deny_query("1 < 2".to_string(), enable_tracing), true);

assert_eq!(engine.eval_deny_query("1+1".to_string(), enable_tracing), true);
assert_eq!(engine.eval_deny_query("true; true".to_string(), enable_tracing), true);
assert_eq!(engine.eval_deny_query("true; false; true".to_string(), enable_tracing), true);
Source

pub fn add_extension( &mut self, path: String, nargs: u8, extension: Box<dyn Extension>, ) -> Result<()>

Add a custom builtin (extension).

  • path: The fully qualified path of the builtin.
  • nargs: The number of arguments the builtin takes.
  • extension: The Extension instance.
let mut engine = Engine::new();

// Policy uses `do_magic` custom builtin.
engine.add_policy(
   "test.rego".to_string(),
   r#"package test
      x = do_magic(1)
   "#.to_string(),
)?;

// Evaluating fails since `do_magic` is not defined.
assert!(engine.eval_query("data.test.x".to_string(), false).is_err());

// Add extension to implement `do_magic`. The extension can be stateful.
let mut magic = 8;
engine.add_extension("do_magic".to_string(), 1 , Box::new(move | mut params: Vec<Value> | {
  // params is mut and therefore individual values can be removed from it and modified.
  // The number of parameters (1) has already been validated.

  match &params[0].as_i64() {
     Ok(i) => {
        // Compute value
        let v = *i + magic;
        // Update extension state.
        magic += 1;
        Ok(Value::from(v))
     }
     // Extensions can raise errors. Regorus will add location information to
     // the error.
     _ => bail!("do_magic expects i64 value")
  }
}))?;

// Evaluation will now succeed.
let r = engine.eval_query("data.test.x".to_string(), false)?;
assert_eq!(r.result[0].expressions[0].value.as_i64()?, 9);

// Cloning the engine will also clone the extension.
let mut engine1 = engine.clone();

// Evaluating again will return a different value since the extension is stateful.
let r = engine.eval_query("data.test.x".to_string(), false)?;
assert_eq!(r.result[0].expressions[0].value.as_i64()?, 10);

// The second engine has a clone of the extension.
let r = engine1.eval_query("data.test.x".to_string(), false)?;
assert_eq!(r.result[0].expressions[0].value.as_i64()?, 10);

// Once added, the extension cannot be replaced or removed.
assert!(engine.add_extension("do_magic".to_string(), 1, Box::new(|_:Vec<Value>| {
  Ok(Value::Undefined)
})).is_err());

// Extensions don't support out-parameter syntax.
engine.add_policy(
  "policy.rego".to_string(),
  r#"package invalid
     x = y if {
      do_magic(2, y)  # y is supplied as an out parameter.
    }
   "#.to_string()
)?;

// Evaluation fails since rule x calls an extension with out parameter.
assert!(engine.eval_query("data.invalid.x".to_string(), false).is_err());
Source

pub fn get_coverage_report(&self) -> Result<Report>

Available on crate feature coverage only.

Get the coverage report.

let mut engine = Engine::new();

engine.add_policy(
   "policy.rego".to_string(),
   r#"
package test    # Line 2

x = y if {         # Line 4
  input.a > 2   # Line 5
  y = 5         # Line 6
}
   "#.to_string()
)?;

// Enable coverage.
engine.set_enable_coverage(true);

engine.eval_query("data".to_string(), false)?;

let report = engine.get_coverage_report()?;
assert_eq!(report.files[0].path, "policy.rego");

// Only line 5 is evaluated.
assert_eq!(report.files[0].covered.iter().cloned().collect::<Vec<u32>>(), vec![5]);

// Line 4 and 6 are not evaluated.
assert_eq!(report.files[0].not_covered.iter().cloned().collect::<Vec<u32>>(), vec![4, 6]);

See also [crate::coverage::Report::to_colored_string].

Source

pub fn set_enable_coverage(&mut self, enable: bool)

Available on crate feature coverage only.

Enable/disable policy coverage.

If enable is different from the current value, then any existing coverage information will be cleared.

Source

pub fn clear_coverage_data(&mut self)

Available on crate feature coverage only.

Clear the gathered policy coverage data.

Source

pub fn set_gather_prints(&mut self, b: bool)

Gather output from print statements instead of emiting to stderr.

See Engine::take_prints.

Source

pub fn take_prints(&mut self) -> Result<Vec<String>>

Take the gathered output of print statements.

let mut engine = Engine::new();

// Print to stderr.
engine.eval_query("print(\"Hello\")".to_string(), false)?;

// Configure gathering print statements.
engine.set_gather_prints(true);

// Execute query.
engine.eval_query("print(\"Hello\")".to_string(), false)?;

// Take and clear prints.
let prints = engine.take_prints()?;
assert_eq!(prints.len(), 1);
assert!(prints[0].contains("Hello"));

for p in prints {
  println!("{p}");
}
Source

pub fn get_ast_as_json(&self) -> Result<String>

Available on crate feature ast only.

Get the policies and corresponding AST.

engine.add_policy("test.rego".to_string(), "package test\n x := 1".to_string())?;

let ast = engine.get_ast_as_json()?;
let value = Value::from_json_str(&ast)?;

assert_eq!(value[0]["ast"]["package"]["refr"]["Var"][1].as_string()?.as_ref(), "test");
Source

pub fn get_policy_package_names( &self, ) -> Result<Vec<PolicyPackageNameDefinition>>

Available on crate feature azure_policy only.

Get the package names of each policy added to the engine.

engine.add_policy("test.rego".to_string(), "package test\n x := 1".to_string())?;
engine.add_policy("test2.rego".to_string(), "package test.multi.segment\n x := 1".to_string())?;

let package_names = engine.get_policy_package_names()?;

assert_eq!("test", package_names[0].package_name);
assert_eq!("test.multi.segment", package_names[1].package_name);
Source

pub fn get_policy_parameters(&self) -> Result<Vec<PolicyParameters>>

Available on crate feature azure_policy only.

Get the parameters defined in each policy.

engine.add_policy("test.rego".to_string(), "package test default parameters.a = 5 parameters.b = 10\n x := 1".to_string())?;

let parameters = engine.get_policy_parameters()?;

assert_eq!("a", parameters[0].parameters[0].name);
assert_eq!("b", parameters[0].modifiers[0].name);

Trait Implementations§

Source§

impl Clone for Engine

Source§

fn clone(&self) -> Engine

Returns a duplicate of the value. Read more
1.0.0 · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Debug for Engine

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl Default for Engine

Create a default engine.

Source§

fn default() -> Self

Returns the “default value” for a type. Read more

Auto Trait Implementations§

§

impl Freeze for Engine

§

impl !RefUnwindSafe for Engine

§

impl Send for Engine

§

impl Sync for Engine

§

impl Unpin for Engine

§

impl !UnwindSafe for Engine

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<V, T> VZip<V> for T
where V: MultiLane<T>,

Source§

fn vzip(self) -> V

Source§

impl<T> ErasedDestructor for T
where T: 'static,