Skip to content

docs(policy): clarify brew preset requires pre-installed Homebrew (#3757)#3846

Closed
latenighthackathon wants to merge 4 commits into
NVIDIA:mainfrom
latenighthackathon:docs/brew-preset-bootstrap-3757
Closed

docs(policy): clarify brew preset requires pre-installed Homebrew (#3757)#3846
latenighthackathon wants to merge 4 commits into
NVIDIA:mainfrom
latenighthackathon:docs/brew-preset-bootstrap-3757

Conversation

@latenighthackathon

@latenighthackathon latenighthackathon commented May 20, 2026

Copy link
Copy Markdown
Contributor

Summary

Closes #3757 (also duplicates the earlier #1767 from 2026-04-10). Clarifies that the brew policy preset whitelists Homebrew network egress and binary paths but does not install Homebrew itself; users must bootstrap brew inside the sandbox once after applying the preset.

Problem

The brew preset's binary list includes /home/linuxbrew/.linuxbrew/bin/brew and the linuxbrew bin glob, alongside the bootstrap binaries /usr/bin/curl and /usr/bin/git. The bootstrap binaries are real and present in the sandbox base image, so the user can run the Homebrew install script. The linuxbrew paths are placeholders that become real once Homebrew is installed inside the sandbox.

Two QA reports (#1767 from 2026-04-10, #3757 from 2026-05-18) hit the same trap: apply the preset, connect into the sandbox, run brew install hello, get bash: brew: command not found. The preset description "Homebrew (Linuxbrew) package manager access" reads as if it provides the manager, not just the network policy for it.

Filesystem-permission caveat (root cause)

This PR is a docs-only band-aid. The Homebrew install script cannot actually succeed in the default sandbox today: /home/linuxbrew/ is not in filesystem_policy.read_write (Landlock denies writes), AND the sandbox runs as the unprivileged sandbox user with no sudo (Homebrew's install script's first step is sudo to create + chown /home/linuxbrew/.linuxbrew).

The root-cause fix lives in #3916, which bakes Homebrew core into the sandbox base image (mirroring the #3682 WeChat-plugin precedent) and adds /home/linuxbrew to the baseline read_write list. Once #3916 lands, users only need to apply the preset; the bootstrap step in this PR becomes optional (and would only matter for sandboxes built before the base-image rebuild).

Until #3916 ships, the bootstrap one-liner in this PR will return Homebrew's "Insufficient permissions" error on a fresh sandbox. The "Untar Anywhere" alternative under /sandbox/ works as a workaround but builds formulae from source (unsupported by Homebrew).

Approach

Documentation + preset description fix, no behavior change:

  • nemoclaw-blueprint/policies/presets/brew.yaml - update the preset description to explicitly call out the pre-install requirement, add a file-header comment explaining why the linuxbrew paths are whitelisted before brew exists, and split the binary list into a bootstrap group (curl, git) and a post-install group (linuxbrew paths) with inline comments.
  • docs/network-policy/customize-network-policy.mdx - the brew row in the presets table now links to the bootstrap walkthrough.
  • docs/network-policy/integration-policy-examples.mdx - new "Homebrew Bootstrap" section after Package and Model Tooling. Shows the policy-add -> connect -> Homebrew install script -> brew shellenv -> brew install hello sequence.

Test plan

  • prek run --files clean on all three modified files (yaml + 2 mdx)
  • git grep "Homebrew (Linuxbrew) package manager" returns only the updated preset (no test fixture depends on the old description)
  • Verified the preset YAML still parses (validated by the schema-check prek hook)

Signed-off-by: latenighthackathon latenighthackathon@users.noreply.github.com

@copy-pr-bot

copy-pr-bot Bot commented May 20, 2026

Copy link
Copy Markdown

This pull request requires additional validation before any workflows can run on NVIDIA's runners.

Pull request vetters can view their responsibilities here.

Contributors can view more details about this message here.

@coderabbitai

coderabbitai Bot commented May 20, 2026

Copy link
Copy Markdown
Contributor
📝 Walkthrough

Walkthrough

This PR clarifies that the brew network-policy preset requires Homebrew to be installed inside the sandbox, updates brew.yaml with explanatory comments and bootstrap-related binary whitelist notes, and adds user documentation with a one-time Homebrew bootstrap workflow and commands.

Changes

Homebrew Preset Bootstrap

Layer / File(s) Summary
Homebrew preset policy and metadata
nemoclaw-blueprint/policies/presets/brew.yaml
Preset description now states Homebrew must be installed inside the sandbox. Added comments and clarified /usr/bin/curl and /usr/bin/git whitelist entries as bootstrap tools and the rationale for post-install whitelisting under /home/linuxbrew/.linuxbrew/....
Homebrew bootstrap guidance and preset reference
docs/network-policy/customize-network-policy.mdx, docs/network-policy/integration-policy-examples.mdx
Preset table entry updated with a Homebrew-in-sandbox requirement and link. New "Homebrew Bootstrap" subsection documents the one-time per-sandbox install workflow (apply preset, connect, run Homebrew install script, and configure brew shell environment) with concrete commands.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

Possibly related PRs

  • NVIDIA/NemoClaw#3799: Related network-policy documentation updates covering preset application and persistence semantics.

Suggested labels

documentation

Suggested reviewers

  • miyoungc
  • ericksoa

Poem

🐰 I hopped into docs with a curious brew,
A tiny install dance for users and crew,
Curl and git paved the sandbox trail,
Homebrew wakes where policies prevail,
Sip success — cheers from this rabbit too! 🥂

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately and concisely summarizes the main change: clarifying that the brew preset requires pre-installed Homebrew, which directly addresses the core issue reported in #3757.
Linked Issues check ✅ Passed The PR directly addresses the primary objective from #3757 by updating documentation and preset description to clarify that the brew preset provides network access only and does not install the brew CLI, requiring users to manually install Homebrew first.
Out of Scope Changes check ✅ Passed All changes are documentation and preset description updates directly related to clarifying the brew preset's scope; no runtime behavior changes or unrelated modifications are present.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@docs/network-policy/integration-policy-examples.mdx`:
- Line 243: Split the single source line containing two sentences into two
separate lines: keep "After the first install, `brew` is on the sandbox `PATH`
and subsequent `brew install <package>` calls work directly." as one line, and
place "The bootstrap is per-sandbox; recreating the sandbox requires re-running
the install." on the following line so each sentence is on its own source line
for diff readability.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: 7feb4c98-4a58-470d-bd91-6eb7036b6c2a

📥 Commits

Reviewing files that changed from the base of the PR and between 6d910d3 and 60f929a.

📒 Files selected for processing (3)
  • docs/network-policy/customize-network-policy.mdx
  • docs/network-policy/integration-policy-examples.mdx
  • nemoclaw-blueprint/policies/presets/brew.yaml

Comment thread docs/network-policy/integration-policy-examples.mdx Outdated
@ericksoa ericksoa added the v0.0.47 Release target label May 20, 2026
…IDIA#3757)

The brew policy preset whitelists network egress to the Homebrew
registry and the binary paths under /home/linuxbrew/.linuxbrew/, but
the sandbox base image does not ship the brew CLI itself. Users who
apply the preset and run `brew install hello` immediately hit
`bash: brew: command not found` (NVIDIA#3757, duplicates NVIDIA#1767 from
2026-04-10).

The linuxbrew paths in the preset binary list are intentional: they
become active once the user installs Homebrew inside the sandbox, and
whitelisting them up front avoids a second policy round-trip. The
preset surface just was not telling users that step is on them.

Changes:

- nemoclaw-blueprint/policies/presets/brew.yaml: clarify the preset
  description, add an inline header comment explaining the design,
  and group the bootstrap binaries (curl, git) vs the post-install
  linuxbrew paths so a future reader sees the intent.
- docs/network-policy/customize-network-policy.mdx: the brew row in
  the preset table now links to the bootstrap walkthrough.
- docs/network-policy/integration-policy-examples.mdx: new Homebrew
  Bootstrap section after Package and Model Tooling. Shows the
  preset-add + connect + install one-liner + shellenv eval sequence.

Refs NVIDIA#3757, NVIDIA#1767

Signed-off-by: latenighthackathon <support@latenighthackathon.com>
CodeRabbit nit: integration-policy-examples.mdx:243 had two sentences
on one line. Split per the repo's one-sentence-per-line style so diffs
stay readable.

Signed-off-by: latenighthackathon <support@latenighthackathon.com>
@latenighthackathon latenighthackathon force-pushed the docs/brew-preset-bootstrap-3757 branch from 31bfdf5 to 939cec2 Compare May 20, 2026 02:36
@wscurran

Copy link
Copy Markdown
Contributor

✨ Thanks for submitting this detailed PR about clarifying the brew preset requirements. This PR proposes a way to update the documentation and improve the brew policy preset to avoid confusion about Homebrew installation.


Related open issues:

@latenighthackathon

latenighthackathon commented May 20, 2026

Copy link
Copy Markdown
Contributor Author

Closing this docs-only PR in favor of #3916, which fixes the root cause by baking Homebrew into the sandbox base image. Will open a follow-up docs PR with up-to-date content if/when #3916 lands (or receive guidance from maintainers on preferred way to solve for this)!

@latenighthackathon latenighthackathon deleted the docs/brew-preset-bootstrap-3757 branch May 20, 2026 18:18
latenighthackathon added a commit to latenighthackathon/NemoClaw that referenced this pull request May 20, 2026
…#3913)

The brew policy preset advertises "Homebrew (Linuxbrew) package manager
access" and whitelists the linuxbrew binary paths, but the sandbox
cannot actually install Homebrew at runtime:

  1. nemoclaw-blueprint/policies/openclaw-sandbox.yaml does not list
     /home/linuxbrew under filesystem_policy.read_write, so Landlock
     denies writes there.
  2. The sandbox runs as the unprivileged `sandbox` user with no sudo
     (Dockerfile.base creates `sandbox` with HOME=/sandbox). Homebrew's
     install script's first step is `sudo` to create + chown
     /home/linuxbrew/.linuxbrew, which the sandbox cannot grant.

Applying the brew preset and running the documented bootstrap line in
the sandbox fails immediately with "Insufficient permissions to install
Homebrew to /home/linuxbrew/.linuxbrew". The preset's binary whitelist
for /home/linuxbrew/.linuxbrew/bin/* becomes dead code.

This change bakes Homebrew core into the sandbox base image during
build (running as root, then dropping to sandbox via gosu for the
clone). The companion baseline-policy change adds /home/linuxbrew to
filesystem_policy.read_write so brew can extract bottles and manage
Cellar/opt symlinks at runtime.

After the next base-image rebuild, every sandbox starts with a working
brew at /home/linuxbrew/.linuxbrew/bin/brew. Applying the brew preset
plus running `brew install <formula>` works end-to-end with no
bootstrap required.

Precedent: NVIDIA#3682 (in v0.0.46, closes NVIDIA#3677) baked the WeChat plugin
into the sandbox base image for the same reason.

Files:

- Dockerfile.base: add the brew install step at the end, after the
  WeChat plugin block. Image-build cost is ~80 to 150 MB for Homebrew
  core (formulae download on demand).
- nemoclaw-blueprint/policies/openclaw-sandbox.yaml: add /home/linuxbrew
  to filesystem_policy.read_write with an inline comment explaining
  the link to the Dockerfile.base step.
- test/policies.test.ts: add a behavior-style assertion that the
  baseline read_write list includes the Homebrew prefix, so a future
  removal of this entry trips CI.

Out of scope for this PR:

- agents/hermes/Dockerfile.base. Hermes does not currently get the
  WeChat plugin baking either; same scoping rationale.
- Adding /home/linuxbrew/.linuxbrew/bin to the system PATH. Users can
  run `brew` via the full path or via `eval "$(brew shellenv)"`. PR
  NVIDIA#3846 documents the latter.

Closes NVIDIA#3913
Refs NVIDIA#1767, NVIDIA#3757

Signed-off-by: latenighthackathon <support@latenighthackathon.com>
ericksoa added a commit that referenced this pull request May 21, 2026
…#3916)

## Summary

Closes #3913. Bakes Homebrew core into the sandbox base image so the
`brew` policy preset actually works end-to-end. Without this, applying
the preset and running `brew install <formula>` inside the sandbox fails
with `Insufficient permissions to install Homebrew to
"/home/linuxbrew/.linuxbrew"` because the sandbox lacks filesystem write
to `/home/linuxbrew/` AND runs as an unprivileged user with no sudo.

## Problem

Two filesystem constraints block runtime Homebrew installation today:

1. `nemoclaw-blueprint/policies/openclaw-sandbox.yaml` lists only
`[/tmp, /dev/null, /sandbox/.openclaw, /sandbox/.nemoclaw]` plus the
workdir under `filesystem_policy.read_write`. Landlock denies writes to
`/home/linuxbrew/`.
2. `Dockerfile.base` runs the sandbox as `useradd -r -g sandbox -d
/sandbox -s /bin/bash sandbox` (no sudo). Homebrew's install script's
first step is `sudo` to create + chown `/home/linuxbrew/.linuxbrew`,
which the sandbox cannot grant.

Result: the `brew` preset's binary whitelist for
`/home/linuxbrew/.linuxbrew/bin/*` is dead code. Two QA reports already
documented the symptom:
[#1767](#1767) (filed
2026-04-10) and [#3757](#3757)
(filed 2026-05-18).
[#3846](#3846) was an interim
docs-only attempt that we closed in favor of this PR; documenting a
bootstrap that cannot actually succeed in the default sandbox would have
set wrong expectations.

## Approach

Follow the [#3682](#3682)
precedent (WeChat plugin baked into the base image in v0.0.46):
provision the tool at image-build time, when the build runs as root and
can create + chown the prefix.

- `Dockerfile.base`: after the existing WeChat plugin install block, add
a step that creates `/home/linuxbrew/.linuxbrew/bin`, chowns to
`sandbox:sandbox`, clones Homebrew core as the sandbox user via `gosu`
at the pinned `ARG HOMEBREW_VERSION=5.1.12` tag, symlinks the `brew`
entry point, and asserts `brew --version` succeeds. The `ARG` keeps the
base-image layer reproducible across rebuilds and can be bumped by
editing the default or passing `--build-arg`.
- `nemoclaw-blueprint/policies/openclaw-sandbox.yaml`: add
`/home/linuxbrew` to `filesystem_policy.read_write` so runtime `brew
install <formula>` can extract bottles and manage Cellar/opt symlinks.
- `test/policies.test.ts`: behavior-style assertion that the baseline
`read_write` list includes the Homebrew prefix. Trips CI if a future
change drops the entry.

## Cost

Approximately 80 to 150 MB on the base image (Homebrew core only;
formulae download on demand). Acceptable relative to the existing ~2.4
GB sandbox image and consistent with the trade-off the project already
accepted for the WeChat plugin baking.

## Follow-up docs PR planned

Once this merges and the base image rebuilds, a small docs PR will land
covering the new flow on the matching MDX pages: apply the `brew`
preset, run `brew install <formula>`. The previous attempt at
documenting a runtime bootstrap (closed
[#3846](#3846)) becomes obsolete
and the new docs will reflect that `brew` is included by default.

## Out of scope

- **`agents/hermes/Dockerfile.base`** — Hermes does not currently get
the WeChat plugin baking either; same scoping rationale. Can extend in a
follow-up if maintainers want Homebrew under Hermes.
- **System `PATH`** — users can run `brew` via the full path
`/home/linuxbrew/.linuxbrew/bin/brew` or via `eval
"$(/home/linuxbrew/.linuxbrew/bin/brew shellenv)"`. A separate PR could
add the prefix to `/etc/bash.bashrc` if a cleaner default UX is wanted.
- **Option B (drop the brew preset entirely)** — discussed in
[#3913](#3913); rejected
because removing a Balanced-tier preset is a user-visible regression.

## Test plan

- [x] `prek run --files` clean on all changed files
- [x] New `test/policies.test.ts` assertion passes (`Homebrew prefix`
test)
- [x] Behavior-style test (parses YAML and checks the structured
`read_write` array); satisfies the source-shape budget
- [x] Verified the pinned `HOMEBREW_VERSION=5.1.12` tag exists upstream
(`gh api repos/Homebrew/brew/releases` + direct
`https://github.com/Homebrew/brew/releases/tag/5.1.12` returns 200)
- [ ] **CI to verify:** sandbox base image rebuilds successfully with
the new step
- [ ] **CI to verify:** `brew --version` runs inside a freshly-created
sandbox (covered by the build-time `gosu sandbox
/home/linuxbrew/.linuxbrew/bin/brew --version` assertion in
`Dockerfile.base`)
- [ ] **Manual smoke after base-image publish:** `nemoclaw onboard` ->
`<name> policy-add brew --yes` -> `<name> connect` -> `brew install
hello` -> succeeds

Signed-off-by: latenighthackathon
<latenighthackathon@users.noreply.github.com>


<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

* **New Features**
* Homebrew package manager is now pre-installed and available in the
sandbox environment, enabling users to install and manage software
packages using standard Homebrew commands.

* **Tests**
* Added validation tests for Homebrew policy configuration and binary
permissions.

<!-- review_stack_entry_start -->

[![Review Change
Stack](https://storage.googleapis.com/coderabbit_public_assets/review-stack-in-coderabbit-ui.svg)](https://app.coderabbit.ai/change-stack/NVIDIA/NemoClaw/pull/3916?utm_source=github_walkthrough&utm_medium=github&utm_campaign=change_stack)

<!-- review_stack_entry_end -->

<!-- end of auto-generated comment: release notes by coderabbit.ai -->

---------

Signed-off-by: latenighthackathon <support@latenighthackathon.com>
Signed-off-by: Aaron Erickson <aerickson@nvidia.com>
Co-authored-by: latenighthackathon <latenighthackathon@users.noreply.github.com>
Co-authored-by: Aaron Erickson <aerickson@nvidia.com>
@wscurran wscurran added bug-fix PR fixes a bug or regression area: docs Documentation, examples, guides, or docs build and removed fix labels Jun 3, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area: docs Documentation, examples, guides, or docs build bug-fix PR fixes a bug or regression v0.0.47 Release target

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[NemoClaw][Linux] Brew policy preset applies network rules but does not provision brew binary, so brew install step in test cannot succeed

3 participants