#!/bin/bash set -euo pipefail # ============================================================ # OrionToolbar - Developer ID Release # ============================================================ APP_NAME="OrionToolbar" SCHEME="OrionToolbar" PROJECT="OrionToolbar.xcodeproj" SIGNING_IDENTITY="B99D353C88996866C49E4389B375645F76870A3F" TEAM_ID="39R6U3437D" NOTARY_PROFILE="orion-notary" ROOT_DIR="$(cd "$(dirname "$0")/.." && pwd)" BUILD_DIR="$ROOT_DIR/build" LOG_DIR="$ROOT_DIR/build-logs" ARCHIVE_PATH="$BUILD_DIR/$APP_NAME.xcarchive" EXPORT_DIR="$BUILD_DIR/export" DMG_STAGE="$BUILD_DIR/dmg" DMG_PATH="$ROOT_DIR/$APP_NAME.dmg" EXPORT_OPTIONS="$BUILD_DIR/ExportOptions.plist" mkdir -p "$LOG_DIR" LOG_FILE="$LOG_DIR/release-$(date +%Y%m%d-%H%M%S).log" exec > >(tee -a "$LOG_FILE") 2>&1 echo echo "============================================================" echo " ORION TOOLBAR - DIRECT DISTRIBUTION" echo "============================================================" echo cd "$ROOT_DIR" # ------------------------------------------------------------ # Prerequisites # ------------------------------------------------------------ echo "==> Checking signing identity" security find-identity -v -p codesigning if ! security find-identity -v -p codesigning | \ grep -q "$SIGNING_IDENTITY"; then echo "ERROR: Developer ID signing identity unavailable." exit 1 fi echo echo "==> Checking notarization profile" xcrun notarytool history \ --keychain-profile "$NOTARY_PROFILE" \ >/dev/null echo "Notarization profile available." # ------------------------------------------------------------ # Clean # ------------------------------------------------------------ echo echo "==> Cleaning previous release" rm -rf "$BUILD_DIR" rm -f "$DMG_PATH" mkdir -p \ "$BUILD_DIR" \ "$EXPORT_DIR" \ "$DMG_STAGE" # ------------------------------------------------------------ # Export options # ------------------------------------------------------------ cat > "$EXPORT_OPTIONS" < method developer-id signingStyle automatic teamID $TEAM_ID EOF # ------------------------------------------------------------ # Archive # ------------------------------------------------------------ echo echo "==> Creating Release archive" xcodebuild \ -project "$PROJECT" \ -scheme "$SCHEME" \ -configuration Release \ -destination "generic/platform=macOS" \ -archivePath "$ARCHIVE_PATH" \ clean archive echo echo "==> Archive created" # ------------------------------------------------------------ # Export # ------------------------------------------------------------ echo echo "==> Exporting Developer ID application" xcodebuild \ -exportArchive \ -archivePath "$ARCHIVE_PATH" \ -exportPath "$EXPORT_DIR" \ -exportOptionsPlist "$EXPORT_OPTIONS" APP_PATH="$EXPORT_DIR/$APP_NAME.app" if [ ! -d "$APP_PATH" ]; then echo "ERROR: Exported application not found." exit 1 fi # ------------------------------------------------------------ # Verify signature # ------------------------------------------------------------ echo echo "==> Verifying application signature" codesign \ --verify \ --deep \ --strict \ --verbose=2 \ "$APP_PATH" echo echo "==> Checking signing team" ACTUAL_TEAM=$( codesign -dv --verbose=4 "$APP_PATH" 2>&1 | sed -n 's/^TeamIdentifier=//p' ) if [ "$ACTUAL_TEAM" != "$TEAM_ID" ]; then echo "ERROR: Incorrect signing team: $ACTUAL_TEAM" exit 1 fi echo "Signing team verified: $ACTUAL_TEAM" # ------------------------------------------------------------ # Notarize application # ------------------------------------------------------------ echo echo "==> Creating notarization ZIP" APP_ZIP="$BUILD_DIR/$APP_NAME.zip" ditto \ -c \ -k \ --keepParent \ "$APP_PATH" \ "$APP_ZIP" echo echo "==> Notarizing application" xcrun notarytool submit \ "$APP_ZIP" \ --keychain-profile "$NOTARY_PROFILE" \ --wait echo echo "==> Stapling application" xcrun stapler staple "$APP_PATH" echo echo "==> Validating application ticket" xcrun stapler validate "$APP_PATH" echo echo "==> Gatekeeper application verification" spctl \ --assess \ --type execute \ --verbose=4 \ "$APP_PATH" # ------------------------------------------------------------ # Prepare DMG # ------------------------------------------------------------ echo echo "==> Preparing DMG" rm -rf "$DMG_STAGE" mkdir -p "$DMG_STAGE" ditto "$APP_PATH" "$DMG_STAGE/$APP_NAME.app" ln -s /Applications "$DMG_STAGE/Applications" # ------------------------------------------------------------ # Create DMG # ------------------------------------------------------------ echo echo "==> Creating DMG" hdiutil create \ -volname "$APP_NAME" \ -srcfolder "$DMG_STAGE" \ -ov \ -format UDZO \ "$DMG_PATH" # ------------------------------------------------------------ # Sign DMG # ------------------------------------------------------------ echo echo "==> Signing DMG" codesign \ --force \ --timestamp \ --sign "$SIGNING_IDENTITY" \ "$DMG_PATH" echo echo "==> Verifying DMG signature" codesign \ --verify \ --verbose=2 \ "$DMG_PATH" # ------------------------------------------------------------ # Notarize DMG # ------------------------------------------------------------ echo echo "==> Notarizing DMG" xcrun notarytool submit \ "$DMG_PATH" \ --keychain-profile "$NOTARY_PROFILE" \ --wait echo echo "==> Stapling DMG" xcrun stapler staple "$DMG_PATH" echo echo "==> Validating DMG ticket" xcrun stapler validate "$DMG_PATH" # ------------------------------------------------------------ # Final verification # ------------------------------------------------------------ echo echo "==> Final Gatekeeper verification" spctl \ --assess \ --type open \ --context context:primary-signature \ --verbose=4 \ "$DMG_PATH" echo echo "==> Final DMG information" ls -lh "$DMG_PATH" echo echo "==> SHA-256" shasum -a 256 "$DMG_PATH" echo echo "============================================================" echo " RELEASE BUILD COMPLETE" echo "============================================================" echo echo "DMG:" echo "$DMG_PATH" echo echo "Build log:" echo "$LOG_FILE" echo