testsAndMisc/meta/scripts/check_no_inline_python.sh
Krzysztof kuhy Rudnicki 17b20e5fae Gate the no-inline-Python rule instead of asking people to remember it
CLAUDE.md's longest and most emphatic code rule -- never embed Python program
logic in a shell script -- was enforced by nothing. A repo-wide scan found it
had already been violated: install_plagiarism_tools.sh ran a 6-line NLTK
download as an inline `python3 -c`, invisible to ruff, mypy, pylint, bandit
and pytest, exactly the failure mode the rule exists to prevent.

check_no_inline_python.sh flags heredocs and multi-line `python -c` while
permitting the single-line availability probes the rule explicitly allows, so
the ~250 shell files here produce zero false positives. Commented-out examples
are skipped; otherwise the rule's own documentation would fail the hook.

The extracted download_nltk_data.py also fixes a real defect: the inline block
ignored nltk.download()'s return value, so a partial corpus download reported
success. It now returns non-zero and the caller's `set -e` sees it.

nltk is imported via importlib inside main(), not at module scope: it belongs
to the plagiarism toolchain, not this repo, so it is absent from
requirements.txt and unresolvable to pylint as a static import.

No suppressions anywhere: T201 avoided with sys.stderr.write, INP001 with a
shebang (matching sibling fast_count.py), E0401 with the dynamic import.
pylint 10.00/10, ruff clean, mypy clean.

Verified the gate fires rather than passing vacuously -- a staged canary with
a real heredoc exits non-zero -- and that the extracted script runs.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011w2Pj4Ek3ZNMQVYcFHgXDY
2026-08-16 15:11:56 +02:00

63 lines
2.5 KiB
Bash
Executable File

#!/usr/bin/env bash
# Block Python program logic embedded inline in a shell script.
#
# Inline Python is invisible to the repo's Python tooling: ruff, mypy, pylint,
# bandit and pytest all skip it, so it is the one place a type error or a
# security finding can live undetected. Extract it to a .py file under
# python_pkg/ and invoke it as `python3 "$(dirname "$0")/helper.py" "$arg"`.
#
# Permitted, and deliberately not flagged: a SINGLE-LINE availability or
# version probe with no logic, e.g.
# python3 -c 'import kasa'
# python -c "import sys; print(sys.version_info[0])"
# These carry no logic worth linting -- they are a yes/no question about the
# interpreter, and extracting them to a file would be sillier than inlining.
#
# Used as a pre-commit hook; receives staged file paths as arguments.
set -uo pipefail
errors=()
# A `python <<EOF` / `python3 <<-'PY'` heredoc: always real logic, never a
# probe. Matches an optional redirect target so `python3 <<'PY' >out` is caught.
readonly HEREDOC_RE='(^|[^[:alnum:]_])python3?[[:space:]]+<<-?'
# The opening of a `python -c "` whose closing quote is NOT on the same line,
# i.e. a multi-line inline program. A single-line -c closes its own quote and
# so does not match.
readonly MULTILINE_C_RE='(^|[^[:alnum:]_])python3?[[:space:]]+(-[[:alnum:]]+[[:space:]]+)*-c[[:space:]]*("[^"]*$|'"'"'[^'"'"']*$)'
for file in "$@"; do
case "$file" in
*.sh | *.bash | *.zsh) ;;
*) continue ;;
esac
[[ -f "$file" ]] || continue
while IFS=: read -r lineno text; do
[[ -z "${lineno:-}" ]] && continue
stripped="$(printf '%s' "$text" | sed 's/^[[:space:]]*//')"
# A commented-out example is documentation, not shipped logic. Without
# this, the rule's own explanatory comments would fail the hook.
[[ "$stripped" == \#* ]] && continue
errors+=("$file:$lineno: $stripped")
done < <(grep -nE "$HEREDOC_RE|$MULTILINE_C_RE" "$file" 2>/dev/null || true)
done
if [[ ${#errors[@]} -gt 0 ]]; then
echo "ERROR: Python program logic embedded in a shell script."
echo "Inline Python is skipped by ruff, mypy, pylint, bandit and pytest."
echo ""
for err in "${errors[@]}"; do
echo " $err"
done
echo ""
echo "Move the code to its own .py file and call it:"
echo " python3 \"\$(dirname \"\$0\")/helper.py\" \"\$arg\" # bash"
echo " python3 \"\${0:A:h}/helper.py\" \"\$arg\" # zsh"
echo ""
echo "A single-line probe such as python3 -c 'import kasa' is allowed."
exit 1
fi