SSH 執行 xcodebuild archive 時,若建置停在 CodeSign 並出現 errSecInternalComponent,先比較 SSH 與圖形工作階段的執行使用者、鑰匙圈狀態和私鑰存取權;不要一開始就重建憑證。
適合: 維護遠端 Mac 建置流程、需要定位簽名階段故障的 iOS 開發者與小型團隊。
不適合: 尚未確認是否進入簽名階段,或只遇到 SSH 連線、依賴安裝等其他故障的人;應先依照實際失敗階段排查。
00Xcode 27 遠端 Mac SSH 簽名失敗:先找出錯誤階段
先在建置記錄中定位第一個 CodeSign 錯誤,而不是從最後一行的 Archive 失敗訊息推斷原因。編譯錯誤表示程式碼或建置設定尚未通過;CodeSign 錯誤才需要查身份、鑰匙圈或簽名設定;若 Archive 已完成、錯誤發生在上傳階段,則應另外檢查上傳流程。
Apple DTS 說明,errSecInternalComponent 可能出現在 SSH 或 CI 等非標準簽名環境,鑰匙圈鎖定是可能原因之一,但錯誤本身並不指向唯一根因。可參考 Apple DTS 對 SSH、CI 與簽名錯誤的說明,不要只因錯誤代碼就判定必須重建憑證。
| 建置結果 | 優先檢查 | 不要先做的事 |
|---|---|---|
| 編譯尚未完成便失敗 | 第一個編譯錯誤、Scheme、建置設定 | 修改鑰匙圈或撤銷簽名身份 |
| Archive 卡在 CodeSign | 執行帳戶、鑰匙圈、私鑰授權及簽名身份 | 僅憑錯誤代碼重建憑證 |
| Archive 已完成,後續上傳失敗 | 上傳帳戶、網路與交付流程 | 把上傳錯誤當成 CodeSign 故障 |
先用相同專案、Scheme 和目的地,比較圖形登入工作階段與 SSH 工作階段的結果。若前者可簽名、後者失敗,這是執行環境差異的線索,不是已證實的單一原因。記錄首個錯誤,以及失敗發生在編譯、簽名還是上傳,有助於避免在錯誤層級修改設定。
01第一步:確認建置任務實際使用的帳戶
登入 SSH 的帳戶不一定等於真正執行建置的帳戶。若建置由 CI、排程任務或常駐程序啟動,應在該任務的執行環境中核對身份,而不是從另一個互動式終端機推測。
可在建置腳本加入非敏感診斷資訊:
id -un
printf 'HOME=%s\n' "$HOME"
pwd
比對輸出是否符合預期的 macOS 使用者及其家目錄。若腳本以 sudo 或其他方式切換身份,也要確認切換發生在哪個步驟;切換使用者後,使用者鑰匙圈的可見範圍可能不同。Apple 對背景 Daemon、Agent 與登入工作階段的執行上下文有不同說明,應按實際啟動方式判斷,而非把圖形登入環境視為所有任務的共同上下文;詳見 Apple Daemons 與 Agents 技術說明。
| 比對項目 | 在 SSH 建置任務中記錄 | 異常時的下一步 |
|---|---|---|
| 執行帳戶 | id -un 的結果 |
檢查任務啟動設定及使用者切換 |
| 使用者家目錄 | HOME 的值 |
確認鑰匙圈查找範圍是否正確 |
| 任務類型 | 互動式 SSH、CI 或背景任務 | 按實際工作階段檢查鑰匙圈是否可用 |
如果需要先了解遠端連線方式與帳戶操作,可參考 NUKCLOUD 使用說明;但連得上主機不代表建置程序已取得正確的 macOS 使用者上下文。
02第二步:確認 macOS 鑰匙圈在任務執行時可用
使用者正確後,確認簽名身份所在的鑰匙圈,以及它在建置當下是否已解鎖。互動式桌面可能出現解鎖提示,但純 SSH 任務不能依賴視窗彈出後由人員按下確認。要檢查的是建置實際使用的鑰匙圈,而不是另一位使用者的鑰匙圈或不同登入工作階段中的狀態。
可在同一建置工作階段檢視使用者鑰匙圈清單與狀態:
security list-keychains -d user
security show-keychain-info "$KEYCHAIN_PATH"
其中 $KEYCHAIN_PATH 應由安全的任務設定提供,不能用真實密碼、憑證內容或主機資訊替換成公開範例。Apple DTS 提到 SSH 簽名失敗可能與鑰匙圈鎖定有關;這是排查方向,不是適用所有環境的修復指令。可對照 Apple 對鑰匙圈簽名身份的說明。
提醒:不要把鑰匙圈密碼寫入 Git 儲存庫、終端機命令列、公開腳本或建置記錄。診斷時只保留必要的帳戶與狀態資訊,並遮蔽憑證識別資料。
若鑰匙圈顯示已解鎖,仍需確認該身份包含匹配的憑證和私鑰,且建置程序有權使用私鑰。解鎖只代表鑰匙圈可讀,不等於 codesign 已獲准使用其中的私鑰;私鑰的使用授權和簽名身份內容應分開檢查。Apple 的憑證類型與保護建議可協助核對身份構成,但不應把某一種權限設定當成所有 SSH 建置的通用解法。
03第三步:依證據分流,不要先重建簽名資產
以下條件用來決定下一個檢查方向;若證據不符合其中任何一項,先保存錯誤記錄,再確認建置上下文與專案設定。
- 若圖形工作階段能簽名、SSH 不能:先回查任務帳戶、
HOME、實際鑰匙圈及其解鎖狀態;不要立即撤銷憑證。 - 若 SSH 工作階段看不到預期身份,或身份沒有對應私鑰:檢查匯入位置、身份完整性與私鑰可用權限,再判斷是否需要重新匯入正確資產。
- 若身份可見、鑰匙圈可用,但錯誤明確指向 Bundle ID、Team 或描述檔:才進入簽名設定檢查,核對專案識別資訊和 Provisioning Profile。
- 若 Archive 已完成、錯誤只出現在後續交付:轉查上傳階段,不要把它歸因於鑰匙圈或 CodeSign。
- 若同一錯誤在多個工作階段出現:保留首個錯誤及相關簽名輸出,繼續檢查身份完整性、憑證鏈或其他簽名證據;不要假設問題必然來自 SSH。
簽名身份問題和描述檔不匹配不是同一層。只有在錯誤輸出指向身份或應用識別資訊時,才核對憑證有效性、Bundle ID、Team 與 Profile。需要重新產生或下載描述檔時,可先參照 Apple 編輯、下載或刪除 Provisioning Profile 的說明;若涉及 Entitlements,使用 Apple 的 Entitlements 診斷指引檢查建置產物,避免在沒有證據時同時更換多項簽名資產。
04常見排查問題
為什麼 SSH 執行 xcodebuild 會出現 errSecInternalComponent?
這個錯誤可能與 SSH 或 CI 的非互動式簽名環境有關,也可能涉及鑰匙圈鎖定;它不是單一根因的證明。先定位 CodeSign 的首個錯誤,再比對任務帳戶、鑰匙圈與私鑰授權。若實際錯誤指向其他簽名設定,應按該證據繼續排查。
怎樣確認 SSH 建置任務用的是預期 macOS 使用者?
在建置任務本身輸出 id -un、HOME 和目前目錄,並與預期帳戶比較。CI 或背景任務可能使用不同的啟動上下文;因此,從互動式 SSH 工作階段看到的身份不能代替任務執行時的檢查。記錄時不要輸出密碼、私鑰或其他敏感內容。
鑰匙圈已解鎖,但 codesign 仍然失敗,下一步是什麼?
先確認解鎖的鑰匙圈屬於建置帳戶,且其中的簽名身份包含匹配憑證與私鑰。接著檢查 codesign 是否有權使用該私鑰;如身份重複、不完整或憑證鏈有異常,再依實際診斷結果處理,而非直接套用通用權限設定。
如何分辨鑰匙圈故障與憑證或 Provisioning Profile 不匹配?
GUI 成功而 SSH 失敗時,優先比較工作階段、帳戶、鑰匙圈及私鑰存取。若身份可用,而首個錯誤明確指向 Bundle ID、Team、Profile 或 Entitlements,才檢查專案和描述檔設定。兩類問題可能並存,因此應以實際簽名錯誤與 Archive 結果交叉確認。
05最後一步:在正式 SSH 上下文中驗收 Archive
完成調整後,以正式任務使用的帳戶、工作階段與建置參數重跑同一專案的代表性 Archive。不要只用圖形介面成功作為修復依據,因為它沒有驗證 SSH 任務取得鑰匙圈和私鑰的方式。
建置命令應沿用專案原有的 Scheme、目的地與設定,並用佔位值呈現敏感項目:
xcodebuild \
-project "<PROJECT_PATH>" \
-scheme "<SCHEME>" \
-destination "<DESTINATION>" \
-archivePath "<ARCHIVE_PATH>" \
archive
以上只是命令結構示例,不代表任何特定專案都可直接照搬參數。修復後確認 Archive 的建置狀態、簽名身份及產物中的 Entitlements;Apple 亦提供查看與診斷 Entitlements 的方法。若 Xcode 版本或簽名行為有疑問,再核對Apple Xcode 27 Release Notes,不要將其他版本的論壇個案直接視為目前環境的通用結論。
驗收完成後,記錄建置使用者、鑰匙圈位置、重現條件、首個失敗訊息與修復項目,並限制簽名憑據的存取範圍。請勿把密碼、Token、Team ID、Bundle ID、完整日誌或內部路徑直接放入公開報告;對外分享時應先遮蔽可識別資料。若本機已有穩定 Mac,且建置量持續、需要實體介面或由團隊長期控制硬體,自購或沿用本機設備可能更合適;反之,臨時購置硬體會增加前期成本、維護與閒置管理,雲端 CI 也未必提供符合專案需求的完整 macOS 簽名上下文。當問題已集中在遠端建置環境而非專案簽名資產時,可查看 NUKCLOUD 遠端 Mac 方案,先按 SSH 工作流程確認環境需求,再判斷租用是否比另購一台專用 Mac 更合適。