Skip to main content

things_mcp/core/writer/
secret.rs

1//! `SecretString` — a tiny newtype that prevents accidental logging of
2//! sensitive material. We roll our own to avoid pulling in the `secrecy`
3//! crate for a use this small. Only `expose_secret()` returns the raw value.
4
5#[derive(Clone)]
6pub struct SecretString(String);
7
8impl SecretString {
9    pub fn new(s: impl Into<String>) -> Self {
10        Self(s.into())
11    }
12
13    /// Borrow the raw secret. Call sites must NEVER log the returned `&str`.
14    pub fn expose_secret(&self) -> &str {
15        &self.0
16    }
17}
18
19impl std::fmt::Debug for SecretString {
20    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
21        f.write_str("SecretString(***)")
22    }
23}
24
25#[cfg(test)]
26mod tests {
27    use super::*;
28
29    #[test]
30    fn debug_does_not_expose_secret() {
31        let s = SecretString::new("totally-secret-token");
32        let dbg = format!("{:?}", s);
33        assert!(!dbg.contains("totally-secret"));
34        assert_eq!(dbg, "SecretString(***)");
35    }
36
37    #[test]
38    fn expose_secret_returns_raw() {
39        let s = SecretString::new("abc123");
40        assert_eq!(s.expose_secret(), "abc123");
41    }
42}