Repository navigation
Lock-only requirements.txt discovery sends PEP 440-equivalent pins verbatim (six==1.16 → pkg:pypi/six@1.16), so a fresh checkout reports "No patches available" while the same file with a venv is patched #604
Description
Activity
- addedbugSomething isn't workingSomething isn't workingbughuntFound by a scheduled package-manager bug-hunt agentFound by a scheduled package-manager bug-hunt agentpm:pippip / requirements.txtpip / requirements.txt
on Oct 2, 2026 mikolalysenko commented
on Oct 2, 2026 CollaboratorAuthorMore actions[agent] Triaged as
priority:p1(pip, PyPI family). It isn't a duplicate: this is the lock-only follow-up that #478 left open on #475. I found no open PR for it. The cause is inutils/requirements.rsexact_pin, which returns the version as spelled.vendor/lock_inventory/pypi.rsthen uses that spelling in the lock-only purl, and it never gets PEP 440 normalization.
Generated by Claude Code
- added a commit that references this issue
on Oct 2, 2026 - addedv5-blockerMust resolve before v5: public interface/migration or ordinary patch-install-undo failure.Must resolve before v5: public interface/migration or ordinary patch-install-undo failure.uxCLI commands, help, diagnostics, output consistency, or actionable recovery instructions.CLI commands, help, diagnostics, output consistency, or actionable recovery instructions.compatibilityPublic CLI/JSON, saved state, upgrades, or package-manager compatibility.Public CLI/JSON, saved state, upgrades, or package-manager compatibility.and removed
on Oct 8, 2026 mikolalysenko commented
on Oct 9, 2026 CollaboratorAuthorMore actionsv5 release blocker (P1). A fresh lockfile-only requirements scan should find the same patch for PEP 440-equivalent version spellings as an installed project.
This follows the maintainer's release scope: one normally completing CLI instance, prioritizing valid-lockfile patch/install behavior, compatibility, and actionable CLI UX.
mikolalysenko commented
on Oct 9, 2026 CollaboratorAuthorMore actions[agent] Claiming for v5 blocker burn-down (shared root cause: lock-only requirements discovery builds the purl from the spelled == version, not the PEP 440 canonical release). Branch: agent/v5-pypi-pep440-lockonly. Claim-ID: 20261009T164145Z-338260
mikolalysenko commented
on Oct 9, 2026 CollaboratorAuthorMore actions[agent] Architecture audit (ecosystems and formats): this is one symptom of #1365. requirements.txt exact pins are read by three grammars:
utils::requirements::exact_pin(inventory and VEX), the hostedrequirement_version, and the vendoredparse_requirement_line/scan_pins. They disagree on PEP 440 equality (this issue), on parentheses (six (==1.16.0)is refused by vendored only) and on===. #1365 proposes one sharedRequirementparse with a PEP 440exact_version(), on top of which this fix becomes a one-place change.
Generated by Claude Code
- added a commit that references this issue
on Oct 9, 2026
[agent] Found by the scheduled pip / requirements.txt bug-hunt routine (ledger #309).
Summary
#478 fixed #475 for projects with an installed venv: the hosted rewriter and the vendored writer now compare
==pins under PEP 440. Lock-only discovery (no venv, e.g. a fresh CI checkout) still builds the purl from the version as spelled.six==1.16is queried aspkg:pypi/six@1.16,six==1.16.0.0as@1.16.0.0, andsix==01.16.0as@01.16.0. pip resolves all three to the registry release1.16.0, but the patch is keyedpkg:pypi/six@1.16.0, so discovery finds nothing.scanexits 0 with "No patches available", nothing is rewritten, andpip install -rinstalls the unpatched release.This is the follow-up the #478 author flagged on #475 ("on a lock-only checkout with no venv,
exact_pinstill carries the spelled version into the purl … left for a separate change"). I couldn't find an issue tracking it, so this one does.Impact
The result depends on whether a venv happens to exist. On a developer machine with a venv, the file is rewritten to the patched wheel. In CI, or on any fresh checkout, the same file is left alone, exit 0, and the unpatched release is installed. Hosted and vendored modes are both affected.
Repro (Linux, pip 24.0 / CPython 3.11, main
045d7ec)The mock patch API serves one patch for
pkg:pypi/six@1.16.0and matches purls exactly. It has the same shape as the wiremock incrates/socket-patch-cli/tests/mode_migration_pypi.rs.VIRTUAL_ENVpoints at an empty venv so the host's dist-packages don't confound the result.Expected vs actual
==pin like pip does. Per PEP 440,==1.16selects the1.16.0release, and Fix requirements.txt pins not matched under PEP 440 (#475) #478 already applies that rule to the rewriters. docs/ecosystems.md says requirements.txt lock-only checkouts are discovered in hosted and vendored modes, so the patch should be found and the line rewritten, as it is with a venv.six==1.16.0six@1.16.0six==1.16six@1.16six==1.16.0.0six@1.16.0.0six==01.16.0six@01.16.0six==1.16with a venv holding 1.16.0six@1.16.0(crawler)It never worked, so this isn't a regression: lock-only
six==1.16was also unmatched before #478.Suspect code
crates/socket-patch-core/src/utils/requirements.rs:104(exact_pinreturns the spelled version), used bycrates/socket-patch-core/src/vendor/lock_inventory/pypi.rs:645to build the lock-only purl.crates/socket-patch-cli/src/commands/scan/discovery.rs:105(lockfile_only_contains) already bridges version spellings for composer (@3.0.2≡@3.0.2.0), but not for pypi.Possible directions: query the canonical PyPI release spelling (the JSON API, or the index), or send PEP 440 zero-padded variants and match the API's purl back with
pep440::versions_equal.Backlog review — 2026-10-08
Priority: P1 → P2. PEP 440-equivalent lock-only pins miss available patches; installed discovery/exact normalized pins provide a workaround.