Skip to content

feat(release): let the Homebrew formula withdraw macOS - #349

Merged
hyperb1iss merged 2 commits into
mainfrom
nova/homebrew-withdraw-macos
Oct 4, 2026
Merged

hyperb1iss merged 2 commits into
mainfrom
nova/homebrew-withdraw-macos

Conversation

@hyperb1iss

@hyperb1iss hyperb1iss commented Oct 4, 2026 •

Copy link
Copy Markdown
Owner

What this changes

The Homebrew renderer can now withdraw macOS instead of carrying an old build forward. homebrew-formula.mjs --withdraw-macos replaces the formula's on_macos download block with a fatal NotarizedMacosBuildRequirement. As a result, a macOS install or upgrade fails with the reason and the command to remove an older build, and no build is offered.

Once withdrawn, macOS stays withdrawn: readPublishedMacos recognises the withdrawn stanza, so carry mode keeps it on every later release while Linux advances. The next release that ships a notarized macOS build renders macOS and the cask in full again, with no manual step.

The README and the three macOS install sections on the docs site (installation guide, download page, install chooser) now open with a notice. It says macOS is on hold for notarization, that the older macOS builds on the release page should not be installed, and how to remove 0.3.2 or earlier. The notices sit above the existing instructions, so restoring macOS is a deletion.

Why

Carry mode pinned macOS to the newest notarized build in the tap, which is 0.3.2. That release predates the --macos-owner argument the formula's own service passes, and we don't want anyone installing it. Apple has held every notarization since 2026-09-29, so there is no newer notarized build to offer instead. The companion tap PR applies the withdrawal now and disables the cask.

