Fix hosted gem redirect ignoring Bundler mirror.all (#681) - #684
Mikola Lysenko (mikolalysenko) wants to merge 5 commits into
Conversation
Assisted-by: Claude Code:claude-opus-5-5
Bundler's mirror.all (or a mirror for the patch-registry source) sends the per-dep source block the hosted redirect writes to the mirror, which serves the unpatched upstream gem. The scan reported the gem redirected and the in-run VEX attested not_affected while the next bundle install was unpatched or failed CHECKSUMS. The hosted intake now reads the mirror settings from the bundler app config and BUNDLE_MIRROR__ALL and, when one captures the patch registry, leaves the Gemfile pair untouched, attests nothing, and warns redirect_gem_mirror_overrides_source with the remedy (scope the mirror to rubygems.org). Fixes #681 Assisted-by: Claude Code:claude-opus-5-5
|
BugBot review Generated by Claude Code |
The redirect_gem_mirror_overrides_source detail always advised unsetting a local mirror.all, which never clears a BUNDLE_MIRROR__ALL from the environment or a mirror.<source> key for the patch registry. The mirror model now returns the remedy for the setting it detected, and a test applies each remedy and checks the next scan passes. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NEpjVvY7X41jPuVuoiCLVz
|
Generated by Claude Code |
|
bugbot run Generated by Claude Code |
|
Ready for review at head
Slack announcement not sent: this run has no Slack send tool, so the next run should retry. Generated by Claude Code |
|
Codex follow-up review of The older hosted gem pin finding is independently confirmed: an empty catalog or empty grants bypass mirror detection and can still yield a false attestation. A further correction is in progress. The Windows case-handling finding was investigated and dismissed using the tagged Ruby/Bundler source chain; the thread explains why OS lookup semantics do not apply to Bundler's case-sensitive snapshot. No native Windows test is claimed. The validation below covers the correction already pushed, and does not establish safety for the newly confirmed candidate-gap case. The original P1 had several paths to a false hosted attestation: hostname/app and per-source environment mirrors escaped detection; an empty The correction models effective app/environment mirror precedence and all/source/hostname matching, including Bundler key normalization and fallback-only shadowing. Empty Validation on the exact committed source:
User-global Bundler config and mirror settings introduced only in a later install environment remain documented limits. Standalone VEX behavior is unchanged. This is focused local validation, not a full workspace/platform rerun. Ready for review remains off while these findings are verified and resolved, and until complete CI and Bugbot are clear. |
|
Cursor (@cursor) review |
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes using high effort and found 2 potential issues.
Autofix Details
Bugbot Autofix prepared a fix for the issue found in the latest run.
- ✅ Fixed: VEX misses mirrors without gem candidates
- Added independent mirror detection that checks for capturing mirrors even when no gem candidates are present, preventing false attestations for lockfile-discovered gems.
Or push these changes by commenting:
@cursor push d702d51261
Preview (d702d51261)
diff --git a/crates/socket-patch-cli/src/commands/scan/hosted.rs b/crates/socket-patch-cli/src/commands/scan/hosted.rs
--- a/crates/socket-patch-cli/src/commands/scan/hosted.rs
+++ b/crates/socket-patch-cli/src/commands/scan/hosted.rs
@@ -1253,10 +1253,25 @@
// rediscovers older pins too, so a candidate-only set would miss some
// refused hosted gems. Keep their actual installed-byte verification,
// but do not infer applied status from the intercepted source.
- params.hosted_gem_mirror_refused = rewrite
- .warnings
- .iter()
- .any(|warning| warning.code == "redirect_gem_mirror_overrides_source");
+ // Check for mirrors independently of whether gem candidates are
+ // present: a lockfile-discovered gem pin can still be affected by a
+ // capturing mirror even when this run has no gem grants. Probe for
+ // mirror.all and hostname/exact-source mirrors that would capture the
+ // patch registry, using a representative source URL.
+ params.hosted_gem_mirror_refused = {
+ let patch_registry_sources = &["https://patch.socket.dev/gem/"];
+ let mirror_detected = socket_patch_core::crawlers::ruby_crawler::bundler_source_mirror(
+ &common.cwd,
+ patch_registry_sources,
+ )
+ .await
+ .is_some();
+ mirror_detected
+ || rewrite
+ .warnings
+ .iter()
+ .any(|warning| warning.code == "redirect_gem_mirror_overrides_source")
+ };
// Stale-flagged purls are EXCLUDED from assume_applied: the same-run
// envelope carries a redirect_gem_stale_install warning proving the
// installed materialization unpatched, so attesting that purl fromYou can send follow-ups to the cloud agent here.
The mirror refusal flag for embedded VEX was derived only from the rewrite's redirect_gem_mirror_overrides_source warning, which exists only when this run had gem candidates. A hosted scan with an empty catalog, a paid-only gem or a withdrawn offer still rediscovers older hosted gem pins in its VEX plan, so lockfile inference and --vex-no-verify could attest them while Bundler fetched unpatched bytes through a capturing mirror. Embedded hosted VEX now checks each hosted gem pin in the completed plan against the project's Bundler mirror settings (using the pin's own Socket source), on the redirect path and on the hosted scan's empty JSON and human terminal paths. Verified installed bytes remain valid evidence; standalone and agent/vendored VEX are unchanged. Co-Authored-By: Claude <noreply@anthropic.com>
|
bugbot run Generated by Claude Code |
There was a problem hiding this comment.
✅ 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 86718e9. Configure here.
|
[burn-down agent] Ready for review at head
Slack announcement not sent this run (Slack send tool unavailable). Generated by Claude Code |

LLM Description written by Claude Code:claude-opus-5-5
Fixes #681
Summary
Hosted gem scans refuse redirects when the effective Bundler mirror would capture the Socket patch-registry source. The refusal preserves the manifest and lockfile and emits
redirect_gem_mirror_overrides_sourcewithout exposing private mirror credentials. Embedded VEX then requires verified installed bytes for hosted gems, so a previous hosted pin cannot falsely attest a missing or upstream installation.Root cause
Bundler can capture a per-dependency source with an all-source, exact-source, or hostname mirror. The original implementation missed hostname and source-specific environment settings, treated an empty
BUNDLE_APP_CONFIGas unset, and let independent VEX lockfile inference bypass a detected refusal on later scans. Automatic warning/remedy text also copied credentials from mirror URLs.Fix
BUNDLE_APP_CONFIGandBUNDLE_IGNORE_CONFIGconsistently with the shared Ruby intake. An explicitly empty app-config path selects the project-rootconfigfile. Environment mirror keys retain their literal native interpretation.Known limits: user-global
~/.bundle/configremains outside this reader; mirror settings introduced only in a later install environment cannot be observed during the scan. A capturing mirror conservatively refuses all gem redirects in the run.Validation of the correction
scan/hosted.rsformatting is retained. These are focused local checks, not a full workspace/platform rerun.Author validation on the original commit
468a237Historical evidence below is from the original implementation on Linux, Ruby 3.3.6, Bundler 4.0.17, and toolchain 1.93.1. It does not establish CI status for the correction.
gem_hosted_bundler_mirror_all_redirects_nothingFAILED with"redirect":{"redirected":1,"rewrittenFiles":["Gemfile"],…},"vex":{"statements":1,…}, the exact symptom in Hosted gem redirect ignores Bundler'smirror.allsetting, so the nextbundle installfetches the redirected gem's upstream bytes from the mirror while the in-run VEX attestsnot_affected#681.bundler_mirror_all_redirects_nothingandbundler_mirror_for_the_patch_source_redirects_nothingalso FAILED.cargo test -p socket-patch-cli --all-features --test e2e_redirect_gem_build -- --ignored: 12/12 pass, including the new test and every existing hosted gem capstone.cargo clippy --workspace --all-features -- -D warnings: clean. The new files are rustfmt-clean.mainitself isn't rustfmt-clean and CI doesn't gate on it, so unrelated files were left alone.cargo test --workspace --all-features --no-fail-fast: 214 suites ok. 12 tests fail only because this sandbox runs as uid 0, wherechmod 0555and unremovable-file injections can't force the write failures they test (*_state_write_failure_*,*unremovable*,relax_loop_must_not_traverse_symlinked_root,wire_write_failure_*). None of them touches gem or hosted-intake code. CI runs them as a normal user.CI
CI on
cb0fd60ff09b1e624eff168d0d38f8845011ea27is still running. Bugbot reported two additional findings under independent verification; Ready for review remains off until they are resolved and complete checks are clear.🤖 Generated with Claude Code
https://claude.ai/code/session_01NEpjVvY7X41jPuVuoiCLVz
Note
Medium Risk
Changes hosted-mode gem redirect and embedded VEX attestation paths; incorrect mirror detection could block valid redirects or allow false attestations, though behavior is fail-closed with broad test coverage.
Overview
Hosted gem redirects now fail closed when Bundler mirror settings (
mirror.all, exact patch-source, or hostname mirrors from app config orBUNDLE_MIRROR__*env) would route the Socket patch-registry source to an upstream mirror. The newformats/gem/mirrormodel matches Bundler precedence and key normalization; the hosted intake drops gem manifest/lock candidates and emitsredirect_gem_mirror_overrides_sourcewith remediation text that does not leak mirror URLs or credentials.Embedded VEX on hosted scans sets
hosted_gem_mirror_check/hosted_gem_mirror_refusedso rediscovered hosted gem pins cannot be attested via lockfile inference,assume_applied, or--vex-no-verifywhen a mirror applies; verified installed bytes still count.BUNDLE_APP_CONFIG: an empty value now selects<project>/config, aligned with Bundler.Contract docs, ecosystem matrix, unit/engine/VEX tests, and native Bundler e2e scenarios cover mirror refusal and rescan behavior.
Reviewed by Cursor Bugbot for commit 86718e9. Configure here.
Generated by Claude Code