Skip to content

Global scan (-g) never crawls pipx venvs, so the dependencies of a pipx-installed Hatch are never reported, patched or rolled back on any OS #415

Description

[agent] Found by the scheduled Hatch bug-hunt routine (ledger #314).

Summary

pipx is one of Hatch's documented install methods (pipx install hatch). Each pipx app gets its own venv: ~/.local/share/pipx/venvs/<app> on Linux (pipx ≥ 1.3), ~/.local/pipx/venvs/<app> on macOS, and %USERPROFILE%\pipx\venvs\<app> on Windows. get_global_python_site_packages probes uv tool venvs (~/.local/share/uv/tools/*, %LOCALAPPDATA%\uv\tools), conda, pyenv, Homebrew, the python.org framework and pip --user, but not pipx venvs. As a result:

  • scan -g (report-only) doesn't crawl the pipx Hatch venv at all. On Linux, scannedPackages is the same (102) whether or not a 96-entry pipx Hatch venv is present. A uv-tool-installed Hatch adds 30 to the count.
  • scan -g --mode agent / apply -g never patch the copy inside the pipx venv. With six==1.16.0 injected into the pipx Hatch venv (pipx inject hatch six==1.16.0, byte-identical to PyPI's wheel), the patch applies to 0 files. Control: the same six inside a uv tool install hatch venv is patched, and rollback -g restores it byte for byte.

The agent run exits 1 partial_failure with applied: 0, but nothing tells the user that a whole tool venv was skipped. The run says nothing about pipx at all.

Impact

Anyone who installs Hatch (or any Python CLI) the way Hatch's docs suggest, through pipx, can't patch that tool's dependencies with -g, and scan -g gives an incomplete inventory of global installs. The code's own doc comment says global discovery covers "Homebrew, conda, uv tools, pip --user, etc.", so leaving out pipx (the other mainstream tool installer) looks like an oversight rather than a documented limitation. Neither README.md nor CLI_CONTRACT.md mentions pipx.

Repro (Linux; macOS and Windows identical, see the probe)

Mock patch API serving a patched six 1.16.0 (same mock as the #335 probe, plus integrity.sha512).

SP="socket-patch --api-url http://127.0.0.1:18080 --api-token fake --org test-org --patch-server-url http://127.0.0.1:18080 --ecosystems pypi"
python -m venv pv && pv/bin/pip install pipx==1.7.1
pv/bin/python -m pipx install hatch==1.18.1
pv/bin/python -m pipx inject hatch six==1.16.0
ls ~/.local/share/pipx/venvs/hatch/lib/python3.11/site-packages/six.py   # present
mkdir w && cd w
$SP scan -g --json        # scannedPackages unchanged vs. without the pipx venv
$SP scan -g --mode agent --json --yes
#  -> exit 1, status partial_failure, apply.applied 0
grep -c SOCKET_PATCHED ~/.local/share/pipx/venvs/hatch/lib/python3.11/site-packages/six.py   # 0

# control: the same thing through uv tool works
uv tool install hatch==1.16.5 --with six==1.16.0
$SP scan -g --mode agent --json --yes   # applied 1; ~/.local/share/uv/tools/hatch/.../six.py patched
$SP rollback -g --json                  # restored byte for byte

Reproduced twice locally (main 2463257, release build), plus the probe below.

Expected vs actual

  • Expected: CLI_CONTRACT.md: --global / -g "Operate on globally-installed packages". Global discovery already treats per-tool venvs (uv tools) as global installs. pipx venvs ($PIPX_HOME/venvs/*, default per platform as above, honouring PIPX_HOME) should be crawled the same way, so scan -g reports them and apply -g / rollback -g / vex -g reach them.
  • Actual: pipx venvs are invisible to every -g command on all three OSes.

OS × Hatch version (pipx 1.7.1, Python 3.11, scan -g --mode agent)

1.7.0 1.16.5 1.18.1
Linux (sandbox + ubuntu-latest, ~/.local/share/pipx/venvs) repro repro repro
macOS (macos-latest, ~/.local/pipx/venvs) repro repro repro
Windows (windows-latest, C:\Users\runneradmin\pipx\venvs) repro repro repro

Working as designed in the same probe, on all 9 cells: scan -g is report-only and leaves pyproject.toml untouched when run inside a Hatch project; scan -g --mode hosted exits 2 ("global installs have no project lockfile to redirect"); --global-prefix "<dir with space>/ünï/site-packages" agent apply patches, vex attests not_affected, and rollback is byte-exact.

First bad

Not a regression: pipx has never been in get_global_python_site_packages. v4.0.0 has the same discovery list.

Suspect code

  • crates/socket-patch-core/src/crawlers/python_crawler.rs:1073 get_global_python_site_packages. The uv-tools arms at :1250–:1290 are the model: add $PIPX_HOME/venvs/*/{lib,lib64}/python3.*/site-packages (Unix) and …\venvs\*\Lib\site-packages (Windows), using pipx's defaults when PIPX_HOME is unset (~/.local/share/pipx, legacy ~/.local/pipx, macOS ~/Library/Application Support/pipx, Windows %USERPROFILE%\pipx).

Probe

https://github.com/SocketDev/socket-patch/actions/runs/36812282643 (ubuntu, macos and windows × Hatch 1.7.0 / 1.16.5 / 1.18.1; every cell reproduces).

Activity

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions