diff --git a/Library/Homebrew/test/cmd/as-brew-user_spec.rb b/Library/Homebrew/test/cmd/as-brew-user_spec.rb index ac28e5fd5f..8ec2c26cbe 100644 --- a/Library/Homebrew/test/cmd/as-brew-user_spec.rb +++ b/Library/Homebrew/test/cmd/as-brew-user_spec.rb @@ -52,7 +52,7 @@ RSpec.describe Homebrew::Cmd::AsBrewUser do it "runs directly as the prefix owner without sudo" do brew_file = test_root/"brew" - brew_file.write "#!/bin/bash\nprintf '%s\\n' \"$USER|$HOME|$*|$HOMEBREW_NO_SUDO\"\n" + brew_file.write "#!/bin/bash\nprintf '%s\\n' \"$USER|$HOME|$PWD|$*|$HOMEBREW_NO_SUDO\"\n" brew_file.chmod(0755) stdout, = run_as_brew_user_shell( <<~SH, @@ -69,7 +69,7 @@ RSpec.describe Homebrew::Cmd::AsBrewUser do "HOMEBREW_BREW_FILE" => brew_file.to_s), ) - expect(stdout).to eq("brewer|#{test_root}|list|1\n") + expect(stdout).to eq("brewer|#{test_root}|#{Dir.pwd}|list|1\n") end it "rejects a root-owned prefix" do @@ -85,9 +85,9 @@ RSpec.describe Homebrew::Cmd::AsBrewUser do expect(stderr).to include("The Homebrew prefix owner must not be root.") end - it "enters the owner's home after switching users" do + it "preserves the working directory and relative paths after switching users" do brew_file = test_root/"brew" - brew_file.write "#!/bin/bash\nprintf '%s\\n' \"$PWD\"\n" + brew_file.write "#!/bin/bash\nprintf '%s\\n' \"$PWD\" \"$@\"\n" brew_file.chmod(0755) stdout, = run_as_brew_user_shell( <<~SH, @@ -97,14 +97,13 @@ RSpec.describe Homebrew::Cmd::AsBrewUser do [[ "$1" == -un ]] && { echo operator; return; } printf 'brewer:*:503:20::0:0:Brewer:#{test_root}:/bin/zsh\\n' } - cd() { return 1; } sudo() { shift 3; "$@"; } - homebrew-as-brew-user list + homebrew-as-brew-user bundle --file ./Brewfile SH macos_env.merge("HOMEBREW_PREFIX" => "/opt/homebrew", "HOMEBREW_BREW_FILE" => brew_file.to_s), ) - expect(stdout).to eq("#{test_root}\n") + expect(stdout).to eq("#{Dir.pwd}\nbundle\n--file\n./Brewfile\n") end it "selects the prefix owner on Linux" do diff --git a/Library/Homebrew/test/cmd/as-console-user_spec.rb b/Library/Homebrew/test/cmd/as-console-user_spec.rb index 1dde190703..e615b17a39 100644 --- a/Library/Homebrew/test/cmd/as-console-user_spec.rb +++ b/Library/Homebrew/test/cmd/as-console-user_spec.rb @@ -266,7 +266,7 @@ RSpec.describe Homebrew::Cmd::AsConsoleUser do expect(stdout).to be_empty expect(stderr).to be_empty expect(args_file.read).to eq <<~EOS - cwd=#{console_home} + cwd=#{Dir.pwd} -H -u mike @@ -275,7 +275,7 @@ RSpec.describe Homebrew::Cmd::AsConsoleUser do HOME=#{console_home} USER=mike LOGNAME=mike - PWD=#{console_home} + PWD=#{Dir.pwd} PATH=/usr/bin:/bin:/usr/sbin:/sbin /opt/homebrew/bin/brew upgrade diff --git a/Library/Homebrew/test/cmd/shared_examples/as_user.rb b/Library/Homebrew/test/cmd/shared_examples/as_user.rb index a51bd075ef..65a0e48235 100644 --- a/Library/Homebrew/test/cmd/shared_examples/as_user.rb +++ b/Library/Homebrew/test/cmd/shared_examples/as_user.rb @@ -74,7 +74,7 @@ RSpec.shared_examples "switching users without sudo" do |command_name = nil| stdout, stderr, status = result expect([stdout.lines(chomp: true), stderr, status.exitstatus]).to eq([ - ["brewer", test_root.to_s, test_root.to_s, "1", "unset", + ["brewer", test_root.to_s, Dir.pwd, "1", "unset", "list", "argument with spaces", "", '$(exit 1); * "quotes"'], "", 42 ]) diff --git a/Library/Homebrew/utils/as_user.sh b/Library/Homebrew/utils/as_user.sh index ec7025ff85..d9b28dfc96 100644 --- a/Library/Homebrew/utils/as_user.sh +++ b/Library/Homebrew/utils/as_user.sh @@ -78,24 +78,12 @@ homebrew-as-user() { fi fi - ( - if [[ "${command_name}" == as-brew-user ]] - then - # Expand HOME only after switching to the prefix owner. - # shellcheck disable=SC2016 - set -- /bin/bash -c 'cd -- "$HOME" && exec "$@"' -- "${HOMEBREW_BREW_FILE}" "$@" - else - cd "${selected_home}" &>/dev/null || odie "Failed to cd to ${selected_home}!" - set -- "${HOMEBREW_BREW_FILE}" "$@" - fi - - "${user_command[@]}" /usr/bin/env -i \ - "HOME=${selected_home}" \ - "USER=${selected_user}" \ - "LOGNAME=${selected_user}" \ - "PWD=${selected_home}" \ - "PATH=/usr/bin:/bin:/usr/sbin:/sbin" \ - ${HOMEBREW_NO_SUDO:+"HOMEBREW_NO_SUDO=${HOMEBREW_NO_SUDO}"} \ - "$@" - ) + "${user_command[@]}" /usr/bin/env -i \ + "HOME=${selected_home}" \ + "USER=${selected_user}" \ + "LOGNAME=${selected_user}" \ + "PWD=${PWD}" \ + "PATH=/usr/bin:/bin:/usr/sbin:/sbin" \ + ${HOMEBREW_NO_SUDO:+"HOMEBREW_NO_SUDO=${HOMEBREW_NO_SUDO}"} \ + "${HOMEBREW_BREW_FILE}" "$@" } diff --git a/docs/Installation.md b/docs/Installation.md index eb36a0aaf1..9b1949e818 100644 --- a/docs/Installation.md +++ b/docs/Installation.md @@ -85,6 +85,8 @@ brew as-brew-user install wget ``` The command uses the owner's home and a clean environment, switching accounts through sudo when necessary. +It preserves the caller's working directory, so relative paths resolve as usual. +The owner must have access to the working directory and any files used by the command. When sudo is disabled or unavailable, an already-root process switches through macOS `login` or Linux `runuser` instead. These commands use the selected account's primary and supplementary groups. Without permission to switch accounts, log in as the owner instead. @@ -102,6 +104,7 @@ brew as-console-user install wget ``` The command uses that user's home and a clean environment. +Like `as-brew-user`, it preserves the caller's working directory, which the selected user must be able to access. An already-root process can switch users even when sudo is disabled or unavailable, using the same fallback as `as-brew-user`. Other accounts need sudo access to switch users. It fails if no supported console user is logged in.