Skip to content
Merged
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
29 changes: 28 additions & 1 deletion .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,8 @@ jobs:
name: Release
needs: [test, security]
runs-on: ubuntu-latest
timeout-minutes: 15
timeout-minutes: 45
environment: release
env:
GOPRIVATE: github.com/basecamp/basecamp-sdk
steps:
Expand Down Expand Up @@ -238,6 +239,27 @@ jobs:
echo "RELEASE_CHANGELOG=" >> $GITHUB_ENV
fi

- name: Verify macOS signing secrets
if: github.repository == 'basecamp/basecamp-cli'
run: |
missing=()
for var in MACOS_SIGN_P12 MACOS_SIGN_PASSWORD MACOS_NOTARY_KEY MACOS_NOTARY_KEY_ID MACOS_NOTARY_ISSUER_ID; do
if [ -z "${!var}" ]; then
missing+=("$var")
fi
done
if [ ${#missing[@]} -gt 0 ]; then
echo "::error::Missing macOS signing secrets: ${missing[*]}"
exit 1
fi
echo "All macOS signing secrets present"
env:
MACOS_SIGN_P12: ${{ secrets.MACOS_SIGN_P12 }}
MACOS_SIGN_PASSWORD: ${{ secrets.MACOS_SIGN_PASSWORD }}
MACOS_NOTARY_KEY: ${{ secrets.MACOS_NOTARY_KEY }}
MACOS_NOTARY_KEY_ID: ${{ secrets.MACOS_NOTARY_KEY_ID }}
MACOS_NOTARY_ISSUER_ID: ${{ secrets.MACOS_NOTARY_ISSUER_ID }}

- name: Run GoReleaser
uses: goreleaser/goreleaser-action@ec59f474b9834571250b370d4735c50f8e2d1e29 # v7
with:
Expand All @@ -247,6 +269,11 @@ jobs:
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
HOMEBREW_TAP_TOKEN: ${{ steps.sdk-token.outputs.token }}
MACOS_SIGN_P12: ${{ secrets.MACOS_SIGN_P12 }}
MACOS_SIGN_PASSWORD: ${{ secrets.MACOS_SIGN_PASSWORD }}
MACOS_NOTARY_KEY: ${{ secrets.MACOS_NOTARY_KEY }}
MACOS_NOTARY_KEY_ID: ${{ secrets.MACOS_NOTARY_KEY_ID }}
MACOS_NOTARY_ISSUER_ID: ${{ secrets.MACOS_NOTARY_ISSUER_ID }}

- name: Publish to AUR
env:
Expand Down
16 changes: 16 additions & 0 deletions .goreleaser.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,22 @@ signs:
artifacts: checksum
output: true

# Sign and notarize macOS binaries (cross-platform via embedded quill)
notarize:
macos:
- enabled: '{{ and .Env.MACOS_SIGN_P12 .Env.MACOS_SIGN_PASSWORD .Env.MACOS_NOTARY_KEY .Env.MACOS_NOTARY_KEY_ID .Env.MACOS_NOTARY_ISSUER_ID }}'
ids:
- basecamp
sign:
certificate: "{{.Env.MACOS_SIGN_P12}}"
password: "{{.Env.MACOS_SIGN_PASSWORD}}"
notarize:
issuer_id: "{{.Env.MACOS_NOTARY_ISSUER_ID}}"
key_id: "{{.Env.MACOS_NOTARY_KEY_ID}}"
key: "{{.Env.MACOS_NOTARY_KEY}}"
wait: true
timeout: 20m

changelog:
# Use GitHub's auto-generated release notes (categories configured in .github/release.yml)
use: github-native
Expand Down
13 changes: 13 additions & 0 deletions RELEASING.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ make release VERSION=0.2.0 DRY_RUN=1
- Collects PGO profile from benchmarks
- Generates AI changelog from commit history
- Builds binaries for all platforms (darwin, linux, windows, freebsd, openbsd × amd64/arm64)
- Signs and notarizes macOS binaries (Developer ID via GoReleaser/quill)
- Signs checksums with cosign (keyless via Sigstore OIDC)
- Generates SBOM for supply chain transparency
- Updates Homebrew cask in `basecamp/homebrew-tap`
Expand All @@ -42,12 +43,24 @@ Pre-1.0: minor bumps for features, patch bumps for fixes. Prerelease tags

## CI secrets

**Repository secrets** (Settings → Secrets and variables → Actions):

| Secret | Purpose |
|--------|---------|
| `RELEASE_CLIENT_ID` (var) | GitHub App ID for `bcq-release-bot` |
| `RELEASE_APP_PRIVATE_KEY` | GitHub App private key |
| `AUR_KEY` | SSH private key for AUR push (optional) |

**Environment secrets** (`release` environment — Settings → Environments):

| Secret | Purpose |
|--------|---------|
| `MACOS_SIGN_P12` | Base64-encoded Developer ID Application certificate (.p12) |
| `MACOS_SIGN_PASSWORD` | .p12 unlock password |
| `MACOS_NOTARY_KEY` | Base64-encoded App Store Connect API key (.p8) |
| `MACOS_NOTARY_KEY_ID` | App Store Connect API key ID (10 characters) |
| `MACOS_NOTARY_ISSUER_ID` | App Store Connect issuer UUID |

## AUR setup (one-time)

1. Create an account at https://aur.archlinux.org
Expand Down
11 changes: 3 additions & 8 deletions scripts/install.sh
Original file line number Diff line number Diff line change
Expand Up @@ -81,17 +81,12 @@ verify_checksums() {
if command -v cosign &>/dev/null; then
info "Verifying cosign signature..."

if ! curl -fsSL "${base_url}/checksums.txt.sig" -o "${tmp_dir}/checksums.txt.sig"; then
error "Failed to download checksums.txt.sig"
fi

if ! curl -fsSL "${base_url}/checksums.txt.pem" -o "${tmp_dir}/checksums.txt.pem"; then
error "Failed to download checksums.txt.pem"
if ! curl -fsSL "${base_url}/checksums.txt.bundle" -o "${tmp_dir}/checksums.txt.bundle"; then
error "Failed to download checksums.txt.bundle"
fi

cosign verify-blob \
--certificate "${tmp_dir}/checksums.txt.pem" \
--signature "${tmp_dir}/checksums.txt.sig" \
--bundle "${tmp_dir}/checksums.txt.bundle" \
--certificate-identity "https://github.com/basecamp/basecamp-cli/.github/workflows/release.yml@refs/tags/v${version}" \
--certificate-oidc-issuer "https://token.actions.githubusercontent.com" \
"${tmp_dir}/checksums.txt" \
Expand Down
Loading