Repository navigation
Redaction exception values and scan cache (core v0.86.0) - #130
Merged
Merged
Conversation
….86.0) - Core crates pinned to v0.86.0. - Exception values: stored in the redaction policy (`security.redact. exceptions`, SHA-256 and masked form only). New endpoints list, add (the pasted value is hashed on arrival and never stored, logged or answered) and remove them, with the permissions of editing the redaction policy; each add and remove is audited with the rule and the masked value. The row is locked from read to write. A policy written through the settings endpoint keeps the stored exceptions, since the console writes the policy back from the rule view, which does not carry them. - Console: an Exceptions section under the redaction rules (masked value, rule, added time, remove; add dialog; adding unavailable at the cap); the trial marks excepted values as left as is. - Gateway: one thinkwatch-core ScanCache per compiled redaction rule set, used when looking at and replacing a request, so unchanged conversation history is taken from the previous turn. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to subscribe to this conversation on GitHub.
Already have an account?
Sign in.
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What this changes
thinkwatch-core moves to v0.86.0. Secrets and privacy gains exception values: a value recognised by mistake can be listed so that it is neither replaced nor recorded by any rule, while the rule keeps working for every other value. The gateway also stops rescanning unchanged conversation history every turn.
Why
Until now a false positive (a fixed test value, say) could only be silenced by switching the whole rule off, which also switched off its protection for real values. And a client sends the whole conversation every turn, so a long session's requests were scanned from the start each time.
Details
Storage. Exceptions live in the redaction policy as core defines it:
security.redact.exceptions, each{ sha256, masked, rule?, added_at }, at most 500. Only the SHA-256 and the masked form are stored, never the value. Saved provider keys cannot be exceptions.API (OpenAPI updated):
GET /api/admin/security/redact/exceptions→{ items, max };settings:read.POST /api/admin/security/redact/exceptions{ value }→ the exception as stored (201). The value is hashed on arrival by core'sRedactPolicy::exception_of, which also picks the masked form and the rule; the value is never stored, logged or answered. 409 when already listed; 400 when empty, a saved provider key, or the list is full.DELETE /api/admin/security/redact/exceptions/{sha256}→ the exception removed; 404 when absent.settings:writeandpii_redactor:write, the permissions of editing redaction rules. Each is audited (security.redact_exception_added/_removed) with the rule and the masked value only.config:changed.PATCH /api/admin/settingswithsecurity.redactkeeps the stored exceptions whatever it carries: the console rebuilds the policy from the rule view, which does not carry them.Console. An "Exceptions · N" section under the redaction rule table: masked value, the rule that first recognised it (named from the rule view), when it was added, and Remove (with confirmation). "Add exception" opens a dialog to paste a value, and is unavailable at the cap with the reason shown. With no exceptions the section is one line and the button. The trial marks excepted values ("Exception, left as is") and does not count them as hits.
Scan cache.
Redactionholds one coreScanCacheper compiled rule set and passes it tolook_hits_with/replace_with. The cache keeps hit positions and rule ids in process memory, never values, and is dropped with the rules whenever a policy, the providers' keys or the exceptions change. Results are identical to an uncached scan.Left out: "List as exception" from the security log. The audit log stores neither the value nor its hash, and should not. Offering the button would need each finding's hash kept somewhere until an admin clicks. Kept in one gateway instance's memory, it would be unreachable from the console instance handling the click (any of several replicas) and lost on restart; kept in Redis or the database, it would put value hashes at rest outside the policy. Exceptions are added by pasting the value instead.
How it was verified
cargo fmt --check,cargo clippy --workspace --all-targets: clean.excepted, audit rows with the rule and masked value only, remove then 404; and a saved provider key refused as an exception.check-i18n, eslint, vitest (205 passed, new tests for the section, the cap, the empty state and the trial),tsc -b, vite build.🤖 Generated with Claude Code