CI/CD 2026年9月8日 约 30 分钟 macOS 公证 Apple Notary API

macOS App 公证需要 Mac 吗?2026 CI 部署判断

本文面向以 Linux CI 为主、需要发布 macOS 软件的开发者和平台工程师。文章沿制品生成、Developer ID 签名、公证提交、状态查询、票据装订与最终验证的时间线,判断哪些环节可以放在通用节点,哪些环节应保留真实 Mac,并给出仅 Mac、混合 CI 与按需 Mac 节点的选择条件。

macOS App 公证需要 Mac 吗?2026 CI 部署判断

本文面向以 Linux CI 为主、需要发布 macOS 软件的开发者和平台工程师。文章沿制品生成、Developer ID 签名、公证提交、状态查询、票据装订与最终验证的时间线,判断哪些环节可以放在通用节点,哪些环节应保留真实 Mac,并给出仅 Mac、混合 CI 与按需 Mac 节点的选择条件。

macOS App 公证需要 Mac 吗?如果流水线只负责向 Apple 提交已签名制品并查询结果,Linux CI 可以承担这部分工作;如果还要构建、Developer ID 签名、票据装订或本地验证,就应保留真实 Mac。

对多数团队,最快的落地方式不是把整条链路搬到 Mac,而是让通用 CI 负责编排、制品传递和状态记录,再让远程 Mac CI 完成 macOS 专属交付闭环。

这篇文章适合 3 类人:

  • 以 Linux CI 为主、准备增加 macOS 软件发布能力的平台工程师;
  • 需要把签名、公证和制品分发改造成无人值守流程的 macOS 开发者;
  • 正在判断长期租用远程 Mac,还是仅保留按需发布节点的技术负责人。
01

先把公证拆成一条可验收的发布时间线

很多团队把“上传到 Apple 公证服务”误认为“macOS 发布完成”。实际上,交付链路至少包括制品生成、代码签名、公证提交、状态查询、日志处理、票据装订和最终验证。

Apple 的官方流程建立在一个前提上:提交给公证服务的软件应先完成 Developer ID 签名。公证不是 App Review,也不能替代代码签名;它主要负责对软件执行自动化检查,并在通过后生成供 Gatekeeper 使用的票据。Apple 公证流程说明

阶段 主要输入 通用 Linux CI 真实 Mac CI 阶段验收结果
构建与归档 源码、依赖、Xcode 工程 △ 取决于工具链 ✅ 通常需要 可重复生成归档
Developer ID 签名 待签名 App、权限配置、证书身份 △ 需单独验证 ✅ 推荐 签名身份和权限验证通过
公证提交 已签名 .zip.dmg.pkg ✅ Notary API 可行 notarytool 可行 获得提交标识
状态与日志 提交标识 保存状态和原始日志
票据装订 通过公证的最终制品 ❌ 不应作为默认方案 ✅ 使用 stapler 最终文件完成装订
本地验证 最终分发文件 △ 可做哈希和结构检查 ✅ 推荐 制品可被 macOS 验证

真正的判断标准不是“能不能发送 HTTP 请求”,而是最终交付对象是否经过正确签名、装订和验证。Apple 的工作流也把 notarytool、Notary API、stapler 和本地验证分别处理,而不是把它们合并为一次上传动作。Apple 自定义公证工作流

02

第一步:先确认制品生成是否依赖 macOS 工具链

如果流水线已经拿到一个结构正确、能够重复生成的待提交制品,Linux CI 可以承担哈希计算、归档传输、公证 API 调用和状态轮询。

但如果流水线从 Xcode 工程开始构建,情况就不同。包含 App Extension、Framework、插件、Helper 或命令行工具的 macOS App,需要在构建阶段确定目录结构、嵌套关系、权限配置和后续签名顺序。Apple 的分发文档也将 Xcode 归档、导出分发制品和外部签名流程分别处理。Apple 分发签名代码说明

因此,构建阶段的验收不能只检查“文件生成成功”,还应检查:

  1. 相同源码和依赖锁定文件能够生成一致的制品结构;
  2. App、嵌套 Framework、插件和命令行工具都位于预期路径;
  3. 制品与源码版本、构建编号和构建日志建立关联;
  4. 进入签名阶段后,制品不会被脚本静默修改;
  5. 失败时可以从归档阶段重新开始,而不是依赖上一次任务的工作目录。

Linux CI 能不能承担 macOS 软件的公证提交?

可以,但需要把“提交”与“完整发布”拆开。Linux 节点可以通过 Apple Notary API 创建提交、上传制品、查询状态并取得日志;这并不等于它能够自然完成 Xcode 构建、Developer ID 签名、stapler 票据装订和 macOS 本地验证。

