Description
The brew policy preset advertises "Homebrew (Linuxbrew) package manager access" and whitelists the linuxbrew binary paths, but the sandbox cannot actually install Homebrew. Two filesystem constraints in the baseline block the install script:
nemoclaw-blueprint/policies/openclaw-sandbox.yaml sets filesystem_policy.read_write to [/tmp, /dev/null, /sandbox/.openclaw, /sandbox/.nemoclaw] plus the workdir. /home/linuxbrew/ is not on the list, so Landlock denies writes there.
Dockerfile.base runs the sandbox as the unprivileged sandbox user with no sudo (useradd -r -g sandbox -d /sandbox -s /bin/bash sandbox). Homebrew's install script's first step is sudo to create and chown /home/linuxbrew/.linuxbrew, which the sandbox cannot grant.
Result: applying the brew preset, connecting into the sandbox, and running the documented Homebrew bootstrap one-liner fails with:
==> Checking for `sudo` access (which may request your password)...
Insufficient permissions to install Homebrew to "/home/linuxbrew/.linuxbrew" (the default prefix).
Two QA reports already documented the symptom: #1767 (filed 2026-04-10), #3757 (filed 2026-05-18). #3846 is an interim docs-only PR clarifying that users must install Homebrew first, but that PR cannot actually unblock the install because of the filesystem gap.
Why the brew preset is the outlier
Looking at how the other presets actually provision their binaries:
| Preset |
Binary source |
npm |
Node + npm pre-installed via apt in Dockerfile.base |
pypi |
Python + pip pre-installed via apt |
huggingface |
Uses pre-installed Python |
github |
git pre-installed; gh was a phantom and was removed in #3377 |
local-inference |
Routes via host gateway, no in-sandbox binary |
slack / discord / telegram / wechat / whatsapp |
Plugins baked into the agent via the plugin system |
brew |
Nothing pre-installed and the sandbox cannot install it |
The gh precedent (#3377) shows the project's approach when a preset advertises a tool that isn't actually present: drop the phantom binary from the preset. The WeChat precedent (#3682 in v0.0.46, closing #3677) shows the opposite approach for a tool that should be available: bake it into the sandbox base image.
Proposed fix (Option A): bake Homebrew into the sandbox base image
Follow the #3682 pattern. In Dockerfile.base, after the existing user setup:
USER root
RUN mkdir -p /home/linuxbrew/.linuxbrew/bin \
&& chown -R sandbox:sandbox /home/linuxbrew \
&& gosu sandbox git clone --depth=1 --branch=stable \
https://github.com/Homebrew/brew \
/home/linuxbrew/.linuxbrew/Homebrew \
&& ln -s /home/linuxbrew/.linuxbrew/Homebrew/bin/brew \
/home/linuxbrew/.linuxbrew/bin/brew \
&& gosu sandbox /home/linuxbrew/.linuxbrew/bin/brew --version
USER sandbox
Then add /home/linuxbrew to filesystem_policy.read_write in openclaw-sandbox.yaml so brew can install formulae at runtime under that prefix.
Apply the same change to agents/hermes/Dockerfile.base so Hermes sandboxes get the same behavior.
The image-build path runs as root, so the chown step works. Once the base image is published, every sandbox starts with a working brew under /home/linuxbrew/.linuxbrew/bin/brew, and brew install <package> Just Works after applying the preset.
Cost
Approximately 80 to 150 MB on the base image (Homebrew core, no formulae). Acceptable relative to the existing ~2.4 GB sandbox image and consistent with the WeChat-plugin trade-off the project already accepted.
Alternative (Option B), not recommended
Remove the brew preset entirely (matching the #3377 approach for the gh phantom binary). Cheaper at the image level but a user-visible regression: removes a preset that's currently in the Balanced tier menu, and steers Linux users without .deb packages toward unsupported workarounds.
Acceptance criteria
brew --version succeeds inside a freshly-created sandbox with no user setup beyond applying the preset.
brew install hello succeeds, downloads the bottle, and prints the install marker.
- The preset's existing binary whitelist remains correct.
- E2E smoke test added for the brew bootstrap path.
Related
Description
The
brewpolicy preset advertises "Homebrew (Linuxbrew) package manager access" and whitelists the linuxbrew binary paths, but the sandbox cannot actually install Homebrew. Two filesystem constraints in the baseline block the install script:nemoclaw-blueprint/policies/openclaw-sandbox.yamlsetsfilesystem_policy.read_writeto[/tmp, /dev/null, /sandbox/.openclaw, /sandbox/.nemoclaw]plus the workdir./home/linuxbrew/is not on the list, so Landlock denies writes there.Dockerfile.baseruns the sandbox as the unprivilegedsandboxuser with no sudo (useradd -r -g sandbox -d /sandbox -s /bin/bash sandbox). Homebrew's install script's first step issudoto create and chown/home/linuxbrew/.linuxbrew, which the sandbox cannot grant.Result: applying the
brewpreset, connecting into the sandbox, and running the documented Homebrew bootstrap one-liner fails with:Two QA reports already documented the symptom: #1767 (filed 2026-04-10), #3757 (filed 2026-05-18). #3846 is an interim docs-only PR clarifying that users must install Homebrew first, but that PR cannot actually unblock the install because of the filesystem gap.
Why the
brewpreset is the outlierLooking at how the other presets actually provision their binaries:
npmDockerfile.basepypihuggingfacegithubghwas a phantom and was removed in #3377local-inferenceslack/discord/telegram/wechat/whatsappbrewThe
ghprecedent (#3377) shows the project's approach when a preset advertises a tool that isn't actually present: drop the phantom binary from the preset. The WeChat precedent (#3682 in v0.0.46, closing #3677) shows the opposite approach for a tool that should be available: bake it into the sandbox base image.Proposed fix (Option A): bake Homebrew into the sandbox base image
Follow the
#3682pattern. InDockerfile.base, after the existing user setup:Then add
/home/linuxbrewtofilesystem_policy.read_writeinopenclaw-sandbox.yamlso brew can install formulae at runtime under that prefix.Apply the same change to
agents/hermes/Dockerfile.baseso Hermes sandboxes get the same behavior.The image-build path runs as root, so the chown step works. Once the base image is published, every sandbox starts with a working
brewunder/home/linuxbrew/.linuxbrew/bin/brew, andbrew install <package>Just Works after applying the preset.Cost
Approximately 80 to 150 MB on the base image (Homebrew core, no formulae). Acceptable relative to the existing ~2.4 GB sandbox image and consistent with the WeChat-plugin trade-off the project already accepted.
Alternative (Option B), not recommended
Remove the
brewpreset entirely (matching the#3377approach for theghphantom binary). Cheaper at the image level but a user-visible regression: removes a preset that's currently in the Balanced tier menu, and steers Linux users without.debpackages toward unsupported workarounds.Acceptance criteria
brew --versionsucceeds inside a freshly-created sandbox with no user setup beyond applying the preset.brew install hellosucceeds, downloads the bottle, and prints the install marker.Related