Skip to main content

via/providers/
mod.rs

1use std::collections::BTreeMap;
2
3use crate::config::{Config, ProviderConfig};
4use crate::error::ViaError;
5use crate::secrets::SecretValue;
6
7mod onepassword;
8
9pub trait SecretProvider {
10    fn resolve(&self, reference: &str) -> Result<SecretValue, ViaError>;
11}
12
13pub struct ProviderRegistry {
14    providers: BTreeMap<String, Box<dyn SecretProvider>>,
15}
16
17impl ProviderRegistry {
18    pub fn from_config(config: &Config) -> Result<Self, ViaError> {
19        let mut providers: BTreeMap<String, Box<dyn SecretProvider>> = BTreeMap::new();
20        for (name, provider) in &config.providers {
21            match provider {
22                ProviderConfig::OnePassword { account } => {
23                    providers.insert(
24                        name.clone(),
25                        Box::new(onepassword::OnePasswordCliProvider::new(account.clone())),
26                    );
27                }
28            }
29        }
30
31        Ok(Self { providers })
32    }
33
34    pub fn get(&self, name: &str) -> Result<&dyn SecretProvider, ViaError> {
35        self.providers
36            .get(name)
37            .map(|provider| provider.as_ref())
38            .ok_or_else(|| ViaError::InvalidConfig(format!("unknown provider `{name}`")))
39    }
40}
41
42#[cfg(test)]
43mod tests {
44    use super::*;
45
46    fn config() -> Config {
47        Config::from_toml_str(
48            r#"
49version = 1
50
51[providers.onepassword]
52type = "1password"
53"#,
54        )
55        .unwrap()
56    }
57
58    #[test]
59    fn builds_registry_from_config() {
60        let registry = ProviderRegistry::from_config(&config()).unwrap();
61
62        assert!(registry.get("onepassword").is_ok());
63    }
64
65    #[test]
66    fn reports_missing_provider() {
67        let registry = ProviderRegistry::from_config(&config()).unwrap();
68        let error = match registry.get("missing") {
69            Ok(_) => panic!("expected missing provider error"),
70            Err(error) => error,
71        };
72
73        assert!(
74            matches!(error, ViaError::InvalidConfig(message) if message.contains("unknown provider"))
75        );
76    }
77}