From 84a204900b6628ceafd2e535385b627b0555ac7f Mon Sep 17 00:00:00 2001 From: ojab Date: Mon, 23 Apr 2018 12:42:36 +0000 Subject: [PATCH] Use realpath in clean_load_path what happens next will shock you: ``` From: /real_path/.rvm/gems/ruby-2.5.1/gems/bundler-1.16.2/lib/bundler/shared_helpers.rb @ line 339 Bundler::SharedHelpers#clean_load_path: 330: def clean_load_path 331: # handle 1.9 where system gems are always on the load path 332: return unless defined?(::Gem) 333: 334: bundler_lib = bundler_ruby_lib 335: 336: loaded_gem_paths = Bundler.rubygems.loaded_gem_paths 337: 338: binding.pry => 339: $LOAD_PATH.reject! do |p| 340: path = File.expand_path(p) 341: path = File.realpath(path) if File.exist?(path) 342: next if path.start_with?(bundler_lib) 343: loaded_gem_paths.delete(p) 344: end 345: $LOAD_PATH.uniq! 346: end [1] pry(#)> bundler_lib => "/real_path/.rvm/gems/ruby-2.5.1/gems/bundler-1.16.2/lib" [2] pry(#)> loaded_gem_paths => ["/symlinked_path/.rvm/gems/ruby-2.5.1@global/gems/did_you_mean-1.2.0/lib", "/symlinked_path/.rvm/gems/ruby-2.5.1/gems/bundler-1.16.2/lib", "/symlinked_path/.rvm/gems/ruby-2.5.1/gems/byebug-10.0.2/lib", "/symlinked_path/.rvm/gems/ruby-2.5.1/extensions/x86_64-linux/2.5.0/byebug-10.0.2", "/symlinked_path/.rvm/gems/ruby-2.5.1/gems/coderay-1.1.2/lib", "/symlinked_path/.rvm/gems/ruby-2.5.1/gems/method_source-0.9.0/lib", "/symlinked_path/.rvm/gems/ruby-2.5.1/gems/pry-0.11.3/lib", "/symlinked_path/.rvm/gems/ruby-2.5.1/gems/pry-byebug-3.6.0/lib", "/real_path/.rvm/rubies/ruby-2.5.1/lib/ruby/gems/2.5.0/gems/fileutils-1.0.2/lib", "/real_path/.rvm/rubies/ruby-2.5.1/lib/ruby/gems/2.5.0/gems/psych-3.0.2/lib", "/real_path/.rvm/rubies/ruby-2.5.1/lib/ruby/gems/2.5.0/extensions/x86_64-linux/2.5.0/psych-3.0.2"] ``` basically we're not rejecting `bundler_lib` because symlink there and real path in $LOAD_PATH --- lib/bundler/shared_helpers.rb | 7 +++++- spec/runtime/setup_spec.rb | 41 +++++++++++++++++++++++++++++++++++ 2 files changed, 47 insertions(+), 1 deletion(-) diff --git a/lib/bundler/shared_helpers.rb b/lib/bundler/shared_helpers.rb index 45185209f14..3d488326d68 100644 --- a/lib/bundler/shared_helpers.rb +++ b/lib/bundler/shared_helpers.rb @@ -336,7 +336,12 @@ def clean_load_path loaded_gem_paths = Bundler.rubygems.loaded_gem_paths $LOAD_PATH.reject! do |p| - next if File.expand_path(p).start_with?(bundler_lib) + expanded_p = File.expand_path(p) + if File.exist?(expanded_p) && File.respond_to?(:realpath) + path = File.realpath(expanded_p) + next if path.start_with?(bundler_lib) + end + next if expanded_p.start_with?(bundler_lib) loaded_gem_paths.delete(p) end $LOAD_PATH.uniq! diff --git a/spec/runtime/setup_spec.rb b/spec/runtime/setup_spec.rb index e84cdaabf5c..2d2aff78a71 100644 --- a/spec/runtime/setup_spec.rb +++ b/spec/runtime/setup_spec.rb @@ -857,6 +857,47 @@ def clean_load_path(lp) expect(out).to eq("true\ntrue") end + context "with bundler is located in symlinked GEM_HOME" do + let(:gem_home) { Dir.mktmpdir } + let(:symlinked_gem_home) { Tempfile.new } + let(:bundler_dir) { File.expand_path("../..", __dir__) } + let(:bundler_lib) { File.join(bundler_dir, lib) } + before do + FileUtils.ln_sf(gem_home, symlinked_gem_home) + gems_dir = File.join(gem_home, "gems") + specifications_dir = File.join(gem_home, "specifications") + Dir.mkdir(gems_dir) + Dir.mkdir(specifications_dir) + + FileUtils.ln_s(bundler_dir, File.join(gems_dir, "bundler-#{Bundler::VERSION}")) + + gemspec = File.read("#{bundler_dir}/bundler.gemspec"). + sub("Bundler::VERSION", %("#{Bundler::VERSION}")) + gemspec = gemspec.lines.grep_v(%r{lib/bundler/version}).join + + File.open(File.join(specifications_dir, "bundler.gemspec"), "wb") do |f| + f.write(gemspec) + end + end + + it "should succesfully require 'bundler/setup'" do + install_gemfile "" + + ENV["GEM_PATH"] = symlinked_gem_home.to_path + + ruby <<-R + if $LOAD_PATH,include?(bundler_lib) + $LOAD_PATH.delete(bundler_lib) + else + raise "We don't have #{bundler_lib} in $LOAD_PATH" + end + puts (require 'bundler/setup') + R + + expect(out).to eql("true") + end + end + it "stubs out Gem.refresh so it does not reveal system gems" do system_gems "rack-1.0.0"