#!/usr/bin/env bash set -euo pipefail PROJECT_ROOT="$(cd "$(dirname "$0")" && pwd)" cd "$PROJECT_ROOT" APP_NAME="SonarDesk" PROJECT="SonarDesk.xcodeproj" SCHEME="SonarDesk" CONFIGURATION="Release" TEAM_ID="39R6U3437D" SIGN_IDENTITY="B99D353C88996866C49E4389B375645F76870A3F" PROFILE_NAME="SonarDesk" NOTARY_PROFILE="sonardesk-notary" BUILD_DIR="$PROJECT_ROOT/build" ARCHIVE="$BUILD_DIR/SonarDesk.xcarchive" APP="$ARCHIVE/Products/Applications/SonarDesk.app" STAGE="$BUILD_DIR/dmg-stage" RELEASE_DIR="$PROJECT_ROOT/release" echo echo "========================================" echo " SonarDesk Release Build" echo "========================================" echo echo "===== CLEAN =====" rm -rf "$ARCHIVE" "$STAGE" mkdir -p "$BUILD_DIR" "$RELEASE_DIR" echo echo "===== ARCHIVE =====" xcodebuild \ -project "$PROJECT" \ -scheme "$SCHEME" \ -configuration "$CONFIGURATION" \ -archivePath "$ARCHIVE" \ -destination 'generic/platform=macOS' \ CODE_SIGN_STYLE=Manual \ CODE_SIGN_IDENTITY="$SIGN_IDENTITY" \ DEVELOPMENT_TEAM="$TEAM_ID" \ PROVISIONING_PROFILE_SPECIFIER="$PROFILE_NAME" \ ENABLE_HARDENED_RUNTIME=YES \ clean archive echo echo "===== VERIFY APP SIGNATURE =====" codesign --verify --deep --strict --verbose=2 "$APP" SIGN_INFO="$(codesign -dv --verbose=4 "$APP" 2>&1)" echo "$SIGN_INFO" | grep \ "Authority=Developer ID Application: Mark Gregory (39R6U3437D)" echo "$SIGN_INFO" | grep \ "TeamIdentifier=$TEAM_ID" echo "$SIGN_INFO" | grep \ "Runtime Version=" echo echo "===== VERIFY EMBEDDED PROFILE =====" PROFILE_PLIST="$(mktemp)" trap 'rm -f "$PROFILE_PLIST"' EXIT security cms -D \ -i "$APP/Contents/embedded.provisionprofile" \ > "$PROFILE_PLIST" PROFILE_NAME_ACTUAL=$( /usr/libexec/PlistBuddy \ -c 'Print :Name' \ "$PROFILE_PLIST" ) PROFILE_UUID=$( /usr/libexec/PlistBuddy \ -c 'Print :UUID' \ "$PROFILE_PLIST" ) ICLOUD_ENV=$( /usr/libexec/PlistBuddy \ -c 'Print :Entitlements:com.apple.developer.icloud-container-environment' \ "$PROFILE_PLIST" ) echo "Profile: $PROFILE_NAME_ACTUAL" echo "UUID: $PROFILE_UUID" echo "iCloud Environment: $ICLOUD_ENV" if [[ "$ICLOUD_ENV" != "Production" ]]; then echo "ERROR: iCloud environment is not Production." exit 1 fi echo echo "===== VERIFY SIGNED ENTITLEMENTS =====" ENTITLEMENTS="$(codesign -d --entitlements :- "$APP" 2>/dev/null)" echo "$ENTITLEMENTS" | grep -q \ 'iCloud.net.absdev.SonarDesk' echo "$ENTITLEMENTS" | grep -q \ 'CloudDocuments' echo "$ENTITLEMENTS" | grep -q \ '39R6U3437D.net.absdev.SonarDesk' echo "iCloud entitlements verified." echo echo "===== DETERMINE VERSION =====" VERSION=$( /usr/libexec/PlistBuddy \ -c 'Print :CFBundleShortVersionString' \ "$APP/Contents/Info.plist" ) BUILD=$( /usr/libexec/PlistBuddy \ -c 'Print :CFBundleVersion' \ "$APP/Contents/Info.plist" ) DMG="$RELEASE_DIR/SonarDesk-${VERSION}.dmg" echo "Version: $VERSION" echo "Build: $BUILD" echo "DMG: $DMG" echo echo "===== PREPARE DMG =====" rm -rf "$STAGE" rm -f "$DMG" mkdir -p "$STAGE" ditto "$APP" "$STAGE/SonarDesk.app" ln -s /Applications "$STAGE/Applications" echo echo "===== CREATE DMG =====" hdiutil create \ -volname "SonarDesk" \ -srcfolder "$STAGE" \ -ov \ -format UDZO \ "$DMG" echo echo "===== SIGN DMG =====" codesign \ --force \ --timestamp \ --sign "$SIGN_IDENTITY" \ "$DMG" echo echo "===== VERIFY DMG SIGNATURE =====" codesign --verify --verbose=2 "$DMG" echo echo "===== NOTARIZE =====" xcrun notarytool submit "$DMG" \ --keychain-profile "$NOTARY_PROFILE" \ --wait echo echo "===== STAPLE =====" xcrun stapler staple "$DMG" echo echo "===== VALIDATE STAPLE =====" xcrun stapler validate "$DMG" echo echo "===== GATEKEEPER CHECK =====" spctl \ --assess \ --type open \ --context context:primary-signature \ --verbose=4 \ "$DMG" echo echo "===== VERIFY APP INSIDE DMG =====" MOUNT_DIR="$(mktemp -d)" cleanup_mount() { hdiutil detach "$MOUNT_DIR" >/dev/null 2>&1 || true rmdir "$MOUNT_DIR" >/dev/null 2>&1 || true } trap 'cleanup_mount; rm -f "$PROFILE_PLIST"' EXIT hdiutil attach "$DMG" \ -nobrowse \ -readonly \ -mountpoint "$MOUNT_DIR" \ >/dev/null codesign \ --verify \ --deep \ --strict \ --verbose=2 \ "$MOUNT_DIR/SonarDesk.app" spctl \ --assess \ --type execute \ --verbose=4 \ "$MOUNT_DIR/SonarDesk.app" cleanup_mount rm -rf "$STAGE" echo echo "========================================" echo " RELEASE COMPLETE" echo "========================================" echo echo "Application: SonarDesk" echo "Version: $VERSION" echo "Build: $BUILD" echo "DMG: $DMG" echo echo "Signed: YES" echo "Notarized: YES" echo "Stapled: YES" echo "Gatekeeper: PASSED" echo echo "========================================"