fix: add /api/ws WebSocket endpoint to APIServerAdapter for remote TUI attach (hardened) - #32955
trevor-ai-assistant wants to merge 1 commit into
Conversation
…I attach The TUI frontend (HERMES_TUI_GATEWAY_URL) expects to connect to ws://host:port/api/ws?token=... but the APIServerAdapter (aiohttp) only registers HTTP routes — no WebSocket handler at /api/ws, causing HTTP 404 on remote TUI attach. This patch hardens the approach from PR NousResearch#32904 with security fixes: - Adds try/except import guard for tui_gateway.server and Transport - Registers GET /api/ws route on the aiohttp web.Application (only when tui_gateway is available) - Implements _handle_tui_ws with an _AiohttpWsTransport adapter that bridges aiohttp's WebSocketResponse to the Transport protocol so tui_gateway.server.dispatch() works over WebSocket - Authentication via ?token= query parameter using hmac.compare_digest (same API_SERVER_KEY as REST endpoints) - Defense-in-depth: refuses network-accessible connections without key at the endpoint level (in addition to existing startup guard) - Resource limits: heartbeat=30.0, autoping=True, max_msg_size=2MB - Sends gateway.ready event on connect, then runs JSON-RPC dispatch loop - Cleanly tears down transport binding on disconnect Closes NousResearch#32882
|
Closing this — the fix targets the wrong API surface.
The real bug behind #32882 is misleading documentation — The security analysis here was genuinely good — you correctly identified that #32904 would have left an unauthenticated RPC channel wide open. Thanks for the careful work; it just lands on a surface we don't want to expose this on. |
…emote-attach (#42162) The TUI docs presented HERMES_TUI_GATEWAY_URL + /api/ws as a supported 'attach the TUI to a standalone running gateway' workflow. It isn't. /api/ws exists only inside the dashboard's FastAPI server (hermes_cli/web_server.py), which spawns its own embedded TUI child and injects the var as an internal wiring detail. The OpenAI-compat API server (api_server platform) deliberately does not serve /api/ws, so the documented ws://host:port/api/ws workflow 404s — the cause of #32882 and the two PRs (#32904, #32955) that tried to add the route to the wrong surface. Rewrites the section in en + zh-Hans to describe the var accurately and point users at shared state.db / dashboard embedded chat for multi-surface session sharing.
…emote-attach (NousResearch#42162) The TUI docs presented HERMES_TUI_GATEWAY_URL + /api/ws as a supported 'attach the TUI to a standalone running gateway' workflow. It isn't. /api/ws exists only inside the dashboard's FastAPI server (hermes_cli/web_server.py), which spawns its own embedded TUI child and injects the var as an internal wiring detail. The OpenAI-compat API server (api_server platform) deliberately does not serve /api/ws, so the documented ws://host:port/api/ws workflow 404s — the cause of NousResearch#32882 and the two PRs (NousResearch#32904, NousResearch#32955) that tried to add the route to the wrong surface. Rewrites the section in en + zh-Hans to describe the var accurately and point users at shared state.db / dashboard embedded chat for multi-surface session sharing.
…emote-attach (#42162) The TUI docs presented HERMES_TUI_GATEWAY_URL + /api/ws as a supported 'attach the TUI to a standalone running gateway' workflow. It isn't. /api/ws exists only inside the dashboard's FastAPI server (hermes_cli/web_server.py), which spawns its own embedded TUI child and injects the var as an internal wiring detail. The OpenAI-compat API server (api_server platform) deliberately does not serve /api/ws, so the documented ws://host:port/api/ws workflow 404s — the cause of #32882 and the two PRs (#32904, #32955) that tried to add the route to the wrong surface. Rewrites the section in en + zh-Hans to describe the var accurately and point users at shared state.db / dashboard embedded chat for multi-surface session sharing.
…emote-attach (NousResearch#42162) The TUI docs presented HERMES_TUI_GATEWAY_URL + /api/ws as a supported 'attach the TUI to a standalone running gateway' workflow. It isn't. /api/ws exists only inside the dashboard's FastAPI server (hermes_cli/web_server.py), which spawns its own embedded TUI child and injects the var as an internal wiring detail. The OpenAI-compat API server (api_server platform) deliberately does not serve /api/ws, so the documented ws://host:port/api/ws workflow 404s — the cause of NousResearch#32882 and the two PRs (NousResearch#32904, NousResearch#32955) that tried to add the route to the wrong surface. Rewrites the section in en + zh-Hans to describe the var accurately and point users at shared state.db / dashboard embedded chat for multi-surface session sharing.
…emote-attach (NousResearch#42162) The TUI docs presented HERMES_TUI_GATEWAY_URL + /api/ws as a supported 'attach the TUI to a standalone running gateway' workflow. It isn't. /api/ws exists only inside the dashboard's FastAPI server (hermes_cli/web_server.py), which spawns its own embedded TUI child and injects the var as an internal wiring detail. The OpenAI-compat API server (api_server platform) deliberately does not serve /api/ws, so the documented ws://host:port/api/ws workflow 404s — the cause of NousResearch#32882 and the two PRs (NousResearch#32904, NousResearch#32955) that tried to add the route to the wrong surface. Rewrites the section in en + zh-Hans to describe the var accurately and point users at shared state.db / dashboard embedded chat for multi-surface session sharing.
…emote-attach (NousResearch#42162) The TUI docs presented HERMES_TUI_GATEWAY_URL + /api/ws as a supported 'attach the TUI to a standalone running gateway' workflow. It isn't. /api/ws exists only inside the dashboard's FastAPI server (hermes_cli/web_server.py), which spawns its own embedded TUI child and injects the var as an internal wiring detail. The OpenAI-compat API server (api_server platform) deliberately does not serve /api/ws, so the documented ws://host:port/api/ws workflow 404s — the cause of NousResearch#32882 and the two PRs (NousResearch#32904, NousResearch#32955) that tried to add the route to the wrong surface. Rewrites the section in en + zh-Hans to describe the var accurately and point users at shared state.db / dashboard embedded chat for multi-surface session sharing.
…emote-attach (NousResearch#42162) The TUI docs presented HERMES_TUI_GATEWAY_URL + /api/ws as a supported 'attach the TUI to a standalone running gateway' workflow. It isn't. /api/ws exists only inside the dashboard's FastAPI server (hermes_cli/web_server.py), which spawns its own embedded TUI child and injects the var as an internal wiring detail. The OpenAI-compat API server (api_server platform) deliberately does not serve /api/ws, so the documented ws://host:port/api/ws workflow 404s — the cause of NousResearch#32882 and the two PRs (NousResearch#32904, NousResearch#32955) that tried to add the route to the wrong surface. Rewrites the section in en + zh-Hans to describe the var accurately and point users at shared state.db / dashboard embedded chat for multi-surface session sharing.
…emote-attach (NousResearch#42162) The TUI docs presented HERMES_TUI_GATEWAY_URL + /api/ws as a supported 'attach the TUI to a standalone running gateway' workflow. It isn't. /api/ws exists only inside the dashboard's FastAPI server (hermes_cli/web_server.py), which spawns its own embedded TUI child and injects the var as an internal wiring detail. The OpenAI-compat API server (api_server platform) deliberately does not serve /api/ws, so the documented ws://host:port/api/ws workflow 404s — the cause of NousResearch#32882 and the two PRs (NousResearch#32904, NousResearch#32955) that tried to add the route to the wrong surface. Rewrites the section in en + zh-Hans to describe the var accurately and point users at shared state.db / dashboard embedded chat for multi-surface session sharing.
…emote-attach (NousResearch#42162) The TUI docs presented HERMES_TUI_GATEWAY_URL + /api/ws as a supported 'attach the TUI to a standalone running gateway' workflow. It isn't. /api/ws exists only inside the dashboard's FastAPI server (hermes_cli/web_server.py), which spawns its own embedded TUI child and injects the var as an internal wiring detail. The OpenAI-compat API server (api_server platform) deliberately does not serve /api/ws, so the documented ws://host:port/api/ws workflow 404s — the cause of NousResearch#32882 and the two PRs (NousResearch#32904, NousResearch#32955) that tried to add the route to the wrong surface. Rewrites the section in en + zh-Hans to describe the var accurately and point users at shared state.db / dashboard embedded chat for multi-surface session sharing.
…emote-attach (NousResearch#42162) The TUI docs presented HERMES_TUI_GATEWAY_URL + /api/ws as a supported 'attach the TUI to a standalone running gateway' workflow. It isn't. /api/ws exists only inside the dashboard's FastAPI server (hermes_cli/web_server.py), which spawns its own embedded TUI child and injects the var as an internal wiring detail. The OpenAI-compat API server (api_server platform) deliberately does not serve /api/ws, so the documented ws://host:port/api/ws workflow 404s — the cause of NousResearch#32882 and the two PRs (NousResearch#32904, NousResearch#32955) that tried to add the route to the wrong surface. Rewrites the section in en + zh-Hans to describe the var accurately and point users at shared state.db / dashboard embedded chat for multi-surface session sharing.
…emote-attach (NousResearch#42162) The TUI docs presented HERMES_TUI_GATEWAY_URL + /api/ws as a supported 'attach the TUI to a standalone running gateway' workflow. It isn't. /api/ws exists only inside the dashboard's FastAPI server (hermes_cli/web_server.py), which spawns its own embedded TUI child and injects the var as an internal wiring detail. The OpenAI-compat API server (api_server platform) deliberately does not serve /api/ws, so the documented ws://host:port/api/ws workflow 404s — the cause of NousResearch#32882 and the two PRs (NousResearch#32904, NousResearch#32955) that tried to add the route to the wrong surface. Rewrites the section in en + zh-Hans to describe the var accurately and point users at shared state.db / dashboard embedded chat for multi-surface session sharing.
Summary
This PR fixes Issue #32882: the documented
HERMES_TUI_GATEWAY_URLworkflow for attaching a local TUI to a remote gateway fails with HTTP 404 because the gateway'sAPIServerAdapter(aiohttp) never registers a WebSocket route at/api/ws. The route only exists in the separate FastAPI web dashboard server.Changes
gateway/platforms/api_server.pytui_gateway.serverandTransport(graceful degradation when TUI gateway is unavailable)GET /api/ws— registered only whenTUI_GATEWAY_AVAILABLEisTrue_handle_tui_ws— full WebSocket lifecycle handler with:?token=query parameter usinghmac.compare_digest(sameAPI_SERVER_KEYas REST endpoints)heartbeat=30.0,autoping=True,max_msg_size=2*1024*1024(2MB cap)_AiohttpWsTransportadapter — bridges aiohttp'sWebSocketResponseto thetui_gateway.Transportprotocol soserver.dispatch()works over WebSocketgateway.readyhandshake — TUI expects this before any RPCtui_gateway.ws.handle_wslogicfinallytests/gateway/test_api_server_ws.py(new)9 tests covering:
gateway.readyhandshakeTest Results
Security Hardening (vs. PR #32904)
This implementation supersedes PR #32904 with critical security fixes:
?token=viahmac.compare_digestmax_msg_sizeheartbeatautopingWithout authentication, PR #32904 would allow any network client to open a WebSocket and execute JSON-RPC commands (
shell.exec,cli.exec, etc.) on a gateway withAPI_SERVER_KEYconfigured — rendering the REST API auth useless while leaving the WS schiene wide open.Checklist
Related