feat(dashboard): add hardened API-only remote proxy - #66498
feat(dashboard): add hardened API-only remote proxy#66498joelbrilliant wants to merge 2 commits into
Conversation
4fcd32a to
ebec5bc
Compare
teknium1
left a comment
There was a problem hiding this comment.
Thanks for addressing a real remote-dashboard boundary problem; the API-only and lifecycle-deny direction is useful. There are blocking integration issues.
Problems
hermes_cli/remote_proxy.py:118returns 404 for every non-/apipath. Desktop OAuth intentionally opens/login(apps/desktop/electron/main.ts:5119-5121,5255) and completes through/auth/callback, so the documented sign-in flow cannot work through this proxy.- The documented loopback
hermes servetopology does not engage the current OAuth gate: loopback is explicitly a no-op inhermes_cli/dashboard_auth/middleware.py:13-15, whilestart_server()derivesauth_requiredfrom the bind host (hermes_cli/web_server.py:17856-17879). hermes_cli/remote_proxy.py:206collapses response headers into a dict. Dashboard auth emits multipleSet-Cookieheaders (hermes_cli/dashboard_auth/cookies.py:191-212), so cookie-based auth cannot be forwarded reliably.
Suggested changes
- Design an explicit authenticated loopback-upstream mode, then allow only the narrow auth-bootstrap routes needed by Desktop—without serving the SPA/static surface.
- Preserve repeated response headers and add an end-to-end OAuth/login + WS-ticket proxy test.
- Audit denied WebSocket upgrades as well as HTTP denies.
This is an automated hermes-sweeper review.
…ote access The desktop's remote-gateway mode expects "an already-running Hermes backend ... behind a trusted proxy", but the trusted proxy has always been DIY. This adds it as a first-class command, ported from a proxy that has been running in production in front of a Cloudflare tunnel since early July. hermes dashboard proxy forwards only /api/* (HTTP + WebSocket) to the loopback backend, so the SPA HTML — which inlines the dashboard session token — never crosses the tunnel. Machine-lifecycle routes are denied by default with an audit log: - /api/hermes/update (a remotely triggered self-update restarts backends with nobody at the machine; the read-only update/check stays reachable) - /api/gateway/start|stop|restart|drain - /api/ops/backup + backup/download (single-request exfiltration of the whole HERMES_HOME), ops/import + import-upload, ops/config-migrate --allow-route re-enables a denied route per explicit operator decision; --deny-route adds more. Denials are 403 + one audit line in logs/remote-proxy-denied.log. Auth is deliberately untouched: every forwarded request still hits the backend's session-token/OAuth checks. Built on the existing core stack (FastAPI/uvicorn, httpx, websockets). Docs: user-guide/remote-access.md covers the loopback + tunnel setup (Cloudflare, Tailscale, SSH -R), the deny table, and policy overrides. Tests: 29 covering route classification, deny/allow overrides, hop-by-hop header stripping, forwarding with query/header passthrough, 403 + audit on denied routes, SPA/static 404s, and WS policy close. Verified live against a running backend: forwarded routes return the upstream's own 401 without a session, denied routes 403 without ever reaching the backend. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Address hermes-sweeper review on NousResearch#66498: - Document Desktop token mode as the supported API-only topology and keep browser OAuth routes closed. - Preserve repeated upstream response headers and audit denied WebSocket upgrades. - Add a production-shaped regression against the real loopback backend token gate. - Wire the proxy handler into existing parser test harnesses to fix the seven CI failures.
ebec5bc to
5a41613
Compare
hermes dashboard proxy — hardened API-only remote access|
Thanks for the review. I rechecked the runtime auth path and found an important distinction: loopback disables the OAuth and password gate, but Addressed in the pushed commits:
Verified after rebasing onto current Out of scope for this PR: supporting browser OAuth or the browser dashboard through the API-only proxy. That needs a separate auth-bootstrap design rather than partially exposing login routes here. |
Problem
The desktop remote gateway expects a trusted proxy, but tunnelling the whole dashboard server exposes more of the host than remote Desktop access needs.
Related remote access demand appears in #9269, #8951, #34390, #37119, #39553, and #53839.
Security model
This is an API-only topology for Desktop token authentication. The loopback backend remains the authentication authority for every protected HTTP and WebSocket route. Configure a fixed
HERMES_DASHBOARD_SESSION_TOKENon the backend and enter the same value in Desktop token mode.The proxy does not forward
/login,/auth/callback, the SPA, or static assets. Browser OAuth and the browser dashboard are intentionally unsupported through this surface. Use the normal authenticated non-loopback dashboard deployment when those are required.What this adds
hermes dashboard proxycommand that forwards only/api/*HTTP and WebSocket traffic to the loopback backend.logs/remote-proxy-denied.log.Set-Cookiefields.Review follow-up
The hermes-sweeper findings are addressed in the follow-up commit:
Validation
scripts/run_tests.shacross the proxy, HTTP auth, WebSocket auth, admin endpoint, dashboard parser, and serve parser suitesgit diff --checkpassed