Skip to content

brew: escalate writes to the prefix owner so the agent converges deps itself - #171

Merged
JPDuchesne merged 2 commits into
mainfrom
brew-prefix-owner-escalation
Sep 16, 2026
Merged

JPDuchesne merged 2 commits into
mainfrom
brew-prefix-owner-escalation

Conversation

@JPDuchesne

Copy link
Copy Markdown
Contributor

Stacked on #170.

Homebrew assumes exactly one non-root owner of exactly one prefix, so on cooperative shared machines (d3mlabs/plans#26) the sandboxed agent user cannot install formulae — the machine-level root cause of the plans#36 leg-2 googletest incident (brew wwise-cli EPERM aborting install-deps).

Rejected alternatives: per-user prefix (no bottles off the default prefix on Apple Silicon → source builds), host-level provisioning (human in the loop for every new formula), group-writable prefix (fragments brew's single-owner ownership metadata; unsupported by brew). Precedent: snappy's build image already routes brew through a dedicated linuxbrew user because brew refuses root — same pattern, designated owner.

  • BrewIntegration prepends sudo -n -u <prefix-owner> to brew writes (tap, install) when the prefix is not writable by the current user. Owner stat'd at runtime, never hardcoded; a writable prefix short-circuits to plain brew (single-user machines unchanged). sudo -n refusal surfaces "run dev runner register to re-converge" instead of a cryptic brew failure; escalated tap failures hint at local-tap path readability.
  • AgentBootstrap#sudoers_content gains the brew edge: agent may run exactly the brew binary as the prefix owner, NOPASSWD. Prefix/owner stat'd at bootstrap time; re-running register re-converges; omitted when the host has no brew or the agent already owns the prefix.

Test-first: all 7 new tests written and confirmed failing before the implementation. Full suite green except the 4 pre-existing BuildContainerTest failures (also fail on clean main on this machine).

End-to-end verification on this machine (after merge): re-run dev runner register, then dev install-deps as ai-agent in the snappy workspace — the previously failing wwise-cli install should succeed unattended.

Made with Cursor

… itself

Homebrew assumes exactly one non-root owner of exactly one prefix, so on
cooperative shared machines (plans#26) the sandboxed agent user cannot
install formulae — the machine-level root cause of the plans#36 leg-2
googletest incident (brew wwise-cli EPERM). Rejected alternatives:
per-user prefix (no bottles off the default prefix on Apple Silicon →
source builds), host-level provisioning (a human in the loop for every
new formula), group-writable prefix (fragments brew's single-owner
ownership metadata). Precedent: snappy's build image already routes brew
through a dedicated linuxbrew user — same pattern, designated owner.

- BrewIntegration prepends sudo -n -u <prefix-owner> to brew writes
  (tap, install) when the prefix is not writable by the current user.
  The owner is stat'd at runtime — never hardcoded — and a writable
  prefix short-circuits to plain brew: single-user machines unchanged.
  A sudo -n refusal names the missing edge and its remediation.
- AgentBootstrap's sudoers drop-in gains the brew edge: the agent may
  run exactly brew as the prefix owner, NOPASSWD. Stat'd at bootstrap,
  re-converged by re-running register, omitted when the host has no
  brew or the agent owns the prefix itself.

Co-authored-by: Cursor <cursoragent@cursor.com>
@codecov

codecov Bot commented Sep 15, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

srb tc rejects splatting a dynamically-sized array into system()
(error 7019); route the escalation argv through T.unsafe like
run_brew_install already does. Cover the changed lines codecov
flagged: URL-less tap registration (with and without escalation,
asserting the remediation hint only appears when escalated) and
brew --prefix discovery (memoized success and ENOENT-absent brew).

Co-authored-by: Cursor <cursoragent@cursor.com>
Base automatically changed from install-deps-failure-isolation to main September 16, 2026 15:39
@JPDuchesne
JPDuchesne merged commit 00d6b5d into main Sep 16, 2026
6 checks passed
@JPDuchesne
JPDuchesne deleted the brew-prefix-owner-escalation branch September 16, 2026 15:40
JPDuchesne added a commit that referenced this pull request Sep 16, 2026
Agent-isolation and emulated-Mac fixes: install-deps failure isolation with typed errors (#170), brew escalation to the prefix owner + AgentBootstrap sudoers edge (#171), BuildKit secret files in a verified per-uid dir under the data root — colima-visible and substitution-proof (#173), build-watcher guest-load liveness signal + 15m stall window (#174), sigpending ulimit for Rosetta signal-queue aborts (#175), and brew trust before tap in docker-install-build-deps (tap-rot fix).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant