-
Notifications
You must be signed in to change notification settings - Fork 90
fix(xmtp_db,xmtp_mls): tolerate unknown intent kinds + app-data hardening docs #3871
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
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
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
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
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
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
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
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
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
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,85 @@ | ||
| # App-data validator remediation runbook | ||
|
|
||
| What to do when a **fielded release ships a receive-side validation bug** on the | ||
| app-data (post-migration) path — a validator that wrongly rejects commits other | ||
| versions accept, or wrongly accepts commits it shouldn't. The goal is always the | ||
| same: convert divergence into **pause** (recoverable by upgrading) and never into | ||
| **fork** (permanent group split). No wire-format migration is required for any | ||
| scenario below. | ||
|
|
||
| ## The lever: per-group protocol-version floor bumps | ||
|
|
||
| `MlsGroup::update_group_min_version` (and `update_group_min_version_to_match_self`) | ||
| writes the group's `MIN_SUPPORTED_PROTOCOL_VERSION` floor — the legacy | ||
| `GroupMutableMetadata` attribute pre-migration, the `0x800A` AppData component | ||
| post-migration. Receive-side monotonicity means a floor can only rise. | ||
|
|
||
| Any member processing a commit on a group whose **committed** floor exceeds its | ||
| own version pauses the group (`paused_for_version`): the cursor holds, all | ||
| subsequent commits are deferred, and after the app upgrades the sweep unpauses | ||
| the group and reprocesses everything with fixed code. Pausing never accepts or | ||
| rejects anything, so a wrongly-paused client always converges once upgraded. | ||
|
|
||
| Writing the floor is super-admin-gated on groups (both members on DMs). | ||
|
|
||
| ## Scenario: version X validator wrongly REJECTS valid commits | ||
|
|
||
| Fielded X clients fork off groups whenever the triggering commit shape appears. | ||
|
|
||
| 1. Fix the validator in version Y. | ||
| 2. Bump `PROPOSALS_MIN_PROTOCOL_VERSION` to Y so newly-migrating groups get the | ||
| Y floor from bootstrap. | ||
| 3. For existing migrated groups: have (super-admin) clients on Y bump each | ||
| group's floor to Y — e.g. wire `update_group_min_version_to_match_self` into | ||
| a recovery flow. X members pause **at the floor-bump commit** (its cursor | ||
| holds there), so they never process the bug-triggering commits mid-stream; | ||
| after upgrading to Y they reprocess everything with the fixed validator. | ||
| 4. X members who already rejected a commit before the floor bump landed are | ||
| forked; recovery for them is the normal fork-recovery path (re-add / | ||
| re-welcome), not this runbook. | ||
|
|
||
| ## Scenario: version X validator wrongly ACCEPTS bad state | ||
|
|
||
| E.g. the pre-#3863 registry-poison bug: state that wedges or corrupts readers. | ||
|
|
||
| 1. Fix acceptance in Y, plus a read-side tolerance for the already-fielded bad | ||
| state where possible (the #3863 pattern: preserved-but-invisible registry | ||
| entries — bad state degrades to "that component is unavailable", not "no | ||
| commit validates"). | ||
| 2. Floor-bump affected groups to Y as above so X members stop extending the bad | ||
| state and pause until they can run the tolerant readers. | ||
|
|
||
| ## Why the floor is trustworthy | ||
|
|
||
| The pause guards read only **committed** floor state (the pre-commit dict or | ||
| legacy GMM), never same-commit proposals — a floor value only exists after its | ||
| super-admin policy check passed on every honest receiver. See the floor-bump | ||
| convention in `xmtp_mls_common::app_data::registry_table` for the send-side | ||
| rules protocol evolution must follow. | ||
|
|
||
| **Caveat — the floor-bump commit is not self-pausing.** The commit that *raises* | ||
| the floor is itself validated under the *old* floor: on migrated groups | ||
| `ValidatedCommit::from_staged_commit` reads the floor from the post-commit | ||
| dictionary overlay (which includes the bump commit's own staged `AppDataUpdate`), | ||
| and `ProtocolVersionTooLow` is checked only *after* the other commit validators | ||
| and policy evaluation. So an X client pauses on the *next* commit it sees under | ||
| the raised floor — not on the bump commit itself. That means the floor-bump | ||
| commit must be one every affected (X) version can still *accept*: if a bug in the | ||
| bump commit's shape makes an X validator reject it before the floor check runs, X | ||
| clients fork instead of pausing. Keep the floor-bump commit format-boring (a plain | ||
| `MIN_SUPPORTED_PROTOCOL_VERSION` write, no new-format payloads) — this is exactly | ||
| why the convention requires the bump to land in a strictly-earlier, boring commit. | ||
|
|
||
| ## Sharp edges | ||
|
|
||
| - **Monotonic means permanent.** A floor of `999.0.0` written by a rogue or | ||
| buggy super admin pauses the group for everyone forever (send-side clamp | ||
| `min_version <= own pkg_version` makes accidents unlikely; a malicious super | ||
| admin can equally destroy a group in more direct ways). | ||
| - **The registry must stay loadable** for the post-migration floor to be | ||
| readable — the entry-validation + tolerant-loader pair (#3863) is what keeps | ||
| this lever alive on groups carrying unexpected registry state. | ||
| - **Same-device downgrades** below a group's committed floor pause at the next | ||
| commit (pause-before-parse guards, #3864); unknown-`IntentKind` rows written | ||
| by the newer build are excluded from outbound queries rather than wedging | ||
| them. Both recover on re-upgrade. | ||
Oops, something went wrong.
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.
Uh oh!
There was an error while loading. Please reload this page.