use anyhow::Result;
use dotenv::dotenv;
use std::collections::HashMap;
use std::sync::{Arc, Mutex};
use tracing::{debug, warn};
fn key_to_env_var_name(key: &str) -> String {
let env_name = key.to_uppercase().replace('.', "_");
format!("ENACT_{}", env_name)
}
#[derive(Clone)]
pub struct SecretManager {
mock_store: Option<Arc<Mutex<HashMap<String, String>>>>,
}
impl SecretManager {
pub fn new() -> Self {
if let Err(e) = dotenv() {
debug!("No .env file found or error loading it: {}", e);
} else {
debug!("Loaded .env file");
}
Self { mock_store: None }
}
pub fn new_mock() -> Self {
Self {
mock_store: Some(Arc::new(Mutex::new(HashMap::new()))),
}
}
pub fn set(&self, key: &str, value: &str) -> Result<()> {
if let Some(ref store) = self.mock_store {
let mut map = store.lock().unwrap();
map.insert(key.to_string(), value.to_string());
debug!("Stored secret in mock store: {}", key);
return Ok(());
}
warn!("Setting secrets programmatically is not supported with .env auth. Please update your .env file or environment manually.");
Err(anyhow::anyhow!(
"Setting secrets is not supported in .env mode"
))
}
pub fn get(&self, key: &str) -> Result<Option<String>> {
if let Some(ref store) = self.mock_store {
let map = store.lock().unwrap();
let value = map.get(key).cloned();
return Ok(value);
}
let env_var_name = key_to_env_var_name(key);
if let Ok(value) = std::env::var(&env_var_name) {
debug!(
"Retrieved secret from environment variable {}: {}",
env_var_name, key
);
return Ok(Some(value));
}
Ok(None)
}
pub fn delete(&self, key: &str) -> Result<()> {
if let Some(ref store) = self.mock_store {
let mut map = store.lock().unwrap();
map.remove(key);
return Ok(());
}
Err(anyhow::anyhow!(
"Deleting secrets is not supported in .env mode"
))
}
}
impl Default for SecretManager {
fn default() -> Self {
Self::new()
}
}