|
27 | 27 | macos_deployment_target: "14.0" |
28 | 28 |
|
29 | 29 | # macOS Intel |
30 | | - # If this runner label is not available in your account, |
31 | | - # replace it with your available Intel macOS runner label. |
32 | 30 | - name: macos-x86_64 |
33 | 31 | os: macos-15-intel |
34 | 32 | qt_version: "6.11.0" |
|
54 | 52 |
|
55 | 53 | env: |
56 | 54 | CMAKE_VERSION: "4.2.3" |
| 55 | + APP_VERSION: "1.3.0" |
57 | 56 |
|
58 | 57 | steps: |
59 | 58 | - name: Checkout |
@@ -185,7 +184,127 @@ jobs: |
185 | 184 | fi |
186 | 185 | done |
187 | 186 |
|
| 187 | + - name: Re-sign macOS app ad-hoc and create DMG |
| 188 | + if: runner.os == 'macOS' |
| 189 | + shell: bash |
| 190 | + run: | |
| 191 | + set -euo pipefail |
| 192 | +
|
| 193 | + APP="build/bin/GenyConnect.app" |
| 194 | + OUT_DIR="build/final/macos-${{ matrix.target_arch }}" |
| 195 | + DMG_NAME="GenyConnect-${APP_VERSION}-macos-${{ matrix.target_arch }}.dmg" |
| 196 | + DMG_PATH="${OUT_DIR}/${DMG_NAME}" |
| 197 | +
|
| 198 | + if [[ ! -d "$APP" ]]; then |
| 199 | + echo "App not found: $APP" |
| 200 | + exit 1 |
| 201 | + fi |
| 202 | +
|
| 203 | + mkdir -p "$OUT_DIR" |
| 204 | +
|
| 205 | + echo "Cleaning previous DMG..." |
| 206 | + rm -f "$DMG_PATH" |
| 207 | +
|
| 208 | + echo "Cleaning extended attributes..." |
| 209 | + xattr -cr "$APP" || true |
| 210 | +
|
| 211 | + echo "Fixing executable permissions..." |
| 212 | + chmod +x "$APP/Contents/MacOS/GenyConnect" || true |
| 213 | + chmod +x "$APP/Contents/MacOS/GenyConnectUpdater" || true |
| 214 | + chmod +x "$APP/Contents/MacOS/GenyConnectTunHelper" || true |
| 215 | + chmod +x "$APP/Contents/MacOS/xray-core" || true |
| 216 | +
|
| 217 | + echo "Removing old signatures from app bundle where possible..." |
| 218 | + codesign --remove-signature "$APP" || true |
| 219 | +
|
| 220 | + echo "Ad-hoc signing nested Mach-O files..." |
| 221 | +
|
| 222 | + while IFS= read -r file_path; do |
| 223 | + if file "$file_path" | grep -q "Mach-O"; then |
| 224 | + echo "Signing Mach-O: $file_path" |
| 225 | + codesign --force --sign - "$file_path" || true |
| 226 | + fi |
| 227 | + done < <(find "$APP/Contents" -type f) |
| 228 | +
|
| 229 | + echo "Ad-hoc signing frameworks..." |
| 230 | + while IFS= read -r framework_path; do |
| 231 | + echo "Signing framework: $framework_path" |
| 232 | + codesign --force --sign - "$framework_path" || true |
| 233 | + done < <(find "$APP/Contents" -type d -name "*.framework" | sort -r) |
| 234 | +
|
| 235 | + echo "Ad-hoc signing bundles/plugins..." |
| 236 | + while IFS= read -r bundle_path; do |
| 237 | + echo "Signing bundle/plugin: $bundle_path" |
| 238 | + codesign --force --sign - "$bundle_path" || true |
| 239 | + done < <(find "$APP/Contents" $begin:math:text$ \-name \"\*\.bundle\" \-o \-name \"\*\.plugin\" \-o \-name \"\*\.appex\" $end:math:text$ -type d | sort -r) |
| 240 | +
|
| 241 | + echo "Signing main app..." |
| 242 | + codesign --force --deep --sign - "$APP" |
| 243 | +
|
| 244 | + echo "Verifying app signature..." |
| 245 | + codesign --verify --deep --strict --verbose=4 "$APP" |
| 246 | +
|
| 247 | + echo "Gatekeeper check. Expected to fail without Developer ID/notarization:" |
| 248 | + spctl --assess --type execute --verbose=4 "$APP" || true |
| 249 | +
|
| 250 | + echo "Creating clean DMG..." |
| 251 | + STAGING="$(mktemp -d)" |
| 252 | +
|
| 253 | + cp -R "$APP" "$STAGING/GenyConnect.app" |
| 254 | + ln -s /Applications "$STAGING/Applications" |
| 255 | +
|
| 256 | + hdiutil create \ |
| 257 | + -volname "GenyConnect" \ |
| 258 | + -srcfolder "$STAGING" \ |
| 259 | + -ov \ |
| 260 | + -format UDZO \ |
| 261 | + "$DMG_PATH" |
| 262 | +
|
| 263 | + rm -rf "$STAGING" |
| 264 | +
|
| 265 | + echo "Verifying DMG..." |
| 266 | + hdiutil verify "$DMG_PATH" |
| 267 | +
|
| 268 | + echo "Created DMG:" |
| 269 | + ls -lh "$DMG_PATH" |
| 270 | +
|
| 271 | + - name: Verify macOS package |
| 272 | + if: runner.os == 'macOS' |
| 273 | + shell: bash |
| 274 | + run: | |
| 275 | + set -euo pipefail |
| 276 | +
|
| 277 | + DMG="$(find build/final -type f -name "*.dmg" | head -n 1)" |
| 278 | +
|
| 279 | + if [[ -z "$DMG" ]]; then |
| 280 | + echo "No DMG found." |
| 281 | + exit 1 |
| 282 | + fi |
| 283 | +
|
| 284 | + echo "Verifying DMG: $DMG" |
| 285 | + hdiutil verify "$DMG" |
| 286 | +
|
| 287 | + MOUNT_DIR="$(mktemp -d)" |
| 288 | + hdiutil attach "$DMG" -mountpoint "$MOUNT_DIR" -nobrowse -quiet |
| 289 | +
|
| 290 | + APP="$(find "$MOUNT_DIR" -maxdepth 2 -name "GenyConnect.app" -type d | head -n 1)" |
| 291 | +
|
| 292 | + if [[ -z "$APP" ]]; then |
| 293 | + echo "GenyConnect.app not found inside DMG." |
| 294 | + hdiutil detach "$MOUNT_DIR" -quiet || true |
| 295 | + exit 1 |
| 296 | + fi |
| 297 | +
|
| 298 | + echo "Verifying app inside DMG: $APP" |
| 299 | + codesign --verify --deep --strict --verbose=4 "$APP" |
| 300 | +
|
| 301 | + echo "Gatekeeper check. Expected to fail without Developer ID/notarization:" |
| 302 | + spctl --assess --type execute --verbose=4 "$APP" || true |
| 303 | +
|
| 304 | + hdiutil detach "$MOUNT_DIR" -quiet |
| 305 | +
|
188 | 306 | - name: Package |
| 307 | + if: runner.os != 'macOS' |
189 | 308 | run: cpack --config build/CPackConfig.cmake -C Release |
190 | 309 |
|
191 | 310 | - name: Collect packages |
|
0 commit comments