Skip to main content

secrets_core/
sink.rs

1//! [`SecretsSink`] — the write-target abstraction for *promoting* a resolved
2//! secret set to a destination backend (e.g. a cloud secret manager during a
3//! cloud deploy).
4//!
5//! Per the consolidation design, the lib owns the trait and the promotion logic
6//! ([`crate::provision::promote`]); the deployer keeps its CLI-shelling
7//! implementation behind this trait rather than re-implementing the discovery /
8//! resolution dance. [`StoreSink`] adapts any [`SecretsStore`] (e.g. the local
9//! dev store) into a sink so local promotion uses the same code path.
10
11use crate::errors::Result;
12use crate::seed::SecretsStore;
13use async_trait::async_trait;
14use greentic_secrets_spec::SecretUri;
15use greentic_types::secrets::SecretFormat;
16
17/// A destination secrets can be written to during promotion.
18#[async_trait]
19pub trait SecretsSink: Send + Sync {
20    /// Write `value` for `uri` into the destination backend.
21    async fn put_secret(&self, uri: &SecretUri, value: &[u8], format: SecretFormat) -> Result<()>;
22}
23
24/// Adapts any [`SecretsStore`] into a [`SecretsSink`], so the local dev store
25/// (or broker store) can be a promotion target with the same code as a cloud
26/// sink.
27pub struct StoreSink<S: SecretsStore> {
28    store: S,
29}
30
31impl<S: SecretsStore> StoreSink<S> {
32    /// Wrap a store as a sink.
33    pub fn new(store: S) -> Self {
34        Self { store }
35    }
36
37    /// Borrow the underlying store.
38    pub fn store(&self) -> &S {
39        &self.store
40    }
41}
42
43#[async_trait]
44impl<S: SecretsStore> SecretsSink for StoreSink<S> {
45    async fn put_secret(&self, uri: &SecretUri, value: &[u8], format: SecretFormat) -> Result<()> {
46        self.store.put(&uri.to_string(), format, value).await
47    }
48}