Hacktoberfest 2026: những issue maintainer đã đánh dấu cho tháng Mười, đang mở và phù hợp người mới. Xem issue Hacktoberfest

Vendored uv transitive package later added as a direct dependency (`uv add six==1.16.0`): `vendor --revert` / `remove` / `rollback` half-revert the pair, so `uv sync --locked` fails and `vendor --check` claims nothing references the wheel

Đã đóng
#1,374 3 bình luận 0 reaction 0 người được giao Xem trên GitHub

Maintainer thường phản hồi trong vòng 1 ngày

@mikolalysenko đang làm issue này rồi.

Từ ngày 11/10/2026.

  • #1384 của @mikolalysenko — đang mở

Đánh giá

Độ khó
4/5
Thời gian dự kiến
3-5 ngày
Mức phù hợp với người mới
28/100
Loại issue
Lỗi
Độ rõ ràng
Khá rõ ràng
Mức độ hoạt động
Sôi nổi
Công nghệ
python, rust
Lĩnh vực
build-system, cli

Hướng nghiên cứu

Start with revert_uv in crates/socket-patch-core/src/vendor/pypi_uv.rs (around line 795), which reverts only the recorded wiring fragments, then the residual-reference guard in crates/socket-patch-core/src/vendor/pypi.rs (around line 2416). Reproduce with the repro steps in the issue, then check that uv sync --locked passes and vendor --check agrees with uv.lock after vendor --revert. Done means the root requires-dist element is restored or the revert fails closed, and the check no longer reports a false 'wiring missing'.

Do mô hình lập chỉ mục viết ra từ nội dung của issue.

Mô tả

agent:claimed agent:triaged bug bughunt pm:uv priority:p1

