Adds a publish-homebrew job to the release workflow that renders Formula/safe-chain.rb from a template (substituting the released version + per-platform SHA256s parsed from the install script asset) and pushes it to AikidoSec/homebrew-tap on every non-prerelease. Users can then install via: brew install AikidoSec/tap/safe-chain safe-chain setup The formula downloads the existing prebuilt single-file binaries from the GitHub release (the same ones the install script uses), so there is no extra build work in this pipeline. One-time maintainer setup (creating the AikidoSec/homebrew-tap repo and adding HOMEBREW_TAP_TOKEN as a secret on safe-chain) is documented in docs/homebrew.md. Tested locally on macOS arm64 with Homebrew 5.1.11: - brew style: 0 offenses - brew install --build-from-source: success - brew test: 2 assertions pass (--version + help) - brew audit --new: 0 offenses This PR addresses item 1 of #372 (Homebrew only). The integrity-check piece in item 2 has already shipped — install-safe-chain.sh already calls verify_checksum() against the baked-in SHA256s. winget and Chocolatey are not in scope here; see docs/homebrew.md for notes on why they belong in separate PRs.
6.7 KiB
Homebrew Tap
End-user install instructions live in the top-level README.md. This page is for maintainers: how the tap is wired up and what one-time setup is required.
Architecture
AikidoSec/safe-chain AikidoSec/homebrew-tap
┌──────────────────────────┐ ┌──────────────────────────┐
│ tag push (vX.Y.Z) │ │ Formula/ │
│ → create-binaries │ │ safe-chain.rb │
│ → publish-binaries │ │ ^ │
│ (draft release + │ │ │ │
│ install-*.sh with │ │ │ │
│ baked SHA256s) │ │ │ git push │
│ │ │ │ on each release │
│ release.published │ ────────► │ │ │
│ → publish-homebrew │ │ │
│ → publish-npm │ │ │
└──────────────────────────┘ └──────────────────────────┘
The publish-homebrew job in .github/workflows/build-and-release.yml fires on release.published (i.e. when a maintainer publishes the draft release that publish-binaries created on the tag push). It:
- Downloads the release's
install-safe-chain.shasset (already has per-platform SHA256s baked in by the earlierpublish-binariesstep — see lines 76–86 of the workflow). - Parses the four SHA256s it needs (macOS x64/arm64, Linux x64/arm64) out of the install script.
- Renders
Formula/safe-chain.rbfrom a quoted heredoc template, substituting the new version and SHAs. - Pushes the rendered formula to the
mainbranch ofAikidoSec/homebrew-tap.
Prereleases are skipped (if: ... && !github.event.release.prerelease) so beta tags like 0.0.1-sha256-in-installer-beta don't update the stable tap.
One-time setup
This needs to happen exactly once. Until it's done, the publish-homebrew job will fail on the next release with a 404 on the tap-repo checkout (which is harmless — it doesn't block npm publish — but the job will appear red).
1. Create the tap repository
Create a new public repository under the AikidoSec organisation called homebrew-tap (the homebrew- prefix is required by brew tap; users will run brew tap AikidoSec/tap which expands to AikidoSec/homebrew-tap).
Owner: AikidoSec
Repository: homebrew-tap
Visibility: Public
Initialize: Yes (add a README — anything will do, the workflow only touches Formula/safe-chain.rb)
Default branch: main
No further repo configuration is required. The Formula/ directory will be created by the workflow on the first publish.
2. Create the token used by the workflow
The workflow needs to push to AikidoSec/homebrew-tap from AikidoSec/safe-chain. The default GITHUB_TOKEN is scoped to the safe-chain repo only and cannot push cross-repo, so we need a token that grants write access to the tap repo.
Recommended: a fine-grained personal access token from a maintenance bot account (or a deploy-token-style PAT), scoped to AikidoSec/homebrew-tap only.
- Resource owner:
AikidoSec - Repository access: Only select repositories →
AikidoSec/homebrew-tap - Repository permissions: Contents: Read and write
- Expiration: 1 year (set a calendar reminder; expired tokens silently break releases)
Alternative: a GitHub App installation with contents:write on the tap repo and a step that exchanges the App's private key for an installation token. More secure for an org-owned automation but more setup. The PAT path is fine for a low-blast-radius tap.
3. Add the token as a secret on AikidoSec/safe-chain
Settings → Secrets and variables → Actions → New repository secret:
- Name:
HOMEBREW_TAP_TOKEN - Value: the PAT (or App installation token) from step 2
That's it. The next release published from main will populate Formula/safe-chain.rb in the tap.
4. (Optional) Bootstrap with the current release
If you want users to be able to brew install AikidoSec/tap/safe-chain immediately rather than waiting for the next release, manually trigger the workflow against the current tag:
gh workflow run "Create Release" --repo AikidoSec/safe-chain --ref <current-tag>
Or simply cut a patch release; the next normal release will populate the tap.
How users install
brew install AikidoSec/tap/safe-chain
safe-chain setup
brew install downloads the prebuilt platform-specific binary from the GitHub release (verified against the SHA256 in the formula) and places it on PATH as safe-chain. The user then runs safe-chain setup (or safe-chain setup-ci) to install the shell aliases that wrap npm, yarn, pnpm, pip, etc. This second step is the same as the one in the curl | sh install path; Homebrew doesn't (and shouldn't) modify user shell rc files at install time.
How users upgrade
brew upgrade safe-chain
The formula's livecheck block uses GitHub's releases/latest strategy, so brew outdated and Homebrew's auto-bump tooling pick up new versions automatically once the tap repo has been updated by the release workflow.
Testing the formula locally
brew tap AikidoSec/tap
brew install --build-from-source AikidoSec/tap/safe-chain
brew test AikidoSec/tap/safe-chain
brew style $(brew --repository)/Library/Taps/aikidosec/homebrew-tap/Formula/safe-chain.rb
brew audit --new --formula AikidoSec/tap/safe-chain
The PR that wired this up (#TBD) validated all four of these against the 1.5.3 release on macOS arm64 (Homebrew 5.1.11).
Future work
- Submission to
homebrew-core: A custom tap is the lowest-friction path. If we ever wantbrew install safe-chain(no tap prefix) to work, the formula needs to be submitted to Homebrew's centralhomebrew-corerepo. That requires the project to meet Homebrew's notability criteria and the formula to build from source (no prebuilt binaries) — which would mean either compiling the Node + pkg bundling in-formula or rewriting the wrapper in a compiled language. Not in scope right now. - winget and Chocolatey: Also requested in #372. Each has its own manifest format and release-time automation; they should be separate PRs.