fix(gem): bundler >= 2.2 floor — setup refuses to wire 1.x, check red-flags unloadable wiring - #209
Open
Mikola Lysenko (mikolalysenko) wants to merge 4 commits into
Open
fix(gem): bundler >= 2.2 floor — setup refuses to wire 1.x, check red-flags unloadable wiring#209Mikola Lysenko (mikolalysenko) wants to merge 4 commits into
Mikola Lysenko (mikolalysenko) wants to merge 4 commits into
Conversation
Bundler 1.x cannot load the `plugin ... path:` directive gem setup writes (Plugin::DSL undef's :path; the 1.x plugin installer knows only git/rubygems sources), so a wired project fails EVERY later `bundle install` with exit 7 before plugin registration, with an error that never names socket-patch — while setup and setup --check keep reporting "configured" (campaign-confirmed on bundler 1.17.3). Red now: - core: add_plugin_directive wires a Gemfile.lock'd BUNDLED WITH 1.17.3 project (real + dry-run) - cli: setup exits 0/"success" on the same project; setup --check says "configured" on a wired project after a 1.x lock lands Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…gs unloadable wiring New core probe (setup/gem/version.rs): read the project's bundler from the lock's BUNDLED WITH (Gemfile.lock / gems.locked — deterministic, works where bundle is not on PATH, and the version RubyGems' switching actually runs), falling back to `bundle --version` (bundler 4's bare output parses too); fail OPEN when neither yields a version. - add_plugin_directive (dry-run included) refuses below the floor with an error naming the detected version, the >= 2.2 floor, and the upgrade remedy; remove_plugin_directive stays ungated (recovery path) - setup --check red-flags both unsupported states as errors: wired-but- unloadable (names `setup --remove`) and unwired-unwireable Matches the gem branch's own error-channel precedent (missing Gemfile, unwritable plugin dir): where setup cannot deliver a WORKING configuration it errors loudly rather than narrowing silently. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…mages, floor docs - tests/docker/Dockerfile.gem-b1 (ruby 3.1 + bundler 1.17.3) and Dockerfile.gem-b4 (ruby 3.4 + bundler ~> 4.0) from the campaign's bundler-version matrix, with a BASE_IMAGE build-arg so a binary under test can be baked without touching shared :latest tags. Not built in CI (the CI setup-matrix job drives scripts/setup-matrix.sh against the plain gem image only) — local build lines documented in the headers and tests/docker/README.md. - setup_matrix_gem.rs: bundler_floor_docker leg (soft-skip when docker/ image absent; SOCKET_PATCH_GEM_B1_IMAGE override) driving real bundler 1.17.3: setup refuses via the `bundle --version` fallback, `bundle install` keeps working, the lock path refuses too, and --check red-flags. Verified: fails against a pre-fix image (SETUP-RC=0), passes against a fix-baked one. - README.md + docs/ecosystems.md: document the bundler >= 2.2 floor. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…d 1.x refusal Two nits from the lane review: - probe_bundler's `bundle --version` fallback (lock-less projects only) now runs under a 10s timeout with kill_on_drop, degrading to Unknown (fail open) instead of hanging setup/setup --check on a wedged bundler. - Re-running `setup` on an ALREADY-wired bundler-1.x project appends the `socket-patch setup --remove` recovery path to the refusal message, matching what `setup --check` already names for that state. Co-Authored-By: Claude Fable 5 <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.
Defect
socket-patch setupon a gem project locked to bundler 1.x silently wires aplugin "socket-patch", path: ...directive that bundler 1.x cannot load — and worse, cannot even parse as a plugin. Bundler 1.x (Plugin::DSLundef_methods:path; the 1.x plugin installer supports only git/rubygems sources) resolves the directive as an ORDINARY GEM, so every laterbundle installdies with exit 7 ("Could not find gem 'socket-patch' ...") before plugin registration — an error that never names socket-patch, and in--deploymentmode adds a misleading "Perhaps the lockfile is corrupted?" line. Meanwhilesetup --checkkept reporting "configured", so the CI gate went green over broken installs.Root cause
crates/socket-patch-core/src/setup/gem/update.rs:233(add_plugin_directive) wired unconditionally — no bundler version probe existed.crates/socket-patch-cli/src/commands/setup.rs:817(append_gem_check_entries) judged only directive/file presence, so a wired-but-unloadable project checked asconfigured.Campaign repros (setup-plugin-lifecycle, frozen-deployment-apply; root-cause clusters D2/C2 in the campaign REPORT.md) reproduced both on real bundler 1.17.3 under
docker run --network none.Fix
New
crates/socket-patch-core/src/setup/gem/version.rs: probe the bundler that will actually run installs —BUNDLED WITH(Gemfile.lock, orgems.lockedforgems.rbprojects) — deterministic, PATH-independent, and the version RubyGems' switching selects;bundle --versionfallback for lock-less projects (both the "Bundler version 2.7.2" and bundler-4 bare "4.0.18" spellings), stdin-nulled and bounded by a 10s timeout withkill_on_drop;Below the
>= 2.2floor:setup(dry-run included) refuses with an error naming the detected version, source, floor, and upgrade remedy — via the gem branch's existing error channel (exit 1, message in preview Errors /--jsonfiles[]/--silentstderr). If the project is ALREADY wired, the refusal also names thesetup --removerecovery.setup --checkred-flags both states as errors (notneeds_configuration, sincesetupcannot fix them); the wired state's message explains the exit-7 failure and namessetup --remove.setup --removeis deliberately ungated: it is the recovery path.Docs: README.md, docs/ecosystems.md, tests/docker/README.md; new local-build matrix images
Dockerfile.gem-b1(ruby:3.1 + bundler 1.17.3) /Dockerfile.gem-b4, both with aBASE_IMAGEbuild-arg (these legs do not run in CI — the CI setup-matrix job drivesscripts/setup-matrix.shagainst the plain gem image).Tests (red -> green)
Red-first history: commit 3b7c3d3 lands the regression tests failing against the pre-fix behavior (core:
test_add_refuses_bundler_1x_locked_project,test_add_dry_run_also_refuses_bundler_1x— "wiring a bundler-1.x project must be refused as an error: [... status: Updated]"; CLI:gem_setup_refuses_bundler_1x_locked_projectsaw{"status": "success", "updated": 2},gem_check_red_flags_wired_but_unloadable_bundler_1xsaw "configured"). 1d21fd4 turns them green.bundle --versionspellings, floor boundaries 1.17/2.1/2.2/2.7/4.0, gems.rb->gems.locked pairing, lock-beats-machine-bundler, message contents) + 5 update.rs floor tests (refuse, dry-run refuse, 2.x proceeds, remove ungated, wired-refusal names--remove).setup_matrix_gem.rs): setup refusal end-to-end (exit 1, Gemfile byte-untouched, no plugin dir) and check red-flag +--removerecovery.bundler_1x_setup_refuses_and_installs_keep_workingagainst real bundler 1.17.3 (--network none) — refusal, thenbundle installstill exits 0 (was exit 7). Anti-vacuity verified: the same leg FAILS (SETUP-RC=0) against a stale pre-fix image.applystill landing the patch.Final gate on this branch head: core
setup::gem67/67;setup_matrix_gem17/17 (docker leg included);setup_invariants19,setup_contract_gaps6,cli_setup_silent10,cli_parse_setup29 all green; clippy clean on both crates (only pre-existing warnings in untouched test files).Review
Lane-reviewed and approved with independently verified red->green (both red commits re-failed, head re-passed, docker anti-vacuity re-confirmed, both campaign repro scripts re-run in fresh
--network nonecontainers). 4 nits, no must-fix; two nits addressed in d43c61c (probe timeout;--removehint on wired-1.x refusal), the stale local:latestgem-b1/b4 images retagged to the fixed build on the dev machine, the remaining nit (host-bundler test precondition) documented in-test.🤖 Generated with Claude Code
Note
Medium Risk
Changes gem setup/check behavior for legacy Bundler 1.x projects (now hard errors instead of silent breakage), but the change is narrowly scoped to Ruby setup wiring with explicit recovery paths and broad test coverage.
Overview
Adds a bundler ≥ 2.2 gate for RubyGems
setupwiring. Bundler 1.x cannot loadplugin ... path:directives (they are resolved as a normal gem and everybundle installfails with exit 7), so wiring those projects was worse than refusing.version.rsprobes bundler via lockBUNDLED WITH(includinggems.lockedforgems.rb), thenbundle --versionwith a 10s timeout; unknown version fails open.add_plugin_directive(including dry-run) errors below the floor and leaves the Gemfile untouched; already-wired 1.x projects get asetup --removehint.setup --checkreports error (not “configured”) for unsupported bundler, including wired-but-unloadable states, with recovery guidance.removestays ungated.Docs note the floor;
Dockerfile.gem-b1/Dockerfile.gem-b4support local matrix legs; host and docker tests cover refusal, check, and recovery.Reviewed by Cursor Bugbot for commit d43c61c. Configure here.