Commit Graph

8 Commits

Author SHA1 Message Date
Dan Guido c199e0cc7d Narrow the modern-python shims to the commands uv run replaces (#255)
* Narrow the modern-python shims to the commands uv run replaces

Closes #207.

The shims sit on PATH, so they intercept every subprocess any tool
spawns, not just what Claude types. Two of the intercepted invocations
were not package management at all, and blocking them broke real tooling.

`uv pip` now passes through when it carries --project, --directory or
--target. Those say a tool is building an environment it owns, where
`uv add` is not the available advice: prek installs every hook with
`uv pip install --project / --directory <cache>`, so the refusal made
`git commit` fail in any repo whose hooks need a Python environment.
A bare `uv pip install requests` is still refused.

`python -c`, `python -m <module>` and `python -` now reach the real
interpreter. None of them resolves a script against a project's
dependencies, which is what `uv run` exists to do, and `uv run python3 -`
is not a drop-in replacement inside a pipeline. `python -m pip` stays
intercepted, as do bare `python` and `python script.py`.

Passing anything through is new for the python shim, which previously
ended every branch in exit 1, so it gains the same skip-my-own-dir PATH
walk the uv shim already had. That walk now uses parameter expansion
rather than basename, because the one case where it must report failure
is a PATH holding nothing but the shim, where shelling out to coreutils
fails first with a confusing error.

Verified by A/B on the two symptoms #207 reports, running each suite
against the old shim and the new one:

- zeroize-audit's rust-regression smoke test: FAILED at line 72 before,
  "Rust regression smoke checks passed." after.
- prek hook installation from a cold cache: refused before, "check json
  Passed" after.

bats goes from 19 cases to 38. Five python cases inverted rather than
being deleted: the ones asserting that -c and -m are refused now assert
they run. AGENTS.md's note on `make shell-suites` is corrected rather
than removed — the #207 interceptions are gone, but the target still
fails because variant-analysis invokes `python3 <script>.py`, which the
shim intercepts by design. That one belongs to variant-analysis.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* Decide on the mode selector, not on argument position

Two gaps in the narrowing, both from review.

`uv pip install --help` documents `-t, --target <TARGET>`, so the short
form has to be exempt alongside the long one. Without it the same
tool-managed install was allowed or refused depending on spelling.

The python shim read only $1 to find the mode selector, so `python -u -c
'code'` was refused while `python -c 'code'` ran, even though they are
the same invocation. It now steps over interpreter flags to find the
selector, giving `-W`, `-X` and `--check-hash-based-pycs` the two slots
they take. `-u -m pip` is still refused, and so is `-u script.py`: a
script path is what `uv run` replaces regardless of what precedes it.

bats 38 -> 43. Both #207 regressions re-verified after the restructure:
zeroize-audit's smoke test passes and prek installs hooks from a cold
cache.

Not fixed here, deliberately: `uv --no-progress pip install requests`
still slips past the refusal, because the subcommand check reads $1 as
well. Parsing that correctly means knowing which uv global flags take a
value, and getting it wrong would refuse a command that works today. The
failure mode is a missed nudge rather than a breakage — the real uv runs
and behaves correctly — so it does not belong in a change whose purpose
is to refuse less.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-18 20:35:44 -04:00
William Tan 3b316e6ac7 fix(modern-python): suggest exact uv run python so shim advice works outside projects (#196)
* fix(modern-python): suggest exact `uv run python` so the advice works outside projects

The python/python3 shim suggested `uv run $cmd ...`, echoing back whichever
name was invoked. For `python3` that advice is self-defeating on machines
with no uv-managed interpreters: uv resolves the `python3` command through
an ordinary PATH lookup, which hits the shim again and fails with the same
suggestion. uv special-cases the exact command name `python` (uv >= 0.4.0)
and executes its resolved interpreter directly, so always suggesting
`uv run python ...` works everywhere.

Reproduced on stock Debian + uv 0.11.27 (apt python3, zero managed
pythons, no project): `uv run python3 script.py` fails via the shim while
`uv run python script.py` succeeds, across script/-c/-m/REPL forms.

Reported in #195.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* fix(modern-python): satisfy shellcheck SC2016 in new bats assertions

Escaped backticks in double quotes instead of literal backticks in
single quotes, which shellcheck flags as a possible unintended
non-expansion.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* fix(modern-python): requote shim suggestions and carry all arguments through

Review findings on #196: the -m branch interpolated only the module name,
so `python -m http.server 8000` suggested a command missing the port, and
`${*}` flattened arguments without quoting, so `python -c 'print(1+1)'`
suggested a command that is a bash syntax error if run verbatim (plus a
trailing space inside the backticks for bare invocations). Both branches
now build the suggestion from %q-requoted arguments, with regression tests
for each case.

Also consolidates the exact-`python` rationale into a single canonical
copy in the shim's header comment; README, setup-shims.sh, and the bats
file now point there instead of paraphrasing it.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
2026-07-29 15:16:05 -04:00
William Tan dc1bc277f0 Also hook pipx (#90)
* Also hook pipx

* fix: resolve code review findings for PR #90

- Add upgrade-all case to pipx shim (pipx upgrade-all → uv tool upgrade --all)
- Add ensurepath case to pipx shim (pipx ensurepath → uv tool update-shell)
- Update setup-shims.sh comment to mention pipx
- Add README rows for upgrade-all and ensurepath mappings
- Add tests for upgrade-all, ensurepath, and unknown subcommand
- Rename generic ensurepath test to unknown subcommand test

P2 fixed: missing upgrade-all subcommand mapping
P3 fixed: stale setup-shims.sh comment, ensurepath deserves specific mapping
P3 dismissed: -ne 0 vs -eq 1 in tests (matches existing convention)
P4 noted: pipefail no-op, Gemini false positive on bats syntax

All 37 bats tests pass. Shellcheck clean.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Dan Guido <dan@trailofbits.com>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-13 14:43:27 -05:00
William Tan 994fe9687b use PATH shim override technique instead of hooking every pre tool usage (#89)
* use PATH shim override technique instead of hooking every pre tool usage

* remove unecessary check

* fix: resolve code review findings for PR #89

P1 fixes:
- setup-shims.sh: Add CLAUDE_ENV_FILE guard to prevent opaque
  'unbound variable' crash when env var is unset (matches
  gh-cli plugin pattern)

P2 fixes:
- setup-shims.sh: Guard shims_dir resolution failure to prevent
  empty PATH prefix on partial installs
- shims/uv: Fix shfmt formatting (here-string spacing)
- shims/uv: Resolve PATH entries before comparison to prevent
  exec loop with symlinked/unnormalized paths
- shims/uv: Use ${PATH:-} to handle unset PATH defensively
- setup-shims.bats: Add test for unset CLAUDE_ENV_FILE
- uv-shim.bats: Add test for 'real uv not found' error path

P3 dismissed:
- CI linting gap for extensionless shim scripts: accepted as-is
  since shims must masquerade as real binaries (no .sh extension);
  manual review covers these files
- Unset PATH in uv shim: addressed by ${PATH:-} fix above

All 27 bats tests pass. shellcheck and shfmt clean.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Dan Guido <dan@trailofbits.com>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-12 22:16:40 -05:00
William Tan 4aeaa737f6 Add hook to modern-python to intercept python3 and pip calls (#40)
* Add hook to modern-python to intercept python3 and pip calls

Uses tree-sitter-bash parse the AST for more robust hooking

* Fix ruff line-length lint in intercept-legacy-python hook

Run ruff format to properly break long lines into multi-line tuples.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* Rewrite legacy Python hook in shell for performance

Replace tree-sitter-based Python implementation with a shell script
using jq and regex patterns. This eliminates the overhead of spawning
Python and loading tree-sitter on every Bash command.

- Use jq for JSON parsing (fast, commonly available)
- Regex-based pattern matching for python/pip commands
- Allow uv run commands to pass through
- Context-aware suggestions based on subcommand
- Passes shellcheck validation

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* Allow diagnostic commands and simplify error message

- Skip `which`, `type`, `whereis`, `command -v` for python/pip
- Simplify denial message (Claude already knows uv commands)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* Allow search tools through legacy Python hook

Add allowlist for grep, rg, ag, ack, find to prevent false positives
when searching for "python" or "pip" as text patterns. Also normalize
character class ordering for consistency with other patterns.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* Fix shfmt formatting (2-space indent)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* Add hook development guidance to CLAUDE.md

Document design lessons from PR #40's Python-to-shell rewrite:
- Performance: prefer shell+jq over Python with dependencies
- Simplicity: accept false positives when performance gain is worth it
- False positive awareness: diagnostic commands, search tools, filenames
- Explicit tradeoff documentation in PR descriptions

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* Refine CLAUDE.md formatting for consistent density

Remove section breaks (horizontal rules) between major sections and
condense the Hooks section from verbose multi-paragraph format into
a unified list while preserving all guidance.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
Co-authored-by: Dan Guido <dan@trailofbits.com>
2026-01-26 19:03:08 -05:00
Dan Guido 0c9da5d813 Update modern-python README to reflect current skill coverage (#39)
- Rewrite "When to Use" with specific, outcome-focused triggers
- Add security tools section (shellcheck, detect-secrets, actionlint, zizmor, pip-audit, Dependabot)
- Add prek and ty to core tools
- Group into Core Tools, Security Tools, and Standards sections

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-26 14:27:24 -05:00
Dan Guido bcd1d25c76 Fix Python version in README (3.10 -> 3.11) (#38)
The skill content consistently uses 3.11 as the minimum version.

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-26 14:20:32 -05:00
William Tan 4e5828f6f2 Add modern python best practices skill (#22)
* add modern python best practices skill

* update README and update markeplace metadata

* make description more direct and shorter

* update description

* Update plugins/modern-python/skills/modern-python/SKILL.md

Co-authored-by: dm <darkamaul@hotmail.fr>

* Reorganize reference files and fix issues

- Move reference files to references/ directory per CLAUDE.md convention
- Update all links in SKILL.md to point to new paths
- Fix typo: closing code fence had extra dot character
- Add version pinning notes in prek.md with links to release pages
- Update ty version from 0.0.12 to 0.0.13

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* Fix review feedback: typos, fragile command, SHA pinning

- Fix "Trail Of Bits" → "Trail of Bits" and "boostrap" → "bootstrap"
- Replace fragile shell one-liner for requirements.txt migration with
  robust while-read loop that handles version specifiers properly
- Pin GitHub Actions to SHA with version comments:
  - actions/checkout@v6.0.1
  - j178/prek-action@v1.0.12
  - codecov/codecov-action@v5.5.2
- Update uv_build version constraint to >=0.9,<1 to prefer latest
- Add note about preferring open version constraints for rapidly
  evolving tools
- Fix prek description to be factual rather than marketing copy

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* Add Dependabot configuration with 7-day cooldown

Adds recommended .github/dependabot.yml configuration for:
- Python (pip) dependencies
- GitHub Actions

Includes cooldown.default-days: 7 for supply chain protection,
which delays updates for newly published versions to allow time
for community detection of compromised packages.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* Replace hardcoded versions with <latest> placeholders

Add release URLs as comments so Claude looks up current versions
when using the skill instead of using stale training data.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* Extract Dependabot configuration to separate reference file

Move Dependabot content from prek.md to dedicated dependabot.md
for better organization and discoverability.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* Add [tool.ty.rules] configuration example

Show how to configure individual rule severities for stricter
type checking, including possibly-unbound, possibly-unresolved-reference,
and unused-ignore-comment.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* Address review feedback: fix section titles and Makefile scope

- prek.md: Remove lint/format targets from Makefile (not prek-specific)
- pep723-scripts.md: Rename "Optional Dependencies" → "Private Package Index"
  to match the actual content (extra-index-url configuration)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

---------

Co-authored-by: dm <darkamaul@hotmail.fr>
Co-authored-by: Dan Guido <dan@trailofbits.com>
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-26 12:36:49 -05:00