feat(release): Homebrew formula automation and manual-dispatch binary builds - #1
Open
trumpyla wants to merge 6 commits into
Open
feat(release): Homebrew formula automation and manual-dispatch binary builds#1trumpyla wants to merge 6 commits into
trumpyla wants to merge 6 commits into
Conversation
…n npm fallback The formula is now rendered by scripts/sea/generate-formula.mjs, the single writer of both install paths: platforms with a published single-executable asset pin its immutable release tarball, and every other platform installs the npm package with Homebrew's node. A new formula job in release-binaries.yml regenerates the file after publish — from the release's SHA256SUMS and the npm registry tarball — and opens a PR, replacing the paste-by-hand checksum step. Also fixes the darwin-x64 matrix leg: macos-13 is a retired runner label, so the next tag would have failed that build; macos-15-intel is the supported Intel image. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The darwin matrix legs run on GitHub-hosted macOS runners, which bill at a premium, so the tag-push trigger is removed: binaries are built when a human dispatches the workflow for a validated tag. The npm release in release.yml stays automatic on its Linux runner. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
There was a problem hiding this comment.
Pull request overview
Adds release automation to keep the Homebrew formula in sync with published release artifacts, and shifts binary builds to an explicit manual dispatch to control macOS runner cost.
Changes:
- Introduces
scripts/sea/generate-formula.mjsto regenerateFormula/acpx.rbfrom releaseSHA256SUMSplus the npm tarball checksum. - Updates
release-binaries.ymlto beworkflow_dispatch-only, fixes the retired Intel macOS runner label, and adds aformulajob that opens a PR with the regenerated formula. - Refreshes
Formula/acpx.rbto support per-platform binary installs with npm+Homebrew-node fallback elsewhere.
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 3 comments.
| File | Description |
|---|---|
| scripts/sea/generate-formula.mjs | New generator script that renders the Homebrew formula from release checksums and npm tarball checksum. |
| Formula/acpx.rb | Updated formula content to support binary installs where available and npm fallback where not. |
| .github/workflows/release-binaries.yml | Makes binary builds manual-dispatch only, updates macOS runner label, hardens checksum generation, and adds formula PR automation. |
Comments suppressed due to low confidence (1)
scripts/sea/generate-formula.mjs:82
releaseBaseis hard-coded togithub.com/artagon/acpx, but this repo’s release workflow and metadata expectopenclaw/acpx(e.g..github/workflows/release.ymlvalidatespackage.jsonagainsthttps://github.com/openclaw/acpx). This will generate Homebrew URLs that 404 or point at a different repo than the checksums were downloaded from.
const releaseBase = `https://github.com/artagon/acpx/releases/download/v${version}`;
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Comment on lines
+118
to
+121
| "class Acpx < Formula", | ||
| ' desc "Headless CLI client for the Agent Client Protocol (ACP)"', | ||
| ' homepage "https://github.com/artagon/acpx"', | ||
| "", |
Comment on lines
+39
to
+56
| const version = args.version ?? ""; | ||
| const npmSha = args["npm-sha256"] ?? ""; | ||
| const sumsPath = args.sums ?? ""; | ||
| const outPath = args.out ?? path.join(repoRoot, "Formula", "acpx.rb"); | ||
|
|
||
| if (!/^\d+\.\d+\.\d+$/.test(version)) { | ||
| throw new Error(`--version must be X.Y.Z; received "${version}".`); | ||
| } | ||
| if (!/^[0-9a-f]{64}$/.test(npmSha)) { | ||
| throw new Error(`--npm-sha256 must be 64 hex characters; received "${npmSha}".`); | ||
| } | ||
|
|
||
| // The four slots Homebrew can address with on_macos/on_linux × on_arm/on_intel. | ||
| // A manifest naming any other target fails the run: silently skipping it would | ||
| // publish a formula that pretends the platform does not exist. | ||
| const SLOTS = ["darwin-arm64", "darwin-x64", "linux-arm64", "linux-x64"]; | ||
|
|
||
| const shaByTarget = new Map(); |
Comment on lines
29
to
33
| on_macos do | ||
| on_arm do | ||
| url "https://github.com/artagon/acpx/releases/download/v0.12.0/acpx-0.12.0-darwin-arm64.tar.gz" | ||
| sha256 "823fea276f249b73c9305f0b36299f0af8f8936966208e5b52ef73f6f97e2c58" | ||
| end |
…rmula job's invariants Two findings from the adversarial review of this branch: - The job-list invariant in test/release-workflow.test.ts did not know about the formula job, so the Test job was red on this branch. The test now pins the five-job list and asserts the formula job's trust model: no OIDC, no dependency installs, checksums only from the immutable release manifest. - The npm checksum was trust-on-first-use: whatever bytes the registry served were pinned into the formula. The formula job now runs gh attestation verify against the tarball — the provenance release.yml attests over the exact packed tarball before publish — before recording its sha256. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Adversarial-review finding: the formula job held a contents-write token with a persisted credential while checking out movable main and executing repo scripts — the exact co-residency the rest of this workflow is built to avoid. The job is now split on the same line as build/attest: `formula` renders from the immutable validated tag with read-only permissions and no persisted credential, syntax-checks the result (bot PRs from GITHUB_TOKEN get no CI), and uploads it; `formula-pr` holds the write credential but executes no repository code — it commits only the artifact bytes. The gate now reads package.json from the tagged commit rather than the dispatch-branch checkout, the generator refuses duplicate targets in a manifest, and the invariant tests cover both new jobs. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
scripts/sea/generate-formula.mjsrendersFormula/acpx.rbas the single writer of both install paths: platforms with a published single-executable asset pin the immutable release tarball; every other platform installs the npm package with Homebrew's node (std_npm_args).formulajob inrelease-binaries.ymlregenerates the formula after publish — from the release'sSHA256SUMSand the npm registry tarball — and opens a PR, replacing the paste-by-hand checksum step. Requires the "Allow GitHub Actions to create and approve pull requests" Actions setting.release-binaries.ymlnow triggers onworkflow_dispatchonly: the darwin matrix legs run on premium-billed GitHub-hosted macOS runners, so binaries build when a human dispatches the workflow for a tag. The npm release inrelease.ymlstays automatic on Linux.macos-13is a retired runner label (the next tag build would have failed); nowmacos-15-intel.Validation
actionlintclean on the workflow.brew styleandbrew audit --formulapass on the generated formula (validated in a scratch tap).🤖 Generated with Claude Code