Skip to content

chore: harden install script for preview releases (#18) #27

chore: harden install script for preview releases (#18)

chore: harden install script for preview releases (#18) #27

Workflow file for this run

name: Release
on:
push:
tags:
- "v*.*.*"
branches:
- main
permissions:
contents: write
id-token: write
packages: write
jobs:
build-linux:
name: Build Linux Executables
runs-on: ubuntu-latest
outputs:
version: ${{ steps.version.outputs.VERSION }}
steps:
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Set up Bun
uses: oven-sh/setup-bun@v2
with:
bun-version: latest
- name: Install dependencies
run: bun install
- name: Set version in package.json
id: version
run: |
if [[ "$GITHUB_REF" == refs/tags/v* ]]; then
# For tagged releases, use the tag version
VERSION="${GITHUB_REF#refs/tags/v}"
else
# For main branch, generate prerelease version
CURRENT_VERSION=$(bun -e "console.log(require('./package.json').version)")
COMMIT_SHA=${GITHUB_SHA::7}
VERSION="${CURRENT_VERSION}-preview.${COMMIT_SHA}"
fi
echo "Setting version to: ${VERSION}"
echo "VERSION=${VERSION}" >> $GITHUB_OUTPUT
npm version "${VERSION}" --no-git-tag-version --allow-same-version
- name: Build for Linux x64
run: bun run build:linux-x64
- name: Build for Linux ARM64
run: bun run build:linux-arm64
- name: Upload Linux executables
uses: actions/upload-artifact@v4
with:
name: grove-linux-executables
path: |
grove-linux-x64
grove-linux-arm64
build-macos:
name: Build and Sign macOS Executables
runs-on: macos-latest
needs: build-linux
steps:
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Set up Bun
uses: oven-sh/setup-bun@v2
with:
bun-version: latest
- name: Install dependencies
run: bun install
- name: Set version in package.json
run: npm version "${{ needs.build-linux.outputs.version }}" --no-git-tag-version --allow-same-version
- name: Build for macOS x64
run: bun run build:darwin-x64
- name: Build for macOS ARM64
run: bun run build:darwin-arm64
- name: Import Code Signing Certificate
env:
MACOS_CERT_P12_BASE64: ${{ secrets.MACOS_CERT_P12_BASE64 }}
MACOS_CERT_P12_PASSWORD: ${{ secrets.MACOS_CERT_P12_PASSWORD }}
run: |
# Create a temporary keychain
KEYCHAIN_PATH=$RUNNER_TEMP/signing.keychain-db
KEYCHAIN_PASSWORD=$(openssl rand -base64 32)
# Decode the certificate
echo "$MACOS_CERT_P12_BASE64" | base64 --decode > $RUNNER_TEMP/certificate.p12
# Create and configure keychain
security create-keychain -p "$KEYCHAIN_PASSWORD" $KEYCHAIN_PATH
security set-keychain-settings -lut 21600 $KEYCHAIN_PATH
security unlock-keychain -p "$KEYCHAIN_PASSWORD" $KEYCHAIN_PATH
# Import certificate
security import $RUNNER_TEMP/certificate.p12 -P "$MACOS_CERT_P12_PASSWORD" -A -t cert -f pkcs12 -k $KEYCHAIN_PATH
security set-key-partition-list -S apple-tool:,apple: -s -k "$KEYCHAIN_PASSWORD" $KEYCHAIN_PATH
security list-keychain -d user -s $KEYCHAIN_PATH
# Clean up certificate file
rm $RUNNER_TEMP/certificate.p12
- name: Sign macOS Binaries
run: |
# Find the signing identity
IDENTITY=$(security find-identity -v -p codesigning | grep "Developer ID Application" | head -1 | awk -F'"' '{print $2}')
echo "Signing with identity: $IDENTITY"
# Sign both binaries with JIT entitlements
codesign --force --options runtime --timestamp --entitlements .github/workflows/assets/entitlements.plist --sign "$IDENTITY" grove-darwin-x64
codesign --force --options runtime --timestamp --entitlements .github/workflows/assets/entitlements.plist --sign "$IDENTITY" grove-darwin-arm64
# Verify signatures
codesign --verify --verbose grove-darwin-x64
codesign --verify --verbose grove-darwin-arm64
- name: Notarize macOS Binaries
env:
APPLE_ID_EMAIL: ${{ secrets.APPLE_ID_EMAIL }}
APPLE_APP_SPECIFIC_PASSWORD: ${{ secrets.APPLE_APP_SPECIFIC_PASSWORD }}
run: |
# Create zip files for notarization
zip grove-darwin-x64.zip grove-darwin-x64
zip grove-darwin-arm64.zip grove-darwin-arm64
# Get team ID from signing identity
TEAM_ID=$(security find-identity -v -p codesigning | grep "Developer ID Application" | head -1 | sed -n 's/.*(\([A-Z0-9]*\)).*/\1/p')
# Notarize x64 binary
xcrun notarytool submit grove-darwin-x64.zip \
--apple-id "$APPLE_ID_EMAIL" \
--password "$APPLE_APP_SPECIFIC_PASSWORD" \
--team-id "$TEAM_ID" \
--wait
# Notarize ARM64 binary
xcrun notarytool submit grove-darwin-arm64.zip \
--apple-id "$APPLE_ID_EMAIL" \
--password "$APPLE_APP_SPECIFIC_PASSWORD" \
--team-id "$TEAM_ID" \
--wait
# Clean up zip files
rm grove-darwin-x64.zip grove-darwin-arm64.zip
- name: Upload macOS executables
uses: actions/upload-artifact@v4
with:
name: grove-macos-executables
path: |
grove-darwin-x64
grove-darwin-arm64
prerelease:
name: Prerelease
runs-on: ubuntu-latest
needs: [build-linux, build-macos]
if: github.ref == 'refs/heads/main' && !startsWith(github.ref, 'refs/tags/')
steps:
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Download Linux executables
uses: actions/download-artifact@v4
with:
name: grove-linux-executables
path: ./executables
- name: Download macOS executables
uses: actions/download-artifact@v4
with:
name: grove-macos-executables
path: ./executables
- name: Create GitHub Preview Release
uses: softprops/action-gh-release@v2
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
tag_name: v${{ needs.build-linux.outputs.version }}
name: Preview v${{ needs.build-linux.outputs.version }}
body: |
## Preview Release
This is an automated preview release from the `main` branch.
**Commit:** ${{ github.sha }}
## Installation
```bash
curl -fsSL https://safia.rocks/grove/install.sh | sh -s -- v${{ needs.build-linux.outputs.version }}
```
## Manual Downloads
| Platform | Architecture | Download |
|----------|--------------|----------|
| Linux | x64 | `grove-linux-x64` |
| Linux | ARM64 | `grove-linux-arm64` |
| macOS | x64 | `grove-darwin-x64` (signed & notarized) |
| macOS | ARM64 | `grove-darwin-arm64` (signed & notarized) |
draft: false
prerelease: true
files: |
./executables/grove-linux-x64
./executables/grove-linux-arm64
./executables/grove-darwin-x64
./executables/grove-darwin-arm64
release:
name: Release
runs-on: ubuntu-latest
needs: [build-linux, build-macos]
if: startsWith(github.ref, 'refs/tags/v')
steps:
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Set up Node.js
uses: actions/setup-node@v4
with:
node-version: "20"
cache: "npm"
registry-url: "https://registry.npmjs.org"
- name: Set up Bun
uses: oven-sh/setup-bun@v2
with:
bun-version: latest
- name: Install dependencies
run: bun install
- name: Extract version from tag
id: version
run: echo "VERSION=${GITHUB_REF#refs/tags/v}" >> $GITHUB_OUTPUT
- name: Update package.json version
run: npm version ${{ steps.version.outputs.VERSION }} --no-git-tag-version --allow-same-version
- name: Build
run: bun run build
- name: Publish to npm
run: npm publish --provenance --access public
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
- name: Set up Node.js for GitHub Packages
uses: actions/setup-node@v4
with:
node-version: "20"
registry-url: "https://npm.pkg.github.com"
scope: "@captainsafia"
- name: Publish to GitHub Packages
run: npm publish
env:
NODE_AUTH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Download Linux executables
uses: actions/download-artifact@v4
with:
name: grove-linux-executables
path: ./executables
- name: Download macOS executables
uses: actions/download-artifact@v4
with:
name: grove-macos-executables
path: ./executables
- name: Create GitHub Release
uses: softprops/action-gh-release@v2
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
tag_name: ${{ github.ref_name }}
name: Release ${{ github.ref_name }}
body: |
## Installation
```bash
curl -fsSL https://safia.rocks/grove/install.sh | sh -s -- ${{ github.ref_name }}
```
## Manual Downloads
| Platform | Architecture | Download |
|----------|--------------|----------|
| Linux | x64 | `grove-linux-x64` |
| Linux | ARM64 | `grove-linux-arm64` |
| macOS | x64 | `grove-darwin-x64` (signed & notarized) |
| macOS | ARM64 | `grove-darwin-arm64` (signed & notarized) |
## Changes
See the [commits](https://github.com/captainsafia/grove/compare/v${{ steps.version.outputs.VERSION }}...HEAD) for details.
draft: false
prerelease: false
files: |
./executables/grove-linux-x64
./executables/grove-linux-arm64
./executables/grove-darwin-x64
./executables/grove-darwin-arm64