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