diff --git a/Library/Homebrew/cask/artifact/abstract_uninstall.rb b/Library/Homebrew/cask/artifact/abstract_uninstall.rb
index 234a7a5d8b3f8..78547326b5d80 100644
--- a/Library/Homebrew/cask/artifact/abstract_uninstall.rb
+++ b/Library/Homebrew/cask/artifact/abstract_uninstall.rb
@@ -379,7 +379,7 @@ def uninstall_script(directives, directive_name: :script, force: false, command:
end
def uninstall_pkgutil(*pkgs, command: nil, **_)
- ohai "Uninstalling packages; your password may be necessary:"
+ ohai "Uninstalling packages with sudo; the password may be necessary:"
pkgs.each do |regex|
::Cask::Pkg.all_matching(regex, command).each do |pkg|
puts pkg.package_id
diff --git a/Library/Homebrew/cask/artifact/pkg.rb b/Library/Homebrew/cask/artifact/pkg.rb
index 61cd142ec01d7..0d2610f29f620 100644
--- a/Library/Homebrew/cask/artifact/pkg.rb
+++ b/Library/Homebrew/cask/artifact/pkg.rb
@@ -36,8 +36,7 @@ def install_phase(**options)
private
def run_installer(command: nil, verbose: false, **_options)
- ohai "Running installer for #{cask}; your password may be necessary.",
- "Package installers may write to any location; options such as `--appdir` are ignored."
+ ohai "Running installer for #{cask} with sudo; the password may be necessary."
unless path.exist?
pkg = path.relative_path_from(cask.staged_path)
pkgs = Pathname.glob(cask.staged_path/"**"/"*.pkg").map { |path| path.relative_path_from(cask.staged_path) }
diff --git a/Library/Homebrew/cask/staged.rb b/Library/Homebrew/cask/staged.rb
index bd7b2f2a53e73..74df26ec2165c 100644
--- a/Library/Homebrew/cask/staged.rb
+++ b/Library/Homebrew/cask/staged.rb
@@ -27,7 +27,7 @@ def set_ownership(paths, user: T.must(User.current), group: "staff")
full_paths = remove_nonexistent(paths)
return if full_paths.empty?
- ohai "Changing ownership of paths required by #{@cask}; your password may be necessary."
+ ohai "Changing ownership of paths required by #{@cask} with sudo; the password may be necessary."
@command.run!("/usr/sbin/chown", args: ["-R", "--", "#{user}:#{group}", *full_paths],
sudo: true)
end
diff --git a/Library/Homebrew/env_config.rb b/Library/Homebrew/env_config.rb
index b7a0aba96a6de..ae7b7e6c756b5 100644
--- a/Library/Homebrew/env_config.rb
+++ b/Library/Homebrew/env_config.rb
@@ -373,6 +373,11 @@ module EnvConfig
"the system-wide environment file will be loaded last to override any prefix or user settings.",
boolean: true,
},
+ HOMEBREW_SUDO_THROUGH_SUDO_USER: {
+ description: "If set, Homebrew will use the `SUDO_USER` environment variable to define the user to " \
+ "`sudo`(8) through when running `sudo`(8).",
+ boolean: true,
+ },
HOMEBREW_TEMP: {
description: "Use this path as the temporary directory for building packages. Changing " \
"this may be needed if your system temporary directory and Homebrew prefix are on " \
diff --git a/Library/Homebrew/env_config.rbi b/Library/Homebrew/env_config.rbi
index b61b8e519d9c8..1fa98249b3404 100644
--- a/Library/Homebrew/env_config.rbi
+++ b/Library/Homebrew/env_config.rbi
@@ -217,6 +217,9 @@ module Homebrew::EnvConfig
sig { returns(T.nilable(String)) }
def self.sudo_askpass; end
+ sig { returns(T::Boolean) }
+ def self.sudo_through_sudo_user?; end
+
sig { returns(T.nilable(String)) }
def self.svn; end
diff --git a/Library/Homebrew/system_command.rb b/Library/Homebrew/system_command.rb
index 2a2d7bd6b6265..afe55309216d2 100644
--- a/Library/Homebrew/system_command.rb
+++ b/Library/Homebrew/system_command.rb
@@ -157,11 +157,25 @@ def env_args
set_variables
end
+ sig { returns(T.nilable(String)) }
+ def homebrew_sudo_user
+ ENV.fetch("HOMEBREW_SUDO_USER", nil)
+ end
+
sig { returns(T::Array[String]) }
def sudo_prefix
- user_flags = []
- user_flags += ["-u", "root"] if sudo_as_root?
askpass_flags = ENV.key?("SUDO_ASKPASS") ? ["-A"] : []
+ user_flags = []
+ if Homebrew::EnvConfig.sudo_through_sudo_user?
+ raise ArgumentError, "HOMEBREW_SUDO_THROUGH_SUDO_USER set but SUDO_USER unset!" if homebrew_sudo_user.blank?
+
+ user_flags += ["--prompt", "Password for %p:", "-u", homebrew_sudo_user,
+ *askpass_flags,
+ "-E", *env_args,
+ "--", "/usr/bin/sudo"]
+ elsif sudo_as_root?
+ user_flags += ["-u", "root"]
+ end
["/usr/bin/sudo", *user_flags, *askpass_flags, "-E", *env_args, "--"]
end
diff --git a/docs/Manpage.md b/docs/Manpage.md
index c660eb7c32ec1..a643b40a43954 100644
--- a/docs/Manpage.md
+++ b/docs/Manpage.md
@@ -2362,6 +2362,9 @@ command execution e.g. `$(cat file)`.
- `HOMEBREW_SYSTEM_ENV_TAKES_PRIORITY`
If set in Homebrew's system-wide environment file (`/etc/homebrew/brew.env`), the system-wide environment file will be loaded last to override any prefix or user settings.
+- `HOMEBREW_SUDO_THROUGH_SUDO_USER`
+
If set, Homebrew will use the `SUDO_USER` environment variable to define the user to `sudo`(8) through when running `sudo`(8).
+
- `HOMEBREW_TEMP`
Use this path as the temporary directory for building packages. Changing this may be needed if your system temporary directory and Homebrew prefix are on different volumes, as macOS has trouble moving symlinks across volumes when the target does not yet exist. This issue typically occurs when using FileVault or custom SSD configurations.
diff --git a/manpages/brew.1 b/manpages/brew.1
index 3f905a50456e5..d2eaee580d905 100644
--- a/manpages/brew.1
+++ b/manpages/brew.1
@@ -3483,6 +3483,12 @@ Use this as the \fBsvn\fR(1) binary\.
If set in Homebrew\'s system\-wide environment file (\fB/etc/homebrew/brew\.env\fR), the system\-wide environment file will be loaded last to override any prefix or user settings\.
.
.TP
+\fBHOMEBREW_SUDO_THROUGH_SUDO_USER\fR
+.
+.br
+If set, Homebrew will use the \fBSUDO_USER\fR environment variable to define the user to \fBsudo\fR(8) through when running \fBsudo\fR(8)\.
+.
+.TP
\fBHOMEBREW_TEMP\fR
.
.br