ci: add universal macOS release workflow

This commit is contained in:
reaper
2026-08-14 20:40:26 -05:00
parent d1fa7825fb
commit d3849acdd3
7 changed files with 173 additions and 3 deletions
+95
View File
@@ -0,0 +1,95 @@
name: macOS release
on:
workflow_dispatch:
push:
tags:
- 'v*'
permissions:
contents: read
jobs:
build-macos:
runs-on: macos-14
timeout-minutes: 45
env:
HAS_APPLE_SIGNING: ${{ secrets.MAC_CERTIFICATE_P12 != '' }}
HAS_APPLE_NOTARIZATION: ${{ secrets.APPLE_API_KEY_P8 != '' }}
CSC_LINK: ${{ secrets.MAC_CERTIFICATE_P12 }}
CSC_KEY_PASSWORD: ${{ secrets.MAC_CERTIFICATE_PASSWORD }}
APPLE_API_KEY_ID: ${{ secrets.APPLE_API_KEY_ID }}
APPLE_API_ISSUER: ${{ secrets.APPLE_API_ISSUER }}
steps:
- name: Check out source
uses: actions/checkout@v4
- name: Set up Node.js
uses: actions/setup-node@v4
with:
node-version: 22
cache: npm
- name: Install dependencies
run: npm ci
- name: Generate macOS icon
run: bash scripts/create-mac-icon.sh
- name: Verify source
run: |
npm run typecheck
npm run test:run
npm run build
- name: Prepare Apple API key
if: env.HAS_APPLE_NOTARIZATION == 'true'
env:
APPLE_API_KEY_P8: ${{ secrets.APPLE_API_KEY_P8 }}
run: |
printf '%s' "$APPLE_API_KEY_P8" > "$RUNNER_TEMP/AuthKey.p8"
chmod 600 "$RUNNER_TEMP/AuthKey.p8"
- name: Build unsigned universal DMG and ZIP
if: env.HAS_APPLE_SIGNING != 'true'
run: npx electron-builder --mac dmg zip --universal --publish never
- name: Build signed and notarized universal DMG and ZIP
if: env.HAS_APPLE_SIGNING == 'true' && env.HAS_APPLE_NOTARIZATION == 'true'
env:
APPLE_API_KEY: ${{ runner.temp }}/AuthKey.p8
run: npx electron-builder --mac dmg zip --universal --publish never -c.mac.notarize=true
- name: Reject incomplete signing configuration
if: env.HAS_APPLE_SIGNING == 'true' && env.HAS_APPLE_NOTARIZATION != 'true'
run: |
echo 'A signing certificate was supplied without Apple notarization credentials.' >&2
exit 1
- name: Verify embedded PAC catalog
run: |
test -f dist/module-catalog/wordpress-1.2.0.pac
test -f "dist/mac-universal/Aurora Dockside.app/Contents/Resources/module-catalog/wordpress-1.2.0.pac"
cmp dist/module-catalog/wordpress-1.2.0.pac "dist/mac-universal/Aurora Dockside.app/Contents/Resources/module-catalog/wordpress-1.2.0.pac"
unzip -t "dist/mac-universal/Aurora Dockside.app/Contents/Resources/module-catalog/wordpress-1.2.0.pac"
- name: Create checksums
run: |
find dist -maxdepth 1 -type f \( -name '*.dmg' -o -name '*-mac.zip' -o -name '*.yml' \) -print0 | sort -z | xargs -0 shasum -a 256 > dist/SHA256SUMS-macos.txt
shasum -a 256 dist/module-catalog/*.pac >> dist/SHA256SUMS-macos.txt
cat dist/SHA256SUMS-macos.txt
- name: Upload macOS release bundle
uses: actions/upload-artifact@v4
with:
name: aurora-dockside-macos-universal
if-no-files-found: error
retention-days: 14
path: |
dist/*.dmg
dist/*-mac.zip
dist/*.yml
dist/SHA256SUMS-macos.txt
dist/module-catalog/*.pac
+2 -1
View File
@@ -4,7 +4,8 @@ node_modules/
# Build output
out/
dist/
build/
build/*
!build/entitlements.mac.plist
release/
# Environment / secrets
+12
View File
@@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>com.apple.security.cs.allow-jit</key>
<true/>
<key>com.apple.security.cs.allow-unsigned-executable-memory</key>
<true/>
<key>com.apple.security.cs.disable-library-validation</key>
<true/>
</dict>
</plist>
+2 -1
View File
@@ -14,6 +14,7 @@
- Native `.pac` files are ZIP-compressed Aurora packages with `manifest.json` at archive root.
- A `.pac` placed beside the AppImage or in its `modules` folder is discovered automatically and appears in the Modules screen.
- Packaged applications also carry a generated `.pac` catalog in their application resources. The macOS DMG layout exposes the same catalog as an **Aurora Modules** folder while the copied `.app` retains its own embedded catalog after the DMG is ejected.
- The `macOS release` GitHub Actions workflow builds universal DMG and ZIP artifacts, verifies the embedded catalog, emits checksums, and optionally signs/notarizes when Apple credentials are configured.
- Linux packages use Aurora's 512×512 application icon and a synchronized `aurora-dockside` desktop filename, executable name, icon name, and `StartupWMClass`.
- `.pac` inspection rejects encrypted entries, symbolic links, path traversal, absolute/drive paths, excessive entry counts, and expanded archives larger than 256 MiB before extraction.
- Installation uses staging plus rollback-safe replacement, so a failed update preserves the currently installed module.
@@ -87,4 +88,4 @@ d2165af4b75ab888c6d35a750a449205123866231ba5e98e1cbe9bcaa8738f46 aurora-module-
- Clean-registry install/remove behavior was exercised through the real registry implementation in automated temporary-directory tests. The live GUI smoke used the already installed local WordPress package and project `24`.
- AppImage systems without working FUSE can use `--appimage-extract` and launch `squashfs-root/AppRun --no-sandbox`.
- The embedded catalog and DMG layout are configured and the identical Linux application-resource layout was verified. A final signed/notarized `.app` and DMG must be built and inspected on macOS or a macOS CI runner.
- The embedded catalog and DMG layout are configured and the identical Linux application-resource layout was verified. The macOS CI workflow must still complete once to validate the final Apple-generated DMG and `.app` artifacts.
+41
View File
@@ -0,0 +1,41 @@
# macOS release build
The `macOS release` GitHub Actions workflow builds a universal Intel and Apple Silicon release containing:
- `Aurora Dockside.app`
- DMG installer
- ZIP updater artifact
- Embedded WordPress `.pac` catalog
- Separate WordPress `.pac`
- SHA-256 checksum manifest
Run it manually from **Actions → macOS release → Run workflow**, or push a version tag such as `v2.0.0-alpha.24`.
## Unsigned test build
No secrets are required. The workflow produces an unsigned DMG suitable for internal verification. macOS Gatekeeper will warn users because it is not signed or notarized.
## Signed and notarized release
Configure these GitHub Actions repository secrets:
| Secret | Purpose |
| --- | --- |
| `MAC_CERTIFICATE_P12` | Base64-encoded Developer ID Application `.p12` certificate |
| `MAC_CERTIFICATE_PASSWORD` | Password protecting the `.p12` certificate |
| `APPLE_API_KEY_P8` | App Store Connect API private key contents |
| `APPLE_API_KEY_ID` | App Store Connect API key ID |
| `APPLE_API_ISSUER` | App Store Connect API issuer ID |
The workflow refuses a partially configured release where a signing certificate is present but notarization credentials are missing.
## DMG contents
The mounted DMG contains the application, an Applications shortcut, and an **Aurora Modules** folder. The application also retains the module catalog internally at:
```text
Aurora Dockside.app/Contents/Resources/module-catalog/
└── wordpress-1.2.0.pac
```
The workflow verifies that the internal `.pac` is byte-for-byte identical to the separately uploaded package before publishing its artifacts.
+4 -1
View File
@@ -25,10 +25,13 @@ nsis:
uninstallDisplayName: ${productName}
createDesktopShortcut: always
mac:
category: public.app-category.developer-tools
icon: build/icon.icns
entitlements: build/entitlements.mac.plist
entitlementsInherit: build/entitlements.mac.plist
notarize: false
dmg:
artifactName: ${name}-${version}.${ext}
artifactName: ${name}-${version}-${arch}.${ext}
contents:
- x: 130
y: 220
+17
View File
@@ -0,0 +1,17 @@
#!/usr/bin/env bash
set -euo pipefail
project_root="$(cd "$(dirname "$0")/.." && pwd)"
source_icon="$project_root/resources/icon.png"
iconset="$project_root/build/icon.iconset"
output="$project_root/build/icon.icns"
mkdir -p "$iconset"
for size in 16 32 128 256 512; do
sips -z "$size" "$size" "$source_icon" --out "$iconset/icon_${size}x${size}.png" >/dev/null
retina=$((size * 2))
sips -z "$retina" "$retina" "$source_icon" --out "$iconset/icon_${size}x${size}@2x.png" >/dev/null
done
iconutil -c icns "$iconset" -o "$output"
echo "Created $output"