1use std::{
2    collections::{HashMap, HashSet},
3    path::PathBuf,
4};
5
6use vector_lib::configurable::{component::GenerateConfig, configurable_component};
7
8use crate::{config::SecretBackend, signal};
9
10#[configurable_component(secrets("file"))]
12#[derive(Clone, Debug)]
13pub struct FileBackend {
14    pub path: PathBuf,
16}
17
18impl GenerateConfig for FileBackend {
19    fn generate_config() -> toml::Value {
20        toml::Value::try_from(FileBackend {
21            path: PathBuf::from("/path/to/secret"),
22        })
23        .unwrap()
24    }
25}
26
27impl SecretBackend for FileBackend {
28    async fn retrieve(
29        &mut self,
30        secret_keys: HashSet<String>,
31        _: &mut signal::SignalRx,
32    ) -> crate::Result<HashMap<String, String>> {
33        let contents = tokio::fs::read_to_string(&self.path).await?;
34        let output = serde_json::from_str::<HashMap<String, String>>(&contents)?;
35        let mut secrets = HashMap::new();
36        for k in secret_keys.into_iter() {
37            if let Some(secret) = output.get(&k) {
38                if secret.is_empty() {
39                    return Err(format!("secret for key '{k}' was empty").into());
40                }
41                secrets.insert(k, secret.to_string());
42            } else {
43                return Err(format!("secret for key '{k}' was not retrieved").into());
44            }
45        }
46        Ok(secrets)
47    }
48}