use hyperion_vault_core::rbac;
fn rules(pairs: &[(&str, &str)]) -> Vec<(String, String)> {
pairs
.iter()
.map(|(a, p)| (a.to_string(), p.to_string()))
.collect()
}
#[test]
fn deny_by_default_for_non_admin_without_rules() {
let none = rules(&[]);
for action in rbac::ACTIONS {
assert!(!rbac::authorize(false, &none, action, "anything"));
}
}
#[test]
fn admin_is_allowed_every_action_and_path() {
for action in rbac::ACTIONS {
assert!(rbac::authorize(true, &[], action, "db/root"));
}
}
#[test]
fn exact_rule_matches_only_that_name_and_action() {
let r = rules(&[("update", "db/root")]);
assert!(rbac::authorize(false, &r, "update", "db/root"));
assert!(!rbac::authorize(false, &r, "update", "db/root2"));
assert!(!rbac::authorize(false, &r, "delete", "db/root"));
}
#[test]
fn prefix_glob_matches_subpaths_not_bare_prefix() {
let r = rules(&[("*", "stripe/*")]);
assert!(rbac::authorize(false, &r, "create", "stripe/key"));
assert!(rbac::authorize(false, &r, "rotate", "stripe/sub/key"));
assert!(!rbac::authorize(false, &r, "create", "stripe"));
assert!(!rbac::authorize(false, &r, "create", "db/stripe"));
}
#[test]
fn action_must_match_the_rule() {
let r = rules(&[("create", "stripe/*")]);
assert!(rbac::authorize(false, &r, "create", "stripe/key"));
assert!(!rbac::authorize(false, &r, "delete", "stripe/key"));
assert!(!rbac::authorize(false, &r, "rotate", "stripe/key"));
}
#[test]
fn wildcard_action_grants_all_actions_on_path() {
let r = rules(&[("*", "svc/*")]);
for action in rbac::ACTIONS {
assert!(rbac::authorize(false, &r, action, "svc/token"));
}
}
#[test]
fn wildcard_path_grants_one_action_everywhere() {
let r = rules(&[("rotate", "*")]);
assert!(rbac::authorize(false, &r, "rotate", "anything/here"));
assert!(!rbac::authorize(false, &r, "create", "anything/here"));
}
#[test]
fn multiple_rules_are_a_union() {
let r = rules(&[("create", "stripe/*"), ("delete", "db/legacy")]);
assert!(rbac::authorize(false, &r, "create", "stripe/x"));
assert!(rbac::authorize(false, &r, "delete", "db/legacy"));
assert!(!rbac::authorize(false, &r, "delete", "stripe/x"));
assert!(!rbac::authorize(false, &r, "create", "db/legacy"));
}
#[test]
fn payment_role_is_confined_to_stripe() {
let r = rules(&[("*", "stripe/*")]);
assert!(rbac::authorize(false, &r, "create", "stripe/secret-key"));
assert!(rbac::authorize(false, &r, "rotate", "stripe/webhook"));
assert!(rbac::authorize(false, &r, "delete", "stripe/old"));
assert!(!rbac::authorize(false, &r, "create", "db/root"));
assert!(!rbac::authorize(false, &r, "rotate", "payments/other"));
}
#[test]
fn visibility_ignores_action_and_follows_paths() {
let r = rules(&[("create", "stripe/*")]);
assert!(rbac::visible(false, &r, "stripe/a"));
assert!(!rbac::visible(false, &r, "db/a"));
assert!(rbac::visible(true, &[], "db/a"));
assert!(!rbac::visible(false, &[], "stripe/a"));
}
#[test]
fn patterns_are_case_sensitive() {
let r = rules(&[("create", "Stripe/*")]);
assert!(rbac::authorize(false, &r, "create", "Stripe/key"));
assert!(!rbac::authorize(false, &r, "create", "stripe/key"));
}
#[test]
fn only_known_actions_are_valid() {
for action in ["create", "update", "delete", "rotate", "*"] {
assert!(rbac::is_valid_action(action));
}
for action in ["read", "list", "admin", "", "Create"] {
assert!(!rbac::is_valid_action(action));
}
}