feat(poc/diagnostics): add diagnostics-redaction spike
Proof-of-concept proving the diagnostics-redaction exit criterion from
docs/architecture/proof-of-concept-plan.md §2:
"Password and identity-secret samples are redacted."
Full coverage of the audit-report test matrix in
docs/security/diagnostic-redaction-audit-report.md §4
(REDACT-TC-001..010), plus two sanity tests.
The spike ships:
- RedactionPolicy: typed catalogue of regex rules
(identity-base64-blob, password-kv, ts3server-url-password,
authorization-bearer, linux/windows/macos user-path) with
optional capture-group narrowing.
- Structured-field redaction keyed on case-insensitive name
substrings (password, secret, token, ...).
- Bundle-level switches: chat and channel tree excluded by
default per audit-report §5.
- KnownSecretRegistry: literal-substring scrub for secrets the
host application has already loaded into memory (defense in
depth that regexes alone cannot guarantee — closes the gap
behind REDACT-TC-002).
- Length cap (MAX_PROTOCOL_STRING_LEN = 256) with truncation
marker for REDACT-TC-009.
- UTF-8 preserved in non-sensitive fields per REDACT-TC-010 /
ADR-008.
Test suite (12/12 PASS on 2026-05-13):
REDACT-TC-001 server password in connection data
REDACT-TC-002 identity secret in storage error (via KnownSecretRegistry)
REDACT-TC-003 server URL with password field
REDACT-TC-004 chat text excluded by default
REDACT-TC-005 channel name with Unicode excluded by default
REDACT-TC-006 nickname with Unicode preserved in safe field
REDACT-TC-007 local file path user segment minimized
REDACT-TC-008 mixed sensitive bundle (whole-bundle JSON scan)
REDACT-TC-009 long hostile protocol string truncated
REDACT-TC-010 multilingual safe text preserved
+ known-secret literal scrub
+ empty registered secret ignored
Out of scope: tracing-subscriber integration, diagnostic export
file format, memory/core dumps, performance, adversarial regex
evasion beyond trivial cases. These belong to chanora_diagnostics.
Authority: PoC plan §2, docs/security/diagnostic-redaction-audit-report.md,
SRS-093, SysRS-152/154/155.
Not product code; not promoted into chanora_diagnostics.
This commit is contained in:
@@ -0,0 +1,79 @@
|
||||
# Diagnostics Redaction Spike
|
||||
|
||||
Chanora proof-of-concept. **Not product code.**
|
||||
|
||||
| Field | Value |
|
||||
|---|---|
|
||||
| PoC name | `diagnostics-redaction-spike` |
|
||||
| PoC plan | [`docs/architecture/proof-of-concept-plan.md`](../../docs/architecture/proof-of-concept-plan.md) §2 |
|
||||
| Purpose | Prove redaction of secrets before logs or diagnostic export |
|
||||
| Exit criterion | "Password and identity-secret samples are redacted" |
|
||||
| Authority | `docs/security/diagnostic-redaction-audit-report.md` §2 + §4 + §5; SRS-093, SysRS-152/154/155, SDD §5 |
|
||||
|
||||
## What it proves
|
||||
|
||||
- A typed `RedactionPolicy` carrying:
|
||||
- regex-driven rules (with optional capture-group narrowing so the
|
||||
rule can scrub a value while keeping the surrounding context);
|
||||
- structured-field redaction keyed on case-insensitive name
|
||||
substrings (`password`, `secret`, `token`, …);
|
||||
- bundle-level switches (chat / channel tree default to *excluded*).
|
||||
- A `Redactor` that applies the policy to free text and to a typed
|
||||
`DiagnosticBundle`.
|
||||
- A `KnownSecretRegistry` for *literal* scrubbing — the strongest
|
||||
defence when the host has already loaded the actual secret value
|
||||
into memory. This is what closes the gap that regexes alone cannot
|
||||
fully cover (REDACT-TC-002).
|
||||
- A length cap (`MAX_PROTOCOL_STRING_LEN`) so hostile / oversized
|
||||
protocol strings cannot grow the diagnostic surface
|
||||
(REDACT-TC-009).
|
||||
- UTF-8 preservation for benign multilingual text (REDACT-TC-010 /
|
||||
ADR-008).
|
||||
|
||||
## Coverage of the audit-report test matrix
|
||||
|
||||
All ten REDACT-TC-001..010 entries are covered (see `VERIFICATION.md`).
|
||||
|
||||
## Layout
|
||||
|
||||
```text
|
||||
diagnostics-redaction-spike/
|
||||
src/
|
||||
lib.rs # crate root, re-exports, REDACTION_MARKER
|
||||
policy.rs # RedactionRule, RedactionPolicy, default policy
|
||||
redactor.rs # Redactor, KnownSecretRegistry
|
||||
bundle.rs # DiagnosticBundle DTO + bundle-level redaction
|
||||
main.rs # diagnostics-redaction-cli driver
|
||||
tests/
|
||||
redaction.rs # 12 tests; REDACT-TC-001..010 + sanity
|
||||
Cargo.toml
|
||||
```
|
||||
|
||||
## Reproduce
|
||||
|
||||
Requires Rust stable (developed against 1.95).
|
||||
|
||||
```bash
|
||||
cargo test
|
||||
echo 'INFO password=hunter2 path=/home/alice/x' | cargo run --bin diagnostics-redaction-cli
|
||||
```
|
||||
|
||||
## Scope boundaries
|
||||
|
||||
- **Not a `tracing` layer.** Production code in `chanora_diagnostics`
|
||||
will wire the redactor as a `tracing-subscriber` layer to enforce
|
||||
redaction at write-time, not via post-processing. The mechanism
|
||||
here is the same; the integration surface is not.
|
||||
- **No diagnostic bundle file format.** The spike only redacts the
|
||||
in-memory struct; the actual export format (zip / json-lines / etc.)
|
||||
is owned by `chanora_diagnostics`.
|
||||
- **No threat-model coverage of memory dumps, core dumps, or kernel
|
||||
logs.** That is `docs/security/threat-model.md` territory.
|
||||
- **No language-aware redaction.** The Unicode policy is "preserve
|
||||
multilingual text in non-sensitive fields; do not introspect it."
|
||||
- **No PII discovery.** This is a deny-list redactor; it does not
|
||||
attempt to detect previously-unknown secrets by entropy heuristics.
|
||||
|
||||
## Verification log
|
||||
|
||||
See `VERIFICATION.md` in this directory.
|
||||
Reference in New Issue
Block a user