Fix formatting

Signed-off-by: Till Wegmueller <toasterson@gmail.com>
This commit is contained in:
Till Wegmueller 2026-02-08 20:30:52 +01:00
parent df57dda960
commit 4f0dac7645
No known key found for this signature in database
6 changed files with 95 additions and 83 deletions

View file

@ -476,7 +476,10 @@ fn eval_value(expr: &Expr, context: &Value) -> Result<EvalResult, AuthzError> {
)),
}
}
Expr::In { element, collection } => {
Expr::In {
element,
collection,
} => {
let elem = eval_value(element, context)?;
let coll = eval_value(collection, context)?;
match coll {
@ -491,17 +494,13 @@ fn eval_value(expr: &Expr, context: &Value) -> Result<EvalResult, AuthzError> {
let r = eval_value(right, context)?;
match op {
BinOp::And => match (&l, &r) {
(EvalResult::Bool(a), EvalResult::Bool(b)) => {
Ok(EvalResult::Bool(*a && *b))
}
(EvalResult::Bool(a), EvalResult::Bool(b)) => Ok(EvalResult::Bool(*a && *b)),
_ => Err(AuthzError::InvalidCondition(
"`&&` requires boolean operands".into(),
)),
},
BinOp::Or => match (&l, &r) {
(EvalResult::Bool(a), EvalResult::Bool(b)) => {
Ok(EvalResult::Bool(*a || *b))
}
(EvalResult::Bool(a), EvalResult::Bool(b)) => Ok(EvalResult::Bool(*a || *b)),
_ => Err(AuthzError::InvalidCondition(
"`||` requires boolean operands".into(),
)),
@ -591,9 +590,7 @@ mod tests {
fn test_parse_boolean_and() {
let expr = parse_condition("a > 1 && b < 2").unwrap();
match expr {
Expr::BinOp {
op: BinOp::And, ..
} => {}
Expr::BinOp { op: BinOp::And, .. } => {}
_ => panic!("expected And"),
}
}
@ -657,8 +654,7 @@ mod tests {
#[test]
fn test_evaluate_boolean_and() {
let expr =
parse_condition("request.time.hour >= 9 && request.time.hour < 17").unwrap();
let expr = parse_condition("request.time.hour >= 9 && request.time.hour < 17").unwrap();
let ctx = json!({ "request": { "time": { "hour": 14 } } });
assert!(evaluate(&expr, &ctx).unwrap());

View file

@ -92,7 +92,10 @@ fn check_abac_rules(
// Check if the principal matches any of the rule's principal patterns
let principal_match = rule.principals.is_empty()
|| rule.principals.iter().any(|p| matches_principal(principal, p, state));
|| rule
.principals
.iter()
.any(|p| matches_principal(principal, p, state));
if !principal_match {
continue;
@ -323,9 +326,14 @@ mod tests {
fn test_check_inherited_permission() {
let state = make_vm_state();
// alice has vm_admin which includes vm_viewer -> vm:view_console
assert!(
check(&state, "user/alice", "vm:view_console", "vm/vm-123", &json!({})).unwrap()
);
assert!(check(
&state,
"user/alice",
"vm:view_console",
"vm/vm-123",
&json!({})
)
.unwrap());
}
#[test]
@ -341,9 +349,14 @@ mod tests {
fn test_check_userset_membership() {
let state = make_vm_state();
// bob is member of group/engineers, which has vm_viewer on vm/vm-456
assert!(
check(&state, "user/bob", "vm:view_console", "vm/vm-456", &json!({})).unwrap()
);
assert!(check(
&state,
"user/bob",
"vm:view_console",
"vm/vm-456",
&json!({})
)
.unwrap());
// but bob can't start vm-456 (only viewer)
assert!(!check(&state, "user/bob", "vm:start", "vm/vm-456", &json!({})).unwrap());
}
@ -351,9 +364,7 @@ mod tests {
#[test]
fn test_check_unknown_permission() {
let state = make_vm_state();
assert!(
!check(&state, "user/alice", "vm:delete", "vm/vm-123", &json!({})).unwrap()
);
assert!(!check(&state, "user/alice", "vm:delete", "vm/vm-123", &json!({})).unwrap());
}
#[test]
@ -384,20 +395,16 @@ mod tests {
effect: "allow".into(),
permissions: vec!["invoice:view".into()],
principals: vec!["group:finance".into()],
condition: Some(
"request.time.hour >= 9 && request.time.hour < 17".into(),
),
condition: Some("request.time.hour >= 9 && request.time.hour < 17".into()),
}],
grants: vec![
GrantTuple {
grants: vec![GrantTuple {
relation: "member".into(),
object_type: "group".into(),
object_id: "finance".into(),
subject_type: "user".into(),
subject_id: "carol".into(),
subject_relation: None,
},
],
}],
};
let state = compile_policies(vec![parsed]).unwrap();
@ -407,15 +414,25 @@ mod tests {
// Carol is in finance, outside business hours -> denied
let ctx_late = json!({ "request": { "time": { "hour": 22 } } });
assert!(
!check(&state, "user/carol", "invoice:view", "invoice/inv-1", &ctx_late).unwrap()
);
assert!(!check(
&state,
"user/carol",
"invoice:view",
"invoice/inv-1",
&ctx_late
)
.unwrap());
// Dave is NOT in finance -> denied even during business hours
let ctx_hours = json!({ "request": { "time": { "hour": 14 } } });
assert!(
!check(&state, "user/dave", "invoice:view", "invoice/inv-1", &ctx_hours).unwrap()
);
assert!(!check(
&state,
"user/dave",
"invoice:view",
"invoice/inv-1",
&ctx_hours
)
.unwrap());
}
#[test]

View file

@ -21,7 +21,9 @@ pub enum AuthzError {
#[error("Invalid policy: {0}")]
#[diagnostic(
code(barycenter::authz::invalid_policy),
help("Each policy file must contain valid `resource`, `role`, `rule`, or `grant` KDL nodes")
help(
"Each policy file must contain valid `resource`, `role`, `rule`, or `grant` KDL nodes"
)
)]
InvalidPolicy(String),

View file

@ -32,11 +32,10 @@ pub fn load_policies(dir: &Path) -> Result<AuthzState, AuthzError> {
for entry in entries {
let path = entry.path();
let contents = std::fs::read_to_string(&path).map_err(|source| {
AuthzError::PolicyLoadError {
let contents =
std::fs::read_to_string(&path).map_err(|source| AuthzError::PolicyLoadError {
path: path.display().to_string(),
source,
}
})?;
let parsed = parse_kdl_document(&contents)?;
all_parsed.push(parsed);
@ -214,16 +213,14 @@ mod tests {
},
],
rules: vec![],
grants: vec![
GrantTuple {
grants: vec![GrantTuple {
relation: "vm_admin".into(),
object_type: "vm".into(),
object_id: "vm-123".into(),
subject_type: "user".into(),
subject_id: "alice".into(),
subject_relation: None,
},
],
}],
}
}

View file

@ -135,19 +135,13 @@ pub fn parse_kdl_document(source: &str) -> Result<ParsedPolicy, AuthzError> {
)
})?;
let on = node
.get("on")
.and_then(|v| v.as_string())
.ok_or_else(|| {
let on = node.get("on").and_then(|v| v.as_string()).ok_or_else(|| {
AuthzError::InvalidGrant(format!(
"grant `{relation}` missing `on` property (e.g. on=\"vm/vm-123\")"
))
})?;
let to = node
.get("to")
.and_then(|v| v.as_string())
.ok_or_else(|| {
let to = node.get("to").and_then(|v| v.as_string()).ok_or_else(|| {
AuthzError::InvalidGrant(format!(
"grant `{relation}` missing `to` property (e.g. to=\"user/alice\")"
))

View file

@ -22,7 +22,13 @@ async fn handle_check(
State(state): State<Arc<AuthzState>>,
Json(req): Json<CheckRequest>,
) -> impl IntoResponse {
match engine::check(&state, &req.principal, &req.permission, &req.resource, &req.context) {
match engine::check(
&state,
&req.principal,
&req.permission,
&req.resource,
&req.context,
) {
Ok(allowed) => Json(CheckResponse { allowed }).into_response(),
Err(e) => e.into_response(),
}