mecha10_core/secrets/environment.rs
1//! Environment Variable Secret Backend
2
3use super::SecretBackend;
4use crate::{Mecha10Error, Result};
5
6/// Secret backend that reads from environment variables
7///
8/// This is the simplest backend, reading secrets from environment variables.
9/// Secret keys are automatically uppercased and prefixed.
10///
11/// # Example
12///
13/// ```rust
14/// use mecha10::secrets::{EnvironmentBackend, SecretBackend};
15///
16/// # async fn example() -> Result<(), Box<dyn std::error::Error>> {
17/// // Creates backend with prefix "MECHA10_SECRET_"
18/// let backend = EnvironmentBackend::new("MECHA10_SECRET");
19///
20/// // Will read from env var: MECHA10_SECRET_API_KEY
21/// let api_key = backend.get("api_key").await?;
22/// # Ok(())
23/// # }
24/// ```
25pub struct EnvironmentBackend {
26 prefix: String,
27}
28
29impl EnvironmentBackend {
30 /// Create a new environment backend with a prefix
31 ///
32 /// The prefix will be prepended to all secret keys when reading from
33 /// environment variables. Keys are automatically uppercased.
34 pub fn new(prefix: &str) -> Self {
35 Self {
36 prefix: prefix.to_string(),
37 }
38 }
39
40 /// Create backend with default prefix "MECHA10_SECRET"
41 #[allow(clippy::should_implement_trait)]
42 pub fn default() -> Self {
43 Self::new("MECHA10_SECRET")
44 }
45
46 fn make_env_key(&self, key: &str) -> String {
47 format!("{}_{}", self.prefix, key.to_uppercase())
48 }
49}
50
51#[async_trait::async_trait]
52impl SecretBackend for EnvironmentBackend {
53 async fn get(&self, key: &str) -> Result<String> {
54 let env_key = self.make_env_key(key);
55 std::env::var(&env_key).map_err(|_| {
56 Mecha10Error::Configuration(format!(
57 "Secret '{}' not found in environment variable '{}'",
58 key, env_key
59 ))
60 })
61 }
62
63 async fn list(&self) -> Result<Vec<String>> {
64 let prefix_with_underscore = format!("{}_", self.prefix);
65 let keys: Vec<String> = std::env::vars()
66 .filter_map(|(k, _)| k.strip_prefix(&prefix_with_underscore).map(|s| s.to_lowercase()))
67 .collect();
68 Ok(keys)
69 }
70}