Skip to content

Commit 6be8cc4

Browse files
Merge pull request #7985 from rubygems/deivid-rodriguez/insecure-install-path-error
Fix some errors about a previous installation folder that's unsafe to remove, when there's no need to remove it (cherry picked from commit a704d1d)
1 parent 63272ea commit 6be8cc4

File tree

3 files changed

+36
-7
lines changed

3 files changed

+36
-7
lines changed

bundler/lib/bundler/errors.rb

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -217,15 +217,15 @@ def initialize(orig_exception, msg)
217217
end
218218

219219
class InsecureInstallPathError < BundlerError
220-
def initialize(path)
220+
def initialize(name, path)
221+
@name = name
221222
@path = path
222223
end
223224

224225
def message
225-
"The installation path is insecure. Bundler cannot continue.\n" \
226-
"#{@path} is world-writable (without sticky bit).\n" \
227-
"Bundler cannot safely replace gems in world-writeable directories due to potential vulnerabilities.\n" \
228-
"Please change the permissions of this directory or choose a different install path."
226+
"Bundler cannot reinstall #{@name} because there's a previous installation of it at #{@path} that is unsafe to remove.\n" \
227+
"The parent of #{@path} is world-writable and does not have the sticky bit set, making it insecure to remove due to potential vulnerabilities.\n" \
228+
"Please change the permissions of #{File.dirname(@path)} or choose a different install path."
229229
end
230230

231231
status_code(38)

bundler/lib/bundler/rubygems_gem_installer.rb

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -150,12 +150,13 @@ def prepare_extension_build(extension_dir)
150150

151151
def strict_rm_rf(dir)
152152
return unless File.exist?(dir)
153+
return if Dir.empty?(dir)
153154

154155
parent = File.dirname(dir)
155156
parent_st = File.stat(parent)
156157

157158
if parent_st.world_writable? && !parent_st.sticky?
158-
raise InsecureInstallPathError.new(parent)
159+
raise InsecureInstallPathError.new(spec.full_name, dir)
159160
end
160161

161162
begin

bundler/spec/commands/install_spec.rb

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1055,7 +1055,35 @@ def run
10551055

10561056
bundle "install --redownload", raise_on_error: false
10571057

1058-
expect(err).to include("The installation path is insecure. Bundler cannot continue.")
1058+
expect(err).to include("Bundler cannot reinstall foo-1.0.0 because there's a previous installation of it at #{gems_path}/foo-1.0.0 that is unsafe to remove")
1059+
end
1060+
end
1061+
1062+
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
1063+
let(:gems_path) { bundled_app("vendor/#{Bundler.ruby_scope}/gems") }
1064+
let(:full_path) { gems_path.join("foo-1.0.0") }
1065+
1066+
before do
1067+
build_repo4 do
1068+
build_gem "foo", "1.0.0" do |s|
1069+
s.write "CHANGELOG.md", "foo"
1070+
end
1071+
end
1072+
1073+
gemfile <<-G
1074+
source "https://gem.repo4"
1075+
gem 'foo'
1076+
G
1077+
end
1078+
1079+
it "does not try to remove the directory and thus don't abort with an error about unsafe directory removal" do
1080+
bundle "config set --local path vendor"
1081+
1082+
FileUtils.mkdir_p(gems_path)
1083+
FileUtils.chmod(0o777, gems_path)
1084+
Dir.mkdir(full_path)
1085+
1086+
bundle "install"
10591087
end
10601088
end
10611089

0 commit comments

Comments
 (0)