跳转至

Windows 签名期间不占用 runner

状态:实现提案;生产签名行为保持不变。

实测成本

在 发布运行 33821033674 (2026 年 9 月 4 日)中,Windows 作业耗时 21m56s。内部二进制下载步骤 耗时 13m19s,安装程序下载步骤耗时 40s:13m59s,即作业的 64%, 花在了签名下载/等待步骤上。这些时长包含下载本身,因此它们是可移除空闲时间的上限,而不是在作业之间转移状态后净节省的预测。

release-cut.yml 使用 wait-for-completion: false 提交两个请求,但随后在同一 Windows runner 上调用 Get-SignedArtifact,完成超时分别为一小时和四小时。六小时的作业超时容纳了这两次等待。再次更改提交标志、降低轮询频率,或在容器内运行等待,都不会释放 runner 槽位。

这是 runner 占用,不是计费估算。公共仓库中的标准 GitHub 托管 runner 可能免费;移除等待仍会为其他工作释放并发。在认定美元节省之前,请核对实际计费。

同一次发布还占用了一个 Ubuntu runner 11m38s,期间 run-release-mac-build-workflow.mjs 等待隔离的 macOS 工作流。 这是另一个编排优化。Windows 开发渠道构建有意以未签名形式发布,没有可移除的 SignPath 等待。

建议的执行图

保留原始 release-cut.yml 运行中的所有 Windows 阶段,以维持当前 SignPath GitHub 工件来源边界:

  1. build-windows 构建并上传解包后的应用、原始安装程序、更新器元数据和内部签名清单。它提交内部请求,发送现有通知,暴露请求 ID,然后结束。
  2. package-windows 依赖于该作业,并使用名为 windows-inner-signing 的受保护环境。其 runner 仅在 GitHub 批准后分配。它恢复精确的构建,使用短暂且有界的完成等待下载已签名二进制文件,应用现有签名恢复和已签名 elevate.exe 缓存替换,构建 NSIS 安装程序,上传它,提交第二个签名请求,通知审批人,然后结束。
  3. finalize-windows 依赖于打包,并使用第二个名为 windows-installer-signing 的受保护环境。批准后,它下载已签名安装程序,重新生成其 blockmap 和 latest.yml,运行现有外部和内部签名检查,上传证据,并将资产上传到草稿。
  4. publish-release 依赖于最终化,以及现有的 Linux、macOS 和阻塞式发布门。它仍然是唯一发布草稿的作业。

审批人在 SignPath 中签名,等待该请求完成,然后批准对应的待处理 GitHub 作业。每个通知都应链接到这两个位置并说明顺序。GitHub 批准是一个额外操作;仅在 SignPath 中批准不会释放环境门。

必需配置

2026 年 9 月 5 日,通过 GitHub API 检查了仓库环境。两个 Windows 环境均不存在。adhoc-mac-build 没有保护规则;它不能被复用为审批门。在仓库的工作流、脚本、应用或云代码中均未找到 SignPath 回调处理器。

在启用该图之前:

  1. 在仓库设置 → 环境中创建这两个环境。
  2. 将发布审批人添加为每个环境的必需审阅人。决定发布发起人是否可以批准自己的作业,并使其与现有 SignPath 策略保持一致。
  3. 将部署分支限制为用于分发发布工作流的受信 refs,并检查发布工作流的 ref 是否通过该限制。工作流 ref 与签出的发布标签是不同的概念。
  4. 通过 API 读回这两个环境,并在更改发布图之前验证 required_reviewers 规则存在。仅在 YAML 中引用新的环境名称可能会创建一个未受保护的环境,并悄悄地将等待留在 runner 上。
  5. 为这些规则添加预检断言,以便意外移除在任何签名请求提交之前失败。使用发布工作流的 token 验证该断言所需的 API 访问权限;不要假设管理员的本地 gh 访问权限能证明 workflow-token 访问权限。

自动替代方案需要一个 SignPath 完成回调和一个经过身份验证的集成,以释放对应的部署门。在选择该架构之前,确认 Foundation 计划支持所需的回调。不要引入长时间运行的 GitHub 轮询作业作为回调替代:它仍会继续占用槽位。

状态与失败契约

  • 使用来自该精确运行和尝试的工件,并附带包含标签、标签提交 SHA、工作流 SHA、请求 ID、工件 ID 和 SHA-256 哈希的清单。仅工件名称是不够的。保留原始未签名安装程序,用于现有内部签名回退。
  • 将 dist/win-unpacked、暂存列表、安装程序和更新器元数据作为一个检查点恢复。使用归档来保留目录树。在批准不同的二进制树后,不要发布应用的全新重新构建。
  • 每个新的 Windows runner 都需要固定的 Node/pnpm 工具链、构建依赖项、SignPath 模块和 electron-builder 工具缓存。第二个 runner 必须在替换 elevate.exe 之前填充 NSIS 缓存;旧代码假设第一次安装程序构建已经填充了该缓存。
  • 保留从标签签出的行为,以及对早于复合操作的发布标签的现有支持。必要时,从工作流 SHA 显式恢复新的编排代码。
  • 保留重新运行工作流绝不提交新签名请求的规则。恢复必须消费已记录的请求和工件。分别测试失败阶段重跑、整个工作流重跑以及缺失/过期检查点。
  • 保持安装程序签名检查为阻塞式。除非在单独决定中更改,否则保留内部验证证据及其当前仅警告策略。
  • 有意解决当前一小时内部签名回退:环境批准可能保持待处理状态超过一小时,而拒绝会跳过依赖作业。它本身无法复现现有的自动超时回退。首次迁移应明确记录新的人工发布/取消行为;悄悄地将被拒绝的批准视为发布许可是不可接受的。
  • 在图等待期间保持发布范围的并发锁,防止另一个发布超越此草稿。这节省了 worker 占用,但不会缩短串行发布队列的人工审批时间。

生产前验证

首先适配 windows-signing-rehearsal.yml,以使用自动批准的测试签名策略 运行相同的分阶段代码。然后使用受保护环境执行一次手动演练,并确认 待审批状态没有分配 Windows runner。通过现有的基于解包的 安装程序检查验证已签名的字节,而不仅仅是外部安装程序签名。

覆盖 SignPath 完成前的审批、被拒绝的审批、缺失的已签名 文件、变更的检查点哈希、丢失的检查点、过期工件、 打包失败,以及阶段重跑且不产生重复提交。确认在所有平台和签名 门禁通过之前,没有任何发布变为公开。将传输的 工件/设置时间与原始 13m59s 等待样本进行比较,以衡量净节省。

单独的 workflow_dispatch 续接可以避免环境配置, 但会大幅改变此设计:原始发布运行结束, 工作流级并发不再保护待处理草稿,并且 SignPath 必须接受由先前运行组装的工件。该选项在生产使用前需要 持久化发布状态机和来源验证;它不是 两个下载步骤的直接替换。

本页原文 Markdown:在 AtomGit 查看·内容源自开源项目 orca48/orca