fix(release): notarize macOS apps before packaging

Replace electron-builder's internal macOS notarization wait with an explicit notarytool flow: build a signed app with update config, submit it with a bounded notarytool timeout, staple and validate it, then rebuild dmg/zip from the notarized app via --prepackaged. Keep draft-only signed/no-notary builds available for fast artifact checks.\n\nTested: bun test scripts/pr/release-workflow.test.ts\nTested: git diff --check\nTested: bun run scripts/release.ts 0.4.3 --dry\nTested: local arm64 signed/no-notary build followed by --prepackaged dmg/zip rebuild\nTested: bun run test:package-smoke --platform macos --package-kind release --artifacts-dir desktop/build-artifacts/electron\nTested: codesign --verify --deep --strict --verbose=2 desktop/build-artifacts/electron/mac-arm64/Claude\ Code\ Haha.app\nConfidence: medium\nScope-risk: moderate
This commit is contained in:
程序员阿江(Relakkes)
2026-06-17 09:10:39 +08:00
parent f9b48a3031
commit 6715e75161
2 changed files with 130 additions and 23 deletions
+15 -3
View File
@@ -129,6 +129,8 @@ describe('release desktop workflow', () => {
const signedBuildStep = extractStep(workflow, 'Build signed macOS Electron release artifacts')
const unsignedBuildStep = extractStep(workflow, 'Build unsigned Electron release artifacts')
expect(workflow).toContain('app_bundle_dir: mac-arm64')
expect(workflow).toContain('app_bundle_dir: mac')
expect(signedBuildStep).toContain("if: matrix.smoke_platform == 'macos' && needs.signing-preflight.outputs.macos_signed == 'true'")
expect(signedBuildStep).toContain('CSC_LINK: ${{ secrets.MACOS_CERTIFICATE }}')
expect(signedBuildStep).toContain('CSC_KEY_PASSWORD: ${{ secrets.MACOS_CERTIFICATE_PASSWORD }}')
@@ -143,16 +145,26 @@ describe('release desktop workflow', () => {
expect(signedBuildStep).toContain('xcrun --find notarytool')
expect(signedBuildStep).toContain('security find-identity -v -p codesigning')
expect(signedBuildStep).toContain('macOS notarization requested: ${MACOS_NOTARIZE}')
expect(signedBuildStep).toContain('max_attempts=2')
expect(signedBuildStep).toContain('build_timeout_seconds=2100')
expect(signedBuildStep).toContain('builder_args=( ${{ matrix.builder_args }} --publish never -c.mac.notarize=false )')
expect(signedBuildStep).toContain('max_attempts=1')
expect(signedBuildStep).toContain('build_timeout_seconds=900')
expect(signedBuildStep).toContain('-c.mac.notarize=false')
expect(signedBuildStep).toContain('macOS notarization is disabled for this draft run')
expect(signedBuildStep).toContain('run_signed_electron_builder')
expect(signedBuildStep).toContain('run_electron_builder_with_retries')
expect(signedBuildStep).toContain('notarize_app_bundle')
expect(signedBuildStep).toContain('xcrun notarytool submit "$notary_zip"')
expect(signedBuildStep).toContain('--timeout "$notary_timeout"')
expect(signedBuildStep).toContain('notary_attempts=3')
expect(signedBuildStep).toContain('xcrun stapler staple "$app_path"')
expect(signedBuildStep).toContain('xcrun stapler validate "$app_path"')
expect(signedBuildStep).toContain('spctl -a -vv -t execute "$app_path"')
expect(signedBuildStep).toContain('app_path="build-artifacts/electron/${{ matrix.app_bundle_dir }}/Claude Code Haha.app"')
expect(signedBuildStep).toContain('package_args=( ${{ matrix.builder_args }} --prepackaged "$app_path" --publish never -c.mac.notarize=false )')
expect(signedBuildStep).toContain('find build-artifacts/electron -maxdepth 1 -type f -delete')
expect(signedBuildStep).toContain('Signed electron-builder timed out')
expect(signedBuildStep).toContain('pkill -TERM -P "$build_pid"')
expect(signedBuildStep).toContain('with ${build_timeout_seconds}s watchdog')
expect(signedBuildStep).toContain('with ${timeout_seconds}s watchdog')
expect(signedBuildStep).toContain('set +e')
expect(signedBuildStep).toContain('status=$?')
expect(signedBuildStep).toContain('if [ "$status" -eq 0 ]; then')