如果团队已经能从其他节点稳定生成正确签名的 .zip.dmg.pkg,可以先把 Linux CI 用作提交层。若制品仍需在流水线内构建和签名,就应把这些任务放到远程 Mac CI。

03

第二步:把 Developer ID 签名和公证严格分开

公证服务检查的是已经签名的 macOS 软件。Apple 的发布文档说明,直接分发的软件需要使用相应的 Developer ID 身份;App、磁盘映像和安装包等不同对象,也可能需要分别处理签名。Apple Mac 软件打包文档

签名阶段至少要验证 4 个边界:

  • 身份边界:执行账户能否访问所需钥匙串项目;
  • 证书边界:当前身份确实用于直接分发,而不是调试或开发;
  • 嵌套代码边界:Framework、Extension、Helper 和命令行工具是否按正确顺序签名;
  • 权限边界:Hardened Runtime、Entitlements 和发布环境配置是否与调试版本区分。

Apple 还提醒,复杂产品不应简单依赖 codesign --deep 完成全部处理,因为不同嵌套代码可能需要不同的签名选项和权限。发布版本也要检查不适合生产分发的调试权限是否被清除。Apple 代码签名说明

签名与权限检查 专用远程 Mac 共享 Mac 节点 外部签名步骤
钥匙串隔离 评分:★★★★★ 评分:★★★☆☆ 评分:★★★☆☆
适合无人值守 CI 评分:★★★★★ 评分:★★★☆☆ 评分:★★☆☆☆
临时接入成本 评分:★★★☆☆ 评分:★★★★☆ 评分:★★★☆☆
故障定位清晰度 评分:★★★★★ 评分:★★☆☆☆ 评分:★★☆☆☆
适合高频发布 评分:★★★★★ 评分:★★★★☆ 评分:★★★☆☆

这张评分表比较的是权限和运维边界,不是编译速度排名。对于含有生产签名凭据的流水线,我们更看重执行账户、钥匙串状态、审计记录和重启后的恢复能力。

验收证据至少应包括:

  • codesign 对目标 App 和嵌套代码的验证结果;
  • security find-identity 是否找到预期身份;
  • 执行账户和钥匙串访问状态;
  • 签名后制品的哈希值;
  • 修改制品后能否明确触发重新签名,而不是继续复用旧签名。

如果团队正在准备独立的签名节点,可以将 远程 Mac Developer ID 签名环境 作为部署规划入口,但不要把租到一台 Mac 直接等同于签名环境已经合格。

04

第三步:按节点职责选择 notarytool 或 Notary API

已有 Mac 节点时,通常优先评估 notarytool;由 Linux CI 统一编排提交和查询时,再评估 Notary API。

notarytool 适合在真实 Mac 上快速接入。它可以提交制品、等待结果、输出状态,并配合脚本保存日志和处理失败退出码。

Apple Notary API 则适合由 Linux 或其他通用节点调用。官方文档说明,Notary API 可以绕过 notarytool,直接通过服务端接口完成提交、状态查询、日志获取和历史提交查询。Apple Notary API 概览

两条路径的差异主要集中在运维责任:

  • notarytool:Mac 侧命令行接入更直接,适合已有 Mac 构建节点的团队;
  • Notary API:适合由通用 CI 统一管理,需要自行处理 HTTP 认证、临时上传凭据、轮询和日志下载;
  • 两者都不能替代 Developer ID 签名;
  • 两者都不能自动完成最终的 stapler 装订和本地 Gatekeeper 验证。

Notary API 的提交接口会返回提交标识和用于上传的临时凭据。Apple 文档说明,这类临时上传凭据取得后 12 小时 过期,因此 CI 不应把它当作长期缓存的访问令牌。Apple Submit Software 接口

提交阶段应保存以下信息:

  • 制品文件名和 SHA-256;
  • 提交标识;
  • 使用的认证方式;
  • 当前状态;
  • 原始日志;
  • 失败后的重新提交次数;
  • 人工接管入口和对应操作记录。
05

第四步:公证成功后完成票据装订与最终验证

公证状态变为成功,不等于交付文件已经完成。对于 App、磁盘映像和扁平安装包,通常还需要根据最终分发格式完成票据装订,并对最终文件进行验证。

Apple 说明,票据可以在线交由 Gatekeeper 查询,但将票据装订到软件中,可以让用户在没有网络连接时完成相应验证。stapler 可以处理 App、Bundle、磁盘映像和扁平安装包,但不能直接把票据装订到 ZIP 文件;如果最终交付格式是 ZIP,应先对其中的 App 完成装订,再重新创建 ZIP。Apple 票据装订说明

