Skip to content

Fix uv scans wiring wheels under no-binary (#1603) - #1649

Open
Mikola Lysenko (mikolalysenko) wants to merge 4 commits into
mainfrom
agent/fix-uv-no-binary-wire-guard
Open

Mikola Lysenko (mikolalysenko) wants to merge 4 commits into
mainfrom
agent/fix-uv-no-binary-wire-guard

Conversation

@mikolalysenko

@mikolalysenko Mikola Lysenko (mikolalysenko) commented Oct 21, 2026 •

Copy link
Copy Markdown
Collaborator

LLM Description written by Claude Code:claude-opus-5-5

Refs #1603

Summary

uv's no-binary = true / no-binary-package = [...] make uv install a
package only from an sdist. Every socket-patch PyPI artifact is a wheel, so
when a scan wired a patch for such a package (hosted: the patch-server
.whl URL; vendored: .socket/vendor/pypi/<uuid>/*.whl), it exited 0 and
every later uv sync / uv sync --locked / uv run --locked failed with
"marked as --no-binary but is itself a binary distribution".

Both modes now refuse before writing anything:

  • vendored: pypi_uv_no_binary (uv projects and PEP 723 scripts)
  • hosted: redirect_uv_project_unsupported /
    redirect_uv_script_unsupported, the same warnings no-sources uses,
    so the package is skipped and the scan still exits 0 for the rest.

Root cause

The wire-time guards (vendor/pypi_uv.rs check_target_guards,
vendor/pypi_lock.rs script lane, and the uv metadata step in
patch/redirect/mod.rs) checked no-sources and ancestor shadowing,
never no-binary. Only hosted restore looked at no-binary*.

Fix

utils/python_script.rs: the no-sources settings reader is now a
generic refuse_package_setting over a (bool key, package-list key) pair,
so no-binary gets exactly uv's precedence for free: a project uv.toml
replaces [tool.uv]; a script's own bool wins over the project's; lists
add up; no-binary = false disables the list; a script whose root sets
nothing takes the nearest parent uv.toml / [tool.uv]. New
refuse_uv_no_binary / refuse_uv_script_no_binary are called at all
three wire sites. The no-sources message text is unchanged.
no-build* allows wheels and is not refused. Docs:
docs/testing/uv-compatibility.md.

No wrapper changes needed (npm/, pypi/, gem/ only dispatch to the
binary).

Why Refs and not Fixes

The issue's follow-up comment adds a hosted uv pip compile --no-binary
pylock.toml lane. That lock records nothing of the filter in its data;
the only signal is the uv header command line and the uv config files
uv pip reads. #1614 adds exactly that parser for the restore side (#1613).
Reusing it for the wire side belongs after #1614 lands, so #1603 stays open
for that lane. The project / uv.toml / script matrix from the issue body
is fully covered here.

Tests (red → green)

Each new test fails with the guard disabled (refuse_uv_*no_binary
short-circuited to Ok(())) and passes with the fix:

Lane Test Red Green
hosted project + script, [tool.uv], uv.toml, parent uv.toml, controls patch::redirect::python_metadata_pairing_tests::no_binary_refuses_a_wheel_uv_would_not_install FAILED ok
vendored project, [tool.uv] + uv.toml, controls vendor::pypi_uv::tests::guards_refuse_workspace_lock_version_fork_sources_and_dynamic FAILED ok
vendored PEP 723 script (own, uv.toml, pyproject, parent) vendor::pypi_lock::tests::script_no_binary_refuses_before_writing FAILED ok
CLI end to end, both modes, writes nothing; no-build-package control still pinned mode_migration_pypi::uv_no_binary_is_refused_in_both_modes FAILED ok (suite 65/65)

Controls (wired, not refused): no-binary-package naming another package,
no-build-package, no-build = true, no-binary = false + list,
a script's no-binary = false over the project's list.

Local (all at 3b0c27e):

  • cargo fmt --all -- --check: ok
  • cargo clippy --workspace --all-features -- -D warnings: ok
  • e2e_redirect_uv_build -- --include-ignored: 23/23 ok (uv 0.11.32)
  • e2e_vendor_pypi_build -- --include-ignored: 55/55 ok
  • mode_migration_pypi: 65/65 ok
  • cargo test --workspace --all-features --no-fail-fast: 233 targets ok;
    10 tests failed for sandbox reasons unrelated to this diff (CI will
    confirm): 9 write-failure tests that rely on read-only permissions,
    which don't bind as root (uid 0) here (e.g. pypi_poetry::tests:: wire_write_failure_maps_error_and_leaves_lock_untouched, repair
    unremovable-lock tests, in_process_redirect write-failure tests), and
    e2e_bun_lockb::binary_shared_bundled_record_hosted_pin_is_managed,
    which needs patches-api.socket.dev (blocked by this sandbox's proxy).

/code-review high

Fixed: refusal text for no-binary = true (now names the package and a
remedy a bool allows); vendored half of the no-build-package control;
stale engine comment; install-machine settings caveat in the docs.
Not fixed:

  • Hosted lock-only checkout (uv.lock + uv.toml, no pyproject.toml)
    skips the metadata guards. Pre-existing for no-sources too, and uv
    itself can't uv sync a project without its pyproject.toml, so no
    real install reaches the wired wheel.
  • Folding the two guard calls into one: kept as two calls so each keeps
    its own stable error code (pypi_uv_no_sources / pypi_uv_no_binary)
    at every site; the extra TOML parse is a one-off per wired package.

Generated by Claude Code

Assisted-by: Claude Code:claude-opus-5-5
uv installs a package listed in no-binary / no-binary-package only from
an sdist, and every Socket patch is a wheel, so a hosted or vendored
scan that wired one left a project where every uv sync failed. Both
modes now refuse before writing anything: vendored with
pypi_uv_no_binary, hosted with the uv project/script unsupported
warnings. Settings are read with uv's precedence, shared with the
existing no-sources check.

Refs #1603

Assisted-by: Claude Code:claude-opus-5-5
Assisted-by: Claude Code:claude-opus-5-5
The no-binary = true refusal said "remove the package from the
setting", which a bool can't do and which never named the package.
The message now names the package and how to let uv install it from a
wheel. Also cover vendored mode in the no-build-package control, note
in the docs that install-machine uv settings are invisible to the
scan, and update the hosted engine comment on why uv.toml is read.

Refs #1603

Assisted-by: Claude Code:claude-opus-5-5
@mikolalysenko
Mikola Lysenko (mikolalysenko) marked this pull request as ready for review October 21, 2026 01:11
@mikolalysenko

Copy link
Copy Markdown
Collaborator Author

BugBot review


Generated by Claude Code

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ 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 3b0c27e. Configure here.

@mikolalysenko Mikola Lysenko (mikolalysenko) added the Ready for review Agent-verified: mergeable, CI green, Bugbot clean — awaiting human review label Oct 21, 2026
@mikolalysenko

Copy link
Copy Markdown
Collaborator Author

Labeled Ready for review at 3b0c27e.


Generated by Claude Code

@mikolalysenko

Copy link
Copy Markdown
Collaborator Author

Final review brief (final reviewer agent)

What it does. uv's no-binary = true / no-binary-package = [...] make uv install a package only from an sdist, but every socket-patch PyPI artifact is a wheel, so a scan used to wire the patch, exit 0, and leave every later uv sync failing. Both modes now refuse before writing: vendored with the new pypi_uv_no_binary code, hosted with the existing redirect_uv_project_unsupported / redirect_uv_script_unsupported warnings (package skipped, scan still exits 0). The no-sources reader becomes a generic bool + package-list checker so no-binary gets the same precedence rules.

Risk: low. It only adds refusals in cases that were already broken after wiring; the no-sources path is refactored but its message text and precedence are unchanged (existing tests cover it). Controls in the tests confirm no-build*, another package's no-binary-package entry, and no-binary = false still wire.

Look here

Verified

Changes I made: none.

Open questions: none blocking. Machine-level UV_NO_BINARY / user uv.toml can't be seen by the scan; the docs say so.

Auto-merge is armed, so approving sends this straight to the merge queue.


Generated by Claude Code

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Ready for review Agent-verified: mergeable, CI green, Bugbot clean — awaiting human review

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants