Skip to content

Fix Go vex of +incompatible module patches (#484) - #1427

Merged
Mikola Lysenko (mikolalysenko) merged 3 commits into
mainfrom
agent/fix-go-vex-incompatible-purl-key
Oct 12, 2026
Merged

Mikola Lysenko (mikolalysenko) merged 3 commits into
mainfrom
agent/fix-go-vex-incompatible-purl-key

Conversation

@mikolalysenko

@mikolalysenko Mikola Lysenko (mikolalysenko) commented Oct 12, 2026 •

Copy link
Copy Markdown
Collaborator

LLM Description written by Claude Code:claude-opus-5-5

Fixes #484

Summary

socket-patch vex now attests an applied agent-mode Go patch for a
+incompatible module. Before, it said not_applied and exited 1 because
it couldn't match the go.mod spelling of the version to the manifest key.

Root cause

The patch API keys a +incompatible Go module as
pkg:golang/M@v2.0.0%2Bincompatible. vex rebuilds Go purls from
go.mod replace entries with build_golang_purl, which spells the +
literally, and then compared that string to manifest keys byte for byte:

Change (crates/socket-patch-cli/src/commands/vex.rs)

  • The Go purls in vex's go-patches synthesis, go.work-override filter and
    version-not-selected filter are now matched by release identity
    (PurlKey, percent-decoded) instead of by string equality.
  • The synthesis maps the copy dir under every manifest spelling of the
    release (deterministic; it used to be one exact key), and omissions are
    reported under the record's own purl (%2B) so --json consumers can
    join them to manifest keys.
  • Because `PurlKey` ignores qualifiers and subpath, synthesis now also maps a
    qualified Go key (e.g. `pkg:golang/M@v1?x=y`) to the replace's copy dir,
    which the old exact lookup never did. This stays fail-closed: each record is
    still verified against its own file hashes, and the copy path comes from
    go.mod coordinates, not the key. If a manifest holds both the `+` and
    `%2B` spellings, each omitted record gets its own warning, one per spelling.

Tests

New covgap_commands_vex::go_patches_replace_of_an_incompatible_module_matches_the_encoded_key
is hermetic and needs no Go toolchain. It uses a %2Bincompatible manifest
key, a go.mod +incompatible go-patches replace and a hash-matching copy dir:

case before after
plain redirect exit 1, package_not_found omission (red) exit 0, one not_affected statement for the %2B purl
go.work replace overrides it (masked by the above; attests if only the lookup is fixed) exit 1, omitted (go_workspace_override) under the %2B purl
require selects v2.1.0+incompatible (masked) exit 1, omitted (go_version_not_selected) under the %2B purl

Per-issue checklist:

Local runs (Linux, go 1.24.7):

  • cargo fmt --all -- --check: ok
  • cargo clippy --workspace --all-features -- -D warnings: ok
  • cargo test -p socket-patch-cli --all-features --test covgap_commands_vex --test e2e_golang_build --test e2e_golang_workspace_build --test e2e_vex_vendor --test e2e_vex_lockfile -- --include-ignored: 470 passed
  • --lib, e2e_vex, e2e_vex_redirect, vex_terminal_output, e2e_golang: all pass
  • cargo test --workspace --all-features --no-fail-fast: 14229 passed, 13 failed. None of the failures are in this diff's path, and all of them come from the sandbox: write-failure-injection tests that use chmod 0o555, which the sandbox's uid 0 ignores (covgap_commands_vendor, repair, core --lib write-failure tests, in_process_redirect), and one bun test that needs patches-api.socket.dev, which the sandbox proxy blocks. CI runs these as non-root.

No wrapper changes are needed: npm/, pypi/ and gem/ only dispatch to the binary.

Review notes (/code-review high)

Fixed: nondeterministic single-key lookup, omissions named under the
go.mod spelling, the missing version-not-selected coverage, and the
per-element PurlKey recompute.

Not changed:

  • The hosted-mode assume_applied / known_stale sets still compare by
    qualifier-stripped string. Both sides come from the API in the same
    spelling, and switching them to PurlKey would also change PyPI and NuGet
    name folding for every ecosystem, which is outside this fix.
  • The empty Start fix for #484 commit is this automation's claim marker.
    It goes away on a squash merge.

🤖 Generated with Claude Code

https://claude.ai/code/session_01P36de77ifXHcVkDgy5ozXo


Generated by Claude Code

Assisted-by: Claude Code:claude-opus-5-5
The patch API keys a +incompatible Go module as
@v2.0.0%2Bincompatible, but go.mod spells the version with a literal
+. vex compared the two spellings as plain strings, so an applied
agent-mode Go patch for such a module was never verified: vex said
not_applied and exited 1, leaving the patch out of the OpenVEX doc.

Match Go purls by release identity (PurlKey) when looking up the
manifest record for a go-patches replace, and in the go.work override
filter, so a go.work replace that overrides a %2B-keyed patch is still
caught and never attested.

Fixes #484

Assisted-by: Claude Code:claude-opus-5-5
Follow-up to the +incompatible fix. When go.work overrides a Go patch,
or the build selects another version, vex now names the omitted patch
by the manifest's own purl (with %2B), not the go.mod spelling, so
--json consumers can join omissions to manifest keys. The copy-dir
lookup now maps every record spelling of the release, deterministically.

Assisted-by: Claude Code:claude-opus-5-5
@mikolalysenko
Mikola Lysenko (mikolalysenko) marked this pull request as ready for review October 12, 2026 10:19
@mikolalysenko

Copy link
Copy Markdown
Collaborator Author

BugBot review


Generated by Claude Code

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ 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 f63372d. Configure here.

@mikolalysenko Mikola Lysenko (mikolalysenko) added the Ready for review Agent-verified: mergeable, CI green, Bugbot clean — awaiting human review label Oct 12, 2026
@mikolalysenko

Copy link
Copy Markdown
Collaborator Author

Labeled Ready for review at head f63372dfb5afe0d926ffaa88bb7fdef31f7e9801.

  • CI: 36/36 run checks green, 50 path-skipped, no failures (no main-wide failures).
  • Bugbot: reviewed f63372d, no findings.
  • Mergeable, no conflicts; does not touch CHANGELOG.md.

Slack announcement not sent this run (Slack send unavailable); the next run will retry.


Generated by Claude Code

@mikolalysenko

Copy link
Copy Markdown
Collaborator Author

Final review brief

What it does: Fixes #484. The patch API writes a +incompatible Go version as %2Bincompatible, but go.mod spells it with a literal +. vex compared the two strings exactly, so it never verified an applied Go patch for such a module and reported it not_applied (exit 1). Now all three Go paths in vex match purls by decoded release identity (PurlKey): go-patches synthesis, the go.work-override filter and the version-not-selected filter.

Risk: low. The change only touches Go purl matching in vex, and it fails closed:

  • Synthesis gains candidates, but each record is still verified against its own hashes (verify.rs:186-194).
  • The two filters can only omit more than before, never attest more.
  • Go module paths stay case-sensitive, and decoding can't reach the copy path, which is built from go.mod coordinates.

Look here

  • vex.rs:1679-1721: synthesize_go_patches, the by_release index and the per-record copy mapping
  • vex.rs:833-849: the go.work-override filter (was string equality, now PurlKey)
  • vex.rs:866-898: the version-not-selected filter, which now reports under the record's own purl
  • covgap_commands_vex.rs:1083-1177:`` the new three-case test

Verified

  • cargo test -p socket-patch-cli --test covgap_commands_vex: 34 passed.

  • Mutation checks:

    • With main's vex.rs, the new test fails on the attest case.
    • Reverting only the go.work filter makes it fail on the omission case.

    So the test covers both halves.

  • CHANGELOG.md is untouched and there's no debug code.

  • CI: ci-ok and clippy are green, 86/86 check runs are passing or skipped, and Bugbot passed. No unresolved threads.

Changes I made: none.

Open questions (non-blocking):

  • Synthesis now also matches Go manifest keys that carry qualifiers or a subpath (e.g. pkg:golang/M@v1?x=y), which the old exact lookup never did. That's safe because verification is per record, but neither the description nor a test mentions it.
  • When a manifest has both + and %2B spellings, each filter warns once per spelling.

Auto-merge is armed, so approving sends this straight to the merge queue.


Generated by Claude Code

Merged via the queue into main with commit 4e146dd Oct 12, 2026
86 checks passed
@mikolalysenko
Mikola Lysenko (mikolalysenko) deleted the agent/fix-go-vex-incompatible-purl-key branch October 12, 2026 16:11
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Ready for review Agent-verified: mergeable, CI green, Bugbot clean — awaiting human review

Projects

None yet

3 participants