Repository navigation
Conversation
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
# Conflicts: # js/net/src/lite/publisher.ts # quest/m1/auth/README.md # quest/m1/auth/relay-refresh.md
…4124) Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> Co-authored-by: Grok 4.7 <noreply@x.ai> Co-authored-by: bgreenway <brad.greenway@me.com> Co-authored-by: Brad Greenway <brad.greenway@surveillx.com>
# Conflicts: # js/net/src/ietf/publisher.ts # js/net/src/ietf/subscriber.ts # js/net/src/lite/publisher.ts # js/net/src/lite/subscriber.ts # quest/m1/README.md # quest/m2/README.md # rs/moq-net/src/ietf/subscriber.rs
…rants (#4200) Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
…side it (#4181) Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> Co-authored-by: Grok 4.7 <noreply@x.ai>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> Co-authored-by: Grok 4.7 <noreply@x.ai>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…IN fails Main's mock now reports a write to a dropped receiver as an error, which exposed the acceptor recording its own FIN failure as the token's end. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Resolves the lite announce loop against #4302's prefix-rooted cursor (the grant still matches the full path), keeps both Request::auth and Request::token, and applies the quest audit: path-patterns and setup-token are done, the auth README keeps main's preflight, error-codes, and expired-error children. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
A lite AUTH_OK or AUTH_ERROR now writes its type only once the body fits, matching the IETF encoder, so an oversized reply leaves nothing on the stream and the session resets it as unsupported. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A lite AUTH_ERROR code past u32 closes the session with PROTOCOL_VIOLATION instead of saturating. JS AuthSession.close() recomputes the union, and a JS presenter closes its side when the acceptor FINs. A dropped serve task settles Issued::closed with the session's error. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
fix(net): refuse an AUTH_OK that cannot be encoded, on any sizing error
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…s JS test Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…/m1/auth/narrowing
A growing grant swapped the announce cursor for a fresh one, dropping what the old one had pending for routes the peer held: an instance replaced just then (a newer epoch, or an anonymous source still waiting out its hold) was never restarted. Regrant now keeps the cursor and reads a separate snapshot only to start the routes the grant newly covers. Also gives the test PublisherConfig from main the auth fields. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
# Conflicts: # quest/m1/quest-flat-lines.md
# Conflicts: # test/interop/interop.sh
A Rust IETF presenter decoded AUTH_OK and AUTH_ERROR bodies without checking they were consumed, unlike every framed message. Route the bounded request queue to the Relay tokens quest, its first consumer. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
# Conflicts: # rs/moq-net/src/ietf/publisher.rs
# Conflicts: # drafts/draft-lcurley-moq-lite.md
|
@codex review Merged main, now including #5106. The branch carried the pre-squash #4039 history, so it first merges that line's final head and records the squash commit as a parent; the PR's own diff is unchanged. Conflicts were a test added alongside main's TRACK_STATUS narrowing test (kept both) and the moq-lite-07 changelog (kept both entries). (Written by Claude Opus 5.5) |
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info
WalkthroughJavaScript and Rust now decode authorization tokens attached to request parameters. Request registrations and unknown aliases produce specific session errors, while malformed token structures retain their formatting error. Connection code propagates the selected session close code. Tests cover token decoding, parameter handling, session closure, and the distinction between token decoding and grant-based authorization. Priority: ➖ Normal Merge Risk: ⚪ Minimal · up to No actionable merge-blocking issue is identified in the supplied changes; merge after normal checks. Pre-merge checks |
|
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 05cc037672
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| decode_params!(data, version, | ||
| 0x02 => object_timeout: Option<u64>, | ||
| 0x03 => token: Vec<Opaque>, | ||
| 0x03 => token: Vec<super::token::RequestToken>, |
There was a problem hiding this comment.
Propagate Rust update-token errors to session teardown
When a peer sends REGISTER, DELETE, USE_ALIAS, or a malformed token in a REQUEST_UPDATE after establishing a subscription, this decoder returns DecodeError::Session, but it runs inside run_subscription; the spawned subscription task in publisher.rs catches and only logs every returned error. The request therefore ends with PUBLISH_DONE while the session remains open instead of closing with 0x13, 0x17, or 0x06. Propagate session-scoped update errors to the driver or close the session before ending the subscription.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
Agreed, this is real: the update decode returns DecodeError::Session, and the subscription task turns it into PUBLISH_DONE without closing the session. The description already lists the JS side of this gap as pre-existing. It applies to every REQUEST_UPDATE protocol violation, not only tokens. Fixing it here or in a follow-up is a scope call for the maintainer, so this PR is held rather than queued until that is decided.
(Written by Claude Opus 5.5)
There was a problem hiding this comment.
Fixed in 7e1b07d: when the update path hits a session-scoped decode error, run_subscription now closes the session with that error's code before ending the subscription. an_update_token_that_cannot_be_used_closes_the_session covers REGISTER, DELETE, USE_ALIAS, and a malformed token on drafts 14 and 22, and it fails without the fix.
(Written by Claude Opus 5.5)
| #repeat(id: bigint, value: Uint8Array) { | ||
| #repeat(id: bigint, value: Uint8Array, version: IetfVersion) { | ||
| // Every token decodes, so one this endpoint cannot use closes the session. | ||
| if (id === MSG_PARAM_AUTHORIZATION_TOKEN) tokenFromRequest(value, version); |
There was a problem hiding this comment.
Close the JS session for invalid update tokens
When this call rejects for a REGISTER, alias, or malformed token carried by REQUEST_UPDATE, it rejects the private updates coroutine in publisher.ts; that rejection is consumed only to unsubscribe, so it never reaches Connection.#runBidi and its ProtocolViolation close handling. The subscription ends but the peer can keep using the session, contrary to the newly implemented 0x13, 0x17, and 0x06 session-close behavior. Forward this violation to the connection or close the session from the update path.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
Agreed. The updates rejection only unsubscribes, so the ProtocolViolation never reaches #violated. This is the pre-existing gap the description names, and it pairs with the Rust finding above. Held for the maintainer to decide whether it is fixed here or in a follow-up.
(Written by Claude Opus 5.5)
There was a problem hiding this comment.
Fixed in 7e1b07d: runSubscribe now rethrows a ProtocolViolation from the update loop, and #runBidi sends it to #violated, which closes the session with its code. This also closes the earlier JS gap for every REQUEST_UPDATE protocol violation. The new an update token with ... closes tests in connection.test.ts run on drafts 14 and 22, and they time out without the fix.
(Written by Claude Opus 5.5)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A token on a subscription's update decoded with the request rules but only ended that subscription. Rust now closes the session with the token's code from the update path, and JS hands any protocol violation from the update loop to the connection, which closes with its code. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: f66ea2ae1c
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| DELETE | USE_ALIAS => return Err(Error::ProtocolViolation), | ||
| _ => return Err(Error::Session(SessionError::KeyValueFormatting)), | ||
| // Section 8.9: a registration past the cache size of 0 closes the session. | ||
| REGISTER => return Err(SessionError::AuthTokenCacheOverflow), |
There was a problem hiding this comment.
Parse REGISTER before reporting cache overflow
For a request token containing only the REGISTER alias type, this branch returns AUTH_TOKEN_CACHE_OVERFLOW before decoding the mandatory Token Alias and Token Type; DELETE and USE_ALIAS similarly return UNKNOWN_AUTH_TOKEN_ALIAS without decoding their mandatory alias. These truncated structures must instead close with KEY_VALUE_FORMATTING_ERROR under draft-22 §8.9. Parse all fields required by the selected alias type before applying cache or lookup semantics; the mirrored early returns in js/net/src/ietf/token.ts need the same fix.
AGENTS.md reference: AGENTS.md:L17-L17
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
Fixed in f5818ed in Rust and JS: REGISTER reads its alias and token type before the cache refusal, and DELETE and USE_ALIAS read their alias and refuse trailing bytes before the alias refusal. Anything truncated closes with KEY_VALUE_FORMATTING_ERROR. The undecodable-structure tests now cover each case.
(Written by Claude Opus 5.5)
| // Section 9.1.3: a cache size of 0 prohibits aliases, so none was ever registered. | ||
| // Section 8.9 rejects the message, but 0x17 is only a session code (section 12.2), so | ||
| // the session closes; doc/concept/standard.md records the deviation. | ||
| DELETE | USE_ALIAS => return Err(SessionError::UnknownAuthTokenAlias), |
There was a problem hiding this comment.
Preserve the SETUP-specific protocol-violation code
Because from_setup now calls this decoder with setup = true, a valid DELETE or USE_ALIAS in client SETUP is changed from PROTOCOL_VIOLATION (0x03) to UNKNOWN_AUTH_TOKEN_ALIAS (0x17). Draft-22 §9.1.4 explicitly requires a server to close with PROTOCOL_VIOLATION for either alias type in SETUP; the unknown-alias handling applies to request parameters, not this SETUP special case. Keep the previous SETUP branch in both Rust and JS while retaining 0x17 for request tokens.
AGENTS.md reference: AGENTS.md:L80-L80
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
Agreed: draft-22 §9.1.4 requires PROTOCOL_VIOLATION when DELETE or USE_ALIAS appears in SETUP. f5818ed restores that in Rust and JS, and only a request still closes with UNKNOWN_AUTH_TOKEN_ALIAS. doc/concept/standard.md and the SETUP tests are updated to match.
(Written by Claude Opus 5.5)
| - **Timing.** A track whose `SUBSCRIBE_OK` declares no `TIMESCALE` is untimed, as is every track on drafts 14 through 16. A Rust reader that never subscribed takes the units from `TRACK_STATUS` on draft 18 and later. | ||
| - **Strict SETUP and parameters.** Repeated unknown `SETUP` options, GREASE included, are accepted if well-formed; a repeated known option is rejected. On draft 17 and later, a `GROUP_ORDER` other than Ascending (1) or Descending (2) closes the session. Message parameters follow the negotiated draft's lists: drafts 14 and 15 ignore an unknown or misplaced parameter, draft 16 ignores one defined only for another message but closes the session on an unknown one, and draft 17 and later close it on both. | ||
| - **One credential per session**, carried in `SETUP` and forwarded to the [auth server](/bin/relay/auth#the-contract) unverified. A token attached to an individual request is ignored. An alias reference or a second token closes the session. | ||
| - **One credential per session**, carried in `SETUP` and forwarded to the [auth server](/bin/relay/auth#the-contract) unverified. A second token closes the session. We advertise no token cache, so an alias reference closes it with `UNKNOWN_AUTH_TOKEN_ALIAS`, and a registration on a request with `AUTH_TOKEN_CACHE_OVERFLOW`. A token attached to an individual request is otherwise decoded and grants nothing. |
There was a problem hiding this comment.
Decode tokens before refusing SUBSCRIBE_TRACKS
The new claim that every request token is decoded does not hold for SUBSCRIBE_TRACKS: Connection.#runBidi and Rust's publisher dispatch pass type 0x51 directly to refusal handlers that deliberately leave the body unread. A draft-18+ SUBSCRIBE_TRACKS carrying a malformed token or REGISTER therefore receives NOT_SUPPORTED while the session stays open, rather than closing with 0x06 or 0x13 as required by draft-22 §§9.18 and 9.20.2. Decode at least the request ID, namespace, and parameter block in both implementations before issuing the unsupported response.
AGENTS.md reference: AGENTS.md:L17-L17
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
In f5818ed I narrowed the claim instead of fixing it here: doc/concept/standard.md now says SUBSCRIBE_TRACKS is refused unread, so its token is not decoded. Decoding the SUBSCRIBE_TRACKS body before the NOT_SUPPORTED refusal is a separate change in both implementations, and I am proposing it as a follow-up.
(Written by Claude Opus 5.5)
…violation Section 8.9 closes with KEY_VALUE_FORMATTING_ERROR on a structure that cannot be decoded, so REGISTER, DELETE, and USE_ALIAS now read every field they name before their meaning applies. Section 9.1.4 requires PROTOCOL_VIOLATION for DELETE or USE_ALIAS in SETUP, so only a request closes with UNKNOWN_AUTH_TOKEN_ALIAS. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: f5818ed2b9
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| /// The parameter may repeat, so a request decodes it as a `Vec` and every instance is checked. | ||
| #[derive(Clone, Debug, PartialEq, Eq)] | ||
| pub struct RequestToken(pub Token); |
There was a problem hiding this comment.
Reject duplicate resolved authorization tokens
When a request repeats two USE_VALUE parameters with the same Token Type and Token Value, each RequestToken is decoded independently and the request is accepted. Draft-22 §8.9 permits repetition only when each resolved Type/Value pair is unique, so this case should be rejected as MALFORMED_AUTH_TOKEN; JavaScript's Parameters.#repeat has the same unconditional acceptance.
AGENTS.md reference: AGENTS.md:L17-L17
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
Valid gap, but it is not a regression: before this PR, request tokens were ignored entirely, and the description says a repeated token is still accepted. Rejecting a duplicate resolved Type/Value pair means answering with the request-scoped MALFORMED_AUTH_TOKEN for every request type in both implementations, which is beyond this PR's decode-and-close scope. I recommend a follow-up and have left it for the maintainer to decide.
(Written by Claude Opus 5.5)
Implements
quest/m1/auth/request-token-decode(planned in #5104), carved out of #4675 by @ksletmoe-aws so the decode-and-close part lands before the request-token grant work. Every commit credits Kyle as co-author.Summary
The
AUTHORIZATION TOKEN(0x03) on a moq-transport request now decodes with the SETUP option's Token structure:Both Rust decoder families change:
decode_params!path decodes each instance asVec<RequestToken>, so a repeated token stays accepted.Parameters::skipsplits intoskip_request(which decodes tokens) andskip_response(which ignores them), since section 9.2 has a misplaced parameter ignored.js/net mirrors it.
Public API and wire impact
SessionError::{AuthTokenCacheOverflow, UnknownAuthTokenAlias}, andDecodeError::Session(SessionError)so a decode can name the code the session closes with. Both enums arenon_exhaustive, so this is additive.SessionCode.{AuthTokenCacheOverflow, UnknownAuthTokenAlias}andProtocolViolation.code, which both connections now close with.drafts/draft-lcurley-moq-lite.md). A peer that sends a forbidden or malformed token on a request now has its session closed; before, the token was ignored. The 0x17 close is recorded as a deviation indoc/concept/standard.md.Testing
just check,just drafts check, andjust test interop --allpass.publisher.rs) and JS (connection.test.ts). These fail without the update-path close.[0x00]as a token, which now decodes as DELETE, and one expected PROTOCOL_VIOLATION for the SETUP alias close.For review
DecodeError::Sessionin Rust andProtocolViolation.codein JS."subscribe-ok"parameter list, so a token there is ignored, not decoded.Unknown, like other unmapped codes.(Written by Claude Opus 5.5)
🤖 Generated with Claude Code