macOSアプリ用の自動アップデート管理ライブラリSparkleを入れたらCIでNotarizationが通らなくなった
Mac App Store外で配布されるmacOSアプリに自動アップデート機能を提供するライブラリとしてSparkleがよく使われています。
macOS向けのアプリの開発が軌道に乗ってきたので自動アップデート機能を使用したくなったのでSparkleを導入したところ、GitHub Actionsで動かしていたNotarization(公証)が動かなくなってしまいました。解決の糸口がなかなかつかめず、結構な時間を浪費したのでどう解決したか書いておきます。
そもそもNotarizationとは
Mac App Store外で配布されているアプリについて、Developer ID署名のほかにApple Notary Serviceにアプリバイナリを送信し、マルウェア等が含まれていない等のチェックを受けることとなります。2020年3月以降はGateKeeperにNotarizationされていないアプリは起動をGateKeeperに停められてしまいますので、事実上必須となっています。
CIビルドが通らなくなった状況
使用していたGitHub Actionsでは、以下のようにアプリをCIしていました。
- xcodebuild archive で xcarchive を作成
- xcodebuild -exportArchive で xcarchive から .app を出力
- .app を zip と dmg にアーカイブ
- zip と dmg をそれぞれ xcrun notarytool で送信
Sparkleを導入したあとはNotarizationの処理で以下のようなエラーが発生しました。
Successfully uploaded file
id: 00000000-0000-0000-0000-000000000000
path: /Users/runner/work/Ukam/Ukam/build/Ukam.dmg
Waiting for processing to complete.
Current status: In Progress...
Current status: In Progress....
Current status: In Progress.....
Current status: In Progress......
Current status: Invalid.......Processing complete
id: 00000000-0000-0000-0000-000000000000
status: Invalid
Notarizationのログを見る
Notarizationのログを見て問題を解決したいと思い、notarytool info で確認しようとしますが、Invalid以上の情報を得られず、エラーなのにログが何もない、みたいな状況になりました。
$ xcrun notarytool info 00000000-0000-0000-0000-000000000000 --keychain-profile ****
Successfully received submission info
createdDate: 2024-08-18T10:00:41.307Z
id: 00000000-0000-0000-0000-000000000000
name: Ukam.dmg
status: Invalid
notarytool の履歴を見る系統のコマンドとしては、一覧を見る history
概要を見る info
以外に、詳細ログを見る log
があります。log の存在を知らずに詳細な理由を調べることができずにいました。
$ xcrun notarytool log 00000000-0000-0000-0000-000000000000 --keychain-profile ***
{
"logFormatVersion": 1,
"jobId": "00000000-0000-0000-0000-000000000000",
"status": "Invalid",
"statusSummary": "Archive contains critical validation errors",
"statusCode": 4000,
"archiveFilename": "Ukam.dmg",
"uploadDate": "2024-08-18T10:00:43.421Z",
"sha256": "****",
"ticketContents": null,
"issues": [
{
"severity": "error",
"code": null,
"path": "Ukam.dmg/Ukam.app/Contents/MacOS/Ukam",
"message": "The signature of the binary is invalid.",
"docUrl": "https://developer.apple.com/documentation/security/notarizing_macos_software_before_distribution/resolving_common_notarization_issues#3087735",
"architecture": "x86_64"
},
{
"severity": "error",
"code": null,
"path": "Ukam.dmg/Ukam.app/Contents/MacOS/Ukam",
"message": "The signature of the binary is invalid.",
"docUrl": "https://developer.apple.com/documentation/security/notarizing_macos_software_before_distribution/resolving_common_notarization_issues#3087735",
"architecture": "arm64"
},
{
"severity": "error",
"code": null,
"path": "Ukam.dmg/Ukam.app/Contents/Frameworks/Sparkle.framework/Sparkle",
"message": "The signature of the binary is invalid.",
"docUrl": "https://developer.apple.com/documentation/security/notarizing_macos_software_before_distribution/resolving_common_notarization_issues#3087735",
"architecture": "x86_64"
},
{
"severity": "error",
"code": null,
"path": "Ukam.dmg/Ukam.app/Contents/Frameworks/Sparkle.framework/Sparkle",
"message": "The signature of the binary is invalid.",
"docUrl": "https://developer.apple.com/documentation/security/notarizing_macos_software_before_distribution/resolving_common_notarization_issues#3087735",
"architecture": "arm64"
}
]
}
exportOptions.plist を修正する
XcodeのUI上からアーカイブし、NotarizationまでをUIで行った場合はエラーなしに出力が成功することがわかり、exportArchiveの処理が原因だと見立てがつきました。
指定できる中で設定値が大きな変動がありそうなのはexportOptions.plistでしたので、この内容を見直すことにしました。
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>compileBitcode</key>
<true/>
<key>method</key>
<string>developer-id</string>
<key>signingCertificate</key>
<string>Developer ID Application</string>
<key>signingStyle</key>
<string>manual</string>
<key>teamID</key>
<string>******</string>
</dict>
</plist>
調べてみると、signingStyleにはautomaticというのがあるため、なるべく自動的に設定がされるように修正してみます。
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>method</key>
<string>developer-id</string>
<key>signingStyle</key>
<string>automatic</string>
</dict>
</plist>
ここまででdmgのアップデートは成功するようになっていましたが、zipのほうがまだ通りませんでした。
ZIPはdittoを使用する
ZIPアーカイブの作成には、元々zipコマンドを使用していました。
zip -r Ukam.zip Ukam.app
しかし、このように圧縮するとリソースフォークなどのmacOS特有の管理情報が欠落してしまいます。そのため、dittoコマンドを使用する必要があります。
/usr/bin/ditto -c -k --sequesterRsrc --keepParent Ukam.app Ukam.zip
これで、zipファイルでのNotarizationも通るようになりました。
参考サイト
紹介
別のディスプレイにあるウィンドウを、現在操作しているディスプレイに移動するアプリを作っています。よければ使ってみてください。
Discussion