@@ -7,21 +7,15 @@ DIRPATH="$(dirname "$CANONPATH")"
77cd " $DIRPATH " || exit
88
99# This script handles code signing and notarization for the macOS app.
10- # It's designed to be called from the CI environment.
11- #
1210# It expects the following environment variables to be set for real signing:
1311# - MACOS_CERTIFICATE_P12_B64: The base64 encoded .p12 certificate.
1412# - MACOS_CERTIFICATE_PASSWORD: The password for the .p12 certificate.
1513# - MACOS_APPLE_ID: Your Apple ID email used for notarization.
1614# - MACOS_NOTARIZATION_PASSWORD: An app-specific password for your Apple ID.
1715# - MACOS_TEAM_ID: Your Apple Developer Team ID.
18- #
19- # If these variables are not set, it will fall back to ad-hoc (self) signing for .app bundles
20- # and skip notarization for .dmg files.
2116
2217# The first argument is the path to the artifact, relative to this script's location.
2318ARTIFACT_PATH=" $1 "
24- # The entitlements file is in the same directory as this script.
2519ENTITLEMENTS_PATH=" entitlements.plist"
2620
2721if [[ -z " $ARTIFACT_PATH " ]]; then
3832if [[ -z " $MACOS_CERTIFICATE_P12_B64 " ]]; then
3933 if [[ " $ARTIFACT_PATH " == * .app ]]; then
4034 echo " No signing certificate found. Performing ad-hoc signing..."
41- # Find and sign all binaries within the app bundle
4235 find " $ARTIFACT_PATH /Contents/MacOS/" -type f -exec codesign --force --sign - {} \;
4336 codesign --force --sign - " $ARTIFACT_PATH "
4437 echo " Ad-hoc signing complete."
4538 fi
46- # For .dmg files, we just skip if no credentials
4739 exit 0
4840fi
4941
@@ -54,25 +46,54 @@ KEYCHAIN_NAME="build.keychain"
5446KEYCHAIN_PASSWORD=" a-very-secure-password"
5547CERTIFICATE_P12_PATH=" certificate.p12"
5648
57- # Decode the certificate
58- echo " $MACOS_CERTIFICATE_P12_B64 " | base64 --decode > " $CERTIFICATE_P12_PATH "
49+ # Check if keychain already exists
50+ if [[ -f " $HOME /Library/Keychains/$KEYCHAIN_NAME -db" ]]; then
51+ echo " Keychain $KEYCHAIN_NAME already exists. Reusing it..."
52+ security unlock-keychain -p " $KEYCHAIN_PASSWORD " " $KEYCHAIN_NAME "
53+ else
54+ echo " Creating temporary keychain: $KEYCHAIN_NAME "
55+ security create-keychain -p " $KEYCHAIN_PASSWORD " " $KEYCHAIN_NAME "
56+ security default-keychain -s " $KEYCHAIN_NAME "
57+ security set-keychain-settings -t 3600 -u " $KEYCHAIN_NAME "
58+
59+ # Decode and import the certificate
60+ echo " Decoding certificate..."
61+ echo " $MACOS_CERTIFICATE_P12_B64 " | base64 --decode > " $CERTIFICATE_P12_PATH "
62+ if [[ ! -s " $CERTIFICATE_P12_PATH " ]]; then
63+ echo " Error: Certificate file is empty or invalid."
64+ exit 1
65+ fi
5966
60- # Create a temporary keychain
61- security create-keychain -p " $KEYCHAIN_PASSWORD " " $KEYCHAIN_NAME "
62- security default-keychain -s " $KEYCHAIN_NAME "
63- security unlock-keychain -p " $KEYCHAIN_PASSWORD " " $KEYCHAIN_NAME "
64- security set-keychain-settings -t 3600 -u " $KEYCHAIN_NAME "
67+ echo " Importing certificate into keychain..."
68+ security import " $CERTIFICATE_P12_PATH " -k " $KEYCHAIN_NAME " -P " $MACOS_CERTIFICATE_PASSWORD " -T /usr/bin/codesign -T /usr/bin/security
69+ if [[ $? -ne 0 ]]; then
70+ echo " Error: Failed to import certificate."
71+ exit 1
72+ fi
6573
66- # Import the certificate into the keychain
67- security import " $CERTIFICATE_P12_PATH " -k " $KEYCHAIN_NAME " -P " $MACOS_CERTIFICATE_PASSWORD " -T /usr/bin/codesign -T /usr/bin/security
74+ # Allow codesign access
75+ echo " Setting keychain partition list..."
76+ security set-key-partition-list -S apple-tool:,apple:,codesign: -s -k " $KEYCHAIN_PASSWORD " " $KEYCHAIN_NAME " > /dev/null
77+ if [[ $? -ne 0 ]]; then
78+ echo " Error: Failed to set keychain partition list."
79+ exit 1
80+ fi
81+ fi
6882
69- # Allow codesign to access the certificate
70- security set-key-partition-list -S apple-tool:,apple: -s -k " $KEYCHAIN_PASSWORD " " $KEYCHAIN_NAME " > /dev/null
83+ # Debug: List certificates
84+ echo " Listing certificates in keychain for debugging..."
85+ security find-certificate -a -p " $KEYCHAIN_NAME "
86+
87+ # Ensure keychain is unlocked
88+ echo " Ensuring keychain is unlocked..."
89+ security unlock-keychain -p " $KEYCHAIN_PASSWORD " " $KEYCHAIN_NAME "
7190
7291# Find the signing identity
92+ echo " Searching for signing identity..."
7393SIGNING_IDENTITY=$( security find-identity -v -p codesigning " $KEYCHAIN_NAME " | grep " Developer ID Application" | head -n 1 | awk -F ' "' ' {print $2}' )
7494if [[ -z " $SIGNING_IDENTITY " ]]; then
75- echo " Error: Signing identity not found in keychain."
95+ echo " Error: No Developer ID Application signing identity found."
96+ security find-identity -v -p codesigning " $KEYCHAIN_NAME "
7697 exit 1
7798fi
7899echo " Using signing identity: $SIGNING_IDENTITY "
@@ -82,26 +103,23 @@ echo "Using signing identity: $SIGNING_IDENTITY"
82103# Function to sign the .app bundle
83104sign_app () {
84105 echo " Signing application bundle at: $ARTIFACT_PATH "
85- # Sign all dylibs, frameworks and executables from the inside out
86106 find " $ARTIFACT_PATH " -depth -name " *.dylib" -o -name " *.framework" -o -path " $ARTIFACT_PATH /Contents/MacOS/*" -type f | while read -r comp; do
87107 echo " Signing component: $comp "
88- codesign --force --verify -- verbose --sign " $SIGNING_IDENTITY " --options runtime --timestamp " $comp "
108+ codesign --force --verbose --sign " $SIGNING_IDENTITY " --options runtime --timestamp " $comp "
89109 done
90110
91111 echo " Signing main application bundle with entitlements..."
92- codesign --force --verify -- verbose --sign " $SIGNING_IDENTITY " --entitlements " $ENTITLEMENTS_PATH " --options runtime --timestamp " $ARTIFACT_PATH "
112+ codesign --force --verbose --sign " $SIGNING_IDENTITY " --entitlements " $ENTITLEMENTS_PATH " --options runtime --timestamp " $ARTIFACT_PATH "
93113 echo " App signing complete."
94114
95- # Notarize the app: Zip it first (Apple recommends zipping apps for submission)
115+ # Notarize the app
96116 ZIP_PATH=" ${ARTIFACT_PATH% .* } .zip"
97117 echo " Zipping app for notarization: $ZIP_PATH "
98118 ditto -c -k --sequesterRsrc --keepParent " $ARTIFACT_PATH " " $ZIP_PATH "
99119
100- # Temporary file to store the command's output
101120 local notary_output_file
102121 notary_output_file=$( mktemp)
103122
104- # Submit for notarization
105123 echo " Notarizing app zip..."
106124 if ! xcrun notarytool submit " $ZIP_PATH " \
107125 --apple-id " $MACOS_APPLE_ID " \
@@ -128,43 +146,49 @@ sign_app() {
128146 cat " $notary_output_file "
129147 rm " $notary_output_file "
130148
131- # Staple to the app (not the zip)
132149 echo " Stapling ticket to app..."
133150 xcrun stapler staple " $ARTIFACT_PATH "
134151 echo " App stapling complete."
135152
136- # Clean up zip
137153 rm -f " $ZIP_PATH "
138154}
139155
140156# Function to notarize and staple the .dmg
141157notarize_dmg () {
142158 echo " Notarizing DMG at: $ARTIFACT_PATH "
143159
144- # Sign the DMG first (required before notarization)
160+ # Re-verify keychain state
161+ echo " Verifying keychain state before DMG signing..."
162+ security unlock-keychain -p " $KEYCHAIN_PASSWORD " " $KEYCHAIN_NAME "
163+ security find-identity -v -p codesigning " $KEYCHAIN_NAME "
164+
165+ # Sign the DMG
145166 echo " Signing DMG..."
146- codesign --force --verify --verbose --sign " $SIGNING_IDENTITY " --timestamp " $ARTIFACT_PATH "
167+ codesign --force --verbose --sign " $SIGNING_IDENTITY " " $ARTIFACT_PATH "
168+ if [[ $? -ne 0 ]]; then
169+ echo " Error: Failed to sign DMG. Checking keychain state..."
170+ security find-identity -v -p codesigning " $KEYCHAIN_NAME "
171+ exit 1
172+ fi
147173 echo " DMG signing complete."
148174
149- # Temporary file to store the command's output
175+ # Verify the signature
176+ echo " Verifying DMG signature..."
177+ codesign --verify --verbose " $ARTIFACT_PATH "
178+
179+ # Notarize the DMG
150180 local notary_output_file
151181 notary_output_file=$( mktemp)
152182
153- # Submit for notarization and check the exit code directly.
154- # The --wait flag makes the command exit with 0 on success and non-zero on failure.
155- # We redirect all output to a temp file so we can show it and parse it later.
183+ echo " Notarizing DMG..."
156184 if ! xcrun notarytool submit " $ARTIFACT_PATH " \
157185 --apple-id " $MACOS_APPLE_ID " \
158186 --password " $MACOS_NOTARIZATION_PASSWORD " \
159187 --team-id " $MACOS_TEAM_ID " \
160188 --wait > " $notary_output_file " 2>&1 ; then
161189
162190 echo " Error: Notarization failed."
163- # Print the full output from the failed command for debugging
164191 cat " $notary_output_file "
165-
166- # Attempt to get logs if we can find a UUID.
167- # Use 'head -n 1' to ensure we only get the first matching line.
168192 REQUEST_UUID=$( grep " id:" " $notary_output_file " | head -n 1 | awk ' {print $2}' )
169193 if [[ -n " $REQUEST_UUID " ]]; then
170194 echo " Fetching notarization logs for UUID: $REQUEST_UUID "
@@ -177,7 +201,6 @@ notarize_dmg() {
177201 exit 1
178202 fi
179203
180- # If we reach here, the command succeeded.
181204 echo " Notarization successful. Full log:"
182205 cat " $notary_output_file "
183206 rm " $notary_output_file "
@@ -188,12 +211,13 @@ notarize_dmg() {
188211}
189212
190213# --- CLEANUP ---
191- cleanup () {
192- echo " Cleaning up..."
193- security delete-keychain " $KEYCHAIN_NAME " || true
194- rm -f " $CERTIFICATE_P12_PATH "
195- }
196- trap cleanup EXIT
214+ # Note: Cleanup is handled in CI, not here, since this script is called twice
215+ # cleanup() {
216+ # echo "Cleaning up..."
217+ # security delete-keychain "$KEYCHAIN_NAME" || true
218+ # rm -f "$CERTIFICATE_P12_PATH"
219+ # }
220+ # trap cleanup EXIT
197221
198222# --- EXECUTION ---
199223if [[ " $ARTIFACT_PATH " == * .app ]]; then
0 commit comments