diff --git a/hermes_cli/gateway.py b/hermes_cli/gateway.py index 78604b34e5..421180eb33 100644 --- a/hermes_cli/gateway.py +++ b/hermes_cli/gateway.py @@ -3234,9 +3234,12 @@ def systemd_install( else: print(f"Service already installed at: {unit_path}") print("Use --force to reinstall") + # Same post-install guarantee as a fresh install: a repaired user unit must survive logout too. configured_user = _read_systemd_user_from_unit(unit_path) if system else None if configured_user: _ensure_system_service_linger(configured_user) + elif not system: + _ensure_linger_enabled() return unit_path.parent.mkdir(parents=True, exist_ok=True) diff --git a/tests/hermes_cli/test_gateway_linger.py b/tests/hermes_cli/test_gateway_linger.py index 3182f87f74..7a70ef8b38 100644 --- a/tests/hermes_cli/test_gateway_linger.py +++ b/tests/hermes_cli/test_gateway_linger.py @@ -215,3 +215,25 @@ def test_existing_system_install_repairs_linger_for_configured_user(monkeypatch, gateway.systemd_install(system=True, run_as_user="alice") assert helper_calls == ["alice"] + + +@pytest.mark.parametrize("system", [False, True]) +def test_systemd_install_repair_path_keeps_linger_guarantee(monkeypatch, tmp_path, system): + """Repairing a stale unit used to return before the linger step, so an upgraded headless + user service died at logout (#12863). System scope never touches user linger.""" + unit_path = tmp_path / "hermes-gateway.service" + unit_path.write_text("old unit\n", encoding="utf-8") + monkeypatch.setattr(gateway, "get_systemd_unit_path", lambda system=False: unit_path) + monkeypatch.setattr(gateway, "systemd_unit_is_current", lambda system=False: False) + monkeypatch.setattr(gateway, "has_legacy_hermes_units", lambda: False) + monkeypatch.setattr(gateway, "_require_root_for_system_service", lambda _action: None) + monkeypatch.setattr(gateway, "_sync_hermes_home_from_systemd_unit", lambda system=False: None) + monkeypatch.setattr(gateway, "_read_systemd_user_from_unit", lambda path: None) + monkeypatch.setattr(gateway, "refresh_systemd_unit_if_needed", lambda system=False: None) + monkeypatch.setattr(gateway, "_run_systemctl", lambda *args, **kwargs: None) + helper_calls = [] + monkeypatch.setattr(gateway, "_ensure_linger_enabled", lambda: helper_calls.append(True)) + + gateway.systemd_install(force=False, system=system) + + assert helper_calls == ([] if system else [True])