feat(ws-topic)!: reject a topic subscription on binary-encoding mismatch - #3160
Open
phil-opp wants to merge 1 commit into
Open
feat(ws-topic)!: reject a topic subscription on binary-encoding mismatch#3160phil-opp wants to merge 1 commit into
phil-opp wants to merge 1 commit into
Conversation
The topic data channel pushes `subscription_id ++ <encoded Timestamped<InterDaemonEvent>>` with no per-frame envelope. Both the old (bincode) and current (postcard) encodings are positional, so a peer on the wrong one does not fail to decode — it misparses, yielding plausible-looking garbage. That was the one break in #3153 that could not fail loudly. The subscription handshake now carries `protocol_version` in both directions and either side refuses on mismatch. Both fields are `#[serde(default)]`, so a peer predating the handshake omits them, deserializes to `None`, and is rejected for the same reason a wrong number is — covering both skew directions. `Hello`/`check_cli_version` does not make this redundant: third-party subscribers never send `Hello`, and `versions_compatible` is semver-caret, so a future encoding change inside 1.x would be waved through. Refs #3153
Contributor
|
Merging to
After your PR is submitted to the merge queue, this comment will be automatically updated with its status. If the PR fails, failure details will also be posted here |
Collaborator
Author
No issues found. I traced the new
Generated by Claude Code |
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.
Follow-up to #3153, which noted this gap but left it out of scope.
The WebSocket topic-data channel pushes
subscription_id ++ <encoded Timestamped<InterDaemonEvent>>with no per-frame envelope. Both the old (bincode) and current (postcard) encodings are positional, so a peer on the wrong one doesn't fail to decode — it misparses, yielding plausible-looking garbage. That was the one break in #3153 that couldn't fail loudly.The subscription handshake now carries
protocol_versionin both directions and either side refuses on mismatch:{"TopicSubscribe": {"dataflow_id": "…", "topics": […], "protocol_version": 2}} {"TopicSubscribed": {"subscription_id": "…", "protocol_version": 2}}Both fields are
#[serde(default)], so a peer predating the handshake omits them, deserializes toNone, and is rejected for the same reason a wrong number is. That covers both skew directions: an old coordinator's ack has no version and the CLI refuses it; an old CLI's request has no version and the coordinator refuses it before creating anything.TOPIC_DATA_PROTOCOL_VERSIONlives indora-message(1 = bincode, 2 = postcard). Bump it whenever the binary payload encoding changes; the JSON handshake is self-describing and doesn't need it.Rejections name both versions so an operator can tell which side is old without reading the source:
Note on the coordinator-side subscription
On mismatch the CLI refuses the ack but deliberately does not send
TopicUnsubscribe. Only a pre-handshake coordinator reaches that branch having actually created a subscription — a current one rejects before creating anything — and all foursubscribe_topicscallers propagate the error with?, dropping theWsSession, which closes the connection and makes the coordinator tear its subscriptions down. Threading an outgoing sender intohandle_response(already at its argument limit) to save an already-closing subscription didn't seem to earn its keep. Reasoning is recorded at the call site.Tests
only_our_exact_protocol_version_is_acceptedpins the accept/reject decision itself —check_topic_protocolis split out of the request handler so deleting or inverting the guard fails a test rather than only changing a message.topic_subscribe_ack_rejects_older_protocol_version/…_missing_protocol_versionassert the CLI refuses and that the subscription is not registered for frame dispatch.tests/ws-cli-e2e.rs's mock coordinator now advertises the current version, which is what proves the happy path still connects end to end.Docs and the guide mirror gain a Protocol version section; the changelog entry and the
docs/websocket-topic-data-channel.mdnote that both said "there is no version handshake on this channel" are corrected.