From 52df642d7348d38e942f70c3472418e733674eb0 Mon Sep 17 00:00:00 2001 From: Adarsh Prashar Date: Thu, 18 Jun 2026 01:38:49 +0530 Subject: [PATCH] feat(release): Homebrew formula publishing MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add a release workflow + formula generator that publish the riskkernel formula to a Homebrew tap on each version tag, so 'brew install riskkernel' installs a prebuilt binary and stays current — mirroring the per-artifact publish pattern of the Python (PyPI) and TypeScript (npm) SDKs. - scripts/gen-homebrew-formula.sh renders a binary formula from a release's checksums.txt (per-OS/arch url + sha256 for the GoReleaser darwin/linux amd64/arm64 archives). - .github/workflows/homebrew-publish.yml runs on a version tag (and manual dispatch), downloads the release checksums, renders the formula, and commits it to the tap repo. It is INERT until a HOMEBREW_TAP_TOKEN secret is set: without it the job logs a notice and exits 0, so it never blocks a release. Activating it is a one-time maintainer step (create the homebrew-riskkernel tap repo + add the token) documented in docs/HOMEBREW.md. README points at it; until then the existing go install / docker run / release-binary paths are unchanged. Verified the generator against the real v0.7.0 release: rendered the formula from the published checksums.txt (correct per-platform sha256s) and confirmed valid Ruby syntax (ruby -c). --- .github/workflows/homebrew-publish.yml | 65 +++++++++++++++++++++++++ CHANGELOG.md | 7 +++ README.md | 3 +- docs/HOMEBREW.md | 48 +++++++++++++++++++ scripts/gen-homebrew-formula.sh | 66 ++++++++++++++++++++++++++ 5 files changed, 188 insertions(+), 1 deletion(-) create mode 100644 .github/workflows/homebrew-publish.yml create mode 100644 docs/HOMEBREW.md create mode 100755 scripts/gen-homebrew-formula.sh diff --git a/.github/workflows/homebrew-publish.yml b/.github/workflows/homebrew-publish.yml new file mode 100644 index 0000000..594825b --- /dev/null +++ b/.github/workflows/homebrew-publish.yml @@ -0,0 +1,65 @@ +name: Publish Homebrew formula + +# Pushes the riskkernel formula to the Homebrew tap on each version tag, so +# `brew install riskkernel` works (and stays current with releases). +# +# INERT until set up — needs two things (see docs/HOMEBREW.md): +# 1. a tap repo: prashar32/homebrew-riskkernel +# 2. a repo secret HOMEBREW_TAP_TOKEN: a fine-grained PAT with contents:write +# on that tap repo. +# Without the secret this workflow logs a notice and exits 0 — it never blocks a +# release (the binaries + GitHub release are cut by release.yml regardless). +on: + push: + tags: ["v*"] + workflow_dispatch: + +permissions: + contents: read + +jobs: + publish: + name: Publish formula to the Homebrew tap + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v6 + + - name: Render and push the formula + env: + TAP_TOKEN: ${{ secrets.HOMEBREW_TAP_TOKEN }} + GH_TOKEN: ${{ github.token }} + TAP_REPO: prashar32/homebrew-riskkernel + run: | + set -euo pipefail + if [ -z "${TAP_TOKEN}" ]; then + echo "::notice::HOMEBREW_TAP_TOKEN not set — skipping Homebrew publish. See docs/HOMEBREW.md to enable." + exit 0 + fi + + # The version to publish: the tag that triggered this, or the latest + # release when run manually from a branch. + if [ "${GITHUB_REF_TYPE}" = "tag" ]; then + version="${GITHUB_REF_NAME#v}" + else + version="$(gh release view --repo "${GITHUB_REPOSITORY}" --json tagName -q .tagName | sed 's/^v//')" + fi + echo "Publishing Homebrew formula for v${version}" + + # Pull the release's checksums and render the formula from them. + gh release download "v${version}" --repo "${GITHUB_REPOSITORY}" --pattern checksums.txt --dir /tmp/rk-rel --clobber + formula="$(bash scripts/gen-homebrew-formula.sh "${version}" /tmp/rk-rel/checksums.txt)" + + # Commit it to the tap. + git clone --depth 1 "https://x-access-token:${TAP_TOKEN}@github.com/${TAP_REPO}.git" /tmp/tap + mkdir -p /tmp/tap/Formula + printf '%s\n' "${formula}" > /tmp/tap/Formula/riskkernel.rb + cd /tmp/tap + git config user.name "Adarsh Prashar" + git config user.email "adarsh.prashar32@gmail.com" + git add Formula/riskkernel.rb + if git diff --cached --quiet; then + echo "Formula already up to date for v${version} — nothing to push." + exit 0 + fi + git commit -m "riskkernel ${version}" + git push diff --git a/CHANGELOG.md b/CHANGELOG.md index f34fb98..1bbd7c4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,13 @@ surface is governed by [`COMPATIBILITY.md`](COMPATIBILITY.md). ## [Unreleased] ### Added +- **Homebrew formula publishing.** A release workflow + formula generator publish the + `riskkernel` formula to a Homebrew tap on each version tag, so `brew install + riskkernel` installs a prebuilt binary and stays current with releases — the same + per-artifact publish pattern as the Python and TypeScript SDKs. It's inert until the + tap repo (`homebrew-riskkernel`) and a `HOMEBREW_TAP_TOKEN` secret are configured + (one-time maintainer step) and never blocks a release without them. See + [`docs/HOMEBREW.md`](docs/HOMEBREW.md). - **Native AWS Bedrock provider.** Run Bedrock-hosted models through RiskKernel with full budgets / approvals / audit / OTel — set the standard AWS env vars (`AWS_ACCESS_KEY_ID`, `AWS_SECRET_ACCESS_KEY`, optional `AWS_SESSION_TOKEN`, diff --git a/README.md b/README.md index 11eb356..25b4385 100644 --- a/README.md +++ b/README.md @@ -105,7 +105,8 @@ riskkernel init # scaffold a .env + a runnable example in the current dir riskkernel serve # start the daemon (reads .env) ``` -(or `make build` from a clone). Tab-complete the CLI in your shell: +(or `make build` from a clone, or Homebrew — see [`docs/HOMEBREW.md`](docs/HOMEBREW.md)). +Tab-complete the CLI in your shell: ```bash riskkernel completion bash > /etc/bash_completion.d/riskkernel # bash diff --git a/docs/HOMEBREW.md b/docs/HOMEBREW.md new file mode 100644 index 0000000..6cd2732 --- /dev/null +++ b/docs/HOMEBREW.md @@ -0,0 +1,48 @@ +# Homebrew + +Install RiskKernel as a prebuilt binary on macOS or Linux via Homebrew: + +```bash +brew install prashar32/riskkernel/riskkernel +# or: +brew tap prashar32/riskkernel +brew install riskkernel +``` + +This pulls the signed release binary for your OS/arch (no compile). Upgrade with +`brew upgrade riskkernel`. + +> **Status:** the publishing automation is in the repo, but `brew install` works only +> once the tap repo and token are set up (one-time maintainer step, below). Until +> then, install via `go install`, `docker run`, or the release binaries — see the +> [README quickstart](../README.md#quickstart-60-seconds). + +## How it works + +On every version tag, the [`Publish Homebrew formula`](../.github/workflows/homebrew-publish.yml) +workflow downloads the release's `checksums.txt`, renders the formula with +[`scripts/gen-homebrew-formula.sh`](../scripts/gen-homebrew-formula.sh) (a binary +formula with a per-OS/arch `url` + `sha256` taken from the GoReleaser archives), and +commits it to the tap repo as `Formula/riskkernel.rb`. It mirrors how the Python and +TypeScript SDKs publish on a tag. + +## Maintainer setup (one-time, to activate) + +The workflow is **inert until two things exist** — without them it logs a notice and +exits 0, so it never blocks a release: + +1. **Create the tap repo.** A *public* repo named **`homebrew-riskkernel`** under the + same owner (`prashar32`). Homebrew requires the `homebrew-` name prefix; it maps to + the tap `prashar32/riskkernel`. It can start empty — the workflow writes + `Formula/riskkernel.rb`. +2. **Add the token secret.** On the `prashar32/riskkernel` repo, add an Actions secret + **`HOMEBREW_TAP_TOKEN`**: a fine-grained personal access token scoped to the + `homebrew-riskkernel` repo with **Contents: read and write**. + +Then publish the current release: re-run the **Publish Homebrew formula** workflow +(Actions → *Run workflow*), or just cut the next release — it runs automatically on +each `v*` tag. + +> On the eventual org transfer (`prashar32` → a `riskkernel` org), move the tap repo +> and re-point the `TAP_REPO` in the workflow, the same way the PyPI/npm trusted +> publishers move. diff --git a/scripts/gen-homebrew-formula.sh b/scripts/gen-homebrew-formula.sh new file mode 100755 index 0000000..c89c494 --- /dev/null +++ b/scripts/gen-homebrew-formula.sh @@ -0,0 +1,66 @@ +#!/usr/bin/env bash +# Generates the Homebrew formula for riskkernel from a release's checksums.txt. +# Kept as a standalone script so it can be run/verified locally, not just in CI. +# +# Usage: scripts/gen-homebrew-formula.sh +# Prints the formula (Formula/riskkernel.rb) to stdout. +set -euo pipefail + +version="${1:?usage: gen-homebrew-formula.sh }" +checksums="${2:?usage: gen-homebrew-formula.sh }" +base="https://github.com/prashar32/riskkernel/releases/download/v${version}" + +# sha256 of a named release asset, from goreleaser's " " checksums.txt. +sha() { + local got + got="$(awk -v f="$1" '$2 == f {print $1}' "$checksums")" + if [ -z "$got" ]; then + echo "gen-homebrew-formula: no checksum for $1 in $checksums" >&2 + exit 1 + fi + printf '%s' "$got" +} + +darwin_arm="$(sha "riskkernel_${version}_darwin_arm64.tar.gz")" +darwin_amd="$(sha "riskkernel_${version}_darwin_amd64.tar.gz")" +linux_arm="$(sha "riskkernel_${version}_linux_arm64.tar.gz")" +linux_amd="$(sha "riskkernel_${version}_linux_amd64.tar.gz")" + +cat <