diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 092896c..170a646 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -168,7 +168,49 @@ jobs: set -o pipefail # Build MAS package (notarization disabled by unsetting APPLE_API_KEY* vars above) npm run build:desktop:mas 2>&1 | tee /tmp/electron-builder-mas.log - exit ${PIPESTATUS[0]} + BUILD_EXIT=$? + + # Verify and fix PKG signing if needed + PKG_FILE=$(find dist -name "*.pkg" -type f | head -1) + if [ -n "$PKG_FILE" ] && [ -f "$PKG_FILE" ]; then + echo "Checking PKG signature: $PKG_FILE" + + # Check if PKG is signed with installer certificate + if ! pkgutil --check-signature "$PKG_FILE" 2>&1 | grep -q "3rd Party Mac Developer Installer"; then + echo "⚠️ PKG not signed with installer certificate, re-signing..." + + # Find installer identity + INSTALLER_IDENTITY=$(security find-identity -v -p basic | grep "3rd Party Mac Developer Installer" | head -1 | sed 's/.*"\(.*\)".*/\1/') + + if [ -n "$INSTALLER_IDENTITY" ]; then + echo "Found installer identity: $INSTALLER_IDENTITY" + + # Re-sign the PKG with installer certificate + TEMP_PKG="${PKG_FILE}.temp" + productsign --sign "$INSTALLER_IDENTITY" "$PKG_FILE" "$TEMP_PKG" + + if [ -f "$TEMP_PKG" ]; then + mv "$TEMP_PKG" "$PKG_FILE" + echo "✅ PKG re-signed with installer certificate" + + # Verify the signature + pkgutil --check-signature "$PKG_FILE" + else + echo "❌ Failed to re-sign PKG" + exit 1 + fi + else + echo "❌ Could not find 3rd Party Mac Developer Installer certificate" + exit 1 + fi + else + echo "✅ PKG already signed with installer certificate" + fi + else + echo "⚠️ No PKG file found" + fi + + exit $BUILD_EXIT env: # Enable signing for MAS builds (but NOT notarization) CI: true diff --git a/desktop/entitlements.mas.plist b/desktop/entitlements.mas.plist index a071326..77a321b 100644 --- a/desktop/entitlements.mas.plist +++ b/desktop/entitlements.mas.plist @@ -4,10 +4,6 @@ com.apple.security.app-sandbox - com.apple.security.application-groups - - 4MSL3T2696.com.iandmiller.visualtimer - com.apple.security.network.client com.apple.security.files.user-selected.read-write diff --git a/package-lock.json b/package-lock.json index 6c4c125..c92dafd 100644 --- a/package-lock.json +++ b/package-lock.json @@ -11,7 +11,8 @@ "devDependencies": { "electron": "^39.2.7", "electron-builder": "^26.4.0", - "jimp": "^1.6.0" + "jimp": "^1.6.0", + "unique-slug": "^5.0.0" } }, "node_modules/@develar/schema-utils": { @@ -398,6 +399,7 @@ "dev": true, "license": "BSD-2-Clause", "optional": true, + "peer": true, "dependencies": { "cross-dirname": "^0.1.0", "debug": "^4.3.4", @@ -419,6 +421,7 @@ "dev": true, "license": "MIT", "optional": true, + "peer": true, "dependencies": { "graceful-fs": "^4.2.0", "jsonfile": "^6.0.1", @@ -435,6 +438,7 @@ "dev": true, "license": "MIT", "optional": true, + "peer": true, "dependencies": { "universalify": "^2.0.0" }, @@ -449,6 +453,7 @@ "dev": true, "license": "MIT", "optional": true, + "peer": true, "engines": { "node": ">= 10.0.0" } @@ -2177,7 +2182,8 @@ "integrity": "sha512-+R08/oI0nl3vfPcqftZRpytksBXDzOUveBq/NBVx0sUp1axwzPQrKinNx5yd5sxPu8j1wIy8AfnVQ+5eFdha6Q==", "dev": true, "license": "MIT", - "optional": true + "optional": true, + "peer": true }, "node_modules/cross-spawn": { "version": "7.0.6", @@ -2684,6 +2690,7 @@ "dev": true, "hasInstallScript": true, "license": "MIT", + "peer": true, "dependencies": { "@electron/asar": "^3.2.1", "debug": "^4.1.1", @@ -2704,6 +2711,7 @@ "integrity": "sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "graceful-fs": "^4.1.2", "jsonfile": "^4.0.0", @@ -4492,7 +4500,6 @@ "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", "dev": true, "license": "MIT", - "peer": true, "engines": { "node": ">=12" }, @@ -4555,6 +4562,7 @@ "dev": true, "license": "MIT", "optional": true, + "peer": true, "dependencies": { "commander": "^9.4.0" }, @@ -4572,6 +4580,7 @@ "dev": true, "license": "MIT", "optional": true, + "peer": true, "engines": { "node": "^12.20.0 || >=14" } @@ -4820,6 +4829,7 @@ "deprecated": "Rimraf versions prior to v4 are no longer supported", "dev": true, "license": "ISC", + "peer": true, "dependencies": { "glob": "^7.1.3" }, @@ -5300,6 +5310,7 @@ "integrity": "sha512-yYrrsWnrXMcdsnu/7YMYAofM1ktpL5By7vZhf15CrXijWWrEYZks5AXBudalfSWJLlnen/QUJUB5aoB0kqZUGA==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "mkdirp": "^0.5.1", "rimraf": "~2.6.2" @@ -5363,6 +5374,7 @@ "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "minimist": "^1.2.6" }, @@ -5481,7 +5493,13 @@ "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz", "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==", "dev": true, - "license": "MIT" + "license": "ISC", + "dependencies": { + "imurmurhash": "^0.1.4" + }, + "engines": { + "node": "^18.17.0 || >=20.5.0" + } }, "node_modules/unique-filename": { "version": "4.0.0", @@ -5496,10 +5514,10 @@ "node": "^18.17.0 || >=20.5.0" } }, - "node_modules/undici-types": { - "version": "6.21.0", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz", - "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==", + "node_modules/unique-slug": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/unique-slug/-/unique-slug-5.0.0.tgz", + "integrity": "sha512-9OdaqO5kwqR+1kVgHAhsp5vPNU0hnxRa26rBFNfNgM7M6pNtgzeBn3s/xbyCQL3dcjzOatcef6UUHpB/6MaETg==", "dev": true, "license": "ISC", "dependencies": { diff --git a/package.json b/package.json index 7cdd350..52f6bd2 100644 --- a/package.json +++ b/package.json @@ -70,7 +70,7 @@ "mas": { "category": "public.app-category.productivity", "icon": "desktop/assets/icon.icns", - "hardenedRuntime": true, + "hardenedRuntime": false, "gatekeeperAssess": false, "entitlements": "desktop/entitlements.mas.plist", "entitlementsInherit": "desktop/entitlements.mas.inherit.plist", diff --git a/scripts/fix-mas-icon.js b/scripts/fix-mas-icon.js index 55577c2..d50af7b 100755 --- a/scripts/fix-mas-icon.js +++ b/scripts/fix-mas-icon.js @@ -118,7 +118,8 @@ exports.default = async function(context) { const helperPath = path.join(helpersPath, helper); if (fs.statSync(helperPath).isFile() && !helper.endsWith('.plist')) { try { - execSync(`codesign --force --sign "${identity}" --entitlements "${entitlementsInherit}" --options runtime "${helperPath}"`, { + // Don't use --options runtime for MAS builds (that's for Developer ID only) + execSync(`codesign --force --sign "${identity}" --entitlements "${entitlementsInherit}" "${helperPath}"`, { stdio: 'inherit' }); console.log(`✅ Re-signed helper: ${helper}`); @@ -133,8 +134,8 @@ exports.default = async function(context) { helperApps.sort((a, b) => b.split(path.sep).length - a.split(path.sep).length); for (const helperApp of helperApps) { try { - // Sign the helper app - execSync(`codesign --force --sign "${identity}" --entitlements "${entitlementsInherit}" --options runtime "${helperApp}"`, { + // Sign the helper app (no --options runtime for MAS builds) + execSync(`codesign --force --sign "${identity}" --entitlements "${entitlementsInherit}" "${helperApp}"`, { stdio: 'inherit' }); @@ -154,25 +155,25 @@ exports.default = async function(context) { const electronFrameworkPath = path.join(frameworksPath, 'Electron Framework.framework'); const electronFrameworkExecutable = path.join(electronFrameworkPath, 'Versions', 'A', 'Electron Framework'); if (fs.existsSync(electronFrameworkExecutable)) { - // Sign the executable inside the framework first - execSync(`codesign --force --sign "${identity}" --entitlements "${entitlementsInherit}" --options runtime "${electronFrameworkExecutable}"`, { + // Sign the executable inside the framework first (no --options runtime for MAS) + execSync(`codesign --force --sign "${identity}" --entitlements "${entitlementsInherit}" "${electronFrameworkExecutable}"`, { stdio: 'inherit' }); // Then sign the framework bundle - execSync(`codesign --force --sign "${identity}" --entitlements "${entitlementsInherit}" --options runtime "${electronFrameworkPath}"`, { + execSync(`codesign --force --sign "${identity}" --entitlements "${entitlementsInherit}" "${electronFrameworkPath}"`, { stdio: 'inherit' }); console.log('✅ Re-signed Electron Framework (executable and bundle)'); } else if (fs.existsSync(electronFrameworkPath)) { // Fallback: sign the framework bundle if executable path doesn't exist - execSync(`codesign --force --sign "${identity}" --entitlements "${entitlementsInherit}" --options runtime "${electronFrameworkPath}"`, { + execSync(`codesign --force --sign "${identity}" --entitlements "${entitlementsInherit}" "${electronFrameworkPath}"`, { stdio: 'inherit' }); console.log('✅ Re-signed Electron Framework (bundle only)'); } - // Sign main app bundle last - execSync(`codesign --force --sign "${identity}" --entitlements "${entitlements}" --options runtime "${appBundlePath}"`, { + // Sign main app bundle last (no --options runtime for MAS builds) + execSync(`codesign --force --sign "${identity}" --entitlements "${entitlements}" "${appBundlePath}"`, { stdio: 'inherit' }); console.log('✅ App bundle re-signed successfully');