fix(dashboard): stopped gateway no longer reports a dead process's platform error

gateway_state.json preserves per-platform entries across restarts, so a gateway
that once ran without TELEGRAM_BOT_TOKEN and then stopped kept reporting
'fatal / No bot token configured' on the Channels/Messaging pages even after the
user saved a token — the Desktop showed 'Saved' on both fields next to the error.
Only a live gateway's verdict describes current config; when no gateway is running
the platform reads gateway_stopped with no error.
This commit is contained in:
Teknium
2026-09-10 01:39:20 -07:00
parent 2bbb279c18
commit e1f1c8a935
2 changed files with 61 additions and 0 deletions

View File

@@ -214,6 +214,12 @@ def _messaging_platform_payload(
pid_probe=get_running_pid_cached, runtime_reader=read_runtime_status,
runtime_pid_probe=get_runtime_status_running_pid,
).running
if not gateway_running:
# gateway_state.json outlives its writer and keeps per-platform entries across
# restarts, so a stopped gateway that once ran WITHOUT credentials still says
# "fatal / No bot token configured" after the user saved a token. Only a live
# process's verdict describes the current config; a dead one's is history.
runtime_platform = {}
def env_value(key: str) -> str:
# Profile-scoped: judge only the profile's own .env — the dashboard process's

View File

@@ -0,0 +1,55 @@
"""A stopped gateway's per-platform verdict is history, not current state.
``gateway_state.json`` preserves platform entries across restarts, so a gateway that once ran
WITHOUT a Telegram token and then stopped leaves ``fatal / No bot token configured`` behind. The
Channels payload must not repeat that after the user saved credentials: with no live gateway the
platform reads ``gateway_stopped`` and carries no error (Desktop Messaging page report).
"""
import json
import pytest
_VALID_BOT_TOKEN = "123456789:ABCDEFGHIJKLMNOPQRSTUVWXYZ_1234"
@pytest.fixture
def client(monkeypatch, _isolate_hermes_home):
try:
from starlette.testclient import TestClient
except ImportError:
pytest.skip("fastapi/starlette not installed")
import hermes_state
from hermes_constants import get_hermes_home
from hermes_cli.web_server import app, _SESSION_HEADER_NAME, _SESSION_TOKEN
home = get_hermes_home()
monkeypatch.setattr(hermes_state, "DEFAULT_DB_PATH", home / "state.db")
monkeypatch.delenv("TELEGRAM_BOT_TOKEN", raising=False)
(home / ".env").write_text(f"TELEGRAM_BOT_TOKEN={_VALID_BOT_TOKEN}\nTELEGRAM_ALLOWED_USERS=42\n", encoding="utf-8")
(home / "config.yaml").write_text("platforms:\n telegram:\n enabled: true\n", encoding="utf-8")
(home / "gateway_state.json").write_text(json.dumps({
"kind": "gateway", "pid": 999_999_999, "start_time": 1.0, "gateway_state": "stopped",
"exit_reason": "shutdown", "updated_at": "2026-01-01T00:00:00+00:00",
"platforms": {"telegram": {
"state": "fatal", "error_code": "missing_credentials",
"error_message": "No bot token configured",
"writer_pid": 999_999_999, "writer_start_time": 1.0,
}},
}), encoding="utf-8")
c = TestClient(app)
c.headers[_SESSION_HEADER_NAME] = _SESSION_TOKEN
return c
def test_stopped_gateway_does_not_report_stale_platform_error(client):
payload = client.get("/api/messaging/platforms").json()
telegram = next(p for p in payload["platforms"] if p["id"] == "telegram")
assert telegram["configured"] is True
assert telegram["gateway_running"] is False
# The saved token is current; the dead gateway's "no token" verdict is not.
assert telegram["state"] == "gateway_stopped"
assert telegram["error_code"] is None
assert telegram["error_message"] is None