hermes - ✅(Solved) Fix [Bug]: systemd repair path skips linger enablement for user gateway service [1 pull requests, 1 participants]

Official PRs (…)
ON THIS PAGE

Recommended Tools

×6

Utilities matched from this issue’s tags and category — try them while you read without losing context.

GitHub issue graph ai analysis

Paste a GitHub issue URL. We fetch that issue, discover linked issues from bodies/comments/timeline, collect linked pull requests, and produce a structured English report.

The report is written in English Markdown for sharing and archival.

Helpful · Quick feedback

Loading…
GitHub stats
NousResearch/hermes-agent#12863Fetched 2026-04-20 12:16:38
View on GitHub
Comments
0
Participants
1
Timeline
2
Reactions
0
Participants
Timeline (top)
cross-referenced ×1referenced ×1

hermes gateway install repairs an outdated user systemd unit and returns before calling _ensure_linger_enabled(). On headless Linux, the repaired service can still stop at logout even though the command reports success.

Root Cause

hermes gateway install repairs an outdated user systemd unit and returns before calling _ensure_linger_enabled(). On headless Linux, the repaired service can still stop at logout even though the command reports success.

Fix Action

Fix / Workaround

Minimal reproduction

from pathlib import Path
from tempfile import TemporaryDirectory
from unittest.mock import patch
from hermes_cli import gateway as g

calls = []
with TemporaryDirectory() as td:
    unit = Path(td) / "hermes-gateway.service"
    unit.write_text("old", encoding="utf-8")
    with patch.object(g, "get_systemd_unit_path", return_value=unit), \
         patch.object(g, "systemd_unit_is_current", return_value=False), \
         patch.object(g, "refresh_systemd_unit_if_needed", side_effect=lambda system=False: calls.append("refresh")), \
         patch.object(g, "_run_systemctl", side_effect=lambda *a, **k: calls.append(("systemctl", a, k))), \
         patch.object(g, "_ensure_linger_enabled", side_effect=lambda: calls.append("linger")):
        g.systemd_install(force=False, system=False)

PR fix notes

PR #12989: fix(gateway): enable linger on systemd user-service repair path

Description (problem / solution / changelog)

Closes #12863.

Summary

  • The repair branch in systemd_install() returns as soon as it rewrites an outdated unit and re-runs systemctl enable, bypassing _ensure_linger_enabled(). On headless Linux the command reports success, but the repaired user service still stops at logout.
  • Call _ensure_linger_enabled() before the early return when the install is user-scoped, mirroring the fresh-install path.

What changed

  • hermes_cli/gateway.py: in the repair branch, call _ensure_linger_enabled() when system=False before returning.
  • tests/hermes_cli/test_gateway_linger.py: add two regression tests covering the repair path:
    • test_systemd_install_repair_path_calls_linger_helper — user scope must call the linger helper.
    • test_systemd_install_repair_path_system_scope_skips_linger — system scope must not call it.

Verification

Without the fix, the new user-scope test fails with assert [] == [True] (helper never invoked). With the fix, both new tests pass and the rest of the gateway suite is green:

uv run pytest tests/hermes_cli/test_gateway_linger.py tests/hermes_cli/test_gateway_service.py tests/hermes_cli/test_gateway.py
# 124 passed

Test plan

  • New regression tests pass locally.
  • Reverse-check: new repair-path user-scope test fails on main without this fix.
  • Full test_gateway_linger.py, test_gateway_service.py, and test_gateway.py pass.

Changed files

  • hermes_cli/gateway.py (modified, +2/-0)
  • tests/hermes_cli/test_gateway_linger.py (modified, +64/-0)

Code Example

from pathlib import Path
from tempfile import TemporaryDirectory
from unittest.mock import patch
from hermes_cli import gateway as g

calls = []
with TemporaryDirectory() as td:
    unit = Path(td) / "hermes-gateway.service"
    unit.write_text("old", encoding="utf-8")
    with patch.object(g, "get_systemd_unit_path", return_value=unit), \
         patch.object(g, "systemd_unit_is_current", return_value=False), \
         patch.object(g, "refresh_systemd_unit_if_needed", side_effect=lambda system=False: calls.append("refresh")), \
         patch.object(g, "_run_systemctl", side_effect=lambda *a, **k: calls.append(("systemctl", a, k))), \
         patch.object(g, "_ensure_linger_enabled", side_effect=lambda: calls.append("linger")):
        g.systemd_install(force=False, system=False)

