Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: get_policies: Way to obtain policy files and content #267

Merged
merged 1 commit into from
Jun 19, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 10 additions & 1 deletion bindings/ffi/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -189,7 +189,6 @@ pub extern "C" fn regorus_engine_add_data_json(
/// Get list of loaded Rego packages as JSON.
///
/// See https://docs.rs/regorus/latest/regorus/struct.Engine.html#method.get_packages
/// * `data`: JSON encoded value to be used as policy data.
#[no_mangle]
pub extern "C" fn regorus_engine_get_packages(engine: *mut RegorusEngine) -> RegorusResult {
to_regorus_string_result(|| -> Result<String> {
Expand All @@ -198,6 +197,16 @@ pub extern "C" fn regorus_engine_get_packages(engine: *mut RegorusEngine) -> Reg
}())
}

/// Get list of policies as JSON.
///
/// See https://docs.rs/regorus/latest/regorus/struct.Engine.html#method.get_policies
#[no_mangle]
pub extern "C" fn regorus_engine_get_policies(engine: *mut RegorusEngine) -> RegorusResult {
to_regorus_string_result(|| -> Result<String> {
to_ref(&engine)?.engine.get_policies_as_json()
}())
}

#[cfg(feature = "std")]
#[no_mangle]
pub extern "C" fn regorus_engine_add_data_from_json_file(
Expand Down
13 changes: 13 additions & 0 deletions bindings/go/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,19 @@ func main() {
fmt.Fprintf(os.Stderr, "error: %v\n", err)
os.Exit(1)
}
fmt.Printf("%s\n", output)

// Print packages
if output, err = engine1.GetPackages(); err != nil {
fmt.Fprintf(os.Stderr, "error: %v\n", err)
os.Exit(1)
}
fmt.Printf("%s\n", output)

// Print policies
if output, err = engine1.GetPolicies(); err != nil {
fmt.Fprintf(os.Stderr, "error: %v\n", err)
os.Exit(1)
}
fmt.Printf("%s\n", output)
}
19 changes: 19 additions & 0 deletions bindings/go/pkg/regorus/mod.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,25 @@ func (e *Engine) AddPolicyFromFile(path string) (string, error) {
return C.GoString(result.output), nil
}

func (e *Engine) GetPackages() (string, error) {
result := C.regorus_engine_get_packages(e.e)
defer C.regorus_result_drop(result)
if result.status != C.RegorusStatusOk {
return "", fmt.Errorf("%s", C.GoString(result.error_message))
}
return C.GoString(result.output), nil
}

func (e *Engine) GetPolicies() (string, error) {
result := C.regorus_engine_get_policies(e.e)
defer C.regorus_result_drop(result)
if result.status != C.RegorusStatusOk {
return "", fmt.Errorf("%s", C.GoString(result.error_message))
}
return C.GoString(result.output), nil
}


func (e *Engine) AddDataJson(data string) error {
data_c := C.CString(data)
defer C.free(unsafe.Pointer(data_c))
Expand Down
6 changes: 6 additions & 0 deletions bindings/java/Test.java
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,12 @@ public static void main(String[] args) {
System.out.println(coverageJson);

System.out.println(engine.getCoverageReportPretty());

String packagesJson = engine.getPackages();
System.out.println(packagesJson);

String policiesJson = engine.getPolicies();
System.out.println(policiesJson);
}
}
}
19 changes: 19 additions & 0 deletions bindings/java/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,25 @@ pub extern "system" fn Java_com_microsoft_regorus_Engine_nativeGetPackages(
}
}

#[no_mangle]
pub extern "system" fn Java_com_microsoft_regorus_Engine_nativeGetPolicies(
env: JNIEnv,
_class: JClass,
engine_ptr: jlong,
) -> jstring {
let res = throw_err(env, |env| {
let engine = unsafe { &mut *(engine_ptr as *mut Engine) };
let policies = engine.get_policies_as_json()?;
let policies_json = env.new_string(&policies)?;
Ok(policies_json.into_raw())
});

match res {
Ok(val) => val,
Err(_) => JObject::null().into_raw(),
}
}

