Skip to content

[Homebrew] Make the stock guest bootstrap usable#1059

Draft
brandonpayton wants to merge 2 commits into
mainfrom
codex/homebrew-guest-bootstrap-qk044
Draft

[Homebrew] Make the stock guest bootstrap usable#1059
brandonpayton wants to merge 2 commits into
mainfrom
codex/homebrew-guest-bootstrap-qk044

Conversation

@brandonpayton

@brandonpayton brandonpayton commented Jul 22, 2026

Copy link
Copy Markdown
Member

Why

Kandelo can start upstream Homebrew, but starting brew --version is not enough
to make Homebrew useful inside a guest machine. Stock Homebrew also expects a
writable Linuxbrew prefix, a versioned Ruby location, Git and certificate
paths, cache and lock directories, and a supported way to discover taps without
silently cloning the very large homebrew/core repository.

Without those pieces, ordinary commands such as brew config, brew doctor,
and brew tap fail even though the brew script itself launches. This PR gives
the opt-in Homebrew image that conventional guest layout. It keeps
/usr/bin/brew as a direct link to pinned upstream Homebrew rather than hiding
missing platform behavior behind a Kandelo-specific wrapper.

This is groundwork for a built-in brew command in the main shell. It does not
activate that command in the main shell yet, and it does not claim that the
complete install lifecycle is ready.

What changed

  • Pin Homebrew to upstream commit
    4ead8619231cb15cbe15e8e8188081e347d6f7cd, the reviewed revision that
    supports the public Formula syntax used by the Kandelo tap.
  • Install /usr/bin/brew, Ruby, RubyGems, and Bundler through their normal
    guest paths.
  • Give the unprivileged linuxbrew user (uid=1000, gid=1000) the standard
    writable repository, Cellar, tap, cache, configuration, lock, and temporary
    directories.
  • Provide Homebrew's expected portable-Ruby alias, managed certificate path,
    and Git HTTP/HTTPS helper paths using the corresponding Kandelo image files.
  • Configure Homebrew's supported no-API mode. GitHub's official Homebrew
    package API has no Kandelo platform index, so API mode otherwise requests a
    nonexistent dunno_generic index. No-API mode also prevents unrelated custom
    tap commands from cloning homebrew/core automatically.
  • Record the immutable initial source and layout as root-owned metadata while
    truthfully leaving the live checkout and install state guest-writable.
  • Cover the layout, source pin, generated metadata, rootfs manifest, Node.js
    guest contract, and Chromium guest contract.

What the current proof covers

The exact opt-in image has demonstrated the following behavior through stock
Homebrew commands:

  • brew config reports the Linuxbrew prefix and Kandelo's Ruby, Git, curl, and
    no-API configuration.
  • The bottles-only brew doctor checks for directories, temporary state, Git,
    and core integrity pass. The remaining warning truthfully says that this
    image has no source-build developer toolchain.
  • brew tap clones the public Kandelo-dev/homebrew-tap-core tap and resolves
    its Bzip2 bottle.
  • brew tap also clones the independent public canary tap and resolves M4 plus
    its fully qualified Dash dependency from the first-party tap.
  • A bounded diagnostic metadata closure let unmodified
    brew install --force-bottle kandelo-dev/tap-core/bzip2 download, pour, and
    execute the public bottle. Its receipt records poured_from_bottle: true and
    no runtime dependencies.

The small diagnostic metadata closure is evidence, not a product mechanism.
A complete homebrew/core checkout measured about 1.3 GiB, including a 1.22
GiB Git pack with more than 3.6 million objects, so embedding or cloning it in
the guest is not viable.

Remaining work

Kandelo Formulae currently describe publisher-only native tools such as
binaryen and wabt as Formula dependencies. Stock Homebrew recursively
resolves those Formulae before it prunes them from a bottle installation. The
next change will model them as tightly allowlisted custom Homebrew
Requirement classes, which is Homebrew's normal representation for external
tools that do not belong in the guest Formula graph.

That follow-up must preserve exact publisher trust and provenance, reject
unknown or forged Requirement definitions, and test ordinary install,
reinstall, uninstall, and cross-tap behavior in Node.js and Chromium. Durable
state across reboot and activation of brew in the canonical main shell also
remain Phase 5 work.

Validation

Fresh validation after restacking these commits onto current main:

  • Homebrew bootstrap source and pin contract
  • 29 focused layout and rootfs tests
  • host declaration-file typecheck
  • merge-candidate workflow contract
  • shell and Node.js syntax checks
  • Playwright discovery of the browser bootstrap test
  • git diff --check

Earlier exact-candidate validation also built the 805,315,495-byte bootstrap
image and passed the same unprivileged guest contract in Node.js and Chromium,
plus the live tap and diagnostic Bzip2-pour checks described above. The current
restacked head must repeat its exact image and runtime gates in CI; those broad
runtime claims are not inferred from the focused restack checks alone.

This changes the opt-in package/image contract and shared Node.js/browser guest
bootstrap path. It does not change the kernel ABI.

@brandonpayton

Copy link
Copy Markdown
Member Author

Fresh exact-shell CI stopped before building the Homebrew image: the changed Bash revision correctly missed the older public archive, but the generic source fallback had not prepared musl or the wasm32 sysroot. That workflow defect is isolated in #1065, including clean-source cache protection. After #1065 lands, I will restack this draft and rerun the changed-Bash path as the end-to-end proof.

@github-actions

Copy link
Copy Markdown

Phase B-1 matrix build status — pr-1059-staging

ABI v41. 2 built, 0 failed, 2 total.

Package Arch Status Sha
bash wasm32 built d3cdc172
rootfs wasm32 built 094a00cc

Auto-generated; replaced on each push. Raw data in the publish-status workflow artifact.

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