Skip to content

fix(hooks): strip shebang argument so pipx launchers resolve (#2629) - #2687

Open
ousamabenyounes wants to merge 1 commit into
Graphify-Labs:v8from
ousamabenyounes:fix/issue-2629
Open

fix(hooks): strip shebang argument so pipx launchers resolve (#2629)#2687
ousamabenyounes wants to merge 1 commit into
Graphify-Labs:v8from
ousamabenyounes:fix/issue-2629

Conversation

@ousamabenyounes

Copy link
Copy Markdown
Contributor

Summary

Fixes #2629.

pipx installs write the graphify launcher with a shebang that carries an
argument, e.g. #!/Users/me/.local/pipx/venvs/graphifyy/bin/python -E. Every
interpreter probe read that shebang and used the whole string as a path. The
trailing -E puts a space in the string, which trips the character allowlist,
so the valid pipx interpreter is discarded and the probe silently falls back to
a bare python3 that has no graphify installed. On the reporter's machine the
post-commit hook therefore printed

[graphify hook] could not locate a Python with graphify installed.

after every commit and the graph silently stopped updating.

Fix

Strip any interpreter argument (and resolve /usr/bin/env python) before using
the shebang as a path, at all three POSIX probe sites:

  • graphify/hooks.py — the generated post-commit / post-checkout hook probe.
  • tools/skillgen/fragments/shell/posix.md — the skill's step-1 interpreter probe.
  • tools/skillgen/fragments/shell/interpreter-guard-posix.md — the subcommand
    guard that pins graphify-out/.graphify_python.

The graphify/skill*.md and tools/skillgen/expected/* changes are the
regenerated skill artifacts (python -m tools.skillgen); the two source
fragments are the only hand edits there. The aider/devin monoliths inline
the same probe but are frozen by --monolith-roundtrip, so they are out of
scope for this change.

Reproduces with

A launcher whose shebang carries an argument resolves to a bare python3
instead of the real interpreter:

$ printf '#!%s -E\n' "$(which python)" > bin/graphify   # pipx-style shebang
# probe result before: RESOLVED= (empty) -> "could not locate a Python..."
# probe result after:  RESOLVED=/.../bin/python

TDD verification (RED -> GREEN)

New tests in tests/test_hooks.py:
test_hook_probe_resolves_pipx_shebang_with_argument executes the real
_PYTHON_DETECT block against a pipx-style launcher, and
test_generated_skill_probes_strip_shebang_argument guards both rendered probe
sites.

RED (production fix reverted, tests kept):

FAILED tests/test_hooks.py::test_hook_probe_resolves_pipx_shebang_with_argument
  AssertionError: got 'python3', expected '/.../.venv/bin/python'
FAILED tests/test_hooks.py::test_generated_skill_probes_strip_shebang_argument
  AssertionError: step-1 probe does not strip shebang argument
2 failed

GREEN (with fix):

2 passed, 78 deselected

Full suite: uv run --frozen pytest tests/ -q — 4330 passed, 3 skipped. The 3
failing tests/test_ollama.py::test_detect_backend_* are pre-existing on a
clean v8 checkout (backend-detection tests sensitive to a locally-running
Ollama) and are unrelated to this change. skillgen validators (--check,
--audit-coverage, --schema-singleton, --monolith-roundtrip,
--always-on-roundtrip) all pass.

…y-Labs#2629)

pipx writes the graphify launcher shebang with an argument
(`#!/.../python -E`). The interpreter probes used the whole shebang as a
path; the space tripped the character allowlist, the valid interpreter was
discarded, and the probe silently fell back to a `python3` without graphify
— printing "could not locate a Python with graphify installed" after every
commit and leaving the graph stale.

Strip any interpreter argument (and resolve `/usr/bin/env python`) before
using the shebang as a path, in the post-commit hook probe and both skill
interpreter probes (regenerated via skillgen).

@graphify-labs graphify-labs Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Graphify reviewed this change.

Looks safe to merge — no coupling regressions and no blocking issues, checked against the code graph (not a self-assessment).


Graphify review — findings

This PR fixes shebang parsing in the git post-commit hook and the interpreter-detection probes across the various agent skill files (graphify/hooks.py, skill-*.md, and their generated tools/skillgen expected fixtures). It adds a step that strips a trailing interpreter argument (e.g., the -E in pipx's #!/.../python -E) so the leading path word is kept before the character allowlist check. The change spans a CHANGELOG entry and the corresponding hook test file (tests/test_hooks.py), touching many parallel skill-template copies that share the same snippet.

No blocking issues surfaced. 3 lower-confidence candidates did not survive cross-model review.

Analysis details — impact, health, verification

Impact & health

Graphify review

Impact — 1133 functions depend on the 987 functions this change touches.

Health — grade B; 7 existing hotspot(s) in the area this change touches (pre-existing, not introduced here):

  • dispatch_command() — 2 callers, 117 callees (high)
  • install() — 25 callers, 6 callees (high)
  • dispatch_install_cli() — 2 callers, 31 callees (high)
  • uninstall() — 9 callers, 5 callees (high)
  • status() — 6 callers, 5 callees (medium)
  • uninstall_all() — 2 callers, 13 callees (high)
  • test_poisoned_manifest_is_healed() — 0 callers, 6 callees (medium)

Verification — 1133 functions in the blast radius were not formally verified this run (proofs are advisory here).

Gate & verification

graphify gate

PASS — objectively clean (no health regressions, tests not run — proofs not run this pass (advisory)). Grounded, not self-assessed.

Advisory (not blocking):

  • verification_scope: 994 function(s) in the blast radius were not formally verified this run

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Interpreter probe fails on pipx installs: shebang with an argument is parsed as a file path

1 participant