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}