Class AuditingRedactor
- All Implemented Interfaces:
Redactor
Redactor decorator that emits a RedactionAuditEvent
to a RedactionAuditListener every time the wrapped redactor
matches at least one pattern (issue #80).
Why a decorator: keeps the Redactor SPI free of
audit concerns. Audit emission is opt-in by wrapping:
Redactor base = PatternRedactor.withDefaults();
Redactor audited = new AuditingRedactor(base, event -> {
metrics.counter("redaction.applied",
"pattern", event.patternCounts().keySet().toString(),
"severity", event.highestSeverity().name())
.increment(event.totalFindings());
if (event.isCritical()) slack.alert("CRITICAL pii redaction in " + event.eventContext().tenantId());
});
Composition: the audited redactor IS a Redactor,
so it slots into anywhere a redactor is accepted —
RedactingMemoryStore, RedactingAgentEventPublisher,
CompositeRedactor, TenantPolicyRedactor per-tenant
values. Stack order matters: wrap the audited redactor inside the
tenant dispatcher to get per-tenant audit; wrap the dispatcher inside
the audit decorator to get cross-tenant audit.
Hot-path safety: the listener is invoked synchronously, but
any exception is caught and logged at WARN — a broken audit sink
cannot break redaction itself. Listeners that need async dispatch
should hand off to an executor inside RedactionAuditListener.onRedaction(com.tnsai.quality.redaction.RedactionAuditEvent).
scrubValue recurses through the SPI default impl, which
calls back into scrubString(java.lang.String, com.tnsai.quality.redaction.RedactionContext) for every leaf String. Each
leaf with findings produces one audit event. This may fan out heavily
for large object trees — operators who want a single per-call audit
should run the listener at a higher layer (e.g. inside their own
decorator that wraps the RedactingMemoryStore).
Thread-safety: stateless beyond holding the immutable delegate + listener references.
- Since:
- 0.9.0 (issue #80)
-
Constructor Summary
Constructors -
Method Summary
Modifier and TypeMethodDescriptionbooleanmaybeContainsSensitive(String input) Cheap pre-check: returnstruewheninputmight contain something worth scanning.scrubString(String input, RedactionContext ctx) Scrub sensitive patterns out ofinput, returning the redacted text + every match.Methods inherited from class java.lang.Object
equals, getClass, hashCode, notify, notifyAll, toString, wait, wait, waitMethods inherited from interface com.tnsai.quality.redaction.Redactor
scrubValue
-
Constructor Details
-
AuditingRedactor
- Throws:
NullPointerException- if either arg is null
-
-
Method Details
-
scrubString
Description copied from interface:RedactorScrub sensitive patterns out ofinput, returning the redacted text + every match.- Specified by:
scrubStringin interfaceRedactor- Parameters:
input- plaintext to scan; never null.""is acceptable and returns an unchanged result.ctx- per-call context (sink, tenant policy)- Returns:
- redacted text + findings; never null
-
maybeContainsSensitive
Description copied from interface:RedactorCheap pre-check: returnstruewheninputmight contain something worth scanning. Lets the framework short-circuit the regex loop on guaranteed-clean strings (UUIDs, numeric IDs, fixed-vocabulary enums). Defaulttruebecause the safe fallback is "always scan"; override when you can do better.- Specified by:
maybeContainsSensitivein interfaceRedactor
-