Verification

  • Added or updated tests
  • Added or updated docs (README, AGENTS.md, relevant spec, or guide)
  • just verify passes locally (Rust fmt + lint + test)
  • just deny passes (required for dependency or license changes)
  • just ui-test and just ui-build pass (required for crates/hypercolor-ui/)
  • just sdk-lint, just sdk-check, and just sdk-build pass (required for sdk/)
  • just python-verify passes (required for python/)
  • just compat-check passes (required for data/drivers/vendors/*.toml)
  • just docs-build passes (required for docs or README changes)
  • cd docs && zola check passes (required for docs link/content changes)
  • Packaging scripts were syntax-checked (required for scripts/ or packaging/)
  • just e2e-build passes with the normal Servo stack (required for daemon/UI/effect integration changes)
  • just e2e-build-cpu passes when validating the CPU smoke fallback
  • just e2e passes against the Servo stack (required for end-to-end behavior changes; starts daemon/browser)
  • Tested on real hardware, simulator, or e2e harness (describe below)

No Rust, UI, SDK or Python files change. zola build and zola check pass with the new notices (97 pages).

  • Workflow tests: the homebrew-formula, macos-release and macos-ci-coverage suites pass 32 of 32 under node --test. As before, the one existing shasum test runs here with a sha256sum shim. The new cases cover four paths:

    • the withdrawn render itself (refusal block, real Linux URL and checksum, service block unchanged);
    • carry over a withdrawn formula, which stays withdrawn;
    • a notarized release after withdrawal, which restores macOS;
    • the CLI's refusal to combine --withdraw-macos with other macOS inputs, and the guard that refuses a template whose first on_macos block is not the download (removing that guard fails the test).

    A workflow test also runs the job's real checksum, render and push shell against a withdrawn published formula.

  • Real Homebrew: the companion tap PR's workflow installs the withdrawn formula and the disabled cask on macOS with Homebrew 7.0.7. The formula resolves 0.6.1 and then fails on the unsatisfied requirement with the notarization message, before anything is downloaded. The cask refuses with "has been disabled because it is waiting on a notarized release".

  • Independent review: a separate agent traced Homebrew's source and confirmed that install and upgrade both check requirements before fetching. It mutation-tested the carry and withdraw paths and passed the change. Its should-fixes (the releases link, uninstall guidance, docs, merge order) are addressed here.

  • Workflow lint: actionlint reports nothing new.

Notes for reviewers

  • The macOS stanza still carries a URL. Homebrew won't load a formula on macOS without one, so the withdrawn block names the release's Linux amd64 tarball with its real checksum, and the requirement is what stops the install. The tap workflow asserts that the tarball never reaches the download cache.
  • Merge this before the tap PR. The renderer on main misreads a withdrawn formula as a carried build and would re-render a broken macOS stanza on the next tag.
  • Existing 0.3.2 installs can't be removed remotely. Formula users now get the refusal on brew upgrade, which names the uninstall command. Cask upgrades are skipped with a warning, and the disabled reason names the cask's uninstall command.
  • Escape hatches remain: brew install --ignore-dependencies skips requirements (it would install the Linux tarball on a Mac), and brew fetch downloads without checking them. Neither path reaches 0.3.2.
  • Wording fix: the tap commit body for a carried release now says macOS "stays as published", since that stanza may be withdrawn rather than pinned.

🤖 Generated with Claude Code

Summary by CodeRabbit

  • Homebrew
    • Linux packages continue to use each stable release. macOS packages are published only when a notarized macOS build is available.
    • When a release lacks a notarized macOS build, macOS installs and upgrades are blocked with an explanation and a link to the releases page. The published macOS package remains in place until a notarized build ships.
    • Later releases can retain the macOS restriction until notarized builds are available again.

Carry mode pinned macOS to the last notarized build in the tap, which
today is 0.3.2: a daemon too old for the formula's own service
arguments. With Apple holding every notarization since 2026-09-29,
offering that build is worse than offering none.

The renderer gains a withdrawn macOS state. --withdraw-macos replaces
the on_macos download block with a fatal NotarizedMacosBuildRequirement,
so a macOS install or upgrade fails with the reason and a link to the
releases page. Homebrew needs a URL to load the formula on macOS, so
the withdrawn block names the release's Linux amd64 tarball with its
checksum; the requirement stops the install. readPublishedMacos
recognises the withdrawn stanza, so carry mode keeps it withdrawn on
later releases, and the next release with a notarized build renders
macOS and the cask in full again.

The tap commit body for a carried release no longer claims macOS sits
on the last notarized build, since it may be withdrawn. RELEASING.md
describes the state and the matching disable! on the cask.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Oct 4, 2026 •

Copy link
Copy Markdown

Review in Change Stack →

Navigate logical layers of code changes, visualize relationships, and explore their blast radius.

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration
  • Configuration used: Organization UI
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: c1d4a2bd-3a38-4f06-90a8-2ac236f17c40
📥 Commits

Reviewing files that changed from the base of the PR and between f687e51 and 2ab7d5d.

📒 Files selected for processing (6)
  • .github/workflows/ci.yml
  • docs/development/RELEASING.md
  • packaging/homebrew/hypercolor.rb
  • scripts/homebrew-formula.mjs
  • scripts/tests/homebrew-formula.test.mjs
  • scripts/tests/macos-release.test.mjs

Included review availability: This review used your included allowance. Your plan provides up to 1 included review per hour; 0 remain after this review.


📝 Walkthrough

Walkthrough

The Homebrew formula generator now supports withdrawing macOS installs while continuing Linux releases. Carry mode preserves the withdrawn state, and a later notarized macOS release restores the macOS formula stanza and cask.

Changes

Homebrew macOS withdrawal

Layer / File(s) Summary
Withdrawn formula state
packaging/homebrew/hypercolor.rb, scripts/homebrew-formula.mjs, scripts/tests/homebrew-formula.test.mjs
The formula uses a notarization requirement to refuse macOS installs for withdrawn releases. The generator detects and carries the withdrawn state while rendering Linux release values. Tests cover withdrawal, carry-forward, and restoration of the macOS download.
Withdrawal CLI and release flow
scripts/homebrew-formula.mjs, scripts/tests/homebrew-formula.test.mjs, scripts/tests/macos-release.test.mjs, docs/development/RELEASING.md, .github/workflows/ci.yml
The CLI adds --withdraw-macos, rejects incompatible macOS inputs, and writes only the formula. Release guidance and tests cover carry behavior, the unchanged cask, and the updated Homebrew commit message.

Priority: ⬇️ Low

Estimated code review effort: 3 (Moderate) | ~20 minutes

Change: Feature

Sequence Diagram(s)

sequenceDiagram
  participant ReleaseOperator
  participant homebrew-formula.mjs
  participant HomebrewFormula
  participant NotarizedMacosBuildRequirement
  ReleaseOperator->>homebrew-formula.mjs: Provide --withdraw-macos and Linux release inputs
  homebrew-formula.mjs->>HomebrewFormula: Write formula with withdrawn macOS stanza
  HomebrewFormula->>NotarizedMacosBuildRequirement: Check platform requirement
  NotarizedMacosBuildRequirement-->>HomebrewFormula: Fail on macOS with releases guidance
Loading

Merge Risk: ⚪ Minimal · up to 2ab7d

Normal macOS formula installs are blocked before the Linux archive is downloaded. The cask requires the separately documented disablement step. No merge-blocking issue remains after normal checks.

Security Architecture Review

Security architecture risk: 🔵 Low · up to 2ab7d

The change restricts macOS installation without adding runtime privileges. Withdrawal persists across later releases, but complete withdrawal also requires separately disabling the cask. That external rollout and behavior on a supported Homebrew version remain unverified.

Retained concerns
No architecture-level concerns identified.

Security review details

Security Blast Radius

  • inferred — The changed control affects availability of this project's macOS formula in its Homebrew tap. Linux publication continues independently, and complete macOS withdrawal also depends on cask state. No expansion into another tenant, data store, or runtime privilege domain was identified in the scoped source change.

Trust Boundaries and Controls

  • observed — The renderer consumes operator-supplied templates, paths, versions, checksums, and published formula text. Versions and checksums are constrained before interpolation. The release workflow obtains artifacts from the named release and requires an authenticated token with push permission to publish the tap. The withdrawal marker remains trusted published configuration, not independently authenticated state.

Resilience and Maintainability Implications

  • observed — The release job stops on an incomplete macOS asset pair or failed download rather than silently selecting carry. Inspected tests cover repeated carry, restoration, conflicting withdrawal inputs, and unchanged cask content. They do not establish interrupted-write recovery, concurrent-writer behavior, or live Homebrew enforcement.

Hardening Proposals

  • proposed — Verify the published withdrawn formula and disabled cask together, and exercise normal install and upgrade behavior on a supported Homebrew version. This would confirm the documented rollout without treating formula rendering as an unconditional no-download guarantee.
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 25.00% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 8 functions across 4 files. (2 skipped: 2… Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the main change: adding support to withdraw macOS from the Homebrew formula during releases.
Full details: Docstring Coverage

Explanation

Docstring coverage is 25.00% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 8 functions across 4 files. (2 skipped: 2 unsupported.)

  • Fix all pre-merge checks with AI
✨ Finishing Touches 💡 1
📝 Generate docstrings 💡
  • Commit to this branch
  • Create a new PR
  • Autopilot · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

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

The withdrawn formula's message linked the releases page, whose only
macOS downloads are 0.3.2 and older, and the README and three docs
pages still sent macOS users to the DMG and the cask. The requirement
message now says to remove an older build with `brew uninstall
hypercolor`, and each macOS install section opens with a notice that
macOS is on hold for notarization, that the older builds on the release
page should not be installed, and how to remove 0.3.2 or earlier. The
notices sit above the existing instructions so restoring macOS is a
deletion.

Also from review: the withdrawn-render test now checks a phrase that
exists on one line, a new test covers the guard that refuses a template
whose first on_macos block is not the download, the generated comment
no longer claims the requirement is the only thing that could stop an
install, and RELEASING.md says the disabled cask skips upgrades rather
than failing them.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
hyperb1iss added a commit to hyperb1iss/homebrew-tap that referenced this pull request Oct 4, 2026
The formula's refusal no longer links the releases page, whose only
macOS downloads are 0.3.2 and older; it says to remove an older build
with brew uninstall hypercolor. The disabled cask's reason names
brew uninstall --cask hypercolor-app the same way. Rendered from the
updated template in hyperb1iss/hypercolor#349.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@hyperb1iss
hyperb1iss merged commit 96e9cc5 into main Oct 4, 2026
42 checks passed
@hyperb1iss
hyperb1iss deleted the nova/homebrew-withdraw-macos branch October 4, 2026 19:22
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