forked from ARK-Builders/Drop
-
Notifications
You must be signed in to change notification settings - Fork 0
375 lines (323 loc) Β· 14.8 KB
/
Copy pathrelease-ios.yml
File metadata and controls
375 lines (323 loc) Β· 14.8 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
name: Release iOS App
# Trigger: push tags or manual dispatch
on:
push:
tags:
- 'v*'
branches:
# TEMPORARY: Remove after testing
- 'feature/kmp-ios-impl'
- 'fix/kmp-ios-impl'
workflow_dispatch:
jobs:
build:
runs-on: macos-26 # macOS 26 Tahoe with Xcode 26.2 (required for App Store from Apr 28, 2026 - ITMS-90725)
environment: Testflight
env:
APP_BUNDLE_ID: dev.ark-builders.drop
APP_TEAM_ID: SQNXHTL7FT
IOS_P12_PASSWORD: ${{ secrets.IOS_P12_PASSWORD }}
ASC_KEY_ID: ${{ secrets.ASC_KEY_ID }}
ASC_ISSUER_ID: ${{ secrets.ASC_ISSUER_ID }}
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
steps:
# 1οΈβ£ Checkout code
- name: Checkout repository
uses: actions/checkout@v4
# π Diagnostic: Check all secrets availability
- name: Validate Secrets
run: |
echo "π Checking which secrets are available..."
echo ""
# Check each required secret
MISSING_SECRETS=()
if [ -z "${{ secrets.IOS_P12_BASE64 }}" ]; then
echo "β IOS_P12_BASE64 - MISSING or EMPTY"
MISSING_SECRETS+=("IOS_P12_BASE64")
else
echo "β
IOS_P12_BASE64 - Available (${#IOS_P12_BASE64} chars)"
fi
if [ -z "${{ secrets.IOS_P12_PASSWORD }}" ]; then
echo "β IOS_P12_PASSWORD - MISSING or EMPTY"
MISSING_SECRETS+=("IOS_P12_PASSWORD")
else
echo "β
IOS_P12_PASSWORD - Available"
fi
if [ -z "${{ secrets.IOS_PROFILE_BASE64 }}" ]; then
echo "β IOS_PROFILE_BASE64 - MISSING or EMPTY"
MISSING_SECRETS+=("IOS_PROFILE_BASE64")
else
echo "β
IOS_PROFILE_BASE64 - Available (${#IOS_PROFILE_BASE64} chars)"
fi
if [ -z "${{ secrets.ASC_API_KEY_BASE64 }}" ]; then
echo "β ASC_API_KEY_BASE64 - MISSING or EMPTY"
MISSING_SECRETS+=("ASC_API_KEY_BASE64")
else
echo "β
ASC_API_KEY_BASE64 - Available (${#ASC_API_KEY_BASE64} chars)"
fi
if [ -z "${{ secrets.ASC_KEY_ID }}" ]; then
echo "β ASC_KEY_ID - MISSING or EMPTY"
MISSING_SECRETS+=("ASC_KEY_ID")
else
echo "β
ASC_KEY_ID - Available"
fi
if [ -z "${{ secrets.ASC_ISSUER_ID }}" ]; then
echo "β ASC_ISSUER_ID - MISSING or EMPTY"
MISSING_SECRETS+=("ASC_ISSUER_ID")
else
echo "β
ASC_ISSUER_ID - Available"
fi
echo ""
echo "π Summary: ${#MISSING_SECRETS[@]} secrets missing"
if [ ${#MISSING_SECRETS[@]} -gt 0 ]; then
echo ""
echo "β οΈ Missing secrets need to be added to:"
echo " Settings β Environments β Testflight β Environment secrets"
echo ""
echo "Current repository: ${{ github.repository }}"
echo "Current environment: Testflight"
exit 1
fi
echo ""
echo "β
All required secrets are available!"
env:
IOS_P12_BASE64: ${{ secrets.IOS_P12_BASE64 }}
IOS_PROFILE_BASE64: ${{ secrets.IOS_PROFILE_BASE64 }}
ASC_API_KEY_BASE64: ${{ secrets.ASC_API_KEY_BASE64 }}
# 2οΈβ£ Setup Ruby and Fastlane
- name: Setup Ruby
uses: ruby/setup-ruby@v1
with:
ruby-version: "3.2"
bundler-cache: true
- name: Install gems
run: bundle install
# 3οΈβ£ Build Kotlin framework before Xcode (required for KMP - Xcode expects it at XCFrameworks/debug)
- name: Build Kotlin framework for Release
run: |
export JAVA_HOME=$(/usr/libexec/java_home -v 17)
./gradlew :shared:assembleSharedReleaseXCFramework
mkdir -p shared/build/XCFrameworks/debug
cp -R shared/build/XCFrameworks/release/shared.xcframework shared/build/XCFrameworks/debug/
# 3b Ensure XCFramework has Info.plist (Kotlin may not create it; Xcode requires it)
- name: Ensure XCFramework Info.plist
run: |
XCF_DIR="shared/build/XCFrameworks/debug/shared.xcframework"
if [ ! -f "$XCF_DIR/Info.plist" ]; then
echo "Creating Info.plist for XCFramework..."
cp shared/build/XCFrameworks/release/shared.xcframework/Info.plist "$XCF_DIR/" 2>/dev/null || \
cp shared/XCFramework-Info.plist "$XCF_DIR/Info.plist"
echo "β
Info.plist ready"
else
echo "β
Info.plist already exists"
fi
# 4οΈβ£ Setup Xcode 26.2 (macos-26 has it pre-installed)
- name: Select Xcode version
uses: maxim-lobanov/setup-xcode@v1
with:
xcode-version: '26.2'
# 4οΈβ£ Decode certificate (Fastlane will import it)
- name: Decode iOS certificate
run: |
# Check if the secret exists and is not empty
if [ -z "$IOS_P12_BASE64" ]; then
echo "β ERROR: IOS_P12_BASE64 secret is missing or empty!"
exit 1
fi
# Decode certificate
echo "$IOS_P12_BASE64" | base64 --decode > cert.p12
# Verify the .p12 file was created and has content
FILE_SIZE=$(stat -f%z cert.p12)
echo "β
Certificate file size: $FILE_SIZE bytes"
if [ "$FILE_SIZE" -lt 100 ]; then
echo "β ERROR: Certificate file is too small, likely corrupted"
exit 1
fi
env:
IOS_P12_BASE64: ${{ secrets.IOS_P12_BASE64 }}
# 6οΈβ£ Validate iOS certificate contains private key
- name: Validate iOS certificate contains private key
run: |
set +e # Don't exit on openssl failure - we need to show the error
echo "π Validating p12 certificate contents..."
echo ""
# Check if p12 file exists
if [ ! -f cert.p12 ]; then
echo "β ERROR: cert.p12 file not found!"
exit 1
fi
# Test 1: Check for PRIVATE KEY in p12 structure
# -legacy: OpenSSL 3.x on macos-26 disables RC2-40-CBC; Apple p12 often uses it
echo "π Test 1: Checking p12 structure for private key..."
CERT_CONTENTS=$(openssl pkcs12 -in cert.p12 -legacy -nodes -passin env:IOS_P12_PASSWORD 2>&1)
OPENSSL_EXIT=$?
set -e
if [ $OPENSSL_EXIT -ne 0 ]; then
echo "β ERROR: OpenSSL failed to read p12 (exit code $OPENSSL_EXIT)"
echo ""
echo "Output: $CERT_CONTENTS"
echo ""
echo "π‘ Possible causes: wrong IOS_P12_PASSWORD, or OpenSSL 3 on macos-26 (we use -legacy for Apple p12)"
exit 1
fi
HAS_PRIVATE_KEY=true
if echo "$CERT_CONTENTS" | grep -q "PRIVATE KEY"; then
echo "β
Private key found in p12 certificate structure"
else
echo "β ERROR: p12 certificate does NOT contain a private key in its structure!"
HAS_PRIVATE_KEY=false
fi
# Test 2: Check if private key can be extracted (nocerts flag) - informational only
echo ""
echo "π Test 2: Attempting to extract private key only (nocerts)..."
if openssl pkcs12 -in cert.p12 -legacy -nocerts -passin pass:"$IOS_P12_PASSWORD" >/dev/null 2>&1; then
echo "β
Private key can be extracted separately"
else
echo "β οΈ Note: nocerts extraction failed (this is OK if Test 1 passed)"
fi
# Test 3: Alternative private key check using env variable - informational only
echo ""
echo "π Test 3: Alternative private key extraction test..."
if openssl pkcs12 -in cert.p12 -legacy -nocerts -passin env:IOS_P12_PASSWORD >/dev/null 2>&1; then
echo "β
Alternative extraction succeeded"
else
echo "β οΈ Note: Alternative extraction failed (this is OK if Test 1 passed)"
fi
# Test 4: Show certificate details
echo ""
echo "π Test 4: Certificate details (subject and validity):"
CERT_SUBJECT=$(echo "$CERT_CONTENTS" | openssl x509 -noout -subject 2>/dev/null || echo "Could not extract subject")
CERT_DATES=$(echo "$CERT_CONTENTS" | openssl x509 -noout -dates 2>/dev/null || echo "Could not extract dates")
echo "$CERT_SUBJECT"
echo "$CERT_DATES"
# Check if this is the correct certificate (Apple Distribution)
if echo "$CERT_SUBJECT" | grep -q "Apple Distribution"; then
echo "β
Certificate type confirmed: Apple Distribution"
else
echo "β οΈ WARNING: Certificate may not be 'Apple Distribution' type"
fi
# Test 5: List certificate and key components (double-check private key presence)
echo ""
echo "π Test 5: Certificate and key components found in p12:"
COMPONENTS=$(echo "$CERT_CONTENTS" | grep -E "BEGIN|END")
echo "$COMPONENTS"
# Final validation: Ensure private key is present in the structure
if echo "$COMPONENTS" | grep -q "BEGIN PRIVATE KEY"; then
echo ""
echo "β
FINAL CHECK: Private key structure confirmed in p12"
HAS_PRIVATE_KEY=true
elif echo "$COMPONENTS" | grep -q "BEGIN RSA PRIVATE KEY"; then
echo ""
echo "β
FINAL CHECK: RSA private key structure confirmed in p12"
HAS_PRIVATE_KEY=true
elif [ "${HAS_PRIVATE_KEY}" = "false" ]; then
echo ""
echo "β VALIDATION FAILED: p12 does not contain a valid private key"
echo ""
echo "β οΈ Possible issues:"
echo " 1. The p12 was exported without including the private key"
echo " 2. Wrong password is being used (IOS_P12_PASSWORD)"
echo " 3. The certificate file is corrupted"
echo ""
echo "π‘ To fix: Export the certificate from Keychain Access ensuring:"
echo " - Expand the certificate (click the triangle/arrow)"
echo " - Select both the certificate AND its private key (you should see 2 items)"
echo " - Right-click and choose 'Export 2 items...'"
echo " - Save as .p12 format"
exit 1
fi
echo ""
echo "β
All validation tests passed - p12 contains a valid private key"
echo ""
echo "π Note: After Fastlane imports this certificate into the keychain,"
echo " additional checks will verify:"
echo " - security find-certificate (certificate in keychain)"
echo " - security find-key (private key in keychain)"
echo " - security find-identity (valid signing identity)"
env:
IOS_P12_PASSWORD: ${{ secrets.IOS_P12_PASSWORD }}
# 7οΈβ£ Decode provisioning profile (Fastlane will install it)
- name: Decode provisioning profile
run: |
# Check if the secret exists
if [ -z "$IOS_PROFILE_BASE64" ]; then
echo "β ERROR: IOS_PROFILE_BASE64 secret is missing or empty!"
exit 1
fi
# Decode provisioning profile
echo "$IOS_PROFILE_BASE64" | base64 --decode > profile.mobileprovision
FILE_SIZE=$(stat -f%z profile.mobileprovision)
echo "β
Provisioning profile size: $FILE_SIZE bytes"
env:
IOS_PROFILE_BASE64: ${{ secrets.IOS_PROFILE_BASE64 }}
# 8οΈβ£ Setup App Store Connect API Key
- name: Setup App Store Connect API Key
run: |
# Check if secrets exist
if [ -z "$ASC_API_KEY_BASE64" ]; then
echo "β ERROR: ASC_API_KEY_BASE64 secret is missing or empty!"
exit 1
fi
if [ -z "${{ secrets.ASC_KEY_ID }}" ] || [ -z "${{ secrets.ASC_ISSUER_ID }}" ]; then
echo "β ERROR: ASC_KEY_ID or ASC_ISSUER_ID secret is missing!"
exit 1
fi
mkdir -p ~/.fastlane
echo "$ASC_API_KEY_BASE64" | base64 --decode > ~/.fastlane/AuthKey.p8
chmod 600 ~/.fastlane/AuthKey.p8
# Verify the key file was created
if [ ! -f ~/.fastlane/AuthKey.p8 ]; then
echo "β ERROR: Failed to create AuthKey.p8"
exit 1
fi
echo "β
App Store Connect API key configured"
env:
ASC_API_KEY_BASE64: ${{ secrets.ASC_API_KEY_BASE64 }}
# 8b Set build number (Config.xcconfig overrides agvtool; must be > previous TestFlight build)
- name: Set build number for TestFlight
run: |
BUILD_NUM=$(date +%s)
sed -i.bak "s/CURRENT_PROJECT_VERSION=.*/CURRENT_PROJECT_VERSION=$BUILD_NUM/" iosApp/Configuration/Config.xcconfig
rm -f iosApp/Configuration/Config.xcconfig.bak
echo "Set CURRENT_PROJECT_VERSION to $BUILD_NUM"
# 9οΈβ£ Build & Upload to TestFlight via Fastlane (includes verification inside)
- name: Build & Upload to TestFlight
run: bundle exec fastlane beta
env:
IOS_P12_PASSWORD: ${{ secrets.IOS_P12_PASSWORD }}
APP_STORE_CONNECT_API_KEY_ID: ${{ secrets.ASC_KEY_ID }}
APP_STORE_CONNECT_API_KEY_ISSUER_ID: ${{ secrets.ASC_ISSUER_ID }}
# 9οΈβ£ Upload build artifacts
- name: Upload IPA artifact
uses: actions/upload-artifact@v4
if: success()
with:
name: ARK-Drop-${{ github.run_number }}.ipa
path: build/ARK-Drop.ipa
retention-days: 30
# π Show build errors if build failed
- name: Show Build Log Tail
if: failure()
run: |
echo "π Last 200 lines of build log:"
find build/logs -name "*.log" -exec tail -200 {} \; 2>/dev/null || echo "No build log found"
echo ""
echo "π Checking for error lines:"
find build/logs -name "*.log" -exec grep -i "error:" {} \; 2>/dev/null || echo "No errors found in log"
# π Upload build logs for debugging
- name: Upload Build Logs
uses: actions/upload-artifact@v4
if: always()
with:
name: xcode-build-logs
path: |
~/Library/Logs/gym/
build/
retention-days: 7
# π Cleanup
- name: Cleanup
if: always()
run: |
# Clean up certificate and profile files
rm -f cert.p12 profile.mobileprovision ~/.fastlane/AuthKey.p8
# Fastlane's setup_ci will clean up its own keychain automatically