症狀 (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 目前:
對已安裝的 /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_PASSWORD、APPLE_SIGNING_IDENTITY、APPLE_ID、APPLE_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)
相關
症狀 (Symptom)
正式版透過 update & restart(Tauri updater)更新後,voice typing 不能用:
cmd+Q完全重開後依然如此。AXIsProcessTrusted()回 false 而無法安裝)。實測發生在 update 到 v0.8.7 之後。
根因 (Root cause)
正式版是 ad-hoc 簽章。
src-tauri/tauri.conf.json目前:對已安裝的
/Applications/Parley.app檢查:關鍵:ad-hoc 簽章的 Designated Requirement 綁在 cdhash 上。macOS 的 TCC(Accessibility / Microphone / Screen Recording 等)是用 DR 來比對授權對象的。
為什麼每次更新都會壞
cdhash是「該 build 二進位的雜湊」,每次 build 都不同。所以每次 update & restart 換成新二進位後:AXIsProcessTrusted()回 false。這不是 bug 在偵測邏輯,是簽章策略的必然後果。
暫時解法 (Workaround,使用者每次更新都得做一次)
然後重開 Parley → 重新授權(會記錄新版 cdhash)→
cmd+Q再重開。Mic / 螢幕錄製如有需要同樣重授權。永久解法 (Fix) — 改成穩定簽章
DR 必須在版本之間穩定,授權才能跨更新保留。兩條路:
方案 A:Developer ID Application + 公證(建議)
anchor apple generic and identifier "com.pathors.parley" and certificate leaf[subject.OU] = <TeamID>),跨版本穩定 → 授權不再因更新失效。spctlaccepted),第一次從網站下載安裝不再跳「無法驗證開發者」。APPLE_CERTIFICATE(.p12 base64)、APPLE_CERTIFICATE_PASSWORD、APPLE_SIGNING_IDENTITY、APPLE_ID、APPLE_PASSWORD(app-specific)、APPLE_TEAM_ID。tauri-action 原生支援。方案 B:固定的自簽憑證(免費)
identifier "…" and certificate leaf = H"<cert hash>"),只要每次都用同一張憑證 → 跨更新穩定 → 授權保留。spctl本來就 rejected),不會更糟,而且換來「授權跨更新保留」。建議
長期用 方案 A(順便解決 Gatekeeper)。若暫時不想付費 / 設公證,先上 方案 B 即可止血,因為它對第一次安裝體驗沒有比現況更差,卻能讓更新後不再掉權限。
驗收 (Acceptance criteria)
Parley.app不再是Signature=adhoc;codesign -d --requirements -的 designated requirement 不再是cdhash H"…"。AXIsProcessTrusted()回 true、fn 可用),不需重新授權。spctl -a -vvv Parley.app回 accepted。相關
src-tauri/src/hotkey.rs(fn HID tap,gated onAXIsProcessTrusted/CGPreflightListenEventAccess)