Repository navigation
Keep Go hosted pins after go mod tidy drops the zip line - #1748
Mikola Lysenko (mikolalysenko) wants to merge 3 commits into
Conversation
When nothing imports a package from a hosted-patched Go module (it is only a transitive requirement), `go mod tidy` keeps just the socket module's `/go.mod` go.sum line and drops its zip line. The build still succeeds offline, but VEX discovery required both lines, so the patch was skipped as `package_not_found` instead of attested. The `/go.mod` line for the exact socket module+version is now enough to recognise the pin. Without the zip line the ref has no locked integrity and is not integrity-required, so it attests from the lockfile: go compiles none of the module's packages, and the module path carries the patch uuid. A zip line, when present, must still be the single well-formed hash and supplies `locked_integrity`. Conflicting hashes or a malformed line for the socket module+version still mean no pin. The hosted writer is unchanged: it still writes both lines and refuses a module outside the build graph. Assisted-by: Claude Code:claude-opus-5-5
A `/go.mod`-only go.sum line also exists for versions MVS reads but does not select, so in a go < 1.17 graph a `/go.mod`-only hosted pin whose version go.sum shows is not selected is now reported as inert instead of attested. In workspace mode go verifies against go.work.sum and every member's go.sum, so discovery now reads those too (in-root members only) and a member's zip line still supplies the locked integrity. go.sum parsing now follows go: a line of other than three tokens makes the whole file unusable, a non-dirhash `h1:` breaks that module's pin, and hashes of other algorithms are ignored. Re-running the hosted rewrite over a project `go mod tidy` pruned to the `/go.mod` line now leaves go.sum alone instead of re-adding the zip line the next tidy removes again. Assisted-by: Claude Code:claude-opus-5-5
Assisted-by: Claude Code:claude-opus-5-5
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes using high effort and found 1 potential issue.
Bugbot Autofix is ON, but none of the reported issues met your autofix severity threshold.
Comment @cursor review or bugbot run to trigger another review on this PR
Reviewed by Cursor Bugbot for commit 14057c8. Configure here.
|
Burn-down agent: labeled Ready for review at head
Generated by Claude Code |
Final review briefWhat it does. When Risk: low. The only new attestation path covers modules whose packages go doesn't compile: if a package were loaded, Look here
Verified
Changes I made: none. Open questions (non-blocking; can be follow-ups):
Auto-merge is armed, so approving sends this PR straight to the merge queue. Generated by Claude Code |

Problem
A root module requires
b,brequiresa, nothing imports a package froma, and the root has the hostedreplace a v => patch.socket.dev/gopatch/<uuid> <sver>. Herego mod tidykeeps only the socket module's/go.mod h1:go.sum line. It drops the zip line because Go keeps just the/go.modline for a module that provides no loaded package.go build -mod=readonlystill succeeds, but VEX discovery required both lines, sosocket-patch vexskipped the patch aspackage_not_foundinstead of attesting it.The new real-toolchain test reproduces this with go1.26.3. A reviewer first found it with go1.18.1.
Change
Reader (
vex/discover/golang.rs)/go.modline for the exact socket module+version is now enough to recognise the hosted pin. When the zip line is present, it must be the one well-formed hash, and it supplieslocked_integrityas before.locked_integrityandintegrity_required = false, so it attests from the lockfile. Go compiles none of the module's packages in this state, and the module path carries the patch uuid./go.modline of versions it reads but does not select. So in a go < 1.17 graph, a/go.mod-only pin is now diagnosed as inert (ref_invalid, no ref) when go.sum shows that another version is selected (go_build_list::select). This matches depscan#29121, which only annotates the selected version.go.sum. With ago.work, it also readsgo.work.sumand each in-rootusemember'sgo.sum, because Go verifies against all of them and a member's go.sum may hold the zip line.h1:, for the socket module+version mean no pin.Writer (
patch/redirect/mod.rs)redirect_golang_not_in_module_graph./go.modline and no zip line, leaves go.sum alone and still confirms the uuid. Before, it re-added the zip line, and the nextgo mod tidyremoved it again.Docs
CLI_CONTRACT.mdand the confirmation paragraph are updated.integrity_requiredcontract indiscover/mod.rsnow allows the choice to depend on lock state, as gem already does.Other readers checked
list,rollback,remove,repair, the hosted engine and upstream restore (redirect/upstream/golang.rs) find hosted Go pins from go.mod alone. Discovery already emitted the ref whatever go.sum held, so no change was needed. Onlylockfile_basis_ok, which VEX uses, depended on both lines.Tests
cargo test -p socket-patch-core --libfiltered tovex::,golang,go_sum,tidyandworkspace: all pass. New unit tests cover:/go.mod-only pin, in both go.mod and go.work flavors/go.modhash casesholds_only_go_mod_linee2e_vex_lockfilegolang cells (22): cell g gains a/go.mod-line-only case that attests(redirected)without an installed copy.e2e_golang_hosted_build(23), with a new real-toolchain regressiontidy_pruned_zip_line_still_pins_the_hosted_replace, which:go mod tidy/go.modline keptlockfile_basis_ok()e2e_golang_hosted_state(29) ande2e_golang_workspace_build(16) pass.package_not_found, and the toolchain test fails itslockfile_basis_okassertion.cargo clippy --locked -p socket-patch-core -p socket-patch-cli --all-features -- -D warnings(the CI command) is clean./code-review highran on the first commit. Its findings are addressed in the second commit.🤖 Generated with Claude Code
Note
Medium Risk
Changes VEX/discovery attestation rules for hosted Go pins and go.sum interpretation; incorrect edge-case handling could attest or skip patches wrongly, but scope is golang hosted lockfile logic with extensive new tests.
Overview
Fixes manifest-less VEX and discovery for hosted Go patches when
go mod tidyremoves the socket module’s ziph1:line but keeps the/go.modline (transitive replace with no imported packages).Discovery now treats a well-formed
/go.modpin as sufficient:integrity_requiredis false in that state solockfile_basis_ok()allows lockfile attestation without the zip line; when the zip line exists, behavior is unchanged. It also readsgo.work.sumand in-root workspace membergo.sumfiles, applies stricter go.sum parsing (malformed lines, conflicting hashes), and marks/go.mod-only pins inert on pre-1.17 graphs when MVS selects another version.Hosted redirect re-runs skip re-inserting the zip line when the replace already matches and
go.sumis exactly the tidy go.mod-only pair (holds_only_go_mod_line), avoiding tidy churn.Docs update the golang hosted confirmation and discovery-table rules;
integrity_requiredmay depend on lock state (like gems).Reviewed by Cursor Bugbot for commit 14057c8. Configure here.
Generated by Claude Code