fix: redact dead rich-text style values in shallow snapshot exports - #1072
Merged
Conversation
…1057) Rationale and invariants: context/shallow-snapshot-style-redaction.md Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Contributor
WASM Size Report
|
- Structured leak assertions: internal tests decode the exported state KV and assert StyleOp values directly (root + nested text key ranges, overlay whitelist keep/redact, legacy unredacted blob cleaned on re-export), since LZ4 can hide secrets from raw byte scans. - Collapse the root/overlay redaction protocol into redact_export_states so the historical-checkout invariant lives in one place. - Merge the two shallow-root reuse branches; overlay decided by ops_num. - Single ContainerWrapper::decode_header shared by all header readers. Co-Authored-By: Claude Fable 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 join this conversation on GitHub.
Already have an account?
Sign in to comment
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.
Summary
Shallow snapshot export retained the value of a rich-text mark whose entire range had been deleted, even though every read API reported the data as gone. Deleted character content was already dropped correctly, so the leaked mark value defeated the documented content-redaction use of shallow snapshots. Reported with a failing test in #1057.
Deleting styled text removes the text chunks but style anchors stay in the state sequence forever, and the richtext state codec serialized each start anchor's value verbatim into the shallow-root state bytes.
Fix
Before the state KV is exported, shallow export now nulls the values of style pairs that are dead at the shallow root (no text between the anchors), operating directly on the live
KvWrapperwith no serialization round-trip:redact_dead_style_values(richtext snapshot codec): rewrites only the columnar tail of a Text container payload; single pass, pairs matched by id, dead iff no text span lies between the anchors.redact_dead_text_styles(shallow_snapshot.rs): scans only the two Text key ranges of the state KV; applied on all export paths — both reuse branches (so blobs produced by older versions are cleaned on re-export), the checkout branch, andStateOnly.Key invariants (full rationale in
context/shallow-snapshot-style-redaction.md):expand: bothpairs are never redacted. An empty both-expand pair still captures future inserts, so its value is live data; nulling it would break convergence with full-history replicas (verified experimentally). For after/none/before, insertion can never re-enter an empty pair, and inserts concurrent with the deletion cannot be imported into a shallow doc (ImportUpdatesThatDependsOnOutdatedVersion), so the value is truly unobservable.Validation
loro_rust_test183/183, all 11 loro-internal test targets, clippy clean, fuzz corpus smoke pass.Closes #1057.
🤖 Generated with Claude Code