Skip to content

fix(cron): stop lifecycle guard false-positives and crashes on .py/binary scripts - #77201

Closed
criptogus wants to merge 1 commit into
NousResearch:mainfrom
criptogus:fix/lifecycle-guard-pathlib-77131
Closed

fix(cron): stop lifecycle guard false-positives and crashes on .py/binary scripts#77201
criptogus wants to merge 1 commit into
NousResearch:mainfrom
criptogus:fix/lifecycle-guard-pathlib-77131

Conversation

@criptogus

Copy link
Copy Markdown
Contributor

What

The gateway lifecycle guard (cron/lifecycle_guard.py) applied shell-style tokenization and script-reference resolution to non-shell content, producing two regressions:

#77131 — every .py cron script using pathlib division was hard-blocked

Path.home() / ".hermes" / ".env" tokenizes the bare / operator as an executable path, which resolves to the filesystem root; the regular-file check then fails closed as unsafe. Since Python runs under the interpreter, never through a POSIX shell, the shell-script reference walk is a false-positive generator on Python sources.

#76762 — terminal commands invoking a binary by absolute path crashed the guard

/usr/bin/python3 -c "print(1)" crashed with ValueError: embedded null byte: the walk read the binary's bytes, decoded them as text, and re-tokenized machine code; the recursion then hit Path.resolve() on a NUL-bearing path while only OSError was caught.

Fix

  1. check_gateway_lifecycle — skip the shell-script reference walk for *.py scripts (the direct command regex still scans the full text, so a literal lifecycle command embedded in .py is still blocked; non-regular/oversized files still fail closed via the sentinel).
  2. _iter_referenced_shell_scripts — skip pure-separator tokens (pathlib's / operator).
  3. _read_referenced_script — treat NUL-containing files (ELF/Mach-O/PE binaries) as "nothing to scan": binaries are not referenced shell scripts, and scanning them fed junk paths into the recursion.
  4. _contains_unsafe_gateway_action — tolerate ValueError at Path.resolve() time (not just OSError).

Shell scripts (.sh/.bash/.zsh) keep the full deep scan; the referenced-script walk still catches a .sh wrapper that invokes another lifecycle script.

How to test

pytest tests/hermes_cli/test_gateway_restart_loop.py -o 'addopts=' -q

4 new regression tests:

E2E verified: cron.jobs.create_job with a pathlib-heavy .py script now succeeds; with evil.py it is still rejected.

Platforms tested

  • macOS (local). Full test_gateway_restart_loop.py suite (82 passed), cron area (153 passed), terminal tool (129 passed; 1 pre-existing unrelated theme test failure that reproduces on main).

Closes #77131, closes #76762

…nary scripts

The gateway lifecycle guard (cron/lifecycle_guard.py) applied shell-style
tokenization and script-reference resolution to non-shell content, with two
regressions:

NousResearch#77131 - every .py cron script using pathlib division was hard-blocked:
  Path.home() / ".hermes" / ".env" tokenizes the bare "/" operator as an
  executable path, which resolves to the filesystem root; the regular-file
  check then fails closed as unsafe. Since Python runs under the
  interpreter, never through a POSIX shell, the shell-script reference walk
  is a false-positive generator on Python sources. check_gateway_lifecycle
  now skips the walk for *.py scripts (the direct command regex still scans
  the full text), and _iter_referenced_shell_scripts skips pure-separator
  tokens.

NousResearch#76762 - terminal commands invoking a binary by absolute path (e.g.
  /usr/bin/python3) crashed the guard with ValueError: embedded null byte:
  the walk read the binary's bytes, decoded them as text, and re-tokenized
  machine code; the recursion then hit Path.resolve() on a NUL-bearing
  path while only OSError was caught. _read_referenced_script now skips
  NUL-containing files (binaries are not referenced shell scripts) and
  resolve() tolerates ValueError.

Shell scripts (.sh/.bash/.zsh) keep the full deep scan; literal lifecycle
commands in .py scripts are still blocked by the direct regex. New tests
cover all four behaviors.
@alt-glitch alt-glitch added type/bug Something isn't working P2 Medium — degraded but workaround exists comp/cron Cron scheduler and job management needs-decision Awaiting maintainer decision before any implementation labels Aug 3, 2026
@kshitijk4poor

Copy link
Copy Markdown
Collaborator

Merged via #77332 using your implementation — your commits cherry-picked with authorship preserved. Your PR was the most thorough of the three competing fixes: it preserved / detection for shell-script chains (via executable.strip("/")), fixed the binary NUL crash (#76762), and included positive+negative test coverage. Thanks!

#77332

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

comp/cron Cron scheduler and job management needs-decision Awaiting maintainer decision before any implementation P2 Medium — degraded but workaround exists type/bug Something isn't working

Projects

None yet

3 participants