GV

GeezerVison

The World Wide Web, restored to 800 pixels of glory.

Home|About|Gaming cabinet|Archives|How it works|Starter sites

On this site

  • Sign in
  • ActionsCI/CD and automation
  • CodespacesCloud development environments
  • All Features
  • Documentation
  • Training
  • Certifications
  • Build with Copilot
  • Customize Copilot
  • Integrations
  • Trending repos
  • GitHub Sponsors
  • Developer articles
  • Enterprises

This view

  • Original page
  • New address

GeezerVison is showing github.com — Hosted `rollback`, `remove` and the vendored takeover refuse a requirements.txt whose only requirements are hosted pins (`six==1.16.0` alone can be patched but never unpatched) · Issue #410 · SocketDev/socket-patch

Hosted rollback, remove and the vendored takeover refuse a requirements.txt whose only requirements are hosted pins (six==1.16.0 alone can be patched but never unpatched) #410

New issue
Copy link
New issue
Copy link
Closed
#827
Closed
Hosted rollback, remove and the vendored takeover refuse a requirements.txt whose only requirements are hosted pins (six==1.16.0 alone can be patched but never unpatched)#410
#827
Copy link
Labels
agent:triagedbugSomething 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.txtpriority:p1

Description

@mikolalysenko
Mikola Lysenko (mikolalysenko)
opened on Oct 1, 2026
Issue body actions

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

Summary

v5 hosted rollback, remove and the hosted → vendored takeover (scan --mode vendored over a hosted pin) all refuse a requirements.txt when every requirement line in it is a hosted pin. The simplest project shape, a single six==1.16.0 line, can be patched by socket-patch scan but can't be un-patched or vendored afterwards.

The refusal comes from the upstream restore. It tries to infer pip's hash-checking mode from the other requirement lines, and when there are none it gives up:

cannot restore pkg:pypi/[email protected] to its upstream registry entry: every requirement in requirements.txt is a hosted pin, so whether the original used pip's hash-checking mode (`--hash`) is not derivable; restore it from version control instead (`git checkout -- requirements.txt`)

The same refusal fires when the only other lines are options or editables. For example, -e . plus a pin is refused, even though -e lines are incompatible with hash-checking mode, so the original must have been unhashed.

Impact

  • socket-patch rollback and socket-patch remove <purl> exit 1 (partial_failure / hosted_revert_failed) on single-dependency projects, on projects where every pin is patched, and on -e . + pin projects.
  • socket-patch scan --mode vendored on such a hosted project can't take over: Vendored 0 packages; 1 failed., exit 1, and the project stays hosted. The documented mode-takeover path (CLI_CONTRACT.md, "Takeover reconciliation (every hosted ecosystem, v5.0)") is unusable for these projects.
  • v5 keeps no hosted ledger, so the CLI can't undo the rewrite at all. The only remedy is version control.

Repro

Uses a local mock of the patch API that serves a patched six-1.16.0 wheel. It's the same shape as tests/vex_pypi_real_common::RealApi: POST /v0/orgs/test-org/patches/batch, /patches/package grant, /patches/view/<uuid>, and the wheel route. Linux, pip 24.0, CPython 3.11, main 2463257.

A="--api-url http://127.0.0.1:8765 --api-token fake --org test-org --patch-server-url http://127.0.0.1:8765"
mkdir p && cd p && printf 'six==1.16.0\n' > requirements.txt
socket-patch scan $A                      # Switched 1 package to hosted patches; rewrote 1 file.
socket-patch rollback --yes $A; echo $?   # Error: Cannot restore … not derivable …   → 1
socket-patch remove pkg:pypi/[email protected] --yes $A; echo $?   # same error → 1
socket-patch scan --mode vendored $A; echo $?               # Cannot vendor … not derivable … Vendored 0 packages; 1 failed. → 1

Variants I checked (scan, then rollback):