哪些环节应固定放在真实 Mac 上?

如果发布链路包括以下任一动作,就应把相关阶段放在真实 Mac:

  • 从 Xcode 工程构建和导出;
  • 使用钥匙串中的 Developer ID 身份完成签名;
  • 执行 stapler staple
  • 执行 stapler validatespctl 等本地验证;
  • 在接近真实用户环境的 macOS 上启动最终 App。

最终验收对象必须是实际分发文件,而不是中间归档。发布 .dmg 时验证完成装订后的 .dmg;发布 .pkg 时验证最终安装包;发布 .zip 时验证重新创建的 ZIP 以及其中的 App。

日志也不应只在失败时保存。Apple 建议公证成功后仍下载并检查日志,因为日志中可能包含下一次发布前应修复的警告。Apple 获取公证日志接口

状态查询依赖提交标识,日志接口返回的下载地址可能具有临时性,因此流水线应在任务结束前把日志复制到自己的制品存储中,而不是只保留一个外部地址。

06

第五步:用双节点试运行确定最终拓扑

在决定长期租用周期前,我们建议先做一次真实制品试运行:通用 CI 负责拉取源码、编排任务、传递制品和保存日志;远程 Mac CI 负责 macOS 构建、签名、装订和最终验证。

试运行不要只测试“绿色通过”,还要主动验证失败、重启和人工接管:

  1. 通用 CI 生成带版本标识的源码制品;
  2. 远程 Mac 拉取制品并完成构建或导出;
  3. 在隔离钥匙串中执行 Developer ID 签名;
  4. 记录签名验证结果和制品哈希;
  5. 通过 notarytool 或 Notary API 提交;
  6. 等待状态并保存完整 JSON 日志;
  7. 在 Mac 上完成票据装订;
  8. 对最终分发文件执行本地验证;
  9. 重启远程 Mac 后重新执行一次恢复测试;
  10. 人为制造一次公证失败,确认流水线会停止发布并保留提交标识。

可以按下面的条件分支确定部署方案:

  • 若已有正确签名的制品,只需提交、查询和保存日志,选择通用 CI 加 Notary API;否则回退到 Mac 节点完成签名和验证。
  • 若流水线需要 Xcode、Mac 专属 SDK 或 macOS 打包工具,选择远程 Mac CI,不要把 Linux 节点当成完整替代品。
  • 若生产签名凭据需要独立钥匙串、专用账户和可审计权限,选择专用远程 Mac,不要把敏感身份长期放在多人共享节点。
  • 若发布频率不高,但每次发布都需要完整构建和签名,选择按需启用的 Mac 节点,并保留固定验收脚本。
  • 若每天高频构建,需要重试和并行发布,选择长期运行的远程 Mac CI,并设计重启恢复和任务锁。
  • 若团队只想先验证公证接口,可以在 Linux CI 中试验 Notary API,但不能把“提交成功”直接当成生产发布资格。

对于需要长期运行的节点,还应额外验证:

  • CI 代理重启后能否自动上线;
  • 钥匙串是否处于预期锁定状态;
  • 未完成任务是否会被重复执行;
  • 远程节点断电或重启后是否能恢复;
  • 签名凭据是否不会出现在普通构建日志;
  • 构建、签名、公证和发布权限是否能分别审计。

如果重点是节点恢复、持续运行和远程接入,可以进一步查看 VNCMac 的远程 Mac 方案;如果团队还在比较一次性购买设备与按需使用节点,也可以参考 Mac 设备方案与远程使用选择

07

最终判断:提交层可以脱离 Mac,完整交付闭环通常不能

macOS App 公证需要 Mac 吗?答案取决于团队把“公证”定义到哪一步:Apple Notary API 可以让 Linux CI 负责提交和查询,但构建、Developer ID 签名、票据装订及本地验证仍然属于真实 macOS 交付职责。

如果当前方案是 Linux 云主机加临时人工 Mac,常见缺点是:签名凭据难以隔离、人工接管容易遗漏、装订与验证难以稳定复现,而且重启后工具链和钥匙串状态不一定能恢复。相比之下,VNCMac 的远程 Mac 更适合先作为隔离发布节点完成一次端到端试运行,再根据构建频率决定按需使用或长期租用。

因此,建议先用真实制品验证“构建—签名—提交—装订—验证—重启恢复”这条链路。只有整条链路都能稳定通过,才应把远程 Mac CI 固定为生产发布节点;如果只需要提交和查询,则保留 Linux CI 加 Apple Notary API,避免为不需要的环节扩大 Mac 运维范围。