Repository navigation
Hosted uv scan silently wires a platform-specific patched wheel (cp311 manylinux) into a universal uv.lock, so uv sync --locked fails on every other Python version, macOS and Windows, and rollback then refuses #701
Description
[agent] Found by the scheduled uv bug-hunt routine (ledger #310).
Summary
When the patch service grants a platform-specific wheel for a pypi patch (here MarkupSafe-2.1.5-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl), hosted scan --mode hosted on a uv project rewrites [tool.uv.sources] and uv.lock so the package resolves only from that one wheel. It reports success with no platform warning (only the usual redirect_pypi_stale_install). uv.lock is a universal lock (requires-python = ">=3.9"), and before the rewrite it carried every MarkupSafe wheel. After the rewrite:
uv lock --checkpasses, anduv sync --lockedworks on the scanning machine (CPython 3.11, linux x86_64).uv sync --lockedon CPython 3.12 (same machine) fails:can't be installed because the binary distribution is incompatible with the current platform … only has wheels with the following Python ABI tag: cp311.- The same happens for
--python-platform x86_64-apple-darwin,aarch64-apple-darwinandx86_64-pc-windows-msvc. rollbackthen refuses (the release ships platform- or interpreter-specific wheels, and which of them uv kept … is not derivable; restore it from version control instead). That refusal is documented, so the only way back isgit checkout.
The vendored path already handles this case: crates/socket-patch-core/src/vendor/pypi.rs:1139 emits vendor_platform_locked ("uv.lock now resolves it from this single-platform wheel only"). Hosted gem has a fail-closed guard for the same problem (redirect_gem_platform_unsupported, crates/socket-patch-core/src/patch/redirect/mod.rs:5533). Hosted pypi has neither a warning nor a refusal. The PEP 751 lane is affected too: a uv export --format pylock.toml pylock gets archive = { url = ".../MarkupSafe-2.1.5-cp311-cp311-manylinux…whl" }, also with no warning.
Impact
A team that runs hosted scan on a dev box or a single CI image commits a lock that breaks uv sync --locked for every teammate and CI job on another OS, architecture or Python minor version. Nothing in the scan output warns about it, and hosted rollback can't undo it.
Repro (Linux, real uv; local mock patch service)
The mock answers POST /v0/orgs/acme/patches/{batch,package}, GET …/by-package/… and GET …/view/<uuid>, and serves a deterministic patched copy of the real PyPI wheel MarkupSafe-2.1.5-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (one marker line appended to markupsafe/__init__.py, RECORD regenerated), with SRI sha512 and hex sha256 integrity.
mkdir app && cd app
cat > pyproject.toml <<'EOF'
[project]
name = "app"
version = "1.0.0"
requires-python = ">=3.9"
dependencies = ["markupsafe==2.1.5", "packaging==24.1"]
EOF
uv lock && uv sync -p python3.11
socket-patch scan --mode hosted --json --yes --cwd . \
--api-url http://127.0.0.1:8765 --api-token fake --org acme --patch-server-url http://127.0.0.1:8765
# -> status success, redirected 1, warnings: [redirect_pypi_stale_install] only
uv lock --check # ok
uv sync --locked -p python3.11 # ok, patched
rm -rf .venv && uv sync --locked -p python3.12 # error: ... only has wheels with the following Python ABI tag: `cp311`
uv sync --locked -p 3.11 --python-platform x86_64-pc-windows-msvc # error: ... incompatible with the current platform
socket-patch rollback --json --yes --cwd . ... # partial_failure: "release ships platform- or interpreter-specific wheels ... restore it from version control"The original (pre-scan) lock syncs fine with -p python3.12 and --python-platform x86_64-pc-windows-msvc.
Expected vs actual
- Expected: hosted scan either refuses to redirect a uv lock (or pylock) to a single platform/ABI-tagged wheel when the lock is universal, like hosted gem's
redirect_gem_platform_unsupported, or at least warns as vendored mode does (vendor_platform_locked). CLI_CONTRACT.md (rollback section, line 853) already treats "a release that has a wheel that is not pure Python 3" as a case hosted mode can't round-trip. A scan that creates a state its own rollback refuses, without telling the user, contradicts that. - Actual: silent
success. The lock becomes cp311 + manylinux x86_64 only.
Matrix (Linux sandbox; macOS / Windows via uv's --python-platform resolver, not native runners)
| uv | scan warns? | sync py3.11 linux | sync py3.12 | sync macOS x86_64 / arm64 | sync Windows x64 | rollback |
|---|---|---|---|---|---|---|
| 0.5.31 | no | ok, patched | fail | – | – | – |
| 0.8.17 | no | ok, patched | fail | – | – | refused (documented) |
| 0.12.22 (latest) | no | ok, patched | fail | fail | fail | – |
Main 045d7ec (CLI 4.0.0). Reproduced on three fresh projects (six or packaging as the sibling). Not bisected: the hosted uv rewriter has never had a platform check.
Suspect code
crates/socket-patch-core/src/patch/redirect/mod.rs:4638(rewrite_uv_lock):ArtifactSource::Url(&dep.artifact_url)is planned and rewritten without inspecting the wheel filename's tags. Comparecrates/socket-patch-core/src/vendor/pypi.rs:1139(platform_locked→vendor_platform_locked) andwheel_filename_from_urlincrates/socket-patch-core/src/api/client.rs:357.
Activity
uv: run 12 ledger (#701)
mikolalysenko commentedon Oct 3, 2026
[agent] Triaged as
priority:p1(uv / PyPI family). Not a duplicate: no other open or closed issue covers hosted uv/pylock wiring of a platform-tagged wheel, and no open PR touches it. Confirmed onmain(f6b7fb9):rewrite_uv_lockincrates/socket-patch-core/src/patch/redirect/mod.rsplansArtifactSource::Urlwithout looking at the wheel tags, while vendored mode'splatform_lockedcheck (vendor/pypi.rs,vendor_platform_locked) already parses them. Likely fix: reuse the vendored tag parse in the hosted uv/pylock planner and fail closed (or warn) on a universal lock.Generated by Claude Code
mikolalysenko commentedon Oct 4, 2026
[agent] Two more uv lanes hit the same missing platform check (scheduled uv bug-hunt, ledger #310). Main
045d7ec, Linux, real uv, and the same local mock that serves the patchedMarkupSafe-2.1.5-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.1. Hosted requirements lane,
uv pip compile --universal. The file is explicitly universal (its header names--universal). Before the scan it carried all 60 MarkupSafe hashes. Hosted scan replaces that entry withmarkupsafe @ http://…/MarkupSafe-2.1.5-cp311-cp311-manylinux…whl --hash=sha256:…. It reportsstatus: successwith no warning error code at all.uv pip syncpy3.11--python-platform)Unlike the uv.lock lane, hosted
rollbackrestores this requirements.txt byte for byte (when an unpatched sibling such asidnais present). So it can be recovered, but the scan still breaks every other interpreter in the meantime without saying so.2. PEP 723 script lock (
uv lock --script), 0.8.17. The script gains# tool.uv.sources.markupsafe = { url = "…cp311-cp311-manylinux…whl" }, andtool.py.lockis narrowed to that wheel. There's no warning.uv run -p 3.11 --frozen --script tool.pyprints1, anduv run -p 3.12 --frozen --script tool.pyfails withthe binary distribution is incompatible with the current platform.So a fix in
rewrite_uv_lockalone won't cover it. The requirements writer and the script-lock path need the same wheel-tag check, or the samevendor_platform_locked-style warning.Generated by Claude Code
uv: run 14 ledger (#742, #701 comment, pip handover)
mikolalysenko commentedon Oct 6, 2026
[agent] Shares root cause with #932: the hosted PyPI redirect never inspects the granted wheel's platform/ABI tags, in any of its lock writers (uv.lock, pylock, requirements, PEP 723 script locks, and Pipfile.lock in #932). Will be fixed together, with one check at the shared PyPI rewriter dispatch in
patch/redirect/mod.rs.Generated by Claude Code
mikolalysenko commentedon Oct 7, 2026
[agent] Claiming this issue (with #932; shared root cause: the hosted PyPI redirect never inspects the granted wheel's platform/ABI tags before narrowing a cross-platform lock). Branch: agent/fix-hosted-pypi-platform-wheel. Claim-ID: 2026-10-07T04:20:35Z-c338c4
Generated by Claude Code
mikolalysenko commentedon Oct 7, 2026
[agent] Draft fix PR (also covers #932): #984
Generated by Claude Code
Stop hosted PyPI pinning platform-only wheels
Keep vendored PyPI patch on a platform grant