requirements.txt before scan rollback
six==1.16.0 refused
-e . + six==1.16.0 refused
six==1.16.0 --hash=… --hash=… (only line) refused
six==1.16.0 + idna==3.7 restored
--require-hashes + hashed six restored
--index-url … + six==1.16.0 + idna==3.7 restored
pip-compile hashed idna + six (LF and CRLF) restored byte-exact

Expected vs actual

  • Expected: CLI_CONTRACT.md, "Hosted unwind coverage", says every file wiring a pin is rewritten back to the default upstream entry. The pypi bullet lists what gets refused: pdm.lock without cross_platform, non-pure uv / pylock wheels, uv option filters, and uv 0.2 locks. An all-hosted requirements.txt isn't in that list. When no other requirement constrains the mode, either restored form, six==1.16.0 or six==1.16.0 --hash=… for every release file, installs with every pip, because there is no other line it could conflict with. A -e line also settles the mode as unhashed.
  • Actual: the pin is refused in rollback, remove and the takeover.

OS × version

OS pip / Python reproduces
Linux (sandbox) 24.0 / 3.11 (CLI-only; no pip step involved) yes, twice
ubuntu-latest (probe) 20.3.4 / 3.8 yes (rollback, remove and takeover all refused, exit 1)
ubuntu-latest (probe) 25.0.1 / 3.8 yes (rollback, remove and takeover all refused, exit 1)
ubuntu-latest (probe) 26.2.1 / 3.13 yes (rollback, remove and takeover all refused, exit 1)
macos-latest (probe) 20.3.4 / 3.8 yes (rollback, remove and takeover all refused, exit 1)
macos-latest (probe) 25.0.1 / 3.8 yes (rollback, remove and takeover all refused, exit 1)
macos-latest (probe) 26.2.1 / 3.13 yes (rollback, remove and takeover all refused, exit 1)
windows-latest (probe) 20.3.4 / 3.8 yes (rollback, remove and takeover all refused, exit 1)
windows-latest (probe) 25.0.1 / 3.8 yes (rollback, remove and takeover all refused, exit 1)
windows-latest (probe) 26.2.1 / 3.13 yes (rollback, remove and takeover all refused, exit 1)
all 3 OS (probe) 20.3.4 / 3.13 blocked: pip 20.3.4 can't run on 3.13 (no distutils)

The refusal is decided before any pip runs, so it doesn't depend on the pip version.

First bad

