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。