147 lines
3.9 KiB
Rust
Raw Permalink Normal View History

/// Integration test: Cedar authorization — multi-policy permit/deny scenarios.
use std::io::Write;
use stratum_orchestrator::auth::CedarAuthorizer;
use tempfile::TempDir;
fn write_policy(dir: &TempDir, name: &str, content: &str) {
let path = dir.path().join(name);
let mut f = std::fs::File::create(path).unwrap();
f.write_all(content.as_bytes()).unwrap();
}
#[test]
fn test_permit_orchestrator_executes_allowed_node() {
let dir = TempDir::new().unwrap();
write_policy(
&dir,
"allow.cedar",
r#"permit(
principal == User::"orchestrator",
action == Action::"execute",
resource == Node::"lint"
);"#,
);
let authz = CedarAuthorizer::load_from_dir(dir.path()).unwrap();
authz
.authorize("orchestrator", "execute", "Node::\"lint\"")
.unwrap();
}
#[test]
fn test_deny_unknown_principal() {
let dir = TempDir::new().unwrap();
write_policy(
&dir,
"allow.cedar",
r#"permit(
principal == User::"orchestrator",
action == Action::"execute",
resource == Node::"lint"
);"#,
);
let authz = CedarAuthorizer::load_from_dir(dir.path()).unwrap();
// Unknown principal — no matching permit → implicit deny
let err = authz
.authorize("rogue-agent", "execute", "Node::\"lint\"")
.unwrap_err();
assert!(err.to_string().contains("Cedar denied"));
}
#[test]
fn test_deny_wrong_resource() {
let dir = TempDir::new().unwrap();
write_policy(
&dir,
"allow.cedar",
r#"permit(
principal == User::"orchestrator",
action == Action::"execute",
resource == Node::"lint"
);"#,
);
let authz = CedarAuthorizer::load_from_dir(dir.path()).unwrap();
let err = authz
.authorize("orchestrator", "execute", "Node::\"build\"")
.unwrap_err();
assert!(err.to_string().contains("Cedar denied"));
}
#[test]
fn test_explicit_forbid_overrides_permit() {
let dir = TempDir::new().unwrap();
write_policy(
&dir,
"00_permit.cedar",
r#"permit(
principal == User::"orchestrator",
action == Action::"execute",
resource == Node::"lint"
);"#,
);
write_policy(
&dir,
"01_forbid.cedar",
r#"forbid(principal, action, resource);"#,
);
let authz = CedarAuthorizer::load_from_dir(dir.path()).unwrap();
// Cedar: forbid overrides permit
let err = authz
.authorize("orchestrator", "execute", "Node::\"lint\"")
.unwrap_err();
assert!(err.to_string().contains("Cedar denied"));
}
#[test]
fn test_empty_policy_dir_returns_error() {
let dir = TempDir::new().unwrap();
let err = match CedarAuthorizer::load_from_dir(dir.path()) {
Err(e) => e,
Ok(_) => panic!("expected load_from_dir to fail on empty directory"),
};
assert!(
err.to_string().contains("no .cedar policy files"),
"expected 'no .cedar policy files' error, got: {err}"
);
}
#[test]
fn test_multiple_permits_any_matching_allows() {
let dir = TempDir::new().unwrap();
write_policy(
&dir,
"nodes.cedar",
r#"permit(
principal == User::"orchestrator",
action == Action::"execute",
resource == Node::"lint"
);
permit(
principal == User::"orchestrator",
action == Action::"execute",
resource == Node::"build"
);
permit(
principal == User::"orchestrator",
action == Action::"execute",
resource == Node::"install"
);"#,
);
let authz = CedarAuthorizer::load_from_dir(dir.path()).unwrap();
for node in ["lint", "build", "install"] {
authz
.authorize("orchestrator", "execute", &format!("Node::\"{node}\""))
.unwrap_or_else(|e| panic!("node '{node}' should be permitted: {e}"));
}
// Node not in the permit list → deny
authz
.authorize("orchestrator", "execute", "Node::\"notify\"")
.unwrap_err();
}