This commit is contained in:
LeonSGP 2026-04-24 17:27:18 -05:00 committed by GitHub
commit 6acfc5d31b
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 60 additions and 0 deletions

View file

@ -1507,6 +1507,38 @@ def _hermes_home_for_target_user(target_home_dir: str) -> str:
return str(current_hermes)
def _login_shell_hermes_home(username: str) -> str | None:
"""Best-effort lookup of ``HERMES_HOME`` from ``username``'s login shell.
This helps ``sudo hermes gateway install --system`` preserve a custom
``HERMES_HOME`` that exists in the target user's login environment even
when sudo sanitizes it out of the root process environment.
"""
username = (username or "").strip()
if not username or username == "root":
return None
try:
result = subprocess.run(
["su", "-l", username, "-s", "/bin/sh", "-c", 'printf %s "$HERMES_HOME"'],
capture_output=True,
text=True,
check=False,
timeout=10,
)
except (FileNotFoundError, subprocess.TimeoutExpired, PermissionError, OSError):
return None
if result.returncode != 0:
return None
value = (result.stdout or "").strip()
if not value:
return None
return str(Path(value).expanduser())
def generate_systemd_unit(system: bool = False, run_as_user: str | None = None) -> str:
python_path = get_python_path()
working_dir = str(PROJECT_ROOT)
@ -1535,6 +1567,13 @@ def generate_systemd_unit(system: bool = False, run_as_user: str | None = None)
if system:
username, group_name, home_dir = _system_service_identity(run_as_user)
hermes_home = _hermes_home_for_target_user(home_dir)
if (
not os.getenv("HERMES_HOME", "").strip()
and hermes_home == str(Path(home_dir) / ".hermes")
):
login_shell_home = _login_shell_hermes_home(username)
if login_shell_home:
hermes_home = login_shell_home
profile_arg = _profile_arg(hermes_home)
# Remap all paths that may resolve under the calling user's home
# (e.g. /root/) to the target user's home so the service can

View file

@ -891,6 +891,27 @@ class TestSystemUnitHermesHome:
assert 'HERMES_HOME=/opt/hermes-shared' in unit
def test_system_unit_uses_target_login_shell_hermes_home_when_sudo_drops_env(self, monkeypatch):
monkeypatch.setattr(Path, "home", staticmethod(lambda: Path("/root")))
monkeypatch.delenv("HERMES_HOME", raising=False)
monkeypatch.setattr(
gateway_cli, "_system_service_identity",
lambda run_as_user=None: ("alice", "alice", "/home/alice"),
)
monkeypatch.setattr(
gateway_cli, "_build_user_local_paths",
lambda home, existing: [],
)
monkeypatch.setattr(
gateway_cli,
"_login_shell_hermes_home",
lambda username: "/srv/hermes-shared",
)
unit = gateway_cli.generate_systemd_unit(system=True, run_as_user="alice")
assert 'HERMES_HOME=/srv/hermes-shared' in unit
def test_user_unit_unaffected_by_change(self):
# User-scope units should still use the calling user's HERMES_HOME
unit = gateway_cli.generate_systemd_unit(system=False)