Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 9 additions & 7 deletions .github/workflows/release-menubar.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@ name: Release macOS Menubar

# Triggers on a `mac-v*` tag push (e.g. `git tag mac-v0.8.0 && git push origin mac-v0.8.0`),
# or manually via the Actions tab. Builds a universal arm64+x86_64 bundle, ad-hoc signs it,
# zips via `ditto`, and uploads the zip to the GitHub Release. `npx codeburn menubar` clears
# the download quarantine flag on install so Gatekeeper stays quiet.
# zips via `ditto`, and uploads the zip to the GitHub Release. The installer verifies
# the checksum and bundle identity before replacing the local app.
on:
push:
tags:
Expand Down Expand Up @@ -60,13 +60,15 @@ jobs:
Install with:

```
npx codeburn menubar
npm install -g codeburn
codeburn menubar
```

That command drops the app into `~/Applications`, clears the download
quarantine, and launches it. If you download the zip from this page directly
and macOS shows "cannot verify developer", right-click the app in Finder and
pick Open to whitelist it once.
That command drops the app into `~/Applications`, records the persistent
`codeburn` CLI path used by the menubar, verifies the downloaded checksum,
clears quarantine after bundle verification, and launches it. If you download
the zip from this page directly and macOS shows "cannot verify developer",
right-click the app in Finder and pick Open to whitelist it once.
files: |
mac/.build/dist/CodeBurnMenubar-${{ steps.version.outputs.value }}.zip
mac/.build/dist/CodeBurnMenubar-${{ steps.version.outputs.value }}.zip.sha256
Expand Down
24 changes: 12 additions & 12 deletions RELEASING.md
Original file line number Diff line number Diff line change
Expand Up @@ -120,25 +120,25 @@ git push origin mac-v0.9.8
The `.github/workflows/release-menubar.yml` workflow automatically detects the `mac-v*` tag and:

1. Checks out the repo
2. Runs `mac/Scripts/package-app.sh 0.9.8`
2. Runs `mac/Scripts/package-app.sh v0.9.8`
3. Signs the app bundle (ad-hoc signing)
4. Creates a zip file: `CodeBurnMenubar-0.9.8.zip`
5. Computes a SHA-256 checksum: `CodeBurnMenubar-0.9.8.zip.sha256`
4. Creates a zip file: `CodeBurnMenubar-v0.9.8.zip`
5. Computes a SHA-256 checksum: `CodeBurnMenubar-v0.9.8.zip.sha256`
6. Uploads both to a GitHub Release named "Menubar v0.9.8"

The script output on the build machine shows:

```
✓ Built /path/mac/.build/dist/CodeBurnMenubar-0.9.8.zip
✓ Checksum /path/mac/.build/dist/CodeBurnMenubar-0.9.8.zip.sha256
<sha256-hash> CodeBurnMenubar-0.9.8.zip
✓ Built /path/mac/.build/dist/CodeBurnMenubar-v0.9.8.zip
✓ Checksum /path/mac/.build/dist/CodeBurnMenubar-v0.9.8.zip.sha256
<sha256-hash> CodeBurnMenubar-v0.9.8.zip
```

No manual action is needed; the workflow handles everything.

### 4. Verify the Release

After the workflow completes, the GitHub Release page shows the zip and sha256 files. The menubar installer command in the CLI calls `npx codeburn menubar`, which fetches the latest release from GitHub and installs it into `~/Applications`.
After the workflow completes, the GitHub Release page shows the zip and sha256 files. The installed CLI command `codeburn menubar --force` fetches the newest `mac-v*` menubar release that includes both assets, verifies the checksum and bundle identity, and installs it into `~/Applications`.

## Homebrew Tap Update

