Repository navigation
fix(net): make every AUTH stream ending exact on both sides - #4550
Conversation
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>
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: 7bc0dd0f0f
ℹ️ 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".
…s JS test Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
kixelated
left a comment
There was a problem hiding this comment.
Automated review by review (OpenAI)
Reviewed head: 39d5f08
Direction: the token-lifetime fixes are well targeted. A serving guard that settles Issued.closed on every exit is preferable to adding cleanup independently to each return path; recomputing grants on session close is also necessary.
No additional actionable defect found in the changed serving/drop and presenter termination paths. The current head includes the changelog and test-cleanup fixes from earlier review. JS/IETF session-fatal propagation remains deliberately deferred to #4554, so this PR should be described as exact AUTH endings, not complete cross-language protocol-violation parity.
Verification: static review of changed Rust/JS paths and regression tests; no Rust/Bun tests executed here.
(Written by OpenAI)
# Conflicts: # drafts/draft-lcurley-moq-lite.md # quest/m1/auth/README.md
|
You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard. |
# Conflicts: # quest/m1/auth/README.md
|
You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard. |
Review (head
|
Resolves the auth.rs / lite publisher conflict by keeping both changes: the Serving drop guard from this branch and the DefaultGrant re-sent path from the base.
A regression left `Issued.closed` pending, so the test hung until the runner's own timeout, once per protocol. Race it against the existing `withTimeout` helper, which clears its timer, and fail loud when the setup token never arrives.
|
You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard. |
Takeover: base merge, CI, and the three review threadsPushed The conflictThe branch had merged
Quest alignment check afterwards: CIThere was no red check: head After the merge,
No unrelated breakage found. Review threads
StateMergeable, no blocking findings outstanding, no public API or wire change beyond what the body already claims. Marking it ready for review. (Written by Space Bunny Free) |
Re-review (head
|
kixelated
left a comment
There was a problem hiding this comment.
Automated review by review (OpenAI)
Reviewed head: d2755ac
P2: Record dispatcher failures before dropping its AUTH handlers. This is a newly identified gap in the original PR, also present at 39d5f08, not a regression from this update. The auth.close at ietf/session.rs:472–477 is too late when run_dispatch itself fails. That function owns its TaskSet and returns UnexpectedStream for an unknown bidi request, dropping active AUTH handlers before its caller receives the error. With an existing issued grant, Serving::drop consequently records Cancel because the auth handle is still open; its first-reason-wins settlement prevents the later session close from correcting Issued.closed. Record the dispatcher error before its local tasks unwind, or keep those tasks owned by the outer driver. Add a regression that issues a grant, sends an unknown bidi request, and checks that Issued.closed reports UnexpectedStream rather than Cancel. The existing driver-abort test only expects Cancel, so it cannot catch this.
Direction: keep this PR and the private Serving guard; the lifetime fix is worth its small complexity. The merge preserves the base's DefaultGrant refresh path, and the JS timeout change cleans up both sessions on failure. Fix the teardown ordering above; no broader API redesign is needed. Previously deferred JS/IETF protocol-violation parity remains separate.
Verification: static review of the base merge, changed code, task ownership, and regression tests. Rust/Bun tests were not run here; head CI is not yet complete.
(Written by OpenAI)
`run_dispatch` owns the TaskSet that holds the AUTH serve tasks, so an error return dropped them before the driver reached its own `auth.close`. The new `Serving` guard then read a still-open handle and recorded `Cancel`, and because the first reason wins, the driver's later close with the real error could not correct it. Every grant on the session reported a bare cancel instead of, say, `UnexpectedStream`. Scope the loop so the handle closes while `tasks` is still alive. The driver closes it again with the same error, which then does nothing. No public API or wire change. Co-Authored-By: Space Bunny Free <noreply@opencode.ai>
Re-review (head
|
kixelated
left a comment
There was a problem hiding this comment.
Automated review by review (OpenAI)
Reviewed head: 6857be9
The previous P2 is fixed in the code: the scoped dispatch loop borrows its TaskSet, and ietf/session.rs:945–950 records the dispatcher error before that set drops. UnexpectedStream and the other error returns now reach Serving::drop with the correct reason; the outer driver's close remains idempotent. No new actionable defect found in this one-commit update from d2755ac.
The requested regression is still missing. tests/auth.rs:614–632 only aborts the driver and expects Cancel, so it cannot protect this ordering fix. Add the previously suggested issued-grant + unknown-bidi test asserting UnexpectedStream.
Direction: keep this focused fix and the private Serving guard. The scoped loop adds little complexity and fixes the ownership boundary without changing the public API or wire contract.
Verification: static review of the complete incremental diff, dispatcher/driver teardown, TaskSet, Serving, and the existing test. No Rust/Bun tests run here. Head CI is still running/queued.
(Written by OpenAI)
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 6857be9ba8
ℹ️ 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".
| impl Drop for Serving { | ||
| fn drop(&mut self) { | ||
| let err = self.handle.state.read().closed().unwrap_or(Error::Cancel); | ||
| self.end(err); |
There was a problem hiding this comment.
Settle lite grants when the driver completes
When a lite session driver reaches a terminal result but its caller retains the Driver, Driver::State::poll caches the completed Protocol::Lite instead of dropping it. The Publisher and its AuthServe children therefore remain parked, so this drop-only guard never records the session error and Issued::closed() can still wait indefinitely after the session has ended. Settle the issues when the lite driver completes, rather than relying on the public driver being dropped.
AGENTS.md reference: rs/AGENTS.md:L13-L15
Useful? React with 👍 / 👎.
|
Merged as a merge commit into One commit past the reviewed headThe automated review posted a P2 at 05:06 UTC, after the takeover summary, so it had not been addressed yet. It is real, and I confirmed it against the code:
Fixed in What I did not doI did not add the regression the review asked for, which issues a grant, sends an unknown bidi request, and asserts The JS oversized-AUTH_ERROR rule stays in the AUTH violations quest, as settled: the Rust and JS halves land together there. The existing reply on that thread already says so, so I left it alone. No package versions bumped. (Written by Space Bunny Free) |
Problem
Four loose ends from #4062 left some AUTH stream endings reporting something other than what happened:
u32was saturated tou32::MAX, so distinct peer codes collapsed into one the peer never sent.AuthSession.close()cleared its tokens without recomputing the union, soauth.grantkept a live grant after the session closed.Issued.closedstayed pending until the session ended.Issued::closed()never resolved when the session dropped the task serving that token (AuthServein lite,Servein IETF).Approach
u32ends the token withProtocolViolation, and a token ending inProtocolViolationnow closes the session with PROTOCOL_VIOLATION. This also applies to the existing out-of-range AUTH_OK expiry, which used to end only the token. The lite draft says so in one line.AuthSession.close()recomputes the union, so it becomes empty, matching Rust.auth::Servingguard owns the sharedIssue. When it drops, it records the session's close error, unless the task already recorded one. The IETF driver now closes the auth handle before its Auth serve tasks drop, so they settle with the session's real error rather than a bare cancel. Lite already had that ordering.Each fix has a regression test that fails without it:
lite::session::tests::an_auth_error_code_past_u32_closes_the_sessionan_issued_grant_ends_with_its_session, run on lite-06, moqt-17 and moqt-22closing the session drops the grantandan acceptor that ends a grant sees its stream close, each run on all three protocolsImpact
auth::Servingispub(crate).Alternatives
u64code. The quest decided against it, since session codes areu32everywhere else.Issued::closed()also watch the session handle, instead of using a drop guard. That would need no change to the IETF drop order, but the quest chose a drop path so that no exit path can forget to settle.Follow-ups
Tracked by the AUTH violations quest in #4554:
ProtocolViolationon the IETF side (an out-of-range AUTH_OK expiry) still ends only that token.(Written by Claude Opus 5.5)
🤖 Generated with Claude Code