Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions hermes_cli/gateway.py
Original file line number Diff line number Diff line change
Expand Up @@ -1664,6 +1664,7 @@ def generate_systemd_unit(system: bool = False, run_as_user: str | None = None)
Group={group_name}
ExecStart={python_path} -m hermes_cli.main{f" {profile_arg}" if profile_arg else ""} gateway run --replace
WorkingDirectory={working_dir}
EnvironmentFile=-{hermes_home}/.env
Environment="HOME={home_dir}"
Environment="USER={username}"
Environment="LOGNAME={username}"
Expand Down Expand Up @@ -1699,6 +1700,7 @@ def generate_systemd_unit(system: bool = False, run_as_user: str | None = None)
Type=simple
ExecStart={python_path} -m hermes_cli.main{f" {profile_arg}" if profile_arg else ""} gateway run --replace
WorkingDirectory={working_dir}
EnvironmentFile=-{hermes_home}/.env
Environment="PATH={sane_path}"
Environment="VIRTUAL_ENV={venv_dir}"
Environment="HERMES_HOME={hermes_home}"
Expand Down
35 changes: 35 additions & 0 deletions tests/hermes_cli/test_gateway_service.py
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,41 @@ def test_system_unit_avoids_recursive_execstop_and_uses_extended_stop_timeout(se
assert "TimeoutStopSec=90" in unit
assert "WantedBy=multi-user.target" in unit

def test_user_unit_loads_hermes_env_file(self):
# The gateway runs under systemd with a clean environment, so it must
# explicitly load ~/.hermes/.env to pick up API keys (HINDSIGHT_API_URL,
# OPENAI_API_KEY, TELEGRAM_BOT_TOKEN, ...). Without this, plugins that
# require env vars silently skip registration (see PR #2768 / #2765),
# tools fail auth at runtime, and the gateway falls back to a minimal
# toolset. The leading "-" makes the directive optional so a missing
# file does not fail unit start.
unit = gateway_cli.generate_systemd_unit(system=False)

assert "EnvironmentFile=-" in unit
assert "/.env" in unit
# Must reference the same HERMES_HOME used elsewhere in the unit so
# profile-aware paths (e.g. ~/.hermes-dev/.env) resolve correctly.
for line in unit.splitlines():
if line.startswith("EnvironmentFile=-"):
env_file_path = line.split("=-", 1)[1]
assert env_file_path.endswith("/.env")
break
else:
raise AssertionError("EnvironmentFile=- directive not found")

def test_system_unit_loads_hermes_env_file(self):
unit = gateway_cli.generate_systemd_unit(system=True)

assert "EnvironmentFile=-" in unit
assert "/.env" in unit
for line in unit.splitlines():
if line.startswith("EnvironmentFile=-"):
env_file_path = line.split("=-", 1)[1]
assert env_file_path.endswith("/.env")
break
else:
raise AssertionError("EnvironmentFile=- directive not found")


class TestGatewayStopCleanup:
def test_stop_only_kills_current_profile_by_default(self, tmp_path, monkeypatch):
Expand Down