mirror of
https://github.com/microsoft/regorus.git
synced 2026-08-05 02:16:11 +00:00
Lock down ACI tests and more OPA test folders (#54)
Borrowed from rego-cpp Significantly (> 10 times) faster execution. $ cargo test -r --test aci aci/mount_device passed 9.597958ms aci/mount_overlay passed 10.159208ms aci/scratch_mount passed 8.598875ms aci/create_container passed 10.237292ms aci/shutdown_container passed 6.904084ms aci/scratch_unmount passed 6.530875ms aci/unmount_overlay passed 5.958875ms aci/unmount_device passed 5.657834ms aci/load_fragment passed 6.049917ms Signed-off-by: Anand Krishnamoorthi <anakrish@microsoft.com>
This commit is contained in:
committed by
GitHub
parent
639ba72c90
commit
bb0ca29753
@@ -17,6 +17,7 @@ env_logger="0.10.0"
|
||||
lazy_static = "1.4.0"
|
||||
rand = "0.8.5"
|
||||
data-encoding = "2.4.0"
|
||||
regex = "1.10.2"
|
||||
|
||||
[dev-dependencies]
|
||||
clap = { version = "4.4.7", features = ["derive"] }
|
||||
@@ -33,3 +34,8 @@ debug = true
|
||||
name="opa"
|
||||
harness=false
|
||||
test=false
|
||||
|
||||
[[test]]
|
||||
name="aci"
|
||||
harness=false
|
||||
test=false
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
// 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;
|
||||
@@ -20,6 +21,7 @@ lazy_static! {
|
||||
m.insert("all", (all, 1));
|
||||
m.insert("any", (any, 1));
|
||||
m.insert("set_diff", (set_diff, 2));
|
||||
m.insert("re_match", (regex_match, 2));
|
||||
m
|
||||
};
|
||||
}
|
||||
|
||||
@@ -11,6 +11,7 @@ pub mod deprecated;
|
||||
mod encoding;
|
||||
pub mod numbers;
|
||||
mod objects;
|
||||
mod regex;
|
||||
mod semver;
|
||||
pub mod sets;
|
||||
mod strings;
|
||||
@@ -45,7 +46,7 @@ lazy_static! {
|
||||
sets::register(&mut m);
|
||||
objects::register(&mut m);
|
||||
strings::register(&mut m);
|
||||
//regex::register(&mut m);
|
||||
regex::register(&mut m);
|
||||
//glob::register(&mut m);
|
||||
bitwise::register(&mut m);
|
||||
conversions::register(&mut m);
|
||||
|
||||
51
src/builtins/regex.rs
Normal file
51
src/builtins/regex.rs
Normal file
@@ -0,0 +1,51 @@
|
||||
// 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_string};
|
||||
use crate::lexer::Span;
|
||||
use crate::value::Value;
|
||||
|
||||
use std::collections::HashMap;
|
||||
|
||||
use anyhow::{bail, Result};
|
||||
use regex::Regex;
|
||||
|
||||
pub fn register(m: &mut HashMap<&'static str, builtins::BuiltinFcn>) {
|
||||
m.insert("regex.is_valid", (is_valid, 1));
|
||||
m.insert("regex.match", (regex_match, 2));
|
||||
m.insert("regex.split", (regex_split, 2));
|
||||
}
|
||||
|
||||
fn is_valid(span: &Span, params: &[Ref<Expr>], args: &[Value]) -> Result<Value> {
|
||||
let name = "regex.is_valid";
|
||||
ensure_args_count(span, name, params, args, 1)?;
|
||||
Ok(ensure_string(name, ¶ms[0], &args[0])
|
||||
.map_or(Value::Bool(false), |p| Value::Bool(Regex::new(&p).is_ok())))
|
||||
}
|
||||
|
||||
pub fn regex_match(span: &Span, params: &[Ref<Expr>], args: &[Value]) -> Result<Value> {
|
||||
let name = "regex.match";
|
||||
ensure_args_count(span, name, params, args, 2)?;
|
||||
let pattern = ensure_string(name, ¶ms[0], &args[0])?;
|
||||
let value = ensure_string(name, ¶ms[1], &args[1])?;
|
||||
|
||||
let pattern = Regex::new(&pattern).or_else(|_| bail!(span.error("invalid regex")))?;
|
||||
Ok(Value::Bool(pattern.is_match(&value)))
|
||||
}
|
||||
|
||||
pub fn regex_split(span: &Span, params: &[Ref<Expr>], args: &[Value]) -> Result<Value> {
|
||||
let name = "regex.split";
|
||||
ensure_args_count(span, name, params, args, 2)?;
|
||||
let pattern = ensure_string(name, ¶ms[0], &args[0])?;
|
||||
let value = ensure_string(name, ¶ms[1], &args[1])?;
|
||||
|
||||
let pattern = Regex::new(&pattern).or_else(|_| bail!(span.error("invalid regex")))?;
|
||||
Ok(Value::from_array(
|
||||
pattern
|
||||
.split(&value)
|
||||
.map(|s| Value::String(s.into()))
|
||||
.collect::<Vec<Value>>(),
|
||||
))
|
||||
}
|
||||
@@ -242,7 +242,7 @@ impl Interpreter {
|
||||
// Stop path collection upon encountering the leading variable.
|
||||
Expr::Var(v) => {
|
||||
path.reverse();
|
||||
return self.lookup_var(v, &path[..]);
|
||||
return self.lookup_var(v, &path[..], false);
|
||||
}
|
||||
// Accumulate chained . field accesses.
|
||||
Expr::RefDot { refr, field, .. } => {
|
||||
@@ -259,8 +259,23 @@ impl Interpreter {
|
||||
// Note, we have the choice to evaluate a non-string index
|
||||
_ => {
|
||||
path.reverse();
|
||||
let obj = self.eval_expr(refr)?;
|
||||
|
||||
let index = self.eval_expr(index)?;
|
||||
|
||||
// Handle indexing into data.
|
||||
if let Ok(ref_path) = get_path_string(refr, None) {
|
||||
if get_root_var(refr)?.text() == "data" && index != Value::Undefined {
|
||||
let index = match &index {
|
||||
Value::String(s) => s.to_string(),
|
||||
_ => index.to_string(),
|
||||
};
|
||||
let ref_path = ref_path + "." + &index + "." + &path.join("");
|
||||
self.ensure_rule_evaluated(ref_path)?;
|
||||
}
|
||||
}
|
||||
|
||||
let obj = self.eval_expr(refr)?;
|
||||
|
||||
let mut v = obj[&index].clone();
|
||||
// Qualified references starting with data (e.g data.p.q) can
|
||||
// be indexed using numbers. The number will be converted to string
|
||||
@@ -451,55 +466,87 @@ impl Interpreter {
|
||||
let (name, value) = match op {
|
||||
AssignOp::Eq => {
|
||||
match (lhs.as_ref(), rhs.as_ref()) {
|
||||
(Expr::Var(lhs_span), Expr::Var(rhs_span)) => {
|
||||
let (lhs_name, lhs_var) = (lhs_span.source_str(), self.eval_expr(lhs)?);
|
||||
let (rhs_name, rhs_var) = (rhs_span.source_str(), self.eval_expr(rhs)?);
|
||||
|
||||
match (&lhs_var, &rhs_var) {
|
||||
(Value::Undefined, Value::Undefined) => {
|
||||
bail!(lhs.span().error("both operands are unsafe"))
|
||||
(_, Expr::Var(var)) if self.lookup_var(var, &[], true)? == Value::Undefined => {
|
||||
(var.source_str(), self.eval_expr(lhs)?)
|
||||
}
|
||||
(Expr::Var(var), _) if self.lookup_var(var, &[], true)? == Value::Undefined => {
|
||||
(var.source_str(), self.eval_expr(rhs)?)
|
||||
}
|
||||
(
|
||||
Expr::Array {
|
||||
items: lhs_items, ..
|
||||
},
|
||||
Expr::Array {
|
||||
items: rhs_items,
|
||||
span: rhs_span,
|
||||
},
|
||||
) => {
|
||||
if lhs_items.len() != rhs_items.len() {
|
||||
bail!(rhs_span
|
||||
.error("mismatch in number of array elements in lhs and rhs"));
|
||||
}
|
||||
for (lhs, rhs) in std::iter::zip(lhs_items.iter(), rhs_items.iter()) {
|
||||
if self.eval_assign_expr(&AssignOp::Eq, lhs, rhs)? != Value::Bool(true)
|
||||
{
|
||||
return Ok(Value::Bool(false));
|
||||
}
|
||||
(Value::Undefined, _) => (lhs_name, rhs_var),
|
||||
(_, Value::Undefined) => (rhs_name, lhs_var),
|
||||
// TODO: avoid reeval
|
||||
_ => return self.eval_bool_expr(&BoolOp::Eq, lhs, rhs),
|
||||
}
|
||||
return Ok(Value::Bool(true));
|
||||
}
|
||||
(Expr::Var(lhs_span), _) => {
|
||||
let (name, var) = (lhs_span.source_str(), self.eval_expr(lhs)?);
|
||||
|
||||
// TODO: Check this
|
||||
// Allow variable overwritten inside a loop
|
||||
if !matches!(var, Value::Undefined)
|
||||
&& self.loop_var_values.get(rhs).is_none()
|
||||
{
|
||||
return self.eval_bool_expr(&BoolOp::Eq, lhs, rhs);
|
||||
}
|
||||
|
||||
(name, self.eval_expr(rhs)?)
|
||||
(Expr::Object { .. }, Expr::Object { .. }) => {
|
||||
// TODO: destructure
|
||||
return self.eval_bool_expr(&BoolOp::Eq, lhs, rhs);
|
||||
}
|
||||
(_, Expr::Var(rhs_span)) => {
|
||||
let (name, var) = (rhs_span.source_str(), self.eval_expr(rhs)?);
|
||||
|
||||
// TODO: Check this
|
||||
// Allow variable overwritten inside a loop
|
||||
if !matches!(var, Value::Undefined)
|
||||
&& self.loop_var_values.get(lhs).is_none()
|
||||
{
|
||||
return self.eval_bool_expr(&BoolOp::Eq, lhs, rhs);
|
||||
}
|
||||
|
||||
(name, self.eval_expr(lhs)?)
|
||||
(Expr::Array { .. }, _) => {
|
||||
let value = self.eval_expr(rhs)?;
|
||||
let mut cache = BTreeMap::new();
|
||||
let mut type_match = BTreeSet::new();
|
||||
return self
|
||||
.make_bindings(false, &mut type_match, &mut cache, lhs, &value)
|
||||
.map(Value::Bool);
|
||||
}
|
||||
(_, Expr::Array { .. }) => {
|
||||
let value = self.eval_expr(lhs)?;
|
||||
let mut cache = BTreeMap::new();
|
||||
let mut type_match = BTreeSet::new();
|
||||
return self
|
||||
.make_bindings(false, &mut type_match, &mut cache, rhs, &value)
|
||||
.map(Value::Bool);
|
||||
}
|
||||
(Expr::Object { .. }, _) => {
|
||||
let value = self.eval_expr(rhs)?;
|
||||
let mut cache = BTreeMap::new();
|
||||
let mut type_match = BTreeSet::new();
|
||||
return self
|
||||
.make_bindings(false, &mut type_match, &mut cache, lhs, &value)
|
||||
.map(Value::Bool);
|
||||
}
|
||||
(_, Expr::Object { .. }) => {
|
||||
let value = self.eval_expr(lhs)?;
|
||||
let mut cache = BTreeMap::new();
|
||||
let mut type_match = BTreeSet::new();
|
||||
return self
|
||||
.make_bindings(false, &mut type_match, &mut cache, rhs, &value)
|
||||
.map(Value::Bool);
|
||||
}
|
||||
// Treat the assignment as comparison if neither lhs nor rhs is a variable
|
||||
_ => return self.eval_bool_expr(&BoolOp::Eq, lhs, rhs),
|
||||
}
|
||||
}
|
||||
AssignOp::ColEq => {
|
||||
let rhs_value = self.eval_expr(rhs)?;
|
||||
if rhs_value == Value::Undefined {
|
||||
return Ok(rhs_value);
|
||||
}
|
||||
|
||||
let name = if let Expr::Var(span) = lhs.as_ref() {
|
||||
span.source_str()
|
||||
} else {
|
||||
bail!("internal error: unexpected");
|
||||
let mut cache = BTreeMap::new();
|
||||
let mut type_match = BTreeSet::new();
|
||||
return self
|
||||
.make_bindings(false, &mut type_match, &mut cache, lhs, &rhs_value)
|
||||
.map(Value::Bool);
|
||||
};
|
||||
|
||||
// TODO: Check this
|
||||
@@ -513,7 +560,7 @@ impl Interpreter {
|
||||
.error(&format!("redefinition for variable {}", name)));
|
||||
}
|
||||
|
||||
(name, self.eval_expr(rhs)?)
|
||||
(name, rhs_value)
|
||||
}
|
||||
};
|
||||
|
||||
@@ -632,6 +679,7 @@ impl Interpreter {
|
||||
let raise_error = is_last && type_match.get(expr).is_none();
|
||||
|
||||
match (expr.as_ref(), value) {
|
||||
(Expr::Var(ident), _) if ident.text().as_ref() == &"_" => Ok(true),
|
||||
(Expr::Var(ident), _) => {
|
||||
self.add_variable(&ident.source_str(), value.clone())?;
|
||||
Ok(true)
|
||||
@@ -1649,29 +1697,25 @@ impl Interpreter {
|
||||
));
|
||||
}
|
||||
|
||||
let mut args_scope = Scope::new();
|
||||
for (idx, a) in args.iter().enumerate() {
|
||||
let a = match a.as_ref() {
|
||||
Expr::Var(s) => s.source_str(),
|
||||
_ => {
|
||||
match self.eval_expr(a) {
|
||||
Ok(a) => {
|
||||
if a != param_values[idx] {
|
||||
// Skip this rule definition.
|
||||
continue 'outer;
|
||||
}
|
||||
// Back up local variables of current function and empty
|
||||
// the local variables of callee function.
|
||||
let scopes = std::mem::take(&mut self.scopes);
|
||||
|
||||
continue;
|
||||
}
|
||||
_ => {
|
||||
// TODO: destructuring function arguments.
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
//TODO: check call in params
|
||||
args_scope.insert(a, param_values[idx].clone());
|
||||
// Set the arguments scope.
|
||||
let args_scope = Scope::new();
|
||||
self.scopes.push(args_scope);
|
||||
|
||||
let mut cache = BTreeMap::new();
|
||||
let mut type_match = BTreeSet::new();
|
||||
|
||||
for (idx, a) in args.iter().enumerate() {
|
||||
if self
|
||||
.make_bindings(false, &mut type_match, &mut cache, a, ¶m_values[idx])
|
||||
.is_err()
|
||||
{
|
||||
self.scopes = scopes;
|
||||
continue 'outer;
|
||||
}
|
||||
}
|
||||
|
||||
let ctx = Context {
|
||||
@@ -1683,12 +1727,6 @@ impl Interpreter {
|
||||
is_compr: false,
|
||||
};
|
||||
|
||||
// Back up local variables of current function and empty
|
||||
// the local variables of callee function.
|
||||
let scopes = std::mem::take(&mut self.scopes);
|
||||
|
||||
// Set the arguments scope.
|
||||
self.scopes.push(args_scope);
|
||||
let value = match self.eval_rule_bodies(ctx, span, bodies) {
|
||||
Ok(v) => v,
|
||||
Err(e) => {
|
||||
@@ -1768,10 +1806,17 @@ impl Interpreter {
|
||||
}
|
||||
Ok(Value::Bool(true))
|
||||
}
|
||||
_ => {
|
||||
_ if allow_return_arg => {
|
||||
let ret_value = self.eval_call_impl(span, fcn, ¶ms[..params.len() - 1])?;
|
||||
let value = self.eval_expr(&ea)?;
|
||||
Ok(Value::Bool(ret_value == value))
|
||||
let mut cache = BTreeMap::new();
|
||||
let mut type_match = BTreeSet::new();
|
||||
self.make_bindings(false, &mut type_match, &mut cache, &ea, &ret_value)
|
||||
.map(Value::Bool)
|
||||
}
|
||||
_ => {
|
||||
let expected = self.eval_expr(¶ms[params.len() - 1])?;
|
||||
let ret_value = self.eval_call_impl(span, fcn, ¶ms[..params.len() - 1])?;
|
||||
Ok(Value::Bool(ret_value == expected))
|
||||
}
|
||||
}
|
||||
} else {
|
||||
@@ -1813,7 +1858,7 @@ impl Interpreter {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn lookup_var(&mut self, span: &Span, fields: &[&str]) -> Result<Value> {
|
||||
fn lookup_var(&mut self, span: &Span, fields: &[&str], no_error: bool) -> Result<Value> {
|
||||
let name = span.source_str();
|
||||
|
||||
// Return local variable/argument.
|
||||
@@ -1828,6 +1873,9 @@ impl Interpreter {
|
||||
|
||||
// TODO: should we return before checking for input?
|
||||
if self.no_rules_lookup {
|
||||
if no_error {
|
||||
return Ok(Value::Undefined);
|
||||
}
|
||||
return Err(span.error("undefined var"));
|
||||
}
|
||||
|
||||
@@ -1869,6 +1917,12 @@ impl Interpreter {
|
||||
Self::get_path_string(&self.current_module()?.package.refr, Some("data"))?;
|
||||
let rule_path = module_path + "." + name.text();
|
||||
|
||||
if !no_error
|
||||
&& self.rules.get(&rule_path).is_none()
|
||||
&& self.default_rules.get(&rule_path).is_none()
|
||||
{
|
||||
bail!(span.error("var is unsafe"));
|
||||
}
|
||||
self.ensure_rule_evaluated(rule_path)?;
|
||||
|
||||
let value = Self::get_value_chained(self.data.clone(), &path[..]);
|
||||
|
||||
@@ -147,7 +147,7 @@ impl Source {
|
||||
let col_spaces = col as usize - 1;
|
||||
|
||||
format!(
|
||||
"\n-->{}:{}:{}\n{:<line_num_width$}|\n\
|
||||
"\n--> {}:{}:{}\n{:<line_num_width$}|\n\
|
||||
{:<line_num_width$}| {}\n\
|
||||
{:<line_num_width$}| {:<col_spaces$}^\n\
|
||||
{}: {}",
|
||||
|
||||
@@ -570,6 +570,15 @@ impl Analyzer {
|
||||
} else {
|
||||
gather_input_vars(expr, &self.scopes, scope)?;
|
||||
gather_loop_vars(expr, &self.scopes, scope)?;
|
||||
|
||||
let extra_arg = get_extra_arg(
|
||||
expr,
|
||||
Some(self.current_module_path.as_str()),
|
||||
&self.functions,
|
||||
);
|
||||
if let Some(ea) = extra_arg {
|
||||
gather_vars(&ea, false, &self.scopes, scope)?;
|
||||
}
|
||||
}
|
||||
}
|
||||
Literal::Every { domain, .. } => {
|
||||
@@ -600,19 +609,26 @@ impl Analyzer {
|
||||
scope: &mut Scope,
|
||||
first_use: &mut BTreeMap<SourceStr, Span>,
|
||||
definitions: &mut Vec<Definition<SourceStr>>,
|
||||
return_arg: &Option<Ref<Expr>>,
|
||||
assigned_vars: &Option<&BTreeSet<SourceStr>>,
|
||||
) -> Result<(Vec<SourceStr>, Vec<Ref<Expr>>)> {
|
||||
let mut used_vars = vec![];
|
||||
let mut comprs = vec![];
|
||||
traverse(expr, &mut |e| match e.as_ref() {
|
||||
Var(v) if !matches!(*v.text(), "_" | "input" | "data") => {
|
||||
let name = v.source_str();
|
||||
let is_extra_arg = match assigned_vars {
|
||||
Some(vars) => vars.contains(&v.source_str()),
|
||||
_ => false,
|
||||
};
|
||||
|
||||
if scope.locals.contains(&name)
|
||||
/*|| scope.inputs.contains(name) */
|
||||
{
|
||||
used_vars.push(name.clone());
|
||||
first_use.entry(name).or_insert(v.clone());
|
||||
} else if !scope.inputs.contains(&name) && Some(e.clone()) != *return_arg {
|
||||
if !is_extra_arg {
|
||||
used_vars.push(name.clone());
|
||||
first_use.entry(name).or_insert(v.clone());
|
||||
}
|
||||
} else if !scope.inputs.contains(&name) {
|
||||
bail!(v.error(format!("use of undefined variable `{name}` is unsafe").as_str()));
|
||||
}
|
||||
Ok(false)
|
||||
@@ -627,7 +643,7 @@ impl Analyzer {
|
||||
scope,
|
||||
first_use,
|
||||
definitions,
|
||||
return_arg,
|
||||
assigned_vars,
|
||||
)?;
|
||||
definitions.push(Definition {
|
||||
var: var.clone(),
|
||||
@@ -992,30 +1008,42 @@ impl Analyzer {
|
||||
&self.functions,
|
||||
);
|
||||
if let Some(ref ea) = extra_arg {
|
||||
if let Expr::Var(return_arg) = ea.as_ref() {
|
||||
let (mut used_vars, comprs) = Self::gather_used_vars_comprs_index_vars(
|
||||
expr,
|
||||
&mut scope,
|
||||
&mut first_use,
|
||||
&mut definitions,
|
||||
&extra_arg,
|
||||
)?;
|
||||
let var = if *return_arg.text() != "_" {
|
||||
// The var in the return argument slot would have been processed as
|
||||
// an used var. Remove it from used vars and add it as the variable being
|
||||
// defined.
|
||||
used_vars.pop();
|
||||
return_arg.source_str()
|
||||
} else {
|
||||
empty_str.clone()
|
||||
};
|
||||
self.process_comprs(
|
||||
&comprs[..],
|
||||
&mut scope,
|
||||
&mut first_use,
|
||||
&mut used_vars,
|
||||
)?;
|
||||
definitions.push(Definition { var, used_vars });
|
||||
// Gather vars that are being bound
|
||||
let mut extras_scope = Scope::default();
|
||||
gather_assigned_vars(ea, false, &self.scopes, &mut extras_scope)?;
|
||||
|
||||
for var in &extras_scope.locals {
|
||||
scope.locals.insert(var.clone());
|
||||
}
|
||||
|
||||
// Gather vars being used.
|
||||
let (mut used_vars, comprs) = Self::gather_used_vars_comprs_index_vars(
|
||||
expr,
|
||||
&mut scope,
|
||||
&mut first_use,
|
||||
&mut definitions,
|
||||
&Some(&extras_scope.locals),
|
||||
)?;
|
||||
|
||||
self.process_comprs(
|
||||
&comprs[..],
|
||||
&mut scope,
|
||||
&mut first_use,
|
||||
&mut used_vars,
|
||||
)?;
|
||||
|
||||
if !extras_scope.locals.is_empty() {
|
||||
for var in extras_scope.locals {
|
||||
definitions.push(Definition {
|
||||
var,
|
||||
used_vars: used_vars.clone(),
|
||||
});
|
||||
}
|
||||
} else {
|
||||
definitions.push(Definition {
|
||||
var: empty_str.clone(),
|
||||
used_vars,
|
||||
});
|
||||
}
|
||||
} else {
|
||||
self.process_expr(expr, &mut scope, &mut first_use, &mut definitions)?;
|
||||
|
||||
390
tests/aci/aci.yaml
Normal file
390
tests/aci/aci.yaml
Normal file
@@ -0,0 +1,390 @@
|
||||
# Copyright (c) Microsoft Corporation.
|
||||
# Licensed under the MIT License.
|
||||
cases:
|
||||
- note: aci/mount_device
|
||||
modules:
|
||||
- api.rego
|
||||
- framework.rego
|
||||
- policy.rego
|
||||
input:
|
||||
deviceHash: 1b80f120dbd88e4355d6241b519c3e25290215c469516b49dece9cf07175a766
|
||||
target: /run/layers/p0-layer0
|
||||
data:
|
||||
metadata: {}
|
||||
query: data.policy.mount_device=x
|
||||
want_result:
|
||||
- x:
|
||||
allowed: true
|
||||
metadata:
|
||||
- action: add
|
||||
key: /run/layers/p0-layer0
|
||||
name: devices
|
||||
value: 1b80f120dbd88e4355d6241b519c3e25290215c469516b49dece9cf07175a766
|
||||
- note: aci/mount_overlay
|
||||
modules:
|
||||
- api.rego
|
||||
- framework.rego
|
||||
- policy.rego
|
||||
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
|
||||
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
|
||||
query: data.policy.mount_overlay=x
|
||||
want_result:
|
||||
- x:
|
||||
allowed: true
|
||||
metadata:
|
||||
- action: add
|
||||
key: container0
|
||||
name: matches
|
||||
value:
|
||||
- {"allow_elevated":true,"allow_stdio_access":false,"capabilities":{"ambient":["CAP_SYS_ADMIN"],"bounding":["CAP_SYS_ADMIN"],"effective":["CAP_SYS_ADMIN"],"inheritable":["CAP_SYS_ADMIN"],"permitted":["CAP_SYS_ADMIN"]},"command":["rustc","--help"],"env_rules":[{"pattern":"PATH=/usr/local/cargo/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin","required":true,"strategy":"string"},{"pattern":"RUSTUP_HOME=/usr/local/rustup","required":true,"strategy":"string"},{"pattern":"CARGO_HOME=/usr/local/cargo","required":true,"strategy":"string"},{"pattern":"RUST_VERSION=1.52.1","required":true,"strategy":"string"},{"pattern":"TERM=xterm","required":false,"strategy":"string"},{"pattern":"PREFIX_.+=.+","required":false,"strategy":"re2"}],"exec_processes":[{"command":["top"],"signals":[]}],"layers":["fe84c9d5bfddd07a2624d00333cf13c1a9c941f3a261f13ead44fc6a93bc0e7a","4dedae42847c704da891a28c25d32201a1ae440bce2aecccfa8e6f03b97a6a6c","41d64cdeb347bf236b4c13b7403b633ff11f1cf94dbc7cf881a44d6da88c5156","eb36921e1f82af46dfe248ef8f1b3afb6a5230a64181d960d10237a08cd73c79","e769d7487cc314d3ee748a4440805317c19262c7acd2fdbdb0d47d2e4613a15c","1b80f120dbd88e4355d6241b519c3e25290215c469516b49dece9cf07175a766"],"mounts":[{"destination":"/container/path/one","options":["rbind","rshared","rw"],"source":"sandbox:///host/path/one","type":"bind"},{"destination":"/container/path/two","options":["rbind","rshared","ro"],"source":"sandbox:///host/path/two","type":"bind"}],"no_new_privileges":true,"seccomp_profile_sha256":"","signals":[],"user":{"group_idnames":[{"pattern":"","strategy":"any"}],"umask":"0022","user_idname":{"pattern":"","strategy":"any"}},"working_dir":"/home/user"}
|
||||
- action: add
|
||||
key: /run/gcs/c/container0/rootfs
|
||||
name: overlayTargets
|
||||
value: true
|
||||
- note: aci/scratch_mount
|
||||
modules:
|
||||
- api.rego
|
||||
- framework.rego
|
||||
- policy.rego
|
||||
input:
|
||||
encrypted: true
|
||||
target: /mnt/layer6
|
||||
data:
|
||||
metadata: {}
|
||||
query: data.policy.scratch_mount=x
|
||||
want_result:
|
||||
- x:
|
||||
allowed: true
|
||||
metadata:
|
||||
- action: add
|
||||
key: /mnt/layer6
|
||||
name: scratch_mounts
|
||||
value:
|
||||
encrypted: true
|
||||
- note: aci/create_container
|
||||
modules:
|
||||
- api.rego
|
||||
- framework.rego
|
||||
- policy.rego
|
||||
input:
|
||||
argList:
|
||||
- rustc
|
||||
- --help
|
||||
capabilities:
|
||||
ambient: ["CAP_SYS_ADMIN"]
|
||||
bounding: ["CAP_SYS_ADMIN"]
|
||||
effective: ["CAP_SYS_ADMIN"]
|
||||
inheritable: ["CAP_SYS_ADMIN"]
|
||||
permitted: ["CAP_SYS_ADMIN"]
|
||||
containerID: container0
|
||||
envList:
|
||||
- CARGO_HOME=/usr/local/cargo
|
||||
- RUST_VERSION=1.52.1
|
||||
- TERM=xterm
|
||||
- PATH=/usr/local/cargo/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
|
||||
- RUSTUP_HOME=/usr/local/rustup
|
||||
groups:
|
||||
- id: 0
|
||||
name: root
|
||||
hugePagesDir: /run/gcs/c/sandbox0/hugepages
|
||||
mounts:
|
||||
- destination: /container/path/one
|
||||
options: ["rbind", "rshared", "rw"]
|
||||
source: /run/gcs/c/sandbox0/sandboxMounts/host/path/one
|
||||
type: bind
|
||||
- destination: /container/path/two
|
||||
options: ["rbind", "rshared", "ro"]
|
||||
source: /run/gcs/c/sandbox0/sandboxMounts/host/path/two
|
||||
type: bind
|
||||
noNewPrivileges: true
|
||||
privileged: false
|
||||
seccompProfileSHA256: ""
|
||||
sandboxDir: /run/gcs/c/sandbox0/sandboxMounts
|
||||
umask: "0022"
|
||||
user:
|
||||
id: 0
|
||||
name: root
|
||||
workingDir: /home/user
|
||||
data:
|
||||
sandboxPrefix: "sandbox://"
|
||||
hugePagesPrefix: "hugepages://"
|
||||
plan9Prefix: "plan9://"
|
||||
defaultMounts: []
|
||||
privilegedMounts: []
|
||||
defaultPrivilegedCapabilities:
|
||||
- CAP_CHOWN
|
||||
- CAP_DAC_OVERRIDE
|
||||
- CAP_DAC_READ_SEARCH
|
||||
- CAP_FOWNER
|
||||
- CAP_FSETID
|
||||
- CAP_KILL
|
||||
- CAP_SETGID
|
||||
- CAP_SETUID
|
||||
- CAP_SETPCAP
|
||||
- CAP_LINUX_IMMUTABLE
|
||||
- CAP_NET_BIND_SERVICE
|
||||
- CAP_NET_BROADCAST
|
||||
- CAP_NET_ADMIN
|
||||
- CAP_NET_RAW
|
||||
- CAP_IPC_LOCK
|
||||
- CAP_IPC_OWNER
|
||||
- CAP_SYS_MODULE
|
||||
- CAP_SYS_RAWIO
|
||||
- CAP_SYS_CHROOT
|
||||
- CAP_SYS_PTRACE
|
||||
- CAP_SYS_PACCT
|
||||
- CAP_SYS_ADMIN
|
||||
- CAP_SYS_BOOT
|
||||
- CAP_SYS_NICE
|
||||
- CAP_SYS_RESOURCE
|
||||
- CAP_SYS_TIME
|
||||
- CAP_SYS_TTY_CONFIG
|
||||
- CAP_MKNOD
|
||||
- CAP_LEASE
|
||||
- CAP_AUDIT_WRITE
|
||||
- CAP_AUDIT_CONTROL
|
||||
- CAP_SETFCAP
|
||||
- CAP_MAC_OVERRIDE
|
||||
- CAP_MAC_ADMIN
|
||||
- CAP_SYSLOG
|
||||
- CAP_WAKE_ALARM
|
||||
- CAP_BLOCK_SUSPEND
|
||||
- CAP_AUDIT_READ
|
||||
- CAP_PERFMON
|
||||
- CAP_BPF
|
||||
- CAP_CHECKPOINT_RESTORE
|
||||
defaultUnprivilegedCapabilities:
|
||||
- CAP_DAC_OVERRIDE
|
||||
- CAP_FSETID
|
||||
- CAP_FOWNER
|
||||
- CAP_MKNOD
|
||||
- CAP_NET_RAW
|
||||
- CAP_SETGID
|
||||
- CAP_SETUID
|
||||
- CAP_SETFCAP
|
||||
- CAP_SETPCAP
|
||||
- CAP_NET_BIND_SERVICE
|
||||
- CAP_SYS_CHROOT
|
||||
- CAP_KILL
|
||||
- CAP_AUDIT_WRITE
|
||||
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
|
||||
matches:
|
||||
container0:
|
||||
- {"allow_elevated":true,"allow_stdio_access":false,"capabilities":{"ambient":["CAP_SYS_ADMIN"],"bounding":["CAP_SYS_ADMIN"],"effective":["CAP_SYS_ADMIN"],"inheritable":["CAP_SYS_ADMIN"],"permitted":["CAP_SYS_ADMIN"]},"command":["rustc","--help"],"env_rules":[{"pattern":"PATH=/usr/local/cargo/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin","required":true,"strategy":"string"},{"pattern":"RUSTUP_HOME=/usr/local/rustup","required":true,"strategy":"string"},{"pattern":"CARGO_HOME=/usr/local/cargo","required":true,"strategy":"string"},{"pattern":"RUST_VERSION=1.52.1","required":true,"strategy":"string"},{"pattern":"TERM=xterm","required":false,"strategy":"string"},{"pattern":"PREFIX_.+=.+","required":false,"strategy":"re2"}],"exec_processes":[{"command":["top"],"signals":[]}],"layers":["fe84c9d5bfddd07a2624d00333cf13c1a9c941f3a261f13ead44fc6a93bc0e7a","4dedae42847c704da891a28c25d32201a1ae440bce2aecccfa8e6f03b97a6a6c","41d64cdeb347bf236b4c13b7403b633ff11f1cf94dbc7cf881a44d6da88c5156","eb36921e1f82af46dfe248ef8f1b3afb6a5230a64181d960d10237a08cd73c79","e769d7487cc314d3ee748a4440805317c19262c7acd2fdbdb0d47d2e4613a15c","1b80f120dbd88e4355d6241b519c3e25290215c469516b49dece9cf07175a766"],"mounts":[{"destination":"/container/path/one","options":["rbind","rshared","rw"],"source":"sandbox:///host/path/one","type":"bind"},{"destination":"/container/path/two","options":["rbind","rshared","ro"],"source":"sandbox:///host/path/two","type":"bind"}],"no_new_privileges":true,"seccomp_profile_sha256":"","signals":[],"user":{"group_idnames":[{"pattern":"","strategy":"any"}],"umask":"0022","user_idname":{"pattern":"","strategy":"any"}},"working_dir":"/home/user"}
|
||||
- {"allow_elevated":false,"allow_stdio_access":false,"capabilities":null,"command":["rustc","--version"],"env_rules":[{"pattern":"PATH=/usr/local/cargo/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin","required":true,"strategy":"string"},{"pattern":"RUSTUP_HOME=/usr/local/rustup","required":true,"strategy":"string"},{"pattern":"CARGO_HOME=/usr/local/cargo","required":true,"strategy":"string"},{"pattern":"RUST_VERSION=1.52.1","required":true,"strategy":"string"},{"pattern":"TERM=xterm","required":false,"strategy":"string"}],"exec_processes":[{"command":["bash"],"signals":[]}],"layers":["fe84c9d5bfddd07a2624d00333cf13c1a9c941f3a261f13ead44fc6a93bc0e7a","4dedae42847c704da891a28c25d32201a1ae440bce2aecccfa8e6f03b97a6a6c","41d64cdeb347bf236b4c13b7403b633ff11f1cf94dbc7cf881a44d6da88c5156","eb36921e1f82af46dfe248ef8f1b3afb6a5230a64181d960d10237a08cd73c79","e769d7487cc314d3ee748a4440805317c19262c7acd2fdbdb0d47d2e4613a15c","1b80f120dbd88e4355d6241b519c3e25290215c469516b49dece9cf07175a766"],"mounts":[],"no_new_privileges":true,"seccomp_profile_sha256":"","signals":[],"user":{"group_idnames":[{"pattern":"","strategy":"any"}],"umask":"0022","user_idname":{"pattern":"","strategy":"any"}},"working_dir":"/home/fragment"}
|
||||
overlayTargets:
|
||||
"/run/gcs/c/container0/rootfs": true
|
||||
scratch_mounts:
|
||||
"/mnt/layer6":
|
||||
encrypted: true
|
||||
query: data.policy.create_container=x
|
||||
want_result:
|
||||
- x:
|
||||
allow_stdio_access: false
|
||||
allowed: true
|
||||
caps_list:
|
||||
ambient: ["CAP_SYS_ADMIN"]
|
||||
bounding: ["CAP_SYS_ADMIN"]
|
||||
effective: ["CAP_SYS_ADMIN"]
|
||||
inheritable: ["CAP_SYS_ADMIN"]
|
||||
permitted: ["CAP_SYS_ADMIN"]
|
||||
env_list:
|
||||
- CARGO_HOME=/usr/local/cargo
|
||||
- RUST_VERSION=1.52.1
|
||||
- TERM=xterm
|
||||
- PATH=/usr/local/cargo/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
|
||||
- RUSTUP_HOME=/usr/local/rustup
|
||||
metadata:
|
||||
- action: update
|
||||
key: container0
|
||||
name: matches
|
||||
value:
|
||||
- {"allow_elevated":true,"allow_stdio_access":false,"capabilities":{"ambient":["CAP_SYS_ADMIN"],"bounding":["CAP_SYS_ADMIN"],"effective":["CAP_SYS_ADMIN"],"inheritable":["CAP_SYS_ADMIN"],"permitted":["CAP_SYS_ADMIN"]},"command":["rustc","--help"],"env_rules":[{"pattern":"PATH=/usr/local/cargo/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin","required":true,"strategy":"string"},{"pattern":"RUSTUP_HOME=/usr/local/rustup","required":true,"strategy":"string"},{"pattern":"CARGO_HOME=/usr/local/cargo","required":true,"strategy":"string"},{"pattern":"RUST_VERSION=1.52.1","required":true,"strategy":"string"},{"pattern":"TERM=xterm","required":false,"strategy":"string"},{"pattern":"PREFIX_.+=.+","required":false,"strategy":"re2"}],"exec_processes":[{"command":["top"],"signals":[]}],"layers":["fe84c9d5bfddd07a2624d00333cf13c1a9c941f3a261f13ead44fc6a93bc0e7a","4dedae42847c704da891a28c25d32201a1ae440bce2aecccfa8e6f03b97a6a6c","41d64cdeb347bf236b4c13b7403b633ff11f1cf94dbc7cf881a44d6da88c5156","eb36921e1f82af46dfe248ef8f1b3afb6a5230a64181d960d10237a08cd73c79","e769d7487cc314d3ee748a4440805317c19262c7acd2fdbdb0d47d2e4613a15c","1b80f120dbd88e4355d6241b519c3e25290215c469516b49dece9cf07175a766"],"mounts":[{"destination":"/container/path/one","options":["rbind","rshared","rw"],"source":"sandbox:///host/path/one","type":"bind"},{"destination":"/container/path/two","options":["rbind","rshared","ro"],"source":"sandbox:///host/path/two","type":"bind"}],"no_new_privileges":true,"seccomp_profile_sha256":"","signals":[],"user":{"group_idnames":[{"pattern":"","strategy":"any"}],"umask":"0022","user_idname":{"pattern":"","strategy":"any"}},"working_dir":"/home/user"}
|
||||
- action: add
|
||||
key: container0
|
||||
name: started
|
||||
value:
|
||||
privileged: false
|
||||
- note: aci/shutdown_container
|
||||
modules:
|
||||
- api.rego
|
||||
- framework.rego
|
||||
- policy.rego
|
||||
input:
|
||||
containerID: container0
|
||||
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
|
||||
matches:
|
||||
container0:
|
||||
- {"allow_elevated":true,"allow_stdio_access":false,"capabilities":{"ambient":["CAP_SYS_ADMIN"],"bounding":["CAP_SYS_ADMIN"],"effective":["CAP_SYS_ADMIN"],"inheritable":["CAP_SYS_ADMIN"],"permitted":["CAP_SYS_ADMIN"]},"command":["rustc","--help"],"env_rules":[{"pattern":"PATH=/usr/local/cargo/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin","required":true,"strategy":"string"},{"pattern":"RUSTUP_HOME=/usr/local/rustup","required":true,"strategy":"string"},{"pattern":"CARGO_HOME=/usr/local/cargo","required":true,"strategy":"string"},{"pattern":"RUST_VERSION=1.52.1","required":true,"strategy":"string"},{"pattern":"TERM=xterm","required":false,"strategy":"string"},{"pattern":"PREFIX_.+=.+","required":false,"strategy":"re2"}],"exec_processes":[{"command":["top"],"signals":[]}],"layers":["fe84c9d5bfddd07a2624d00333cf13c1a9c941f3a261f13ead44fc6a93bc0e7a","4dedae42847c704da891a28c25d32201a1ae440bce2aecccfa8e6f03b97a6a6c","41d64cdeb347bf236b4c13b7403b633ff11f1cf94dbc7cf881a44d6da88c5156","eb36921e1f82af46dfe248ef8f1b3afb6a5230a64181d960d10237a08cd73c79","e769d7487cc314d3ee748a4440805317c19262c7acd2fdbdb0d47d2e4613a15c","1b80f120dbd88e4355d6241b519c3e25290215c469516b49dece9cf07175a766"],"mounts":[{"destination":"/container/path/one","options":["rbind","rshared","rw"],"source":"sandbox:///host/path/one","type":"bind"},{"destination":"/container/path/two","options":["rbind","rshared","ro"],"source":"sandbox:///host/path/two","type":"bind"}],"no_new_privileges":true,"seccomp_profile_sha256":"","signals":[],"user":{"group_idnames":[{"pattern":"","strategy":"any"}],"umask":"0022","user_idname":{"pattern":"","strategy":"any"}},"working_dir":"/home/user"}
|
||||
- {"allow_elevated":false,"allow_stdio_access":false,"capabilities":null,"command":["rustc","--version"],"env_rules":[{"pattern":"PATH=/usr/local/cargo/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin","required":true,"strategy":"string"},{"pattern":"RUSTUP_HOME=/usr/local/rustup","required":true,"strategy":"string"},{"pattern":"CARGO_HOME=/usr/local/cargo","required":true,"strategy":"string"},{"pattern":"RUST_VERSION=1.52.1","required":true,"strategy":"string"},{"pattern":"TERM=xterm","required":false,"strategy":"string"}],"exec_processes":[{"command":["bash"],"signals":[]}],"layers":["fe84c9d5bfddd07a2624d00333cf13c1a9c941f3a261f13ead44fc6a93bc0e7a","4dedae42847c704da891a28c25d32201a1ae440bce2aecccfa8e6f03b97a6a6c","41d64cdeb347bf236b4c13b7403b633ff11f1cf94dbc7cf881a44d6da88c5156","eb36921e1f82af46dfe248ef8f1b3afb6a5230a64181d960d10237a08cd73c79","e769d7487cc314d3ee748a4440805317c19262c7acd2fdbdb0d47d2e4613a15c","1b80f120dbd88e4355d6241b519c3e25290215c469516b49dece9cf07175a766"],"mounts":[],"no_new_privileges":true,"seccomp_profile_sha256":"","signals":[],"user":{"group_idnames":[{"pattern":"","strategy":"any"}],"umask":"0022","user_idname":{"pattern":"","strategy":"any"}},"working_dir":"/home/fragment"}
|
||||
overlayTargets:
|
||||
"/run/gcs/c/container0/rootfs": true
|
||||
scratch_mounts:
|
||||
"/mnt/layer6":
|
||||
encrypted: true
|
||||
started:
|
||||
container0:
|
||||
- {"privileged": false}
|
||||
query: data.policy.shutdown_container=x
|
||||
want_result:
|
||||
- x:
|
||||
allowed: true
|
||||
metadata:
|
||||
- action: remove
|
||||
key: container0
|
||||
name: matches
|
||||
- note: aci/scratch_unmount
|
||||
modules:
|
||||
- api.rego
|
||||
- framework.rego
|
||||
- policy.rego
|
||||
input:
|
||||
unmountTarget: /mnt/layer6
|
||||
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
|
||||
overlayTargets:
|
||||
"/run/gcs/c/container0/rootfs": true
|
||||
scratch_mounts:
|
||||
"/mnt/layer6":
|
||||
encrypted: true
|
||||
query: data.policy.scratch_unmount=x
|
||||
want_result:
|
||||
- x:
|
||||
allowed: true
|
||||
metadata:
|
||||
- action: remove
|
||||
key: /mnt/layer6
|
||||
name: scratch_mounts
|
||||
- note: aci/unmount_overlay
|
||||
modules:
|
||||
- api.rego
|
||||
- framework.rego
|
||||
- policy.rego
|
||||
input:
|
||||
unmountTarget: /run/gcs/c/container0/rootfs
|
||||
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
|
||||
overlayTargets:
|
||||
"/run/gcs/c/container0/rootfs": true
|
||||
scratch_mounts: []
|
||||
query: data.policy.unmount_overlay=x
|
||||
want_result:
|
||||
- x:
|
||||
allowed: true
|
||||
metadata:
|
||||
- action: remove
|
||||
key: /run/gcs/c/container0/rootfs
|
||||
name: overlayTargets
|
||||
- note: aci/unmount_device
|
||||
modules:
|
||||
- api.rego
|
||||
- framework.rego
|
||||
- policy.rego
|
||||
input:
|
||||
unmountTarget: /run/layers/p0-layer0
|
||||
data:
|
||||
metadata:
|
||||
devices:
|
||||
"/run/layers/p0-layer0": 1b80f120dbd88e4355d6241b519c3e25290215c469516b49dece9cf07175a766
|
||||
query: data.policy.unmount_device=x
|
||||
want_result:
|
||||
- x:
|
||||
allowed: true
|
||||
metadata:
|
||||
- action: remove
|
||||
key: /run/layers/p0-layer0
|
||||
name: devices
|
||||
- note: aci/load_fragment
|
||||
modules:
|
||||
- api.rego
|
||||
- framework.rego
|
||||
- policy.rego
|
||||
- |
|
||||
package fragment
|
||||
|
||||
svn := "1"
|
||||
framework_version := "0.3.0"
|
||||
|
||||
containers := [
|
||||
{
|
||||
"command": ["rustc","--version"],
|
||||
"env_rules": [{"pattern": `PATH=/usr/local/cargo/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin`, "strategy": "string", "required": true},{"pattern": `RUSTUP_HOME=/usr/local/rustup`, "strategy": "string", "required": true},{"pattern": `CARGO_HOME=/usr/local/cargo`, "strategy": "string", "required": true},{"pattern": `RUST_VERSION=1.52.1`, "strategy": "string", "required": true},{"pattern": `TERM=xterm`, "strategy": "string", "required": false}],
|
||||
"layers": ["fe84c9d5bfddd07a2624d00333cf13c1a9c941f3a261f13ead44fc6a93bc0e7a","4dedae42847c704da891a28c25d32201a1ae440bce2aecccfa8e6f03b97a6a6c","41d64cdeb347bf236b4c13b7403b633ff11f1cf94dbc7cf881a44d6da88c5156","eb36921e1f82af46dfe248ef8f1b3afb6a5230a64181d960d10237a08cd73c79","e769d7487cc314d3ee748a4440805317c19262c7acd2fdbdb0d47d2e4613a15c","1b80f120dbd88e4355d6241b519c3e25290215c469516b49dece9cf07175a766"],
|
||||
"mounts": [],
|
||||
"exec_processes": [{"command": ["bash"], "signals": []}],
|
||||
"signals": [],
|
||||
"user": {
|
||||
"user_idname": {"pattern": ``, "strategy": "any"},
|
||||
"group_idnames": [{"pattern": ``, "strategy": "any"}],
|
||||
"umask": "0022"
|
||||
},
|
||||
"capabilities": null,
|
||||
"seccomp_profile_sha256": "",
|
||||
"allow_elevated": false,
|
||||
"working_dir": "/home/fragment",
|
||||
"allow_stdio_access": false,
|
||||
"no_new_privileges": true,
|
||||
},
|
||||
]
|
||||
input:
|
||||
feed: contoso.azurecr.io/infra
|
||||
issuer: did:web:contoso.com
|
||||
namespace: fragment
|
||||
data:
|
||||
metadata: {}
|
||||
query: data.policy.load_fragment=x
|
||||
want_result:
|
||||
- x:
|
||||
add_module: false
|
||||
allowed: true
|
||||
metadata:
|
||||
- action: update
|
||||
key: did:web:contoso.com
|
||||
name: issuers
|
||||
value: {"feeds":{"contoso.azurecr.io/infra":[{"containers":[{"allow_elevated":false,"allow_stdio_access":false,"capabilities":null,"command":["rustc","--version"],"env_rules":[{"pattern":"PATH=/usr/local/cargo/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin","required":true,"strategy":"string"},{"pattern":"RUSTUP_HOME=/usr/local/rustup","required":true,"strategy":"string"},{"pattern":"CARGO_HOME=/usr/local/cargo","required":true,"strategy":"string"},{"pattern":"RUST_VERSION=1.52.1","required":true,"strategy":"string"},{"pattern":"TERM=xterm","required":false,"strategy":"string"}],"exec_processes":[{"command":["bash"],"signals":[]}],"layers":["fe84c9d5bfddd07a2624d00333cf13c1a9c941f3a261f13ead44fc6a93bc0e7a","4dedae42847c704da891a28c25d32201a1ae440bce2aecccfa8e6f03b97a6a6c","41d64cdeb347bf236b4c13b7403b633ff11f1cf94dbc7cf881a44d6da88c5156","eb36921e1f82af46dfe248ef8f1b3afb6a5230a64181d960d10237a08cd73c79","e769d7487cc314d3ee748a4440805317c19262c7acd2fdbdb0d47d2e4613a15c","1b80f120dbd88e4355d6241b519c3e25290215c469516b49dece9cf07175a766"],"mounts":[],"no_new_privileges":true,"seccomp_profile_sha256":"","signals":[],"user":{"group_idnames":[{"pattern":"","strategy":"any"}],"umask":"0022","user_idname":{"pattern":"","strategy":"any"}},"working_dir":"/home/fragment"}]}]}}
|
||||
26
tests/aci/api.rego
Normal file
26
tests/aci/api.rego
Normal file
@@ -0,0 +1,26 @@
|
||||
# Copyright (c) Microsoft Corporation.
|
||||
# Licensed under the MIT License.
|
||||
|
||||
package api
|
||||
|
||||
version := "0.10.0"
|
||||
|
||||
enforcement_points := {
|
||||
"mount_device": {"introducedVersion": "0.1.0", "default_results": {"allowed": false}},
|
||||
"mount_overlay": {"introducedVersion": "0.1.0", "default_results": {"allowed": false}},
|
||||
"create_container": {"introducedVersion": "0.1.0", "default_results": {"allowed": false, "env_list": null, "allow_stdio_access": false}},
|
||||
"unmount_device": {"introducedVersion": "0.2.0", "default_results": {"allowed": true}},
|
||||
"unmount_overlay": {"introducedVersion": "0.6.0", "default_results": {"allowed": true}},
|
||||
"exec_in_container": {"introducedVersion": "0.2.0", "default_results": {"allowed": true, "env_list": null}},
|
||||
"exec_external": {"introducedVersion": "0.3.0", "default_results": {"allowed": true, "env_list": null, "allow_stdio_access": false}},
|
||||
"shutdown_container": {"introducedVersion": "0.4.0", "default_results": {"allowed": true}},
|
||||
"signal_container_process": {"introducedVersion": "0.5.0", "default_results": {"allowed": true}},
|
||||
"plan9_mount": {"introducedVersion": "0.6.0", "default_results": {"allowed": true}},
|
||||
"plan9_unmount": {"introducedVersion": "0.6.0", "default_results": {"allowed": true}},
|
||||
"get_properties": {"introducedVersion": "0.7.0", "default_results": {"allowed": true}},
|
||||
"dump_stacks": {"introducedVersion": "0.7.0", "default_results": {"allowed": true}},
|
||||
"runtime_logging": {"introducedVersion": "0.8.0", "default_results": {"allowed": true}},
|
||||
"load_fragment": {"introducedVersion": "0.9.0", "default_results": {"allowed": false, "add_module": false}},
|
||||
"scratch_mount": {"introducedVersion": "0.10.0", "default_results": {"allowed": true}},
|
||||
"scratch_unmount": {"introducedVersion": "0.10.0", "default_results": {"allowed": true}},
|
||||
}
|
||||
1831
tests/aci/framework.rego
Normal file
1831
tests/aci/framework.rego
Normal file
File diff suppressed because it is too large
Load Diff
120
tests/aci/main.rs
Normal file
120
tests/aci/main.rs
Normal file
@@ -0,0 +1,120 @@
|
||||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT License.
|
||||
use regorus::*;
|
||||
|
||||
use std::path::Path;
|
||||
use std::time::Instant;
|
||||
|
||||
use anyhow::Result;
|
||||
use clap::Parser;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use walkdir::WalkDir;
|
||||
|
||||
#[derive(Serialize, Deserialize, PartialEq, Debug)]
|
||||
struct TestCase {
|
||||
note: String,
|
||||
data: Value,
|
||||
input: Value,
|
||||
modules: Vec<String>,
|
||||
query: String,
|
||||
want_result: Value,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, PartialEq, Debug)]
|
||||
struct YamlTest {
|
||||
cases: Vec<TestCase>,
|
||||
}
|
||||
|
||||
fn eval_test_case(dir: &Path, case: &TestCase) -> Result<Value> {
|
||||
let mut engine = Engine::new();
|
||||
|
||||
engine.add_data(case.data.clone())?;
|
||||
engine.set_input(case.input.clone());
|
||||
|
||||
for (idx, rego) in case.modules.iter().enumerate() {
|
||||
if rego.ends_with(".rego") {
|
||||
let path = dir.join(rego);
|
||||
let path = path.to_str().expect("not a valid path");
|
||||
engine.add_policy_from_file(path.to_string())?;
|
||||
} else {
|
||||
engine.add_policy(format!("rego{idx}.rego"), rego.clone())?;
|
||||
}
|
||||
}
|
||||
|
||||
let query_results = engine.eval_query(case.query.clone(), true)?;
|
||||
|
||||
let mut values = vec![];
|
||||
for qr in query_results.result {
|
||||
values.push(if !qr.bindings.is_empty_object() {
|
||||
qr.bindings.clone()
|
||||
} else if let Some(v) = qr.expressions.last() {
|
||||
v["value"].clone()
|
||||
} else {
|
||||
Value::Undefined
|
||||
});
|
||||
}
|
||||
let result = Value::from_array(values);
|
||||
// Make result json compatible. (E.g: avoid sets).
|
||||
Value::from_json_str(&result.to_string())
|
||||
}
|
||||
|
||||
fn run_aci_tests(dir: &Path) -> Result<()> {
|
||||
let mut nfailures = 0;
|
||||
for entry in WalkDir::new(dir)
|
||||
.sort_by_file_name()
|
||||
.into_iter()
|
||||
.filter_map(|e| e.ok())
|
||||
{
|
||||
let path = entry.path();
|
||||
if !path.to_string_lossy().ends_with(".yaml") {
|
||||
continue;
|
||||
}
|
||||
|
||||
let yaml = std::fs::read(&path)?;
|
||||
let yaml = String::from_utf8_lossy(&yaml);
|
||||
let test: YamlTest = serde_yaml::from_str(&yaml)?;
|
||||
|
||||
for case in &test.cases {
|
||||
print!("{:50}", case.note);
|
||||
let start = Instant::now();
|
||||
let results = eval_test_case(dir, case);
|
||||
let duration = start.elapsed();
|
||||
|
||||
match results {
|
||||
Ok(actual) if actual == case.want_result => {
|
||||
println!("passed {:?}", duration);
|
||||
}
|
||||
Ok(actual) => {
|
||||
println!("failed {:?}", duration);
|
||||
println!("ACTUAL:");
|
||||
println!("{}", serde_json::to_string(&actual)?);
|
||||
println!("EXPECTED");
|
||||
println!("{}", serde_json::to_string(&case.want_result)?);
|
||||
nfailures += 1;
|
||||
}
|
||||
Err(e) => {
|
||||
println!("failed {:?}", duration);
|
||||
println!("{e}");
|
||||
nfailures += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
assert!(nfailures == 0);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[derive(clap::Parser)]
|
||||
#[command(author, version, about, long_about = None)]
|
||||
struct Cli {
|
||||
/// Path to ACI test suite.
|
||||
#[arg(long, short)]
|
||||
#[clap(default_value = "tests/aci")]
|
||||
test_dir: String,
|
||||
}
|
||||
|
||||
fn main() -> Result<()> {
|
||||
let cli = Cli::parse();
|
||||
run_aci_tests(&Path::new(&cli.test_dir))
|
||||
}
|
||||
89
tests/aci/policy.rego
Normal file
89
tests/aci/policy.rego
Normal file
@@ -0,0 +1,89 @@
|
||||
# Copyright (c) Microsoft Corporation.
|
||||
# Licensed under the MIT License.
|
||||
|
||||
package policy
|
||||
|
||||
api_version := "0.10.0"
|
||||
framework_version := "0.3.0"
|
||||
|
||||
fragments := [
|
||||
{"issuer": "did:web:contoso.com", "feed": "contoso.azurecr.io/infra", "minimum_svn": "1", "includes": ["containers"]},
|
||||
]
|
||||
containers := [
|
||||
{
|
||||
"command": ["rustc","--help"],
|
||||
"env_rules": [{"pattern": `PATH=/usr/local/cargo/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin`, "strategy": "string", "required": true},{"pattern": `RUSTUP_HOME=/usr/local/rustup`, "strategy": "string", "required": true},{"pattern": `CARGO_HOME=/usr/local/cargo`, "strategy": "string", "required": true},{"pattern": `RUST_VERSION=1.52.1`, "strategy": "string", "required": true},{"pattern": `TERM=xterm`, "strategy": "string", "required": false},{"pattern": `PREFIX_.+=.+`, "strategy": "re2", "required": false}],
|
||||
"layers": ["fe84c9d5bfddd07a2624d00333cf13c1a9c941f3a261f13ead44fc6a93bc0e7a","4dedae42847c704da891a28c25d32201a1ae440bce2aecccfa8e6f03b97a6a6c","41d64cdeb347bf236b4c13b7403b633ff11f1cf94dbc7cf881a44d6da88c5156","eb36921e1f82af46dfe248ef8f1b3afb6a5230a64181d960d10237a08cd73c79","e769d7487cc314d3ee748a4440805317c19262c7acd2fdbdb0d47d2e4613a15c","1b80f120dbd88e4355d6241b519c3e25290215c469516b49dece9cf07175a766"],
|
||||
"mounts": [{"destination": "/container/path/one", "options": ["rbind","rshared","rw"], "source": "sandbox:///host/path/one", "type": "bind"},{"destination": "/container/path/two", "options": ["rbind","rshared","ro"], "source": "sandbox:///host/path/two", "type": "bind"}],
|
||||
"exec_processes": [{"command": ["top"], "signals": []}],
|
||||
"signals": [],
|
||||
"user": {
|
||||
"user_idname": {"pattern": ``, "strategy": "any"},
|
||||
"group_idnames": [{"pattern": ``, "strategy": "any"}],
|
||||
"umask": "0022"
|
||||
},
|
||||
"capabilities": {
|
||||
"bounding": ["CAP_SYS_ADMIN"],
|
||||
"effective": ["CAP_SYS_ADMIN"],
|
||||
"inheritable": ["CAP_SYS_ADMIN"],
|
||||
"permitted": ["CAP_SYS_ADMIN"],
|
||||
"ambient": ["CAP_SYS_ADMIN"],
|
||||
},
|
||||
"seccomp_profile_sha256": "",
|
||||
"allow_elevated": true,
|
||||
"working_dir": "/home/user",
|
||||
"allow_stdio_access": false,
|
||||
"no_new_privileges": true,
|
||||
},
|
||||
{
|
||||
"command": ["/pause"],
|
||||
"env_rules": [{"pattern": `PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin`, "strategy": "string", "required": true},{"pattern": `TERM=xterm`, "strategy": "string", "required": false}],
|
||||
"layers": ["16b514057a06ad665f92c02863aca074fd5976c755d26bff16365299169e8415"],
|
||||
"mounts": [],
|
||||
"exec_processes": [],
|
||||
"signals": [],
|
||||
"user": {
|
||||
"user_idname": {"pattern": ``, "strategy": "any"},
|
||||
"group_idnames": [{"pattern": ``, "strategy": "any"}],
|
||||
"umask": "0022"
|
||||
},
|
||||
"capabilities": null,
|
||||
"seccomp_profile_sha256": "",
|
||||
"allow_elevated": false,
|
||||
"working_dir": "/",
|
||||
"allow_stdio_access": false,
|
||||
"no_new_privileges": true,
|
||||
},
|
||||
]
|
||||
external_processes := [
|
||||
{"command": ["bash"], "env_rules": [{"pattern": `PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin`, "strategy": "string", "required": true}], "working_dir": "/", "allow_stdio_access": false},
|
||||
]
|
||||
allow_properties_access := false
|
||||
allow_dump_stacks := false
|
||||
allow_runtime_logging := false
|
||||
allow_environment_variable_dropping := false
|
||||
allow_unencrypted_scratch := false
|
||||
allow_capability_dropping := true
|
||||
|
||||
|
||||
mount_device := data.framework.mount_device
|
||||
unmount_device := data.framework.unmount_device
|
||||
mount_overlay := data.framework.mount_overlay
|
||||
unmount_overlay := data.framework.unmount_overlay
|
||||
create_container := data.framework.create_container
|
||||
exec_in_container := data.framework.exec_in_container
|
||||
exec_external := data.framework.exec_external
|
||||
shutdown_container := data.framework.shutdown_container
|
||||
signal_container_process := data.framework.signal_container_process
|
||||
plan9_mount := data.framework.plan9_mount
|
||||
plan9_unmount := data.framework.plan9_unmount
|
||||
get_properties := data.framework.get_properties
|
||||
dump_stacks := data.framework.dump_stacks
|
||||
runtime_logging := data.framework.runtime_logging
|
||||
load_fragment := data.framework.load_fragment
|
||||
scratch_mount := data.framework.scratch_mount
|
||||
scratch_unmount := data.framework.scratch_unmount
|
||||
reason := {
|
||||
"errors": data.framework.errors,
|
||||
"error_objects": data.framework.error_objects,
|
||||
}
|
||||
@@ -16,6 +16,7 @@ embeddedvirtualdoc
|
||||
evaltermexpr
|
||||
example
|
||||
fix1863
|
||||
indexing
|
||||
intersection
|
||||
invalidkeyerror
|
||||
jsonfilteridempotent
|
||||
@@ -26,6 +27,9 @@ objectremoveidempotent
|
||||
objectremovenonstringkey
|
||||
partialsetdoc
|
||||
rand
|
||||
regexisvalid
|
||||
regexmatch
|
||||
regexsplit
|
||||
replacen
|
||||
semvercompare
|
||||
sets
|
||||
@@ -35,8 +39,10 @@ trim
|
||||
trimleft
|
||||
trimprefix
|
||||
trimright
|
||||
trimspace
|
||||
trimsuffix
|
||||
typebuiltin
|
||||
typenamebuiltin
|
||||
undos
|
||||
union
|
||||
units
|
||||
@@ -121,7 +121,12 @@ fn run_opa_tests(opa_tests_dir: String, folders: &[String]) -> Result<()> {
|
||||
}
|
||||
(r, _) => {
|
||||
print!("\n{} failed.", case.note);
|
||||
dbg!((&case, &r));
|
||||
println!("{}", serde_yaml::to_string(&case)?);
|
||||
match &r {
|
||||
Ok(actual) => println!("GOT\n{}", serde_yaml::to_string(&actual)?),
|
||||
Err(e) => println!("ERROR: {e}"),
|
||||
}
|
||||
|
||||
if let Err(e) = r {
|
||||
let msg = e.to_string();
|
||||
let pat = "could not find function ";
|
||||
|
||||
Reference in New Issue
Block a user