pub type SecretBytes = SecretSlice<u8>;
pub use secrecy::{ExposeSecret, ExposeSecretMut, SecretBox, SecretSlice, SecretString};
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn secret_bytes_from_vec_and_expose_roundtrip() {
let raw = vec![1_u8, 2, 3, 4, 5];
let secret: SecretBytes = raw.clone().into();
assert_eq!(secret.expose_secret(), raw.as_slice());
}
#[test]
fn debug_never_leaks_bytes() {
let secret: SecretBytes = vec![0xde_u8, 0xad, 0xbe, 0xef].into();
let debug = format!("{secret:?}");
let lower = debug.to_lowercase();
assert!(
lower.contains("redacted"),
"Debug output is not marked as redacted: {debug}"
);
for leak in ["222", "173", "190", "239", "dead", "beef", "de ad"] {
assert!(
!lower.contains(leak),
"Debug output leaks a plaintext trace {leak:?}: {debug}"
);
}
}
#[test]
fn nested_in_derived_debug_still_safe() {
#[expect(
dead_code,
reason = "the field exists only to build the Debug output and is never read; that is the entire point of this test"
)]
#[derive(Debug)]
struct Wrapper {
label: &'static str,
secret: SecretBytes,
}
let w = Wrapper {
label: "github",
secret: vec![0xde_u8, 0xad].into(),
};
let text = format!("{w:?}");
assert!(
text.contains("github"),
"a non-secret field must print normally: {text}"
);
assert!(
!text.contains("222"),
"nested Debug output leaks plaintext: {text}"
);
}
#[test]
fn zeroize_on_drop_contract_holds() {
fn assert_zeroize_on_drop<T: secrecy::zeroize::ZeroizeOnDrop>() {}
fn assert_zeroize<T: secrecy::zeroize::Zeroize>() {}
assert_zeroize_on_drop::<SecretBytes>();
assert_zeroize::<SecretBytes>();
assert_zeroize_on_drop::<SecretString>();
}
#[test]
fn constructible_from_owned_input() {
let bytes: SecretBytes = vec![0_u8; 32].into();
assert_eq!(bytes.expose_secret().len(), 32);
let text = SecretString::from("correct horse battery staple");
assert_eq!(text.expose_secret(), "correct horse battery staple");
}
#[test]
fn secret_bytes_is_cloneable_and_clone_exposes_same() {
let secret: SecretBytes = vec![9_u8, 8, 7].into();
let copy = secret.clone();
assert_eq!(copy.expose_secret(), secret.expose_secret());
assert_eq!(copy.expose_secret(), &[9, 8, 7]);
}
#[test]
fn container_secret_box_is_not_cloneable_by_upstream_design() {
let scalar = SecretBox::new(Box::new(0xAB_u8));
let copy = scalar.clone();
assert_eq!(*copy.expose_secret(), 0xAB);
}
}