Skip to main content

valence_core/ports/
secrets.rs

1//! Secret lookup port — KMS/Vault-style adapters live in separate host crates.
2
3use crate::error::{Error, Result};
4
5/// Resolve secret material by key at runtime.
6///
7/// Implement this in a host crate (Vault, cloud KMS, …). Never embed product-specific
8/// secret clients inside `valence-core`.
9///
10/// Wire with [`crate::ValenceBuilder::secret_provider`].
11///
12/// # Examples
13///
14/// ```
15/// use valence_core::{EnvSecretProvider, SecretProvider};
16///
17/// let provider = EnvSecretProvider;
18/// // Looks up `std::env::var("MY_API_KEY")` when present.
19/// let _ = provider.get_secret("MY_API_KEY");
20/// ```
21pub trait SecretProvider: Send + Sync {
22    /// Return `Ok(None)` when the key is absent.
23    fn get_secret(&self, key: &str) -> Result<Option<String>>;
24}
25
26/// Always returns `Ok(None)` — default when no provider is configured.
27#[derive(Debug, Default, Clone, Copy)]
28pub struct NoOpSecretProvider;
29
30impl SecretProvider for NoOpSecretProvider {
31    fn get_secret(&self, _key: &str) -> Result<Option<String>> {
32        Ok(None)
33    }
34}
35
36/// Read secrets from process environment variables (`key` = env var name).
37#[derive(Debug, Default, Clone, Copy)]
38pub struct EnvSecretProvider;
39
40impl SecretProvider for EnvSecretProvider {
41    fn get_secret(&self, key: &str) -> Result<Option<String>> {
42        match std::env::var(key) {
43            Ok(v) => Ok(Some(v)),
44            Err(std::env::VarError::NotPresent) => Ok(None),
45            Err(e) => Err(Error::Internal(format!("env var {key}: {e}"))),
46        }
47    }
48}