[agent] Found by the scheduled uv bug-hunt routine (ledger #310).

Summary

Vendor a transitive package in a uv project (here six, pulled in by python-dateutil and held at 1.16.0 by a user constraint-dependencies). Vendored mode wires it through [tool.uv] override-dependencies + [tool.uv.sources] and records five wiring entries: uv_override, uv_sources_entry, uv_lock_package, uv_lock_manifest_overrides and uv_lock_manifest_constraints.

Then the user promotes it to a direct dependency, for example to pin it: uv add six==1.16.0. uv writes a new root requires-dist element, { name = "six", path = ".socket/vendor/pypi/<uuid>/six-1.16.0-…whl" }, because the socket-written source routes it. socket-patch never recorded that element.

vendor --revert, remove six and rollback then revert every recorded fragment. They drop the sources line and the override, and put the lock's [[package]] and [manifest] back on PyPI. They leave the root requires-dist element still pointing at the wheel. Only after writing does the residual-reference guard notice that uv.lock still names the uuid dir, and it keeps the wheel and the ledger entry.

The result is a pair uv rejects:

  • uv sync --locked fails with "The lockfile at uv.lock needs to be updated".
  • vendor --revert exits 0. remove and rollback exit 1.
  • vendor --check then exits 1 with wiring missing: no lockfile or config references .socket/vendor/pypi/<uuid> any more … re-run socket-patch vendor to rewire it. That's false, because uv.lock still references it, and the remedy re-vendors the package the user just asked to unwind.

Impact

A user who pins a vendored transitive dependency directly, which is a normal uv add, can't unwind it cleanly. Every --locked / --frozen-checked CI install breaks after the revert. The only recovery is to know to run uv lock by hand and then vendor --revert again (that converges).

The same uv add after uv remove python-dateutil (the #1287 shape plus a direct re-add) fails the same way, on main and on PR #1337.

Repro

Requires a patch API serving a [email protected] patch. I used the routine's local mock with --api-url/--patch-server-url/--vendor-url http://127.0.0.1:8765, abbreviated sp below.

mkdir demo && cd demo
cat > pyproject.toml <<'EOF'
[project]
name = "demo"
version = "0.1.0"
requires-python = ">=3.9"
dependencies = ["attrs>=20"]

[tool.uv]
constraint-dependencies = ["six==1.16.0"]
EOF
uv add -q python-dateutil==2.9.0.post0 && uv sync -q
sp scan --mode vendored --yes            # six wired via override + sources, exit 0
uv add -q six==1.16.0                    # promote to direct; uv.lock root requires-dist now has { name = "six", path = ".socket/vendor/pypi/<uuid>/…" }
uv sync -q --locked                      # ok, six patched
sp vendor --check; echo $?               # 0
sp vendor --revert --json; echo $?       # 0: vendor_revert_residual_reference + vendor_artifact_kept + vendor_revert_kept
uv sync -q --locked                      # error: The lockfile at `uv.lock` needs to be updated
sp vendor --check; echo $?               # 1: "wiring missing: no lockfile or config references … re-run socket-patch vendor"
grep -n aaaaaaaa uv.lock                 # requires-dist = [ …, { name = "six", path = ".socket/vendor/pypi/…/six-1.16.0-py2.py3-none-any.whl" } ]

After the revert, pyproject.toml has no sources or override, and [[package]] six is back on registry = "https://pypi.org/simple". The root [package.metadata] requires-dist still carries the path element.

Expected vs actual

  • Expected: the revert leaves a pair uv sync --locked accepts. Either restore the root element to the specifier pyproject.toml declares now ({ name = "six", specifier = "==1.16.0" }, the #840 respell rule for root requirement entries), or, failing that, write nothing and drift-keep both files (fail closed, as the PEP 723 script lane already does for this exact shape). CLI_CONTRACT's revert contract keeps the artifact when a file still references it. It doesn't allow a half-written uv pair, and #806 / #821 / #840 were the same class of half-revert.
  • vendor --check should not claim "no lockfile or config references" the uuid dir while uv.lock does.
  • Actual: pyproject and four of the five lock fragments are reverted, the root requires-dist path element is left, uv sync --locked fails, and vendor --revert exits 0.

Matrix (Linux, main 85105c9)

unwind uv 0.5.31 uv 0.12.24
vendor --revert (parent kept, uv add six==1.16.0) fail: exit 0, --locked fails, check 1 fail (same)
remove six --yes fail: exit 1, --locked fails fail
rollback --yes fail: exit 1, --locked fails fail
vendor --revert after uv remove python-dateutil + uv add six==1.16.0 fail (main and PR #1337) fail (main and PR #1337)
hosted takeover (scan --mode hosted) pass: redirect_vendored_revert_failed, files untouched pass
PEP 723 script, uv add --script s.py six==1.16.0, then revert fail-closed: drift-keep, both files untouched, still patched same
recovery: uv lock, then vendor --revert pass, converges, check 0 pass

The checks are text-level uuid checks with no OS-specific branch, so I didn't run a probe.

Suspect code

  • crates/socket-patch-core/src/vendor/pypi_uv.rs:795 (revert_uv): only the recorded records are reverted. The transitive wiring has no uv_lock_requires_dist record, so a root element the user's uv add created through the socket-written source is never restored, and nothing checks the reverted pair for leftover uuid references before writing.
  • crates/socket-patch-core/src/vendor/pypi.rs:2416 (residual-reference guard): it runs after the flavor revert has already written, so it can only keep the artifact, not prevent the inconsistent write.
  • The vendor --check "wiring missing" verdict ignores a requires-dist path element in uv.lock.
Ngôn ngữ chính
Rust
Star
8
Fork
1
Merge trung bình
19 giờ 1 phút
Pull request đã merge (30 ngày)
473

Chuẩn bị môi trường

Bắt đầu từ đâu

  1. Đọc hết issue, rồi đọc hướng dẫn đóng góp của dự án.
  2. Bình luận trên issue rằng bạn sẽ nhận — tránh hai người làm cùng một việc.
  3. Fork repository và làm thay đổi trên một nhánh.
  4. Mở pull request có tham chiếu số hiệu của issue.

Issue khác của SocketDev/socket-patch

Tất cả issue của SocketDev/socket-patch

Issue tương tự

Thêm issue về Rust

Nhận issue mới trong hộp thư của bạn

Bản tóm tắt ngắn những issue GitHub phù hợp với người mới.