Skip to content

Fix hosted Hatch ignoring uv sources (#673) - #1706

Open
Mikola Lysenko (mikolalysenko) wants to merge 3 commits into
mainfrom
agent/fix-hatch-uv-sources-pin
Open

Mikola Lysenko (mikolalysenko) wants to merge 3 commits into
mainfrom
agent/fix-hatch-uv-sources-pin

Conversation

@mikolalysenko

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

Copy link
Copy Markdown
Collaborator

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

Fixes #673

What it fixes

Hosted Hatch scans could report redirected and exit 0 while every fresh Hatch environment still installed the unpatched wheel, or failed to install at all. This happened when a Hatch environment uses the uv installer and the project has a [tool.uv.sources] entry for the patched package.

Root cause

Hosted mode rewrites the [project] declaration to a direct reference (six @ <patch url>#sha256=…), but the Hatch planner (crates/socket-patch-core/src/utils/hatch.rs) never read [tool.uv.sources]. Hatch's uv installer runs uv pip install -e ., and uv resolves a project requirement through its tool.uv.sources entry instead of the direct reference. A url or path source installs the upstream wheel, and a git source fails with "conflicting URLs".

Change

  • utils/hatch.rs: when any Hatch environment uses the uv installer (installer = "uv" or a non-empty uv-path, in pyproject or hatch.toml, or a non-empty HATCH_ENV_TYPE_VIRTUAL_UV_PATH), a patched package with a non-index [tool.uv.sources] entry (url, path, git, workspace, empty array, or a marker array with any non-index member) can no longer be rewritten in [project].dependencies or optional-dependencies. The refusal happens before anything is written, like Hatch's own source tables. The hosted lane reports it as redirect_hatch_unsupported and leaves the dep unconfirmed, so the scan fails closed. Other packages in the same batch still rewrite.
  • Still rewritten, matching the issue's measured matrix: environment dependencies (Hatch passes them to uv as plain strings), index-only sources (the direct URL wins), and the pip installer (pip ignores the table).
  • docs/testing/hatch.md: documents the refusal.
  • Vendored mode is unchanged. It already refuses the uv installer outright.
  • npm/pypi/gem wrappers only dispatch to the binary, so they need no change.

Tests

Issue Regression test red → green
#673 utils::hatch::tests::uv_sources_refuse_project_rewrites_under_the_uv_installer (url / path / git / case-folded name / marker array × project deps / optional deps × installer / uv-path × pyproject / hatch.toml; plus the allowed shapes, the env-var switch, an empty array and a mixed batch) fails on main, passes here
#673 patch::redirect::hatch_tests::hatch_uv_source_leaves_the_dep_unconfirmed (lane-level: no pyproject write, uuid unconfirmed, redirect_hatch_unsupported) fails on main, passes here

Run locally:

  • cargo fmt --all -- --check: ok
  • cargo clippy --workspace --all-features -- -D warnings: ok
  • cargo test -p socket-patch-core --lib hatch: 64 passed. With the fix disabled, both new tests fail.
  • cargo test --workspace --all-features --no-fail-fast: 234 targets ok. 11 tests fail only in this container, and the same tests fail on main here. They are chmod-based write-failure tests, which can't fail while the container runs as root (in_process_redirect, repair, 4 core lib tests). The other two are e2e_bun_lockb tests, because the container has bun 1.4.4 instead of CI's version. None touch Hatch.
  • SOCKET_PATCH_HATCH_E2E_VERSION=1.18.1 cargo test -p socket-patch-cli --all-features --test e2e_vex_build hatch:: -- --ignored: 6 passed

/code-review high findings not fixed

  • Index sources are allowed through. The issue reporter measured six = { index = "internal" } with Hatch 1.18.1 + uv and the direct URL won ("pass"), so refusing would be a false refusal. The reviewer's claim is unmeasured.
  • uv workspace-root sources aren't read: only the project's own pyproject is checked. A Hatch project that is also a uv workspace member is a rare shape. Follow-up if it is reported.
  • no-sources isn't consulted. The refusal fails closed (agent mode still works), so this costs a false refusal, never an unpatched install.
  • A pyproject uv setting shadowed by a hatch.toml envs still counts as uv. This is the existing require_pip_installer_documents behavior shared with vendored mode, and it also fails closed.
  • VEX discovery crediting an already-written reference under a uv source is out of scope. The issue notes that vex already omits the package after inspecting the env.
  • Round recomputing the source set each round is a minor cost on a tiny TOML walk, so I left it.

Note

Medium Risk
Changes hosted Hatch redirect preconditions for uv + [tool.uv.sources]; behavior is fail-closed with new tests, but misclassification could block valid scans or leave edge cases (workspace-only sources) unhandled.

Overview
Fixes #673, where hosted Hatch scans could look successful while uv still installed the unpatched wheel when a Hatch env uses the uv installer and [tool.uv.sources] overrides the rewritten project pin.

The Hatch planner now reads [tool.uv.sources] when uv is active (installer = "uv", uv-path, or HATCH_ENV_TYPE_VIRTUAL_UV_PATH). For packages with a non-index source (url, path, git, mixed marker arrays, empty arrays), it refuses rewriting [project].dependencies and optional-dependencies before any write—same fail-closed pattern as other unsupported Hatch shapes. Hosted redirect leaves the dep unconfirmed, emits redirect_hatch_unsupported, and does not touch pyproject.toml. Environment dependency tables, index-only sources, the pip installer, and other packages in a batch still rewrite as before.

docs/testing/hatch.md documents this refusal. Regression coverage spans utils/hatch (matrix of source shapes and mixed batches) and redirect lane test hatch_uv_source_leaves_the_dep_unconfirmed.

Reviewed by Cursor Bugbot for commit 84d95a4. Configure here.


Generated by Claude Code

Assisted-by: Claude Code:claude-opus-5-5
When a Hatch environment uses the uv installer, uv resolves a project
dependency through the project's [tool.uv.sources] entry instead of
the direct reference hosted mode writes. A url or path source then
installs the unpatched wheel while the scan reports "redirected", and
a git source breaks every install with conflicting URLs.

Hosted Hatch now refuses such a pin before writing, as it already does
for Hatch's own source tables, and reports redirect_hatch_unsupported.
Environment dependencies, index-only sources and the pip installer
are unaffected and still rewrite.

Fixes #673

Assisted-by: Claude Code:claude-opus-5-5
HATCH_ENV_TYPE_VIRTUAL_UV_PATH switches Hatch to the uv installer with
no file setting, so a url or path source still shadowed the hosted
pin there. An empty source array is no longer treated as index-only.

Refs #673

Assisted-by: Claude Code:claude-opus-5-5
@mikolalysenko

Copy link
Copy Markdown
Collaborator Author

BugBot review


Generated by Claude Code

@mikolalysenko
Mikola Lysenko (mikolalysenko) marked this pull request as ready for review October 24, 2026 03:14

@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 84d95a4. Configure here.

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

Copy link
Copy Markdown
Collaborator Author

Ready for review at 84d95a41da3ec23f57408b2b06cc2402bc280033.

  • CI: 38/38 non-skipped checks green (50 skipped), no main-wide failures.
  • Bugbot: reviewed this head, no findings; no open review threads.
  • Reviewer focus: the fail-closed refusal in utils/hatch.rs when uv is active and [tool.uv.sources] gives a package a non-index source (url/path/git/mixed/empty), and the redirect_hatch_unsupported path in patch/redirect/mod.rs.

Generated by Claude Code

@mikolalysenko

Copy link
Copy Markdown
Collaborator Author

Labeled Ready for review by the burn-down agent.

  • Head: 84d95a41da3ec23f57408b2b06cc2402bc280033
  • CI: 38/38 non-skipped checks green (50 skipped), no main-wide failures
  • Bugbot: reviewed 84d95a4, no findings; no open review threads
  • Mergeable, no CHANGELOG.md changes
  • Reviewer focus: the uv-sources refusal in crates/socket-patch-core/src/utils/hatch.rs, and the HATCH_ENV_TYPE_VIRTUAL uv switch handling added in the last commit

Generated by Claude Code

@mikolalysenko

Copy link
Copy Markdown
Collaborator Author

Final review brief

What it does. When a Hatch environment uses the uv installer, uv resolves a project requirement through [tool.uv.sources] and ignores the hosted direct reference. Hosted scans could therefore report redirected while uv still installed the unpatched wheel (#673). Now, a patched package that has a non-index uv source (url, path, git, workspace, an empty array, or a marker array with any non-index member) is refused in [project].dependencies and optional-dependencies before anything is written. The scan fails closed with redirect_hatch_unsupported, and other packages in the batch still rewrite.

Risk: low–medium. The change only adds refusals, so the worst case is a false refusal: the user is pointed to agent mode and never gets an unpatched install. The uv detection reuses the existing require_pip_installer_documents check, which vendored mode already relies on. Pip-installer projects, environment dependencies and index-only sources behave exactly as before.

Look here

  • hatch.rs:428-438: refuse_uv_source, which records the refusal on the target in the check pass, so the apply pass writes nothing for it
  • hatch.rs:445-480: uv_source_names, which decides uv detection and what counts as index-only
  • hatch.rs:587-590: reads HATCH_ENV_TYPE_VIRTUAL_UV_PATH from the process env
  • hatch.rs:383-401: applied only to the project tables, not to env dependencies
  • redirect/mod.rs:27172: lane-level test that checks the dep is left unconfirmed

Verified. I read the full diff and the check/apply round logic around it. A target refused in the check pass is skipped in the apply pass, so a partial write can't happen. cargo test -p socket-patch-core --lib hatch passes on the head (64/64). With uv_sources forced empty, both new tests fail (uv_sources_refuse_project_rewrites_under_the_uv_installer and hatch_uv_source_leaves_the_dep_unconfirmed), so they exercise the fix. CI is 38/38 green on the head (50 skipped by path filters), and ci-ok and clippy both pass. Bugbot reviewed the head with no findings. There are no review threads, and CHANGELOG.md is untouched. The PR body lists the known fail-closed gaps that weren't fixed (uv workspace-root sources, no-sources), and they are reasonable to leave.

Changes I made. None.

Open questions. None.

Auto-merge (squash) is armed: approving sends this PR 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

2 participants