Skip to main content

docbox_secrets/
memory.rs

1//! # Memory secret manager
2//!
3//! In-memory secret manager for use within tests and local development
4//! environments where a full secret manager is not needed
5//!
6//! ## Environment Variables
7//!
8//! * `DOCBOX_SECRET_MANAGER_MEMORY_DEFAULT` - Optional default secret value to provide when missing the secret
9//! * `DOCBOX_SECRET_MANAGER_MEMORY_SECRETS` - JSON encoded hashmap of available secrets
10
11use crate::{Secret, SecretManagerError, SecretManagerImpl, SetSecretOutcome};
12use serde::{Deserialize, Serialize};
13use std::{collections::HashMap, convert::Infallible, fmt::Debug, sync::Arc};
14use thiserror::Error;
15use tokio::sync::RwLock;
16
17/// Secrets manager backed by memory
18#[derive(Clone, Default, Deserialize, Serialize)]
19#[serde(default)]
20pub struct MemorySecretManagerConfig {
21    /// Collection of secrets to include
22    pub secrets: HashMap<String, String>,
23    /// Optional default secret
24    pub default: Option<String>,
25}
26
27/// Errors that could occur with the memory secrets manager config loaded
28/// from the current environment
29#[derive(Debug, Error)]
30pub enum MemorySecretManagerConfigError {
31    /// Failed to parse the secrets env variable
32    #[error("failed to parse DOCBOX_SECRET_MANAGER_MEMORY_SECRETS")]
33    ParseSecrets,
34}
35
36impl MemorySecretManagerConfig {
37    /// Load a [MemorySecretManagerConfigError] from the current environment
38    pub fn from_env() -> Result<Self, MemorySecretManagerConfigError> {
39        let default = std::env::var("DOCBOX_SECRET_MANAGER_MEMORY_DEFAULT").ok();
40        let secrets = match std::env::var("DOCBOX_SECRET_MANAGER_MEMORY_SECRETS") {
41            Ok(secrets) => serde_json::from_str(&secrets).map_err(|error| {
42                tracing::error!(?error, "failed to parse memory secrets");
43                MemorySecretManagerConfigError::ParseSecrets
44            })?,
45            Err(_) => Default::default(),
46        };
47
48        Ok(Self { default, secrets })
49    }
50}
51
52impl Debug for MemorySecretManagerConfig {
53    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
54        f.debug_struct("MemorySecretManagerConfig").finish()
55    }
56}
57
58/// In-memory secret manager
59#[derive(Default, Clone)]
60pub struct MemorySecretManager {
61    inner: Arc<RwLock<MemorySecretManagerInner>>,
62}
63
64#[derive(Default)]
65struct MemorySecretManagerInner {
66    data: HashMap<String, Secret>,
67    default: Option<Secret>,
68}
69
70impl MemorySecretManager {
71    /// Create a new memory secret manager from the provided values
72    pub fn new(data: HashMap<String, Secret>, default: Option<Secret>) -> Self {
73        Self {
74            inner: Arc::new(RwLock::new(MemorySecretManagerInner { data, default })),
75        }
76    }
77}
78
79/// Memory secret manager cannot fail
80pub type MemorySecretError = Infallible;
81
82impl SecretManagerImpl for MemorySecretManager {
83    async fn get_secret(&self, name: &str) -> Result<Option<super::Secret>, SecretManagerError> {
84        let inner = &*self.inner.read().await;
85
86        if let Some(value) = inner.data.get(name) {
87            return Ok(Some(value.clone()));
88        }
89
90        if let Some(value) = inner.default.as_ref() {
91            return Ok(Some(value.clone()));
92        }
93
94        Ok(None)
95    }
96
97    async fn has_secret(&self, name: &str) -> Result<bool, SecretManagerError> {
98        let inner = &*self.inner.read().await;
99        Ok(inner.data.contains_key(name))
100    }
101
102    async fn set_secret(
103        &self,
104        name: &str,
105        value: &str,
106    ) -> Result<SetSecretOutcome, SecretManagerError> {
107        let previous = self
108            .inner
109            .write()
110            .await
111            .data
112            .insert(name.to_string(), Secret::String(value.to_string()));
113        Ok(if previous.is_some() {
114            SetSecretOutcome::Updated
115        } else {
116            SetSecretOutcome::Created
117        })
118    }
119
120    async fn delete_secret(&self, name: &str, _force: bool) -> Result<(), SecretManagerError> {
121        self.inner.write().await.data.remove(name);
122        Ok(())
123    }
124}