Expand Down Expand Up @@ -227,12 +227,12 @@ If a release is published with broken assets (e.g., a menubar zip with a build e
Use `gh release upload` with the `--clobber` flag to overwrite existing files:

```bash
# After re-running mac/Scripts/package-app.sh 0.9.8 to regenerate the zip and sha256
gh release upload mac-v0.9.8 mac/.build/dist/CodeBurnMenubar-0.9.8.zip --clobber
gh release upload mac-v0.9.8 mac/.build/dist/CodeBurnMenubar-0.9.8.zip.sha256 --clobber
# After re-running mac/Scripts/package-app.sh v0.9.8 to regenerate the zip and sha256
gh release upload mac-v0.9.8 mac/.build/dist/CodeBurnMenubar-v0.9.8.zip --clobber
gh release upload mac-v0.9.8 mac/.build/dist/CodeBurnMenubar-v0.9.8.zip.sha256 --clobber
```

The GitHub Release page will now serve the fixed assets. The menubar installer fetches from the Release by tag, so users who run `npx codeburn menubar` after the replacement get the fixed version automatically.
The GitHub Release page will now serve the fixed assets. The menubar installer selects the newest `mac-v*` release with `CodeBurnMenubar-v*.zip` plus its checksum, so users who run `codeburn menubar --force` after the replacement get the fixed version automatically.

## Rollback

Expand All @@ -245,7 +245,7 @@ git push origin --delete v0.9.8

npm does not allow republishing to the same version. If you must unpublish from npm, use `npm unpublish [email protected] --force` (requires Owner role), but this is discouraged and all users who installed that version retain it.

For the menubar, tag a new mac-v0.9.9 and let the workflow build and upload it. Users will see the update pill in the menubar settings and upgrade automatically (or manually via `npx codeburn menubar --force`).
For the menubar, tag a new mac-v0.9.9 and let the workflow build and upload it. Users will see the update pill in the menubar settings and upgrade automatically (or manually via `codeburn menubar --force`).

## Summary

Expand Down
12 changes: 5 additions & 7 deletions mac/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,19 +6,17 @@ Native Swift + SwiftUI menubar app. The codeburn menubar surface.

- macOS 14+ (Sonoma)
- Swift 6.0+ toolchain (bundled with Xcode 16 or standalone)
- `codeburn` CLI installed globally (`npm install -g codeburn`) or available at a path you pass via `CODEBURN_BIN`
- `codeburn` CLI installed globally (`npm install -g codeburn`)

## Install (end users)

One command:

```bash
npx codeburn menubar
codeburn menubar
```

That's it. The command downloads the latest `.app` from GitHub Releases, drops it into `~/Applications`, clears Gatekeeper quarantine, and launches it. Re-running it upgrades in place with `--force`, or just launches the existing copy otherwise.

If you already have the CLI installed globally (`npm install -g codeburn`), `codeburn menubar` works the same way.
That's it. The command records the persistent `codeburn` CLI path, downloads the latest `.app` from the newest `mac-v*` GitHub Release with a matching checksum, verifies it, drops it into `~/Applications`, clears Gatekeeper quarantine, and launches it. Re-running it upgrades in place with `--force`, or just launches the existing copy otherwise.

### Build from source

Expand All @@ -39,7 +37,7 @@ cd mac
swift build
# Point the app at your dev CLI build instead of the globally installed `codeburn`:
npm --prefix .. run build
CODEBURN_BIN="node $(pwd)/../dist/cli.js" swift run
CODEBURN_ALLOW_DEV_BIN=1 CODEBURN_BIN="node $(pwd)/../dist/cli.js" swift run
```

The app registers itself as a menubar accessory (`LSUIElement = true` at runtime). No Dock icon.
Expand All @@ -48,7 +46,7 @@ The app registers itself as a menubar accessory (`LSUIElement = true` at runtime

On launch and every 60 seconds thereafter, the app spawns `codeburn status --format menubar-json --no-optimize` directly (argv, no shell) via `CodeburnCLI.makeProcess` and decodes the JSON into `MenubarPayload`. The manual refresh button in the footer invokes the same command without `--no-optimize`, which includes optimize findings but takes longer.

Override the binary via the `CODEBURN_BIN` environment variable (default: `codeburn` on PATH). The value is validated against a strict allowlist (alphanumerics plus `._/-` space) before use, so a malicious env var can't inject shell commands.
Release installs record a persistent absolute CLI path in `~/Library/Application Support/CodeBurn/codeburn-cli-path.v1`, then fall back to Homebrew's common `codeburn` locations. For development only, set `CODEBURN_ALLOW_DEV_BIN=1` with `CODEBURN_BIN`; the value is validated against a strict allowlist before use, so a malicious env var can't inject shell commands.

## Project layout

Expand Down
11 changes: 5 additions & 6 deletions mac/Scripts/package-app.sh
Original file line number Diff line number Diff line change
Expand Up @@ -87,13 +87,12 @@ cat > "${BUNDLE}/Contents/PkgInfo" <<'PKG'
APPL????
PKG

# Ad-hoc sign so macOS treats the bundle as internally consistent. This satisfies the
# minimum bundle-validity checks on macOS 14+ and prevents a class of Gatekeeper edge
# cases on managed Macs. A Developer ID signature (separate setup) would additionally
# surface the publisher name in Finder; not required here.
# Ad-hoc sign so macOS treats the bundle as internally consistent. Release
# notarization can layer a Developer ID signature on top, but this local step
# must still fail closed if signing or verification breaks.
echo "▸ Ad-hoc signing..."
codesign --force --sign - --timestamp=none --deep "${BUNDLE}" 2>/dev/null || true
codesign --verify --deep --strict "${BUNDLE}" 2>/dev/null || echo " (signature verify skipped)"
codesign --force --sign - --timestamp=none --deep "${BUNDLE}"
codesign --verify --deep --strict "${BUNDLE}"

ZIP_NAME="CodeBurnMenubar-${ASSET_VERSION}.zip"
ZIP_PATH="${DIST_DIR}/${ZIP_NAME}"
Expand Down
Loading
Loading