1pub use hirn_policy::{
11 Action, AuthzDecision, AuthzRequest, DEFAULT_OPEN_POLICY, DEFAULT_SCHEMA, EntityKind,
12 PolicyEngine, PolicyError,
13};
14
15use std::sync::Arc;
18
19pub struct PolicyNamespaceResolver {
28 engine: Arc<PolicyEngine>,
29 action: Action,
31}
32
33impl PolicyNamespaceResolver {
34 pub fn new(engine: Arc<PolicyEngine>, action: Action) -> Self {
36 Self { engine, action }
37 }
38
39 pub fn for_recall(engine: Arc<PolicyEngine>) -> Self {
41 Self::new(engine, Action::Recall)
42 }
43}
44
45#[async_trait::async_trait]
46impl hirn_storage::NamespacePolicy for PolicyNamespaceResolver {
47 async fn allowed_namespaces(&self, principal: &str) -> Option<Vec<String>> {
48 self.engine.allowed_namespaces_for(principal, self.action)
49 }
50}
51
52#[cfg(test)]
55mod tests {
56 use super::*;
57 use hirn_storage::NamespacePolicy;
58
59 #[tokio::test(flavor = "multi_thread")]
60 async fn policy_namespace_resolver_open_mode() {
61 let engine = Arc::new(PolicyEngine::open_mode());
62 let resolver = PolicyNamespaceResolver::for_recall(engine);
63 let result = resolver.allowed_namespaces("anyone").await;
64 assert!(result.is_none());
66 }
67
68 #[tokio::test(flavor = "multi_thread")]
69 async fn policy_namespace_resolver_filters_namespaces() {
70 let engine = Arc::new(
71 PolicyEngine::new(DEFAULT_SCHEMA, &[("default.cedar", DEFAULT_OPEN_POLICY)]).unwrap(),
72 );
73 engine.register_realm("production", "prod realm").unwrap();
74 engine
75 .register_namespace("ns_a", "public", "production")
76 .unwrap();
77 engine
78 .register_namespace("ns_b", "public", "production")
79 .unwrap();
80 engine
81 .register_agent("agent-1", 50, "2024-01-01", &[])
82 .unwrap();
83
84 let resolver = PolicyNamespaceResolver::for_recall(engine);
85 let result = resolver.allowed_namespaces("agent-1").await;
86
87 assert!(result.is_some());
89 let mut allowed = result.unwrap();
90 allowed.sort();
91 assert_eq!(allowed, vec!["ns_a", "ns_b"]);
92 }
93}