chore(ci): macOS app code signing

This commit is contained in:
Neko Ayaka 2026-02-26 23:11:59 +08:00
parent 58991a15fa
commit f04e106b13
No known key found for this signature in database
5 changed files with 65 additions and 35 deletions

View file

@ -104,31 +104,6 @@ jobs:
- uses: actions/checkout@v6
# https://docs.github.com/en/actions/how-tos/deploy/deploy-to-third-party-platforms/sign-xcode-applications
# - name: Install the Apple certificate (macOS Only)
# if: matrix.os == 'macos-15-intel' || matrix.os == 'macos-26'
# env:
# BUILD_CERTIFICATE_BASE64: ${{ secrets.BUILD_CERTIFICATE_BASE64 }}
# P12_PASSWORD: ${{ secrets.P12_PASSWORD }}
# KEYCHAIN_PASSWORD: ${{ secrets.KEYCHAIN_PASSWORD }}
# run: |
# # create variables
# CERTIFICATE_PATH=$RUNNER_TEMP/build_certificate.p12
# KEYCHAIN_PATH=$RUNNER_TEMP/app-signing.keychain-db
# # import certificate from secrets
# echo -n "$BUILD_CERTIFICATE_BASE64" | base64 --decode -o $CERTIFICATE_PATH
# # create temporary 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 to keychain
# security import $CERTIFICATE_PATH -P "$P12_PASSWORD" -A -t cert -f pkcs12 -k $KEYCHAIN_PATH
# security set-key-partition-list -S apple-tool:,apple: -k "$KEYCHAIN_PASSWORD" $KEYCHAIN_PATH
# security list-keychain -d user -s $KEYCHAIN_PATH
- name: macOS Select Xcode 26.2
if: matrix.os == 'macos-15-intel' || matrix.os == 'macos-26'
run: |
@ -164,9 +139,17 @@ jobs:
- name: Build (macOS Only) # macOS
if: matrix.os == 'macos-15-intel' || matrix.os == 'macos-26'
run: pnpm run -F @proj-airi/stage-tamagotchi build && pnpm -F @proj-airi/stage-tamagotchi exec electron-builder build ${{ matrix.builder-args }} --publish=${{ (inputs.build_only || inputs.artifacts_only) && 'never' || 'onTagOrDraft' }}
run: |
echo "$CSC_CONTENT" | base64 --decode > apple-developer-code-signing.p12
export CSC_LINK="./apple-developer-code-signing.p12"
pnpm run -F @proj-airi/stage-tamagotchi build && pnpm -F @proj-airi/stage-tamagotchi exec electron-builder build ${{ matrix.builder-args }} --publish=${{ (inputs.build_only || inputs.artifacts_only) && 'never' || 'onTagOrDraft' }}
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
CSC_CONTENT: ${{ secrets.CSC_CONTENT }}
CSC_KEY_PASSWORD: ${{ secrets.CSC_KEY_PASSWORD }}
APPLE_DEVELOPER_TEAM_ID: ${{ secrets.APPLE_DEVELOPER_TEAM_ID }}
APPLE_DEVELOPER_APPLE_ID: ${{ secrets.APPLE_DEVELOPER_APPLE_ID }}
APPLE_DEVELOPER_APPLE_APP_SPECIFIC_PASSWORD: ${{ secrets.APPLE_DEVELOPER_APPLE_APP_SPECIFIC_PASSWORD }}
- name: Build (Linux Only) # Linux
if: matrix.os == 'ubuntu-latest' || matrix.os == 'ubuntu-24.04-arm'
@ -365,11 +348,6 @@ jobs:
apps/stage-tamagotchi/bundle/latest-*.yml
append_body: true
# - name: Clean up keychain and provisioning profile (macOS Only)
# if: ${{ always() && (matrix.os == 'macos-15-intel' || matrix.os == 'macos-26') }}
# run: |
# security delete-keychain $RUNNER_TEMP/app-signing.keychain-db
merge-mac-latest:
name: Merge macOS latest-mac.yml
if: ${{ github.event_name == 'release' }} # Skipping will only exist when triggered by workflow_dispatch. No need to handle here

View file

