qubit-redact
qubit-redact is a policy-aware Rust redaction runtime for application and
library authors who need useful diagnostics without exposing secrets. It
renders borrowed domain objects, JSON, HTTP values, URIs, environment
variables, and process arguments through one bounded session, then returns an
owned redacted result.
Installation
[]
= { = "0.5" }
The default feature set is empty. Enable integrations explicitly, for example
features = ["derive"] for #[derive(Redact)], or
features = ["serde", "derive"] for derived redacted serialization.
Quick Start
use Redactor;
let output = standard
.text_composer
.literal
.field
.literal
.field
.finish;
assert!;
assert!;
let text = output
.into_complete_text
.expect;
assert!;
For a domain type, implement Redact or use
qubit-redact-derive:
use ;
Then call Redactor::standard().redact(&value) or construct an explicit policy
with Redactor::new(policy). When redaction is enabled, the text remains
confidentiality-safe for Complete, Truncated, and Exhausted; the latter
two states mean only that diagnostic information is incomplete. Debug,
Display, and ordinary logs may render output.text() directly. Inspect
output.summary() only when completeness affects auditing, retry, or program
logic. into_complete_text() and the marker helpers remain available for such
explicit presentation policies.
For several independently formatted diagnostic values, select one fallback once and resolve every handle without error-handling boilerplate:
use Redactor;
let mut batch = standard.batch;
let user = batch.redact_field;
let password = batch.redact_field;
let diagnostics = batch.finish_for_diagnostics;
assert_eq!;
assert!;
Unannotated derive fields and values written through unmarked are
intentionally unredacted. Field sensitivity is application-domain knowledge:
the framework cannot infer it reliably and should not force explicit
"non-sensitive" annotations onto the ordinary majority of fields. Downstream
types must explicitly mark sensitive fields and review that decision when their
domain model changes. unmarked and unredacted are explicit trust-boundary
bypasses: they never consult runtime field policy, including strict policy.
Use them only for values independently reviewed as safe to expose, never for
credentials, user-controlled diagnostics, or values whose classification must
come from runtime policy. The runtime does not mutate or erase the source value.
Scalar field APIs accept Display. To redact a value through its Debug
representation without allocating or formatting it eagerly, wrap the borrow in
DebugDisplay::new(&value). Opaque high- and secret-sensitivity masks can then
avoid invoking Debug altogether; pass-through, disabled, low-, and
medium-sensitivity policies format it only when needed.
Why This Project Exists
Diagnostic values commonly cross logging, error-reporting, and support boundaries before their sensitivity has been reviewed. Ad-hoc masking makes each call site choose its own format, limits, and fallback behavior. This crate keeps those decisions in one immutable policy snapshot, shares one bounded budget across related output, and lets callers observe whether the published diagnostic is complete without reformatting its source.
Capabilities
- bounded text, JSON, URI, HTTP, environment, argv, and process rendering;
Sensitivity-based masking with field, key, and path policy rules;- inspection APIs that report matched rules without emitting raw values;
- parsed
serde_json::ValueAPIs that borrow and leave the input unchanged; - JSON text follows
qubit-json's numeric boundary: negative integers fiti64, non-negative integers fitu64, and fractions are finitef64; - batch APIs that share one budget and summary across related values;
- opt-in
serdeand derive integrations; the default feature set is minimal.
It does not infer application-specific sensitivity, erase source memory, or protect logging and serialization paths that do not use this runtime.
Disabled policies intentionally restore every supported raw value. This is a
deliberate process-wide debugging escape hatch, not an attempt by the framework
to authorize its use. Limits and control-character escaping remain active, but
confidentiality redaction does not. Downstream code owns authorization, timing,
environment controls, and any misuse. Derived Debug, Display, and
Serialize implementations intentionally read the current application-default
snapshot at the start of every call; they do not capture a policy when the value
is created. Replacing the default therefore affects future generated calls,
including installing a disabled policy that restores source values. Explicit
redactors, composers, and batches retain the policy snapshot they already own.
RedactedText means that runtime processing has finished and no second
redaction pass occurs when it is displayed. Its guarantee is relative to the
selected policy and explicit writer choices; it is not proof that content is
confidential when a disabled policy or an unredacted writer API was used.
Learn More
Read the English user guide, 中文用户手册, and architecture design, API documentation, and derive documentation.
Testing
# Run tests with the default feature set
# Run tests with all declared features
# Project CI checks
# Check code coverage
License
Copyright (c) 2025 - 2026. Haixing Hu. All rights reserved.
Licensed under the Apache License, Version 2.0. See LICENSE for the full license text.
Contributing
Contributions are welcome. Please follow the Rust API guidelines, keep public
API documentation and tests current, and run ./align-ci.sh to format code and
./ci-check.sh to satisfy CI requirements before submitting a pull request.
Author
Haixing Hu - Qubit Co. Ltd.
Repository: https://github.com/qubit-ltd/rs-redact