From bb511c3f10918efdcc4d5efd980561903e67dc10 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Rodr=C3=ADguez?= Date: Fri, 30 Aug 2024 18:57:20 +0200 Subject: [PATCH] [rubygems/rubygems] Don't try to remove previous install folder if it's empty Ruby ships with empty directories for default gems. If Ruby installations has unsafe world-writable permissions, we will complain when about to install a gem that happens to be also a default gem, because we'll start by removing the previous install folder and that's supposed to be insecure due to too loose permissions. However, if the folder is empty, we don't actually need to remove anything, so we can skip the whole thing, avoiding the errors. https://github.com/rubygems/rubygems/commit/2f3cd8ac4e --- lib/bundler/rubygems_gem_installer.rb | 1 + spec/bundler/commands/install_spec.rb | 28 +++++++++++++++++++++++++++ 2 files changed, 29 insertions(+) diff --git a/lib/bundler/rubygems_gem_installer.rb b/lib/bundler/rubygems_gem_installer.rb index 3ec73452b3..858ebf32cf 100644 --- a/lib/bundler/rubygems_gem_installer.rb +++ b/lib/bundler/rubygems_gem_installer.rb @@ -150,6 +150,7 @@ module Bundler def strict_rm_rf(dir) return unless File.exist?(dir) + return if Dir.empty?(dir) parent = File.dirname(dir) parent_st = File.stat(parent) diff --git a/spec/bundler/commands/install_spec.rb b/spec/bundler/commands/install_spec.rb index d4bc1d2922..9353d24d95 100644 --- a/spec/bundler/commands/install_spec.rb +++ b/spec/bundler/commands/install_spec.rb @@ -1059,6 +1059,34 @@ RSpec.describe "bundle install with gem sources" do end end + describe "when gems path is world writable (no sticky bit set), but previous install is just an empty dir (like it happens with default gems)", :permissions do + let(:gems_path) { bundled_app("vendor/#{Bundler.ruby_scope}/gems") } + let(:full_path) { gems_path.join("foo-1.0.0") } + + before do + build_repo4 do + build_gem "foo", "1.0.0" do |s| + s.write "CHANGELOG.md", "foo" + end + end + + gemfile <<-G + source "https://gem.repo4" + gem 'foo' + G + end + + it "does not try to remove the directory and thus don't abort with an error about unsafe directory removal" do + bundle "config set --local path vendor" + + FileUtils.mkdir_p(gems_path) + FileUtils.chmod(0o777, gems_path) + Dir.mkdir(full_path) + + bundle "install" + end + end + describe "when bundle cache path does not have write access", :permissions do let(:cache_path) { bundled_app("vendor/#{Bundler.ruby_scope}/cache") }