Fix Hatch takeover leaving direct-ref permission (#674) - #680
Mikola Lysenko (mikolalysenko) wants to merge 4 commits into
Conversation
Assisted-by: Claude Code:claude-opus-5-5
After a hosted -> vendored takeover of two or more Hatch packages, rollback, remove and vendor --revert left allow-direct-references = true (plus empty [tool] / [tool.hatch] tables) in pyproject.toml, silently disabling Hatchling's direct-reference guard. The takeover unwinds hosted pins one at a time, so when the first package is vendored the other packages' hosted references still hold the permission hosted mode added, and the vendored ledger recorded that as the permission's original value. The ledger now records the value the permission has once those live non-vendored references are gone, which is the rule the hosted unwind already applies. Both lanes share one helper for dropping the permission and its emptied tables. Fixes #674 Assisted-by: Claude Code:claude-opus-5-5
Covers #674 through the hosted rewrite, discovery and the takeover's per-pin restore_upstream, rather than a simulated unwind, and checks both revert orders come back to the pre-hosted pyproject bytes. Assisted-by: Claude Code:claude-opus-5-5
Assisted-by: Claude Code:claude-opus-5-5
|
BugBot review Generated by Claude Code |
There was a problem hiding this comment.
✅ 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 d3076b5. Configure here.
|
Ready for review — head
Generated by Claude Code |
|
Reviewed The first vendored permission record now excludes permission held by remaining hosted references. Shared ownership survives selective removal, and final cleanup restores Hatchling’s direct-reference guard. The extracted hosted cleanup helper preserves its existing behavior. Validation:
A separate exploratory case found existing hosted rewriting removes a comment attached to the permission value. This reproduced before any vendoring with both this binary and a control whose Hatch code matches main; it is preserved separately from the eight passing cases and is not introduced here. |
LLM Description written by Claude Code:claude-opus-5-5
Fixes #674
Summary
After a hosted→vendored takeover of two or more Hatch packages,
rollback,removeandvendor --revertused to leaveallow-direct-references = true(plus empty[tool]/[tool.hatch]tables) behind. That silently turned off Hatchling's direct-reference guard and kept the pyproject dirty. With this change the pyproject comes back byte-exact.Root cause
The takeover in
commands/vendor.rscallsrestore_upstreamwith one hosted pin per candidate inside the vendoring loop. When the first Hatch package is vendored, the other packages' hosted direct references are still live, and so is the permission hosted mode added for them. The vendoredhatch_permissionrecord snapshotted that state as itsoriginal. Later packages clone the same record. So once the last reference was unwired, the revert "restored" a permission the user never had.Fix
vendor/pypi_hatch.rs::wire: a new permission record now checks the project for a direct reference the vendored ledger doesn't own (anything that isn't a{root:uri}/.socket/vendor/…reference). If there is one, the permission it finds is held for those references, so the record'soriginalis the document with that permission removed, along with any tables that leaves empty. The hosted unwind already applies this rule: it drops the permission once no project direct reference is left. Because the decision is made once when the record is created, every package that clones the record inherits it, whatever the revert order.utils/hatch.rs:drop_direct_reference_permissionandpermission_keysnow live here. The hosted unwind (redirect/upstream/pypi.rs) and the vendored ledger share them, so both lanes produce the same bytes.revertis unchanged. A permission the user set themselves (with no non-vendored direct reference live at wiring time) is still recorded and restored verbatim.I didn't restructure the generic per-pin takeover loop. It carries many per-candidate refusal gates, and the pnpm (#636) and uv (#670) leftovers have different mechanisms; #672 covers those.
Tests (red → green)
vendor::pypi_hatch::tests::takeover_through_hosted_unwind_reverts_byte_exactdiscover_patched_refs, per-pinrestore_upstreamand vendoredwire, reverted in both orders[tool]…allow-direct-references = true)vendor::pypi_hatch::tests::takeover_snapshot_of_hosted_permission_is_not_restored[metadata](sibling key kept)vendor::pypi_hatch::tests::user_permission_survives_vendored_revertPer-issue checklist:
vendor --revert(all three go throughpypi_hatch::revert) → byte-exact pyproject. Covered by the first two tests above.Local validation
cargo clippy --workspace --all-features -- -D warnings: clean.cargo test -p socket-patch-core --lib -- pypi_hatch hatch upstream: 87 passed.cargo test --workspace --all-features --no-fail-fast: everything passes except 12 tests that simulate write or removal failures withchmod/ read-only dirs. The sandbox runs as root, which bypasses those permissions. None of them touch Hatch code. CI runs unprivileged.SOCKET_PATCH_HATCH_E2E_REQUIRED=1 SOCKET_PATCH_HATCH_E2E_VERSION=1.18.1 cargo test -p socket-patch-cli --all-features --test e2e_vex_build -- hatch:: --ignored: 4 passed.rustfmt --checkis clean on the touched files. Note thatcargo fmt --all -- --checkfails on main itself (about 130 files, from045d7ec), and CI doesn't run rustfmt. I kept those unrelated reformats out of this PR; only one existing line inutils/hatch.rswas reflowed.Behaviour note
If a user had both their own direct reference and
allow-direct-references = truebefore vendoring, the permission is kept as long as any project direct reference remains. It is dropped only once none is left, which is what hosted mode already does.🤖 Generated with Claude Code
Note
Medium Risk
Changes vendored Hatch permission ledger semantics and shared TOML cleanup used on revert; well-covered by new tests but affects dependency wiring rollback paths.
Overview
Fixes #674: after a hosted→vendored Hatch takeover with multiple packages, revert/rollback no longer leaves
allow-direct-references = true(and empty[tool]/[tool.hatch]tables) when the project should return to its pre-hosted bytes.Vendored wiring now treats
hatch_permission“original” as the file without the direct-reference permission when non-vendored project direct refs are still live at wire time (e.g. another package’s hosted pin during per-pin takeover). User-set permissions are still snapshotted verbatim.Shared Hatch helpers —
permission_keysanddrop_direct_reference_permission— moved intoutils/hatch.rsso hosted unwind (restore_hatch) and the vendored ledger apply the same cleanup rule.Adds regression tests for takeover/revert order, full hosted→vendor lane, and user-owned permissions in
pyproject.toml/hatch.toml.Reviewed by Cursor Bugbot for commit d3076b5. Configure here.
Generated by Claude Code