Repository navigation
Vendored PyPI wheels aren't checked against .gitignore or Git LFS rules (*.whl, .socket/), so a vendored Pipenv scan exits 0 and every fresh clone's pipenv sync fails #1572
Description
[agent] Found by the scheduled Pipenv bug-hunt routine (ledger #313).
Summary
Vendored PyPI writes the patched wheel to .socket/vendor/pypi/<uuid>/<name>-<ver>-….whl with no .gitignore check and no owned .gitignore / .gitattributes in the uuid directory. npm (#831 / #837, #1541 / #1559), Maven / Gradle / NuGet (#1061 / #1330) and bun (#1116) all have this protection, but PyPI doesn't. So when the project ignores *.whl or .socket/, or tracks *.whl with Git LFS, scan --mode vendored exits 0 with no warning, and the commit drops the wheel or stores an LFS pointer instead. Pipfile.lock is committed pointing at ./.socket/vendor/pypi/<uuid>/six-….whl, so every fresh clone fails pipenv sync / pipenv install --deploy. CI and teammates can't install at all until someone tracks down the ignore rule.
The vendor code is shared, so the same gap almost certainly hits pip requirements.txt, uv, Poetry and PDM vendored wheels. I only proved it with Pipenv.
Impact
vendor/scan --mode vendoredreports success, and the local tree works (the wheel is on disk), so nothing looks wrong until a fresh checkout breaks.*.whlignore rules are common in Python repos (to keeppip wheel/python -m buildoutput out of git), and so are LFS rules for*.whl.- It fails closed later (sync errors out,
vendor --checkexits 1 on the clone), so it isn't a silent unpatch. But it's the same "commit silently drops the payload" class as Vendored yarn classic exits 0 when .gitignore covers the vendored tarball (*.tgz,vendor/,.socket/), so the commit drops it and every fresh checkout's install fails #831 / Vendored Gradle exits 0 when the project's .gitignore excludes *.jar, so the commit silently drops the patched jar and every fresh checkout fails to build #620 / Vendored Maven, Gradle and NuGet artifacts can be git-ignored silently, because only npm checks .gitignore #1061, which were fixed for the other backends.
Repro (Linux, main e76cb9b, Pipenv 2026.9.1 and 2023.12.1, py3.11)
mkdir proj && cd proj && git init -q
cat > Pipfile <<'EOF'
[[source]]
url = "https://pypi.org/simple"
verify_ssl = true
name = "pypi"
[packages]
six = "==1.16.0"
[requires]
python_version = "3.11"
EOF
pipenv lock --python python3.11
echo '*.whl' > .gitignore # or '.socket/'
git add -A && git commit -qm base
socket-patch scan --mode vendored --json --yes # status success, warnings [], exit 0
git add -A && git commit -qm vend # the wheel is NOT added
git check-ignore -v .socket/vendor/pypi/*/six-1.16.0-py2.py3-none-any.whl
# .gitignore:1:*.whl .socket/vendor/pypi/<uuid>/six-1.16.0-py2.py3-none-any.whl
git clone -q . ../clone && cd ../clone
socket-patch vendor --check --json # partialFailure, exit 1
pipenv sync # exit 1
# Requirement './.socket/vendor/pypi/<uuid>/six-1.16.0-py2.py3-none-any.whl' looks like a filename, but the file does not existLFS variant: with git lfs install --local and .gitattributes set to *.whl filter=lfs diff=lfs merge=lfs -text, the vendored scan exits 0 and git lfs ls-files lists the vendored wheel. A checkout without LFS (GIT_LFS_SKIP_SMUDGE=1 git clone, or CI without lfs: true) gets the 130-byte pointer, and pipenv sync fails with ERROR: Wheel 'six' located at …/six-1.16.0-py2.py3-none-any.whl is invalid.
Patch data came from a local mock of the public patch proxy serving a patched real six-1.16.0 wheel (sha256 + sha512 grant), so no Socket credentials were involved.
Expected vs actual
- Expected: the same as the other vendored backends (docs/ecosystems.md, the npm and JVM vendored sections,
vendor_artifact_gitignored). Either the uuid directory owns a.gitignore(!*) that re-includes the wheel against file rules like*.whl, plus a.gitattributes(* -text -filter …) against LFS / EOL filters, or the scan refuses withvendor_artifact_gitignoredbefore writing when a rule such as.socket/covers the tree. - Actual: exit 0,
warnings: [], the wheel is ignored or LFS-captured, and fresh clones can't install.
Matrix
| OS | Pipenv | *.whl in .gitignore |
.socket/ in .gitignore |
LFS *.whl (LFS-less clone) |
|---|---|---|---|---|
| Linux | 2026.9.1 | fail (sync exit 1) | fail (sync exit 1) | fail (Wheel … is invalid) |
| Linux | 2023.12.1 | fail (sync exit 1) | fail (sync exit 1) | not run |
| macOS / Windows | — | untested (probe branches are blocked for this routine) |
Each failing cell was reproduced 2 times. Control: with no ignore or LFS rule, the clone syncs PATCHED.
Suspect code
crates/socket-patch-core/src/vendor/pypi.rs:713(vendor_pypi) and:1008(vendor_uuid_dir_rel("pypi", …)): the wheel goes into the uuid dir with nonpm_dir::gitignoredprobe and no owned.gitignore/.gitattributes.- Compare
crates/socket-patch-core/src/vendor/npm_common.rs:221(npm_tarball_gitignore_preflight),npm_dir.rs:450(gitignored), and the JVM / NuGet tree.gitignorefrom Fix vendored JVM/NuGet artifacts dropped by .gitignore (#1061) #1330. Vendored Maven, Gradle and NuGet artifacts can be git-ignored silently, because only npm checks .gitignore #1061 proposed hoisting this into the shared vendored sink, but the fix covered only JVM / NuGet. - The hosted → vendored takeover should run the preflight before it restores the registry entry, as npm's preflight comment explains.
No probe runs: macOS / Windows probe branches are blocked for this routine (branch deletion is refused).
Activity
mikolalysenko commentedon Oct 15, 2026
[agent] Triaged: priority:p1 (PyPI/Pipenv). Confirmed on main
e76cb9bby reading the code: none of the PyPI vendor modules (crates/socket-patch-core/src/vendor/pypi*.rs) write a per-uuid.gitignore/.gitattributesor run thevendor_artifact_gitignoredpreflight that npm (npm_common.rsnpm_tarball_gitignore_preflight), NuGet (nuget_feed.rswrite_uuid_gitignore) and the JVM trees use. The gap is in the shared wheel staging path, so it applies to every PyPI vendored lane (requirements, uv, Poetry, PDM, Pipenv, Hatch), not only Pipenv. No duplicate or existing fix PR found.Generated by Claude Code
mikolalysenko commentedon Oct 15, 2026
[agent] Claiming this issue (shared root cause: the PyPI vendored backends write the wheel into
.socket/vendor/pypi/<uuid>/with no gitignore probe and no owned.gitignore/.gitattributes). Branch: agent/fix-pypi-vendor-gitignore. Claim-ID: 2026-10-15T22:21:28Z-b4685eGenerated by Claude Code
mikolalysenko commentedon Oct 15, 2026
[agent] Draft PR: #1593
Generated by Claude Code
Keep vendored PyPI wheels out of gitignore/LFS
Test the PyPI takeover under a .socket/ rule
Heal uuid dotfiles on re-runs and repair
Keep an in-sync rebuilt wheel on commit failures