From ec84eea9242d2d423a7d8c81e2523872cd08ad54 Mon Sep 17 00:00:00 2001 From: 4gray Date: Fri, 13 Mar 2026 07:36:09 +0100 Subject: [PATCH] feat(macOS): add notarization support and entitlements for Electron app --- .github/workflows/build-and-make.yaml | 77 +++++++++++++++++++ .../macos/entitlements.mac.inherit.plist | 12 +++ .../macos/entitlements.mac.plist | 12 +++ electron-builder.json | 8 +- 4 files changed, 105 insertions(+), 4 deletions(-) create mode 100644 apps/electron-backend/macos/entitlements.mac.inherit.plist create mode 100644 apps/electron-backend/macos/entitlements.mac.plist diff --git a/.github/workflows/build-and-make.yaml b/.github/workflows/build-and-make.yaml index edf886084..7dfabbafb 100644 --- a/.github/workflows/build-and-make.yaml +++ b/.github/workflows/build-and-make.yaml @@ -79,7 +79,84 @@ jobs: fs.writeFileSync('electron-builder.json', JSON.stringify(pkg, null, 4)); " + - name: Validate macOS signing configuration + if: matrix.os == 'macos' && github.event_name != 'pull_request' + shell: bash + env: + CSC_LINK: ${{ secrets.CSC_LINK }} + CSC_KEY_PASSWORD: ${{ secrets.CSC_KEY_PASSWORD }} + APPLE_API_KEY_CONTENT: ${{ secrets.APPLE_API_KEY }} + APPLE_API_KEY_ID: ${{ secrets.APPLE_API_KEY_ID }} + APPLE_API_ISSUER: ${{ secrets.APPLE_API_ISSUER }} + APPLE_ID: ${{ secrets.APPLE_ID }} + APPLE_APP_SPECIFIC_PASSWORD: ${{ secrets.APPLE_APP_SPECIFIC_PASSWORD }} + APPLE_TEAM_ID: ${{ secrets.APPLE_TEAM_ID }} + run: | + if [ -z "${CSC_LINK}" ] || [ -z "${CSC_KEY_PASSWORD}" ]; then + echo "::error::Missing CSC_LINK or CSC_KEY_PASSWORD secret for macOS code signing." + exit 1 + fi + + has_api_key_credentials=false + if [ -n "${APPLE_API_KEY_CONTENT}" ] || [ -n "${APPLE_API_KEY_ID}" ] || [ -n "${APPLE_API_ISSUER}" ]; then + if [ -z "${APPLE_API_KEY_CONTENT}" ] || [ -z "${APPLE_API_KEY_ID}" ] || [ -z "${APPLE_API_ISSUER}" ]; then + echo "::error::APPLE_API_KEY, APPLE_API_KEY_ID, and APPLE_API_ISSUER must all be set for App Store Connect API key notarization." + exit 1 + fi + has_api_key_credentials=true + fi + + has_apple_id_credentials=false + if [ -n "${APPLE_ID}" ] || [ -n "${APPLE_APP_SPECIFIC_PASSWORD}" ] || [ -n "${APPLE_TEAM_ID}" ]; then + if [ -z "${APPLE_ID}" ] || [ -z "${APPLE_APP_SPECIFIC_PASSWORD}" ] || [ -z "${APPLE_TEAM_ID}" ]; then + echo "::error::APPLE_ID, APPLE_APP_SPECIFIC_PASSWORD, and APPLE_TEAM_ID must all be set for Apple ID notarization." + exit 1 + fi + has_apple_id_credentials=true + fi + + if [ "${has_api_key_credentials}" = false ] && [ "${has_apple_id_credentials}" = false ]; then + echo "::error::Missing notarization credentials. Configure either APPLE_API_KEY + APPLE_API_KEY_ID + APPLE_API_ISSUER, or APPLE_ID + APPLE_APP_SPECIFIC_PASSWORD + APPLE_TEAM_ID." + exit 1 + fi + + - name: Prepare macOS notarization credentials + if: matrix.os == 'macos' + shell: bash + env: + APPLE_API_KEY_CONTENT: ${{ secrets.APPLE_API_KEY }} + APPLE_API_KEY_ID: ${{ secrets.APPLE_API_KEY_ID }} + APPLE_API_ISSUER: ${{ secrets.APPLE_API_ISSUER }} + APPLE_ID: ${{ secrets.APPLE_ID }} + APPLE_APP_SPECIFIC_PASSWORD: ${{ secrets.APPLE_APP_SPECIFIC_PASSWORD }} + APPLE_TEAM_ID: ${{ secrets.APPLE_TEAM_ID }} + run: | + if [ -n "${APPLE_API_KEY_CONTENT}" ]; then + APPLE_API_KEY_PATH="${RUNNER_TEMP}/AuthKey_${APPLE_API_KEY_ID}.p8" + printf '%s' "${APPLE_API_KEY_CONTENT}" > "${APPLE_API_KEY_PATH}" + chmod 600 "${APPLE_API_KEY_PATH}" + echo "APPLE_API_KEY=${APPLE_API_KEY_PATH}" >> "${GITHUB_ENV}" + echo "APPLE_API_KEY_ID=${APPLE_API_KEY_ID}" >> "${GITHUB_ENV}" + echo "APPLE_API_ISSUER=${APPLE_API_ISSUER}" >> "${GITHUB_ENV}" + echo "APPLE_ID=" >> "${GITHUB_ENV}" + echo "APPLE_APP_SPECIFIC_PASSWORD=" >> "${GITHUB_ENV}" + echo "APPLE_TEAM_ID=" >> "${GITHUB_ENV}" + exit 0 + fi + + if [ -n "${APPLE_ID}" ]; then + echo "APPLE_API_KEY=" >> "${GITHUB_ENV}" + echo "APPLE_API_KEY_ID=" >> "${GITHUB_ENV}" + echo "APPLE_API_ISSUER=" >> "${GITHUB_ENV}" + echo "APPLE_ID=${APPLE_ID}" >> "${GITHUB_ENV}" + echo "APPLE_APP_SPECIFIC_PASSWORD=${APPLE_APP_SPECIFIC_PASSWORD}" >> "${GITHUB_ENV}" + echo "APPLE_TEAM_ID=${APPLE_TEAM_ID}" >> "${GITHUB_ENV}" + fi + - name: Make Electron app + env: + CSC_LINK: ${{ secrets.CSC_LINK }} + CSC_KEY_PASSWORD: ${{ secrets.CSC_KEY_PASSWORD }} run: pnpm run make:app - name: Upload artifacts (macOS) diff --git a/apps/electron-backend/macos/entitlements.mac.inherit.plist b/apps/electron-backend/macos/entitlements.mac.inherit.plist new file mode 100644 index 000000000..9a279dc83 --- /dev/null +++ b/apps/electron-backend/macos/entitlements.mac.inherit.plist @@ -0,0 +1,12 @@ + + + + + com.apple.security.cs.allow-jit + + com.apple.security.cs.allow-unsigned-executable-memory + + com.apple.security.cs.disable-library-validation + + + diff --git a/apps/electron-backend/macos/entitlements.mac.plist b/apps/electron-backend/macos/entitlements.mac.plist new file mode 100644 index 000000000..9a279dc83 --- /dev/null +++ b/apps/electron-backend/macos/entitlements.mac.plist @@ -0,0 +1,12 @@ + + + + + com.apple.security.cs.allow-jit + + com.apple.security.cs.allow-unsigned-executable-memory + + com.apple.security.cs.disable-library-validation + + + diff --git a/electron-builder.json b/electron-builder.json index 042837763..9bc4353d5 100644 --- a/electron-builder.json +++ b/electron-builder.json @@ -31,11 +31,11 @@ "arch": ["x64", "arm64"] }, "category": "public.app-category.video", - "identity": null, "gatekeeperAssess": false, - "hardenedRuntime": false, - "entitlements": null, - "entitlementsInherit": null, + "hardenedRuntime": true, + "entitlements": "apps/electron-backend/macos/entitlements.mac.plist", + "entitlementsInherit": "apps/electron-backend/macos/entitlements.mac.inherit.plist", + "notarize": true, "icon": "apps/web/src/assets/icons/favicon.icns" }, "linux": {