cuenv_secrets/
registry.rs1use crate::{SecretError, SecretResolver, SecretSpec};
7use std::collections::HashMap;
8use std::sync::Arc;
9
10#[derive(Default)]
27pub struct SecretRegistry {
28 resolvers: HashMap<&'static str, Arc<dyn SecretResolver>>,
29}
30
31impl SecretRegistry {
32 #[must_use]
34 pub fn new() -> Self {
35 Self {
36 resolvers: HashMap::new(),
37 }
38 }
39
40 pub fn register(&mut self, resolver: Arc<dyn SecretResolver>) {
45 self.resolvers.insert(resolver.provider_name(), resolver);
46 }
47
48 #[must_use]
52 pub fn get(&self, provider: &str) -> Option<Arc<dyn SecretResolver>> {
53 self.resolvers.get(provider).cloned()
54 }
55
56 #[must_use]
58 pub fn has(&self, provider: &str) -> bool {
59 self.resolvers.contains_key(provider)
60 }
61
62 #[must_use]
64 pub fn providers(&self) -> Vec<&'static str> {
65 self.resolvers.keys().copied().collect()
66 }
67
68 pub async fn resolve(
77 &self,
78 provider: &str,
79 name: &str,
80 spec: &SecretSpec,
81 ) -> Result<String, SecretError> {
82 let resolver = self
83 .get(provider)
84 .ok_or_else(|| SecretError::UnsupportedResolver {
85 resolver: provider.to_string(),
86 })?;
87
88 resolver.resolve(name, spec).await
89 }
90}
91
92impl std::fmt::Debug for SecretRegistry {
93 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
94 f.debug_struct("SecretRegistry")
95 .field("providers", &self.providers())
96 .finish()
97 }
98}
99
100#[cfg(test)]
101mod tests {
102 use super::*;
103 use crate::resolvers::EnvSecretResolver;
104
105 #[test]
106 fn test_registry_new() {
107 let registry = SecretRegistry::new();
108 assert!(registry.providers().is_empty());
109 }
110
111 #[test]
112 fn test_registry_default() {
113 let registry = SecretRegistry::default();
114 assert!(registry.providers().is_empty());
115 }
116
117 #[test]
118 fn test_registry_register() {
119 let mut registry = SecretRegistry::new();
120 registry.register(Arc::new(EnvSecretResolver::new()));
121
122 assert!(registry.has("env"));
123 assert_eq!(registry.providers(), vec!["env"]);
124 }
125
126 #[test]
127 fn test_registry_get() {
128 let mut registry = SecretRegistry::new();
129 registry.register(Arc::new(EnvSecretResolver::new()));
130
131 let resolver = registry.get("env");
132 assert!(resolver.is_some());
133 assert_eq!(resolver.unwrap().provider_name(), "env");
134 }
135
136 #[test]
137 fn test_registry_get_missing() {
138 let registry = SecretRegistry::new();
139 assert!(registry.get("nonexistent").is_none());
140 }
141
142 #[test]
143 fn test_registry_has() {
144 let mut registry = SecretRegistry::new();
145 registry.register(Arc::new(EnvSecretResolver::new()));
146
147 assert!(registry.has("env"));
148 assert!(!registry.has("vault"));
149 }
150
151 #[test]
152 fn test_registry_replace() {
153 let mut registry = SecretRegistry::new();
154 registry.register(Arc::new(EnvSecretResolver::new()));
155 registry.register(Arc::new(EnvSecretResolver::new()));
156
157 assert_eq!(registry.providers().len(), 1);
159 }
160
161 #[test]
162 fn test_registry_debug() {
163 let mut registry = SecretRegistry::new();
164 registry.register(Arc::new(EnvSecretResolver::new()));
165
166 let debug = format!("{registry:?}");
167 assert!(debug.contains("SecretRegistry"));
168 assert!(debug.contains("env"));
169 }
170
171 #[tokio::test]
172 async fn test_registry_resolve_unsupported() {
173 let registry = SecretRegistry::new();
174 let spec = SecretSpec::new("source");
175
176 let result = registry.resolve("unknown", "secret", &spec).await;
177 assert!(result.is_err());
178
179 if let Err(SecretError::UnsupportedResolver { resolver }) = result {
180 assert_eq!(resolver, "unknown");
181 } else {
182 panic!("Expected UnsupportedResolver error");
183 }
184 }
185
186 #[tokio::test]
187 async fn test_registry_resolve_env() {
188 let mut registry = SecretRegistry::new();
189 registry.register(Arc::new(EnvSecretResolver::new()));
190
191 temp_env::async_with_vars([("TEST_SECRET_REGISTRY", Some("test_value"))], async {
192 let spec = SecretSpec::new("TEST_SECRET_REGISTRY");
193
194 let result = registry.resolve("env", "TEST_SECRET_REGISTRY", &spec).await;
195 assert!(result.is_ok());
196 assert_eq!(result.unwrap(), "test_value");
197 })
198 .await;
199 }
200}