secret_vault/simple_sources/
files_source.rs

1use crate::errors::*;
2use crate::*;
3use async_trait::*;
4use rsb_derive::*;
5use rvstruct::*;
6use secret_vault_value::SecretValue;
7use std::collections::HashMap;
8use std::path::Path;
9use tracing::*;
10
11#[derive(Debug, Clone, Eq, PartialEq, Builder)]
12pub struct FilesSourceOptions {
13    pub root_path: Option<Box<Path>>,
14}
15
16#[derive(Debug)]
17pub struct FilesSource {
18    options: FilesSourceOptions,
19}
20
21impl FilesSource {
22    pub fn new() -> Self {
23        Self::with_options(FilesSourceOptions::new())
24    }
25
26    pub fn with_options(options: FilesSourceOptions) -> Self {
27        Self { options }
28    }
29}
30
31#[async_trait]
32impl SecretsSource for FilesSource {
33    fn name(&self) -> String {
34        "FilesSource".to_string()
35    }
36
37    async fn get_secrets(
38        &self,
39        references: &[SecretVaultRef],
40    ) -> SecretVaultResult<HashMap<SecretVaultRef, Secret>> {
41        let mut result_map: HashMap<SecretVaultRef, Secret> = HashMap::new();
42
43        for secret_ref in references {
44            let secret_file_name: String = format!(
45                "{}{}{}",
46                self.options
47                    .root_path
48                    .as_ref()
49                    .and_then(|rp| rp.to_str())
50                    .map(|path| format!("{path}/"))
51                    .unwrap_or_default(),
52                secret_ref.key.secret_name.value(),
53                secret_ref
54                    .key
55                    .secret_version
56                    .as_ref()
57                    .map(|sv| { format!("_v{}", sv.value()) })
58                    .unwrap_or_else(|| "".to_string())
59            );
60
61            trace!("Loading a secret file from: {}", &secret_file_name);
62            match std::fs::read(Path::new(secret_file_name.as_str())) {
63                Ok(file_content) => {
64                    let secret_value = SecretValue::from(file_content);
65                    let metadata = SecretMetadata::create_from_ref(secret_ref);
66
67                    result_map.insert(secret_ref.clone(), Secret::new(secret_value, metadata));
68                }
69                Err(err) if secret_ref.required => {
70                    return Err(SecretVaultError::DataNotFoundError(
71                        SecretVaultDataNotFoundError::new(
72                            SecretVaultErrorPublicGenericDetails::new("SECRET_NOT_FOUND".into()),
73                            format!(
74                                "Secret is required but corresponding file is not available `{}`: {}",
75                                &secret_file_name,
76                                err
77                            ),
78                        ),
79                    ));
80                }
81                Err(err) => {
82                    debug!("Secret or secret version doesn't exist at {} and since it is not required it is skipped: {}",secret_file_name, err);
83                }
84            }
85        }
86
87        Ok(result_map)
88    }
89}