Skip to content

Fixes GRE-798: authenticate job WebSocket upgrades - #1254

Merged
poitee merged 2 commits into
mainfrom
gre-798-job-ws-auth
Oct 27, 2026
Merged

poitee merged 2 commits into
mainfrom
gre-798-job-ws-auth

Conversation

@poitee

@poitee poitee commented Oct 27, 2026 •

Copy link
Copy Markdown
Owner

Job WebSocket upgrades at /ws/jobs/{id} now refuse a bad origin, listener, or credential before any subscription. An admitted caller is checked with read_public, then the socket is held with no snapshots. HEAD uses the same check and does not subscribe.

A missing or foreign job stays HTTP 404, matching read-one. Node accepts the socket and closes 1008 Job not found. The web client treats only that close as final. GRE-799 owns that close.

Definition of done

See the definition of done.

  • One job, under about 1,500 lines. Work for other tickets is noted on those tickets.
  • Unslop pass run on code, comments and docs. No filler comments, dead code or speculative abstractions.
  • Docs updated in this PR, or the PR changes no behavior, setup or interface.
  • Reviewed by a different model vendor than the author, on the exact head commit, with CI green.

Evidence

CARGO_TARGET_DIR=/persist/targets/gre-798-job-ws, CARGO_BUILD_JOBS=2, head 720d62113a4afadc387e21a2d3048b93669a6d32.

cargo test -p pp-api --locked --manifest-path rust/Cargo.toml --features desktop_rebuild --test jobs_http -- --test-threads=2: 14 passed, 0 failed.

cargo test -p pp-api --locked --manifest-path rust/Cargo.toml --test jobs_http job_ws_rejects_invalid_origin_or_principal: feature off, 1 passed.

cargo test -p pp-api --locked --manifest-path rust/Cargo.toml --test jobs_http job_ws_head_does_not_subscribe: feature off, 1 passed.

cargo clippy -p pp-api --locked --manifest-path rust/Cargo.toml --features desktop_rebuild --all-targets -- -D warnings: finished clean.

cargo check -p pp-api --locked --manifest-path rust/Cargo.toml --no-default-features: finished.

Exemption

Exemption: none

Reviewed with sol-loop: 1 round with Claude Opus 5.5 on xhigh. Sol asked for a change on the HTTP 404 for a missing job. This slice keeps that 404, matching read-one, and records the Node 1008 close on GRE-799. The stale mutation test name was renamed. A live 101 hold test was declined. The named tests are the two refusal tests.

Council review

Rounds: 1 of 4. Head 720d62113a4afadc387e21a2d3048b93669a6d32. All three approved. No code change.

Delegate Round 1
Claude Opus 5.5 8/10 APPROVE
Grok 4.7 9/10 APPROVE
Qwen3.8-Flash 8/10 APPROVE

Declined, no code change:

  • No in-repo test of an admitted GET upgrade (101, slot taken, silent socket, slot freed on close). The ticket names the two refusal tests. Claude checked that path by hand on this head and deleted the scratch test. GRE-799 pumps the socket and can pin the hold with that work.
  • Missing-id 404 is asserted for HEAD, and another tenant's session is asserted for GET and HEAD. A missing-id GET and a foreign API key use the same read_public map as read-one.
  • A plain GET with no upgrade headers gets axum's 400 text, Connection header did not include 'upgrade', for both an existing job and a missing job. That is not an upgrade, and it does not leak which id exists.
  • An open socket keeps its stream slot until the client closes. This slice sends no frames. GRE-799 reads that state when it pumps.
  • A missing job is HTTP 404 here, so the web client would reconnect until GRE-799 closes 1008 Job not found. jobs_router is not mounted outside tests, and the route stays behind desktop_rebuild plus PP_DESKTOP_REBUILD. The doc already assigns that close to GRE-799.
  • Two storage reads, a duplicated credential check, and the 64 admission permits ending when the handler returns are the shape this ticket asked for. Storage's 128 subscription cap is what bounds open sockets.

Created with Grok 4.7 in T3 Code.

GET and HEAD /ws/jobs/{id} refuse a bad origin, listener, or credential before subscribe. An admitted upgrade calls read_public, then subscribe, and holds the socket without sending snapshots. HEAD uses the same admission and does not subscribe.
HTTP 404 before upgrade stays in this slice and matches read-one. GRE-799 must accept the socket and close 1008 Job not found before the web client uses the route. The mutation test name now matches the mounted WebSocket route.
@poitee
poitee merged commit d6f6132 into main Oct 27, 2026
35 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant