mirror of
https://github.com/microsoft/regorus.git
synced 2026-08-05 02:16:11 +00:00
OPA Conformance
- Disable default features of jsonschema to reduce binary size (#85) - graph.reachable, graph.reachable_paths builtins. - In progress walk builtin Note: graph.reachable_paths is buggy in upstream OPA and its semantics are not well defined. https://github.com/open-policy-agent/opa/issues/5871 https://github.com/open-policy-agent/opa/issues/6128 - Use correct feature for regex - Ensure that regorus complies with all features disabled. Signed-off-by: Anand Krishnamoorthi <anakrish@microsoft.com>
This commit is contained in:
committed by
GitHub
parent
84bedda1c6
commit
2292774446
@@ -2,7 +2,6 @@
|
||||
// Licensed under the MIT License.
|
||||
|
||||
use crate::ast::{Expr, Ref};
|
||||
use crate::builtins::regex::regex_match;
|
||||
use crate::builtins::utils::{ensure_args_count, ensure_set};
|
||||
use crate::builtins::BuiltinFcn;
|
||||
use crate::lexer::Span;
|
||||
@@ -13,6 +12,9 @@ use std::collections::HashMap;
|
||||
use anyhow::{bail, Result};
|
||||
use lazy_static::lazy_static;
|
||||
|
||||
#[cfg(feature = "regex")]
|
||||
use crate::builtins::regex::regex_match;
|
||||
|
||||
#[rustfmt::skip]
|
||||
lazy_static! {
|
||||
pub static ref DEPRECATED: HashMap<&'static str, BuiltinFcn> = {
|
||||
@@ -28,7 +30,7 @@ lazy_static! {
|
||||
m.insert("cast_string", (cast_string, 1));
|
||||
m.insert("set_diff", (set_diff, 2));
|
||||
|
||||
#[cfg(feature = "crypto")]
|
||||
#[cfg(feature = "regex")]
|
||||
m.insert("re_match", (regex_match, 2));
|
||||
m
|
||||
};
|
||||
|
||||
@@ -0,0 +1,184 @@
|
||||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
use crate::ast::{Expr, Ref};
|
||||
use crate::builtins;
|
||||
use crate::builtins::utils::{ensure_args_count, ensure_object};
|
||||
use crate::lexer::Span;
|
||||
use crate::value::Value;
|
||||
|
||||
use std::collections::{BTreeMap, BTreeSet, HashMap};
|
||||
|
||||
use anyhow::{bail, Result};
|
||||
|
||||
pub fn register(m: &mut HashMap<&'static str, builtins::BuiltinFcn>) {
|
||||
m.insert("graph.reachable", (reachable, 2));
|
||||
m.insert("graph.reachable_paths", (reachable_paths, 2));
|
||||
m.insert("walk", (walk, 1));
|
||||
}
|
||||
|
||||
fn reachable(span: &Span, params: &[Ref<Expr>], args: &[Value], strict: bool) -> Result<Value> {
|
||||
let name = "graph.reachable";
|
||||
ensure_args_count(span, name, params, args, 2)?;
|
||||
|
||||
let graph = ensure_object(name, ¶ms[0], args[0].clone())?;
|
||||
let mut worklist = vec![];
|
||||
|
||||
match &args[1] {
|
||||
Value::Array(arr) => worklist.extend(arr.iter().cloned()),
|
||||
Value::Set(set) => worklist.extend(set.iter().cloned()),
|
||||
_ if strict => bail!(params[1].span().error("initial vertices must be array/set")),
|
||||
_ => return Ok(Value::Undefined),
|
||||
}
|
||||
|
||||
let mut reachable = BTreeSet::new();
|
||||
while let Some(v) = worklist.pop() {
|
||||
if reachable.contains(&v) {
|
||||
continue;
|
||||
}
|
||||
|
||||
match graph.get(&v) {
|
||||
Some(Value::Array(arr)) => worklist.extend(arr.iter().cloned()),
|
||||
Some(Value::Set(set)) => worklist.extend(set.iter().cloned()),
|
||||
Some(_) => (),
|
||||
_ => continue,
|
||||
}
|
||||
|
||||
reachable.insert(v);
|
||||
}
|
||||
|
||||
Ok(Value::from_set(reachable))
|
||||
}
|
||||
|
||||
fn visit(
|
||||
graph: &BTreeMap<Value, Value>,
|
||||
visited: &mut BTreeSet<Value>,
|
||||
node: &Value,
|
||||
path: &mut Vec<Value>,
|
||||
paths: &mut BTreeSet<Value>,
|
||||
) -> Result<()> {
|
||||
if let Value::String(s) = node {
|
||||
if s.as_ref() == "" {
|
||||
if !path.is_empty() {
|
||||
paths.insert(Value::from_array(path.clone()));
|
||||
}
|
||||
return Ok(());
|
||||
}
|
||||
}
|
||||
|
||||
let neighbors = graph.get(node);
|
||||
if neighbors.is_none() {
|
||||
// Current node is not valid. Add path as is.
|
||||
if !path.is_empty() {
|
||||
paths.insert(Value::from_array(path.clone()));
|
||||
}
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
if visited.contains(node) {
|
||||
paths.insert(Value::from_array(path.clone()));
|
||||
} else {
|
||||
path.push(node.clone());
|
||||
visited.insert(node.clone());
|
||||
let n = match neighbors {
|
||||
Some(Value::Array(arr)) => {
|
||||
for n in arr.iter().rev() {
|
||||
visit(graph, visited, n, path, paths)?;
|
||||
}
|
||||
arr.len()
|
||||
}
|
||||
Some(Value::Set(set)) => {
|
||||
for n in set.iter().rev() {
|
||||
visit(graph, visited, n, path, paths)?;
|
||||
}
|
||||
set.len()
|
||||
}
|
||||
Some(&Value::Null) => 0,
|
||||
_ => bail!(format!("neighbors for node `{node}` must be array/set.")),
|
||||
};
|
||||
|
||||
if n == 0 {
|
||||
// Current node has no neighbors.
|
||||
if !path.is_empty() {
|
||||
paths.insert(Value::from_array(path.clone()));
|
||||
}
|
||||
}
|
||||
|
||||
visited.remove(node);
|
||||
path.pop();
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn reachable_paths(
|
||||
span: &Span,
|
||||
params: &[Ref<Expr>],
|
||||
args: &[Value],
|
||||
strict: bool,
|
||||
) -> Result<Value> {
|
||||
let name = "graph.reachable_paths";
|
||||
ensure_args_count(span, name, params, args, 2)?;
|
||||
|
||||
let graph = ensure_object(name, ¶ms[0], args[0].clone())?;
|
||||
let mut visited = BTreeSet::new();
|
||||
let mut path = vec![];
|
||||
let mut paths = BTreeSet::new();
|
||||
|
||||
match &args[1] {
|
||||
Value::Array(arr) => {
|
||||
for node in arr.iter() {
|
||||
visit(&graph, &mut visited, node, &mut path, &mut paths)?;
|
||||
}
|
||||
}
|
||||
Value::Set(set) => {
|
||||
for node in set.iter() {
|
||||
visit(&graph, &mut visited, node, &mut path, &mut paths)?;
|
||||
}
|
||||
}
|
||||
_ if strict => bail!(params[1].span().error("initial vertices must be array/set")),
|
||||
_ => return Ok(Value::Undefined),
|
||||
}
|
||||
|
||||
Ok(Value::from_set(paths))
|
||||
}
|
||||
|
||||
fn walk_visit(path: &mut Vec<Value>, value: &Value, paths: &mut Vec<Value>) -> Result<()> {
|
||||
{
|
||||
let path = Value::from_array(path.clone());
|
||||
paths.push(Value::from_array([path, value.clone()].into()));
|
||||
}
|
||||
match value {
|
||||
Value::Array(arr) => {
|
||||
for (idx, elem) in arr.iter().enumerate() {
|
||||
path.push(Value::from(idx));
|
||||
walk_visit(path, elem, paths)?;
|
||||
path.pop();
|
||||
}
|
||||
}
|
||||
Value::Set(set) => {
|
||||
for elem in set.iter() {
|
||||
path.push(elem.clone());
|
||||
walk_visit(path, elem, paths)?;
|
||||
path.pop();
|
||||
}
|
||||
}
|
||||
Value::Object(obj) => {
|
||||
for (key, value) in obj.iter() {
|
||||
path.push(key.clone());
|
||||
walk_visit(path, value, paths)?;
|
||||
path.pop();
|
||||
}
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn walk(span: &Span, params: &[Ref<Expr>], args: &[Value], _strict: bool) -> Result<Value> {
|
||||
let name = "walk";
|
||||
ensure_args_count(span, name, params, args, 1)?;
|
||||
let mut paths = vec![];
|
||||
walk_visit(&mut vec![], &args[0], &mut paths)?;
|
||||
Ok(Value::from_array(paths))
|
||||
}
|
||||
+5
-1
@@ -15,6 +15,8 @@ pub mod deprecated;
|
||||
mod encoding;
|
||||
#[cfg(feature = "glob")]
|
||||
mod glob;
|
||||
#[cfg(feature = "graph")]
|
||||
mod graph;
|
||||
pub mod numbers;
|
||||
mod objects;
|
||||
#[cfg(feature = "regex")]
|
||||
@@ -64,6 +66,9 @@ lazy_static! {
|
||||
#[cfg(feature = "glob")]
|
||||
glob::register(&mut m);
|
||||
|
||||
#[cfg(feature = "graph")]
|
||||
graph::register(&mut m);
|
||||
|
||||
bitwise::register(&mut m);
|
||||
conversions::register(&mut m);
|
||||
//units::register(&mut m);
|
||||
@@ -75,7 +80,6 @@ lazy_static! {
|
||||
|
||||
#[cfg(feature = "crypto")]
|
||||
crypto::register(&mut m);
|
||||
//graphs::register(&mut m);
|
||||
//graphql::register(&mut m);
|
||||
//http::register(&mut m);
|
||||
//net::register(&mut m);
|
||||
|
||||
@@ -1785,6 +1785,9 @@ impl Interpreter {
|
||||
return Ok(Some(builtin));
|
||||
}
|
||||
|
||||
// Mark as used when deprecated feature is not enabled.
|
||||
std::convert::identity((span, self.allow_deprecated));
|
||||
|
||||
Ok(None)
|
||||
}
|
||||
|
||||
|
||||
@@ -133,6 +133,8 @@ fn get_extra_arg_impl(
|
||||
} else {
|
||||
return Ok(None);
|
||||
}
|
||||
#[cfg(not(feature = "deprecated"))]
|
||||
return Ok(None);
|
||||
}
|
||||
};
|
||||
if (n_args as usize) + 1 == params.len() {
|
||||
|
||||
Reference in New Issue
Block a user