fix(maven): send the official Maven CLI user agent to the maven2 registry; refresh npm wrapper lock for published 4.0.0 platform packages - #233
Merged
Mikola Lysenko (mikolalysenko) merged 2 commits intoAug 27, 2026
Conversation
…stry Maven Central blocks/rate-limits user agents containing "socket", so the fallback pom download in the maven vendor backend (acquire_upstream_pom → fetch_pom_bytes) was refused when sent as SocketPatchCLI/x.y.z — the only CLI code path that talks to Maven Central. maven2 registry requests now identify exactly as the official Maven CLI (Apache-Maven/<v> (Java <v>; <os> <ver>), pinned per-OS so the string stays deterministic). Socket API requests keep the honest CLI UA. Tests: shape + no-"socket" guard on the constant, and a wiremock test that only serves the pom when the Maven CLI UA actually goes out on the wire. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Mikola Lysenko (mikolalysenko)
force-pushed
the
fix/maven-central-user-agent
branch
from
August 27, 2026 17:25
b72c0dd to
90aac5b
Compare
Wenxin Jiang (Wenxin-Jiang)
approved these changes
Aug 27, 2026
….0 platform packages The lock was committed while the 4.0.0 @socketsecurity/socket-patch-* platform packages were still unpublished (npm publish was pending 2FA at release time), so npm silently omitted their node_modules entries. Now that they are live on the registry, version-sync's `npm install --package-lock-only` re-adds them, making the sync a non-no-op and failing release-readiness on every PR. Committing the refreshed lock restores the no-op invariant. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Collaborator
Author
|
CI note: |
Mikola Lysenko (mikolalysenko)
enabled auto-merge (squash)
August 27, 2026 17:56
Mikola Lysenko (mikolalysenko)
deleted the
fix/maven-central-user-agent
branch
August 27, 2026 17:56
Mikola Lysenko (mikolalysenko)
added a commit
that referenced
this pull request
Aug 31, 2026
The release-readiness gate re-runs version-sync.sh and compares the regenerated npm/socket-patch/package-lock.json byte-for-byte, so the lock's canonical shape is defined by whatever npm regenerates it. npm 11 adds libc arrays that npm 10 omits, which is how the #233 refresh (made locally with npm 11) broke the gate under CI's npm 10 — and the same drift would recur in reverse the day the runner image jumps to npm 11. Pinning the refresh via npx makes the gate independent of both the runner default and the developer's local npm; bumping the pin now takes a deliberate commit that refreshes the lock alongside it. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Mikola Lysenko (mikolalysenko)
added a commit
that referenced
this pull request
Sep 2, 2026
release-readiness regenerates the lock with the runner's npm 10, which does not write the `libc` platform arrays npm >= 11 emits — so the npm-11-shaped lock from #233 makes 'version-sync.sh 4.0.0 is not a no-op' fail on every PR and on main. The check's npm is the effective canon; note the npm-major dependence for whoever next refreshes the lock locally. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Mikola Lysenko (mikolalysenko)
added a commit
that referenced
this pull request
Sep 2, 2026
The release-readiness gate re-runs version-sync.sh and compares the regenerated npm/socket-patch/package-lock.json byte-for-byte, so the lock's canonical shape is defined by whatever npm regenerates it. npm 11 adds libc arrays that npm 10 omits, which is how the #233 refresh (made locally with npm 11) broke the gate under CI's npm 10 — and the same drift would recur in reverse the day the runner image jumps to npm 11. Pinning the refresh via npx makes the gate independent of both the runner default and the developer's local npm; bumping the pin now takes a deliberate commit that refreshes the lock alongside it. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Mikola Lysenko (mikolalysenko)
added a commit
that referenced
this pull request
Sep 3, 2026
…argo tier is unpublished (#235) * test(e2e): demote the cargo production legs to canary status — free cargo tier is unpublished Production deleted both pinned traitobject patches between 2026-08-27 and 2026-08-28 (0.1.1/cf2e6f58 for the hosted/vendored suites, 0.0.1/b15f2b7f for the safety round-trip), and now publishes no free-tier patch for ANY cargo crate — probes of every RUSTSEC-advisoried crate and the top 1000 crates.io packages all return empty, while the npm/pypi/gem pins remain live. With nothing to pin, the cargo install proofs cannot run; this has kept hosted-e2e and the three e2e_safety_cargo_build legs red on main since 2026-08-28. Move cargo onto the UNPUBLISHED_ECOSYSTEMS watchlist in both production suites, exactly as maven/nuget/composer are handled: the canaries keep probing production each run and, under the CANARY_STRICT knobs, nag when a free cargo patch appears again so the install proofs can be restored. Retire traitobject_real_socket_patch_round_trip (its oracle was that specific patch's compile_error!) and the cargo-only helpers nothing else references. Docs get the corrected catalog/coverage tables plus a dated demotion note; re-promotion is the existing withdrawn-patch procedure with this commit's history as the restore template. Verified: safety suite 5/5; hosted suite 15/15 live against production under SOCKET_PATCH_HOSTED_E2E_STRICT=1; vendored suite 11/12 (the one red is pre-existing server-side gem-catalog drift, untouched by this change); CI's clippy invocation clean; no traitobject reference remains outside get.rs's mocked unit tests. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * fix(ci): regenerate the npm wrapper lock with CI's npm major release-readiness regenerates the lock with the runner's npm 10, which does not write the `libc` platform arrays npm >= 11 emits — so the npm-11-shaped lock from #233 makes 'version-sync.sh 4.0.0 is not a no-op' fail on every PR and on main. The check's npm is the effective canon; note the npm-major dependence for whoever next refreshes the lock locally. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * fix(ci): pin the npm wrapper lock refresh to npm@10 via npx The release-readiness gate re-runs version-sync.sh and compares the regenerated npm/socket-patch/package-lock.json byte-for-byte, so the lock's canonical shape is defined by whatever npm regenerates it. npm 11 adds libc arrays that npm 10 omits, which is how the #233 refresh (made locally with npm 11) broke the gate under CI's npm 10 — and the same drift would recur in reverse the day the runner image jumps to npm 11. Pinning the refresh via npx makes the gate independent of both the runner default and the developer's local npm; bumping the pin now takes a deliberate commit that refreshes the lock alongside it. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> --------- Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Mikola Lysenko (mikolalysenko)
added a commit
that referenced
this pull request
Sep 8, 2026
* fix(ci): regenerate the npm wrapper lock with CI's npm major release-readiness regenerates the lock with the runner's npm 10, which does not write the `libc` platform arrays npm >= 11 emits — so the npm-11-shaped lock from #233 makes 'version-sync.sh 4.0.0 is not a no-op' fail on every PR and on main. The check's npm is the effective canon; note the npm-major dependence for whoever next refreshes the lock locally. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * fix(ci): pin the npm wrapper lock refresh to npm@10 via npx The release-readiness gate re-runs version-sync.sh and compares the regenerated npm/socket-patch/package-lock.json byte-for-byte, so the lock's canonical shape is defined by whatever npm regenerates it. npm 11 adds libc arrays that npm 10 omits, which is how the #233 refresh (made locally with npm 11) broke the gate under CI's npm 10 — and the same drift would recur in reverse the day the runner image jumps to npm 11. Pinning the refresh via npx makes the gate independent of both the runner default and the developer's local npm; bumping the pin now takes a deliberate commit that refreshes the lock alongside it. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> --------- Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
This was referenced Oct 1, 2026
Mikola Lysenko (mikolalysenko)
added a commit
that referenced
this pull request
Oct 5, 2026
…GELOG sync/fold, blocker gate) (#643) * Add scripts/release.py: release-train stamp, versions, CHANGELOG, blockers PR 1 of the weekly release train (docs/release-train/DESIGN.md §7). One stdlib-only Python file with argparse subcommands: - stamp <V> [--check]: offline, byte-deterministic version stamp of Cargo.toml (workspace version + =V core pin), Cargo.lock (source-less workspace-member entries, so --locked builds), the 15 npm manifests and npm/socket-patch/package-lock.json (JSON edit; platform entries for any other version are dropped instead of re-resolved over the network, which ends the #233/#235 lock-drift class). - semver: X.Y.Z and X.Y.Z-rc.N only, semver precedence. - next-version: from git tags + burned release/* branches + the [Unreleased] headings of sync-main(C) computed in memory, never from main's Cargo version. New majors need APPROVED_MAJORS (5 is pre-approved) and are never skipped; otherwise refused with an error. - changelog cut|promote|sync-main|check: rc sections reach main on every rc; promotion folds rc.1..rc.K into one [X.Y.Z] section and returns later abandoned rc blocks to [Unreleased]. Exact-match, deterministic, idempotent; newer [Unreleased] entries are never touched. - notes: release notes with a link to the open-P1 query, never titles. - blockers --base <sha>: the §3.5 release-blocker rule over REST (injectable transport); any API error blocks. Tests: scripts/tests/test_release.py with temp git repos driven through the train timeline and recorded REST shapes under scripts/tests/fixtures/release/. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * Stamp versions offline and let release-lint accept rc versions - scripts/version-sync.sh is now a thin wrapper over `release.py stamp` (same CLI contract; also stamps Cargo.lock's workspace entries). On the clean tree `version-sync.sh 4.0.0` is a byte no-op. - scripts/release-lint.sh: the grammar accepts X.Y.Z and X.Y.Z-rc.N; check 2 is `release.py stamp --check` (byte compare, offline, no clean-tree requirement, writes nothing); check 3 is `release.py changelog check` (rc sections; a stable fails while rc sections remain unfolded); new --stable-only and --tag-exists. - ci.yml release-readiness: the rolling `release-sync` PR (which moves main to the newest cut tag, rc or stable) runs `release-lint.sh --tag-exists`; every other PR keeps today's behavior. - release.yml (legacy pipeline until the train replaces it): lint with --stable-only so it can never publish an rc as Latest/npm latest. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * Remove the version-bump workflow and bump-version.sh version-bump.yml's unsigned push is rejected by the main ruleset and it never ran; the release train cuts versions with scripts/release.py instead. The CHANGELOG header and docs/releasing.md now point at docs/release-train/DESIGN.md (the full runbook rewrite is PR 4), the interim manual bump uses `release.py changelog cut` + version-sync.sh, and ci.yml stops shellchecking the deleted script. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * Add the release-train design with maintainer decisions D1-D4 D1: GitHub App socket-patch-release + refs/tags/v* ruleset (App-only bypass); the App mints the tag in the publish job (PR 3). D2: version and CHANGELOG reach main on every rc via the release-sync PR, folded at promotion. D3: routines run as mikolalysenko (a routine actor, not an approver) until a bot exists; npm stable is direct OIDC; newest-line hotfixes only. D4: the first train release is 5.0.0 (pre-approved major). Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * Fix PR 1 review findings in release.py, release-lint and the CI gate CHANGELOG (sync-main / cut / promote): - The fold no longer classifies rc sections by rc number. Every rc section whose core shipped is replaced by its blocks (tag text) minus [S]'s blocks, as a multiset shared with the [Unreleased] removal. A train rc cut beside a same-core hotfix now returns its entries instead of losing them, whichever was cut first. TagSource.promoted_from is gone. - Matching counts occurrences: a shipped block removes one occurrence, so a repeated entry ("- Updated dependencies.") survives an unmerged sync PR and no longer changes the bump level. - Returned blocks go before the blocks already in their subsection, and a cut orders its ### subsections canonically (breaking, then Keep a Changelog, then the rest). The next cut is now byte-identical with or without the sync PR, including subsection order left by shipped history. - CRLF CHANGELOGs round-trip, and every generated line uses CRLF. Blocker gate: - Fails closed unless GET /labels/release-blocker returns that exact name. Label names compare case-insensitively. labeled events since L are candidates, and a label that vanished without an unlabeled event still blocks. Deleted, converted and transferred issues block. - RELEASE_APPROVERS / RELEASE_ROUTINE_ACTORS split on commas and whitespace and accept a leading @. A malformed login, an empty list, or no trusted approver blocks with a config error, in cmd_blockers and in evaluate_blockers. - since = committer date of merge-base(L, base), clamped to the base date, not a forgeable tag date. A since later than the base fails closed. - PR-merge closes (closed event with commit_id null, recorded from #454) resolve through the closing PR's merge_commit_sha being in base. - Malformed event shapes fail closed. Lint / CI: - release-lint check 2 also runs the new offline `release.py npm-lock-check`: the wrapper lock's packages[""] must match package.json, and every non-optional dependency needs a node_modules entry. This restores the dependency-drift check the networked lock refresh used to give. - ci.yml takes the release-sync --tag-exists path only for a same-repo release-sync branch into main. - rel.Git ignores GIT_DIR/GIT_WORK_TREE and similar variables. Tests: - StampTests are hermetic: they run on a temp tree stamped to a fixed baseline (4.0.0, and 5.0.0-rc.1 via a subclass), so the suite passes on main after the release-sync PR. - The temp repos ignore the git env and global config. - New coverage: release-lint (plain and --tag-exists) on a sync-main'ed tree at an rc, the CI gate step run with stubs, and a regression test for each finding. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * DESIGN.md: align with the PR 1 review fixes - §1: rc.2's section is synced to main and its unshipped blocks return to [Unreleased] when the stable is synced. - §2: the release.py list adds semver, npm-lock-check, next-version and changelog. - §3.1: U = [Unreleased] of sync-main(C) computed in memory (this replaces the pre-D2 "minus L's section" rule). - §3.4: hotfix cuts use --no-sync, and same-core train rcs return to [Unreleased]. - §3.5: the label check, case-insensitive names, labeled-event candidates, vanished labels and gone issues, the merge-base `since`, strict config parsing, and PR-merge close resolution. - §3.7: multiset fold, chronological returns, canonical cut order, CRLF, and the same-repo-only release-sync CI path. - §4: npm-lock-check and the ci.yml condition. - §5 I1 and PR 4: the stable tree is stamp + promote (fold), not a heading rename. - S5: the release-blocker label must exist before the gate can pass. - §7 PR 1: the accept list adds the new scenarios. - §8: APPROVED_MAJORS is kept (D4), and multiset counting is kept. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * Fix PR 1 re-review findings: multiset fold, since lookback, CRLF stamp - promote keeps every occurrence when folding rcs, so [X.Y.Z] is the multiset sum of its rcs and sync-main charges them with the same count (a repeated entry no longer returns as unshipped or raises the bump); a later abandoned rc returns all of its blocks. - sync-main charges the rc sections on main against [S] before removing the rest of [S] from [Unreleased], so a newer identical entry keeps its place whether or not the release-sync PR merged. - blockers: since is never later than base - 35 days, so a forged high stable tag at the base cannot shrink the candidate window further; S9 is a hard prerequisite for live gate runs. - blockers: a PR-merge close resolves only through PRs merged by the close actor (merged_by.login, recorded for #456). - stamp keeps each file's line endings (CRLF checkouts check clean). - sync-main computes CHANGELOG and stamp before writing anything. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * Fix release lint assertions under GitHub Actions --------- Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
Maven Central is blocking / severely rate-limiting user agents containing
socket. The CLI's only Maven Central-facing request — the maven2 fallback pom download in the maven vendor backend (acquire_upstream_pom→fetch_pom_bytesincrates/socket-patch-core/src/vendor/maven_repo.rs, default basehttps://repo1.maven.org/maven2) — sends the sharedSocketPatchCLI/x.y.zUA and gets refused, so materializing a maven artifact whose upstream pom isn't in~/.m2fails.Fix
maven2 registry requests now identify exactly as the official Maven CLI, matching the shape maven-resolver sends:
Apache-Maven/<maven> (Java <jdk>; <os.name> <os.version>), pinned per-OS (Mac OS X/Windows/Linuxvariants) to fixed Maven/JDK/OS versions so the string stays deterministic with no runtime probing.Scope: only the maven2 registry client changes UA — including private mirrors via
SOCKET_MAVEN_REGISTRY, which serve realApache-Maven/*traffic anyway. Socket API, telemetry, and self-update requests keep the honestSocketPatchCLI/x.y.zUA.Tests
maven_user_agent_is_the_maven_cli_shape: the constant leads with theApache-Maven/product token and never containssocket(the exact substring Central filters on).pom_fetch_sends_the_maven_cli_user_agent: wiremock only serves the pom when the request carriesMAVEN_USER_AGENTon the wire, so a regression back to the CLI UA fails the fetch.cargo test -p socket-patch-core --lib vendor::maven_repo→ 33/33 green;cargo clippy -p socket-patch-core --all-targetsclean.🤖 Generated with Claude Code
Note
Low Risk
Narrow change to one HTTP client in the Maven vendor path; no auth, API, or lockfile behavior changes.
Overview
Maven Central was refusing or rate-limiting the fallback POM download used when vendoring Maven artifacts without a local
~/.m2copy, because those HTTP requests used the sharedSocketPatchCLI/x.y.zuser agent (Central blocks strings containingsocket).fetch_pom_bytesinmaven_repo.rsnow sends a pinned, per-OSApache-Maven/…user agent that matches the official Maven CLI shape instead of the Socket CLI UA.SOCKET_MAVEN_REGISTRYtraffic is included; Socket API and other outbound calls are unchanged and still use the honest CLI UA.Regression tests assert the UA is Maven-shaped, never contains
socket, and is actually sent on the wire (wiremock). [Unreleased] changelog entry documents the fix.Reviewed by Cursor Bugbot for commit b72c0dd. Configure here.