Skip to content

After a hosted rollback or vendored revert of a requirements.txt pin, plain pip install -r keeps the patched build, though rollback says the next install restores it (and vendor --revert says nothing) #1953

Closed

Description

[agent] Found by the scheduled pip / requirements.txt bug-hunt routine (ledger #309).

Summary

#1308 (the fix for #477) added redirect_pypi_reinstall_required / vendor_pypi_reinstall_required for PDM, uv and Pipenv, because their plain sync keeps an installed same-version build once the lock goes back to the registry release. Plain pip behaves the same way: pip install -r requirements.txt reports Requirement already satisfied: six==1.16.0 and keeps the patched wheel. requirements.txt entries were deliberately left on the generic note (#1308: "Poetry, requirements.txt, Hatch and PEP 751 entries keep the generic note"). As a result:

  • Hosted rollback / vendored rollback print Note: 1 unwired package keeps its patched bytes in installed trees until the next package-manager install. For pip that's false: the next pip install -r keeps them.
  • vendor --revert prints only Reverted 1 vendored package., with no advisory. It also deletes .socket/vendor/pypi/<uuid>/six-…whl, while the installed six's direct_url.json still points at that file.

Impact

  • The venv silently keeps the Socket build after the user un-patched. That's harmless for security, but it's the exact After a hosted or vendored PDM rollback, pdm sync / pdm install keep the patched build installed, though rollback says the next install restores it #477 mismatch between what the CLI says and what pip does.
  • pip freeze keeps emitting the Socket source: six @ http://<patch-server>/patch/pypi/six/…whl#sha256=… after a hosted rollback, so a pip freeze > requirements.txt re-introduces the hosted pin the user just rolled back. After a vendored revert it emits six @ file:///…/.socket/vendor/pypi/<uuid>/six-1.16.0-…whl. That file no longer exists, so pip install -r frozen.txt in a new venv fails with ERROR: Could not install packages due to an OSError: [Errno 2] No such file or directory: '…/.socket/vendor/pypi/…/six-1.16.0-py2.py3-none-any.whl'.

Repro

A local mock of the patch API grants pkg:pypi/six@1.16.0 with a patched wheel (SAFE = True appended to six.py), the same fixture shape as tests/mode_migration_pypi.rs. Real pip, real PyPI.

git init -q
printf 'certifi==2024.2.2\nsix==1.16.0\n' > requirements.txt
git add -A && git commit -qm init
socket-patch scan --mode hosted --yes        # or: --mode vendored
python -m venv .venv && .venv/bin/pip install -q -r requirements.txt
.venv/bin/python -c 'import six; print(getattr(six,"SAFE",0))'   # True (patched)
socket-patch rollback                         # or, vendored: socket-patch vendor --revert
#  Note: 1 unwired package keeps its patched bytes in installed trees until the next package-manager install.
git status --short                            # requirements.txt restored byte-identical
.venv/bin/pip install -r requirements.txt     # Requirement already satisfied: six==1.16.0 ...
.venv/bin/python -c 'import six; print(getattr(six,"SAFE",0))'   # still True
.venv/bin/pip freeze | grep six               # six @ http://…/patch/pypi/six/…  (vendored: six @ file:///…/.socket/vendor/…whl, now deleted)

Expected vs actual

  • Expected: CLI_CONTRACT.md's reinstall_required row says installed trees keep patched bytes "until the next package-manager install". Where that isn't true, the contract's own After a hosted or vendored PDM rollback, pdm sync / pdm install keep the patched build installed, though rollback says the next install restores it #477 rule (the vendor_pypi_reinstall_required / redirect_pypi_reinstall_required rows) is to name the reinstall that restores upstream. For pip that is pip install --force-reinstall --no-deps six==1.16.0 (or pip uninstall -y six && pip install -r requirements.txt). The forward direction already handles pip's same-version behaviour: redirect_pypi_stale_install warns that a warm venv keeps the upstream build.
  • Actual: a hosted rollback prints the generic note, which is wrong for pip. vendor --revert prints nothing. The patched build stays, and pip freeze points at the patch server or at the deleted vendored wheel.

Matrix (Linux, main cbbbdb9, socket-patch 5.0.1 build)

pip / CPython hosted rollback vendored vendor --revert vendored rollback
pip 26.2.2 / 3.12 repro (patched kept, generic note) repro (patched kept, no advisory, freeze → deleted file) repro (generic note)
pip 20.3.4 / 3.8 repro repro not run

Each cell ran twice. The pip behaviour is pip's resolver, not OS-specific (Requirement already satisfied for a same-version installed dist, whatever its direct_url.json says). macOS and Windows weren't probed, because this routine's probe branches are blocked.

First bad: present since the unwind advisories landed (#1308). Before that, every PyPI tool got only the generic note.

Suspect code

  • crates/socket-patch-cli/src/commands/pypi_reinstall.rs:43 (Tool::of_flavor) and :54 (Tool::of_file): requirements / requirements.txt map to None, so no advisory is pushed and the qualifier at crates/socket-patch-cli/src/commands/rollback.rs:451 isn't added.
  • crates/socket-patch-cli/src/commands/pypi_reinstall.rs:75 (remedy): no pip arm.

Related: #477. Its uv-routine comment showed the same keep for uv pip install -r requirements.txt and suggested uv pip install --reinstall <pkg> for the requirements / pylock lane. A pip remedy is the plain-pip counterpart. PEP 751 pylock.toml installed by pip install -r pylock.toml likely behaves the same; that wasn't tested here.

No probe runs (probe branches are blocked for this routine).

Activity

  1. mikolalysenko commented on Nov 1, 2026

    @mikolalysenko
    CollaboratorAuthor

    [agent] Triage: priority:p1 (pip / requirements.txt). Not a duplicate: #977 is about reverting after the user edits the socket comment, and #477 / #1308 deliberately left requirements.txt on the generic note. No open PR covers it.


    Generated by Claude Code

  2. mikolalysenko commented on Nov 1, 2026

    @mikolalysenko
    CollaboratorAuthor

    [agent] Claiming this issue (shared root cause: pypi_reinstall::Tool has no pip arm, so requirements.txt unwinds get the generic note or no advisory). Branch: agent/fix-pip-reinstall-advisory. Claim-ID: 2026-11-01T20:21:19Z-2bf094


    Generated by Claude Code

  3. mikolalysenko commented on Nov 1, 2026

    @mikolalysenko
    CollaboratorAuthor

    [agent] Draft PR: #1954


    Generated by Claude Code

  4. added 3 commits that reference this issue on Nov 1, 2026
    5c1d71b
    194940d
    b572ade
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

    agent:triagedbugSomething isn't workingbughuntFound by a scheduled package-manager bug-hunt agentpm:pippip / requirements.txtpriority:p1

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions