2026 年 Mac 云 CI 里做 Apple 公证(Notarization):notarytool 凭据、常见拒绝项与「无头 SSH vs 短时桌面会话」分流决策表

很多团队已经能在 Mac 云节点上稳定 xcodebuild archive,却卡在「公证」这一步:要么 notarytool 报凭据错误,要么 Apple 返回难以解读的拒绝详情,要么流水线必须突然接入图形会话。本文给出一套可写进 Runbook 的分流方法:先用对照表归类失败,再用决策矩阵判断纯 SSH 是否足够,最后给出 notarytool 提交、轮询、stapler 与日志保留的五步落地顺序,并附 Mac 云侧磁盘与并发建议。

Mac 云持续集成与 Apple 公证流程示意图

本文要点

1. 痛点拆解:公证与上传、签名混为一谈

在 Mac 云或自托管 Runner 上,常把三条链路捆在一起:代码签名、Apple 公证(Notarization)、App Store Connect / TestFlight 上传。相关但凭证与失败语义不同。

  1. 签名:Profile、证书链与 Hardened Runtime 决定 codesign;失败多在 Archive/export,日志在 xcodebuild
  2. 公证:向 Apple 提交 zip/dmg/pkg 等待检物;拒绝多在 notarytool 的 JSON 或 log 输出,而非本地编译器。
  3. 上传:Transporter/Fastlane 等走 App Store Connect API Key;与公证端点不同,混用 Secrets 会失去分层排障。

三层拆开,是在 Mac 云「像管 VPS 一样 SSH」前提下稳定自动化的关键。

2. CI 公证失败类型对照表

用于快速定位:先查签名/entitlements,还是先查 notarytool 与网络。

现象更可能根因优先动作
notarytool 立即报认证失败App Store Connect API Key 与公证用途不匹配、Key 过期、Issuer ID 填错核对 Key 权限、.p8 路径、CI 机密注入是否截断换行
提交成功但长时间 In ProgressApple 侧队列、包体过大、或扫描命中额外启发式保留 submission id,使用 notarytool log 拉取详情;对大包体设置更长超时
拒绝信息指向 hardened runtime / library validation嵌入二进制未签名、使用了不当的 disable-library-validation、或 Helper 未独立签名对 app bundle 做 codesign --verify --deep 与 entitlements diff
仅 CI 失败、本机图形会话成功钥匙串或交互依赖见第三节矩阵:短时 VNC 或拆分人工一步

3. 无头 SSH 与短时桌面会话:决策矩阵

Mac 云可像 Linux 一样管 launchd/SSH;公证偶发需图形或钥匙串解锁,下表作工程分流(安全边界由团队自定)。

维度纯 SSH 无头(推荐默认)短时桌面 / VNC 会话
凭据形态使用 API Key + notarytool 非交互参数;Secrets 只注入到 CI Job 环境需要钥匙串解锁、系统弹窗或仅 GUI 工具才能完成的步骤
可审计性日志可完整落盘到构建目录并随制品归档人工步骤多,需额外录屏或双人复核才能满足审计
稳定性适合 7×24 重复执行与多分支并行适合低频、关键路径上的例外流程,不建议作为默认路径
与 Mac 云的结合方式launchd 固定 PATH,CI 用户与 Xcode 命令行工具版本钉死为公证子任务单独队列,避免与重负载 xcodebuild 争用 CPU 与磁盘
实践建议:若已拆分「仅构建/仅上传」,公证作第三条 Job:输入已签名导出物,输出 staple 后的包与 notary 日志;勿与 UI 测试同 Job。

4. 五步落地:notarytool → 轮询 → staple → 归档 → 回滚

2026 年仍可复用的最小顺序;flag 以本机 xcrun notarytool 帮助为准。

  1. 冻结工具链:镜像记录 xcodebuild -version,CI 显式锁定,避免静默升级致行为漂移。
  2. 准备提交物:dmg/zip/pkg 记 sha256;路径在构建目录内且 CI 用户可读;大包预留临时空间。
  3. submit:API Key 调用 notarytool submit,stdout/JSON 写入 artifacts/notary/submit.log
  4. 轮询notarytool info 等轮询,队列高峰指数退避;失败用 notarytool log 拉详情并随制品上传。
  5. staple 与回滚:对 dmg/pkg 执行 xcrun stapler staple;日志与包一并归档;staple 失败则阻断发布并保留上一版制品。

示意(请替换 Key 与路径):

# 1) 提交(示例:使用 API Key 与 issuer/key id) xcrun notarytool submit ./dist/MyApp.zip \ --key ./AuthKey_XXXXX.p8 \ --key-id "XXXXXXXXXX" \ --issuer "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" \ --wait # 2) 若未使用 --wait,则记录 submission id 后轮询 + 拉日志 # xcrun notarytool log <submission-id> --key ... > ./notary-detail.json # 3) 对可分发的载体执行 staple(示例) xcrun stapler staple "./dist/MyApp.dmg"

5. 可引用参数:超时、磁盘与并发

供容量评审与 Runbook;以 Apple 文档与合规为准。

6. FAQ 与和 TestFlight 链路的衔接

问:公证和 TestFlight 上传哪个先做? 常见是先签名与公证/staple,再上传;顺序须与 export 形态一致并写进 Runbook,避免 Gatekeeper 与渠道状态不一致。

问:CI 里 notarytool 偶发网络错误? 查代理 HTTPS_PROXY/NO_PROXY;公证与上传域名可能不同。

问:能否完全避免 VNC? 多数可以;若遇钥匙串/图形依赖,优先拆分密钥与单步人工,而非长期桌面共享。

笔记本易受关机与策略影响;纯托管分钟 Runner 大包公证成本高。要稳定 Apple 工具链与可审计 Key、少扛硬件运维时,专用 Mac 云更适合「签名—公证—上传」;可结合站内 TestFlight 文对齐 Job 与 Secrets。