@ -3,7 +3,9 @@
import type { Configuration } from 'electron-builder'
import { execSync } from 'node:child_process'
import { env } from 'node:process'
import { notarize } from '@electron/notarize'
import { isMacOS } from 'std-env'
function hasXcode26OrAbove() {
@ -42,6 +44,30 @@ export default {
output: 'dist',
buildResources: 'build',
},
// For self-publishing, testing, and distribution after modified the code without access to
// an Apple Developer account, comment and uncomment the following 4 lines.
// Later on when you obtained one, you can set up the necessary certificates and provisioning
// profiles to enable these security features.
//
// https://www.bigbinary.com/blog/code-sign-notorize-mac-desktop-app
// https://kilianvalkhof.com/2019/electron/notarizing-your-electron-application/
afterSign: async (context) => {
const { electronPlatformName, appOutDir } = context
if (electronPlatformName !== 'darwin')
return
if (env.CI !== 'true') {
console.warn('Skipping notarizing step. Packaging is not running in CI')
return
}
const appName = context.packager.appInfo.productFilename
await notarize({
appPath: `${appOutDir}/${appName}.app`,
teamId: env.APPLE_DEVELOPER_TEAM_ID!,
appleId: env.APPLE_DEVELOPER_APPLE_ID!,
appleIdPassword: env.APPLE_DEVELOPER_APPLE_APP_SPECIFIC_PASSWORD!,
})
},
files: [
'out/**',
'resources/**',
@ -91,8 +117,14 @@ export default {
NSCameraUsageDescription: 'AIRI requires camera access for vision understanding',
},
],
// We have customized the notarization step in the `afterSign` hook.
notarize: false,
hardenedRuntime: false,
// For self-publishing, testing, and distribution after modified the code without access to
// an Apple Developer account, comment and uncomment the following 4 lines.
// Later on when you obtained one, you can set up the necessary certificates and provisioning
// profiles to enable these security features.
// hardenedRuntime: false,
hardenedRuntime: true,
executableName: 'airi',
icon: useIconFormattedMacAppIcon ? 'icon.icon' : 'icon.icns',
},

View file

