fix(update): don't truncate cmdlines in the venv-blocker scan — it broke the gateway exemption
_detect_venv_python_processes() returned cmdline_raw[:120]. Gateways autostarted via the managed-runtime interpreter carry a >120-char exe path (.hermes-runtime\python\generation-...\cpython-3.11-...), so the truncated cmdline ended inside the exe path, before '-m hermes_cli.main gateway run'. The Desktop preflight's pausable-gateway exemption (_scan_venv_blockers._is_pausable_gateway) therefore never matched, the gateway was reported as a blocker, and every Desktop update aborted with 'Update didn't finish' even with all windows closed — the updater's own gateway pause never got a chance to run. Fix: return the full cmdline from the detector and truncate only at display time (_format_venv_python_holders_message and the scan's JSON cmdline field, after redaction). Reproduced live on Windows 11: scan reported blocked=true for '...cpython-3.1' (truncated); after the fix the same gateway pair scans clear with pausable_gateways=2.
This commit is contained in:
@@ -144,7 +144,10 @@ def main() -> None:
|
||||
{
|
||||
"pid": pid,
|
||||
"name": name,
|
||||
"cmdline": _redact_sensitive_cmdline(cmdline),
|
||||
# Truncate for display AFTER the gateway exemption has seen the
|
||||
# full cmdline (long managed-runtime interpreter paths would
|
||||
# otherwise swallow the `gateway run` argv).
|
||||
"cmdline": _redact_sensitive_cmdline(cmdline)[:120],
|
||||
}
|
||||
for pid, name, cmdline in matches
|
||||
if not _is_pausable_gateway(cmdline)
|
||||
|
||||
@@ -2926,7 +2926,13 @@ def _detect_venv_python_processes(
|
||||
if not is_holder:
|
||||
continue
|
||||
name = info.get("name") or Path(exe).name
|
||||
matches.append((int(pid), str(name), cmdline_raw[:120]))
|
||||
# Return the FULL cmdline: callers match against it (the Desktop
|
||||
# preflight's pausable-gateway exemption parses for `gateway run`).
|
||||
# Truncating here cut long managed-runtime interpreter paths before
|
||||
# the `-m hermes_cli.main gateway run` argv, so autostarted gateways
|
||||
# were misreported as blockers and the update dead-ended. Truncate
|
||||
# only at display time.
|
||||
matches.append((int(pid), str(name), cmdline_raw))
|
||||
return matches
|
||||
|
||||
def _format_venv_python_holders_message(matches: list[tuple[int, str, str]]) -> str:
|
||||
@@ -2941,7 +2947,7 @@ def _format_venv_python_holders_message(matches: list[tuple[int, str, str]]) ->
|
||||
hint = " ← Hermes Desktop backend (close the desktop app)"
|
||||
elif "gateway" in low:
|
||||
hint = " ← gateway"
|
||||
lines.append(f" PID {pid} {name} {cmdline}{hint}")
|
||||
lines.append(f" PID {pid} {name} {cmdline[:120]}{hint}")
|
||||
if len(matches) > 6:
|
||||
lines.append(f" ... and {len(matches) - 6} more")
|
||||
lines.append("")
|
||||
|
||||
@@ -211,4 +211,35 @@ def test_main_desktop_serve_backend_still_blocks(monkeypatch, capsys):
|
||||
assert code == 0
|
||||
assert data["blocked"] is True
|
||||
assert [p["pid"] for p in data["processes"]] == [78]
|
||||
assert data["pausable_gateways"] == 0
|
||||
assert data["pausable_gateways"] == 0
|
||||
|
||||
def test_main_gateway_with_long_managed_runtime_path_is_exempt(monkeypatch, capsys):
|
||||
"""Regression: the detector must hand the FULL cmdline to the exemption.
|
||||
|
||||
Gateways launched via the managed-runtime interpreter carry a >120-char
|
||||
exe path (`.hermes-runtime\python\generation-...\cpython-3.11-...`).
|
||||
The old `cmdline_raw[:120]` truncation in the detector cut the cmdline
|
||||
before `-m hermes_cli.main gateway run`, so the exemption never matched
|
||||
and every Desktop update aborted with 'Update didn't finish'.
|
||||
Here the detector returns full cmdlines (post-fix contract); the scan
|
||||
must exempt the gateway and truncate only the *displayed* cmdline.
|
||||
"""
|
||||
long_exe = (
|
||||
r'"C:\Users\u\AppData\Local\hermes\hermes-agent\.hermes-runtime\python'
|
||||
r"\generation-1785095035-66720-be29ea9c\cpython-3.11-windows-x86_64-none"
|
||||
r'\python.exe"'
|
||||
)
|
||||
assert len(long_exe) > 120 # the truncation point was inside the exe path
|
||||
gateway = (91, "python.exe", long_exe + " -m hermes_cli.main gateway run --replace")
|
||||
code, data = _run_main_with_detector(monkeypatch, capsys, [gateway])
|
||||
assert code == 0
|
||||
assert data["blocked"] is False
|
||||
assert data["processes"] == []
|
||||
assert data["pausable_gateways"] == 1
|
||||
|
||||
# A long-path NON-gateway holder still blocks, with cmdline truncated for display.
|
||||
stray = (92, "python.exe", long_exe + " -m some_other_module --serve-forever")
|
||||
code, data = _run_main_with_detector(monkeypatch, capsys, [gateway, stray])
|
||||
assert data["blocked"] is True
|
||||
assert [p["pid"] for p in data["processes"]] == [92]
|
||||
assert len(data["processes"][0]["cmdline"]) <= 120
|
||||
|
||||
Reference in New Issue
Block a user