secret-vault 1.19.0

Library provides a secure vault to store securely application secrets in memory from Google/AWS/K8S and environment variables
Documentation
use crate::errors::*;
use crate::*;
use async_trait::*;
use secret_vault_value::SecretValue;
use std::collections::HashMap;
use std::sync::{Arc, Mutex};

#[derive(Debug, Clone)]
pub struct MockSecretsSource {
    pub secrets: Arc<Mutex<HashMap<SecretVaultRef, SecretValue>>>,
}

impl MockSecretsSource {
    pub fn new(secrets: Vec<(SecretVaultRef, SecretValue)>) -> Self {
        Self {
            secrets: Arc::new(Mutex::new(secrets.into_iter().collect())),
        }
    }

    pub fn add(&mut self, secret_ref: SecretVaultRef, secret_value: SecretValue) {
        self.secrets
            .lock()
            .unwrap()
            .insert(secret_ref, secret_value);
    }

    pub fn get(&self, secret_ref: &SecretVaultRef) -> Option<SecretValue> {
        self.secrets.lock().unwrap().get(secret_ref).cloned()
    }

    pub fn keys(&self) -> Vec<SecretVaultRef> {
        self.secrets.lock().unwrap().keys().cloned().collect()
    }
}

#[async_trait]
impl SecretsSource for MockSecretsSource {
    fn name(&self) -> String {
        "MockSecretsSource".to_string()
    }

    async fn get_secrets(
        &self,
        references: &[SecretVaultRef],
    ) -> SecretVaultResult<HashMap<SecretVaultRef, Secret>> {
        let mut result_map: HashMap<SecretVaultRef, Secret> = HashMap::new();
        let secrets = self.secrets.lock().unwrap();

        for secret_ref in references {
            match secrets.get(secret_ref) {
                Some(secret_value) => {
                    result_map.insert(
                        secret_ref.clone(),
                        Secret::new(
                            secret_value.clone(),
                            SecretMetadata::create_from_ref(secret_ref),
                        ),
                    );
                }
                None if secret_ref.required => {
                    return Err(SecretVaultError::DataNotFoundError(
                        SecretVaultDataNotFoundError::new(
                            SecretVaultErrorPublicGenericDetails::new(
                                "MOCK_SECRET_NOT_FOUND".into(),
                            ),
                            format!(
                                "Secret is required but not found in mock variables {:?}.",
                                secret_ref.key.secret_name
                            ),
                        ),
                    ));
                }
                None => {}
            }
        }

        Ok(result_map)
    }
}

#[cfg(test)]
pub mod source_tests {
    use crate::*;
    use proptest::prelude::*;
    use secret_vault_value::SecretValue;

    pub fn generate_secret_value() -> BoxedStrategy<SecretValue> {
        ("[a-zA-Z0-9]+")
            .prop_map(|(mock_secret_str)| SecretValue::new(mock_secret_str.as_bytes().to_vec()))
            .boxed()
    }

    pub fn generate_secret_ref() -> BoxedStrategy<SecretVaultRef> {
        ("[a-zA-Z0-9]+")
            .prop_map(|(mock_secret_name)| {
                SecretVaultRef::new(format!("gen-{mock_secret_name}").into())
            })
            .boxed()
    }

    pub fn generate_mock_secrets_source(
        namespace: SecretNamespace,
    ) -> BoxedStrategy<MockSecretsSource> {
        prop::collection::vec(
            generate_secret_ref().prop_flat_map(move |secret_ref| {
                let namespace = namespace.clone();
                generate_secret_value().prop_map(move |secret_value| {
                    (
                        secret_ref.clone().with_namespace(namespace.clone()),
                        secret_value,
                    )
                })
            }),
            1..100,
        )
        .prop_map(MockSecretsSource::new)
        .boxed()
    }
}