1use std::collections::BTreeMap;
13use std::fmt::Debug;
14use std::sync::{Arc, Mutex};
15use std::time::Duration;
16
17use anyhow::Context;
18use async_trait::async_trait;
19use mz_repr::CatalogItemId;
20
21pub mod cache;
22
23#[async_trait]
25pub trait SecretsController: Debug + Send + Sync {
26 async fn ensure(&self, id: CatalogItemId, contents: &[u8]) -> Result<(), anyhow::Error>;
29
30 async fn delete(&self, id: CatalogItemId) -> Result<(), anyhow::Error>;
32
33 async fn list(&self) -> Result<Vec<CatalogItemId>, anyhow::Error>;
36
37 fn reader(&self) -> Arc<dyn SecretsReader>;
39}
40
41#[derive(Debug)]
42pub struct CachingPolicy {
43 pub enabled: bool,
45 pub ttl: Duration,
47}
48
49#[async_trait]
53pub trait SecretsReader: Debug + Send + Sync {
54 async fn read(&self, id: CatalogItemId) -> Result<Vec<u8>, anyhow::Error>;
56
57 async fn read_string(&self, id: CatalogItemId) -> Result<String, anyhow::Error> {
61 let contents = self.read(id).await?;
62 String::from_utf8(contents).context("converting secret value to string")
63 }
64}
65
66#[derive(Debug)]
67pub struct InMemorySecretsController {
68 data: Arc<Mutex<BTreeMap<CatalogItemId, Vec<u8>>>>,
69}
70
71impl InMemorySecretsController {
72 pub fn new() -> Self {
73 Self {
74 data: Arc::new(Mutex::new(BTreeMap::new())),
75 }
76 }
77}
78
79#[async_trait]
80impl SecretsController for InMemorySecretsController {
81 async fn ensure(&self, id: CatalogItemId, contents: &[u8]) -> Result<(), anyhow::Error> {
82 self.data.lock().unwrap().insert(id, contents.to_vec());
83 Ok(())
84 }
85
86 async fn delete(&self, id: CatalogItemId) -> Result<(), anyhow::Error> {
87 self.data.lock().unwrap().remove(&id);
88 Ok(())
89 }
90
91 async fn list(&self) -> Result<Vec<CatalogItemId>, anyhow::Error> {
92 Ok(self.data.lock().unwrap().keys().cloned().collect())
93 }
94
95 fn reader(&self) -> Arc<dyn SecretsReader> {
96 Arc::new(InMemorySecretsController {
97 data: Arc::clone(&self.data),
98 })
99 }
100}
101
102#[async_trait]
103impl SecretsReader for InMemorySecretsController {
104 async fn read(&self, id: CatalogItemId) -> Result<Vec<u8>, anyhow::Error> {
105 let contents = self.data.lock().unwrap().get(&id).cloned();
106 contents.ok_or_else(|| anyhow::anyhow!("secret does not exist"))
107 }
108}