Skip to main content

stormchaser_engine/
secrets.rs

1use anyhow::Result;
2use async_trait::async_trait;
3use std::collections::HashMap;
4use std::sync::Arc;
5
6#[async_trait]
7/// Secretbackend.
8pub trait SecretBackend: Send + Sync {
9    /// Retrieves a secret value from the specified path and key.
10    async fn get_secret(&self, path: &str, key: &str) -> Result<String>;
11}
12
13/// A secret backend that interacts with HashiCorp Vault.
14pub struct VaultBackend {
15    #[cfg(feature = "vault")]
16    client: vaultrs::client::VaultClient,
17    #[cfg(not(feature = "vault"))]
18    _address: String,
19}
20
21impl VaultBackend {
22    /// Creates a new `VaultBackend` with the specified Vault address and token.
23    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
60/// Mockbackend.
61pub struct MockBackend {
62    /// The secrets.
63    pub secrets: HashMap<String, String>,
64}
65
66impl MockBackend {
67    /// New.
68    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
84/// A thread-safe, shareable reference to a `SecretBackend` implementation.
85pub type SharedSecretBackend = Arc<dyn SecretBackend>;