Skip to content

正式版 ad-hoc 簽章導致 macOS 權限(Accessibility/Mic/螢幕錄製)每次自動更新後失效 #75

Description

@yui0303

症狀 (Symptom)

正式版透過 update & restart(Tauri updater)更新後,voice typing 不能用:

  • macOS 系統設定 → 隱私權與安全性 → 輔助使用 裡 Parley 仍然顯示「已打勾」,但 app 內偵測為「未授權」。
  • cmd+Q 完全重開後依然如此。
  • fn 完全沒反應(HID event tap 因 AXIsProcessTrusted() 回 false 而無法安裝)。

實測發生在 update 到 v0.8.7 之後。

根因 (Root cause)

正式版是 ad-hoc 簽章src-tauri/tauri.conf.json 目前:

"signingIdentity": "-"

對已安裝的 /Applications/Parley.app 檢查:

$ codesign -dvvv /Applications/Parley.app
Identifier=com.pathors.parley
CDHash=c7c7d57dd2c79218fd0e3db03a84690e825d8629
Signature=adhoc
TeamIdentifier=not set

$ codesign -d --requirements - /Applications/Parley.app
# designated => cdhash H"c7c7d57dd2c79218fd0e3db03a84690e825d8629"

$ spctl -a -vvv /Applications/Parley.app
/Applications/Parley.app: rejected

關鍵:ad-hoc 簽章的 Designated Requirement 綁在 cdhash 上。macOS 的 TCC(Accessibility / Microphone / Screen Recording 等)是用 DR 來比對授權對象的。

為什麼每次更新都會壞

cdhash 是「該 build 二進位的雜湊」,每次 build 都不同。所以每次 update & restart 換成新二進位後:

  • 新 cdhash ≠ TCC 紀錄裡的舊 cdhash → DR 比對失敗 → AXIsProcessTrusted() 回 false。
  • 系統設定那條紀錄是用 bundle id / 路徑顯示,所以「看起來還打勾」,但實際失效。
  • → fn 不動、app 顯示未授權。Mic 與螢幕錄製同理(只是 Mic 會自動重新跳出請求,比較不明顯)。

這不是 bug 在偵測邏輯,是簽章策略的必然後果。

暫時解法 (Workaround,使用者每次更新都得做一次)

tccutil reset Accessibility com.pathors.parley

然後重開 Parley → 重新授權(會記錄新版 cdhash)→ cmd+Q 再重開。Mic / 螢幕錄製如有需要同樣重授權。

永久解法 (Fix) — 改成穩定簽章

DR 必須在版本之間穩定,授權才能跨更新保留。兩條路:

方案 A:Developer ID Application + 公證(建議)

  • DR 變成綁 Team ID + bundle identifier(anchor apple generic and identifier "com.pathors.parley" and certificate leaf[subject.OU] = <TeamID>),跨版本穩定 → 授權不再因更新失效。
  • 額外好處:Gatekeeper 乾淨(spctl accepted),第一次從網站下載安裝不再跳「無法驗證開發者」。
  • 成本:Apple Developer Program($99/年)。CI 需要的 secrets:APPLE_CERTIFICATE(.p12 base64)、APPLE_CERTIFICATE_PASSWORDAPPLE_SIGNING_IDENTITYAPPLE_IDAPPLE_PASSWORD(app-specific)、APPLE_TEAM_ID。tauri-action 原生支援。

方案 B:固定的自簽憑證(免費)

  • 在 CI 用一張固定的自簽 code-signing 憑證簽每個 release。DR 變成綁該憑證(identifier "…" and certificate leaf = H"<cert hash>"),只要每次都用同一張憑證 → 跨更新穩定 → 授權保留。
  • 這正是本專案 dev build 能跨重建保留授權的做法。
  • 限制:沒有公證,第一次從網站下載安裝仍會被 Gatekeeper 擋(要右鍵 → 打開)。但這跟現在 ad-hoc 一樣(spctl 本來就 rejected),不會更糟,而且換來「授權跨更新保留」。
  • CI secret:憑證 .p12(base64)+ 密碼。

建議

長期用 方案 A(順便解決 Gatekeeper)。若暫時不想付費 / 設公證,先上 方案 B 即可止血,因為它對第一次安裝體驗沒有比現況更差,卻能讓更新後不再掉權限。

驗收 (Acceptance criteria)

  • release 產出的 Parley.app 不再是 Signature=adhoc;codesign -d --requirements - 的 designated requirement 不再是 cdhash H"…"
  • 從 vN 透過 updater 更新到 vN+1 後,先前授予的 Accessibility 仍然有效(AXIsProcessTrusted() 回 true、fn 可用),不需重新授權。
  • [ ](方案 A)spctl -a -vvv Parley.app 回 accepted。

相關

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions