GeezerVisonThe World Wide Web, restored to 800 pixels of glory. | ||||||||||||||||||||||||||||||||
| Home|About|Gaming cabinet|Archives|How it works|Starter sites | ||||||||||||||||||||||||||||||||
GeezerVison is showing github.com — fix(gem): production-safe bundler plugin — tolerant bootstrap, honest digest, project-scoped stamp by mikolalysenko · Pull Request #178 · SocketDev/socket-patch Conversation
|
| Pin | Test | Red on base |
|---|---|---|
| P0 deadlock | setup_matrix_gem::plugin_runtime::first_bundle_install_survives_failing_apply (real bundle install, fake apply exit 1, generated by the real binary) |
exit 29, "Failed to install plugin" |
| strict hatch | plugin_runtime::strict_mode_fails_bundle_install_on_apply_failure |
green on base (base always raised); pins the hatch against the tolerant default |
| P2 stamp + digest gate | plugin_runtime::successful_apply_stamps_project_scoped (stamp path, 64-hex content, no legacy file, exactly +1 forced apply per cached install) |
stamp under vendor/bundle |
| P1 content digest + migration | plugin_runtime::digest_tracks_gem_file_content_and_legacy_stamp_is_removed (plain-ruby drive; reversion must re-trigger; legacy stamp deleted) |
manifest-only digest misses reversion; legacy stamp kept |
| template invariants | core test_plugin_template_failure_policy_and_stamp_location (new) + test_templates_are_well_formed (extended; also pins published-twin parity) |
2 failures |
| launcher exit code | launcher_guard::windows_branch_propagates_child_exit_code (win_platform stub, child exits 7) |
got 1 |
| launcher error wrap | launcher_guard::unexpected_download_errors_exit_cleanly (stubbed Net::HTTP.start raising SocketError) |
raw backtrace |
| ps-quote / atomic install | launcher_guard::powershell_quote_doubles_single_quotes, install_executable_is_atomic_into_place |
helpers absent |
Red-run evidence: with only the base-branch plugins.rb.tmpl + launcher.rb restored, 7 of 8 runtime/launcher guards fail and both core template tests fail; all green with this branch.
setup_matrix_gem 11/11 — including the docker-mode 6-case gem matrix on an image rebuilt from this branch and a host-mode (4.0.15) matrix rundocker_e2e_gem 2/2, docker_e2e_vendor_gem 1/1, e2e_gem 11/11 (incl. live lifecycle)CLI_CONTRACT.md §gem hook table and README §705 still describe the old "load-time digest gate + after-install-all" wording and don't mention SOCKET_PATCH_STRICT; follow-up doc touch-up needed..bundle/plugin/index (after-install-all only) until re-registration; setup does not force re-registration (deleting .bundle/plugin could break users' other plugins offline). Documented in the template header instead.wrong_target) repeats on every install by design — the honest signal until the stale record is removed; strict mode makes it fatal.🤖 Generated with Claude Code
Note
Medium Risk
Changes default bundle install behavior for all setup-wired Ruby projects (warn vs fail) and re-apply logic; misconfiguration could leave gems unpatched until strict mode or manual apply, but scope is gem/Bundler integration rather than core auth or data paths.
Overview
Makes the generated Bundler plugin safe for fresh clones and honest about on-disk gem state, with matching updates to the published socket-patch-bundler twin and the RubyGems launcher.
Bootstrap / failure policy: Apply failures no longer raise Bundler::BundlerError by default (fixes first bundle install deadlock when plugins.rb runs before gems exist). Failures warn with remediation; SOCKET_PATCH_STRICT=1 restores fatal behavior. Load-time and per-gem after-install triggers use require_stamp so bootstrap installs defer to forced after-install-all.
Triggers & digest: Adds digest-gated after-install (covers bundle pristine in the same run). Digest folds in actual patch-target file bytes under the bundle path, excludes the stamp from its own inputs, and recomputes after apply. APPLY_LOCK mutex avoids concurrent apply children.
Stamp: Digest stamp moves to .socket/gem-plugin-stamp; legacy .socket-patch-gem-stamp under Bundler.bundle_path is deleted best-effort.
Tests & matrix: New plugin_runtime tests (real bundle install with fake apply) and launcher_guard tests; setup-matrix gem fixtures use real beforeHash from published gems via resolve_before_hash in run-case.sh.
Launcher: Windows propagates child exit codes; atomic cache install; clean non-LauncherError failures; PowerShell path quoting; Gem::LoadError fallback for version.
Reviewed by Cursor Bugbot for commit c11248c. Configure here.
Sorry, something went wrong.
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
The reason will be displayed to describe this comment to others. Learn more.
Cursor Bugbot has reviewed your changes using high effort and found 1 potential issue.
Bugbot Autofix is ON. A cloud agent has been kicked off to fix the reported issue.
Comment @cursor review or bugbot run to trigger another review on this PR
Reviewed by Cursor Bugbot for commit c11248c. Configure here.
Sorry, something went wrong.
There was an error while loading. Please reload this page.
There was an error while loading. Please reload this page.
|
Polish pass for the adversarial review findings (commit e356b1b), all empirically validated against real bundler 4.0.15: Major 1 — stamp-existence bootstrap gate (committed-dir stamp): Reproduced the resurrection first: a stale Major 2 — matrix.json gem row: flipped to Minor (strict message lies): Minor (header claim about deleting the stamp): with the gate rework the original claim is now true — verified with a real Minor (remove leaves stamp orphaned): gem Minor (launcher_guard env scrub): Tests: core 2463 pass; 🤖 Generated with Claude Code |
Sorry, something went wrong.
There was an error while loading. Please reload this page.
|
Bugbot finding (Medium, plugins.rb Verification before fixing (host ruby 3.4.10):
Fix: glob a slash-normalized base ( Regression test ( Runs: 🤖 Generated with Claude Code |
Sorry, something went wrong.
There was an error while loading. Please reload this page.
…sts hardened ULTRACODE review + full test matrix over the gem/bundler ecosystem (vendored and hosted modes, every configuration). 24 findings survived adversarial verification; the 13 well-scoped ones are fixed here, each pinned by a test that fails without its fix. Hosted redirect (patch/redirect/mod.rs, gem section): - splice the Gemfile edit by regex byte range: a commented-out duplicate of the gem line no longer gets rewritten instead of the live line - grant-agnostic idempotency guard: re-running scan --mode hosted with a rotated grant token refreshes the source URL in place instead of nesting a second source block (new edit kind redirect_gemfile_source_url) - fail closed on gem-level git:/github:/path:/source: options (they override the enclosing source block, making the redirect an attested no-op); warn redirect_gem_source_option and skip the dep - fail closed on platform-suffixed CHECKSUMS siblings (redirect_gem_platform_unsupported) instead of inserting a duplicate bare-coordinate pin - recognize paren/tab/multi-space gem declarations; gate the append-branch on the gem being genuinely undeclared (no more duplicate declarations bundler rejects) - never pin the lock CHECKSUMS when the Gemfile source redirect did not land (mixed state guaranteed a checksum failure) - warn that a redirected pair breaks frozen/deployment installs - record the upstream sha256 line as original on the CHECKSUMS edit so a future revert can restore it (golden fixture updated) Vendored backend (vendor/gem.rs): - insert new PATH sections at bundler's sorted position (identifier order, verified against real bundler 4.0.15 bundle lock) — two or more vendored gems no longer churn the committed lock - fail closed on platform-suffixed GEM-specs siblings on no-CHECKSUMS locks (mirrors the existing CHECKSUMS guard) - re-vendor on a patch UPDATE (new uuid, same purl): recognize our own path: wiring and rewire in place instead of refusing with gemfile_declaration_not_editable — the documented automatic re-vendor contract now actually works for gem Auto-fetch (vendor/registry_fetch.rs): - stage fetched gems into the canonical <name>-<version> leaf instead of a dir literally named "gem", which vendor_gem refused as platform_gem_unsupported — lockfile auto-fetch for gems was dead Crawler (crawlers/ruby_crawler.rs): - parse_dir_name_version prefers the last dotted-version boundary, so http-2-1.0.1 parses as (http-2, 1.0.1) instead of the ghost (http, 2) - vendor/bundle discovery enumerates engine dirs (jruby, truffleruby) instead of hardcoding ruby/ Scan/get plumbing: - run_nested_apply now threads --ecosystems: scan --ecosystems gem --sync no longer applies (or mutates) other ecosystems' patches - scan --vendor --dry-run --vex no longer writes the VEX file nor exits 1 on not-yet-vendored state Test hardening: - e2e_gem lifecycle harness: BUNDLE_PATH replaces bundle install --path (removed in bundler 3+; all 3 lifecycle tests green under 4.0.15) - e2e_hosted_production gem leg now asserts the CHECKSUMS digest CHANGED after redirect (client-verifiable today) and, in the success arm, verifies installed content against the published afterHashes — an inert gem patch can no longer stay green (the npm minimist blindspot) - docker_e2e_gem serves the true git-blob beforeHash so the chain exercises the default non-forced apply path, not just --force - setup_matrix_gem module doc: the with-setup Docker cases ARE still a baseline gap (bootstrap deadlock: plugin registration evaluates plugins.rb before any gems land; exit-semantics twin), doc corrected Verified: core 2460/0, cli lib 350/0, clippy+fmt clean; e2e_gem 11/11 (incl. live lifecycle under bundler 4.0.15), e2e_vendor_gem_build 6/6 (incl. real-bundler capstone), docker_e2e_gem 2/2, docker_e2e_vendor_gem 1/1, hosted production gem leg green (redirect verified; install still blocked by the known depscan#23630 compact-index 404 — server-side). Co-Authored-By: Claude Fable 5 <[email protected]>
…ll scan arms Addresses both Bugbot findings on #175: - The grant-agnostic Gemfile idempotency guard required LF (`do\n`), so a core.autocrlf checkout of a previously-redirected Gemfile was not recognized and the indented gem line inside the block got wrapped in a second, nested source block on re-run. The recognizer now accepts `do\r?\n`; pinned by gemfile_rerun_on_crlf_checkout_never_nests (verified red without the fix). - The dry-run VEX skip only covered the vendor JSON arm; the interactive `scan --vendor --dry-run --vex` path (embed_vex_human) and the JSON `scan --apply --dry-run --vex` path (embed_vex_into_json at the apply fall-through) still generated the document — exiting 1 on a not-yet-vendored project or writing the attestation during --dry-run. The guard now lives at the top of both embed helpers, covering every scan arm; pinned by scan_vendor_dry_run_with_vex_interactive_* and scan_apply_json_dry_run_with_vex_* (both verified red without it). Co-Authored-By: Claude Fable 5 <[email protected]>
d063cb1 to
99f9cd0
Compare
… digest, project-scoped stamp
The generated Bundler setup plugin could deadlock a project on its own
bootstrap, its design comment described trigger behavior bundler does not
have, and its digest stamp was a machine-global file blind to the actual
gem-file state. All trigger claims below were re-derived empirically
against real bundler 4.0.15 (host) and 2.7.2 (docker image).
plugins.rb template (+ published socket-patch-bundler twin):
- [P0] bootstrap deadlock: bundler evaluates plugins.rb at plugin
REGISTRATION, before any project gem is installed; the load-time
SocketPatch.apply! got apply's exit 1 ("No packages found") and raised
Bundler::BundlerError, so the FIRST `bundle install` of every fresh
clone of a setup-wired project died (exit 29 under 4.0.15, exit 1
under 2.7) and every retry failed identically (registration never
completed). Patch failures now warn once per process — naming what
failed and the manual remediation — and let the install continue;
SOCKET_PATCH_STRICT=1 restores the raise. The load-time and per-gem
triggers are additionally stamp-gated so the bootstrap install stays
quiet and defers to the forced after-install-all pass.
- [P1] trigger reality: the header claimed plugins.rb runs during the
Gemfile pass "on EVERY bundle invocation" — false; bundler evaluates a
plugin when a subscribed hook event first fires. Measured surface
(identical on 2.7 and 4.0): every `bundle install` — fresh AND fully
cached — fires before/after-install(-all); `bundle pristine` fires
ONLY the per-gem events; `bundle exec`/`bundle check`/`gem pristine`
fire nothing. The plugin now also subscribes `after-install`
(digest+stamp-gated), which catches `bundle pristine`'s patch
reversion in the same run, and the digest folds in the on-disk CONTENT
of every gem-patch target (resolved from the manifest purls under
Bundler.bundle_path/gems), recomputed after apply — so out-of-band
reversion flips the digest even when every committed input is
byte-identical. Header documents precisely which flows re-apply and
which cannot, including the stale .bundle/plugin/index caveat for
checkouts registered by an older plugin version.
- [P2] stamp location: the digest stamp was a fixed-name file under
Bundler.bundle_path — the interpreter's machine-global gem dir when no
bundle path is configured, shared and clobbered across every
socket-patch project on the host. It now lives at
.socket/gem-plugin-stamp (project-local, excluded from its own digest
inputs); the legacy global stamp is deleted best-effort and never read.
launcher.rb (gem/socket-patch):
- Windows arm now propagates the child's real exit code instead of
collapsing every non-zero exit to 1.
- the binary-cache install is atomic: staged as a temp file in the
destination dir, chmodded, then renamed into place (cross-run race on
Windows rename tolerated when the winner already published).
- first-run failures outside LauncherError exit with a clean one-line
message instead of a raw backtrace; the PowerShell Expand-Archive
fallback quotes paths containing single quotes; `version`'s documented
from-a-checkout fallback never engaged because Gem::MissingSpecError
is a Gem::LoadError (ScriptError family), not a StandardError — found
by the new launcher guard.
- socket-patch-bundler.gemspec: stale `git:` comment corrected to
`path:` (the source has been path: since #150).
setup-matrix driver (gem-scoped, npm-family byte-identical — verified by
diffing the fixtures the old and new driver produce for npm across all
patchsets):
- the gem fixture now serves the REAL git-blob beforeHash probed from
the published .gem (`gem fetch` + `gem unpack`, mirroring
docker_e2e_gem's probe; verified against an independent oracle), so
hash-gated gem apply passes the variant gate without --force. With the
deadlock fix this turns the formerly-gapped gem with-setup docker
cases green: the full 6-case gem matrix passes in BOTH host mode
(bundler 4.0.15, real rubygems.org installs) and docker mode (rebuilt
image, bundler 2.7) — no dependency on any sibling apply change.
Tests (each red without its fix):
- core template invariants: test_plugin_template_failure_policy_and_
stamp_location (new) + test_templates_are_well_formed (extended) pin
the tolerant reporter, strict hatch, stamp constants, legacy cleanup,
target-content digest, and the published twin's parity — 2 failures
against the old template.
- setup_matrix_gem::plugin_runtime drives the plugin generated by the
REAL binary through REAL `bundle install` runs with a fake apply:
first_bundle_install_survives_failing_apply (the P0 repro: red at exit
29 on the old template), strict_mode_fails_bundle_install_on_apply_
failure, successful_apply_stamps_project_scoped (stamp path + exactly
one forced apply per cached install), digest_tracks_gem_file_content_
and_legacy_stamp_is_removed (plain-ruby drive; red on the old
manifest-only digest and old stamp path).
- setup_matrix_gem::launcher_guard drives launcher.rb with host ruby:
windows_branch_propagates_child_exit_code (red: 7 collapsed to 1),
unexpected_download_errors_exit_cleanly (red: raw backtrace),
powershell_quote_doubles_single_quotes and
install_executable_is_atomic_into_place (red: helpers absent).
7 of 8 runtime/launcher guards fail against the base-branch code.
Verified: core 2461/0, cli lib 350/0, setup_matrix_gem 11/11 (incl. the
docker-mode 6-case matrix on a fresh image AND host-mode 4.0.15 run),
docker_e2e_gem 2/2, docker_e2e_vendor_gem 1/1, e2e_gem 11/11 (incl.
live lifecycle), clippy+fmt clean on both crates.
Co-Authored-By: Claude Fable 5 <[email protected]>
…ir stamp; gitignore + lifecycle it The require_stamp gate trusted the EXISTENCE of .socket/gem-plugin-stamp — a file living in the directory every other workflow file tells users to COMMIT. Reproduced against bundler 4.0.15: a stale stamp that reaches version control passes the gate at plugin REGISTRATION on a fresh clone, digest-mismatches (targets absent), shells apply, and under SOCKET_PATCH_STRICT=1 resurrects the exact bootstrap deadlock this plugin exists to avoid (exit 29, "Failed to install plugin", no plugin index, every retry identical). Deleting the stamp had the inverse sharp edge: the gated triggers went dead, so `bundle pristine` left the patches reverted until the next `bundle install`. - plugins.rb template + published twin: the bootstrap gate now bails while NONE of the manifest's gem-patch targets exist on disk, reading the live gem tree and never the stamp (which is now a pure digest cache). Registration on a fresh clone stays quiet regardless of stamp state, and pristine heals in the same run even with the stamp deleted — both verified against real bundler 4.0.15. - report_failure: the trailer now states what the ACTIVE mode does — the strict raise says the install is failing because SOCKET_PATCH_STRICT is set, instead of claiming "`bundle install` continues". - setup wires /gem-plugin-stamp into .socket/.gitignore (append-only, sparing user lines) so the stamp never lands in git status or a blanket `git add .socket`; `--check` demands the entry (check/setup agreement); `--remove` best-effort deletes the stamp and strips our line. - matrix.json: the gem row records reality — hook_family bundler-plugin, baseline_supported true — so a future regression of the with-setup flow classifies as blocking regression, not a known gap. - launcher_guard::run_ruby scrubs RUBYOPT/BUNDLE_*/GEM_*/SOCKET_* like plugin_runtime::scrub, so the suite survives `bundle exec`. New pins: plugin_runtime::committed_stale_stamp_does_not_deadlock_strict_ fresh_clone (registration recorded, hook-only failure, retry converges), plugin_runtime::bootstrap_gate_keys_on_target_presence_not_stamp (both gate directions), strict-trailer asserts in the strict-mode test, gitignore and stamp-lifecycle asserts in host_guard + core gem tests. Co-Authored-By: Claude Fable 5 <[email protected]>
Dir.glob treats backslash as an escape on EVERY platform, and Bundler.bundle_path carries Windows backslash separators through verbatim (verified: BUNDLE_PATH='vendor\bundle' yields <root>/vendor\bundle/ruby/3.4.0). The platform-install wildcard in patch_target_files (<gems>/<name>-<version>-*/<rel>) therefore escape-ate the separator and matched nothing on Windows: platform installs (nokogiri-1.15.0-x64-mingw-ucrt) dropped out of the digest, so a bundle pristine reversion of them left the stamp matching and the re-apply skipped. Fix: glob a slash-normalized base (forward slashes are valid separators on Windows); the direct non-glob join stays byte-faithful. Applied to both the setup template and the published gem twin, pinned by new needles in the core parity test. Regression test (verified red without the fix): plugin_runtime::backslash_bundle_path_still_digests_platform_gem_files drives the generated plugins.rb with plain ruby under a backslash-bearing BUNDLE_PATH while the real tree lives at the slash spelling (the two-spellings-one-directory situation Windows creates): the platform install must be enumerated as a patch target and its reversion must flip the digest and re-run apply. Co-Authored-By: Claude Fable 5 <[email protected]>
ee9383c to
c954115
Compare
|
Rebased Transplanted exactly this PR's 3 commits via
Conflicts: none — all three commits replayed identically (range-diff shows Verification (all green):
New tip: c954115 🤖 Generated with Claude Code |
Sorry, something went wrong.
There was an error while loading. Please reload this page.
Conflicts: crates/socket-patch-cli/tests/setup_matrix_gem.rs Co-Authored-By: Claude Fable 5 <[email protected]>
|
Heads-up for reviewers: the red Otherwise green: 61 checks passing, including the org-required audit workflow. Awaiting an approving review to merge. 🤖 Generated with Claude Code |
Sorry, something went wrong.
There was an error while loading. Please reload this page.
|
The hosted-e2e fix is up: #199 (production turned out to publish zero free gem patches — the pin is retired and gem is canary-ized like maven/nuget/composer; live suite 15/0 on that branch). Once #199 merges, a rebase/rerun here goes fully green. 🤖 Generated with Claude Code |
Sorry, something went wrong.
There was an error while loading. Please reload this page.
da58dee
into
main
There was an error while loading. Please reload this page.
There was an error while loading. Please reload this page.
Successfully merging this pull request may close these issues.
There was an error while loading. Please reload this page.