fix: allow python@ shebang in skill detection (#1586) + merge-graphs mixed types (#1606)

#1586: the skill's interpreter-detection allowlist rejected any shebath path
with a char outside [a-zA-Z0-9/_.-], so Homebrew's versioned python@3.13 path
was skipped and detection fell through to a bare python3 without graphify.
Allow @ in the skillgen source fragments (core/devin/aider/posix), regenerate
all skill artifacts, and register the change as a sanctioned monolith diff.
Injection chars (; $ ( etc.) are still rejected.

#1606: graphify merge-graphs crashed with an unhandled NetworkXError when
inputs disagreed on directed/multigraph. _to_simple only converted MultiGraph,
leaving a DiGraph to fail compose. Normalize every input to a plain undirected
Graph (the merged cross-repo view is undirected anyway).

Also confirmed on v8: `graphify kilo install` (#1605) works (reporter was on an
older version), and `pip3 install graphifyy` failing on macOS (#1585) is a
broken Homebrew Python 3.14 / pyexpat env, not a graphify issue — pip crashes
in its own vendored distlib before graphify is touched.

skillgen --check / --monolith-roundtrip / --schema-singleton all green; shell
smoke accepts python@3.13 and still rejects `; rm -rf /` and `$(evil)`. Full
suite 2789.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
safishamsi
2026-07-02 11:25:51 +01:00
co-authored by Claude Opus 4.8
parent 5190a4ede9
commit b70a6d7126
40 changed files with 137 additions and 66 deletions
+2
View File
@@ -4,6 +4,8 @@ Full release notes with details on each version: [GitHub Releases](https://githu
## Unreleased
- Fix: the skill's Python-interpreter detection now accepts Homebrew `python@3.x` paths (#1586, thanks @SUDARSHANCHAUDHARI). The shebang allowlist rejected any path with a character outside `[a-zA-Z0-9/_.-]`, but Homebrew installs versioned Python under `python@3.13`, so a valid interpreter containing `@` was skipped and detection fell through to a bare `python3` that lacked graphify (every step then failed with `ModuleNotFoundError`). `@` is now allowed across all skill variants (matching the #473 hooks.py fix); injection characters are still rejected.
- Fix: `graphify merge-graphs` no longer crashes on inputs that disagree on graph type (#1606, thanks @AdrianRusan). Per-repo `graph.json` files don't always share the same `directed` / `multigraph` flags, and `compose` requires one uniform type, so a mixed set raised an unhandled `NetworkXError`. All inputs are now normalized to a plain undirected graph (which the cross-repo merged view already is) before composing.
- Fix: type-reference / inheritance edge gaps closed across seven languages (all thanks @Synvoya):
- Scala: `var` field declarations now emit type `references` like `val` (#1587).
- PowerShell: class base types after `:` now emit `inherits` (first) / `implements` (rest), matching the C# convention (#1588).
+8 -1
View File
@@ -3912,7 +3912,14 @@ def main() -> None:
# may be a MultiGraph and another a Graph. Normalise everything to Graph
# (the graphify default) by converting MultiGraphs with nx.Graph().
def _to_simple(g: "_nx.Graph") -> "_nx.Graph":
if isinstance(g, _nx.MultiGraph):
# nx.compose requires every graph to be the same type. Inputs may
# disagree on BOTH axes — directed vs undirected, and multi vs simple
# — because per-repo graph.json files are written by different extract
# paths at different times. Normalise everything to a plain undirected
# Graph (the merged cross-repo view is undirected anyway), which covers
# DiGraph / MultiGraph / MultiDiGraph. Without this a directed input
# crashed compose with "All graphs must be directed or undirected" (#1606).
if type(g) is not _nx.Graph:
return _nx.Graph(g)
return g
merged = _nx.Graph()
+2 -2
View File
@@ -77,7 +77,7 @@ fi
if [ -z "$PYTHON" ] && [ -n "$GRAPHIFY_BIN" ]; then
_SHEBANG=$(head -1 "$GRAPHIFY_BIN" | tr -d '#!')
case "$_SHEBANG" in
*[!a-zA-Z0-9/_.-]*) ;;
*[!a-zA-Z0-9/_.@-]*) ;;
*) "$_SHEBANG" -c "import graphify" 2>/dev/null && PYTHON="$_SHEBANG" ;;
esac
fi
@@ -626,7 +626,7 @@ if [ ! -f graphify-out/.graphify_python ]; then
GRAPHIFY_BIN=$(which graphify 2>/dev/null)
if [ -n "$GRAPHIFY_BIN" ]; then
PYTHON=$(head -1 "$GRAPHIFY_BIN" | tr -d '#!')
case "$PYTHON" in *[!a-zA-Z0-9/_.-]*) PYTHON="python3" ;; esac
case "$PYTHON" in *[!a-zA-Z0-9/_.@-]*) PYTHON="python3" ;; esac
else
PYTHON="python3"
fi
+1 -1
View File
@@ -71,7 +71,7 @@ fi
if [ -z "$PYTHON" ] && [ -n "$GRAPHIFY_BIN" ]; then
_SHEBANG=$(head -1 "$GRAPHIFY_BIN" | tr -d '#!')
case "$_SHEBANG" in
*[!a-zA-Z0-9/_.-]*) ;;
*[!a-zA-Z0-9/_.@-]*) ;;
*) "$_SHEBANG" -c "import graphify" 2>/dev/null && PYTHON="$_SHEBANG" ;;
esac
fi
+2 -2
View File
@@ -77,7 +77,7 @@ fi
if [ -z "$PYTHON" ] && [ -n "$GRAPHIFY_BIN" ]; then
_SHEBANG=$(head -1 "$GRAPHIFY_BIN" | tr -d '#!')
case "$_SHEBANG" in
*[!a-zA-Z0-9/_.-]*) ;;
*[!a-zA-Z0-9/_.@-]*) ;;
*) "$_SHEBANG" -c "import graphify" 2>/dev/null && PYTHON="$_SHEBANG" ;;
esac
fi
@@ -626,7 +626,7 @@ if [ ! -f graphify-out/.graphify_python ]; then
GRAPHIFY_BIN=$(which graphify 2>/dev/null)
if [ -n "$GRAPHIFY_BIN" ]; then
PYTHON=$(head -1 "$GRAPHIFY_BIN" | tr -d '#!')
case "$PYTHON" in *[!a-zA-Z0-9/_.-]*) PYTHON="python3" ;; esac
case "$PYTHON" in *[!a-zA-Z0-9/_.@-]*) PYTHON="python3" ;; esac
else
PYTHON="python3"
fi
+2 -2
View File
@@ -77,7 +77,7 @@ fi
if [ -z "$PYTHON" ] && [ -n "$GRAPHIFY_BIN" ]; then
_SHEBANG=$(head -1 "$GRAPHIFY_BIN" | tr -d '#!')
case "$_SHEBANG" in
*[!a-zA-Z0-9/_.-]*) ;;
*[!a-zA-Z0-9/_.@-]*) ;;
*) "$_SHEBANG" -c "import graphify" 2>/dev/null && PYTHON="$_SHEBANG" ;;
esac
fi
@@ -629,7 +629,7 @@ if [ ! -f graphify-out/.graphify_python ]; then
GRAPHIFY_BIN=$(which graphify 2>/dev/null)
if [ -n "$GRAPHIFY_BIN" ]; then
PYTHON=$(head -1 "$GRAPHIFY_BIN" | tr -d '#!')
case "$PYTHON" in *[!a-zA-Z0-9/_.-]*) PYTHON="python3" ;; esac
case "$PYTHON" in *[!a-zA-Z0-9/_.@-]*) PYTHON="python3" ;; esac
else
PYTHON="python3"
fi
+2 -2
View File
@@ -77,7 +77,7 @@ fi
if [ -z "$PYTHON" ] && [ -n "$GRAPHIFY_BIN" ]; then
_SHEBANG=$(head -1 "$GRAPHIFY_BIN" | tr -d '#!')
case "$_SHEBANG" in
*[!a-zA-Z0-9/_.-]*) ;;
*[!a-zA-Z0-9/_.@-]*) ;;
*) "$_SHEBANG" -c "import graphify" 2>/dev/null && PYTHON="$_SHEBANG" ;;
esac
fi
@@ -626,7 +626,7 @@ if [ ! -f graphify-out/.graphify_python ]; then
GRAPHIFY_BIN=$(which graphify 2>/dev/null)
if [ -n "$GRAPHIFY_BIN" ]; then
PYTHON=$(head -1 "$GRAPHIFY_BIN" | tr -d '#!')
case "$PYTHON" in *[!a-zA-Z0-9/_.-]*) PYTHON="python3" ;; esac
case "$PYTHON" in *[!a-zA-Z0-9/_.@-]*) PYTHON="python3" ;; esac
else
PYTHON="python3"
fi
+2 -2
View File
@@ -77,7 +77,7 @@ fi
if [ -z "$PYTHON" ] && [ -n "$GRAPHIFY_BIN" ]; then
_SHEBANG=$(head -1 "$GRAPHIFY_BIN" | tr -d '#!')
case "$_SHEBANG" in
*[!a-zA-Z0-9/_.-]*) ;;
*[!a-zA-Z0-9/_.@-]*) ;;
*) "$_SHEBANG" -c "import graphify" 2>/dev/null && PYTHON="$_SHEBANG" ;;
esac
fi
@@ -629,7 +629,7 @@ if [ ! -f graphify-out/.graphify_python ]; then
GRAPHIFY_BIN=$(which graphify 2>/dev/null)
if [ -n "$GRAPHIFY_BIN" ]; then
PYTHON=$(head -1 "$GRAPHIFY_BIN" | tr -d '#!')
case "$PYTHON" in *[!a-zA-Z0-9/_.-]*) PYTHON="python3" ;; esac
case "$PYTHON" in *[!a-zA-Z0-9/_.@-]*) PYTHON="python3" ;; esac
else
PYTHON="python3"
fi
+2 -2
View File
@@ -82,7 +82,7 @@ fi
if [ -z "$PYTHON" ] && [ -n "$GRAPHIFY_BIN" ]; then
_SHEBANG=$(head -1 "$GRAPHIFY_BIN" | tr -d '#!')
case "$_SHEBANG" in
*[!a-zA-Z0-9/_.-]*) ;;
*[!a-zA-Z0-9/_.@-]*) ;;
*) "$_SHEBANG" -c "import graphify" 2>/dev/null && PYTHON="$_SHEBANG" ;;
esac
fi
@@ -865,7 +865,7 @@ if [ ! -f graphify-out/.graphify_python ]; then
GRAPHIFY_BIN=$(which graphify 2>/dev/null)
if [ -n "$GRAPHIFY_BIN" ]; then
PYTHON=$(head -1 "$GRAPHIFY_BIN" | tr -d '#!')
case "$PYTHON" in *[!a-zA-Z0-9/_.-]*) PYTHON="python3" ;; esac
case "$PYTHON" in *[!a-zA-Z0-9/_.@-]*) PYTHON="python3" ;; esac
else
PYTHON="python3"
fi
+2 -2
View File
@@ -77,7 +77,7 @@ fi
if [ -z "$PYTHON" ] && [ -n "$GRAPHIFY_BIN" ]; then
_SHEBANG=$(head -1 "$GRAPHIFY_BIN" | tr -d '#!')
case "$_SHEBANG" in
*[!a-zA-Z0-9/_.-]*) ;;
*[!a-zA-Z0-9/_.@-]*) ;;
*) "$_SHEBANG" -c "import graphify" 2>/dev/null && PYTHON="$_SHEBANG" ;;
esac
fi
@@ -626,7 +626,7 @@ if [ ! -f graphify-out/.graphify_python ]; then
GRAPHIFY_BIN=$(which graphify 2>/dev/null)
if [ -n "$GRAPHIFY_BIN" ]; then
PYTHON=$(head -1 "$GRAPHIFY_BIN" | tr -d '#!')
case "$PYTHON" in *[!a-zA-Z0-9/_.-]*) PYTHON="python3" ;; esac
case "$PYTHON" in *[!a-zA-Z0-9/_.@-]*) PYTHON="python3" ;; esac
else
PYTHON="python3"
fi
+2 -2
View File
@@ -77,7 +77,7 @@ fi
if [ -z "$PYTHON" ] && [ -n "$GRAPHIFY_BIN" ]; then
_SHEBANG=$(head -1 "$GRAPHIFY_BIN" | tr -d '#!')
case "$_SHEBANG" in
*[!a-zA-Z0-9/_.-]*) ;;
*[!a-zA-Z0-9/_.@-]*) ;;
*) "$_SHEBANG" -c "import graphify" 2>/dev/null && PYTHON="$_SHEBANG" ;;
esac
fi
@@ -629,7 +629,7 @@ if [ ! -f graphify-out/.graphify_python ]; then
GRAPHIFY_BIN=$(which graphify 2>/dev/null)
if [ -n "$GRAPHIFY_BIN" ]; then
PYTHON=$(head -1 "$GRAPHIFY_BIN" | tr -d '#!')
case "$PYTHON" in *[!a-zA-Z0-9/_.-]*) PYTHON="python3" ;; esac
case "$PYTHON" in *[!a-zA-Z0-9/_.@-]*) PYTHON="python3" ;; esac
else
PYTHON="python3"
fi
+2 -2
View File
@@ -77,7 +77,7 @@ fi
if [ -z "$PYTHON" ] && [ -n "$GRAPHIFY_BIN" ]; then
_SHEBANG=$(head -1 "$GRAPHIFY_BIN" | tr -d '#!')
case "$_SHEBANG" in
*[!a-zA-Z0-9/_.-]*) ;;
*[!a-zA-Z0-9/_.@-]*) ;;
*) "$_SHEBANG" -c "import graphify" 2>/dev/null && PYTHON="$_SHEBANG" ;;
esac
fi
@@ -629,7 +629,7 @@ if [ ! -f graphify-out/.graphify_python ]; then
GRAPHIFY_BIN=$(which graphify 2>/dev/null)
if [ -n "$GRAPHIFY_BIN" ]; then
PYTHON=$(head -1 "$GRAPHIFY_BIN" | tr -d '#!')
case "$PYTHON" in *[!a-zA-Z0-9/_.-]*) PYTHON="python3" ;; esac
case "$PYTHON" in *[!a-zA-Z0-9/_.@-]*) PYTHON="python3" ;; esac
else
PYTHON="python3"
fi
+2 -2
View File
@@ -77,7 +77,7 @@ fi
if [ -z "$PYTHON" ] && [ -n "$GRAPHIFY_BIN" ]; then
_SHEBANG=$(head -1 "$GRAPHIFY_BIN" | tr -d '#!')
case "$_SHEBANG" in
*[!a-zA-Z0-9/_.-]*) ;;
*[!a-zA-Z0-9/_.@-]*) ;;
*) "$_SHEBANG" -c "import graphify" 2>/dev/null && PYTHON="$_SHEBANG" ;;
esac
fi
@@ -621,7 +621,7 @@ if [ ! -f graphify-out/.graphify_python ]; then
GRAPHIFY_BIN=$(which graphify 2>/dev/null)
if [ -n "$GRAPHIFY_BIN" ]; then
PYTHON=$(head -1 "$GRAPHIFY_BIN" | tr -d '#!')
case "$PYTHON" in *[!a-zA-Z0-9/_.-]*) PYTHON="python3" ;; esac
case "$PYTHON" in *[!a-zA-Z0-9/_.@-]*) PYTHON="python3" ;; esac
else
PYTHON="python3"
fi
+2 -2
View File
@@ -77,7 +77,7 @@ fi
if [ -z "$PYTHON" ] && [ -n "$GRAPHIFY_BIN" ]; then
_SHEBANG=$(head -1 "$GRAPHIFY_BIN" | tr -d '#!')
case "$_SHEBANG" in
*[!a-zA-Z0-9/_.-]*) ;;
*[!a-zA-Z0-9/_.@-]*) ;;
*) "$_SHEBANG" -c "import graphify" 2>/dev/null && PYTHON="$_SHEBANG" ;;
esac
fi
@@ -629,7 +629,7 @@ if [ ! -f graphify-out/.graphify_python ]; then
GRAPHIFY_BIN=$(which graphify 2>/dev/null)
if [ -n "$GRAPHIFY_BIN" ]; then
PYTHON=$(head -1 "$GRAPHIFY_BIN" | tr -d '#!')
case "$PYTHON" in *[!a-zA-Z0-9/_.-]*) PYTHON="python3" ;; esac
case "$PYTHON" in *[!a-zA-Z0-9/_.@-]*) PYTHON="python3" ;; esac
else
PYTHON="python3"
fi
+2 -2
View File
@@ -77,7 +77,7 @@ fi
if [ -z "$PYTHON" ] && [ -n "$GRAPHIFY_BIN" ]; then
_SHEBANG=$(head -1 "$GRAPHIFY_BIN" | tr -d '#!')
case "$_SHEBANG" in
*[!a-zA-Z0-9/_.-]*) ;;
*[!a-zA-Z0-9/_.@-]*) ;;
*) "$_SHEBANG" -c "import graphify" 2>/dev/null && PYTHON="$_SHEBANG" ;;
esac
fi
@@ -627,7 +627,7 @@ if [ ! -f graphify-out/.graphify_python ]; then
GRAPHIFY_BIN=$(which graphify 2>/dev/null)
if [ -n "$GRAPHIFY_BIN" ]; then
PYTHON=$(head -1 "$GRAPHIFY_BIN" | tr -d '#!')
case "$PYTHON" in *[!a-zA-Z0-9/_.-]*) PYTHON="python3" ;; esac
case "$PYTHON" in *[!a-zA-Z0-9/_.@-]*) PYTHON="python3" ;; esac
else
PYTHON="python3"
fi
+2 -2
View File
@@ -77,7 +77,7 @@ fi
if [ -z "$PYTHON" ] && [ -n "$GRAPHIFY_BIN" ]; then
_SHEBANG=$(head -1 "$GRAPHIFY_BIN" | tr -d '#!')
case "$_SHEBANG" in
*[!a-zA-Z0-9/_.-]*) ;;
*[!a-zA-Z0-9/_.@-]*) ;;
*) "$_SHEBANG" -c "import graphify" 2>/dev/null && PYTHON="$_SHEBANG" ;;
esac
fi
@@ -625,7 +625,7 @@ if [ ! -f graphify-out/.graphify_python ]; then
GRAPHIFY_BIN=$(which graphify 2>/dev/null)
if [ -n "$GRAPHIFY_BIN" ]; then
PYTHON=$(head -1 "$GRAPHIFY_BIN" | tr -d '#!')
case "$PYTHON" in *[!a-zA-Z0-9/_.-]*) PYTHON="python3" ;; esac
case "$PYTHON" in *[!a-zA-Z0-9/_.@-]*) PYTHON="python3" ;; esac
else
PYTHON="python3"
fi
+1 -1
View File
@@ -651,7 +651,7 @@ if [ ! -f graphify-out/.graphify_python ]; then
GRAPHIFY_BIN=$(which graphify 2>/dev/null)
if [ -n "$GRAPHIFY_BIN" ]; then
PYTHON=$(head -1 "$GRAPHIFY_BIN" | tr -d '#!')
case "$PYTHON" in *[!a-zA-Z0-9/_.-]*) PYTHON="python3" ;; esac
case "$PYTHON" in *[!a-zA-Z0-9/_.@-]*) PYTHON="python3" ;; esac
else
PYTHON="python3"
fi
+2 -2
View File
@@ -77,7 +77,7 @@ fi
if [ -z "$PYTHON" ] && [ -n "$GRAPHIFY_BIN" ]; then
_SHEBANG=$(head -1 "$GRAPHIFY_BIN" | tr -d '#!')
case "$_SHEBANG" in
*[!a-zA-Z0-9/_.-]*) ;;
*[!a-zA-Z0-9/_.@-]*) ;;
*) "$_SHEBANG" -c "import graphify" 2>/dev/null && PYTHON="$_SHEBANG" ;;
esac
fi
@@ -629,7 +629,7 @@ if [ ! -f graphify-out/.graphify_python ]; then
GRAPHIFY_BIN=$(which graphify 2>/dev/null)
if [ -n "$GRAPHIFY_BIN" ]; then
PYTHON=$(head -1 "$GRAPHIFY_BIN" | tr -d '#!')
case "$PYTHON" in *[!a-zA-Z0-9/_.-]*) PYTHON="python3" ;; esac
case "$PYTHON" in *[!a-zA-Z0-9/_.@-]*) PYTHON="python3" ;; esac
else
PYTHON="python3"
fi
+48
View File
@@ -0,0 +1,48 @@
"""`graphify merge-graphs` tolerates inputs that disagree on graph type (#1606).
Per-repo graph.json files written by different extract paths at different times
don't always agree on the `directed` / `multigraph` flags. compose requires one
uniform type, so a mixed set used to crash with an unhandled NetworkXError. The
handler now normalizes every input to a plain undirected Graph before composing.
"""
from __future__ import annotations
import json
import subprocess
import sys
from pathlib import Path
PYTHON = sys.executable
def _run(args, cwd):
return subprocess.run([PYTHON, "-m", "graphify"] + args, cwd=cwd,
capture_output=True, text=True)
def _write(p: Path, directed: bool, multigraph: bool, node_id: str):
p.parent.mkdir(parents=True, exist_ok=True)
p.write_text(json.dumps({
"directed": directed, "multigraph": multigraph, "graph": {},
"nodes": [{"id": node_id}], "links": [],
}))
def test_merge_graphs_mixed_directed_and_multigraph(tmp_path):
a = tmp_path / "r1" / "graphify-out" / "graph.json"
b = tmp_path / "r2" / "graphify-out" / "graph.json"
c = tmp_path / "r3" / "graphify-out" / "graph.json"
_write(a, directed=True, multigraph=False, node_id="x") # DiGraph
_write(b, directed=False, multigraph=False, node_id="y") # Graph
_write(c, directed=False, multigraph=True, node_id="z") # MultiGraph
out = tmp_path / "merged.json"
r = _run(["merge-graphs", str(a), str(b), str(c), "--out", str(out)], tmp_path)
assert r.returncode == 0, f"merge crashed: {r.stderr}"
assert out.exists()
data = json.loads(out.read_text())
ids = {n["id"] for n in data["nodes"]}
# every input's node survives, normalized into one undirected simple graph
assert {"r1::x", "r2::y", "r3::z"} <= ids or len(ids) == 3
assert data.get("directed") is False
assert data.get("multigraph") is False
@@ -77,7 +77,7 @@ fi
if [ -z "$PYTHON" ] && [ -n "$GRAPHIFY_BIN" ]; then
_SHEBANG=$(head -1 "$GRAPHIFY_BIN" | tr -d '#!')
case "$_SHEBANG" in
*[!a-zA-Z0-9/_.-]*) ;;
*[!a-zA-Z0-9/_.@-]*) ;;
*) "$_SHEBANG" -c "import graphify" 2>/dev/null && PYTHON="$_SHEBANG" ;;
esac
fi
@@ -626,7 +626,7 @@ if [ ! -f graphify-out/.graphify_python ]; then
GRAPHIFY_BIN=$(which graphify 2>/dev/null)
if [ -n "$GRAPHIFY_BIN" ]; then
PYTHON=$(head -1 "$GRAPHIFY_BIN" | tr -d '#!')
case "$PYTHON" in *[!a-zA-Z0-9/_.-]*) PYTHON="python3" ;; esac
case "$PYTHON" in *[!a-zA-Z0-9/_.@-]*) PYTHON="python3" ;; esac
else
PYTHON="python3"
fi
@@ -71,7 +71,7 @@ fi
if [ -z "$PYTHON" ] && [ -n "$GRAPHIFY_BIN" ]; then
_SHEBANG=$(head -1 "$GRAPHIFY_BIN" | tr -d '#!')
case "$_SHEBANG" in
*[!a-zA-Z0-9/_.-]*) ;;
*[!a-zA-Z0-9/_.@-]*) ;;
*) "$_SHEBANG" -c "import graphify" 2>/dev/null && PYTHON="$_SHEBANG" ;;
esac
fi
@@ -77,7 +77,7 @@ fi
if [ -z "$PYTHON" ] && [ -n "$GRAPHIFY_BIN" ]; then
_SHEBANG=$(head -1 "$GRAPHIFY_BIN" | tr -d '#!')
case "$_SHEBANG" in
*[!a-zA-Z0-9/_.-]*) ;;
*[!a-zA-Z0-9/_.@-]*) ;;
*) "$_SHEBANG" -c "import graphify" 2>/dev/null && PYTHON="$_SHEBANG" ;;
esac
fi
@@ -626,7 +626,7 @@ if [ ! -f graphify-out/.graphify_python ]; then
GRAPHIFY_BIN=$(which graphify 2>/dev/null)
if [ -n "$GRAPHIFY_BIN" ]; then
PYTHON=$(head -1 "$GRAPHIFY_BIN" | tr -d '#!')
case "$PYTHON" in *[!a-zA-Z0-9/_.-]*) PYTHON="python3" ;; esac
case "$PYTHON" in *[!a-zA-Z0-9/_.@-]*) PYTHON="python3" ;; esac
else
PYTHON="python3"
fi
@@ -77,7 +77,7 @@ fi
if [ -z "$PYTHON" ] && [ -n "$GRAPHIFY_BIN" ]; then
_SHEBANG=$(head -1 "$GRAPHIFY_BIN" | tr -d '#!')
case "$_SHEBANG" in
*[!a-zA-Z0-9/_.-]*) ;;
*[!a-zA-Z0-9/_.@-]*) ;;
*) "$_SHEBANG" -c "import graphify" 2>/dev/null && PYTHON="$_SHEBANG" ;;
esac
fi
@@ -629,7 +629,7 @@ if [ ! -f graphify-out/.graphify_python ]; then
GRAPHIFY_BIN=$(which graphify 2>/dev/null)
if [ -n "$GRAPHIFY_BIN" ]; then
PYTHON=$(head -1 "$GRAPHIFY_BIN" | tr -d '#!')
case "$PYTHON" in *[!a-zA-Z0-9/_.-]*) PYTHON="python3" ;; esac
case "$PYTHON" in *[!a-zA-Z0-9/_.@-]*) PYTHON="python3" ;; esac
else
PYTHON="python3"
fi
@@ -77,7 +77,7 @@ fi
if [ -z "$PYTHON" ] && [ -n "$GRAPHIFY_BIN" ]; then
_SHEBANG=$(head -1 "$GRAPHIFY_BIN" | tr -d '#!')
case "$_SHEBANG" in
*[!a-zA-Z0-9/_.-]*) ;;
*[!a-zA-Z0-9/_.@-]*) ;;
*) "$_SHEBANG" -c "import graphify" 2>/dev/null && PYTHON="$_SHEBANG" ;;
esac
fi
@@ -626,7 +626,7 @@ if [ ! -f graphify-out/.graphify_python ]; then
GRAPHIFY_BIN=$(which graphify 2>/dev/null)
if [ -n "$GRAPHIFY_BIN" ]; then
PYTHON=$(head -1 "$GRAPHIFY_BIN" | tr -d '#!')
case "$PYTHON" in *[!a-zA-Z0-9/_.-]*) PYTHON="python3" ;; esac
case "$PYTHON" in *[!a-zA-Z0-9/_.@-]*) PYTHON="python3" ;; esac
else
PYTHON="python3"
fi
@@ -77,7 +77,7 @@ fi
if [ -z "$PYTHON" ] && [ -n "$GRAPHIFY_BIN" ]; then
_SHEBANG=$(head -1 "$GRAPHIFY_BIN" | tr -d '#!')
case "$_SHEBANG" in
*[!a-zA-Z0-9/_.-]*) ;;
*[!a-zA-Z0-9/_.@-]*) ;;
*) "$_SHEBANG" -c "import graphify" 2>/dev/null && PYTHON="$_SHEBANG" ;;
esac
fi
@@ -629,7 +629,7 @@ if [ ! -f graphify-out/.graphify_python ]; then
GRAPHIFY_BIN=$(which graphify 2>/dev/null)
if [ -n "$GRAPHIFY_BIN" ]; then
PYTHON=$(head -1 "$GRAPHIFY_BIN" | tr -d '#!')
case "$PYTHON" in *[!a-zA-Z0-9/_.-]*) PYTHON="python3" ;; esac
case "$PYTHON" in *[!a-zA-Z0-9/_.@-]*) PYTHON="python3" ;; esac
else
PYTHON="python3"
fi
@@ -82,7 +82,7 @@ fi
if [ -z "$PYTHON" ] && [ -n "$GRAPHIFY_BIN" ]; then
_SHEBANG=$(head -1 "$GRAPHIFY_BIN" | tr -d '#!')
case "$_SHEBANG" in
*[!a-zA-Z0-9/_.-]*) ;;
*[!a-zA-Z0-9/_.@-]*) ;;
*) "$_SHEBANG" -c "import graphify" 2>/dev/null && PYTHON="$_SHEBANG" ;;
esac
fi
@@ -865,7 +865,7 @@ if [ ! -f graphify-out/.graphify_python ]; then
GRAPHIFY_BIN=$(which graphify 2>/dev/null)
if [ -n "$GRAPHIFY_BIN" ]; then
PYTHON=$(head -1 "$GRAPHIFY_BIN" | tr -d '#!')
case "$PYTHON" in *[!a-zA-Z0-9/_.-]*) PYTHON="python3" ;; esac
case "$PYTHON" in *[!a-zA-Z0-9/_.@-]*) PYTHON="python3" ;; esac
else
PYTHON="python3"
fi
@@ -77,7 +77,7 @@ fi
if [ -z "$PYTHON" ] && [ -n "$GRAPHIFY_BIN" ]; then
_SHEBANG=$(head -1 "$GRAPHIFY_BIN" | tr -d '#!')
case "$_SHEBANG" in
*[!a-zA-Z0-9/_.-]*) ;;
*[!a-zA-Z0-9/_.@-]*) ;;
*) "$_SHEBANG" -c "import graphify" 2>/dev/null && PYTHON="$_SHEBANG" ;;
esac
fi
@@ -626,7 +626,7 @@ if [ ! -f graphify-out/.graphify_python ]; then
GRAPHIFY_BIN=$(which graphify 2>/dev/null)
if [ -n "$GRAPHIFY_BIN" ]; then
PYTHON=$(head -1 "$GRAPHIFY_BIN" | tr -d '#!')
case "$PYTHON" in *[!a-zA-Z0-9/_.-]*) PYTHON="python3" ;; esac
case "$PYTHON" in *[!a-zA-Z0-9/_.@-]*) PYTHON="python3" ;; esac
else
PYTHON="python3"
fi
@@ -77,7 +77,7 @@ fi
if [ -z "$PYTHON" ] && [ -n "$GRAPHIFY_BIN" ]; then
_SHEBANG=$(head -1 "$GRAPHIFY_BIN" | tr -d '#!')
case "$_SHEBANG" in
*[!a-zA-Z0-9/_.-]*) ;;
*[!a-zA-Z0-9/_.@-]*) ;;
*) "$_SHEBANG" -c "import graphify" 2>/dev/null && PYTHON="$_SHEBANG" ;;
esac
fi
@@ -629,7 +629,7 @@ if [ ! -f graphify-out/.graphify_python ]; then
GRAPHIFY_BIN=$(which graphify 2>/dev/null)
if [ -n "$GRAPHIFY_BIN" ]; then
PYTHON=$(head -1 "$GRAPHIFY_BIN" | tr -d '#!')
case "$PYTHON" in *[!a-zA-Z0-9/_.-]*) PYTHON="python3" ;; esac
case "$PYTHON" in *[!a-zA-Z0-9/_.@-]*) PYTHON="python3" ;; esac
else
PYTHON="python3"
fi
@@ -77,7 +77,7 @@ fi
if [ -z "$PYTHON" ] && [ -n "$GRAPHIFY_BIN" ]; then
_SHEBANG=$(head -1 "$GRAPHIFY_BIN" | tr -d '#!')
case "$_SHEBANG" in
*[!a-zA-Z0-9/_.-]*) ;;
*[!a-zA-Z0-9/_.@-]*) ;;
*) "$_SHEBANG" -c "import graphify" 2>/dev/null && PYTHON="$_SHEBANG" ;;
esac
fi
@@ -629,7 +629,7 @@ if [ ! -f graphify-out/.graphify_python ]; then
GRAPHIFY_BIN=$(which graphify 2>/dev/null)
if [ -n "$GRAPHIFY_BIN" ]; then
PYTHON=$(head -1 "$GRAPHIFY_BIN" | tr -d '#!')
case "$PYTHON" in *[!a-zA-Z0-9/_.-]*) PYTHON="python3" ;; esac
case "$PYTHON" in *[!a-zA-Z0-9/_.@-]*) PYTHON="python3" ;; esac
else
PYTHON="python3"
fi
@@ -77,7 +77,7 @@ fi
if [ -z "$PYTHON" ] && [ -n "$GRAPHIFY_BIN" ]; then
_SHEBANG=$(head -1 "$GRAPHIFY_BIN" | tr -d '#!')
case "$_SHEBANG" in
*[!a-zA-Z0-9/_.-]*) ;;
*[!a-zA-Z0-9/_.@-]*) ;;
*) "$_SHEBANG" -c "import graphify" 2>/dev/null && PYTHON="$_SHEBANG" ;;
esac
fi
@@ -621,7 +621,7 @@ if [ ! -f graphify-out/.graphify_python ]; then
GRAPHIFY_BIN=$(which graphify 2>/dev/null)
if [ -n "$GRAPHIFY_BIN" ]; then
PYTHON=$(head -1 "$GRAPHIFY_BIN" | tr -d '#!')
case "$PYTHON" in *[!a-zA-Z0-9/_.-]*) PYTHON="python3" ;; esac
case "$PYTHON" in *[!a-zA-Z0-9/_.@-]*) PYTHON="python3" ;; esac
else
PYTHON="python3"
fi
@@ -77,7 +77,7 @@ fi
if [ -z "$PYTHON" ] && [ -n "$GRAPHIFY_BIN" ]; then
_SHEBANG=$(head -1 "$GRAPHIFY_BIN" | tr -d '#!')
case "$_SHEBANG" in
*[!a-zA-Z0-9/_.-]*) ;;
*[!a-zA-Z0-9/_.@-]*) ;;
*) "$_SHEBANG" -c "import graphify" 2>/dev/null && PYTHON="$_SHEBANG" ;;
esac
fi
@@ -629,7 +629,7 @@ if [ ! -f graphify-out/.graphify_python ]; then
GRAPHIFY_BIN=$(which graphify 2>/dev/null)
if [ -n "$GRAPHIFY_BIN" ]; then
PYTHON=$(head -1 "$GRAPHIFY_BIN" | tr -d '#!')
case "$PYTHON" in *[!a-zA-Z0-9/_.-]*) PYTHON="python3" ;; esac
case "$PYTHON" in *[!a-zA-Z0-9/_.@-]*) PYTHON="python3" ;; esac
else
PYTHON="python3"
fi
@@ -77,7 +77,7 @@ fi
if [ -z "$PYTHON" ] && [ -n "$GRAPHIFY_BIN" ]; then
_SHEBANG=$(head -1 "$GRAPHIFY_BIN" | tr -d '#!')
case "$_SHEBANG" in
*[!a-zA-Z0-9/_.-]*) ;;
*[!a-zA-Z0-9/_.@-]*) ;;
*) "$_SHEBANG" -c "import graphify" 2>/dev/null && PYTHON="$_SHEBANG" ;;
esac
fi
@@ -627,7 +627,7 @@ if [ ! -f graphify-out/.graphify_python ]; then
GRAPHIFY_BIN=$(which graphify 2>/dev/null)
if [ -n "$GRAPHIFY_BIN" ]; then
PYTHON=$(head -1 "$GRAPHIFY_BIN" | tr -d '#!')
case "$PYTHON" in *[!a-zA-Z0-9/_.-]*) PYTHON="python3" ;; esac
case "$PYTHON" in *[!a-zA-Z0-9/_.@-]*) PYTHON="python3" ;; esac
else
PYTHON="python3"
fi
@@ -77,7 +77,7 @@ fi
if [ -z "$PYTHON" ] && [ -n "$GRAPHIFY_BIN" ]; then
_SHEBANG=$(head -1 "$GRAPHIFY_BIN" | tr -d '#!')
case "$_SHEBANG" in
*[!a-zA-Z0-9/_.-]*) ;;
*[!a-zA-Z0-9/_.@-]*) ;;
*) "$_SHEBANG" -c "import graphify" 2>/dev/null && PYTHON="$_SHEBANG" ;;
esac
fi
@@ -625,7 +625,7 @@ if [ ! -f graphify-out/.graphify_python ]; then
GRAPHIFY_BIN=$(which graphify 2>/dev/null)
if [ -n "$GRAPHIFY_BIN" ]; then
PYTHON=$(head -1 "$GRAPHIFY_BIN" | tr -d '#!')
case "$PYTHON" in *[!a-zA-Z0-9/_.-]*) PYTHON="python3" ;; esac
case "$PYTHON" in *[!a-zA-Z0-9/_.@-]*) PYTHON="python3" ;; esac
else
PYTHON="python3"
fi
@@ -651,7 +651,7 @@ if [ ! -f graphify-out/.graphify_python ]; then
GRAPHIFY_BIN=$(which graphify 2>/dev/null)
if [ -n "$GRAPHIFY_BIN" ]; then
PYTHON=$(head -1 "$GRAPHIFY_BIN" | tr -d '#!')
case "$PYTHON" in *[!a-zA-Z0-9/_.-]*) PYTHON="python3" ;; esac
case "$PYTHON" in *[!a-zA-Z0-9/_.@-]*) PYTHON="python3" ;; esac
else
PYTHON="python3"
fi
+2 -2
View File
@@ -77,7 +77,7 @@ fi
if [ -z "$PYTHON" ] && [ -n "$GRAPHIFY_BIN" ]; then
_SHEBANG=$(head -1 "$GRAPHIFY_BIN" | tr -d '#!')
case "$_SHEBANG" in
*[!a-zA-Z0-9/_.-]*) ;;
*[!a-zA-Z0-9/_.@-]*) ;;
*) "$_SHEBANG" -c "import graphify" 2>/dev/null && PYTHON="$_SHEBANG" ;;
esac
fi
@@ -629,7 +629,7 @@ if [ ! -f graphify-out/.graphify_python ]; then
GRAPHIFY_BIN=$(which graphify 2>/dev/null)
if [ -n "$GRAPHIFY_BIN" ]; then
PYTHON=$(head -1 "$GRAPHIFY_BIN" | tr -d '#!')
case "$PYTHON" in *[!a-zA-Z0-9/_.-]*) PYTHON="python3" ;; esac
case "$PYTHON" in *[!a-zA-Z0-9/_.@-]*) PYTHON="python3" ;; esac
else
PYTHON="python3"
fi
+1 -1
View File
@@ -71,7 +71,7 @@ fi
if [ -z "$PYTHON" ] && [ -n "$GRAPHIFY_BIN" ]; then
_SHEBANG=$(head -1 "$GRAPHIFY_BIN" | tr -d '#!')
case "$_SHEBANG" in
*[!a-zA-Z0-9/_.-]*) ;;
*[!a-zA-Z0-9/_.@-]*) ;;
*) "$_SHEBANG" -c "import graphify" 2>/dev/null && PYTHON="$_SHEBANG" ;;
esac
fi
+1 -1
View File
@@ -564,7 +564,7 @@ if [ ! -f graphify-out/.graphify_python ]; then
GRAPHIFY_BIN=$(which graphify 2>/dev/null)
if [ -n "$GRAPHIFY_BIN" ]; then
PYTHON=$(head -1 "$GRAPHIFY_BIN" | tr -d '#!')
case "$PYTHON" in *[!a-zA-Z0-9/_.-]*) PYTHON="python3" ;; esac
case "$PYTHON" in *[!a-zA-Z0-9/_.@-]*) PYTHON="python3" ;; esac
else
PYTHON="python3"
fi
+2 -2
View File
@@ -82,7 +82,7 @@ fi
if [ -z "$PYTHON" ] && [ -n "$GRAPHIFY_BIN" ]; then
_SHEBANG=$(head -1 "$GRAPHIFY_BIN" | tr -d '#!')
case "$_SHEBANG" in
*[!a-zA-Z0-9/_.-]*) ;;
*[!a-zA-Z0-9/_.@-]*) ;;
*) "$_SHEBANG" -c "import graphify" 2>/dev/null && PYTHON="$_SHEBANG" ;;
esac
fi
@@ -865,7 +865,7 @@ if [ ! -f graphify-out/.graphify_python ]; then
GRAPHIFY_BIN=$(which graphify 2>/dev/null)
if [ -n "$GRAPHIFY_BIN" ]; then
PYTHON=$(head -1 "$GRAPHIFY_BIN" | tr -d '#!')
case "$PYTHON" in *[!a-zA-Z0-9/_.-]*) PYTHON="python3" ;; esac
case "$PYTHON" in *[!a-zA-Z0-9/_.@-]*) PYTHON="python3" ;; esac
else
PYTHON="python3"
fi
+1 -1
View File
@@ -11,7 +11,7 @@ fi
if [ -z "$PYTHON" ] && [ -n "$GRAPHIFY_BIN" ]; then
_SHEBANG=$(head -1 "$GRAPHIFY_BIN" | tr -d '#!')
case "$_SHEBANG" in
*[!a-zA-Z0-9/_.-]*) ;;
*[!a-zA-Z0-9/_.@-]*) ;;
*) "$_SHEBANG" -c "import graphify" 2>/dev/null && PYTHON="$_SHEBANG" ;;
esac
fi
+14
View File
@@ -864,6 +864,19 @@ def _is_no_api_key_fix_line(line: str) -> bool:
return "graphify needs no API key" in line
def _is_shebang_allowlist_fix_line(line: str) -> bool:
"""Whether a line is part of the Homebrew ``python@`` shebang allowlist fix (#1586).
The interpreter-detection guard rejected any shebang containing a character
outside ``[!a-zA-Z0-9/_.-]``, but Homebrew installs versioned Python under
``python@3.13``, so a valid interpreter path legitimately contains ``@`` and
detection fell through to a bare ``python3`` that lacked graphify. ``@`` is now
allowed, matching the #473 hooks.py fix; injection chars are still rejected.
Both the old (removed) and new (added) allowlist forms match here.
"""
return "[!a-zA-Z0-9/_." in line
# Every line that may differ between a rendered monolith and its pristine v8
# baseline. Each predicate documents one sanctioned change-class; a blank line is
# allowed because the multi-line fix blocks insert spacing. Anything else failing
@@ -878,6 +891,7 @@ _SANCTIONED_MONOLITH_DIFFS = (
_is_zero_node_guard_fix_line,
_is_manifest_root_fix_line,
_is_no_api_key_fix_line,
_is_shebang_allowlist_fix_line,
)