Expand description
§Qubit Redact
Provides immutable, policy-driven redaction for scalar fields, maps, process diagnostics, and optionally HTTP data. Safe result types separate redacted text from text that has also been escaped for logs.
§Core values and maps
use std::collections::HashMap;
use qubit_redact::{RedactionPolicy, Redactor, Sensitivity};
let mut builder = RedactionPolicy::builder();
builder
.fields()
.raise("tenant_secret", Sensitivity::Secret)?;
let policy = builder.build()?;
let source = HashMap::from([
("tenant_secret".to_owned(), "raw".to_owned()),
("display_name".to_owned(), "Alice".to_owned()),
]);
let redacted = Redactor::new(policy).redact_map(&source);
assert_eq!(redacted["tenant_secret"], "<redacted>");
assert_eq!(source["tenant_secret"], "raw");An application can install one process-wide RedactionPolicy during
assembly or initialization. Builders are deterministic and never read
process-wide state; use RedactionPolicy::default().to_builder() when an
explicit extension of the installed snapshot is needed. Existing policy
snapshots never change. Before an application installs a global policy,
RedactionPolicy::global() and RedactionPolicy::default() return the
fixed standard policy without preventing later installation.
This fallback supports dependency construction during application assembly;
it is not runtime reconfiguration. The executable, never a library, owns the
single installation and should complete it before starting concurrent work.
Anything created earlier keeps its standard-policy snapshot. Construct
policy-sensitive objects afterward or inject the application policy.
use qubit_redact::{RedactionPolicy, Sensitivity};
let mut builder = RedactionPolicy::builder();
builder
.fields()
.raise("tenant_secret", Sensitivity::Secret)?;
let application_default = builder.build()?;
RedactionPolicy::install_global(application_default)?;
let snapshot = RedactionPolicy::default();
assert_eq!(snapshot.sensitivity_for("tenant_secret"), Some(Sensitivity::Secret));RedactedText is not directly displayable. Explicitly cross a plain-text
logging boundary with RedactedText::escape_for_log.
use qubit_redact::Redactor;
let safe = Redactor::default()
.redact_field("message", "line one\nline two")
.escape_for_log();
assert_eq!(safe.to_string(), "line one\\nline two");§Domain objects
Add the companion qubit-redact-derive crate to annotate fields explicitly.
Plain fields are never recursively redacted, nested is the recursion
boundary, map classifies each value by its runtime key, and skip omits a
field only from the redacted representation.
use std::collections::HashMap;
use qubit_redact::{Redact as _, RedactionPolicy, Sensitivity};
use qubit_redact_derive::Redact;
#[derive(Redact)]
struct Account {
id: u64,
#[redact(level = "secret")]
password: String,
#[redact(map)]
metadata: HashMap<String, String>,
}
let mut builder = RedactionPolicy::builder();
builder.fields().raise("api_key", Sensitivity::Secret)?;
let policy = builder.build()?;
let account = Account {
id: 1,
password: "raw-password".to_owned(),
metadata: HashMap::from([
("api_key".to_owned(), "raw-key".to_owned()),
]),
};
let output = format!("{:?}", account.redacted_with(&policy));
assert!(!output.contains("raw-password"));
assert!(!output.contains("raw-key"));RedactMut is an explicit logical in-place redaction contract. The skipped
field below remains unchanged, while nested uses the same policy for the
child. It does not zeroize released allocations or affect aliases, existing
copies, or borrowed backing data. Clone-based to_redacted temporarily
retains a second raw copy. Use a separately designed zeroization strategy
when memory erasure is required.
use qubit_redact::{Redact as _, RedactMut as _};
use qubit_redact_derive::{Redact, RedactMut};
#[derive(Clone, Redact, RedactMut)]
struct Secret {
#[redact(level = "secret")]
value: String,
}
#[derive(Clone, Redact, RedactMut)]
struct Envelope {
#[redact(nested)]
secret: Secret,
#[redact(skip)]
internal_note: String,
}
let mut envelope = Envelope {
secret: Secret { value: "raw".to_owned() },
internal_note: "unchanged".to_owned(),
};
envelope.redact_in_place();
assert_eq!(envelope.secret.value, "<redacted>");
assert_eq!(envelope.internal_note, "unchanged");With the serde feature, a direct serde dependency, and the companion
derive crate, #[redact(serde)] opts the redacted view into serialization.
Redacted intentionally does not implement Deserialize.
use qubit_redact::Redact as _;
use qubit_redact_derive::Redact;
#[derive(Redact)]
#[redact(debug, display, serde)]
struct Credentials {
#[redact(level = "secret")]
token: String,
#[redact(skip)]
internal_note: String,
}
let value = Credentials {
token: "raw-token".to_owned(),
internal_note: "not serialized".to_owned(),
};
let json = serde_json::to_string(&value.redacted())?;
assert!(!json.contains("raw-token"));
assert!(!json.contains("internal_note"));
assert!(!format!("{value:?}").contains("raw-token"));
assert!(!format!("{value}").contains("raw-token"));debug and display are opt-in implementations on the original type and
use the process-wide default policy. Plain fields remain ordinary Debug
values. Redacted Debug and Display output use the policy’s diagnostic
output budget by default. Use with_output_limit() to select a different
explicit limit. Do not request an
implementation already supplied by the type, such as combining
#[derive(Debug)] with #[redact(debug)].
Derives support named, tuple, and unit structs, plus enums with named,
tuple, and unit variants. With #[redact(serde)], redacted serialization
supports Serde’s external, internal, adjacent, and untagged enum
representations through a structure-preserving attribute allowlist.
use qubit_redact::Redact as _;
use qubit_redact_derive::Redact;
#[derive(Redact)]
struct Token(#[redact(level = "secret")] String);
#[derive(Redact)]
enum Event {
Credential(#[redact(level = "secret")] String),
Ready,
}
assert_eq!(
format!("{:?}", Token("raw".into()).redacted()),
"Token(\"<redacted>\")",
);
assert_eq!(
format!("{:?}", Event::Credential("raw".into()).redacted()),
"Credential(\"<redacted>\")",
);
assert_eq!(format!("{:?}", Event::Ready.redacted()), "Ready");redacted() snapshots the process default; redacted_with snapshots an
explicit policy, which every nested and map field reuses. Field-specific
map policies are not supported in the first version; use a domain newtype
plus nested for a separate policy boundary.
§Process diagnostics
Process adapters use the InputOutputLimit in their RedactionPolicy
snapshot. They stop before inspecting argv or environment input beyond the
input limit and truncate their final log-safe list at the output limit.
use std::ffi::OsStr;
use qubit_redact::{ArgvRedactor, EnvRedactor, argv::ArgvItem};
let argv = [
ArgvItem::plain(OsStr::new("client")),
ArgvItem::plain(OsStr::new("--password")),
ArgvItem::plain(OsStr::new("raw")),
];
assert!(!ArgvRedactor::default()
.redact_heuristically(argv)
.to_string()
.contains("raw"));
assert_eq!(
EnvRedactor::default().redact_pair("PASSWORD", "raw").to_string(),
"PASSWORD=<redacted>",
);§JSON values
With the json feature, RedactedJson, RedactedJsonText, and
redact_json_text_in_place share the JsonDepthBudget stored in their
immutable RedactionPolicy snapshot. The default maximum depth is 128;
an over-depth object or array is replaced with the policy’s opaque Secret
mask without visiting its descendants.
§HTTP bodies
Enable this API with qubit-redact = { version = "0.4", features = ["http"] }. http::BodyCapture makes completeness explicit, and the returned
http::BodyRedaction implements std::fmt::Display with bounded,
log-safe output.
use http::HeaderValue;
use qubit_redact::http::{BodyCapture, BodyRedaction, HttpRedactor};
let content_type = HeaderValue::from_static("application/json");
let result: BodyRedaction = HttpRedactor::default().redact_body(
BodyCapture::complete(br#"{"password":"raw","mode":"debug"}"#),
Some(&content_type),
);
assert!(!format!("{result}").contains("raw"));Re-exports§
pub use argv::ArgvRedactor;pub use domain::BoundedRedactedDisplay;pub use domain::Redact;pub use domain::RedactMapValue;pub use domain::RedactMapValueMut;pub use domain::RedactMut;pub use domain::RedactValue;pub use domain::RedactValueMut;pub use domain::Redacted;pub use domain::RedactedKeyedMap;pub use domain::RedactedKeyedMapSession;pub use domain::RedactedKeyedValue;pub use domain::RedactedKeyedValueSession;pub use domain::RedactedMap;pub use domain::RedactedMapSession;pub use domain::RedactedSessionView;pub use domain::RedactedValue;pub use env::EnvRedactor;pub use json::RedactedJson;pub use json::RedactedJsonSession;pub use json::RedactedJsonText;pub use json::RedactedJsonTextSession;pub use json::redact_json_text_in_place;pub use policy::AllowRule;pub use policy::DiagnosticBudgetError;pub use policy::FieldClassification;pub use policy::FieldMatchKind;pub use policy::FieldNameMatching;pub use policy::InputOutputLimit;pub use policy::MaskPolicy;pub use policy::MaskingPolicy;pub use policy::PolicyError;pub use policy::PolicyLocation;pub use policy::RedactionFloor;pub use policy::RedactionFloorBuilder;pub use policy::RedactionLimits;pub use policy::RedactionPolicy;pub use policy::RedactionPolicyBuilder;pub use policy::RedactionRules;pub use policy::RedactionSession;pub use policy::RedactionSessionKind;pub use policy::SensitiveFieldPreset;pub use policy::SensitiveFieldRule;pub use policy::Sensitivity;pub use policy::UnknownFieldPolicy;pub use policy::JsonDepthBudget;pub use policy::JsonDepthBudgetError;pub use policy::UnkeyedJsonValuePolicy;pub use text::BoundedLogSafeDisplay;pub use text::DiagnosticLogBuilder;pub use text::DiagnosticWriteStatus;pub use text::LogOutputLimit;pub use text::LogOutputLimitError;pub use text::LogSafeText;pub use text::RedactedDebug;pub use text::RedactedText;pub use text::redacted_debug;pub use uri::UriComponent;pub use uri::UriFragmentPolicy;pub use uri::UriInspection;pub use uri::UriPathPolicy;pub use uri::UriPolicy;pub use uri::UriRedaction;pub use uri::UriRedactionReason;pub use uri::UriRedactionStatus;pub use uri::UriRedactor;
Modules§
- argv
- Redaction adapters for process argument vectors.
- domain
- Runtime traits and borrowed views for domain-object redaction.
- env
- Redaction adapters for environment-variable diagnostics.
- http
- Immutable HTTP redaction policy, bounded body input, and safe results.
- json
- Policy-aware redaction for parsed JSON values and JSON stored as text.
- policy
- Immutable field classification and value-masking primitives.
- text
- Typed text values that distinguish redacted data from log-safe output.
- uri
- Policy-driven URI redaction.
Structs§
- Install
Global Policy Error - Owns the policy that could not be installed because a global policy was already installed.
- Redactor
- Applies one immutable policy to scalar values and string maps.
Enums§
- Field
Redaction - Explains whether a field value was masked or intentionally passed through.
- Pass
Through Reason - Reason a field value was retained without masking.