MCPcopy Index your code
hub / github.com/eopb/redact

github.com/eopb/redact @v0.1.11

Chat with this repo
repository ↗ · DeepWiki ↗ · release v0.1.11 ↗ · + Follow
20 symbols 24 edges 6 files 1 documented · 5%
What it actually does AI analysis from the code graph — generated when you open this
loading…
README

Redact

License Latest version Latest Docs downloads-badge

API docs

A simple library for keeping secrets out of logs.

Redact provides a wrapper that prevents secrets from appearing in logs.

use redact::Secret;

let encryption_key = Secret::new("hello world");
assert_eq!("[REDACTED &str]", format!("{encryption_key:?}"))

The underlying secret contained within the wrapper can only be accessed using the [expose_secret][Secret::expose_secret] method or [expose_secret] function[^1].

use redact::Secret;

let encryption_key = Secret::new("hello world");
assert_eq!("hello world", *encryption_key.expose_secret())

The Secret type doubles as a useful documentation tool. Documenting values maintainers should be careful with.

use redact::Secret;

#[derive(Debug)] // Safe since Debug is not able to "see" our `Secret`s
struct Payment {
    // The recipient is PII so we don't want it to appear in logs
    recipient: Secret<String>,
    // It's okay for the amount to appear in logs so we don't mark it with `Secret`
    amount: u64,
}

Serde support

For serde support ensure the serde feature is enabled in your Cargo.toml.

redact = { version = "0.1", features = ["serde"] }

Deserialize works as expected, transparently deserializing the enclosed secret.

Since serialization can expose the enclosed secret it is only possible to implement Serialize "with" [expose_secret].

use redact::{Secret, expose_secret};
use serde::{Serialize, Deserialize};

#[derive(Serialize, Deserialize)]
struct Payment {
    #[serde(serialize_with = "expose_secret")]
    recipient: Secret<String>,
    amount: u64,
}

If you would like to implement Serialize without exposing the Secret see [serde::redact_secret].

Zeroizing Secrets

redact does not require Secrets to be [Zeroize][::zeroize::Zeroize]able but does allow Secrets to be Zeroized when the contained secret is Zeroizeable. To be able to Zeroize Secrets, enable zeroize in your Cargo.toml.

redact = { version = "0.1", features = ["zeroize"] }
zeroize = "1"

Once enabled, it is possible zeroize secrets.

# use redact::Secret;
use zeroize::Zeroize;


fn main() {
    let mut secret = Secret::new("hunter2".to_owned());

    // [ ... ] use secret here

    // Now that we're done using the secret, zero it out.
    secret.zeroize();
    # assert_ne!(*secret.expose_secret(), "hunter2")
}

If you would like your Secret to be automatically Zeroized when it is no longer being used, consider wrapping your Secret in [Zeroizing][::zeroize::Zeroizing] which will Zeroize your secret when it is [Drop]ed

# use redact::Secret;
use zeroize::Zeroizing;


fn main() {
    let mut secret = Zeroizing::new(Secret::new("hunter2".to_owned()));

    // [ ... ] use secret here

    // The secret is automatically zeroed out at the end of the scope when it is dropped
}

Comparison with alternatives

secrecy

Secrecy was the original inspiration for this crate and it has a similar API.

One significant difference is that secrecy requires that all secrets implement Zeroize so that it can cleanly wipe secrets from memory after they are dropped. This unfortunately limits the types of values that secrecy can wrap in a Secret since every type has to be aware of Zeroize.

Redact relaxes this requirement, allowing all types to be Secrets. When zeroizing is required, consider the techniques above.

secrets

Secrets provides even stronger memory protection than secrecy using [mlock(2)]/[mprotect(2)] among other things. If you need strong memory protection before and after a Secret is dropped consider secrets.

[^1]: [Secret] will assume that it is safe to expose its secret to its contained types implemenations of [Default], [Hash], [Copy], [Clone], [Ord], [PartialOrd], [Eq], [PartialEq], [std::ops::Add], [std::ops::AddAssign], [std::ops::BitAnd], [std::ops::BitAndAssign], [std::ops::BitOr], [std::ops::BitOrAssign], [std::ops::BitXor], [std::ops::BitXorAssign], [std::ops::Div], [std::ops::DivAssign], [std::ops::Mul], [std::ops::MulAssign], [std::ops::Rem], [std::ops::RemAssign], [std::ops::Shl], [std::ops::ShlAssign], [std::ops::Shr], [std::ops::ShrAssign], [std::ops::Sub], [std::ops::SubAssign], [std::ops::Neg] and [std::ops::Not]

Extension points exported contracts — how you extend this code

SerializableSecret (Interface)
A serializable type that contains a secret. This abstraction enables [expose_secret] to be used to serialize both `Secr [4 …
src/serde.rs

Core symbols most depended-on inside this repo

expose_via
called by 1
src/serde.rs
deserialize
called by 0
src/serde.rs
expose_secret
called by 0
src/serde.rs
redact_secret
called by 0
src/serde.rs
dummy_with_rng
called by 0
src/fake.rs
dummy
called by 0
src/fake.rs
new
called by 0
src/lib.rs
from
called by 0
src/lib.rs

Shape

Method 14
Function 3
Class 2
Interface 1

Languages

Rust100%

Modules by API surface

src/lib.rs8 symbols
src/serde.rs7 symbols
src/zeroize.rs2 symbols
src/fake.rs2 symbols
src/error.rs1 symbols

For agents

$ claude mcp add redact \
  -- python -m otcore.mcp_server <graph>

⬇ download graph artifact