ci: add universal macOS release workflow
This commit is contained in:
@@ -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
@@ -4,7 +4,8 @@ node_modules/
|
|||||||
# Build output
|
# Build output
|
||||||
out/
|
out/
|
||||||
dist/
|
dist/
|
||||||
build/
|
build/*
|
||||||
|
!build/entitlements.mac.plist
|
||||||
release/
|
release/
|
||||||
|
|
||||||
# Environment / secrets
|
# Environment / secrets
|
||||||
|
|||||||
@@ -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>
|
||||||
@@ -14,6 +14,7 @@
|
|||||||
- Native `.pac` files are ZIP-compressed Aurora packages with `manifest.json` at archive root.
|
- 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.
|
- 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.
|
- 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`.
|
- 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.
|
- `.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.
|
- 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`.
|
- 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`.
|
- 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.
|
||||||
|
|||||||
@@ -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.
|
||||||
@@ -25,10 +25,13 @@ nsis:
|
|||||||
uninstallDisplayName: ${productName}
|
uninstallDisplayName: ${productName}
|
||||||
createDesktopShortcut: always
|
createDesktopShortcut: always
|
||||||
mac:
|
mac:
|
||||||
|
category: public.app-category.developer-tools
|
||||||
|
icon: build/icon.icns
|
||||||
|
entitlements: build/entitlements.mac.plist
|
||||||
entitlementsInherit: build/entitlements.mac.plist
|
entitlementsInherit: build/entitlements.mac.plist
|
||||||
notarize: false
|
notarize: false
|
||||||
dmg:
|
dmg:
|
||||||
artifactName: ${name}-${version}.${ext}
|
artifactName: ${name}-${version}-${arch}.${ext}
|
||||||
contents:
|
contents:
|
||||||
- x: 130
|
- x: 130
|
||||||
y: 220
|
y: 220
|
||||||
|
|||||||
@@ -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"
|
||||||
|
|
||||||
Reference in New Issue
Block a user