From b071e8ac26687038e9e1031c2cc66304e7765a71 Mon Sep 17 00:00:00 2001 From: Mikola Lysenko Date: Tue, 27 Oct 2026 16:35:16 -0400 Subject: [PATCH 1/9] Keep Go hosted pins after go mod tidy drops zip line 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 --- crates/socket-patch-cli/CLI_CONTRACT.md | 2 +- .../tests/e2e_golang_hosted_build.rs | 94 +++++++++++ .../tests/e2e_vex_lockfile/golang.rs | 19 ++- .../src/vex/discover/golang.rs | 150 ++++++++++++++---- 4 files changed, 228 insertions(+), 37 deletions(-) diff --git a/crates/socket-patch-cli/CLI_CONTRACT.md b/crates/socket-patch-cli/CLI_CONTRACT.md index 86d5b7805..2c4b5d445 100644 --- a/crates/socket-patch-cli/CLI_CONTRACT.md +++ b/crates/socket-patch-cli/CLI_CONTRACT.md @@ -531,7 +531,7 @@ Discovery is read-only, never touches the network, and never fails the run: a ma | bun | `bun.lock`; `bun.lockb` only when there is no `bun.lock` (bun reads exactly one) | URL tuple / binary remote-tarball resolution; version from the URL leaf. A user URL or `file:` tarball tuple / record whose `-.tgz` leaf names the same `name@version` is installed from its own spec, so every ref for that `name@version` is dropped | `.socket/vendor/npm//-.tgz` tuple / local-tarball resolution | `sha512-…`, required. A 2-tuple that Bun < 1.3.10 re-saved without its digest is still a reference, but it attests only from an installed tree. | | vlt | `vlt-lock.json` (lockfileVersion absent, `0` or `1`; a BOM-prefixed, unparseable, non-object or other-version lock is not read: diagnosed, no ref). `vlt.json` (read only for its `modifiers`) and `node_modules/.vlt-lock.json` are never wiring. | a registry node (any segment) whose slot [3] is a `/patch/npm/…` URL on the patch host with the leaf `-.tgz` of its DepID's `name@version`, whose embedded `/` path (when present) is that `name@version`, and slot [1] == name; version from the DepID | a `file` node `.socket/vendor/npm//-/node_modules/` (or a user-installed `-.tgz`) with slot [1] == name; version from the path. A same-`name@version` registry node, or a diagnosed Socket-shaped one, beside it is diagnosed, no ref. | slot [2] `sha512-…`, required (a hosted node without one is no reference). A same-`name@version` node on another registry, or a diagnosed Socket-shaped one, keeps the reference but withholds the lockfile basis: only an installed tree whose every store copy verifies attests. So does a lock some vlt release discards, the conditions of `redirect_vlt_lockfile_version_missing`, `redirect_vlt_old_lockfile_ignored` and `redirect_vlt_scalar_registry_ignored` (which in-run `--vex` withholds too): every hosted reference in it keeps no pin, and one `patched_ref_unattributable` names them. | | cargo | `Cargo.lock`, `Cargo.toml`, `.cargo/config` (else `.cargo/config.toml`) | `Cargo.lock` `source = "sparse+…//index/"`, confirmed by `Cargo.toml`: a crate the root manifest declares must pin `registry = "socket-patch-"`. A reverted pin is diagnosed, no ref. Another `[[package]]` of the same `name@version` from a non-Socket source (crates.io, git), which cargo locks beside the pin for a dependent added later and builds unpatched (#679), withholds the ref (`patched_ref_unattributable`, never attested) while `rollback` / `remove` still unwind it. | `[patch.] = { path = ".socket/vendor/cargo//-" }` — primarily the root `Cargo.toml` (v5 `vendor`; key-agnostic: `` is `package` when renamed, else the key, so `-socket-` keys count), also the project config (pre-v5 wiring), live only while the lock holds a sourceless entry for it that is not in `[[patch.unused]]`; a manifest entry cargo ignores — the project config redefines its key with another path, or a `[patch."https://github.com/rust-lang/crates.io-index"]` table replaces `[patch.crates-io]` — is diagnosed (`patched_ref_invalid`), no ref | `checksum` (v1: `[metadata]`), required | -| golang | `go.mod`, `go.work`, `go.sum`, `go.work.sum` | `replace M v => patch.socket.dev/gopatch/ ` | `replace M v => ./.socket/vendor/golang//M@v` | both go.sum lines, required. A replace that `require` no longer selects (`require M v'`) is inert: diagnosed, no ref. | +| golang | `go.mod`, `go.work`, `go.sum`, `go.work.sum` | `replace M v => patch.socket.dev/gopatch/ ` | `replace M v => ./.socket/vendor/golang//M@v` | the socket module's `/go.mod` go.sum line, required. The zip line (`h1:` of the module tree) is the locked integrity when present; `go mod tidy` prunes it when no package of the module is loaded and the build stays green, so the `/go.mod` line alone still attests from the lockfile. A conflicting or malformed line for the socket module+version is no pin. A replace that `require` no longer selects (`require M v'`) is inert: diagnosed, no ref. | | pypi | `uv.lock` (confirmed by `pyproject.toml` `[tool.uv.sources]` when present), PEP 723 `