Skip to main content

aa_core/storage/
policy_store.rs

1//! [`PolicyStore`] — read-side access to an agent's effective policy.
2
3use super::{AgentId, PolicyDocument, Result};
4use async_trait::async_trait;
5
6/// Fetches and invalidates the effective [`PolicyDocument`] for an agent.
7///
8/// The runtime calls [`get_policy`](PolicyStore::get_policy) on the hot path
9/// before evaluating an action, so backends are expected to serve from a fast
10/// store (or a cache wrapper layered on top — see Epic C). When a policy changes,
11/// [`invalidate`](PolicyStore::invalidate) drops any cached copy so the next read
12/// reloads from the source of truth.
13///
14/// # Example
15///
16/// ```
17/// use aa_core::storage::{AgentId, PolicyDocument, PolicyStore, Result, StorageError};
18/// use async_trait::async_trait;
19///
20/// /// A backend that has no policy for any agent.
21/// struct EmptyPolicyStore;
22///
23/// #[async_trait]
24/// impl PolicyStore for EmptyPolicyStore {
25///     async fn get_policy(&self, agent_id: &AgentId) -> Result<PolicyDocument> {
26///         Err(StorageError::NotFound(format!("{:?}", agent_id.as_bytes())))
27///     }
28///
29///     async fn invalidate(&self, _agent_id: &AgentId) -> Result<()> {
30///         Ok(())
31///     }
32/// }
33/// ```
34#[async_trait]
35pub trait PolicyStore: Send + Sync {
36    /// Return the effective policy for `agent_id`.
37    ///
38    /// Returns [`StorageError::NotFound`](super::StorageError::NotFound) when the
39    /// agent has no policy on record.
40    async fn get_policy(&self, agent_id: &AgentId) -> Result<PolicyDocument>;
41
42    /// Drop any cached policy for `agent_id` so the next read reloads it.
43    ///
44    /// Idempotent: invalidating an agent with no cached entry succeeds.
45    async fn invalidate(&self, agent_id: &AgentId) -> Result<()>;
46}