ankurah_core/
policy.rs

1use crate::{
2    node::ContextData,
3    proto::{CollectionId, NodeId, ID},
4};
5use ankql::ast::Predicate;
6
7/// The result of a policy check. Currently just Allow/Deny, but will support Trace in the future
8#[derive(Debug, Clone, Copy, PartialEq, Eq)]
9pub enum AccessResult {
10    /// The operation is allowed
11    Allow,
12    /// The operation is denied
13    Deny,
14}
15
16impl AccessResult {
17    /// Convenience method to check if access is allowed
18    pub fn is_allowed(&self) -> bool { matches!(self, AccessResult::Allow) }
19}
20
21/// Applications will implement this trait to control access to resources
22/// (Entities and RPC calls) and the Node will be generic over this trait
23pub trait PolicyAgent: Clone + Send + Sync + 'static {
24    /// The context type that will be used for all resource requests.
25    /// This will typically represent a user or service account.
26    type ContextData: ContextData;
27
28    // For checking if a context can access a collection
29    fn can_access_collection(&self, data: &Self::ContextData, collection: &CollectionId) -> AccessResult;
30
31    // For checking if a context can read an entity
32    fn can_read_entity(&self, data: &Self::ContextData, collection: &CollectionId, id: &ID) -> AccessResult;
33
34    // For checking if a context can modify an entity
35    fn can_modify_entity(&self, data: &Self::ContextData, collection: &CollectionId, id: &ID) -> AccessResult;
36
37    // For checking if a context can create entities in a collection
38    fn can_create_in_collection(&self, data: &Self::ContextData, collection: &CollectionId) -> AccessResult;
39
40    // For checking if a context can subscribe to changes
41    fn can_subscribe(&self, data: &Self::ContextData, collection: &CollectionId, predicate: &Predicate) -> AccessResult;
42
43    // For checking if a context can communicate with another node
44    fn can_communicate_with_node(&self, data: &Self::ContextData, node_id: &NodeId) -> AccessResult;
45}
46
47/// A policy agent that allows all operations
48#[derive(Clone)]
49pub struct PermissiveAgent {}
50
51impl PermissiveAgent {
52    pub fn new() -> Self { Self {} }
53}
54
55impl PolicyAgent for PermissiveAgent {
56    type ContextData = &'static DefaultContext;
57
58    fn can_access_collection(&self, _context: &Self::ContextData, _collection: &CollectionId) -> AccessResult { AccessResult::Allow }
59
60    fn can_read_entity(&self, _context: &Self::ContextData, _collection: &CollectionId, _id: &ID) -> AccessResult { AccessResult::Allow }
61
62    fn can_modify_entity(&self, _context: &Self::ContextData, _collection: &CollectionId, _id: &ID) -> AccessResult { AccessResult::Allow }
63
64    fn can_create_in_collection(&self, _context: &Self::ContextData, _collection: &CollectionId) -> AccessResult { AccessResult::Allow }
65
66    fn can_subscribe(&self, _context: &Self::ContextData, _collection: &CollectionId, _predicate: &Predicate) -> AccessResult {
67        AccessResult::Allow
68    }
69
70    fn can_communicate_with_node(&self, _context: &Self::ContextData, _node_id: &NodeId) -> AccessResult { AccessResult::Allow }
71}
72
73/// A default context that is used when no context is needed
74
75pub struct DefaultContext {}
76pub static DEFAULT_CONTEXT: &'static DefaultContext = &DefaultContext {};
77
78impl DefaultContext {
79    pub fn new() -> Self { Self {} }
80}
81
82impl ContextData for &'static DefaultContext {}