fix(cli): never reap serve processes owned by a valid backend.lock.json

Production incident: the orphan reap killed a legitimate SSH remote backend
started by another client machine. Its process sat at ppid 1 with the same
cmdline shape as a genuine orphan, and the exclusion list only covered THIS
app instance's children — ownership by OTHER clients was invisible.

The reap now treats every backend.lock.json under ~/.hermes/desktop-ssh/*/
as an ownership claim: lock payloads are schema-validated (mirroring
remote-lifecycle.ts) and their PIDs are excluded both before the scan and
re-checked after it (defense in depth against a lock written mid-scan).

Regression tests cover the exact incident shape: a lock-owned PID and a
genuine orphan with identical process shapes — only the orphan is reaped.

Also: fold the new single-field `runtime` config category into `agent`
(_CATEGORY_MERGE) and fix an env leak in the serve-startup test
(HERMES_SERVE_HEADLESS restored via monkeypatch) so the combined suites
run green in any order.
This commit is contained in:
Leon Phull
2026-08-05 19:34:25 +02:00
committed by Teknium
parent 585cee1a42
commit 888624ae61
4 changed files with 347 additions and 0 deletions
+7
View File
@@ -206,6 +206,13 @@ def test_serve_startup_applies_limit_before_web_server(monkeypatch):
import hermes_cli.plugins
import hermes_cli.web_server
# cmd_dashboard(headless_backend=True) exports HERMES_SERVE_HEADLESS=1 into
# this process's environment (main.py serve path). Touch the key through
# monkeypatch FIRST so teardown restores the pre-test state — otherwise the
# leaked flag flips later web-server tests (mount_spa) into the headless
# 404 path.
monkeypatch.setenv("HERMES_SERVE_HEADLESS", "0")
calls: list[str] = []
monkeypatch.setattr(
resource_limits,