公証の結果がInvalidになったときは、notarytool logで失敗の理由を調べる。提出のIDを指定すると、公証のログがJSONで表示される。ログのissuesに、問題のあるファイルとエラーメッセージが記録されている。
$ xcrun notarytool log [提出ID] --keychain-profile "[プロファイル名]"
実行例はXcode 27.0、macOS 27.0.1のもの。認証情報(--keychain-profile)は、事前にnotarytool store-credentialsで保存しておく。
- 前の記事: 【notarytool】アプリを公証してstaple(公証チケットを添付)する
- 親記事: GitHubを使い、macOSアプリを署名・公証・自動アップデート付きで公開する
- 次の記事: 【spctl】Gatekeeperの判定を配布前に確認する
提出のIDを調べる
ログの取得には、提出のID(Submission ID)が必要である。notarytool submit --waitの出力に表示されたidが、提出のIDである。
$ xcrun notarytool submit [アプリ名].zip --keychain-profile "[プロファイル名]" --wait
...
Current status: In Progress...Current status: In Progress....Current status: Invalid.....Processing complete
id: [提出ID]
status: Invalid
提出のIDを控えていない場合は、notarytool historyで過去の提出の一覧を表示して、status: Invalidの提出を探す。
$ xcrun notarytool history --keychain-profile "[プロファイル名]"
historyの使い方は、認証情報を保存する記事でも紹介している。
参考: 【notarytool】App用パスワードで公証用の認証情報を保存する
公証のログを取得する
notarytool logは、提出のIDを引数に取る。結果は整形されたJSONで、標準出力に表示される。ファイルへ保存するときは、提出のIDの後ろで出力先のパスを指定する。
$ xcrun notarytool log [提出ID] --keychain-profile "[プロファイル名]" log.json
Hardened Runtimeを無効のまま提出したアプリのログは、次のとおりである。
{
"logFormatVersion": 1,
"jobId": "[提出ID]",
"status": "Invalid",
"statusSummary": "Archive contains critical validation errors",
"statusCode": 4000,
"archiveFilename": "[アプリ名].zip",
"uploadDate": "[提出した日時]",
"sha256": "[zipのSHA-256]",
"ticketContents": null,
"issues": [
{
"severity": "error",
"code": null,
"path": "[アプリ名].zip/[アプリ名].app/Contents/MacOS/[アプリ名]",
"message": "The executable does not have the hardened runtime enabled.",
"docUrl": "https://developer.apple.com/documentation/security/notarizing_macos_software_before_distribution/resolving_common_notarization_issues#3087724",
"architecture": "arm64"
}
]
}
主な項目は次のとおりである。
| 項目 | 内容 |
|---|---|
status | 公証の結果。Invalidは失敗 |
statusSummary | 結果の要約。失敗ではArchive contains critical validation errors |
statusCode | 結果のコード。今回の検証では、成功が0、失敗が4000 |
ticketContents | 発行された公証チケットの内容。失敗ではnull |
issues | 見つかった問題の一覧。成功ではnull |
issuesの各要素には、次の項目が含まれる。
| 項目 | 内容 |
|---|---|
severity | 重大度。今回の検証ではerror |
path | 問題のあるファイルのパス。提出したzipの名前から始まる |
message | エラーメッセージ |
docUrl | Appleのドキュメントの該当箇所へのリンク |
architecture | 問題のあるバイナリのアーキテクチャ |
jqで問題を一覧にする
issuesが多いときは、jqで絞り込むと読みやすい。
$ jq -r '.issues[] | "\(.severity): \(.path): \(.message)"' log.json
error: [アプリ名].zip/[アプリ名].app/Contents/MacOS/[アプリ名]: The executable does not have the hardened runtime enabled.
よくある失敗とその対処法
公証がInvalidになる原因と、issuesに記録されるメッセージを紹介する。
Hardened Runtimeが有効でない
The executable does not have the hardened runtime enabled.
署名時にHardened Runtimeが有効になっていない。XcodeでHardened Runtimeを有効にして、アーカイブからやり直す。codesignで署名するときは、--options runtimeを付ける。
参考: 【Xcode】公証のためにHardened Runtimeを有効にする
セキュアタイムスタンプがない
The signature does not include a secure timestamp.
署名にセキュアタイムスタンプが含まれていない。codesignで署名するときは、--timestampを付ける。--timestamp=noneを指定すると、このエラーになる。
get-task-allowのentitlementが付いている
The executable requests the com.apple.security.get-task-allow entitlement.
デバッグ用のcom.apple.security.get-task-allowが、署名のentitlementsに含まれている。entitlementsから外して、署名し直す。署名後のentitlementsは、codesign -d --entitlements -で確認できる。
内部のバイナリに署名がない
アプリの内部にあるフレームワークや実行ファイルの署名が欠けていたり、無効だったりすると、そのバイナリごとにエラーが記録される。
The binary is not signed.
The signature of the binary is invalid.
SparkleのAutoupdateの署名を外して再署名したアプリを提出すると、次のように、内部のバイナリのパスとメッセージが一覧になる。
$ jq -r '.issues[] | "\(.severity)\t\(.path)\t\(.message)"' log.json
error [アプリ名].zip/[アプリ名].app/Contents/Frameworks/Sparkle.framework/Versions/B/Autoupdate The binary is not signed.
error [アプリ名].zip/[アプリ名].app/Contents/Frameworks/Sparkle.framework/Versions/B/Autoupdate The signature does not include a secure timestamp.
error [アプリ名].zip/[アプリ名].app/Contents/Frameworks/Sparkle.framework/Versions/B/Autoupdate The executable does not have the hardened runtime enabled.
error [アプリ名].zip/[アプリ名].app/Contents/Frameworks/Sparkle.framework/Versions/B/Sparkle The signature of the binary is invalid.
error [アプリ名].zip/[アプリ名].app/Contents/MacOS/[アプリ名] The signature of the binary is invalid.
同じ内容が、重複して記録される場合がある。内部のバイナリの署名を変更すると、外側のアプリの署名も無効になる。内部のバイナリから順に署名して、最後に外側のアプリに署名する。Xcodeのエクスポートであれば、内部のバイナリにも同じ署名が自動で付く。
対処したら、署名したアプリを提出し直す。再提出では、新しい提出のIDが発行される。
submitの終了コードは失敗でも0になる
notarytool submit --waitは、公証の結果がInvalidでも、終了コードが0である。
$ xcrun notarytool submit [アプリ名].zip --keychain-profile "[プロファイル名]" --wait > submit.out
$ echo $?
0
$ tail -2 submit.out
id: [提出ID]
status: Invalid
CIなどで公証の失敗を検出するときは、終了コードだけでは判定できない。notarytool infoをJSON形式で実行し、statusを確認する。
$ xcrun notarytool info [提出ID] --keychain-profile "[プロファイル名]" -f json
{"status":"Invalid","createdDate":"[提出した日時]","id":"[提出ID]","name":"[アプリ名].zip","message":"Successfully received submission info"}
$ xcrun notarytool info [提出ID] --keychain-profile "[プロファイル名]" -f json | jq -r .status
Invalid
statusがAcceptedでなければ、公証に失敗している。
公証されていないアプリにstapler stapleを実行すると、チケットが見つからず失敗する。終了コードは65である。公証の後にstapler stapleを続けて実行すると、公証の失敗を、ここで検出できる。
$ xcrun stapler staple [アプリ名].app
Processing: [アプリ名].app
CloudKit query for [アプリ名].app ([チケットの識別子]) failed due to "Record not found".
Could not find base64 encoded ticket in response for [チケットの識別子]
The staple and validate action failed! Error 65.
$ echo $?
65
