From 9b0d3113fd8b4e7f79cb2fa5b58d91b236a3ad6b Mon Sep 17 00:00:00 2001 From: Hiroshi SHIBATA Date: Fri, 26 Jun 2026 09:01:54 +0900 Subject: [PATCH 1/5] [ruby/rubygems] Make JRuby OutOfMemoryError friendly error spec deterministic The test ran a real `bundle install` under a 32M JVM heap and expected Bundler to catch the OOM. At that heap size the JVM sometimes dies during boot and the JRuby launcher prints its own message before Bundler's rescue runs, so the spec flaked on Ubuntu JRuby CI. Drive the handler directly like the sibling log_error examples instead. https://github.com/ruby/rubygems/commit/659fac7ba3 Co-Authored-By: Claude Opus 4.8 --- spec/bundler/bundler/friendly_errors_spec.rb | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/spec/bundler/bundler/friendly_errors_spec.rb b/spec/bundler/bundler/friendly_errors_spec.rb index 426e3c856d8fb5..3d6cabdf11ebcb 100644 --- a/spec/bundler/bundler/friendly_errors_spec.rb +++ b/spec/bundler/bundler/friendly_errors_spec.rb @@ -133,11 +133,9 @@ context "Java::JavaLang::OutOfMemoryError", :jruby_only do it "Bundler.ui receive error" do - install_gemfile <<-G, raise_on_error: false, env: { "JRUBY_OPTS" => "-J-Xmx32M" }, artifice: nil - source "https://gem.repo1" - G - - expect(err).to include("JVM has run out of memory") + error = Java::JavaLang::OutOfMemoryError.new + expect(Bundler.ui).to receive(:error).with(/JVM has run out of memory/) + Bundler::FriendlyErrors.log_error(error) end end From 1ffba452018ef6fbc8e4140e4eb89736157cfe15 Mon Sep 17 00:00:00 2001 From: Hiroshi SHIBATA Date: Fri, 26 Jun 2026 08:10:25 +0900 Subject: [PATCH 2/5] [ruby/rubygems] Guard the vendored SecureRandom against double loading When the same Gem::SecureRandom copy is shipped in two gems (RubyGems and Bundler) and required from different paths, RubyGems' unguarded require_relative reloads it and emits "already initialized constant" warnings. Add an idempotent guard at the top of the vendored securerandom.rb so a second load from any path short-circuits. This prepares Bundler to reuse RubyGems' copy. https://github.com/ruby/rubygems/commit/0acdd1d8a9 Co-Authored-By: Claude Opus 4.8 --- lib/rubygems/vendor/securerandom/lib/securerandom.rb | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lib/rubygems/vendor/securerandom/lib/securerandom.rb b/lib/rubygems/vendor/securerandom/lib/securerandom.rb index b6f1d71ad39408..dd759fedaa563e 100644 --- a/lib/rubygems/vendor/securerandom/lib/securerandom.rb +++ b/lib/rubygems/vendor/securerandom/lib/securerandom.rb @@ -38,6 +38,10 @@ # If a secure random number generator is not available, # +NotImplementedError+ is raised. +# Skip reloading when an identical copy (e.g. the one shipped inside the Bundler +# gem) was already required from a different path, to avoid redefinition warnings. +return if defined?(Gem::SecureRandom::VERSION) + module Gem::SecureRandom # The version From 07a62f0b3f55b3b54f3a4e56d3bf8c35c1797ac0 Mon Sep 17 00:00:00 2001 From: Hiroshi SHIBATA Date: Fri, 26 Jun 2026 08:10:48 +0900 Subject: [PATCH 3/5] [ruby/rubygems] Ship RubyGems' vendored SecureRandom in the Bundler gem Add lib/rubygems/vendor/securerandom to the gem's file list so the Bundler gem carries its own copy of Gem::SecureRandom. This keeps Bundler self-contained on RubyGems versions that predate the vendored copy, the same way the vendored URI is shipped. https://github.com/ruby/rubygems/commit/6810522806 Co-Authored-By: Claude Opus 4.8 --- lib/bundler/bundler.gemspec | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/lib/bundler/bundler.gemspec b/lib/bundler/bundler.gemspec index bd48d810286825..e6d77310c670f3 100644 --- a/lib/bundler/bundler.gemspec +++ b/lib/bundler/bundler.gemspec @@ -36,9 +36,11 @@ Gem::Specification.new do |s| s.files = Dir.glob("lib/bundler{.rb,/**/*}", File::FNM_DOTMATCH).reject {|f| File.directory?(f) } - # Bundler reuses RubyGems' vendored URI. Ship a copy under lib/rubygems so - # Bundler stays self-contained on RubyGems versions that predate it. + # Bundler reuses RubyGems' vendored URI and SecureRandom. Ship a copy under + # lib/rubygems so Bundler stays self-contained on RubyGems versions that + # predate them. s.files += Dir.glob("lib/rubygems/vendor/uri/**/*", File::FNM_DOTMATCH).reject {|f| File.directory?(f) } + s.files += Dir.glob("lib/rubygems/vendor/securerandom/**/*", File::FNM_DOTMATCH).reject {|f| File.directory?(f) } # include the gemspec itself because warbler breaks w/o it s.files += %w[lib/bundler/bundler.gemspec] From 8ff7a797bec26ebe562a10f1da6f1101bd78cb34 Mon Sep 17 00:00:00 2001 From: Hiroshi SHIBATA Date: Fri, 26 Jun 2026 08:12:30 +0900 Subject: [PATCH 4/5] [ruby/rubygems] Use RubyGems' vendored SecureRandom in Bundler Bundler now reuses RubyGems' Gem::SecureRandom directly instead of keeping its own vendored copy. The shim prefers an already-loaded Gem::SecureRandom, then the copy shipped in the gem under lib/rubygems/vendor, and only falls back to the stdlib when neither is present. Drop the Bundler vendored tree and its automatiek entry. https://github.com/ruby/rubygems/commit/73478ae41d Co-Authored-By: Claude Opus 4.8 --- .../vendor/securerandom/lib/securerandom.rb | 102 ------------------ lib/bundler/vendored_securerandom.rb | 19 ++-- 2 files changed, 11 insertions(+), 110 deletions(-) delete mode 100644 lib/bundler/vendor/securerandom/lib/securerandom.rb diff --git a/lib/bundler/vendor/securerandom/lib/securerandom.rb b/lib/bundler/vendor/securerandom/lib/securerandom.rb deleted file mode 100644 index 01b7fa15a6fe6f..00000000000000 --- a/lib/bundler/vendor/securerandom/lib/securerandom.rb +++ /dev/null @@ -1,102 +0,0 @@ -# -*- coding: us-ascii -*- -# frozen_string_literal: true - -require 'random/formatter' - -# == Secure random number generator interface. -# -# This library is an interface to secure random number generators which are -# suitable for generating session keys in HTTP cookies, etc. -# -# You can use this library in your application by requiring it: -# -# require 'bundler/vendor/securerandom/lib/securerandom' -# -# It supports the following secure random number generators: -# -# * openssl -# * /dev/urandom -# * Win32 -# -# Bundler::SecureRandom is extended by the Random::Formatter module which -# defines the following methods: -# -# * alphanumeric -# * base64 -# * choose -# * gen_random -# * hex -# * rand -# * random_bytes -# * random_number -# * urlsafe_base64 -# * uuid -# -# These methods are usable as class methods of Bundler::SecureRandom such as -# +Bundler::SecureRandom.hex+. -# -# If a secure random number generator is not available, -# +NotImplementedError+ is raised. - -module Bundler::SecureRandom - - # The version - VERSION = "0.4.1" - - class << self - # Returns a random binary string containing +size+ bytes. - # - # See Random.bytes - def bytes(n) - return gen_random(n) - end - - # Compatibility methods for Ruby 3.2, we can remove this after dropping to support Ruby 3.2 - def alphanumeric(n = nil, chars: ALPHANUMERIC) - n = 16 if n.nil? - choose(chars, n) - end if RUBY_VERSION < '3.3' - - private - - # :stopdoc: - - # Implementation using OpenSSL - def gen_random_openssl(n) - return OpenSSL::Random.random_bytes(n) - end - - # Implementation using system random device - def gen_random_urandom(n) - ret = Random.urandom(n) - unless ret - raise NotImplementedError, "No random device" - end - unless ret.length == n - raise NotImplementedError, "Unexpected partial read from random device: only #{ret.length} for #{n} bytes" - end - ret - end - - begin - # Check if Random.urandom is available - Random.urandom(1) - alias gen_random gen_random_urandom - rescue RuntimeError - begin - require 'openssl' - rescue NoMethodError - raise NotImplementedError, "No random device" - else - alias gen_random gen_random_openssl - end - end - - # :startdoc: - - # Generate random data bytes for Random::Formatter - public :gen_random - end -end - -Bundler::SecureRandom.extend(Random::Formatter) diff --git a/lib/bundler/vendored_securerandom.rb b/lib/bundler/vendored_securerandom.rb index 6a704dbd40e487..2a4fd52f1e2efa 100644 --- a/lib/bundler/vendored_securerandom.rb +++ b/lib/bundler/vendored_securerandom.rb @@ -1,12 +1,15 @@ # frozen_string_literal: true -# Use RubyGems vendored copy when available. Otherwise fallback to Bundler -# vendored copy. The vendored copy in Bundler can be removed once support for -# RubyGems 3.5.18 is dropped. +# Reuse RubyGems' vendored SecureRandom (Gem::SecureRandom). The Bundler gem +# ships a copy under lib/rubygems/vendor, so this resolves even on RubyGems +# versions that predate it. Fall back to the stdlib only when no vendored copy +# is available at all. -begin - require "rubygems/vendored_securerandom" -rescue LoadError - require_relative "vendor/securerandom/lib/securerandom" - Gem::SecureRandom = Bundler::SecureRandom +unless defined?(Gem::SecureRandom) + begin + require "rubygems/vendor/securerandom/lib/securerandom" + rescue LoadError + require "securerandom" + Gem::SecureRandom = SecureRandom + end end From 3527f39160fb3d03c7868bbfe8de0e5fdf7f9550 Mon Sep 17 00:00:00 2001 From: Hiroshi SHIBATA Date: Fri, 26 Jun 2026 08:13:19 +0900 Subject: [PATCH 5/5] [ruby/rubygems] Track the shipped RubyGems SecureRandom in the file invariant https://github.com/ruby/rubygems/commit/08ebcf2e97 Co-Authored-By: Claude Opus 4.8 --- spec/bundler/support/path.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/bundler/support/path.rb b/spec/bundler/support/path.rb index c7d9196bf3fb09..7a482912cf3760 100644 --- a/spec/bundler/support/path.rb +++ b/spec/bundler/support/path.rb @@ -345,7 +345,7 @@ def git_ls_files(glob) end def tracked_files_glob - ruby_core? ? "libexec/bundle* lib/bundler lib/bundler.rb lib/rubygems/vendor/uri spec/bundler man/bundle*" : "exe/bundle exe/bundler lib/bundler lib/bundler.rb lib/rubygems/vendor/uri bundler.gemspec CHANGELOG-bundler.md LICENSE-bundler.md README-bundler.md" + ruby_core? ? "libexec/bundle* lib/bundler lib/bundler.rb lib/rubygems/vendor/uri lib/rubygems/vendor/securerandom spec/bundler man/bundle*" : "exe/bundle exe/bundler lib/bundler lib/bundler.rb lib/rubygems/vendor/uri lib/rubygems/vendor/securerandom bundler.gemspec CHANGELOG-bundler.md LICENSE-bundler.md README-bundler.md" end def lib_tracked_files_glob