feat(release): allow signed-only macOS draft builds

Add a workflow_dispatch-only notarize_macos switch so draft release runs can build Developer ID signed macOS artifacts without waiting on Apple notarization when GitHub runner networking is failing. Tag push releases still default to notarization and Gatekeeper release 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\nConfidence: medium\nScope-risk: moderate
This commit is contained in:
程序员阿江(Relakkes) 2026-06-17 04:47:52 +08:00
parent f7ebe668b5
commit f9b48a3031
2 changed files with 38 additions and 6 deletions

View File

@ -10,6 +10,11 @@ on:
required: false
default: true
type: boolean
notarize_macos:
description: 'Notarize macOS artifacts'
required: false
default: true
type: boolean
permissions:
contents: write
@ -173,6 +178,7 @@ jobs:
APPLE_ID: ${{ secrets.APPLE_ID }}
APPLE_APP_SPECIFIC_PASSWORD: ${{ secrets.APPLE_APP_SPECIFIC_PASSWORD }}
APPLE_TEAM_ID: ${{ secrets.APPLE_TEAM_ID }}
MACOS_NOTARIZE: ${{ github.event_name != 'workflow_dispatch' || inputs.notarize_macos }}
run: |
set -euo pipefail
echo "::group::macOS signing diagnostics"
@ -182,9 +188,18 @@ jobs:
xcrun --find notarytool
xcrun notarytool --version || true
security find-identity -v -p codesigning || true
echo "macOS notarization requested: ${MACOS_NOTARIZE}"
echo "::endgroup::"
max_attempts=2
build_timeout_seconds=2100
if [ "$MACOS_NOTARIZE" = "true" ]; then
max_attempts=2
build_timeout_seconds=2100
builder_args=( ${{ matrix.builder_args }} --publish never )
else
max_attempts=1
build_timeout_seconds=900
builder_args=( ${{ matrix.builder_args }} --publish never -c.mac.notarize=false )
echo "::warning::macOS notarization is disabled for this draft run; artifacts will be Developer ID signed but not notarized."
fi
run_signed_electron_builder() {
local timeout_seconds="$1"
@ -223,7 +238,7 @@ jobs:
echo "Starting signed electron-builder attempt ${attempt}/${max_attempts} at $(date -u '+%Y-%m-%dT%H:%M:%SZ') with ${build_timeout_seconds}s watchdog"
rm -rf build-artifacts/electron
set +e
run_signed_electron_builder "$build_timeout_seconds" node ./node_modules/electron-builder/out/cli/cli.js ${{ matrix.builder_args }} --publish never
run_signed_electron_builder "$build_timeout_seconds" node ./node_modules/electron-builder/out/cli/cli.js "${builder_args[@]}"
status=$?
set -e
if [ "$status" -eq 0 ]; then
@ -254,9 +269,13 @@ jobs:
run: bun run test:package-smoke --platform ${{ matrix.smoke_platform }} --package-kind release --artifacts-dir desktop/build-artifacts/electron
- name: Verify macOS launch policy
if: matrix.smoke_platform == 'macos' && needs.signing-preflight.outputs.macos_signed == 'true'
if: matrix.smoke_platform == 'macos' && needs.signing-preflight.outputs.macos_signed == 'true' && (github.event_name != 'workflow_dispatch' || inputs.notarize_macos == true)
run: bun run test:package-smoke --platform macos --package-kind release --artifacts-dir desktop/build-artifacts/electron --require-macos-gatekeeper
- name: Warn macOS notarization skipped
if: matrix.smoke_platform == 'macos' && needs.signing-preflight.outputs.macos_signed == 'true' && github.event_name == 'workflow_dispatch' && inputs.notarize_macos == false
run: echo "::warning::Skipping macOS Gatekeeper package-smoke because notarization is disabled for this draft. Artifacts are Developer ID signed but not notarized."
- name: Warn unsigned macOS launch policy skipped
if: matrix.smoke_platform == 'macos' && needs.signing-preflight.outputs.macos_signed != 'true'
run: echo "::warning::Skipping macOS Gatekeeper package-smoke because this release is unsigned. Ship install-macos-unsigned.sh with the DMG."

View File

@ -106,12 +106,19 @@ describe('release desktop workflow', () => {
const gatekeeperStep = workflow.match(
/- name: Verify macOS launch policy[\s\S]*?(?:\n\s{6}- name:|$)/,
)?.[0]
const notarizationWarningStep = workflow.match(
/- name: Warn macOS notarization skipped[\s\S]*?(?:\n\s{6}- name:|$)/,
)?.[0]
const unsignedWarningStep = workflow.match(
/- name: Warn unsigned macOS launch policy skipped[\s\S]*?(?:\n\s{6}- name:|$)/,
)?.[0]
expect(gatekeeperStep).toContain("if: matrix.smoke_platform == 'macos' && needs.signing-preflight.outputs.macos_signed == 'true'")
expect(workflow).toContain('notarize_macos:')
expect(workflow).toContain("description: 'Notarize macOS artifacts'")
expect(gatekeeperStep).toContain("if: matrix.smoke_platform == 'macos' && needs.signing-preflight.outputs.macos_signed == 'true' && (github.event_name != 'workflow_dispatch' || inputs.notarize_macos == true)")
expect(gatekeeperStep).toContain('bun run test:package-smoke --platform macos --package-kind release --artifacts-dir desktop/build-artifacts/electron --require-macos-gatekeeper')
expect(notarizationWarningStep).toContain("if: matrix.smoke_platform == 'macos' && needs.signing-preflight.outputs.macos_signed == 'true' && github.event_name == 'workflow_dispatch' && inputs.notarize_macos == false")
expect(notarizationWarningStep).toContain('Developer ID signed but not notarized')
expect(unsignedWarningStep).toContain("if: matrix.smoke_platform == 'macos' && needs.signing-preflight.outputs.macos_signed != 'true'")
expect(unsignedWarningStep).toContain('install-macos-unsigned.sh')
expect(workflow.indexOf('Verify macOS launch policy')).toBeLessThan(workflow.indexOf('Upload release artifacts for final publish'))
@ -128,14 +135,20 @@ describe('release desktop workflow', () => {
expect(signedBuildStep).toContain('APPLE_ID: ${{ secrets.APPLE_ID }}')
expect(signedBuildStep).toContain('APPLE_APP_SPECIFIC_PASSWORD: ${{ secrets.APPLE_APP_SPECIFIC_PASSWORD }}')
expect(signedBuildStep).toContain('APPLE_TEAM_ID: ${{ secrets.APPLE_TEAM_ID }}')
expect(signedBuildStep).toContain("MACOS_NOTARIZE: ${{ github.event_name != 'workflow_dispatch' || inputs.notarize_macos }}")
expect(signedBuildStep).not.toContain('CSC_IDENTITY_AUTO_DISCOVERY')
expect(signedBuildStep).toContain('timeout-minutes: 80')
expect(signedBuildStep).toContain("DEBUG: 'electron-builder,electron-osx-sign,electron-notarize*'")
expect(signedBuildStep).toContain('macOS signing diagnostics')
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('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('Signed electron-builder timed out')
expect(signedBuildStep).toContain('pkill -TERM -P "$build_pid"')
@ -147,7 +160,7 @@ describe('release desktop workflow', () => {
expect(signedBuildStep).toContain('Starting signed electron-builder attempt')
expect(signedBuildStep).toContain('Finished signed electron-builder attempt')
expect(signedBuildStep).toContain('retrying after 120 seconds')
expect(signedBuildStep).toContain(electronBuilderCli)
expect(signedBuildStep).toContain('node ./node_modules/electron-builder/out/cli/cli.js "${builder_args[@]}"')
expect(unsignedBuildStep).toContain("if: matrix.smoke_platform != 'macos' || needs.signing-preflight.outputs.macos_signed != 'true'")
expect(unsignedBuildStep).toContain("CSC_IDENTITY_AUTO_DISCOVERY: 'false'")