stormchaser_engine/
secrets.rs1use anyhow::Result;
2use async_trait::async_trait;
3use std::collections::HashMap;
4use std::sync::Arc;
5
6#[async_trait]
7pub trait SecretBackend: Send + Sync {
9 async fn get_secret(&self, path: &str, key: &str) -> Result<String>;
11}
12
13pub struct VaultBackend {
15 #[cfg(feature = "vault")]
16 client: vaultrs::client::VaultClient,
17 #[cfg(not(feature = "vault"))]
18 _address: String,
19}
20
21impl VaultBackend {
22 pub fn new(address: String, _token: String) -> Result<Self> {
24 #[cfg(feature = "vault")]
25 {
26 use vaultrs::client::VaultClientSettingsBuilder;
27 let settings = VaultClientSettingsBuilder::default()
28 .address(address)
29 .token(_token)
30 .build()?;
31 let client = vaultrs::client::VaultClient::new(settings)?;
32 Ok(Self { client })
33 }
34 #[cfg(not(feature = "vault"))]
35 {
36 Ok(Self { _address: address })
37 }
38 }
39}
40
41#[async_trait]
42impl SecretBackend for VaultBackend {
43 async fn get_secret(&self, _path: &str, _key: &str) -> Result<String> {
44 #[cfg(feature = "vault")]
45 {
46 use vaultrs::kv2;
47 let secret: HashMap<String, String> = kv2::read(&self.client, "secret", _path).await?;
48 secret
49 .get(_key)
50 .cloned()
51 .ok_or_else(|| anyhow::anyhow!("Key {} not found in path {}", _key, _path))
52 }
53 #[cfg(not(feature = "vault"))]
54 {
55 anyhow::bail!("Vault backend is not enabled in this build. Enable 'vault' feature.")
56 }
57 }
58}
59
60pub struct MockBackend {
62 pub secrets: HashMap<String, String>,
64}
65
66impl MockBackend {
67 pub fn new(secrets: HashMap<String, String>) -> Self {
69 Self { secrets }
70 }
71}
72
73#[async_trait]
74impl SecretBackend for MockBackend {
75 async fn get_secret(&self, path: &str, key: &str) -> Result<String> {
76 let full_key = format!("{}:{}", path, key);
77 self.secrets
78 .get(&full_key)
79 .cloned()
80 .ok_or_else(|| anyhow::anyhow!("Secret not found: {}", full_key))
81 }
82}
83
84pub type SharedSecretBackend = Arc<dyn SecretBackend>;