The code is new in 2463257 (#277), which replaced v4's ledger replay with the upstream restore. I didn't get a clean comparison: on v4.0.0, rollback of the same hosted project stopped at Manifest not found even though .socket/vendor/redirect-state.json existed.

Suspect code

  • crates/socket-patch-core/src/patch/redirect/upstream/pypi.rs:597-603: the (false, false) arm of hash_mode. --prefixed lines, -e included, are skipped before the mode tally (if code.starts_with('-') { continue; }).
  • Related: Hosted and vendored requirements.txt rewrites add a --hash to one line, which turns on pip's hash-checking mode and breaks pip install -r for every other unhashed line #376. The hosted writer always emits --hash, so the line itself never records the original mode. Once Hosted and vendored requirements.txt rewrites add a --hash to one line, which turns on pip's hash-checking mode and breaks pip install -r for every other unhashed line #376 / Fix requirements.txt writers ignoring pip hash mode (#376) #383 switch unhashed files to a #sha256= fragment, the hosted line's own shape (--hash vs fragment) would say which mode to restore.

Probe run: https://github.com/SocketDev/socket-patch/actions/runs/36806309982

Activity

  1. Mikola Lysenko (mikolalysenko)
    added
    bugSomething isn't workingSomething isn't working
    bughuntFound by a scheduled package-manager bug-hunt agentFound by a scheduled package-manager bug-hunt agent
    pm:pippip / requirements.txtpip / requirements.txt
    agent:triaged
    priority:p1
    on Oct 1, 2026
  2. mikolalysenko commented on Oct 1, 2026

    @mikolalysenko
    Mikola Lysenko (mikolalysenko)
    on Oct 1, 2026
    CollaboratorAuthor
    More actions

    [agent] Triaged: priority:p1 (pip). Not a duplicate. The cause is the (false, false) arm of hash_mode in upstream/pypi.rs, which also skips -e lines before it counts which lines use hashes. It's related to #376 / PR #383 (the hosted writer always emits --hash) but isn't the same defect: #383 changes how hosted lines are written, and this issue is about how the restore infers the original mode. If #383 lands with a #sha256= fragment for unhashed files, the hosted line's own shape gives the restore that signal. Leaving this open as its own work item and linking it to #383 so the two stay in sync.


    Generated by Claude Code

  3. mikolalysenko commented on Oct 1, 2026

    @mikolalysenko
    Mikola Lysenko (mikolalysenko)
    on Oct 1, 2026
    CollaboratorAuthor
    More actions

    [agent] Re-checked on main 61cfb9b (which includes #383): still reproduces.

    printf 'six==1.16.0\n' > requirements.txt
    socket-patch scan --mode hosted --yes
    # six @ http://…/six-1.16.0-py2.py3-none-any.whl#sha256=84f7…   (fragment pin; no --hash since #383)
    socket-patch rollback --yes; echo $?
    # Error: Cannot restore pkg:pypi/[email protected] … every requirement in requirements.txt is a hosted pin, so whether the original used pip's hash-checking mode (`--hash`) is not derivable …   → 1
    

    Control: idna==3.7 + six==1.16.0 still restores byte for byte.

    New since filing: after #383 the hosted line itself records the mode. An unhashed file gets <url>#sha256=… with no --hash option, and a hashed file gets <url> --hash=sha256:…. So the (false, false) arm in upstream/pypi.rs could read the mode from the hosted line instead of refusing. (A pre-#383 v5 line, which always carried --hash, stays ambiguous.)


    Generated by Claude Code

  4. mikolalysenko commented on Oct 5, 2026

    @mikolalysenko
    Mikola Lysenko (mikolalysenko)
    on Oct 5, 2026
    CollaboratorAuthor
    More actions

    [agent] Claiming this issue (shared root cause: the requirements.txt upstream restore can't infer pip's hash-checking mode when no non-hosted requirement line constrains it, and ignores that -e lines settle it as unhashed). Branch: agent/fix-pypi-restore-hash-mode. Claim-ID: 2026-10-05T05:20:47Z-f70577


    Generated by Claude Code

  5. Mikola Lysenko (mikolalysenko)
    added
    agent:claimed
    on Oct 5, 2026
  6. mikolalysenko commented on Oct 5, 2026

    @mikolalysenko
    Mikola Lysenko (mikolalysenko)
    on Oct 5, 2026
    CollaboratorAuthor
    More actions

    [agent] Draft PR: #827


    Generated by Claude Code

  7. Mikola Lysenko (mikolalysenko)
    added 3 commits that reference this issue on Oct 5, 2026

    Fix pip rollback refusing all-hosted requirements

    This issue will close once commit 191ff15 is merged into the 'main' branch.
    191ff15

    Update restore golden for sole-pin requirements

    This issue will close once commit f4033e3 is merged into the 'main' branch.
    f4033e3

    Merge main into fix-pypi-restore-hash-mode

    This issue will close once commit a7b427d is merged into the 'main' branch.
    a7b427d
  8. Mikola Lysenko (mikolalysenko)
    closed this as completedin 7ce869eon Oct 7, 2026
  9. Mikola Lysenko (mikolalysenko)
    added a commit that references this issue on Oct 7, 2026

    Merge main into agent/fix-yarn-pnp-linker-detect

    9c66aac
  10. Mikola Lysenko (mikolalysenko)
    removed
    agent:claimed
    on Oct 7, 2026
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 workingSomething isn't workingbughuntFound by a scheduled package-manager bug-hunt agentFound by a scheduled package-manager bug-hunt agentpm:pippip / requirements.txtpip / requirements.txtpriority:p1

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions

      You are visitor 01402520 — GeezerVison does not store the pages you look up.
      Best viewed with Netscape Navigator 4.7 or Internet Explorer 6 at 800×600. No cookies required.