Repository navigation
Fix PyPI direct refs not contesting wiring (#1549) - #1562
Conversation
Assisted-by: Claude Code:claude-opus-5-5
A Pipfile.lock `file` url or `path` wheel, or a requirements line like `six @ https://...whl`, installs the upstream release. Discovery took such a reference for no evidence at all, so when another lock wired the same release to a Socket patch, `vendor --check` stayed green and `vex` attested not_affected while `pipenv sync` / `pip install -r` shipped the unpatched package. These references now count as resolving the package elsewhere, exactly like a registry `==` pin: the other lock's wiring is withheld with patched_ref_unattributable naming both files. The release comes from an exact `version` pin or the wheel / sdist filename. A reference with no readable version (a source directory, a VCS checkout) may install any version, so it contests every version of that package. Fixes #1549 Assisted-by: Claude Code:claude-opus-5-5
End-to-end cells for #1549: the real CLI wires a Pipfile.lock or a requirements.txt, then a second install source pins the same release to a non-Socket url or wheel path. `vex` must withhold the statement and explain the contest, as it already does for a registry pin. Assisted-by: Claude Code:claude-opus-5-5
Review follow-ups for #1549. pip installs `-e git+...#egg=six` and a bare `git+...#egg=six` line from source, so both now count as resolving six elsewhere at any version. A Pipfile.lock wheel's own filename now decides its release ahead of a `version` pin beside it, and a wildcard pin like `==1.16.*` is never taken for a release. The "which packages does any lock resolve" query keeps its old meaning. Assisted-by: Claude Code:claude-opus-5-5
Pipenv installs from Pipfile.lock only when its Pipfile sits beside it. A user's own file/path/VCS entry in a leftover lock with no Pipfile installs nothing, so it no longer contests a requirements.txt wiring, and a hosted scan still redirects requirements.txt there (#333). Refs #1549 Assisted-by: Claude Code:claude-opus-5-5
|
BugBot review Generated by Claude Code |
`#egg=six-1.16.0` names the package six, not "six-1.16.0". The egg name now stops at the first `-<digit>`, so a legacy editable or VCS line still contests a Socket wiring of the real package (#1549, Bugbot). Assisted-by: Claude Code:claude-opus-5-5
|
BugBot review Generated by Claude Code |
|
Ready for review at
Generated by Claude Code |
Final review brief: #1562 at
|
pip accepts `-e./src/six#egg=six`, the value attached to the short option. Discovery skipped that spelling, so such a line didn't contest a Socket wiring of six (#1549, final-review note). Assisted-by: Claude Code:claude-opus-5-5
|
BugBot review Generated by Claude Code |
There was a problem hiding this comment.
✅ Bugbot reviewed your changes and found no new issues!
Comment @cursor review or bugbot run to trigger another review on this PR
Reviewed by Cursor Bugbot for commit 07503e7. Configure here.
|
Auto-merge disarmed. Generated by Claude Code |
Final review brief: #1562 at
|
|
Still ready for review at the new head
Slack announcement not sent this run (Slack send unavailable); the next run retries. Generated by Claude Code |
LLM Description written by Claude Code:claude-opus-5-5
Fixes #1549
Summary
A vendored or hosted PyPI wiring in one install source (
requirements.txtor
Pipfile.lock) is now contested when the other source installs thesame release from a non-Socket artifact: a Pipfile.lock
fileurl orpathwheel, a requirementsname @ <url>line, a bare url / wheel pathline, or an editable / VCS checkout. Before this,
vendor --checkstayedgreen and
vexattestednot_affectedwhilepipenv sync/pip install -rinstalled the upstream, unpatched release. A registry==pin in the same place was already contested; now these referencesbehave the same way (
patched_ref_unattributable, naming both files, andno statement).
Root cause
vex/discover/pypi_other.rsrecorded contesting evidence(
resolved_elsewhere) only for registry pins. A non-Socket directreference reached
emit, which returned onOk(None)without recordinganything. The poetry.lock extractor already counts such references.
Fix
Pipfilebeside it) contributes the new evidence; an abandoned lock installs nothing (Hosted scan never sees the Pipfile, so a live Pipfile.lock conflict is treated as abandoned and a sibling requirements.txt is redirected anyway #333).emitnow hands a non-Socket reference fromPipfile.lockor arequirements file to
foreign_reference, which records it as evidence.The release comes from the artifact's wheel / sdist filename (when it
names the declared package), else an exact
versionpin (never awildcard like
==1.16.*). The package name comes from the entry, thefilename, or an
#egg=fragment.checkout, an editable
-e …#egg=six) may install any version, so it isrecorded with the new
Discovery::resolved_elsewhere_any_version, aversionless purl that contests every version of that package.
contest_across_locksmatches it throughResolvedElsewhere::covers,and the diagnostic says the other file resolves the package "at a
version it doesn't name".
pyproject.toml/hatch.tomldependency tables areunchanged: they are declarations a resolver reads, not an install source
of their own.
Tests (red → green)
fileurl /pathwheel /file://url / exactversionbeside a path / wildcard pin beside a wheel, contesting a vendored requirements.txtvex::discover::pypi_other::tests::issue_1549_non_socket_direct_references_contest_wiringsix @ url, bare url, bare wheel path, contesting a vendored Pipfile.lockpathdir, versionless url, VCS entry,six @ git+…,six @ file:///dir, baregit+…#egg=six,-e/--editablelines; another package or another release contests nothingissue_1549_unversioned_direct_references_contest_every_versionscanwiring thenvex(hosted + vendored,--no-verifytoo): requirements direct ref beside a wired Pipfile.locke2e_vex_lockfile pipenv::requirements_direct_reference_contests_the_lock_wiringfileurl /pathwheel beside wired requirements.txte2e_vex_lockfile pip::pipfile_lock_direct_reference_contests_the_requirements_wiringCommands run locally:
cargo fmt --all -- --check: cleancargo clippy --workspace --all-features -- -D warnings: cleancargo test -p socket-patch-core --lib: all pass except 4 tests thatalso fail on
mainin this sandbox because it runs as root (chmod-basedunwritable-dir tests:
relax_loop_must_not_traverse_symlinked_root,an_unremovable_hidden_lock_keeps_every_store_entry,wire_write_failure_maps_error_and_leaves_lock_untouched,wire_failure_rolls_back_already_written_files)cargo test -p socket-patch-cli --test e2e_vex_lockfile -- direct_reference_contests: 2 pass (2 fail with the core fix reverted)SOCKET_PATCH_PIPENV_E2E_VERSIONS=2026.8.0 cargo test -p socket-patch-cli --test e2e_vex_build -- pipenv:: --ignored(real Pipenv): 2 passcargo test --workspace --all-features --no-fail-fast: everything passes except tests that fail identically onmainin this sandbox (checked by running them against main's sources): the 4 root-permission core tests above,in_process_redirectwrite-failure tests (3),repairunremovable-lock tests (2), ande2e_bun_lockb::binary_shared_bundled_record_hosted_pin_is_managed(needs patches-api.socket.dev, unreachable here)cargo test -p socket-patch-cli --test in_process_redirect_pipenv: 11 pass. The full run caughtabandoned_pipfile_lock_conflict_does_not_veto_the_requirements_redirect(Hosted scan never sees the Pipfile, so a live Pipfile.lock conflict is treated as abandoned and a sibling requirements.txt is redirected anyway #333): a userfileentry in a leftover Pipfile.lock with no Pipfile started vetoing the hosted requirements redirect. Pipenv installs from the lock only with its Pipfile, so the new evidence is now recorded only when a Pipfile is present (e97bceb, with a unit case for it).Code review (/code-review high)
Fixed: editable lines and
#egg=-named VCS lines now count; theartifact filename wins over a beside-pin and wildcard pins are ignored;
resolves_packagekeeps its old meaning;pypi_name_purlvalidatesdirectly; the CLI cell asserts the contest phrase, not just the file name.
Not fixed here, deliberately:
(
withhold_rewirable), like every cross-lock contest today, includingthe poetry.lock precedent. A re-run can't rewrite a user's reference, so
"shadowed" would fit better for rollback/remove. That changes the
management commands for all cross-lock contests, so it belongs in its
own PR.
wiring doesn't contest it. That's pre-existing for registry pins too
(cross-lock evidence never contests its own file).
🤖 Generated with Claude Code
https://claude.ai/code/session_01R2uDxa7vv5ajQTMGpCK2ug
Note
Medium Risk
Changes VEX discovery and attestation for contested PyPI wirings; incorrect matching could wrongly attest or block patches, but behavior is heavily regression-tested.
Overview
Fixes #1549: when one Python install file wires a package to a Socket patch but another (
requirements.txtvsPipfile.lock) installs the same release from a non-Socket URL, wheel path, or direct reference, discovery now treats that like an existing registry==pin—withholds attestation and emitspatched_ref_unattributablenaming both files.Discovery changes:
pypi_otherrecords user direct refs viaforeign_reference(version from wheel filename or exact pin; versionless/VCS/editables via newresolved_elsewhere_any_version). Pipfile.lock evidence only applies when a livePipfileis present (#333). Cross-lock matching usesResolvedElsewhere::coversfor versionless contests.Tests: unit regressions plus shared E2E helper
contested_by_a_non_socket_direct_referencefor pip/pipenv flows.Reviewed by Cursor Bugbot for commit 07503e7. Configure here.
Generated by Claude Code