Files
hermes-agent/tests/hermes_cli/test_dashboard_initial_profile_bootstrap.py
liguoyu a8cccc22f2 fix(dashboard): profile-less chat deep links inherit the launcher's preselected profile
`hermes dashboard` from a named profile re-execs as `-p default dashboard --open-profile P`,
but `--open-profile` only reached the one URL `_maybe_open_browser()` opened. A `/chat?resume=<id>`
deep link without `?profile=` initialised `ProfileProvider` with the empty (launch) scope, so the
embedded chat ran in the default profile — no MCP servers, wrong model/skills — while the switcher
showed P. No error, no indication.

The server now records `initial_profile` on `app.state` and injects it into the SPA bootstrap as
`window.__HERMES_INITIAL_PROFILE__` (escaped for the script context); the Vite dev proxy forwards
it. `ProfileProvider` uses it only when the URL carries no `profile` param: an explicit
`?profile=` (including an explicit empty one) still wins, and the sticky-active-profile alignment
no longer replaces a launch-preselected scope.

Closes #73085. Salvage of #73260 (cherry-pick of 99e341cdef0 resolved onto the split
web_server_dashboard.py; start_server assertion dropped as a change-detector).
2026-09-18 15:12:27 -07:00

48 lines
1.5 KiB
Python

from fastapi import FastAPI
from starlette.testclient import TestClient
from hermes_cli import web_server
def test_spa_bootstrap_includes_dashboard_initial_profile(tmp_path, monkeypatch):
dist = tmp_path / "web_dist"
(dist / "assets").mkdir(parents=True)
(dist / "index.html").write_text(
"<html><head></head><body>Dashboard</body></html>",
encoding="utf-8",
)
monkeypatch.setattr(web_server, "WEB_DIST", dist)
monkeypatch.delenv("HERMES_SERVE_HEADLESS", raising=False)
app = FastAPI()
app.state.initial_profile = "worker_x"
web_server.mount_spa(app)
response = TestClient(app).get("/chat?resume=session-1")
assert response.status_code == 200
assert 'window.__HERMES_INITIAL_PROFILE__="worker_x";' in response.text
def test_spa_bootstrap_escapes_initial_profile_for_script_context(
tmp_path, monkeypatch
):
dist = tmp_path / "web_dist"
(dist / "assets").mkdir(parents=True)
(dist / "index.html").write_text(
"<html><head></head><body>Dashboard</body></html>",
encoding="utf-8",
)
monkeypatch.setattr(web_server, "WEB_DIST", dist)
monkeypatch.delenv("HERMES_SERVE_HEADLESS", raising=False)
app = FastAPI()
app.state.initial_profile = "bad</script><script>alert(1)</script>"
web_server.mount_spa(app)
response = TestClient(app).get("/chat")
assert response.status_code == 200
assert "bad<\\/script><script>alert(1)<\\/script>" in response.text
assert "bad</script><script>alert(1)</script>" not in response.text