Skip to content

Commit 06a3a1c

Browse files
committed
Update script for Notarization (#1132)
Update script for Notarization
1 parent a9d36cd commit 06a3a1c

4 files changed

Lines changed: 168 additions & 41 deletions

File tree

Dev/Mac/Effekseer.app/Contents/Info.plist

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,29 @@
33
"http://www.apple.com/DTDs/PropertyList-1.0.dtd">
44
<plist version="1.0">
55
<dict>
6+
<key>CFBundleDevelopmentRegion</key>
7+
<string>en</string>
8+
<key>CFBundleIdentifier</key>
9+
<string>com.effekseer.Effekseer</string>
610
<key>CFBundleExecutable</key>
711
<string>EffekseerLauncher</string>
12+
<key>CFBundleName</key>
13+
<string>Effekseer</string>
14+
<key>CFBundleDisplayName</key>
15+
<string>Effekseer</string>
16+
<key>CFBundlePackageType</key>
17+
<string>APPL</string>
18+
<key>CFBundleInfoDictionaryVersion</key>
19+
<string>6.0</string>
20+
<key>CFBundleShortVersionString</key>
21+
<string>1.73.0</string>
22+
<key>CFBundleVersion</key>
23+
<string>1.73.0</string>
824
<key>CFBundleIconFile</key>
925
<string>Icon.icns</string>
26+
<key>LSMinimumSystemVersion</key>
27+
<string>10.15</string>
28+
<key>NSPrincipalClass</key>
29+
<string>NSApplication</string>
1030
</dict>
1131
</plist>

Script/Notarization_Mac/Effekseer_cert.sh

Lines changed: 79 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -2,27 +2,85 @@
22
set -eu
33

44
profile="${2:-${NOTARYTOOL_PROFILE:-effekseer-notarytool}}"
5+
app_path="Effekseer/Effekseer.app"
6+
dmg_path="Effekseer.dmg"
7+
app_zip="Effekseer-app.zip"
8+
app_submit_out="$(mktemp "${TMPDIR:-/tmp}/effekseer-app-notarytool.XXXXXX")"
9+
dmg_submit_out="$(mktemp "${TMPDIR:-/tmp}/effekseer-dmg-notarytool.XXXXXX")"
10+
11+
trap 'rm -f "$app_zip" "$app_submit_out" "$dmg_submit_out"' EXIT
12+
13+
submit_and_log_failure() {
14+
artifact="$1"
15+
label="$2"
16+
profile="$3"
17+
output_log="$4"
18+
submit_out="$5"
19+
20+
if xcrun notarytool submit "$artifact" --keychain-profile "$profile" --wait >"$submit_out" 2>&1; then
21+
cat "$submit_out"
22+
return 0
23+
fi
24+
25+
echo "Notarization failed for $label" >&2
26+
cat "$submit_out" >&2
27+
28+
request_id=$(sed -n 's/.*id:[[:space:]]*//p' "$submit_out" | head -n 1)
29+
if [ -n "$request_id" ]; then
30+
echo "Downloading notarization log for $label: $output_log" >&2
31+
if xcrun notarytool log "$request_id" --keychain-profile "$profile" "$output_log" >/dev/null 2>&1; then
32+
echo "Saved notarization log: $output_log" >&2
33+
else
34+
echo "Failed to download notarization log for request $request_id" >&2
35+
fi
36+
else
37+
echo "Could not find a request ID in the notarytool output for $label" >&2
38+
fi
39+
40+
return 1
41+
}
542

643
echo "DevID $1 Profile $profile"
744

8-
for file in Effekseer/Effekseer.app/Contents/Resources/*.dylib ; do
9-
[ -f "$file" ] || continue
10-
echo codesign "$file"
11-
codesign --force --verify --verbose --sign "$1" "$file" --deep --options runtime --entitlements entitlements.plist --timestamp
12-
done
13-
14-
codesign --force --verify --verbose --sign "$1" "Effekseer/Effekseer.app/Contents/Resources/EffekseerMaterialEditor" --deep --options runtime --entitlements entitlements.plist --timestamp
15-
codesign --force --verify --verbose --sign "$1" "Effekseer/Effekseer.app/Contents/Resources/Effekseer" --deep --options runtime --entitlements entitlements.plist --timestamp
16-
codesign --force --verify --verbose --sign "$1" "Effekseer/Effekseer.app/Contents/Resources/tools/libfbxsdk.dylib" --deep --options runtime --entitlements entitlements.plist --timestamp
17-
codesign --force --verify --verbose --sign "$1" "Effekseer/Effekseer.app/Contents/Resources/tools/libEffekseerMaterialCompilerGL.dylib" --deep --options runtime --entitlements entitlements.plist --timestamp
18-
codesign --force --verify --verbose --sign "$1" "Effekseer/Effekseer.app/Contents/Resources/tools/mqoToEffekseerModelConverter" --deep --options runtime --entitlements entitlements.plist --timestamp
19-
codesign --force --verify --verbose --sign "$1" "Effekseer/Effekseer.app/Contents/Resources/tools/libEffekseerMaterialCompilerMetal.dylib" --deep --options runtime --entitlements entitlements.plist --timestamp
20-
codesign --force --verify --verbose --sign "$1" "Effekseer/Effekseer.app/Contents/Resources/tools/fbxToEffekseerModelConverter" --deep --options runtime --entitlements entitlements.plist --timestamp
21-
codesign --force --verify --verbose --sign "$1" "Effekseer/Effekseer.app/Contents/Resources/tools/fbxToEffekseerCurveConverter" --deep --options runtime --entitlements entitlements.plist --timestamp
22-
codesign --force --verify --verbose --sign "$1" "Effekseer/Effekseer.app/Contents/MacOS/EffekseerLauncher" --deep --options runtime --entitlements entitlements.plist --timestamp
23-
codesign --force --verify --verbose --sign "$1" "Effekseer/Effekseer.app" --deep --options runtime --entitlements entitlements.plist --timestamp
24-
25-
hdiutil create Effekseer.dmg -volname "Effekseer" -srcfolder "Effekseer"
26-
27-
codesign --force --verify --verbose --sign "$1" "Effekseer.dmg" --deep --options runtime --timestamp
28-
xcrun notarytool submit "Effekseer.dmg" --keychain-profile "$profile" --wait
45+
find "$app_path/Contents" -type f \( -name '*.dylib' -o -perm -u+x -o -perm -g+x -o -perm -o+x \) -exec sh -c '
46+
file="$1"
47+
sign_id="$2"
48+
echo "Signing $file"
49+
case "$file" in
50+
*.dylib)
51+
codesign --force --sign "$sign_id" --options runtime --timestamp "$file"
52+
;;
53+
*)
54+
codesign --force --sign "$sign_id" --options runtime --entitlements entitlements.plist --timestamp "$file"
55+
;;
56+
esac
57+
' sh {} "$1" \;
58+
59+
echo "Signing app bundle: $app_path"
60+
codesign --force --sign "$1" --options runtime --entitlements entitlements.plist --timestamp "$app_path"
61+
62+
echo "Verifying app bundle signature"
63+
codesign --verify --deep --strict --verbose=4 "$app_path"
64+
65+
echo "Creating zip for app notarization: $app_zip"
66+
ditto -c -k --keepParent "$app_path" "$app_zip"
67+
68+
echo "Notarizing app bundle archive: $app_zip"
69+
submit_and_log_failure "$app_zip" "app bundle" "$profile" "Effekseer-app-notarytool-log.json" "$app_submit_out"
70+
71+
echo "Stapling app bundle: $app_path"
72+
xcrun stapler staple "$app_path"
73+
74+
echo "Creating dmg from stapled app bundle: $dmg_path"
75+
hdiutil create "$dmg_path" -volname "Effekseer" -srcfolder "Effekseer"
76+
77+
echo "Signing dmg: $dmg_path"
78+
codesign --force --sign "$1" --timestamp "$dmg_path"
79+
80+
echo "Verifying dmg signature"
81+
codesign --verify --verbose=4 "$dmg_path"
82+
echo "Notarizing dmg: $dmg_path"
83+
submit_and_log_failure "$dmg_path" "dmg" "$profile" "Effekseer-dmg-notarytool-log.json" "$dmg_submit_out"
84+
85+
echo "Stapling dmg: $dmg_path"
86+
xcrun stapler staple "$dmg_path"

Script/Notarization_Mac/Effekseer_cert_post.sh

Lines changed: 0 additions & 4 deletions
This file was deleted.

Script/Notarization_Mac/README.md

Lines changed: 69 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,9 @@ This folder contains helper scripts for codesigning, notarizing, and stapling th
77
### Files
88

99
- `Effekseer_cert.sh`
10-
- Codesigns the app bundle and bundled executables, creates `Effekseer.dmg`, and submits it for notarization with `xcrun notarytool` using a Keychain profile.
10+
- Signs bundled executables that have any executable bit set with the app entitlements, signs `.dylib` files without entitlements, then signs the app bundle, creates a temporary zip for app notarization, creates `Effekseer.dmg`, and submits both for notarization with `xcrun notarytool` using a Keychain profile.
1111
- `Effekseer_cert_check.sh`
1212
- Checks the notarization status using the request ID with `xcrun notarytool` and the same Keychain profile.
13-
- `Effekseer_cert_post.sh`
14-
- Staples the notarization ticket to `Effekseer.dmg`.
1513
- `Effekseer_notarytool_setup.sh`
1614
- Stores App Store Connect credentials in the Keychain for later use by `notarytool`.
1715
- `Effekseer_notarytool_log.sh`
@@ -46,11 +44,7 @@ If you want to use a different profile name, pass it as the second argument or s
4644
sh Effekseer_cert.sh "Developer ID Application: Your Name (TEAMID)" "my-notary-profile"
4745
```
4846

49-
After notarization is approved, run:
50-
51-
```bash
52-
sh Effekseer_cert_post.sh
53-
```
47+
`Effekseer_cert.sh` now performs the full flow, including stapling both the app bundle and the DMG in the correct order.
5448

5549
If you want to check the request status:
5650

@@ -68,8 +62,39 @@ Notes:
6862

6963
- The scripts use `xcrun notarytool` and `xcrun stapler`.
7064
- `Effekseer_cert.sh` expects the app bundle and related tools to already be built and placed under `Effekseer/`.
65+
- `notarytool` does not accept a raw `.app` bundle, so the script creates a temporary zip archive for app notarization and removes it afterward.
7166
- `Effekseer_notarytool_setup.sh` is the only script that handles the App-specific password, and it stores that secret in the Keychain for reuse.
7267
- `Effekseer_notarytool_log.sh` is useful when `notarytool submit` returns a rejection and you need the JSON issue report.
68+
- When `Effekseer_cert.sh` fails, it writes notarization logs to `Effekseer-app-notarytool-log.json` or `Effekseer-dmg-notarytool-log.json` if a request ID can be recovered.
69+
- `Effekseer_cert.sh` now performs this full order: notarize app, staple app, create DMG from the stapled app, notarize DMG, staple DMG.
70+
- `Effekseer_cert.sh` signs bundled executables and `.dylib` files first, then signs the app bundle and the DMG.
71+
- If the app still shows the Gatekeeper warning, check whether the bundle was modified after signing or whether the quarantine attribute is still present.
72+
73+
### Troubleshooting
74+
75+
If the app cannot be opened on macOS, check these in order:
76+
77+
```bash
78+
codesign --verify --deep --strict --verbose=4 "Effekseer/Effekseer.app"
79+
spctl -a -t exec -vv "Effekseer/Effekseer.app"
80+
xcrun stapler validate "Effekseer/Effekseer.app"
81+
xcrun stapler validate "Effekseer.dmg"
82+
xattr -lr "Effekseer/Effekseer.app"
83+
```
84+
85+
What to look for:
86+
87+
- `codesign` errors usually mean something changed after signing, or a bundled file was not signed correctly.
88+
- If notarization complains about a specific bundled executable such as `createdump`, the leaf binary likely kept an ad hoc or incomplete signature. Re-sign the leaf binary before the app bundle.
89+
- `spctl` failures usually mean Gatekeeper does not trust the bundle as distributed.
90+
- `stapler validate` failures usually mean the notarization ticket was not attached to the app or DMG.
91+
- `com.apple.quarantine` in `xattr` output means the file still has a downloaded/quarantined state.
92+
93+
If the issue persists, check the Gatekeeper log:
94+
95+
```bash
96+
log show --last 1h --predicate 'process == "syspolicyd"'
97+
```
7398

7499
## 日本語
75100

@@ -78,11 +103,9 @@ Notes:
78103
### ファイル
79104

80105
- `Effekseer_cert.sh`
81-
- アプリ本体と同梱バイナリにコード署名を行い`Effekseer.dmg` を作成して `xcrun notarytool` で Notarization を申請します。
106+
- 実行ビットが付いた同梱ファイルには app の entitlements を付けて署名し、`.dylib` は entitlements なしで署名します。その後でアプリ本体に署名し`Effekseer.dmg` を作成して `xcrun notarytool` で Notarization を申請します。
82107
- `Effekseer_cert_check.sh`
83108
- Request ID を使って `xcrun notarytool` で Notarization の状況を確認します。
84-
- `Effekseer_cert_post.sh`
85-
- `Effekseer.dmg` に notarization ticket を stapling します。
86109
- `entitlements.plist`
87110
- 署名時に使用する entitlements です。
88111

@@ -113,11 +136,7 @@ sh Effekseer_cert.sh "Developer ID Application: Your Name (TEAMID)" "effekseer-n
113136
sh Effekseer_cert.sh "Developer ID Application: Your Name (TEAMID)" "my-notary-profile"
114137
```
115138

116-
Notarization が承認されたら、次を実行します。
117-
118-
```bash
119-
sh Effekseer_cert_post.sh
120-
```
139+
`Effekseer_cert.sh` が、app の stapling から DMG の作成・stapling までをまとめて実行します。
121140

122141
申請状況を確認したい場合は、次を使います。
123142

@@ -135,5 +154,39 @@ sh Effekseer_notarytool_log.sh "Request ID" "effekseer-notarytool" "notarytool_l
135154

136155
- スクリプトは `xcrun notarytool``xcrun stapler` を使用します。
137156
- `Effekseer_cert.sh` は、`Effekseer/` 配下にアプリ本体と関連ツールがすでに配置されていることを前提としています。
157+
- `notarytool``.app` 直送を受け付けないため、スクリプトは一時的に zip 化してから app を notarize し、終了後に削除します。
138158
- `Effekseer_notarytool_setup.sh` だけが App-specific password を扱い、その後はキーチェーン内の profile を再利用します。
139159
- `Effekseer_notarytool_log.sh` は、`notarytool submit` が拒否されたときの JSON 形式の issue report を確認するのに便利です。
160+
- `Effekseer_cert.sh` が失敗した場合、Request ID を取得できれば `Effekseer-app-notarytool-log.json` または `Effekseer-dmg-notarytool-log.json` にログを保存します。
161+
- `Effekseer_cert.sh` は、`app` を Notarization → staple → DMG 作成 → DMG Notarization → DMG staple の順で処理します。
162+
- `Effekseer_cert.sh` は、まず leaf バイナリを `--options runtime``--timestamp` 付きで署名し、その後に app bundle を署名します。
163+
- `Effekseer_cert.sh` は、`-perm -u+x -o -perm -g+x -o -perm -o+x` で拾える実行ビット付きファイルを署名対象にします。
164+
- `Effekseer_cert.sh` は、`Effekseer` のような Rosetta 下で動く leaf 実行ファイルに `com.apple.security.cs.allow-jit` などの entitlements を付けます。
165+
- 起動できない場合は、署名の破損、Gatekeeper の拒否、quarantine 属性の残存を順に確認してください。
166+
167+
### 問題調査
168+
169+
アプリが起動できないときは、次の順で調べると原因を絞りやすいです。
170+
171+
```bash
172+
codesign --verify --deep --strict --verbose=4 "Effekseer/Effekseer.app"
173+
spctl -a -t exec -vv "Effekseer/Effekseer.app"
174+
xcrun stapler validate "Effekseer/Effekseer.app"
175+
xcrun stapler validate "Effekseer.dmg"
176+
xattr -lr "Effekseer/Effekseer.app"
177+
```
178+
179+
見方:
180+
181+
- `codesign` で失敗する場合は、署名後に中身が変わっているか、同梱ファイルの署名が不完全です。
182+
- `.NET` ベースの実行ファイルが起動直後に `EXC_BAD_ACCESS` で落ちる場合は、その実行ファイルに app entitlements が付いているか確認してください。`Effekseer` のような Rosetta 変換された leaf プロセスは、`allow-jit` などがないと起動時にクラッシュすることがあります。
183+
- `createdump` のような同梱バイナリで notarization が止まる場合は、leaf バイナリの署名が ad hoc のままか、Developer ID 署名・timestamp・hardened runtime のいずれかが不足しています。app bundle の前に leaf バイナリを再署名してください。
184+
- `spctl` で失敗する場合は、Gatekeeper が配布物を許可していません。
185+
- `stapler validate` で失敗する場合は、app または dmg に notarization ticket が付いていません。
186+
- `xattr``com.apple.quarantine` が残っている場合は、ダウンロード由来の quarantine が効いています。
187+
188+
さらに詳しく見る場合は、Gatekeeper のログを確認します。
189+
190+
```bash
191+
log show --last 1h --predicate 'process == "syspolicyd"'
192+
```

0 commit comments

Comments
 (0)