Skip to content

fix(desktop): validate live WebSocket in remote gateway test (salvage #39098) - #39511

Merged
teknium1 merged 3 commits into
mainfrom
hermes/hermes-2173cae3
Jun 5, 2026
Merged

fix(desktop): validate live WebSocket in remote gateway test (salvage #39098)#39511
teknium1 merged 3 commits into
mainfrom
hermes/hermes-2173cae3

Conversation

@teknium1

@teknium1 teknium1 commented Jun 5, 2026

Copy link
Copy Markdown
Contributor

Summary

The Desktop "Test remote" button now validates the live WebSocket the app actually uses — and correctly fails (instead of silently skipping) when an OAuth session can't authenticate the socket.

Salvages #39098 (@xxxigm) onto current main and resolves @YoussefEttamimi's blocking review.

Root cause: desktop boot touches a remote gateway over two transports — HTTP GET /api/status (what "Test remote" checked) and a live WebSocket to /api/ws (what the chat surface needs). The WS upgrade has extra server-side guards (Host/Origin, ws-ticket/token auth, peer-IP) the HTTP route never sees, so a gateway can pass /api/status yet reject the socket — a green "reachable" followed by the opaque "Could not connect to Hermes gateway" overlay.

Changes

  • electron/gateway-ws-probe.cjs (new): injectable WS probe that classifies the handshake (open/stays-open or frame = ok; error / close-before-open / accept-then-early-close / timeout = fail).
  • electron/main.cjs: testDesktopConnectionConfig opens the live WS after the HTTP check; throws an actionable message on probe failure.
  • electron/connection-config.cjs: resolveTestWsUrl extracted here (electron-free, injectable mintTicket) so it's unit-testable.
  • Follow-up fix (Youssef's review): OAuth ticket-mint failure now throws a needsOauthLogin error instead of returning null + skipping the probe — mirroring the real boot path (resolveRemoteBackend), which treats a mint failure as a hard "session expired" auth error.

Validation

Case Before After
Remote behind proxy not forwarding Upgrade green "reachable" → boot fails test fails with WS message
OAuth session expired (ws-ticket mint fails) green "reachable" → boot fails test fails "sign in again"
token + WS fail n/a test fails
OAuth mint ok + WS fail n/a test fails
Healthy token/OAuth remote passes passes

npm run test:desktop:platforms → 62/62 passing (57 prior + 5 new resolveTestWsUrl cases).

Closes #39098. Original commits cherry-picked with @xxxigm's authorship preserved.

Infographic

live-websocket-validation

xxxigm and others added 3 commits June 4, 2026 19:34
Adds electron/gateway-ws-probe.cjs: a small helper that opens a gateway
WebSocket URL and classifies the handshake (open/frame → ok; error or close
before open → fail; open-then-early-close → credential rejected; never-opens →
timeout). The WebSocket implementation is injected so it can be unit-tested
without a real socket.

Wires gateway-ws-probe.test.cjs into test:desktop:platforms, covering every
handshake outcome plus constructor-throw and missing-impl.
The "Test remote" button only checked HTTP GET /api/status, but the chat
surface depends on the renderer opening a live WebSocket to /api/ws — a
separate transport with separate server-side guards (Host/Origin checks,
ws-ticket/token auth, peer-IP checks). A gateway could pass the HTTP check yet
reject the WebSocket, so the test reported "reachable" while boot still failed
with the opaque "Could not connect to Hermes gateway".

testDesktopConnectionConfig now mirrors the renderer's connect: after the
status check it opens the WS URL (token/local) or a freshly minted ws-ticket
(OAuth) and confirms the upgrade is accepted and not immediately torn down by
a post-handshake auth rejection. Failures surface an actionable message instead
of a false-positive. The WS leg is skipped when the runtime lacks a global
WebSocket so it never fails spuriously.
Youssef's review caught a residual false-positive: resolveTestWsUrl
swallowed an OAuth ticket-mint failure and returned null, so the caller
skipped the WS probe and reported the remote test as reachable. But the
real boot path (resolveRemoteBackend) treats a mint failure as a hard
'session expired' auth error and refuses to connect — so an expired OAuth
session passed the test then failed boot, the exact false-positive this
PR exists to kill.

Extract resolveTestWsUrl into the electron-free connection-config.cjs
(injectable mintTicket) so it's unit-testable, and make OAuth mint
failure throw an actionable needsOauthLogin error instead of skipping.
Adds the three cases Youssef requested plus a mintTicket-required guard.
@teknium1
teknium1 requested a review from a team June 5, 2026 02:40
@github-actions

github-actions Bot commented Jun 5, 2026

Copy link
Copy Markdown
Contributor

🔎 Lint report: hermes/hermes-2173cae3 vs origin/main

ruff

Total: 0 on HEAD, 0 on base (➖ 0)

🆕 New issues: none

✅ Fixed issues: none

Unchanged: 0 pre-existing issues carried over.

ty (type checker)

Total: 9850 on HEAD, 9850 on base (➖ 0)

🆕 New issues: none

✅ Fixed issues: none

Unchanged: 5107 pre-existing issues carried over.

Diagnostics are surfaced as warnings — this check never fails the build.

@teknium1
teknium1 merged commit bcb024a into main Jun 5, 2026
20 checks passed
@teknium1
teknium1 deleted the hermes/hermes-2173cae3 branch June 5, 2026 02:49
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.

2 participants