From c243174b759caa436ed0975769037f408133b000 Mon Sep 17 00:00:00 2001 From: Anand Krishnamoorthi Date: Sun, 9 Jun 2024 09:39:46 -0700 Subject: [PATCH] get_policies: Way to obtain policy files and content Signed-off-by: Anand Krishnamoorthi --- bindings/python/src/lib.rs | 8 +++++++- bindings/ruby/ext/regorusrb/src/lib.rs | 25 +++++++++++++++++++++++++ bindings/wasm/src/lib.rs | 22 +++++++++++++++++++--- src/engine.rs | 24 ++++++++++++++++++++++++ src/lexer.rs | 13 +++++++++++++ src/lib.rs | 1 + 6 files changed, 89 insertions(+), 4 deletions(-) diff --git a/bindings/python/src/lib.rs b/bindings/python/src/lib.rs index 7454202d..96055ce2 100644 --- a/bindings/python/src/lib.rs +++ b/bindings/python/src/lib.rs @@ -184,10 +184,16 @@ impl Engine { /// Get the list of packages defined by loaded policies. /// - pub fn get_packages(&mut self) -> Result> { + pub fn get_packages(&self) -> Result> { self.engine.get_packages() } + /// Get the list of policies. + /// + pub fn get_policies(&self) -> Result { + Ok(serde_json::to_string_pretty(&self.engine.get_policies()?)?) + } + /// Add policy data. /// /// * `data`: Rego value. A Rego value is a number, bool, string, None diff --git a/bindings/ruby/ext/regorusrb/src/lib.rs b/bindings/ruby/ext/regorusrb/src/lib.rs index d1e042fb..b6b48166 100644 --- a/bindings/ruby/ext/regorusrb/src/lib.rs +++ b/bindings/ruby/ext/regorusrb/src/lib.rs @@ -92,6 +92,29 @@ impl Engine { Ok(()) } + fn get_packages(&self) -> Result, Error> { + self.engine + .borrow() + .get_packages() + .map_err(|e| Error::new(runtime_error(), format!("Failed to get packages: {e}"))) + } + + fn get_policies(&self) -> Result { + serde_json::to_string_pretty( + &self + .engine + .borrow() + .get_policies() + .map_err(|e| Error::new(runtime_error(), format!("Failed to get policies: {e}"))), + ) + .map_err(|e| { + Error::new( + runtime_error(), + format!("Failed to convert policies to json: {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( @@ -289,6 +312,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))?; diff --git a/bindings/wasm/src/lib.rs b/bindings/wasm/src/lib.rs index 9a03ff00..5884de36 100644 --- a/bindings/wasm/src/lib.rs +++ b/bindings/wasm/src/lib.rs @@ -72,6 +72,14 @@ 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 { + serde_json::to_string_pretty(&self.engine.get_policies().map_err(error_to_jsvalue)?) + .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 @@ -179,6 +187,7 @@ impl Engine { #[cfg(test)] mod tests { + use crate::error_to_jsvalue; use wasm_bindgen::prelude::*; use wasm_bindgen_test::wasm_bindgen_test; @@ -216,7 +225,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"]; @@ -228,7 +237,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")); @@ -246,7 +255,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"] @@ -258,6 +267,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(()) } } diff --git a/src/engine.rs b/src/engine.rs index a0067cdb..f9cd42c4 100644 --- a/src/engine.rs +++ b/src/engine.rs @@ -129,6 +129,30 @@ 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> { + Ok(self + .modules + .iter() + .map(|m| m.package.refr.span().source.clone()) + .collect()) + } + /// Set the input document. /// /// * `input`: Input documented. Typically this [Value] is constructed from JSON or YAML. diff --git a/src/lexer.rs b/src/lexer.rs index 28faa07e..5888300f 100644 --- a/src/lexer.rs +++ b/src/lexer.rs @@ -20,6 +20,7 @@ struct SourceInternal { pub lines: Vec<(u32, u32)>, } +/// A policy file. #[derive(Clone)] #[cfg_attr(feature = "ast", derive(serde::Serialize))] pub struct Source { @@ -27,6 +28,18 @@ pub struct Source { src: Rc, } +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)) diff --git a/src/lib.rs b/src/lib.rs index 58e522f0..39f84b2e 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -28,6 +28,7 @@ mod utils; mod value; pub use engine::Engine; +pub use lexer::Source; pub use value::Value; #[cfg(feature = "arc")]