print(calls)
# Actual: ['refresh', ('systemctl', ...)]
# Missing: 'linger'
RAW_BUFFERClick to expand / collapse

Summary

hermes gateway install repairs an outdated user systemd unit and returns before calling _ensure_linger_enabled(). On headless Linux, the repaired service can still stop at logout even though the command reports success.

Affected code

  • hermes_cli/gateway.py:1049-1055
  • hermes_cli/gateway.py:1080-1081
  • coverage gap: tests/hermes_cli/test_gateway_service.py:16-37, tests/hermes_cli/test_gateway_linger.py:101-125

Why this is a bug

The normal user-service install path enables linger after writing the unit, but the stale-unit repair path exits early:

  • outdated unit detected
  • refresh_systemd_unit_if_needed() runs
  • systemctl enable runs
  • function returns

That skips the later else: _ensure_linger_enabled() block entirely.

Minimal reproduction

from pathlib import Path
from tempfile import TemporaryDirectory
from unittest.mock import patch
from hermes_cli import gateway as g

calls = []
with TemporaryDirectory() as td:
    unit = Path(td) / "hermes-gateway.service"
    unit.write_text("old", encoding="utf-8")
    with patch.object(g, "get_systemd_unit_path", return_value=unit), \
         patch.object(g, "systemd_unit_is_current", return_value=False), \
         patch.object(g, "refresh_systemd_unit_if_needed", side_effect=lambda system=False: calls.append("refresh")), \
         patch.object(g, "_run_systemctl", side_effect=lambda *a, **k: calls.append(("systemctl", a, k))), \
         patch.object(g, "_ensure_linger_enabled", side_effect=lambda: calls.append("linger")):
        g.systemd_install(force=False, system=False)

print(calls)
# Actual: ['refresh', ('systemctl', ...)]
# Missing: 'linger'

Expected behavior

  • Repairing an outdated user unit should preserve the same post-install guarantees as a fresh install.
  • _ensure_linger_enabled() should still run for user-scope installs.

Actual behavior

  • The repair path reports success but never enables linger.

Suggested investigation

  • Move the linger step into the outdated-unit repair path, or refactor both install flows through a shared post-install routine.
  • Add a regression test that combines the stale-unit path with the linger helper expectation.

extent analysis

TL;DR

Move the _ensure_linger_enabled() call into the outdated-unit repair path to ensure linger is enabled after repairing an outdated user systemd unit.

Guidance

  • Investigate refactoring both install flows through a shared post-install routine to avoid code duplication and ensure consistency.
  • Move the _ensure_linger_enabled() call to after the refresh_systemd_unit_if_needed() call in the hermes_cli/gateway.py file to ensure linger is enabled after repairing an outdated unit.
  • Add a regression test to tests/hermes_cli/test_gateway_service.py and tests/hermes_cli/test_gateway_linger.py to cover the stale-unit path with the linger helper expectation.
  • Verify the fix by running the minimal reproduction code and checking that the calls list includes the 'linger' entry.

Example

# hermes_cli/gateway.py
if outdated_unit_detected:
    refresh_systemd_unit_if_needed()
    _ensure_linger_enabled()  # Move this call here

Notes

The current implementation has a coverage gap in the tests, which should be addressed to ensure the fix is properly tested. The suggested investigation provides two possible solutions, and the chosen approach should be thoroughly tested.

Recommendation

Apply workaround: Move the _ensure_linger_enabled() call into the outdated-unit repair path, as this is a more targeted fix that addresses the specific issue without introducing significant changes to the codebase.

Vote matrix · Quick signals

Works
Did the solution work? Tap to confirm.
Easy Fix
Was it a quick fix?
Time Saver
Did it save you time?
Blocking
Was it severely blocking?
Common Issue
Are others likely hitting this too?
Flaky / Intermittent
Is it intermittent?
Verified / Reproducible
Can you reproduce it reliably?
Loading…

FAQ

Expected behavior

  • Repairing an outdated user unit should preserve the same post-install guarantees as a fresh install.
  • _ensure_linger_enabled() should still run for user-scope installs.

Still need to ship something?

×6

Another batch ranked right after the header list — different links, same matching logic.

Back to top recommendations

TRENDING

hermes - ✅(Solved) Fix [Bug]: systemd repair path skips linger enablement for user gateway service [1 pull requests, 1 participants]