use std::sync::Arc; use anyhow::Result; use async_trait::async_trait; /// Full CRUD interface to the secrets store. /// /// Implemented by `SecretsStore` in the main crate. Both plugins (via /// `PluginContext`) and agent tools (via `AppState`) receive an /// `Arc` so neither needs to depend on the main crate. /// /// Security notes: /// - Values should never appear in log output. /// - Keys are safe to log/list. /// - Storage is SQLite — same protection level as the rest of the DB. #[async_trait] pub trait SecretsApi: Send + Sync { /// Returns the value for `key`, or `None` if not set. async fn get(&self, key: &str) -> Option; /// Inserts or replaces the secret for `key`. async fn set(&self, key: &str, value: &str) -> Result<()>; /// Removes the secret for `key`. No-op if not present. async fn delete(&self, key: &str) -> Result<()>; /// Returns all stored keys (never values). async fn list_keys(&self) -> Vec; } /// Resolves a required secret, returning a descriptive error if absent. pub async fn require(secrets: &Arc, key: &str) -> Result { secrets.get(key).await.ok_or_else(|| { anyhow::anyhow!( "secret '{}' is not set — tell the agent: \"set the secret {} to \"", key, key, ) }) }