Skip to main content

secure_gate/compat/
mod.rs

1//! secrecy compatibility layers — drop-in replacements for the `secrecy` crate.
2//!
3//! Enable with `features = ["secrecy-compat"]` in your `Cargo.toml`.
4//!
5//! Two sub-modules mirror the two most-deployed secrecy generations:
6//!
7//! | Module | secrecy version | Key type |
8//! |---|---|---|
9//! | [`v10`] | 0.10.1 (`SecretBox<S>`, heap-alloc) | `SecretBox<str>` for strings |
10//! | [`v08`] | 0.8.0 (`Secret<S>`, stack/inline) | `Secret<String>` for strings |
11//!
12//! ## Shared surface (re-exported from this module)
13//!
14//! | Item | Purpose |
15//! |---|---|
16//! | [`ExposeSecret`] | Read-only access trait (both versions) |
17//! | [`ExposeSecretMut`] | Mutable access trait (v0.10+) |
18//! | [`CloneableSecret`] | Clone opt-in marker (both versions) |
19//! | [`SerializableSecret`] | Serialize opt-in marker (both versions) |
20//! | [`zeroize`] | Re-exported `zeroize` crate (mirrors `secrecy`'s own re-export) |
21//!
22//! ## Quick-start migration
23//!
24//! **From secrecy 0.10.x:**
25//!
26//! ```text
27//! // Before
28//! use secrecy::{SecretBox, SecretString, ExposeSecret};
29//!
30//! // After (one global find/replace)
31//! use secure_gate::compat::v10::{SecretBox, SecretString};
32//! use secure_gate::compat::ExposeSecret;
33//! ```
34//!
35//! **From secrecy 0.8.x:**
36//!
37//! ```text
38//! // Before
39//! use secrecy::{Secret, SecretString, DebugSecret, ExposeSecret};
40//!
41//! // After (one global find/replace)
42//! use secure_gate::compat::v08::{Secret, SecretString, DebugSecret};
43//! use secure_gate::compat::ExposeSecret;
44//! ```
45//!
46//! ## Bridge impls
47//!
48//! Native [`Dynamic<T>`](crate::Dynamic) and [`Fixed<[T; N]>`](crate::Fixed) implement
49//! both [`ExposeSecret`] and [`ExposeSecretMut`] so that code written against the secrecy
50//! traits compiles unchanged when you swap the concrete type for a native secure-gate type.
51
52extern crate alloc;
53
54use zeroize::Zeroize;
55
56// ── zeroize re-export ────────────────────────────────────────────────────────
57
58/// Re-exported [`zeroize`] crate — mirrors `secrecy`'s own `pub use zeroize;`.
59///
60/// Allows `use secrecy::zeroize::Zeroize` to migrate unchanged via
61/// `use secure_gate::compat::zeroize::Zeroize`.
62pub use zeroize;
63
64// ── ExposeSecret / ExposeSecretMut ───────────────────────────────────────────
65
66/// Read-only access to a wrapped secret — mirrors `secrecy::ExposeSecret`.
67///
68/// Implemented directly by [`v08::Secret`] and [`v10::SecretBox`], and by bridge
69/// impls on [`Dynamic<String>`](crate::Dynamic), [`Dynamic<Vec<T>>`](crate::Dynamic),
70/// and [`Fixed<[T; N]>`](crate::Fixed).
71///
72/// # Migration
73///
74/// For new code, prefer [`RevealSecret`](crate::RevealSecret), which additionally provides
75/// scoped `with_secret` access and byte-length metadata.
76pub trait ExposeSecret<S: ?Sized> {
77    /// Returns a shared reference to the inner secret.
78    fn expose_secret(&self) -> &S;
79}
80
81/// Mutable access to a wrapped secret — mirrors `secrecy::ExposeSecretMut`.
82///
83/// Added in secrecy 0.9. Not implemented for [`v08::Secret`] (which is read-only by design
84/// in that era). Implemented for [`v10::SecretBox`] and bridge impls on native types.
85///
86/// # Migration
87///
88/// For new code, prefer [`RevealSecretMut`](crate::RevealSecretMut).
89pub trait ExposeSecretMut<S: ?Sized> {
90    /// Returns a mutable reference to the inner secret.
91    fn expose_secret_mut(&mut self) -> &mut S;
92}
93
94// ── CloneableSecret ──────────────────────────────────────────────────────────
95
96/// Marker trait for secrets that may be cloned — mirrors `secrecy::CloneableSecret`.
97///
98/// Defined here (rather than behind the `cloneable` feature) so the compat layer
99/// works without requiring callers to enable that feature flag.
100///
101/// For native secure-gate code, enable the `cloneable` feature and use
102/// [`secure_gate::CloneableSecret`](crate::CloneableSecret) directly.
103pub trait CloneableSecret: Clone + Zeroize {}
104
105impl CloneableSecret for i8 {}
106impl CloneableSecret for i16 {}
107impl CloneableSecret for i32 {}
108impl CloneableSecret for i64 {}
109impl CloneableSecret for i128 {}
110impl CloneableSecret for isize {}
111impl CloneableSecret for u8 {}
112impl CloneableSecret for u16 {}
113impl CloneableSecret for u32 {}
114impl CloneableSecret for u64 {}
115impl CloneableSecret for u128 {}
116impl CloneableSecret for usize {}
117impl<Z: CloneableSecret, const N: usize> CloneableSecret for [Z; N] {}
118
119// ── SerializableSecret ───────────────────────────────────────────────────────
120
121/// Marker trait for secrets that may be serialized — mirrors `secrecy::SerializableSecret`.
122///
123/// Re-exports [`crate::SerializableSecret`] so that code importing from the compat layer
124/// obtains the **same** trait as code importing from the crate root, preventing
125/// disambiguation issues in compiler error messages.
126///
127/// Requires the `serde-serialize` feature. Serialization of secret wrappers is
128/// deliberately opt-in to prevent accidental exfiltration.
129#[cfg(feature = "serde-serialize")]
130pub use crate::SerializableSecret;
131
132// ── Bridge: secure-gate native types → ExposeSecret / ExposeSecretMut ────────
133//
134// These explicit impls allow code written against the secrecy `ExposeSecret` trait
135// to compile unchanged with native `Dynamic<T>` and `Fixed<[T; N]>` values.
136//
137// Explicit (rather than blanket) impls prevent the blanket from also catching
138// `SecretBox` / `Secret`, which carry their own direct impls.
139
140impl ExposeSecret<alloc::string::String> for crate::Dynamic<alloc::string::String> {
141    #[inline]
142    fn expose_secret(&self) -> &alloc::string::String {
143        crate::RevealSecret::expose_secret(self)
144    }
145}
146
147impl ExposeSecretMut<alloc::string::String> for crate::Dynamic<alloc::string::String> {
148    #[inline]
149    fn expose_secret_mut(&mut self) -> &mut alloc::string::String {
150        crate::RevealSecretMut::expose_secret_mut(self)
151    }
152}
153
154impl<T: Zeroize> ExposeSecret<alloc::vec::Vec<T>> for crate::Dynamic<alloc::vec::Vec<T>> {
155    #[inline]
156    fn expose_secret(&self) -> &alloc::vec::Vec<T> {
157        crate::RevealSecret::expose_secret(self)
158    }
159}
160
161impl<T: Zeroize> ExposeSecretMut<alloc::vec::Vec<T>> for crate::Dynamic<alloc::vec::Vec<T>> {
162    #[inline]
163    fn expose_secret_mut(&mut self) -> &mut alloc::vec::Vec<T> {
164        crate::RevealSecretMut::expose_secret_mut(self)
165    }
166}
167
168impl<const N: usize, T: Zeroize> ExposeSecret<[T; N]> for crate::Fixed<[T; N]> {
169    #[inline]
170    fn expose_secret(&self) -> &[T; N] {
171        crate::RevealSecret::expose_secret(self)
172    }
173}
174
175impl<const N: usize, T: Zeroize> ExposeSecretMut<[T; N]> for crate::Fixed<[T; N]> {
176    #[inline]
177    fn expose_secret_mut(&mut self) -> &mut [T; N] {
178        crate::RevealSecretMut::expose_secret_mut(self)
179    }
180}
181
182// ── Sub-modules ───────────────────────────────────────────────────────────────
183
184/// secrecy **v0.10.1** compatibility — heap-allocated `SecretBox<S>`.
185///
186/// Mirrors secrecy 0.10.1 exactly (edition 2021, rust-version 1.60).
187/// See the [module docs](v10) for a per-item migration guide.
188pub mod v10;
189
190/// secrecy **v0.8.0** compatibility — inline/stack-allocated `Secret<S>`.
191///
192/// Mirrors secrecy 0.8.0 (edition 2018, no const-generic arrays).
193/// See the [module docs](v08) for a per-item migration guide.
194pub mod v08;