Skip to main content

zeph_common/
secret.rs

1// SPDX-FileCopyrightText: 2026 Andrei G <bug-ops>
2// SPDX-License-Identifier: MIT OR Apache-2.0
3
4use std::fmt;
5
6use serde::Deserialize;
7use zeroize::Zeroizing;
8
9/// Wrapper for sensitive strings with redacted Debug/Display.
10///
11/// The inner value is wrapped in [`Zeroizing`] which overwrites the memory on drop.
12/// `Clone` is intentionally not derived — secrets must be explicitly duplicated via
13/// `Secret::new(existing.expose().to_owned())`.
14///
15/// # Clone is not implemented
16///
17/// ```compile_fail
18/// use zeph_common::secret::Secret;
19/// let s = Secret::new("x");
20/// let _ = s.clone(); // must not compile — Secret intentionally does not implement Clone
21/// ```
22#[derive(Deserialize)]
23#[serde(transparent)]
24pub struct Secret(Zeroizing<String>);
25
26impl Secret {
27    pub fn new(s: impl Into<String>) -> Self {
28        Self(Zeroizing::new(s.into()))
29    }
30
31    #[must_use]
32    pub fn expose(&self) -> &str {
33        self.0.as_str()
34    }
35}
36
37impl fmt::Debug for Secret {
38    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
39        f.write_str("[REDACTED]")
40    }
41}
42
43impl fmt::Display for Secret {
44    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
45        f.write_str("[REDACTED]")
46    }
47}
48
49/// Error type for vault operations.
50///
51/// Returned by `VaultProvider::get_secret` on failure.
52///
53/// The `Backend(String)` variant is the escape hatch for third-party vault implementations:
54/// format the underlying error into the `String` when no more specific variant applies.
55#[derive(Debug, thiserror::Error)]
56pub enum VaultError {
57    #[error("secret not found: {0}")]
58    NotFound(String),
59    /// Generic backend failure. Third-party vault implementors should use this variant
60    /// to surface errors that do not fit `NotFound` or `Io`.
61    #[error("vault backend error: {0}")]
62    Backend(String),
63    #[error("vault I/O error: {0}")]
64    Io(#[from] std::io::Error),
65}