mirror of
https://github.com/NousResearch/hermes-agent.git
synced 2026-05-31 06:51:29 +00:00
The s6 dashboard run script flipped `--insecure` on whenever
`HERMES_DASHBOARD_HOST` was anything other than 127.0.0.1 / localhost.
That comment ("the dashboard refuses otherwise") predates the OAuth
auth gate: back when it was written, `start_server` would SystemExit
on any non-loopback bind, so the run script's `--insecure` was the
only way to make in-container deployments work at all.
The gate has since been replaced by `should_require_auth(host,
allow_public)`, which engages the OAuth flow when a
`DashboardAuthProvider` is registered (the bundled `dashboard_auth/nous`
provider auto-registers on `HERMES_DASHBOARD_OAUTH_CLIENT_ID`) and
fails closed with a specific operator-facing error when none is. The
host-derived `--insecure` ran upstream of all that and silently
disabled the gate on every container-deployed dashboard.
Most visible under the portal's wildcard-subdomain rollout: every Fly
machine binds 0.0.0.0 so the edge can reach Flycast, every machine
boots with the correct `HERMES_DASHBOARD_OAUTH_CLIENT_ID`, the nous
provider registers — and `/api/status` still returns
`{"auth_required": false, "auth_providers": ["nous"]}` because the
run script disabled the gate before `start_server` ever saw the
request. The dashboard SPA was served to anyone, no `/login` redirect,
no OAuth challenge.
Fix: derive `--insecure` from an explicit opt-in env var,
`HERMES_DASHBOARD_INSECURE` (truthy values matching the rest of the
s6 boolean envs: 1, true, TRUE, True, yes, YES, Yes). Operators on
trusted LANs behind a reverse proxy without the OAuth contract
(the existing `docker-compose.windows.yml` use case) opt in
explicitly; portal-managed agent deployments leave it unset and let
the gate engage.
`docker-compose.windows.yml` already passes `--insecure` on the
`command:` array directly (line 38), so it doesn't depend on the s6
auto-injection. No compose-file change required.
Tests:
* `tests/test_docker_home_override_scripts.py` — extends the existing
static-text guard with a regression assertion that the legacy
host-derived case-statement is gone and the new env-var opt-in is
present (locks against accidental revert).
* `tests/docker/test_dashboard.py` — adds two Docker-in-Docker tests
exercising the actual `/api/status` round-trip:
- 0.0.0.0 bind + `HERMES_DASHBOARD_OAUTH_CLIENT_ID` → gate engaged
- 0.0.0.0 bind + `HERMES_DASHBOARD_INSECURE=1` → gate disabled
Docs:
* `website/docs/user-guide/docker.md` + zh-Hans i18n — adds the new
env var to the table, replaces the stale prose ("the entrypoint
no longer auto-enables insecure mode" — which until this PR was
flat-out wrong) with an accurate description of the gate's
trigger conditions and the explicit opt-out.
shellcheck clean. Python static-text test passes locally. Behavioural
test will run against any future image build (CI's Docker harness).
52 lines
2.2 KiB
Text
Executable file
52 lines
2.2 KiB
Text
Executable file
#!/command/with-contenv sh
|
|
# shellcheck shell=sh
|
|
# Dashboard service. Always declared so s6 has a supervised slot; if
|
|
# HERMES_DASHBOARD isn't truthy the run script exits cleanly and the
|
|
# companion finish script returns 125 (s6's "permanent failure, do
|
|
# not restart" marker), so s6-svstat reports the slot as down. See
|
|
# also docker/s6-rc.d/dashboard/finish.
|
|
|
|
case "${HERMES_DASHBOARD:-}" in
|
|
1|true|TRUE|True|yes|YES|Yes) ;;
|
|
*)
|
|
# Exit 0; the finish script will exit 125 → s6-supervise won't
|
|
# restart us and the slot reports down. Using a clean exit
|
|
# (rather than `exec sleep infinity`) means s6-svstat reflects
|
|
# reality: when HERMES_DASHBOARD is unset, the service is NOT
|
|
# running, just supervised-with-permanent-failure. See PR
|
|
# #30136 review item I3.
|
|
exit 0
|
|
;;
|
|
esac
|
|
|
|
# with-contenv repopulates HOME from /init as /root. Reset it before
|
|
# dropping privileges so HOME-anchored state lands under /opt/data.
|
|
export HOME=/opt/data
|
|
|
|
cd /opt/data
|
|
# shellcheck disable=SC1091
|
|
. /opt/hermes/.venv/bin/activate
|
|
|
|
dash_host="${HERMES_DASHBOARD_HOST:-0.0.0.0}"
|
|
dash_port="${HERMES_DASHBOARD_PORT:-9119}"
|
|
|
|
# `--insecure` is opt-in via HERMES_DASHBOARD_INSECURE. The dashboard's
|
|
# OAuth auth gate engages automatically on non-loopback binds when a
|
|
# DashboardAuthProvider is registered (e.g. the bundled dashboard_auth/nous
|
|
# provider, which auto-registers when HERMES_DASHBOARD_OAUTH_CLIENT_ID is
|
|
# set). If no provider is registered, start_server fails closed with a
|
|
# specific operator-facing error.
|
|
#
|
|
# This used to derive --insecure from the bind host ("anything non-loopback
|
|
# implies insecure"), but that predates the OAuth gate and silently
|
|
# disabled it on every container-deployed dashboard. The gate is now the
|
|
# authority; operators on trusted LANs / behind a reverse proxy without
|
|
# the OAuth contract opt in explicitly.
|
|
insecure=""
|
|
case "${HERMES_DASHBOARD_INSECURE:-}" in
|
|
1|true|TRUE|True|yes|YES|Yes) insecure="--insecure" ;;
|
|
esac
|
|
|
|
# shellcheck disable=SC2086 # word-splitting of $insecure is intentional
|
|
exec s6-setuidgid hermes hermes dashboard \
|
|
--host "$dash_host" --port "$dash_port" --no-open $insecure
|