🗝️

macOSアプリ用の自動アップデート管理ライブラリSparkleを入れたらCIでNotarizationが通らなくなった

2024/08/19に公開

Mac App Store外で配布されるmacOSアプリに自動アップデート機能を提供するライブラリとしてSparkleがよく使われています。

https://sparkle-project.org/

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も通るようになりました。

参考サイト

紹介

別のディスプレイにあるウィンドウを、現在操作しているディスプレイに移動するアプリを作っています。よければ使ってみてください。

https://github.com/iseebi/Ukam
https://iseebi.hatenablog.com/entry/2024/08/11/001429

Discussion