Repository navigation
Go apply writes its replace into a root go.mod that go.work doesn't use, so the workspace build links the unpatched module while apply, apply --check and VEX all report it patched #458
Description
Activity
- addedbugSomething isn't workingSomething isn't workingbughuntFound by a scheduled package-manager bug-hunt agentFound by a scheduled package-manager bug-hunt agentpm:goGo modulesGo modules
on Oct 1, 2026 - added a commit that references this issue
on Oct 1, 2026 mikolalysenko commented
on Oct 1, 2026 CollaboratorAuthorMore actions[agent] Triaged as priority:p2 (Go). Shares root cause with #393: the agent-mode Go redirect (
patch/redirect/golang_local.rsapply_go_redirect/verify_go_redirect_state) never readsgo.work. It always edits the root go.mod and treats that replace as effective, whatever the workspace'suseset (this issue) or a go.workreplace(#393) says. Will be fixed together. Not a duplicate of #392/#393: here the version is selected and nothing overrides the replace.
Generated by Claude Code
mikolalysenko commented
on Oct 1, 2026 CollaboratorAuthorMore actions[agent] New information: hosted and vendored modes are affected too. Each reproduced 2× on main
61cfb9b(Linux, go 1.24.7). With this, all three Go modes are confirmed.The fixture: the root has go.mod + go.sum,
svc/is a member requiringexample.com/upstream v1.0.0, andgo.workisgo 1.21 / use ./svc(nouse .). The patch API is a local mock in the shapes ofe2e_golang_hosted_build.rs(hosted:view/<uuid>+/patches/packagewith agoproxyoverride) andvendor/golang.rsmount_go_granted(vendored: a granted tarball withsha512integrity).Hosted:
socket-patch get $UUID --mode hosted --yes --json … # exit 0, "redirected": 1, "rewrittenFiles": ["go.mod","go.sum"], "warnings": [] grep replace go.mod svc/go.mod go.work # only root go.mod: replace example.com/upstream v1.0.0 => patch.socket.dev/gopatch/<uuid> v1.0.0-socketpatch.1 (cd svc && go run .) # OUT: PRISTINE (also PRISTINE on a fresh day-2 machine) socket-patch vex … --product pkg:golang/example.com/consumer # exit 0, "status": "not_affected" (redirected)Vendored:
socket-patch vendor --vendor-source=service --api-url … # exit 0; root go.mod: replace … => ./.socket/vendor/golang/<uuid>/example.com/upstream@v1.0.0 (cd svc && go run .) # OUT: PRISTINE socket-patch vex … --product pkg:golang/example.com/consumer # exit 0, "status": "not_affected" (vendored)So the hosted rewriter (
redirect/mod.rsgolang arm),vendor/golang.rsvendor_go_module, and the manifest-less VEX discovery (vex/discover/golang.rs:113-120) all have the same go.work membership gap as the agent path.
Generated by Claude Code
mikolalysenko commented
on Oct 2, 2026 CollaboratorAuthorMore actions[agent] Shares root cause with #393, #531: the Go redirect never reads the enclosing
go.work. #531 adds a third symptom: applying in a second workspace member writes a conflicting per-member replace, which breaks the workspace build. Will be fixed together.
Generated by Claude Code
- added and removed
on Oct 8, 2026 mikolalysenko commented
on Oct 9, 2026 CollaboratorAuthorMore actionsv5 triage: P2, not a release blocker. Retain Go workspaces whose root module is excluded from go.work at P2; ordinary member-root lockfile patching takes priority.
This follows the maintainer's release scope: one normally completing CLI instance, prioritizing valid-lockfile patch/install behavior, compatibility, and actionable CLI UX.
[agent] Found by the scheduled Go modules bug-hunt routine (ledger #317).
Summary
The project root has both a
go.modand ago.work, and thego.workdoesn't list the root module (for exampleuse ./svconly, with nouse .). Agent-modeapplywritesreplace example.com/upstream v1.0.0 => ./.socket/go-patches/…into the rootgo.modand exits 0 with "1 of 1 targeted patch applied".In workspace mode, Go only honours
replacedirectives fromgo.workand from the go.mod files of the modules in itsuselist. A root go.mod that isn't a member is ignored completely. So every workspace build (cd svc && go build) still links the PRISTINE upstream. Despite that:apply --checkreports "Patch redirects are in sync (1 redirect checked)", exit 0.vexattestsnot_affected, exit 0.Positive control: with
use .added to the samego.work, the identical replace takes effect and the member builds PATCHED. The defect is therefore that the go.workuseset isn't consulted.This is different from #393 (a user
replacein go.work overriding ours) and #392 (a replace for a version the graph doesn't select). Here the version is selected and nothing overrides the replace; the file it was written to is simply not part of the build.Impact
A repo whose go.work leaves out the root module (a root tooling/meta module, or a go.work that lists only the services being developed) stays vulnerable, while all three socket-patch signals (apply, the
apply --checkCI gate and OpenVEX) say it's patched. Nothing warns.Repro (Linux, hermetic file GOPROXY, same fixture shape as
tests/e2e_golang_build.rs)Reproduced 2× per cell on go 1.24.7, and once each on 1.22.12 and 1.26.8.
Expected vs actual
replaceas the whole mechanism, withapply --checkas "a read-only audit that the committed redirects still match". The hosted contract (crates/socket-patch-cli/CLI_CONTRACT.md, golang row) already treats an inert replace as "diagnosed, no ref". When ago.workexists and doesn'tusethe directory holding the edited go.mod,applyshould do one of two things: write the replace where the workspace honours it (go.work, or a member go.mod), or refuse/warn.apply --checkandvexshould treat that replace as inert.OS × version
applyapply --checkvexVendored mode (
vendor) couldn't be exercised: v5vendorneeds the patch service (--vendor-source=service), which this sandbox can't reach. It writes the same root go.mod replace, so it's probably affected too (unverified).First bad version: not a regression. Release 4.0.0 behaves the same, and so does main
2463257.Suspect code
crates/socket-patch-core/src/patch/redirect/golang_local.rs:169apply_go_redirect→go_mod_edit::ensure_replace_entry: always edits the rootgo.mod, and never readsgo.workor itsusedirectives.crates/socket-patch-core/src/patch/redirect/golang_local.rs:452verify_go_redirect_state(apply --check): doesn't check that the root module is a workspace member whengo.workexists.crates/socket-patch-core/src/vex/discover/golang.rs:113-120: root go.mod replaces are extracted and checked against the rootrequireeven when the siblinggo.workexcludes.; the same membership gap applies to manifest-less hosted and vendored VEX.Backlog review — 2026-10-08
Priority: P2 → P1. An inert go.mod outside the go.work selection yields a successful but false safety attestation for the workspace build.