mirror of
https://github.com/NousResearch/hermes-agent.git
synced 2026-04-25 00:51:20 +00:00
fix(gateway): quote systemd service paths to handle spaces
This commit is contained in:
parent
ff9752410a
commit
d75278e26f
2 changed files with 39 additions and 4 deletions
|
|
@ -1176,6 +1176,14 @@ def _hermes_home_for_target_user(target_home_dir: str) -> str:
|
|||
return str(current_hermes)
|
||||
|
||||
|
||||
def _systemd_quote_arg(value: str) -> str:
|
||||
"""Quote a systemd command/path argument only when needed."""
|
||||
text = str(value)
|
||||
if text and not any(ch.isspace() for ch in text) and '"' not in text and "\\" not in text:
|
||||
return text
|
||||
return '"' + text.replace("\\", "\\\\").replace('"', '\\"') + '"'
|
||||
|
||||
|
||||
def generate_systemd_unit(system: bool = False, run_as_user: str | None = None) -> str:
|
||||
python_path = get_python_path()
|
||||
working_dir = str(PROJECT_ROOT)
|
||||
|
|
@ -1210,6 +1218,11 @@ def generate_systemd_unit(system: bool = False, run_as_user: str | None = None)
|
|||
path_entries.extend(_build_user_local_paths(Path(home_dir), path_entries))
|
||||
path_entries.extend(common_bin_paths)
|
||||
sane_path = ":".join(path_entries)
|
||||
profile_suffix = f" {profile_arg}" if profile_arg else ""
|
||||
exec_start = (
|
||||
f"{_systemd_quote_arg(python_path)} -m hermes_cli.main"
|
||||
f"{profile_suffix} gateway run --replace"
|
||||
)
|
||||
return f"""[Unit]
|
||||
Description={SERVICE_DESCRIPTION}
|
||||
After=network-online.target
|
||||
|
|
@ -1221,8 +1234,8 @@ StartLimitBurst=5
|
|||
Type=simple
|
||||
User={username}
|
||||
Group={group_name}
|
||||
ExecStart={python_path} -m hermes_cli.main{f" {profile_arg}" if profile_arg else ""} gateway run --replace
|
||||
WorkingDirectory={working_dir}
|
||||
ExecStart={exec_start}
|
||||
WorkingDirectory={_systemd_quote_arg(working_dir)}
|
||||
Environment="HOME={home_dir}"
|
||||
Environment="USER={username}"
|
||||
Environment="LOGNAME={username}"
|
||||
|
|
@ -1248,6 +1261,11 @@ WantedBy=multi-user.target
|
|||
path_entries.extend(_build_user_local_paths(Path.home(), path_entries))
|
||||
path_entries.extend(common_bin_paths)
|
||||
sane_path = ":".join(path_entries)
|
||||
profile_suffix = f" {profile_arg}" if profile_arg else ""
|
||||
exec_start = (
|
||||
f"{_systemd_quote_arg(python_path)} -m hermes_cli.main"
|
||||
f"{profile_suffix} gateway run --replace"
|
||||
)
|
||||
return f"""[Unit]
|
||||
Description={SERVICE_DESCRIPTION}
|
||||
After=network.target
|
||||
|
|
@ -1256,8 +1274,8 @@ StartLimitBurst=5
|
|||
|
||||
[Service]
|
||||
Type=simple
|
||||
ExecStart={python_path} -m hermes_cli.main{f" {profile_arg}" if profile_arg else ""} gateway run --replace
|
||||
WorkingDirectory={working_dir}
|
||||
ExecStart={exec_start}
|
||||
WorkingDirectory={_systemd_quote_arg(working_dir)}
|
||||
Environment="PATH={sane_path}"
|
||||
Environment="VIRTUAL_ENV={venv_dir}"
|
||||
Environment="HERMES_HOME={hermes_home}"
|
||||
|
|
|
|||
|
|
@ -100,6 +100,23 @@ class TestGeneratedSystemdUnits:
|
|||
|
||||
assert "/home/test/.nvm/versions/node/v24.14.0/bin" in unit
|
||||
|
||||
def test_user_unit_quotes_execstart_and_workdir_paths_with_spaces(self, tmp_path, monkeypatch):
|
||||
project_root = tmp_path / "Hermes Agent"
|
||||
venv_dir = project_root / "venv"
|
||||
python_path = venv_dir / "bin" / "python"
|
||||
python_path.parent.mkdir(parents=True)
|
||||
python_path.write_text("", encoding="utf-8")
|
||||
|
||||
monkeypatch.setattr(gateway_cli, "PROJECT_ROOT", project_root)
|
||||
monkeypatch.setattr(gateway_cli, "_detect_venv_dir", lambda: venv_dir)
|
||||
monkeypatch.setattr(gateway_cli, "get_python_path", lambda: str(python_path))
|
||||
monkeypatch.setattr(gateway_cli.shutil, "which", lambda cmd: None)
|
||||
|
||||
unit = gateway_cli.generate_systemd_unit(system=False)
|
||||
|
||||
assert f'ExecStart="{python_path}" -m hermes_cli.main gateway run --replace' in unit
|
||||
assert f'WorkingDirectory="{project_root}"' in unit
|
||||
|
||||
def test_system_unit_avoids_recursive_execstop_and_uses_extended_stop_timeout(self):
|
||||
unit = gateway_cli.generate_systemd_unit(system=True)
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue