Merge pull request #24360 from Homebrew/as-brew-user-relative-brewfile

Preserve working directories when switching users
This commit is contained in:
Mike McQuaid authored and GitHub committed 2026-10-27 08:53:40 +00:00
commit 57c486f02e
5 files changed
+20 -30

No files matched your search

@@ -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
@@ -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
@@ -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
])
+8 -20
View File
@@ -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}" "$@"
}
+3
View File
@@ -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.