Skip to content

Commit add09cf

Browse files
committed
Allow installation without sudo access
- Allow writable prefixes without administrator membership. - Keep macOS's admin group for members and use the primary group otherwise, allowing group changes without elevation. - Remove group and other write access when falling back to `staff`, including existing files, and restrict the umask for new files. - Honour `HOMEBREW_NO_SUDO` and detect known privilege failures. - Probe sudo without refreshing cached credentials. - Try filesystem operations before requesting elevation. - Skip Command Line Tools without sudo and make their installation failures non-fatal when a usable Git is available. - Validate Git before downloading Homebrew, accepting PATH and Xcode installations without invoking Apple's developer-tool stubs. - Recommend the macOS package for MDM and identify the release requirement for installation without Git or developer tools. - Cover permissions and optional tools with Ruby tests and verify installation and package use as a real non-admin account in CI. - Use the test account's login environment to avoid inheriting the runner's inaccessible working directory.
1 parent b41c8e7 commit add09cf

4 files changed

Lines changed: 568 additions & 54 deletions

File tree

‎.github/workflows/tests.yml‎

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,15 @@ jobs:
7575
echo "/home/linuxbrew/.linuxbrew/bin:/usr/bin:/bin" >> "${GITHUB_PATH}"
7676
fi
7777
78+
- name: Test installation permissions
79+
run: |
80+
if [[ "${RUNNER_OS}" != "macOS" ]]
81+
then
82+
sudo apt-get update
83+
sudo apt-get install --yes ruby ruby-minitest
84+
fi
85+
/usr/bin/ruby tests/test_install.rb
86+
7887
- name: Uninstall GitHub Actions Homebrew
7988
run: |
8089
if which brew &>/dev/null
@@ -91,6 +100,34 @@ jobs:
91100

92101
- run: /bin/bash uninstall.sh -f >/dev/null
93102

103+
- name: Install as a non-admin user into a provisioned prefix
104+
run: |
105+
if [[ "${RUNNER_OS}" = "macOS" ]]
106+
then
107+
sudo sysadminctl -addUser brewtest -password "$(uuidgen)" -shell /bin/bash
108+
else
109+
sudo useradd --create-home --user-group --shell /bin/bash brewtest
110+
fi
111+
if id -Gn brewtest | grep -Eq '(^| )(admin|sudo|wheel)( |$)'
112+
then
113+
echo "The test account must not be an administrator."
114+
exit 1
115+
fi
116+
sudo install -d -o brewtest -g "$(id -gn brewtest)" -m 0755 /opt/brew
117+
sudo -i -u brewtest /usr/bin/env HOMEBREW_NO_SUDO=1 NONINTERACTIVE=1 \
118+
/bin/bash -s -- --path /opt/brew < install.sh
119+
if [[ "${RUNNER_OS}" = "macOS" && "$(id -gn brewtest)" = staff ]]
120+
then
121+
test -z "$(find /opt/brew ! -type l \( -perm -0020 -o -perm -0002 \))"
122+
fi
123+
sudo -i -u brewtest /usr/bin/env HOMEBREW_NO_SUDO=1 /opt/brew/bin/brew config
124+
sudo -i -u brewtest /usr/bin/env HOMEBREW_NO_SUDO=1 /opt/brew/bin/brew install --force-bottle ack
125+
sudo -i -u brewtest /opt/brew/bin/ack --version
126+
test -z "$(find /opt/brew ! -user brewtest -o ! -group "$(id -gn brewtest)")"
127+
# These generated files survive removal of the Cellar.
128+
sudo -i -u brewtest /bin/rm -f /opt/brew/lib/ld.so /opt/brew/share/info/dir
129+
sudo /usr/bin/env NONINTERACTIVE=1 /bin/bash uninstall.sh --path /opt/brew
130+
94131
- name: Install into custom prefixes non-interactively
95132
run: |
96133
case "$(uname)" in

‎README.md‎

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,9 @@
88

99
More installation information and options: <https://docs.brew.sh/Installation>.
1010

11-
If you're on macOS, try out our new `.pkg` installer. Download it from [Homebrew's latest GitHub release](https://github.com/Homebrew/brew/releases/latest).
11+
For MDM deployments on Apple Silicon Macs, we recommend the `.pkg` installer from [Homebrew's latest GitHub release](https://github.com/Homebrew/brew/releases/latest).
12+
Use [`HOMEBREW_PKG_USER`](https://docs.brew.sh/Installation) to select an existing non-root account to own the installation.
13+
Installing without Git or developer tools requires a package release containing [Homebrew/brew#24062](https://github.com/Homebrew/brew/pull/24062).
1214

1315
If you are running Linux or WSL, [there are some pre-requisite packages to install](https://docs.brew.sh/Homebrew-on-Linux#requirements).
1416

@@ -38,6 +40,14 @@ For example, to install non-interactively into `/opt/brew`:
3840
NONINTERACTIVE=1 /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)" -- --path /opt/brew
3941
```
4042

43+
The installing account does not need administrator membership when the prefix is writable.
44+
On macOS, falling back to the `staff` group removes group and other write permissions from the prefix and cache.
45+
Set `HOMEBREW_NO_SUDO=1` to prevent sudo calls; missing sudo, recognised privilege failures and explicit policy denials are also detected automatically.
46+
Filesystem operations try without sudo before requesting elevation when needed.
47+
Installations without sudo skip the system PATH file; follow the printed shell setup instructions instead.
48+
Command Line Tools installation is skipped without sudo and CLT installation failures are non-fatal.
49+
The shell installer aborts if Git is missing or unusable; a working Git on `PATH` or supplied by Xcode is supported.
50+
4151
## Uninstall Homebrew
4252

4353
```bash

0 commit comments

Comments
 (0)