#[no_mangle]
pub extern "system" fn Java_com_microsoft_regorus_Engine_nativeClearData(
env: JNIEnv,
Expand Down
10 changes: 10 additions & 0 deletions bindings/java/src/main/java/com/microsoft/regorus/Engine.java
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ public class Engine implements AutoCloseable, Cloneable {
private static native String nativeAddPolicy(long enginePtr, String path, String rego);
private static native String nativeAddPolicyFromFile(long enginePtr, String path);
private static native String nativeGetPackages(long enginePtr);
private static native String nativeGetPolicies(long enginePtr);
private static native void nativeClearData(long enginePtr);
private static native void nativeAddDataJson(long enginePtr, String data);
private static native void nativeAddDataJsonFromFile(long enginePtr, String path);
Expand Down Expand Up @@ -96,6 +97,15 @@ public String getPackages() {
return nativeGetPackages(enginePtr);
}

/**
* Get list of loaded policies.
*
* @return List of Rego policies as a JSON array of sources.
*/
public String getPolicies() {
return nativeGetPolicies(enginePtr);
}

/**
* Clears the data document.
*/
Expand Down
10 changes: 9 additions & 1 deletion bindings/python/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -184,10 +184,18 @@ impl Engine {

/// Get the list of packages defined by loaded policies.
///
pub fn get_packages(&mut self) -> Result<Vec<String>> {
pub fn get_packages(&self) -> Result<Vec<String>> {
self.engine.get_packages()
}

/// Get the list of policies.
///
pub fn get_policies(&self) -> Result<String> {
Ok(serde_json::to_string_pretty(
&self.engine.get_policies_as_json()?,
)?)
}

/// Add policy data.
///
/// * `data`: Rego value. A Rego value is a number, bool, string, None
Expand Down
16 changes: 16 additions & 0 deletions bindings/ruby/ext/regorusrb/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,20 @@ impl Engine {
Ok(())
}

fn get_packages(&self) -> Result<Vec<String>, Error> {
self.engine
.borrow()
.get_packages()
.map_err(|e| Error::new(runtime_error(), format!("Failed to get packages: {e}")))
}

fn get_policies(&self) -> Result<String, Error> {
self.engine
.borrow()
.get_policies_as_json()
.map_err(|e| Error::new(runtime_error(), format!("Failed to get policies: {e}")))
}

fn set_input(&self, ruby_hash: magnus::RHash) -> Result<(), Error> {
let input_value: regorus::Value = serde_magnus::deserialize(ruby_hash).map_err(|e| {
Error::new(
Expand Down Expand Up @@ -289,6 +303,8 @@ fn init(ruby: &Ruby) -> Result<(), Error> {
"add_policy_from_file",
method!(Engine::add_policy_from_file, 1),
)?;
engine_class.define_method("get_packages", method!(Engine::get_packages, 0))?;
engine_class.define_method("get_policies", method!(Engine::get_policies, 0))?;

// data operations
engine_class.define_method("add_data", method!(Engine::add_data, 1))?;
Expand Down
21 changes: 18 additions & 3 deletions bindings/wasm/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,13 @@ impl Engine {
self.engine.get_packages().map_err(error_to_jsvalue)
}

/// Get the list of policies.
///
/// See https://docs.rs/regorus/latest/regorus/struct.Engine.html#method.get_policies
pub fn getPolicies(&self) -> Result<String, JsValue> {
self.engine.get_policies_as_json().map_err(error_to_jsvalue)
}

/// Clear policy data.
///
/// See https://docs.rs/regorus/0.1.0-alpha.2/regorus/struct.Engine.html#method.clear_data
Expand Down Expand Up @@ -179,6 +186,7 @@ impl Engine {

#[cfg(test)]
mod tests {
use crate::error_to_jsvalue;
use wasm_bindgen::prelude::*;
use wasm_bindgen_test::wasm_bindgen_test;

Expand Down Expand Up @@ -216,7 +224,7 @@ mod tests {
assert_eq!(pkg, "data.test");

let results = engine.evalQuery("data".to_string())?;
let r = regorus::Value::from_json_str(&results).map_err(crate::error_to_jsvalue)?;
let r = regorus::Value::from_json_str(&results).map_err(error_to_jsvalue)?;

let v = &r["result"][0]["expressions"][0]["value"];

Expand All @@ -228,7 +236,7 @@ mod tests {

// Use eval_rule to perform same query.
let v = engine.evalRule("data.test.message".to_owned())?;
let v = regorus::Value::from_json_str(&v).map_err(crate::error_to_jsvalue)?;
let v = regorus::Value::from_json_str(&v).map_err(error_to_jsvalue)?;

// Ensure that input and policy were evaluated.
assert_eq!(v, regorus::Value::from("Hello"));
Expand All @@ -246,7 +254,7 @@ mod tests {

// Test code coverage.
let report = engine1.getCoverageReport()?;
let r = regorus::Value::from_json_str(&report).map_err(crate::error_to_jsvalue)?;
let r = regorus::Value::from_json_str(&report).map_err(error_to_jsvalue)?;

assert_eq!(
r["files"][0]["covered"]
Expand All @@ -258,6 +266,13 @@ mod tests {
println!("{}", engine1.getCoverageReportPretty()?);

engine1.clearCoverageData();

let policies = engine1.getPolicies()?;
let v = regorus::Value::from_json_str(&policies).map_err(error_to_jsvalue)?;
assert_eq!(
v[0]["path"].as_string().map_err(error_to_jsvalue)?.as_ref(),
"hello.rego"
);
Ok(())
}
}
60 changes: 60 additions & 0 deletions src/engine.rs
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,66 @@ impl Engine {
.collect()
}

/// Get the list of policy files.
/// ```
/// # use regorus::*;
/// # fn main() -> anyhow::Result<()> {
/// # let mut engine = Engine::new();
///
/// 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");
/// # Ok(())
/// # }
/// ```
pub fn get_policies(&self) -> Result<Vec<Source>> {
Ok(self
.modules
.iter()
.map(|m| m.package.refr.span().source.clone())
.collect())
}

/// Get the list of policy files as a JSON object.
/// ```
/// # use regorus::*;
/// # fn main() -> anyhow::Result<()> {
/// # let mut engine = Engine::new();
///
/// 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");
/// # Ok(())
/// # }
/// ```
pub fn get_policies_as_json(&self) -> Result<String> {
#[derive(Serialize)]
struct Source<'a> {
path: &'a String,
contents: &'a String,
}

let mut sources = vec![];
for m in self.modules.iter() {
let source = &m.package.refr.span().source;
sources.push(Source {
path: source.get_path(),
contents: source.get_contents(),
});
}

serde_json::to_string_pretty(&sources).map_err(anyhow::Error::msg)
}

/// Set the input document.
///
/// * `input`: Input documented. Typically this [Value] is constructed from JSON or YAML.
Expand Down
13 changes: 13 additions & 0 deletions src/lexer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,13 +20,26 @@ struct SourceInternal {
pub lines: Vec<(u32, u32)>,
}

/// A policy file.
#[derive(Clone)]
#[cfg_attr(feature = "ast", derive(serde::Serialize))]
pub struct Source {
#[cfg_attr(feature = "ast", serde(flatten))]
src: Rc<SourceInternal>,
}

impl Source {
/// The path associated with the policy file.
pub fn get_path(&self) -> &String {
&self.src.file
}

/// The contents of the policy file.
pub fn get_contents(&self) -> &String {
&self.src.contents
}
}

impl cmp::Ord for Source {
fn cmp(&self, other: &Source) -> cmp::Ordering {
Rc::as_ptr(&self.src).cmp(&Rc::as_ptr(&other.src))
Expand Down
1 change: 1 addition & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ mod utils;
mod value;

pub use engine::Engine;
pub use lexer::Source;
pub use value::Value;

#[cfg(feature = "arc")]
Expand Down
Loading