test+harden(cli): cover parent-chain walk in concurrent-instance detection

Follow-up to @Strontvod's fix.

Tests:
- Five new tests in test_update_concurrent_quarantine.py cover the parent-
  chain exclusion: the .exe launcher is excluded, an unrelated sibling
  hermes.exe is still reported, multi-level ancestry is fully excluded,
  PID cycles in the parent chain don't hang, and a partially-stubbed
  psutil (no Process attribute) degrades gracefully instead of crashing.
- New _fake_psutil_with_parent_chain helper builds a fuller stand-in
  (Process / NoSuchProcess / AccessDenied + process_iter) than the
  process_iter-only SimpleNamespace the older tests use.

Hardening:
- Broaden the except in the parent-walk to bare Exception. The original
  fix listed (NoSuchProcess, AccessDenied, ValueError), but those names
  are evaluated lazily during exception matching — if psutil is a partial
  stub without the attribute, the exception handler itself raises
  AttributeError that escapes. The function is documented as 'never raises'
  (the surrounding update flow depends on it), so the broader catch keeps
  the contract regardless of how the dependency is shaped.

AUTHOR_MAP:
- Map schepers.zander1@gmail.com -> Strontvod so the salvaged commit
  resolves to @Strontvod in the release notes.

All 18 detect_concurrent + quarantine tests pass.
This commit is contained in:
Teknium 2026-05-24 19:41:23 -07:00
parent 323cce7e94
commit 46f8948bad
3 changed files with 185 additions and 2 deletions

View file

@ -7693,12 +7693,18 @@ def _detect_concurrent_hermes_instances(
exclude_pids: set[int] = {exclude_pid}
else:
exclude_pids = {os.getpid()}
# The parent-walk is best-effort: if psutil rejects a PID (NoSuchProcess /
# AccessDenied) we stop walking and use whatever we've collected so far.
# Broader Exception catch on the outer block guards against partially-
# stubbed psutil in unit tests (e.g. a SimpleNamespace lacking Process /
# NoSuchProcess) — the surrounding update flow documents this helper as
# "never raises".
try:
current = psutil.Process(next(iter(exclude_pids)))
while True:
try:
parent = current.parent()
except (psutil.NoSuchProcess, psutil.AccessDenied):
except Exception:
break
if parent is None or parent.pid <= 0:
break
@ -7706,7 +7712,7 @@ def _detect_concurrent_hermes_instances(
break # loop detected
exclude_pids.add(parent.pid)
current = parent
except (psutil.NoSuchProcess, psutil.AccessDenied, ValueError):
except Exception:
pass
# Resolve every shim path to its canonical form once for cheap comparison.