From e8105cb30e0d479afe44018e31fbaabb0fcc3c5f Mon Sep 17 00:00:00 2001 From: sanasol Date: Wed, 28 Jan 2026 14:48:40 +0100 Subject: [PATCH 1/5] feat: add macOS code signing and notarization support - Add entitlements.mac.plist for hardened runtime - Add notarize.js post-sign hook for Apple notarization - Update package.json with signing config and @electron/notarize dep - Update GitHub Actions workflow with signing secrets Co-Authored-By: Claude Opus 4.5 --- .github/workflows/release.yml | 8 ++++++++ build/entitlements.mac.plist | 18 ++++++++++++++++++ package.json | 8 +++++++- scripts/notarize.js | 36 +++++++++++++++++++++++++++++++++++ 4 files changed, 69 insertions(+), 1 deletion(-) create mode 100644 build/entitlements.mac.plist create mode 100644 scripts/notarize.js diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index ee466e9..5123161 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -40,6 +40,14 @@ jobs: - run: npm ci - name: Build macOS Packages + env: + # Code signing + CSC_LINK: ${{ secrets.CSC_LINK }} + CSC_KEY_PASSWORD: ${{ secrets.CSC_KEY_PASSWORD }} + # Notarization + APPLE_ID: ${{ secrets.APPLE_ID }} + APPLE_APP_SPECIFIC_PASSWORD: ${{ secrets.APPLE_APP_SPECIFIC_PASSWORD }} + APPLE_TEAM_ID: ${{ secrets.APPLE_TEAM_ID }} run: npx electron-builder --mac --publish never - uses: actions/upload-artifact@v4 with: diff --git a/build/entitlements.mac.plist b/build/entitlements.mac.plist new file mode 100644 index 0000000..e7b78d2 --- /dev/null +++ b/build/entitlements.mac.plist @@ -0,0 +1,18 @@ + + + + + com.apple.security.cs.allow-jit + + com.apple.security.cs.allow-unsigned-executable-memory + + com.apple.security.cs.disable-library-validation + + com.apple.security.network.client + + com.apple.security.network.server + + com.apple.security.files.user-selected.read-write + + + diff --git a/package.json b/package.json index c496c76..e9b2fbd 100644 --- a/package.json +++ b/package.json @@ -45,6 +45,7 @@ }, "license": "MIT", "devDependencies": { + "@electron/notarize": "^2.5.0", "electron": "^40.0.0", "electron-builder": "^26.4.0" }, @@ -131,8 +132,13 @@ } ], "icon": "build/icon.icns", - "category": "public.app-category.games" + "category": "public.app-category.games", + "hardenedRuntime": true, + "gatekeeperAssess": false, + "entitlements": "build/entitlements.mac.plist", + "entitlementsInherit": "build/entitlements.mac.plist" }, + "afterSign": "scripts/notarize.js", "nsis": { "oneClick": false, "allowToChangeInstallationDirectory": true, diff --git a/scripts/notarize.js b/scripts/notarize.js new file mode 100644 index 0000000..b8970ac --- /dev/null +++ b/scripts/notarize.js @@ -0,0 +1,36 @@ +const { notarize } = require('@electron/notarize'); +const path = require('path'); + +exports.default = async function notarizing(context) { + const { electronPlatformName, appOutDir } = context; + + // Only notarize macOS builds + if (electronPlatformName !== 'darwin') { + console.log('Skipping notarization: not macOS'); + return; + } + + // Skip if credentials not provided (local builds) + if (!process.env.APPLE_ID || !process.env.APPLE_APP_SPECIFIC_PASSWORD || !process.env.APPLE_TEAM_ID) { + console.log('Skipping notarization: missing credentials (APPLE_ID, APPLE_APP_SPECIFIC_PASSWORD, or APPLE_TEAM_ID)'); + return; + } + + const appName = context.packager.appInfo.productFilename; + const appPath = path.join(appOutDir, `${appName}.app`); + + console.log(`Notarizing ${appPath}...`); + + try { + await notarize({ + appPath, + appleId: process.env.APPLE_ID, + appleIdPassword: process.env.APPLE_APP_SPECIFIC_PASSWORD, + teamId: process.env.APPLE_TEAM_ID, + }); + console.log('Notarization complete!'); + } catch (error) { + console.error('Notarization failed:', error); + throw error; + } +}; From d0b9ae1da8def62e73b37da0620ed650c7559823 Mon Sep 17 00:00:00 2001 From: sanasol Date: Wed, 28 Jan 2026 15:01:57 +0100 Subject: [PATCH 2/5] ci: separate macOS release from main release job macOS notarization is slow (5-10 min). Now release is created immediately when Windows/Linux/Arch complete, and macOS uploads to the same release when notarization finishes. Co-Authored-By: Claude Opus 4.5 --- .github/workflows/release.yml | 72 ++++++++++++++++++++++++++--------- 1 file changed, 55 insertions(+), 17 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 5123161..3e1cd52 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -18,7 +18,7 @@ jobs: node-version: '22' cache: 'npm' - run: npm ci - + - name: Build Windows Packages run: npx electron-builder --win --publish never - uses: actions/upload-artifact@v4 @@ -65,7 +65,7 @@ jobs: run: | sudo apt-get update sudo apt-get install -y libarchive-tools - + - uses: actions/setup-node@v4 with: node-version: '22' @@ -94,7 +94,7 @@ jobs: uses: actions/checkout@v4 with: fetch-depth: 0 - + - name: Install base packages run: | pacman -Syu --noconfirm @@ -131,26 +131,39 @@ jobs: *.src.tar.zst .SRCINFO + # Create release with Windows, Linux, Arch (fast builds) release: - needs: [build-windows, build-macos, build-linux, build-arch] + needs: [build-windows, build-linux, build-arch] runs-on: ubuntu-latest if: | - startsWith(github.ref, 'refs/tags/v') || - github.ref == 'refs/heads/main' || + startsWith(github.ref, 'refs/tags/v') || + github.ref == 'refs/heads/main' || github.event_name == 'workflow_dispatch' permissions: contents: write steps: - # FIX: './package.json' Module Not Found in `Get version` step - name: Checkout code uses: actions/checkout@v4 - - name: Download all artifacts + - name: Download Windows artifacts uses: actions/download-artifact@v4 with: - path: artifacts + name: windows-builds + path: artifacts/windows-builds + + - name: Download Linux artifacts + uses: actions/download-artifact@v4 + with: + name: linux-builds + path: artifacts/linux-builds + + - name: Download Arch artifacts + uses: actions/download-artifact@v4 + with: + name: arch-package + path: artifacts/arch-package - name: Display structure of downloaded files run: ls -R artifacts @@ -163,18 +176,43 @@ jobs: uses: softprops/action-gh-release@v2 with: tag_name: ${{ github.ref_name }} - # If it's a tag, use the tag. - # tag_name: ${{ github.ref_type == 'tag' && github.ref_name || format('v{0}.r{1}', steps.pkg_version.outputs.VERSION, github.run_number) }} - # If it's the 'release' branch, use 'v2.0.2-beta.r42' - # name: ${{ github.ref_type == 'tag' && github.ref_name || format('v{0}-beta.r{1}', steps.pkg_version.outputs.VERSION, github.run_number) }} files: | artifacts/arch-package/*.pkg.tar.zst artifacts/arch-package/*.src.tar.zst artifacts/arch-package/.SRCINFO - artifacts/linux-builds/**/* - artifacts/windows-builds/**/* - artifacts/macos-builds/**/* + artifacts/linux-builds/* + artifacts/windows-builds/* generate_release_notes: true draft: true prerelease: false - + + # Upload macOS builds separately (slow due to notarization) + release-macos: + needs: [build-macos, release] + runs-on: ubuntu-latest + if: | + startsWith(github.ref, 'refs/tags/v') || + github.ref == 'refs/heads/main' || + github.event_name == 'workflow_dispatch' + + permissions: + contents: write + + steps: + - name: Download macOS artifacts + uses: actions/download-artifact@v4 + with: + name: macos-builds + path: artifacts/macos-builds + + - name: Display macOS files + run: ls -R artifacts + + - name: Upload macOS to Release + uses: softprops/action-gh-release@v2 + with: + tag_name: ${{ github.ref_name }} + files: | + artifacts/macos-builds/* + draft: true + prerelease: false \ No newline at end of file From be78f6743977f861230ca2d45aadb8e788419403 Mon Sep 17 00:00:00 2001 From: sanasol Date: Wed, 28 Jan 2026 15:04:13 +0100 Subject: [PATCH 3/5] chore: update package-lock.json Co-Authored-By: Claude Opus 4.5 --- package-lock.json | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index 3a3df94..03906ae 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "hytale-f2p-launcher", - "version": "2.1.1", + "version": "2.1.2", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "hytale-f2p-launcher", - "version": "2.1.1", + "version": "2.1.2", "license": "MIT", "dependencies": { "adm-zip": "^0.5.10", @@ -19,6 +19,7 @@ "uuid": "^9.0.1" }, "devDependencies": { + "@electron/notarize": "^2.5.0", "electron": "^40.0.0", "electron-builder": "^26.4.0" } From 0aaf74a3db067c719dea6713e055d194939177fc Mon Sep 17 00:00:00 2001 From: sanasol Date: Wed, 28 Jan 2026 15:14:59 +0100 Subject: [PATCH 4/5] fix: add verbose logging to notarize script for debugging Co-Authored-By: Claude Opus 4.5 --- scripts/notarize.js | 42 ++++++++++++++++++++++++++++++++++-------- 1 file changed, 34 insertions(+), 8 deletions(-) diff --git a/scripts/notarize.js b/scripts/notarize.js index b8970ac..2ae3890 100644 --- a/scripts/notarize.js +++ b/scripts/notarize.js @@ -1,25 +1,50 @@ -const { notarize } = require('@electron/notarize'); +console.log('[Notarize] Script loaded'); + +let notarize; +try { + notarize = require('@electron/notarize').notarize; + console.log('[Notarize] @electron/notarize loaded successfully'); +} catch (err) { + console.error('[Notarize] Failed to load @electron/notarize:', err.message); + throw err; +} + const path = require('path'); exports.default = async function notarizing(context) { + console.log('[Notarize] afterSign hook called'); + console.log('[Notarize] Context:', JSON.stringify({ + platform: context.electronPlatformName, + appOutDir: context.appOutDir, + outDir: context.outDir + }, null, 2)); + const { electronPlatformName, appOutDir } = context; // Only notarize macOS builds if (electronPlatformName !== 'darwin') { - console.log('Skipping notarization: not macOS'); + console.log('[Notarize] Skipping: not macOS'); return; } - // Skip if credentials not provided (local builds) - if (!process.env.APPLE_ID || !process.env.APPLE_APP_SPECIFIC_PASSWORD || !process.env.APPLE_TEAM_ID) { - console.log('Skipping notarization: missing credentials (APPLE_ID, APPLE_APP_SPECIFIC_PASSWORD, or APPLE_TEAM_ID)'); + // Check credentials + const hasAppleId = !!process.env.APPLE_ID; + const hasPassword = !!process.env.APPLE_APP_SPECIFIC_PASSWORD; + const hasTeamId = !!process.env.APPLE_TEAM_ID; + + console.log('[Notarize] Credentials check:', { hasAppleId, hasPassword, hasTeamId }); + + if (!hasAppleId || !hasPassword || !hasTeamId) { + console.log('[Notarize] Skipping: missing credentials'); return; } const appName = context.packager.appInfo.productFilename; const appPath = path.join(appOutDir, `${appName}.app`); - console.log(`Notarizing ${appPath}...`); + console.log('[Notarize] Starting notarization...'); + console.log('[Notarize] App path:', appPath); + console.log('[Notarize] Team ID:', process.env.APPLE_TEAM_ID); try { await notarize({ @@ -28,9 +53,10 @@ exports.default = async function notarizing(context) { appleIdPassword: process.env.APPLE_APP_SPECIFIC_PASSWORD, teamId: process.env.APPLE_TEAM_ID, }); - console.log('Notarization complete!'); + console.log('[Notarize] Notarization complete!'); } catch (error) { - console.error('Notarization failed:', error); + console.error('[Notarize] Notarization failed:', error.message); + console.error('[Notarize] Full error:', error); throw error; } }; From dfe9ed2a893253568c2a9c56efdc590e3b701917 Mon Sep 17 00:00:00 2001 From: sanasol Date: Thu, 29 Jan 2026 20:59:28 +0100 Subject: [PATCH 5/5] ci: set 6-hour max timeout for macOS notarization Co-Authored-By: Claude Opus 4.5 --- .github/workflows/release.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 3e1cd52..8d5d6ae 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -31,6 +31,7 @@ jobs: build-macos: runs-on: macos-latest + timeout-minutes: 360 # Max allowed (6 hours) for notarization steps: - uses: actions/checkout@v4 - uses: actions/setup-node@v4