Skip to content

Commit 2ec7a2e

Browse files
DeckerSUCharlVS
andauthored
chore(build): Add macOS production scheme and Developer ID Application signing support for standalone distribution (#3185)
* change product bundle identifier (com.komodo.wallet) * Set sdk submodule to chore/sdk-universal-macos-cdn-pods #3175 * XCode: add production scheme and corresponding configurations * make Release-production sign with Developer ID Application * sdk: temp following submodules for patch-macos-release-profile new https://github.com/KomodoPlatform/komodo-defi-sdk-flutter/tree/patch-macos-release-profile branch for macos Developer ID Application release preparations. * sdk: update submodules * add OTHER_CODE_SIGN_FLAGS --options=runtime --timestamp * fix developement team for Release-production after this - kdf binary is signed (but still without timestamp) * fix codesigning for Pods (now CP-User signing in Pods receive correct env) 'Release-production'=> :release, - CocoaPods will create this config in Pods project * add --options=runtime --timestamp for codesigning pods * sdk: pin version with code_sign_if_enabled in cp-user sh script * sdk: bump to new location of KDF binary under MacOS * macos: XCode project update / Pods_Runner.framework in Frameworks * build(macos): set CODE_SIGN_INJECT_BASE_ENTITLEMENTS to NO for Release need to remove below from Entitlements "com.apple.security.get-task-allow" = 1; To check: codesign -d --entitlements :- "build/macos/Build/Products/Release-production/Komodo Wallet.app" | plutil -p - Read more: https://developer.apple.com/documentation/security/resolving-common-notarization-issues#3087731 * update .gitignore to exclude dist/ directory * feat: add make-dmg.sh script for building DMG files on macOS This script automates the process of creating a DMG file for the Komodo Wallet application, including setting up the Finder layout and handling background images. It requires macOS and utilizes hdiutil, osascript, and ditto for the operations. * feat: add test-sign-timestamp.sh script for verifying code signing and timestamping on macOS This script checks the code signing and timestamping of the Komodo Wallet application, providing feedback on the presence of timestamps and the authority of the timestamping service. It simplifies the verification process for macOS app builds. * feat: enhance make-dmg.sh script with default app path and usage instructions * chore: update Podfile.lock to include device_info_plus and update dependencies * chore: update subproject commit reference in sdk * feat: add README.md for contrib scripts and enhance test-sign-timestamp.sh * chore(sdk): roll submodule to latest dev - Update .gitmodules to track dev - Sync sdk to origin/dev --------- Co-authored-by: Nitride <[email protected]>
1 parent 92d5140 commit 2ec7a2e

File tree

10 files changed

+902
-51
lines changed

10 files changed

+902
-51
lines changed

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,3 +82,5 @@ venv/
8282
.fvm/
8383
/macos/build
8484
AGENTS_1.md
85+
# .dmg Release
86+
dist/

contrib/README.md

Lines changed: 147 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,147 @@
1+
# Contrib Scripts
2+
3+
This directory contains utility scripts for building, packaging, and testing the Komodo Wallet application.
4+
5+
## Scripts Overview
6+
7+
### `make-dmg.sh`
8+
Creates a professional DMG installer for macOS applications.
9+
10+
**Purpose:** Builds a disk image (.dmg) file with proper layout for distributing macOS applications.
11+
12+
**Features:**
13+
- Creates a disk image with the application bundle
14+
- Adds a shortcut to the Applications folder
15+
- Supports custom background images
16+
- Configures proper Finder window layout and icon positioning
17+
- Compresses the final output
18+
19+
**Usage:**
20+
```bash
21+
# Use default app path
22+
./make-dmg.sh
23+
24+
# Or specify custom parameters
25+
APP="build/.../Komodo Wallet.app" \
26+
VOL="Komodo Wallet" \
27+
OUT="dist/KomodoWallet.dmg" \
28+
BG="assets/dmg_background.png" \
29+
./make-dmg.sh
30+
```
31+
32+
**Default Parameters:**
33+
- `APP`: `build/macos/Build/Products/Release-production/Komodo Wallet.app`
34+
- `VOL`: `Komodo Wallet`
35+
- `OUT`: `dist/KomodoWallet.dmg`
36+
- `BG`: (optional background image)
37+
- `ICON_SIZE`: `128`
38+
- `WIN_W`: `530` (Finder window width)
39+
- `WIN_H`: `400` (Finder window height)
40+
41+
**Requirements:** macOS, hdiutil, osascript, ditto
42+
43+
---
44+
45+
### `test-sign-timestamp.sh`
46+
Checks code signing and timestamping for macOS applications.
47+
48+
**Purpose:** Verifies that all executable Mach-O files in the app bundle are properly signed and timestamped.
49+
50+
**Features:**
51+
- Scans all executable files in the app bundle
52+
- Checks for valid code signatures
53+
- Verifies timestamping (Apple's timestamp authority)
54+
- Provides colored output for easy reading
55+
- Reports missing timestamps
56+
57+
**Usage:**
58+
```bash
59+
# Use default app path
60+
./test-sign-timestamp.sh
61+
62+
# Or specify custom app path
63+
./test-sign-timestamp.sh "path/to/your/app.app"
64+
```
65+
66+
**Default App Path:** `build/macos/Build/Products/Release-production/Komodo Wallet.app`
67+
68+
**Requirements:** macOS, codesign utility
69+
70+
71+
## Release Build and Notarization Process for macOS (Non-App Store Distribution)
72+
73+
To build and notarize the macOS app for release (for distribution outside the Mac App Store), follow these steps.
74+
Note: The `--flavor production` flag is mandatory in the build command to ensure correct provisioning for signing with a Developer ID Application certificate and for proper notarization/distribution outside the App Store.
75+
76+
```bash
77+
# 1. Clean the project and fetch dependencies
78+
flutter clean
79+
flutter pub get --enforce-lockfile
80+
pushd macos; pod deintegrate; pod install; popd # Generating Pods project
81+
82+
# 2. Fetch all required artifacts (this runs komodo_wallet_build_transformer)
83+
flutter build web --no-pub -v
84+
85+
# 3. Build the macOS release application (ensure --flavor production is present)
86+
flutter build macos --no-pub --release -v \
87+
--dart-define=COMMIT_HASH=<hash> \
88+
--dart-define=FEEDBACK_API_KEY=<key> \
89+
--dart-define=FEEDBACK_PRODUCTION_URL=<url> \
90+
--dart-define=TRELLO_BOARD_ID=<id> \
91+
--dart-define=TRELLO_LIST_ID=<id> \
92+
--dart-define=MATOMO_URL=<url> \
93+
--dart-define=MATOMO_SITE_ID=<id> \
94+
--flavor production
95+
```
96+
Replace the `<...>` placeholders above with your actual values.
97+
98+
To view app entitlements used in the resulting .app:
99+
```bash
100+
codesign -d --entitlements :- "build/macos/Build/Products/Release-production/Komodo Wallet.app" | plutil -p -
101+
```
102+
103+
Package the application bundle as a ZIP archive (required by notary service):
104+
```bash
105+
APP="build/macos/Build/Products/Release-production/Komodo Wallet.app"
106+
ZIP="KomodoWallet.zip"
107+
ditto -c -k --keepParent "$APP" "$ZIP"
108+
```
109+
110+
Submit the ZIP archive to Apple Notary Service:
111+
```bash
112+
xcrun notarytool submit "$ZIP" --keychain-profile "AC_NOTARY" --wait
113+
```
114+
115+
Check notarization status for a specific request:
116+
```bash
117+
xcrun notarytool info <REQUEST_ID> \
118+
--apple-id "<apple_id_email>" \
119+
--team-id "<TEAM_ID>" \
120+
--password "<app-specific-password>"
121+
```
122+
123+
Download notarization log:
124+
```bash
125+
xcrun notarytool log <REQUEST_ID> --keychain-profile AC_NOTARY > notarization_errors.json
126+
```
127+
128+
If there were no errors and the submission status was `Accepted`, you can proceed with the following steps to staple and validate the app:
129+
130+
```bash
131+
xcrun stapler staple "$APP"
132+
xcrun stapler validate "$APP"
133+
spctl --assess --type execute -vv "$APP" # now the status should be accepted
134+
```
135+
136+
137+
138+
139+
140+
141+
142+
143+
144+
145+
146+
147+

contrib/make-dmg.sh

Lines changed: 228 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,228 @@
1+
#!/usr/bin/env bash
2+
# make_dmg.sh — Build DMG with layout «App ⇢ Applications»
3+
#
4+
# This script creates a professional DMG installer for macOS applications.
5+
# It creates a disk image with:
6+
# - The application bundle
7+
# - A shortcut to Applications folder
8+
# - Custom background image (optional)
9+
# - Proper Finder window layout and icon positioning
10+
# - Compressed final output
11+
#
12+
# Requires: macOS, hdiutil, osascript, ditto.
13+
14+
set -euo pipefail
15+
16+
# ------------------------ PARAMETERS ------------------------
17+
# Default app path
18+
DEFAULT_APP="build/macos/Build/Products/Release-production/Komodo Wallet.app"
19+
20+
APP="${APP:-$DEFAULT_APP}" # Path to .app (uses default if not specified)
21+
VOL="${VOL:-Komodo Wallet}" # Volume/window name for DMG
22+
OUT="${OUT:-dist/KomodoWallet.dmg}" # Path to output .dmg
23+
BG="${BG:-}" # Path to PNG background (optional)
24+
ICON_SIZE="${ICON_SIZE:-128}" # Icon size
25+
WIN_W="${WIN_W:-530}" # Finder window width in DMG
26+
WIN_H="${WIN_H:-400}" # Finder window height in DMG
27+
APP_X="${APP_X:-120}" # .app icon position (x)
28+
APP_Y="${APP_Y:-200}" # .app icon position (y)
29+
APPS_X="${APPS_X:-400}" # Applications shortcut position (x)
30+
APPS_Y="${APPS_Y:-200}" # Applications shortcut position (y)
31+
32+
usage() {
33+
cat <<EOF
34+
Usage:
35+
# Use default app path
36+
./make_dmg.sh
37+
38+
# Or specify custom parameters
39+
APP="build/.../Komodo Wallet.app" \\
40+
VOL="Komodo Wallet" \\
41+
OUT="dist/KomodoWallet.dmg" \\
42+
BG="assets/dmg_background.png" \\
43+
./make_dmg.sh
44+
45+
Default APP path: $DEFAULT_APP
46+
EOF
47+
}
48+
[[ ! -d "${APP}" ]] && { echo >&2 "ERROR: .app not found: ${APP}"; exit 1; }
49+
50+
APP_BASENAME="$(basename "${APP}")"
51+
OUT_DIR="$(dirname "${OUT}")"
52+
mkdir -p "${OUT_DIR}"
53+
54+
# Work in local tmp inside project — fewer TCC issues
55+
TMPROOT="${TMPROOT:-$PWD/.dmg_tmp}"
56+
mkdir -p "$TMPROOT"
57+
TMPDIR="$(mktemp -d "$TMPROOT/tmp.XXXXXXXX")"
58+
STAGING="${TMPDIR}/staging"
59+
mkdir -p "${STAGING}"
60+
61+
cleanup() {
62+
set +e
63+
if [[ -n "${MOUNT_POINT:-}" && -d "${MOUNT_POINT:-}" ]]; then
64+
hdiutil detach "${MOUNT_POINT}" -quiet || true
65+
fi
66+
rm -rf "${TMPDIR}" >/dev/null 2>&1 || true
67+
}
68+
trap cleanup EXIT
69+
70+
echo "==> Preparing staging"
71+
cp -R "${APP}" "${STAGING}/"
72+
ln -s /Applications "${STAGING}/Applications"
73+
74+
if [[ -n "${BG}" ]]; then
75+
echo "==> Adding background ${BG}"
76+
mkdir -p "${STAGING}/.background"
77+
cp "${BG}" "${STAGING}/.background/background.png"
78+
chflags hidden "${STAGING}/.background" || true
79+
fi
80+
81+
# --------- IMAGE SIZE CALCULATION (with margin) ----------
82+
echo "==> Estimating image size"
83+
# Staging size in kilobytes
84+
SIZE_KB=$(du -sk "${STAGING}" | awk '{print $1}')
85+
# Add ~30% margin + minimum 20 MB
86+
HEADROOM_KB=$(( SIZE_KB / 3 ))
87+
[[ ${HEADROOM_KB} -lt 20480 ]] && HEADROOM_KB=20480
88+
TOTAL_KB=$(( SIZE_KB + HEADROOM_KB ))
89+
# Round to megabytes
90+
TOTAL_MB=$(( (TOTAL_KB + 1023) / 1024 ))
91+
echo " Estimated size: ${TOTAL_MB} MiB"
92+
93+
TMP_DMG="${TMPDIR}/tmp.dmg"
94+
FINAL_DMG="${OUT}"
95+
96+
echo "==> Creating empty RW DMG (${TOTAL_MB} MiB)"
97+
hdiutil create -verbose \
98+
-size "${TOTAL_MB}m" \
99+
-fs HFS+J -volname "${VOL}" \
100+
"${TMP_DMG}"
101+
102+
# if volume with same name is mounted — unmount it
103+
if [[ -d "/Volumes/${VOL}" ]]; then
104+
hdiutil detach "/Volumes/${VOL}" -force -quiet || true
105+
fi
106+
107+
echo "==> Mounting DMG"
108+
MOUNT_POINT="${TMPDIR}/mnt"
109+
mkdir -p "${MOUNT_POINT}"
110+
111+
# Mount directly to our directory
112+
if ! hdiutil attach "${TMP_DMG}" \
113+
-readwrite -noverify -noautoopen \
114+
-mountpoint "${MOUNT_POINT}" >/dev/null; then
115+
echo >&2 "ERROR: failed to mount DMG (attach returned error)"
116+
exit 1
117+
fi
118+
119+
# Check that it's actually mounted
120+
if [[ ! -d "${MOUNT_POINT}" || ! -e "${MOUNT_POINT}/." ]]; then
121+
echo >&2 "ERROR: failed to mount DMG (mountpoint not accessible)"
122+
exit 1
123+
fi
124+
echo " Mounted at: ${MOUNT_POINT}"
125+
126+
# --------- CONTENT COPYING (DITTO) ----------
127+
echo "==> Copying content to volume (ditto)"
128+
# Application
129+
ditto "${STAGING}/${APP_BASENAME}" "${MOUNT_POINT}/${APP_BASENAME}"
130+
# Applications shortcut (recreate on volume side)
131+
rm -f "${MOUNT_POINT}/Applications" 2>/dev/null || true
132+
ln -s /Applications "${MOUNT_POINT}/Applications"
133+
# Background (if exists)
134+
if [[ -f "${STAGING}/.background/background.png" ]]; then
135+
mkdir -p "${MOUNT_POINT}/.background"
136+
ditto "${STAGING}/.background/background.png" "${MOUNT_POINT}/.background/background.png"
137+
chflags hidden "${MOUNT_POINT}/.background" || true
138+
fi
139+
140+
# --------- FINDER WINDOW STYLING ----------
141+
echo "==> Setting up Finder layout"
142+
sleep 2 # give Finder a bit more time to see the mounted volume
143+
osascript <<OSAEOF
144+
set mpPOSIX to "$MOUNT_POINT"
145+
set appName to "$APP_BASENAME"
146+
147+
tell application "Finder"
148+
activate
149+
set mp to (POSIX file mpPOSIX) as alias
150+
151+
-- Open and get real window
152+
open mp
153+
delay 0.5
154+
set w to window 1
155+
try
156+
set target of w to (folder mp)
157+
end try
158+
159+
-- Window parameters
160+
try
161+
tell w
162+
set current view to icon view
163+
set toolbar visible to false
164+
set statusbar visible to false
165+
set bounds to {100, 100, 100 + $WIN_W, 100 + $WIN_H}
166+
end tell
167+
end try
168+
169+
-- Icon options
170+
try
171+
set vo to the icon view options of w
172+
try
173+
set arrangement of vo to not arranged
174+
end try
175+
try
176+
set icon size of vo to $ICON_SIZE
177+
end try
178+
end try
179+
180+
-- Background (if possible — great; if not — just skip)
181+
try
182+
set bgAlias to (POSIX file (mpPOSIX & "/.background/background.png")) as alias
183+
set background picture of (the icon view options of w) to bgAlias
184+
end try
185+
186+
-- Icon positions
187+
try
188+
set position of item appName of (folder mp) to {$APP_X, $APP_Y}
189+
end try
190+
try
191+
set position of item "Applications" of (folder mp) to {$APPS_X, $APPS_Y}
192+
end try
193+
194+
try
195+
update without registering applications
196+
end try
197+
198+
delay 0.6
199+
try
200+
close w
201+
delay 0.3
202+
open mp
203+
delay 0.3
204+
end try
205+
end tell
206+
OSAEOF
207+
208+
echo "==> Unmounting DMG"
209+
for i in {1..5}; do
210+
if hdiutil detach "${MOUNT_POINT}" -quiet; then
211+
DETACHED=1
212+
break
213+
fi
214+
echo " Retry attempt (${i})..."
215+
sleep 1
216+
done
217+
[[ -z "${DETACHED:-}" ]] && { echo >&2 "ERROR: failed to unmount ${MOUNT_POINT}"; exit 1; }
218+
219+
# Remove old DMG if it already exists
220+
if [[ -f "${FINAL_DMG}" ]]; then
221+
echo "==> Removing old file ${FINAL_DMG}"
222+
rm -f "${FINAL_DMG}"
223+
fi
224+
225+
echo "==> Converting to compressed UDZO"
226+
hdiutil convert -verbose "${TMP_DMG}" -format UDZO -imagekey zlib-level=9 -o "${FINAL_DMG}"
227+
228+
echo "==> Done: ${FINAL_DMG}"

0 commit comments

Comments
 (0)