Skip to content

homebrew: make bootstrap images reproducible and provenance-bound#921

Merged
brandonpayton merged 9 commits into
mainfrom
integration/homebrew-bootstrap-tooling-batch
Jul 13, 2026
Merged

homebrew: make bootstrap images reproducible and provenance-bound#921
brandonpayton merged 9 commits into
mainfrom
integration/homebrew-bootstrap-tooling-batch

Conversation

@brandonpayton

@brandonpayton brandonpayton commented Jul 13, 2026

Copy link
Copy Markdown
Member

Purpose

Provide one reviewable, ABI39-based Homebrew bootstrap tooling batch. It builds an unmodified upstream Homebrew checkout into a Kandelo VFS image through the normal package resolver, binds every manifest entry to the selected artifact tree, preserves trusted ZIP filesystem semantics without importing unsafe permissions, and makes the resulting image byte-reproducible.

The branch is a linear nine-commit stack intended for rebase merge so each independently reviewed fix remains bisectable.

Preserved commits

An independent exact audit verified that every source/candidate pair has the same stable patch ID, message, and author, and that no overlapping hunk was dropped or duplicated. A separate devil's-advocate review accepted the trusted archive permission boundary with no findings.

Integrated evidence

All validation ran through scripts/dev-shell.sh on ABI39.

Claim Evidence
Combined mkrootfs behavior 178/178 tests passed
VFS, ZIP, manifest provenance, artifact validation 108/108 focused tests passed
Shared host compatibility Node ESM/CJS, browser bundles, and declarations built
Tool typing canonical mkrootfs TypeScript check passed with ES2024 shared-memory declarations and ES2022 output target
ABI discipline ABI snapshot/version check passed unchanged at 39
Normal versus skip-resolve image both 805,316,862 bytes, SHA-256 a151cb827da26b1412fe9a8c37ae7c9ee57097e092ccf0f3920a1b4901f78b6c, byte-identical
Artifact closure 1 kernel plus 72 program artifacts validated at ABI39
Full image inspection 4,925 entries; all 64 pinned Homebrew executables are 0755; all 2,900 non-executables are 0644
Archive metadata all 167 symlinks retain exact targets; all 380 directories are 0755; every archive member is uid/gid 1000; zero mismatches

The permission policy remains fixed by default. preserve-executable is an explicit opt-in for a trusted ZIP and imports only 0111 from Unix central-directory entries. Read/write, set-ID, sticky, type, ownership, directory, symlink, and non-Unix compatibility metadata remain controlled by the manifest.

Shell syntax, Node syntax, diff checks, deterministic timestamp adversarial probes, and the complete-output/early-pipe probes also passed.

Truthful runtime boundary

The image runs real upstream Homebrew, not a registry wrapper. brew --version and brew config --no-install-from-api both reach Ruby and then exit 139 because each fork continuation needs 20,012 bytes while ABI39 reserves 16,384. The host reports that exact platform limit instead of corrupting memory. This batch intentionally does not claim that Homebrew installation is functional; continuation sizing belongs in the next ABI/rebuild batch.

Contract scope

This PR does not change ABI_VERSION, the ABI snapshot, or the VFS on-disk layout. Timestamp normalization is opt-in on a detached snapshot; ordinary Node and browser runtime snapshots preserve live POSIX times. Full browser runtime and broad conformance suites were not run locally and remain required CI evidence.

Supersession

This batch is intended to supersede #902, #917, #919, and #920 after the combined CI run is green and maintainer review is complete. Keep those PRs open until then.

Treat manifest and ZIP paths as untrusted archive input: require canonical absolute manifest paths, byte-exact UTF-8 canonical relative ZIP names, and compatible path graphs before VFS mutation. Preserve validated Unix symlink targets and ownership rather than flattening them into regular files.

This removes the generic image-builder blocker found while reviewing the Homebrew bootstrap in #902. It does not change the Kandelo ABI.
Add an exclusive --binaries-dir input to the rootfs package manifest generator. Release-image builders can now bind eager sources and lazy sizes to the same resolver tree they validate, while ordinary development retains the existing local override priority. Reject noncanonical or escaping output paths and cover selected-tree, no-fallback, eager, lazy, and path-identity behavior.
Select the canonical binaries/ tree when generating the bootstrap rootfs manifest, so eager sources and lazy sizes come from the same artifacts the builder resolves and ABI-validates. This prevents local-binaries overrides from contaminating either supported build mode.
Allow Node to flush asynchronous stdout writes before normal shutdown so large inspect output is not truncated. Treat stdout EPIPE as normal pipeline termination when a consumer closes early, while preserving other stream failures.
Keep fixed archive file modes as the safe default. Let explicitly trusted ZIPs add only Unix execute bits to the manifest-normalized file mode, while ownership and all other permission bits remain declarative.

Use the policy for the pinned Homebrew bootstrap so bin/brew and all upstream executable shims work without one-file overrides.
Mirror the ES2024 SharedMemory library surface used by the imported host VFS implementation. Keep the ES2022 code-generation target and existing compiler options unchanged.
@github-actions

github-actions Bot commented Jul 13, 2026

Copy link
Copy Markdown

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

ABI v39. 6 built, 0 failed, 6 total.

Package Arch Status Sha
kandelo-sdk wasm32 built 18405ee6
rootfs wasm32 built 0a05033f
shell wasm32 built d96885ae
lamp wasm32 built 801a444d
node-vfs wasm32 built 8207665f
wordpress wasm32 built 203f33a8

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

@brandonpayton

Copy link
Copy Markdown
Member Author

Updated the batch after devil's-advocate review found that the pinned Homebrew ZIP had 64 executable regular files while the bootstrap manifest normalized every archive file to 0644.

The new opt-in fmode_policy=preserve-executable imports only Unix 0111 bits from this pinned trusted archive. Default archive behavior remains fixed-mode. Independent review accepted the boundary, and exhaustive image comparison found 64/64 executable files at 0755, 2,900/2,900 non-executables at 0644, 167 exact symlinks, 380 directories at 0755, and no mode/owner/target mismatches.

Fresh normal and --skip-package-resolve ABI39 images are byte-identical at 805,316,862 bytes (a151cb827da26b1412fe9a8c37ae7c9ee57097e092ccf0f3920a1b4901f78b6c). The real guest probe now passes the permission boundary and reproduces only the known 20,012-byte continuation versus 16,384-byte ABI39 reserve. Full evidence is in the updated PR body.

@brandonpayton brandonpayton added the ready-to-ship Maintainer attests the exact tested head and requests merge preparation. label Jul 13, 2026
@github-actions github-actions Bot enabled auto-merge (squash) July 13, 2026 21:25
@github-actions

Copy link
Copy Markdown

prepare-merge: test-gate passed against the synthetic PR merge and binaries-abi-v39. Missing entries were built or promoted from PR staging only when their merged-tree cache key matched; merge-gate=success posted on PR HEAD and squash auto-merge enabled.

@brandonpayton brandonpayton disabled auto-merge July 13, 2026 21:30
@brandonpayton brandonpayton merged commit 9a7a679 into main Jul 13, 2026
59 checks passed
@brandonpayton brandonpayton deleted the integration/homebrew-bootstrap-tooling-batch branch July 13, 2026 21:31
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ready-to-ship Maintainer attests the exact tested head and requests merge preparation.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant