Skip to main content

aa_storage_memory/
policy_store.rs

1//! In-memory [`PolicyStore`] backed by a `DashMap`.
2
3use std::sync::Arc;
4
5use aa_storage::{AgentId, PolicyDocument, PolicyStore, Result, StorageError};
6use async_trait::async_trait;
7use dashmap::DashMap;
8
9/// A `DashMap`-backed [`PolicyStore`] for tests and local development.
10///
11/// The store is authoritative — it holds the policies directly rather than
12/// caching a remote source — so [`invalidate`](PolicyStore::invalidate) is a
13/// no-op (there is no upstream to reload from). Cloning shares the same
14/// underlying map.
15#[derive(Clone, Default)]
16pub struct MemoryPolicyStore {
17    policies: Arc<DashMap<[u8; 16], PolicyDocument>>,
18}
19
20impl MemoryPolicyStore {
21    /// Create an empty store.
22    pub fn new() -> Self {
23        Self::default()
24    }
25
26    /// Insert or replace the policy associated with `agent_id`.
27    ///
28    /// A seed helper for tests and boot wiring; not part of the trait contract.
29    pub fn insert(&self, agent_id: &AgentId, policy: PolicyDocument) {
30        self.policies.insert(*agent_id.as_bytes(), policy);
31    }
32}
33
34#[async_trait]
35impl PolicyStore for MemoryPolicyStore {
36    async fn get_policy(&self, agent_id: &AgentId) -> Result<PolicyDocument> {
37        self.policies
38            .get(agent_id.as_bytes())
39            .map(|entry| entry.value().clone())
40            .ok_or_else(|| StorageError::NotFound(format!("policy for agent {:?}", agent_id.as_bytes())))
41    }
42
43    async fn invalidate(&self, _agent_id: &AgentId) -> Result<()> {
44        // Authoritative store: nothing is cached, so there is nothing to drop.
45        Ok(())
46    }
47}