Skip to content

fix(install): detect non-Python venv/bin/hermes and regenerate via pip#22388

Closed
wesleysimplicio wants to merge 1 commit into
NousResearch:mainfrom
wesleysimplicio:fix/install-detect-recursive-hermes-wrapper
Closed

fix(install): detect non-Python venv/bin/hermes and regenerate via pip#22388
wesleysimplicio wants to merge 1 commit into
NousResearch:mainfrom
wesleysimplicio:fix/install-detect-recursive-hermes-wrapper

Conversation

@wesleysimplicio

Copy link
Copy Markdown
Contributor

Problem

After running the curl|bash installer (or after any condition that clobbers the pip-generated console script), venv/bin/hermes can end up as a bash wrapper that execs back into itself. The installer then writes ~/.local/bin/hermes as a launcher that execs \$HERMES_BIN, which execs venv/bin/hermes, which execs itself — hermes hangs silently with no output, no error, no CPU activity. The reporter describes the exact shape in #21802.

Root cause

scripts/install.sh::setup_path validates only that \$HERMES_BIN exists and is executable. It never inspects the file's shape, so a clobbered console script with a bash shebang slips through and the launcher we write on top of it perpetuates the recursion.

Fix

After the existing [ ! -x \"\$HERMES_BIN\" ] check, inspect the first line of \$HERMES_BIN. A correct pip-generated entry point starts with a python shebang (#!.../python...). Anything else triggers a pip install --force-reinstall --no-deps -e . to regenerate the console script in place; if regeneration also fails, surface the exact manual fix instead of silently writing the broken launcher.

The guard is conditional on USE_VENV=true because the system-install path has no venv to reinstall into.

Tests

tests/test_install_sh_recursive_wrapper_guard.py asserts the guard's shape:

  • inspects \$HERMES_BIN's shebang
  • accepts a python shebang only
  • regenerates with --force-reinstall --no-deps
  • references the issue number so future maintainers can trace it
  • falls back to a manual instruction on failure
  • runs before the launcher write
  • is gated on USE_VENV

Pre-existing install.sh tests (pythonpath sanitization, setup wizard tty probe, termux network prereqs) still pass. Bash syntax validated with bash -n.

Closes #21802

Problem
-------
After running the curl|bash installer (or after any condition that
clobbers the pip-generated console script), `venv/bin/hermes` can end
up as a bash wrapper that execs back into itself.  The installer then
writes `~/.local/bin/hermes` as a launcher that execs `$HERMES_BIN`,
which execs `venv/bin/hermes`, which execs itself — `hermes` hangs
silently with no output, no error, no CPU activity.

Root cause
----------
`scripts/install.sh::setup_path` validates only that `$HERMES_BIN`
exists and is executable.  It never inspects the file's shape, so a
clobbered console script with a bash shebang slips through and the
launcher we write on top of it perpetuates the recursion.

Fix
---
After the existing `[ ! -x "$HERMES_BIN" ]` check, inspect the first
line of `$HERMES_BIN`.  A correct pip-generated entry point starts
with a python shebang (`#!.../python...`).  Anything else triggers a
`pip install --force-reinstall --no-deps -e .` to regenerate the
console script in place; if regeneration also fails, surface the
exact manual fix instead of silently writing the broken launcher.

The guard is conditional on `USE_VENV=true` because the system-install
path has no venv to reinstall into.

Tests
-----
`tests/test_install_sh_recursive_wrapper_guard.py` asserts the guard's
shape: it inspects `$HERMES_BIN`'s shebang, accepts a python shebang
only, regenerates with `--force-reinstall --no-deps`, references the
issue number so future maintainers can trace it, falls back to a
manual instruction on failure, runs before the launcher write, and is
gated on `USE_VENV`.  Pre-existing install.sh tests
(pythonpath sanitization / setup wizard tty / termux prereqs) still
pass.  Bash syntax validated with `bash -n`.

Closes NousResearch#21802

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings May 9, 2026 07:52

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR hardens scripts/install.sh against a regression where venv/bin/hermes is clobbered into a self-referential bash wrapper, causing the installed hermes command to hang silently (infinite exec recursion), and adds a regression test to ensure the guard is not removed in future refactors.

Changes:

  • Add a shebang-based validation step in setup_path() to detect non-Python venv/bin/hermes and attempt regeneration with a force-reinstall pip install.
  • Print a manual remediation command when regeneration fails, avoiding writing a launcher that would perpetuate the hang.
  • Add a pytest regression test module that asserts the guard’s presence, ordering, and USE_VENV gating.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 2 comments.

File Description
scripts/install.sh Adds a defensive guard to detect a non-Python venv entrypoint and attempt to regenerate it before writing the launcher shim.
tests/test_install_sh_recursive_wrapper_guard.py Adds regression tests that assert the new guard exists, is ordered correctly, and is gated on USE_VENV.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread scripts/install.sh
Comment on lines +1126 to +1132
return 0
;;
esac
else
log_warn "Could not regenerate venv entry point"
log_info "Manual fix: cd $INSTALL_DIR && uv pip install -e '.[all]'"
return 0
Comment thread scripts/install.sh
*)
log_warn "venv entry point at $HERMES_BIN is not a Python script"
log_info "Regenerating with pip to avoid recursive-exec hang (#21802)..."
if (cd "$INSTALL_DIR" && ./venv/bin/python -m pip install \
@alt-glitch alt-glitch added type/bug Something isn't working P2 Medium — degraded but workaround exists comp/cli CLI entry point, hermes_cli/, setup wizard labels May 9, 2026
@teknium1

Copy link
Copy Markdown
Contributor

Closing in favor of #25734 (merged as c75e1a0), which fixes the root cause of the recursive-wrapper hang — the rm -f before the cat > heredoc in setup_path() prevents venv/bin/hermes from ever being clobbered through a stale symlink in the first place.

The shebang-inspection + --force-reinstall defense-in-depth in this PR was thoughtful, but with the cause closed, the guard would only fire on a venv that's already broken for an unrelated reason — and at that point the right answer is to surface the install failure, not silently pip install --force-reinstall --no-deps over it. Thanks @wesleysimplicio!

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

Labels

comp/cli CLI entry point, hermes_cli/, setup wizard P2 Medium — degraded but workaround exists type/bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: venv/bin/hermes entrypoint is a self-referencing bash wrapper, causing infinite recursion

4 participants