一條封存流水線可能已經穩定執行數月,卻仍將建置帳號、儲存庫目錄,甚至暫存工作區名稱寫入產物。常見痕跡包括 /Users/runner/、DerivedData、掛載磁碟區路徑,以及原始碼檔案的完整位置。這些資訊通常不會直接影響 App 行為,卻會向取得安裝套件、符號檔或日誌的人暴露內部結構。雲端 Mac 會由不同任務反覆使用,因此更應將路徑檢查納入發佈前的固定流程,而不是偶爾執行一次字串搜尋。
先界定需要檢查的產物範圍
一次 Xcode 封存至少要區分三類物件:準備發佈的 .app、留在團隊內部的 .dSYM,以及流水線日誌。這些物件的風險不能混為一談。
可發佈 App 中若出現真實使用者目錄,應列為高優先等級處理。dSYM 記錄原始碼路徑是除錯資訊的一部分,不應只因看到路徑就刪除;真正的問題在於檔案遭到錯誤公開,或路徑包含不應外流的任務識別資訊。日誌的暴露程度取決於讀取權限和保留期限,但仍不應長期保存暫存憑證目錄與個人使用者名稱。
| 物件 | 典型路徑來源 | 建議處置 |
|---|---|---|
| App 執行檔 | 斷言、除錯字串、產生的程式碼 | 命中真實本機路徑時阻擋 |
| dSYM | DWARF 編譯目錄與原始碼路徑 | 對前綴進行映射並重新驗證符號化 |
| 建置日誌 | 命令回顯、指令碼、工具輸出 | 去識別化後限制保留期限 |
| 測試附件 | 螢幕截圖、診斷套件、結果套件 | 單獨檢查後再封存 |
路徑稽核的目的不是消除所有除錯資訊,而是避免將建置機器的真實目錄結構帶入不需要這些資訊的發佈邊界。
從乾淨的封存檔開始掃描
先固定封存路徑,避免掃描指令碼本身產生隨機目錄。Release 設定應由流水線明確傳入,不要依賴開發機上一次選取的 Scheme 狀態。
set -euo pipefail
ARCHIVE="$PWD/output/App.xcarchive"
rm -rf "$ARCHIVE"
xcodebuild archive \
-workspace App.xcworkspace \
-scheme App \
-configuration Release \
-destination 'generic/platform=iOS' \
-archivePath "$ARCHIVE"
找到 App 的主要執行檔後,使用系統內建的 strings 搜尋高價值特徵。除了 /Users/,也應檢查 /Volumes/、DerivedData、.xcworkspace,以及團隊實際使用的暫存目錄前綴。
APP="$ARCHIVE/Products/Applications/App.app"
EXEC=$(/usr/libexec/PlistBuddy -c 'Print :CFBundleExecutable' "$APP/Info.plist")
BIN="$APP/$EXEC"
REPORT="$PWD/output/app-paths.txt"
strings -a "$BIN" |
grep -E '/Users/|/Volumes/|DerivedData|\.xcworkspace|\.xcodeproj' \
> "$REPORT" || true
if [ -s "$REPORT" ]; then
cat "$REPORT"
exit 1
fi
主程式通過檢查,不代表整個套件都沒有問題。還要逐一掃描內嵌 framework、擴充功能和資源檔案。掃描報告應記錄「檔案路徑、比對內容、產物類型」,但不要將完整二進位檔或環境變數直接上傳至日誌。
單獨檢查 dSYM
檢查 dSYM 時,重點應放在 DW_AT_comp_dir 與原始碼檔案記錄,而不是一般字串的數量。先找出 DWARF 檔案,再輸出可能指向真實工作區的項目。
DSYM="$ARCHIVE/dSYMs/App.app.dSYM"
DWARF="$DSYM/Contents/Resources/DWARF/App"
xcrun dwarfdump --debug-info "$DWARF" |
grep -E 'DW_AT_(comp_dir|decl_file).*("/Users/|"/Volumes/)' \
> "$PWD/output/dsym-paths.txt" || true
xcrun dwarfdump --uuid "$DWARF"
UUID 必須與封存檔中的執行檔相符。若兩者不一致,即使路徑處理正確,後續也無法可靠地還原當機位址。
使用編譯前綴映射收斂真實目錄
Swift 編譯器可透過 -debug-prefix-map 將工作區前綴替換為穩定的邏輯目錄;Clang 則使用 -fdebug-prefix-map。可分別在 Xcode 的 Release 設定中加入:
OTHER_SWIFT_FLAGS = $(inherited) -debug-prefix-map $(SRCROOT)=/src
OTHER_CFLAGS = $(inherited) -fdebug-prefix-map=$(SRCROOT)=/src
OTHER_CPLUSPLUSFLAGS = $(inherited) -fdebug-prefix-map=$(SRCROOT)=/src
不要直接映射整個 /Users。範圍過大的規則可能掩蓋外部相依套件的來源,也可能讓不同目錄意外對應到同一個邏輯路徑。應優先映射 $(SRCROOT);若相依套件的簽出目錄固定,再為該目錄加入獨立規則。
完成映射後必須重新封存,不能只修改建置設定後沿用舊的 DerivedData。也要確認編譯命令確實帶有相關參數,因為部分自訂指令碼會略過專案設定,直接呼叫編譯器。
對誤報分級,而不是全部放行
掃描經常會命中資源中的範例路徑、測試夾具或第三方除錯文字。處理方式應依據所在位置與可達性決定,而不是維護一份不斷擴張的全域忽略詞清單。
建議設定三級結果:
- 發佈 App 或內嵌元件中出現目前建置機的真實前綴,直接判定失敗。
- dSYM 中出現未映射的原始碼前綴,標記為失敗,但保留檔案以供診斷。
- 內部日誌或測試結果套件中出現路徑時,產生警告並檢查存取範圍。
白名單應精確到「檔案 + 規則運算式 + 原因」。例如,某個測試資源確實需要顯示 /Users/example/,可以只豁免該項資源;不要將整個 /Users/ 加入忽略清單。流水線也應將目前的工作區路徑設為動態禁止項目,這比猜測所有可能的使用者名稱更可靠。
避免掃描指令碼洩漏更多資訊
報告可將真實前綴替換為 $WORKSPACE,只保留相對路徑與命中類型。命令失敗時也不要輸出完整環境。若必須保留原始報告,應將其作為受限的建置附件,而不是直接展開至所有成員都能讀取的主控台輸出。
發佈前重新驗證符號化能力
路徑映射能通過掃描,不代表除錯鏈路仍然完整。發佈前至少應保存 App、dSYM、UUID 清單和建置提交識別碼,並選取一個真實指令位址執行符號化測試。驗證結果應能傳回函式名稱和原始碼檔案的邏輯路徑 /src/...,而不是只顯示十六進位位址。
最終門檻可歸納為四項:App 內不含真實工作區前綴;dSYM UUID 與二進位檔一致;映射後的原始碼路徑可正確識別;日誌不展開原始掃描內容。這樣既能縮小目錄資訊的暴露面,也能保留定位線上故障所需的證據。
路徑稽核適合在 VMOrbit 雲端 Mac 的封存任務完成後立即執行。它不依賴固定的使用者名稱,也不要求修改原始碼目錄結構;只要工作區根路徑由流水線統一提供,同一套規則就能涵蓋暫存任務與長期建置節點。
常見問題
App 中出現 /Users/ 路徑就一定是安全漏洞嗎?
不一定,但可能暴露建置帳號、目錄結構或專案名稱。應先確認它位於可散佈 App、除錯符號或內部日誌,再依暴露範圍分級。
使用 debug-prefix-map 後還需要保留 dSYM 嗎?
需要。前綴映射只改變除錯資訊中的路徑表示,不能取代 dSYM。發佈前仍應保存 dSYM 並完成一次符號化複驗。
路徑掃描應該阻擋所有建置嗎?
建議阻擋可散佈 App 中的真實本機路徑;dSYM 與內部日誌則先列為警告並人工複核,避免合理除錯資訊造成誤判。
將建置工作交給獨享雲端 Mac
選擇 VMOrbit M4 或 VMOrbit M4 Pro,並依團隊所在位置選擇節點。實際可用性與交付資訊以控制台即時回傳結果為準。