@@ -11,7 +11,7 @@ permissions:
1111 contents : write
1212
1313jobs :
14- build-sign :
14+ build-app :
1515 runs-on : macos-14
1616 steps :
1717 - name : Checkout
@@ -48,13 +48,11 @@ jobs:
4848 INSTALLER_CERTIFICATE : ${{ secrets.INSTALLER_CERTIFICATE }}
4949 INSTALLER_CERTIFICATE_PASSWORD : ${{ secrets.INSTALLER_CERTIFICATE_PASSWORD }}
5050 run : |
51- # Install Developer ID Application certificate
5251 echo "$MACOS_CERTIFICATE" | base64 --decode > signing.p12
5352 security create-keychain -p "" build.keychain
5453 security import signing.p12 -k build.keychain -P "$MACOS_CERTIFICATE_PASSWORD" -T /usr/bin/codesign -T /usr/bin/productsign
5554 rm signing.p12
5655
57- # Install Developer ID Installer certificate (for pkg signing)
5856 if [ -n "$INSTALLER_CERTIFICATE" ]; then
5957 echo "$INSTALLER_CERTIFICATE" | base64 --decode > installer.p12
6058 security import installer.p12 -k build.keychain -P "$INSTALLER_CERTIFICATE_PASSWORD" -T /usr/bin/productsign
6563 security default-keychain -s build.keychain
6664 security unlock-keychain -p "" build.keychain
6765
68- # Install provisioning profile
6966 mkdir -p ~/Library/MobileDevice/Provisioning\ Profiles
7067 echo "$PROVISIONING_PROFILE_BASE64" | base64 --decode > ~/Library/MobileDevice/Provisioning\ Profiles/nailed.provisionprofile
71-
72- # Also save for embedding
7368 echo "$PROVISIONING_PROFILE_BASE64" | base64 --decode > build_profile.provisionprofile
7469
7570 - name : Build PKCS#11 dylib
8681 CODE_SIGN_IDENTITY : ${{ vars.CODE_SIGN_IDENTITY }}
8782 run : |
8883 DYLIB="pkcs11/libnailed_pkcs11.dylib"
89-
90- # Sign the dylib with hardened runtime
9184 codesign --force --options runtime --timestamp \
9285 --sign "$CODE_SIGN_IDENTITY" \
9386 "$DYLIB"
94-
95- # Verify signature
9687 codesign --verify --verbose=2 "$DYLIB"
9788 echo "Dylib signature info:"
9889 codesign -dvv "$DYLIB"
@@ -120,25 +111,21 @@ jobs:
120111
121112 APP="build/export/nailed.app"
122113
123- # Embed provisioning profile
124114 cp build_profile.provisionprofile "$APP/Contents/embedded.provisionprofile"
125115
126- # Create entitlements with resolved variables
127116 sed "s/\$(AppIdentifierPrefix)/${DEVELOPMENT_TEAM}./g" \
128117 nailed/nailed.entitlements > build/entitlements.plist
129118
130119 echo "Resolved entitlements:"
131120 cat build/entitlements.plist
132121
133- # Sign nested bundles first (inside-out signing)
134122 find "$APP/Contents/Resources" -name "*.bundle" -type d | while read bundle; do
135123 echo "Signing bundle: $bundle"
136124 codesign --force --options runtime --timestamp \
137125 --sign "$CODE_SIGN_IDENTITY" \
138126 "$bundle"
139127 done
140128
141- # Sign any frameworks
142129 if [ -d "$APP/Contents/Frameworks" ]; then
143130 find "$APP/Contents/Frameworks" -name "*.framework" -type d | while read framework; do
144131 echo "Signing framework: $framework"
@@ -148,23 +135,16 @@ jobs:
148135 done
149136 fi
150137
151- # Sign the main app with entitlements
152138 codesign --force --options runtime --timestamp \
153139 --entitlements build/entitlements.plist \
154140 --sign "$CODE_SIGN_IDENTITY" \
155141 "$APP"
156142
157- # Verify signature
158143 codesign --verify --verbose=2 "$APP"
159-
160- # Show signature info
161144 echo "Signature info:"
162145 codesign -dvv "$APP"
163-
164- # Show embedded entitlements
165146 echo "Embedded entitlements:"
166147 codesign -d --entitlements - "$APP" 2>/dev/null || true
167-
168148 echo "Signature verification passed"
169149
170150 - name : Create installer package
@@ -173,7 +153,6 @@ jobs:
173153 run : |
174154 chmod +x scripts/build-pkg.sh
175155
176- # Extract version from tag or use default
177156 if [[ "$GITHUB_REF" == refs/tags/v* ]]; then
178157 VERSION="${GITHUB_REF#refs/tags/v}"
179158 else
@@ -190,15 +169,14 @@ jobs:
190169 echo "Package created:"
191170 ls -la build/nailed.pkg
192171
193- # Verify package signature
194172 if [ -n "$INSTALLER_SIGN_IDENTITY" ]; then
195173 pkgutil --check-signature build/nailed.pkg
196174 fi
197175
198- - name : Upload PKG artifact
176+ - name : Upload app PKG artifact
199177 uses : actions/upload-artifact@v4
200178 with :
201- name : nailed-${{ github.run_id }}
179+ name : nailed-pkg
202180 path : build/nailed.pkg
203181
204182 - name : Submit for notarization
@@ -230,7 +208,6 @@ jobs:
230208 SUBMISSION_ID=$(cat build/submission-id.txt)
231209 echo "Waiting for notarization (up to 2 minutes)..."
232210
233- # Wait for notarization to complete (timeout after 2 minutes)
234211 if xcrun notarytool wait "$SUBMISSION_ID" \
235212 --key ~/private_keys/AuthKey_${APPLE_API_KEY_ID}.p8 \
236213 --key-id "$APPLE_API_KEY_ID" \
@@ -240,40 +217,125 @@ jobs:
240217 echo "Notarization completed, stapling..."
241218 xcrun stapler staple build/nailed.pkg
242219 xcrun stapler validate build/nailed.pkg
243- echo "STAPLED=true" >> $GITHUB_ENV
244220 else
245- echo "Notarization not completed within 2 minutes, use staple.yml workflow later "
246- echo "STAPLED=false" >> $GITHUB_ENV
221+ echo "error: Notarization not completed within timeout "
222+ exit 1
247223 fi
248224
249225 rm -rf ~/private_keys
250226
227+ - name : Upload stapled PKG
228+ if : startsWith(github.ref, 'refs/tags/v')
229+ uses : actions/upload-artifact@v4
230+ with :
231+ name : nailed-pkg-stapled
232+ path : build/nailed.pkg
233+
251234 - name : Upload submission ID
252- if : startsWith(github.ref, 'refs/tags/v') && env.STAPLED == 'false'
235+ if : failure()
253236 uses : actions/upload-artifact@v4
254237 with :
255- name : notarization-${{ github.run_id }}
238+ name : notarization-submission
256239 path : build/submission-id.txt
257240
258- - name : Upload stapled PKG
259- if : startsWith(github.ref, 'refs/tags/v') && env.STAPLED == 'true'
241+ build-openvpn :
242+ runs-on : macos-14
243+ env :
244+ OPENSSL_VERSION : " 3.5.5"
245+ LZO_VERSION : " 2.10"
246+ LZ4_VERSION : " 1.10.0"
247+ PKCS11_HELPER_VERSION : " 1.30.0"
248+ OPENVPN_VERSION : " 2.7.0"
249+ steps :
250+ - name : Checkout
251+ uses : actions/checkout@v4
252+
253+ - name : Install certificate
254+ env :
255+ MACOS_CERTIFICATE : ${{ secrets.MACOS_CERTIFICATE }}
256+ MACOS_CERTIFICATE_PASSWORD : ${{ secrets.MACOS_CERTIFICATE_PASSWORD }}
257+ INSTALLER_CERTIFICATE : ${{ secrets.INSTALLER_CERTIFICATE }}
258+ INSTALLER_CERTIFICATE_PASSWORD : ${{ secrets.INSTALLER_CERTIFICATE_PASSWORD }}
259+ run : |
260+ echo "$MACOS_CERTIFICATE" | base64 --decode > signing.p12
261+ security create-keychain -p "" build.keychain
262+ security import signing.p12 -k build.keychain -P "$MACOS_CERTIFICATE_PASSWORD" -T /usr/bin/codesign -T /usr/bin/productsign
263+ rm signing.p12
264+
265+ if [ -n "$INSTALLER_CERTIFICATE" ]; then
266+ echo "$INSTALLER_CERTIFICATE" | base64 --decode > installer.p12
267+ security import installer.p12 -k build.keychain -P "$INSTALLER_CERTIFICATE_PASSWORD" -T /usr/bin/productsign
268+ rm installer.p12
269+ fi
270+
271+ security set-key-partition-list -S apple-tool:,apple: -s -k "" build.keychain
272+ security default-keychain -s build.keychain
273+ security unlock-keychain -p "" build.keychain
274+
275+ - name : Cache source tarballs
276+ uses : actions/cache@v4
277+ with :
278+ path : openvpn-build/_work/sources
279+ key : openvpn-sources-${{ env.OPENSSL_VERSION }}-${{ env.LZO_VERSION }}-${{ env.LZ4_VERSION }}-${{ env.PKCS11_HELPER_VERSION }}-${{ env.OPENVPN_VERSION }}
280+
281+ - name : Cache static libraries
282+ uses : actions/cache@v4
283+ with :
284+ path : openvpn-build/_work/staging
285+ key : openvpn-staging-${{ runner.os }}-${{ runner.arch }}-${{ env.OPENSSL_VERSION }}-${{ env.LZO_VERSION }}-${{ env.LZ4_VERSION }}-${{ env.PKCS11_HELPER_VERSION }}
286+
287+ - name : Build OpenVPN
288+ env :
289+ CODESIGN_IDENTITY : ${{ vars.CODE_SIGN_IDENTITY }}
290+ INSTALLER_IDENTITY : ${{ vars.INSTALLER_SIGN_IDENTITY }}
291+ run : |
292+ cd openvpn-build
293+ chmod +x build-openvpn.sh
294+ ./build-openvpn.sh
295+
296+ - name : Verify build
297+ run : |
298+ openvpn-build/output/openvpn --version
299+ otool -L openvpn-build/output/openvpn
300+ codesign -dvv openvpn-build/output/openvpn 2>&1
301+ pkgutil --check-signature openvpn-build/output/*.pkg
302+
303+ - name : Upload OpenVPN binary
260304 uses : actions/upload-artifact@v4
261305 with :
262- name : nailed-${{ github.run_id }}-stapled
263- path : build/nailed.pkg
306+ name : openvpn-pkg
307+ path : openvpn-build/output/*.pkg
308+
309+ release :
310+ if : startsWith(github.ref, 'refs/tags/v')
311+ needs : [build-app, build-openvpn]
312+ runs-on : ubuntu-latest
313+ steps :
314+ - name : Download nailed package
315+ uses : actions/download-artifact@v4
316+ with :
317+ name : nailed-pkg-stapled
318+ path : release-assets
319+
320+ - name : Download OpenVPN package
321+ uses : actions/download-artifact@v4
322+ with :
323+ name : openvpn-pkg
324+ path : release-assets
325+
326+ - name : List release assets
327+ run : ls -lh release-assets/
264328
265329 - name : Create release
266- if : startsWith(github.ref, 'refs/tags/v') && env.STAPLED == 'true'
267330 env :
268331 GH_TOKEN : ${{ github.token }}
332+ GH_REPO : ${{ github.repository }}
269333 run : |
270334 VERSION="${GITHUB_REF#refs/tags/}"
271-
272- # Rename pkg to include version
273- cp build/nailed.pkg "build/nailed-${VERSION}.pkg"
274-
275- # Create release with the stapled pkg
335+
336+ mv release-assets/nailed.pkg "release-assets/nailed-${VERSION}.pkg"
337+
276338 gh release create "$VERSION" \
277339 --title "Nailed $VERSION" \
278340 --generate-notes \
279- "build/nailed-${VERSION}.pkg"
341+ release-assets/*
0 commit comments