cuenv_secrets/resolvers/
env.rs1use crate::{SecretError, SecretResolver, SecretSpec};
4use async_trait::async_trait;
5
6#[derive(Debug, Clone, Default)]
10pub struct EnvSecretResolver;
11
12impl EnvSecretResolver {
13 #[must_use]
15 pub fn new() -> Self {
16 Self
17 }
18}
19
20#[async_trait]
21impl SecretResolver for EnvSecretResolver {
22 fn provider_name(&self) -> &'static str {
23 "env"
24 }
25
26 async fn resolve(&self, name: &str, spec: &SecretSpec) -> Result<String, SecretError> {
27 std::env::var(&spec.source).map_err(|_| SecretError::NotFound {
28 name: name.to_string(),
29 secret_source: spec.source.clone(),
30 })
31 }
32}
33
34#[cfg(test)]
35mod tests {
36 use super::*;
37 use std::collections::HashMap;
38
39 #[tokio::test]
40 async fn test_resolve_from_env() {
41 temp_env::async_with_vars([("TEST_SECRET_ENV_1", Some("value1"))], async {
42 let resolver = EnvSecretResolver::new();
43 let spec = SecretSpec::new("TEST_SECRET_ENV_1");
44 let result = resolver.resolve("secret1", &spec).await;
45
46 assert_eq!(result.unwrap(), "value1");
47 })
48 .await;
49 }
50
51 #[tokio::test]
52 async fn test_missing_env_var() {
53 let resolver = EnvSecretResolver::new();
54 let spec = SecretSpec::new("NONEXISTENT_ENV_VAR_12345");
55 let result = resolver.resolve("missing", &spec).await;
56
57 assert!(matches!(result, Err(SecretError::NotFound { .. })));
58 }
59
60 #[tokio::test]
61 async fn test_resolve_all() {
62 temp_env::async_with_vars(
63 [
64 ("TEST_SECRET_ENV_2", Some("value2")),
65 ("TEST_SECRET_ENV_3", Some("value3")),
66 ],
67 async {
68 let resolver = EnvSecretResolver::new();
69 let secrets = HashMap::from([
70 ("secret2".to_string(), SecretSpec::new("TEST_SECRET_ENV_2")),
71 ("secret3".to_string(), SecretSpec::new("TEST_SECRET_ENV_3")),
72 ]);
73
74 let result = resolver.resolve_all(&secrets).await.unwrap();
75
76 assert_eq!(result.get("secret2"), Some(&"value2".to_string()));
77 assert_eq!(result.get("secret3"), Some(&"value3".to_string()));
78 },
79 )
80 .await;
81 }
82}