Skip to main content

rskit_config/sink/
contract.rs

1use std::fmt;
2
3use rskit_errors::AppResult;
4use rskit_util::SecretString;
5
6/// Adapter contract for writable configuration backends.
7///
8/// A `ConfigSink` persists or patches configuration values back to a backend — a file,
9/// an in-memory store, or a future remote backend such as Vault, SSM, or a Kubernetes secret.
10/// `rskit-config` owns the contract; concrete backends live in their own adapter crates
11/// and depend only on this trait.
12///
13/// Sinks are injected explicitly (never via a global registry) and are object-safe,
14/// so callers can hold a `Box<dyn ConfigSink>`.
15///
16/// Values flow as [`SecretString`] end-to-end. Implementations must never log the plaintext value;
17/// only the key may appear in diagnostics.
18/// Writing the plaintext to the backing store (e.g. a file) is the sink's intended,
19/// explicit persistence — not a leak.
20pub trait ConfigSink: fmt::Debug + Send + Sync + 'static {
21    /// Set or replace the value stored at `key`.
22    ///
23    /// # Errors
24    ///
25    /// Returns a typed [`AppError`](rskit_errors::AppError) (cause preserved) if the backend rejects the write
26    /// or is unreachable.
27    fn set(&self, key: &str, value: SecretString) -> AppResult<()>;
28
29    /// Remove the value stored at `key`.
30    ///
31    /// Removing a missing key succeeds (idempotent), unless the backend distinguishes absence as an error.
32    ///
33    /// # Errors
34    ///
35    /// Returns a typed [`AppError`](rskit_errors::AppError) (cause preserved) if the backend rejects the removal
36    /// or is unreachable.
37    fn remove(&self, key: &str) -> AppResult<()>;
38
39    /// Set many key/value pairs.
40    ///
41    /// The default applies each entry with [`set`](ConfigSink::set) in order
42    /// and fails fast on the first error, leaving earlier writes applied. Adapters with native batch
43    /// or transactional writes should override this for atomicity and efficiency.
44    ///
45    /// # Errors
46    ///
47    /// Returns the first per-key error encountered.
48    fn set_many(&self, entries: Vec<(String, SecretString)>) -> AppResult<()> {
49        for (key, value) in entries {
50            self.set(&key, value)?;
51        }
52        Ok(())
53    }
54}