Electron 企业构建与受控发布
验证:未记录
- 适用版本
- 未记录
- 验证范围
- 尚未登记验证记录。
CI(Continuous Integration,持续集成)负责构建与验证;正式发布必须等全部平台成功。以下使用 electron-builder,已有 pnpm-lock.yaml、test:ci、build:win:x64、build:mac:arm 脚本;构建脚本必须关闭自动发布(--publish never)。不能让打包工具绕过最后的发布任务。
1. 准备签名与权限#
- 仓库保护
v*标签;配置desktop-signing和desktop-releaseEnvironment,限制受保护标签,后者要求发布审批。 - signing 环境保存 Windows/macOS 签名材料和 Apple 公证凭据;示例使用 electron-builder 的
CSC_LINK、CSC_KEY_PASSWORD。证书由企业签名服务管理时替换为其受控签名步骤。 - macOS 打包配置启用公证,使用 Apple API key,完成后 staple;下方会验证签名/公证结果,缺失即失败。Windows 需受信任代码签名和时间戳。
packageManager固定已验证 pnpm 精确版本。示例 Action 使用主版本便于阅读,落库时通过 Dependabot/Renovate 固定完整 commit SHA,审批升级。
2. 工作流#
保存 .github/workflows/desktop-release.yml:
name: Desktop release
on:
push:
tags: ['v*']
permissions:
contents: read
concurrency:
group: desktop-${{ github.ref }}
cancel-in-progress: false
jobs:
build:
environment: desktop-signing
strategy:
fail-fast: false
matrix:
include:
- {os: windows-latest, platform: win, script: 'build:win:x64', files: 'dist/*.exe'}
- {os: macos-latest, platform: mac, script: 'build:mac:arm', files: 'dist/*.dmg'}
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v6
with: {persist-credentials: false}
- uses: actions/setup-node@v6
with: {node-version: '24'}
- uses: pnpm/action-setup@v6
- run: pnpm install --frozen-lockfile
- run: pnpm run test:ci
- name: Materialize notarization key
if: matrix.platform == 'mac'
shell: bash
env:
API_KEY: ${{ secrets.APPLE_API_KEY_CONTENT }}
run: |
umask 077
printf '%s' "$API_KEY" > "$RUNNER_TEMP/AuthKey.p8"
- name: Package and sign, never publish
run: pnpm run ${{ matrix.script }} --publish never
env:
CSC_LINK: ${{ matrix.platform == 'win' && secrets.WIN_CSC_LINK || secrets.MAC_CSC_LINK }}
CSC_KEY_PASSWORD: ${{ matrix.platform == 'win' && secrets.WIN_CSC_PASSWORD || secrets.MAC_CSC_PASSWORD }}
APPLE_API_KEY: ${{ runner.temp }}/AuthKey.p8
APPLE_API_KEY_ID: ${{ secrets.APPLE_API_KEY_ID }}
APPLE_API_ISSUER: ${{ secrets.APPLE_API_ISSUER }}
- name: Validate Windows signatures
if: matrix.platform == 'win'
shell: pwsh
run: |
$files = @(Get-ChildItem dist/*.exe)
if ($files.Count -eq 0) { throw 'No executable' }
foreach ($file in $files) {
if ((Get-AuthenticodeSignature $file.FullName).Status -ne 'Valid') { throw 'Invalid signature' }
}
- name: Validate macOS notarization
if: matrix.platform == 'mac'
shell: bash
run: |
set -euo pipefail
found=0
for file in dist/*.dmg; do
test -f "$file"
xcrun stapler validate "$file"
spctl --assess --type open --context context:primary-signature --verbose "$file"
found=1
done
test "$found" = 1
- uses: actions/upload-artifact@v4
with:
name: desktop-${{ matrix.platform }}
path: ${{ matrix.files }}
if-no-files-found: error
retention-days: 14
release:
needs: build
environment: desktop-release
runs-on: ubuntu-latest
permissions: {contents: write}
steps:
- uses: actions/download-artifact@v4
with: {pattern: 'desktop-*', path: artifacts}
- name: Validate all platforms and publish complete draft
shell: bash
env:
GH_TOKEN: ${{ github.token }}
GH_REPO: ${{ github.repository }}
TAG: ${{ github.ref_name }}
run: |
set -euo pipefail
compgen -G 'artifacts/desktop-win/*.exe' >/dev/null
compgen -G 'artifacts/desktop-mac/*.dmg' >/dev/null
# Do not mutate an existing release, including a failed run's draft.
if gh release view "$TAG" >/dev/null 2>&1; then
echo 'Release exists; reconcile the previous run before retrying' >&2
exit 1
fi
find artifacts -type f -print0 | sort -z | xargs -0 sha256sum > SHA256SUMS
gh release create "$TAG" --verify-tag --draft --generate-notes
gh release upload "$TAG" artifacts/desktop-win/*.exe artifacts/desktop-mac/*.dmg SHA256SUMS
gh release view "$TAG" --json assets > assets.json
EXPECTED=$(find artifacts -type f | wc -l)
jq -e --argjson n "$EXPECTED" '.assets | length == ($n + 1)' assets.json
if [[ "$TAG" == *-* ]]; then
gh release edit "$TAG" --prerelease
fi
gh release edit "$TAG" --draft=falseApple API 私钥由上述步骤写入临时 runner,禁止上传至构建产物;使用一次性 runner,任务结束后销毁。签名环境不得用于不可信 PR。
3. 验收与恢复#
- 在受保护测试标签故意使 Windows 测试失败:macOS 可构建,但 release 任务跳过,不产生正式版本。
- 移除签名凭据:签名验收失败;禁止通过关闭验签完成发布。
- 双平台通过后核对文件、SHA256SUMS、签名、公证和安装启动;上传失败只留下草稿。修复并人工核对/移除本次草稿后重跑,不覆盖已发布资产。
- 已发布版本有问题时标记问题版本、发布修复版本;自动更新渠道应指向审核版本。二进制可回退不代表用户数据格式可降级,迁移另做兼容测试。