Skip to main content

nexo_auth/
store.rs

1use std::path::PathBuf;
2
3use crate::error::{BuildError, CredentialError};
4use crate::handle::{Channel, CredentialHandle};
5
6/// Per-channel credential store. Implementations own the raw account
7/// data (session dirs, tokens) and issue opaque [`CredentialHandle`]s
8/// that agent tools can use to publish outbound traffic without ever
9/// touching the account id in logs.
10pub trait CredentialStore: Send + Sync + 'static {
11    type Account: Clone + Send + Sync;
12
13    fn channel(&self) -> Channel;
14
15    /// Materialise the account data for the handle. Returns
16    /// [`CredentialError::NotFound`] if the handle refers to an
17    /// account that was removed since issuance (hot-reload edge case).
18    fn get(&self, handle: &CredentialHandle) -> Result<Self::Account, CredentialError>;
19
20    /// Create a handle after checking that `agent_id` is permitted on
21    /// the account's `allow_agents` list (empty list = accept all).
22    /// Called by the resolver at boot — never from hot paths.
23    fn issue(&self, account_id: &str, agent_id: &str) -> Result<CredentialHandle, CredentialError>;
24
25    /// Enumerate every account id known to this store. Used by the
26    /// gauntlet to diagnose missing `credentials.<channel>` bindings.
27    fn list(&self) -> Vec<String>;
28
29    /// `allow_agents` for an account, for boot-time cross-validation.
30    /// Empty vec means the account accepts any agent.
31    fn allow_agents(&self, account_id: &str) -> Vec<String>;
32
33    /// Run the store's internal invariants (permissions, missing
34    /// files). Errors are non-fatal on their own — the gauntlet
35    /// merges them with cross-store checks before failing boot.
36    fn validate(&self) -> ValidationReport;
37}
38
39/// Outcome of a per-store validation pass. Warnings are advisory;
40/// errors fail boot once collected across all stores.
41#[derive(Debug, Default)]
42pub struct ValidationReport {
43    pub accounts_ok: usize,
44    pub warnings: Vec<String>,
45    pub insecure_paths: Vec<PathBuf>,
46    pub unused: Vec<String>,
47    pub errors: Vec<BuildError>,
48}
49
50impl ValidationReport {
51    pub fn is_clean(&self) -> bool {
52        self.errors.is_empty() && self.insecure_paths.is_empty()
53    }
54}