From 34b33696ab84b255f6e563edc6ef6f8cf61d3f74 Mon Sep 17 00:00:00 2001 From: Brandon Payton Date: Thu, 2 Jul 2026 00:13:40 -0400 Subject: [PATCH] docs(homebrew): document GHCR upload layout gap (blob vs native OCI) Add a "GHCR Upload Layout" section to docs/homebrew-publishing.md recording that today's bottle upload (scripts/homebrew-ghcr-upload.sh, oras push) is blob-addressable for the Kandelo VFS fetcher but is not in Homebrew's native version-tagged OCI layout, so a stock guest `brew install` against the GHCR root_url cannot resolve the bottle. Guest brew install remains unsupported. Prevents the homebrew-all package fan-out from implying `brew tap && brew install` works across packages. Docs-only; no code change. Reconciliation to the native OCI layout (brew pr-upload --upload-only, or a version-tagged index emitter) is deferred until guest brew install is a committed goal, per the bottle-publishing research doc's implementation sequence. Bead: kd-7xjc Co-Authored-By: Claude Opus 4.8 --- docs/homebrew-publishing.md | 51 ++++++++++++++++++++++++++++++++++++- 1 file changed, 50 insertions(+), 1 deletion(-) diff --git a/docs/homebrew-publishing.md b/docs/homebrew-publishing.md index d14760066..63e03a575 100644 --- a/docs/homebrew-publishing.md +++ b/docs/homebrew-publishing.md @@ -175,6 +175,53 @@ Use `dry-run: true` for local or CI validation that must not push GHCR blobs, tap commits, or release assets. Dry runs still build bottles and validate the generated metadata shape. +## GHCR Upload Layout + +The bottle upload step (`scripts/homebrew-ghcr-upload.sh`, step 5 above) is +deliberately **blob-addressable for the Kandelo VFS fetcher**, not for a stock +guest `brew install`. Read this before assuming a published bottle is `brew +install`-resolvable, and do not let the package fan-out imply otherwise. + +What the upload publishes today: + +- An OCI artifact at `ghcr.io///` tagged + `--` (e.g. `bottles-abi-v-wasm32-`), + carrying one bottle layer with media type + `application/vnd.homebrew.bottle.layer.v1+gzip` (`homebrew-ghcr-upload.sh`, + `oras push`). +- A sidecar `url` pointing at the **blob**: + `https://ghcr.io/v2////blobs/sha256:`. +- A `bottle do` `root_url` of `https://ghcr.io/v2//` (the publish + workflow passes this to `brew bottle --root-url`). + +Why the VFS fetcher is satisfied: `fetchHomebrewBottleBytes()` in +`host/src/homebrew-vfs-fetch.ts` GETs the sidecar `url` directly and follows the +GHCR `WWW-Authenticate` bearer challenge. It never resolves an OCI manifest, so +the blob digest URL is all it needs. + +Why a stock guest `brew install` cannot resolve it: Homebrew's GitHubPackages +download strategy resolves a bottle from the `root_url` by fetching the OCI +index/manifest **tagged by the formula version** +(`...//manifests/`), then selecting the layer for the running +platform tag. Homebrew's own uploader (`brew pr-upload`) tags manifests by +`version_rebuild` and uses layer media type +`application/vnd.oci.image.layer.v1.tar+gzip`. Kandelo publishes **no** +version-tagged manifest and uses a different layer media type, so a stock `brew +install` against the same `root_url` finds no manifest to pour. **Guest `brew +install` is therefore unsupported today**, consistent with the "not a general +user-facing install guide" note at the top of this document and with +"Current Gaps" below. + +This layout is intentional and sufficient for the only supported consumer (the +VFS builder). Reconciling to Homebrew's native version-tagged OCI layout — +either by switching the upload step to `brew pr-upload --upload-only` or by +teaching `homebrew-ghcr-upload.sh` to additionally emit a version-tagged OCI +index with the native layer media type — is **deferred until guest `brew +install` is a committed goal**. The sidecar `url`/sha stays the stable contract +for the VFS fetcher, so such a swap is URL-only for that consumer. Options, +tradeoffs, and a staged implementation sequence are analyzed in +`docs/plans/2026-07-01-homebrew-builtin-vs-custom-bottle-publishing-research.md`. + ## Sidecar Metadata Generate sidecars with: @@ -318,4 +365,6 @@ The implemented path covers trusted first bottle publication, sidecars, verified VFS image building, Node smoke, browser smoke, and gallery gating. Broader package coverage, general guest `brew install`, and full manual rebuild/rollback runbooks remain separate work and should stay out of -reference docs until they land. +reference docs until they land. Guest `brew install` is additionally blocked by +the non-native upload layout described under "GHCR Upload Layout" above; that +reconciliation is deferred until guest install is a committed goal.