diff options
author | The Bundler Bot <bot@bundler.io> | 2017-02-09 03:12:23 +0000 |
---|---|---|
committer | The Bundler Bot <bot@bundler.io> | 2017-02-09 03:12:23 +0000 |
commit | 311b090449b591d4fb96a725e548b4d35ac95ed0 (patch) | |
tree | 2415597dfd09c75ea9397c01a904abd137a80369 | |
parent | d35a85385e9ddd56aeaabfae6952b1e41aee2992 (diff) | |
parent | 2c1ffb86763d351b0cfc7843e3bf94ea54b94766 (diff) | |
download | bundler-311b090449b591d4fb96a725e548b4d35ac95ed0.tar.gz |
Auto merge of #5363 - svoop:permissive_tmp_home_dirs, r=indirect
Permissive temporary home directory
We're deploying to a server with several Ruby applications each with it's own user. However, the home directory of these users is *not* writable by the users.
Since Bundler 1.14.x, a temporary home directoy in the `tmpdir` is used as a fallback. This works well for only one user, but will fail with more than one:
1. user1 execs `bundle`
2. `/tmp/bundler/home/user1` is created usually with 0755 modes
3. user2 execs `bundle`
4. `/tmp/bundler/home/user2` cannot be created since user2 can't write to `home`
This PR adds a `chmod` to apply mode 0777 to `home`. It rescues to nil in order to silently fail on step 4 (user2 cannot chmod `home` since it's owned by user1) as well as in case of any other problem performing chmod. Since we're in a fallback here, I guess it's okay to do this. However, if this is too much code smell, a `unless File.exist?` will do the trick as well.
-rw-r--r-- | lib/bundler.rb | 45 | ||||
-rw-r--r-- | spec/bundler/bundler_spec.rb | 39 | ||||
-rw-r--r-- | spec/spec_helper.rb | 8 |
3 files changed, 71 insertions, 21 deletions
diff --git a/lib/bundler.rb b/lib/bundler.rb index 2cd8d9916b..c98dece747 100644 --- a/lib/bundler.rb +++ b/lib/bundler.rb @@ -146,34 +146,37 @@ module Bundler def user_home @user_home ||= begin home = Bundler.rubygems.user_home - warning = "Your home directory is not set properly:" - if home.nil? - warning += "\n * It is not set at all" + + warning = if home.nil? + "Your home directory is not set." elsif !File.directory?(home) - warning += "\n * `#{home}` is not a directory" + "`#{home}` is not a directory." elsif !File.writable?(home) - warning += "\n * `#{home}` is not writable" - else - return @user_home = Pathname.new(home) + "`#{home}` is not writable." end - login = Etc.getlogin || "unknown" - - tmp_home = Pathname.new(Dir.tmpdir).join("bundler", "home", login) - begin - SharedHelpers.filesystem_access(tmp_home, :write) do |p| - FileUtils.mkdir_p(p) - end - rescue => e - warning += "\n\nBundler also failed to create a temporary home directory at `#{tmp_home}`:\n#{e}" - raise warning + if warning + user_home = tmp_home_path(Etc.getlogin, warning) + Bundler.ui.warn "#{warning}\nBundler will use `#{user_home}' as your home directory temporarily.\n" + user_home + else + Pathname.new(home) end + end + end - warning += "\n\nBundler will use `#{tmp_home}` as your home directory temporarily" - - Bundler.ui.warn(warning) - tmp_home + def tmp_home_path(login, warning) + login ||= "unknown" + path = Pathname.new(Dir.tmpdir).join("bundler", "home") + SharedHelpers.filesystem_access(path) do |tmp_home_path| + unless tmp_home_path.exist? + tmp_home_path.mkpath + tmp_home_path.chmod(0o777) + end + tmp_home_path.join(login).tap(&:mkpath) end + rescue => e + raise "#{warning}\nBundler also failed to create a temporary home directory at `#{path}':\n#{e}" end def user_bundle_path diff --git a/spec/bundler/bundler_spec.rb b/spec/bundler/bundler_spec.rb index 4458efce6a..268c0d99ac 100644 --- a/spec/bundler/bundler_spec.rb +++ b/spec/bundler/bundler_spec.rb @@ -170,4 +170,43 @@ EOF end end end + + describe "#user_home" do + context "home directory is set" do + it "should return the user home" do + path = "/home/oggy" + allow(Bundler.rubygems).to receive(:user_home).and_return(path) + allow(File).to receive(:directory?).with(path).and_return true + allow(File).to receive(:writable?).with(path).and_return true + expect(Bundler.user_home).to eq(Pathname(path)) + end + end + + context "home directory is not set" do + it "should issue warning and return a temporary user home" do + allow(Bundler.rubygems).to receive(:user_home).and_return(nil) + allow(Etc).to receive(:getlogin).and_return("USER") + allow(Dir).to receive(:tmpdir).and_return("/TMP") + allow(FileTest).to receive(:exist?).with("/TMP/bundler/home").and_return(true) + expect(FileUtils).to receive(:mkpath).with("/TMP/bundler/home/USER") + message = <<EOF +Your home directory is not set. +Bundler will use `/TMP/bundler/home/USER' as your home directory temporarily. +EOF + expect(Bundler.ui).to receive(:warn).with(message) + expect(Bundler.user_home).to eq(Pathname("/TMP/bundler/home/USER")) + end + end + end + + describe "#tmp_home_path" do + it "should create temporary user home" do + allow(Dir).to receive(:tmpdir).and_return("/TMP") + allow(FileTest).to receive(:exist?).with("/TMP/bundler/home").and_return(false) + expect(FileUtils).to receive(:mkpath).once.ordered.with("/TMP/bundler/home") + expect(FileUtils).to receive(:mkpath).once.ordered.with("/TMP/bundler/home/USER") + expect(File).to receive(:chmod).with(0o777, "/TMP/bundler/home") + expect(Bundler.tmp_home_path("USER", "")).to eq(Pathname("/TMP/bundler/home/USER")) + end + end end diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 53b7527545..297d81f531 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -103,6 +103,14 @@ RSpec.configure do |config| config.before :all do build_repo1 + # HACK: necessary until rspec-mocks > 3.5.0 is used + # see https://github.com/bundler/bundler/pull/5363#issuecomment-278089256 + if RUBY_VERSION < "1.9" + FileUtils.module_eval do + alias_method :mkpath, :mkdir_p + module_function :mkpath + end + end end config.before :each do |