@ -129,6 +129,7 @@
},
"devDependencies": {
"@electron-toolkit/tsconfig": "^2.0.0",
"@electron/notarize": "catalog:",
"@iconify-json/carbon": "^1.2.18",
"@iconify-json/eos-icons": "^1.2.4",
"@iconify-json/lucide": "^1.2.94",

23
pnpm-lock.yaml generated
View file

@ -24,6 +24,9 @@ catalogs:
'@electron-toolkit/preload':
specifier: ^3.0.2
version: 3.0.2
'@electron/notarize':
specifier: ^3.1.1
version: 3.1.1
'@guiiai/logg':
specifier: ^1.2.11
version: 1.2.11
@ -1152,6 +1155,9 @@ importers:
'@electron-toolkit/tsconfig':
specifier: ^2.0.0
version: 2.0.0(@types/node@24.10.14)
'@electron/notarize':
specifier: 'catalog:'
version: 3.1.1
'@iconify-json/carbon':
specifier: ^1.2.18
version: 1.2.18
@ -3087,7 +3093,7 @@ importers:
version: 14.1.0(vue@3.5.29(typescript@5.9.3))
'@wxt-dev/module-vue':
specifier: ^1.0.3
version: 1.0.3(vite@7.3.1(@types/node@24.10.14)(jiti@2.6.1)(less@4.5.1)(lightningcss@1.31.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))(vue@3.5.29(typescript@5.9.3))(wxt@0.20.18(@types/node@24.10.14)(canvas@3.2.1)(eslint@9.39.3(jiti@2.6.1))(jiti@2.6.1)(less@4.5.1)(lightningcss@1.31.1)(rollup@4.59.0)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
version: 1.0.3(vite@8.0.0-beta.15(@types/node@24.10.14)(esbuild@0.27.2)(jiti@2.6.1)(less@4.5.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))(vue@3.5.29(typescript@5.9.3))(wxt@0.20.18(@types/node@24.10.14)(canvas@3.2.1)(eslint@9.39.3(jiti@2.6.1))(jiti@2.6.1)(less@4.5.1)(lightningcss@1.31.1)(rollup@4.59.0)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))
nanoid:
specifier: ^5.1.6
version: 5.1.6
@ -4600,6 +4606,10 @@ packages:
resolution: {integrity: sha512-jNT8nwH1f9X5GEITXaQ8IF/KdskvIkOFfB2CvwumsveVidzpSc+mvhhTMdAGSYF3O+Nq49lJ7y+ssODRXu06+A==}
engines: {node: '>= 10.0.0'}
'@electron/notarize@3.1.1':
resolution: {integrity: sha512-uQQSlOiJnqRkTL1wlEBAxe90nVN/Fc/hEmk0bqpKk8nKjV1if/tXLHKUPePtv9Xsx90PtZU8aidx5lAiOpjkQQ==}
engines: {node: '>= 22.12.0'}
'@electron/osx-sign@1.3.3':
resolution: {integrity: sha512-KZ8mhXvWv2rIEgMbWZ4y33bDHyUKMXnx4M0sTyPNK/vcB81ImdeY9Ggdqy0SWbMDgmbqyQ+phgejh6V3R2QuSg==}
engines: {node: '>=12.0.0'}
@ -18350,6 +18360,13 @@ snapshots:
transitivePeerDependencies:
- supports-color
'@electron/notarize@3.1.1':
dependencies:
debug: 4.4.3
promise-retry: 2.0.1
transitivePeerDependencies:
- supports-color
'@electron/osx-sign@1.3.3':
dependencies:
compare-version: 0.1.2
@ -23233,9 +23250,9 @@ snapshots:
'@types/filesystem': 0.0.36
'@types/har-format': 1.2.16
'@wxt-dev/module-vue@1.0.3(vite@7.3.1(@types/node@24.10.14)(jiti@2.6.1)(less@4.5.1)(lightningcss@1.31.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))(vue@3.5.29(typescript@5.9.3))(wxt@0.20.18(@types/node@24.10.14)(canvas@3.2.1)(eslint@9.39.3(jiti@2.6.1))(jiti@2.6.1)(less@4.5.1)(lightningcss@1.31.1)(rollup@4.59.0)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))':
'@wxt-dev/module-vue@1.0.3(vite@8.0.0-beta.15(@types/node@24.10.14)(esbuild@0.27.2)(jiti@2.6.1)(less@4.5.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))(vue@3.5.29(typescript@5.9.3))(wxt@0.20.18(@types/node@24.10.14)(canvas@3.2.1)(eslint@9.39.3(jiti@2.6.1))(jiti@2.6.1)(less@4.5.1)(lightningcss@1.31.1)(rollup@4.59.0)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))':
dependencies:
'@vitejs/plugin-vue': 6.0.4(vite@7.3.1(@types/node@24.10.14)(jiti@2.6.1)(less@4.5.1)(lightningcss@1.31.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))(vue@3.5.29(typescript@5.9.3))
'@vitejs/plugin-vue': 6.0.4(vite@8.0.0-beta.15(@types/node@24.10.14)(esbuild@0.27.2)(jiti@2.6.1)(less@4.5.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))(vue@3.5.29(typescript@5.9.3))
wxt: 0.20.18(@types/node@24.10.14)(canvas@3.2.1)(eslint@9.39.3(jiti@2.6.1))(jiti@2.6.1)(less@4.5.1)(lightningcss@1.31.1)(rollup@4.59.0)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)
transitivePeerDependencies:
- vite

View file

@ -26,6 +26,7 @@ patchedDependencies:
mineflayer-pathfinder: patches/mineflayer-pathfinder.patch
mineflayer@4.33.0: patches/mineflayer@4.33.0.patch
srvx@0.9.8: patches/srvx@0.9.8.patch
catalog:
'@capacitor/cli': ^8.1.0
'@capacitor/core': ^8.1.0
@ -33,6 +34,7 @@ catalog:
'@capacitor/local-notifications': ^8.0.1
'@electric-sql/pglite': ^0.3.15
'@electron-toolkit/preload': ^3.0.2
'@electron/notarize': ^3.1.1
'@guiiai/logg': ^1.2.11
'@histoire/plugin-vue': 1.0.0-beta.1
'@iconify-json/logos': ^1.2.10