#!/bin/bash set -euo pipefail # DBSyn — Developer ID direct distribution (signed and notarized app + DMG) # Install at: /scripts/release-dbsyn-direct.sh # Run from any directory: ./scripts/release-dbsyn-direct.sh APP_NAME="DBSyn" SCHEME="DBSyn" PROJECT="DBSyn.xcodeproj" TEAM_ID="${TEAM_ID:-39R6U3437D}" SIGNING_IDENTITY="${SIGNING_IDENTITY:-B99D353C88996866C49E4389B375645F76870A3F}" NOTARY_PROFILE="${NOTARY_PROFILE:-orion-notary}" SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" if [[ -d "$SCRIPT_DIR/$PROJECT" ]]; then ROOT_DIR="$SCRIPT_DIR" elif [[ -d "$SCRIPT_DIR/../$PROJECT" ]]; then ROOT_DIR="$(cd "$SCRIPT_DIR/.." && pwd)" else echo "ERROR: $PROJECT not found next to this script or in its parent directory." >&2 exit 1 fi BUILD_DIR="$ROOT_DIR/build/direct-distribution" ARCHIVE_PATH="$BUILD_DIR/$APP_NAME.xcarchive" EXPORT_DIR="$BUILD_DIR/export" DMG_STAGE="$BUILD_DIR/dmg-stage" EXPORT_OPTIONS="$BUILD_DIR/ExportOptions.plist" APP_ZIP="$BUILD_DIR/$APP_NAME-notarization.zip" RELEASE_DIR="$ROOT_DIR/releases" DMG_PATH="$RELEASE_DIR/$APP_NAME.dmg" for tool in xcodebuild xcrun codesign spctl ditto hdiutil shasum security; do command -v "$tool" >/dev/null || { echo "ERROR: Missing $tool" >&2; exit 1; } done [[ -d "$ROOT_DIR/$PROJECT" ]] || { echo "ERROR: Missing $PROJECT" >&2; exit 1; } security find-identity -v -p codesigning | grep -Fq "$SIGNING_IDENTITY" || { echo "ERROR: Signing identity $SIGNING_IDENTITY not available in Keychain." >&2 exit 1 } # Check that notarytool profile exists before spending time compiling. xcrun notarytool history --keychain-profile "$NOTARY_PROFILE" >/dev/null || { echo "ERROR: Notarytool profile '$NOTARY_PROFILE' is unavailable or invalid." >&2 exit 1 } printf '\n========== DBSyn DIRECT DISTRIBUTION ==========\n' cd "$ROOT_DIR" rm -rf "$BUILD_DIR" mkdir -p "$BUILD_DIR" "$EXPORT_DIR" "$DMG_STAGE" "$RELEASE_DIR" # Keep previous releases until a new notarized DMG has been successfully built. cat > "$EXPORT_OPTIONS" < methoddeveloper-id signingStyleautomatic teamID$TEAM_ID PLIST echo '==> Archiving DBSyn (Release)...' xcodebuild -project "$PROJECT" -scheme "$SCHEME" -configuration Release \ -destination 'generic/platform=macOS' -archivePath "$ARCHIVE_PATH" \ DEVELOPMENT_TEAM="$TEAM_ID" CODE_SIGN_STYLE=Automatic \ clean archive echo '==> Exporting Developer ID application...' xcodebuild -exportArchive -archivePath "$ARCHIVE_PATH" \ -exportPath "$EXPORT_DIR" -exportOptionsPlist "$EXPORT_OPTIONS" APP_PATH="$EXPORT_DIR/$APP_NAME.app" [[ -d "$APP_PATH" ]] || { echo "ERROR: Exported app missing: $APP_PATH" >&2; exit 1; } echo '==> Checking application signature and hardened runtime...' codesign --verify --deep --strict --verbose=2 "$APP_PATH" codesign -dv --verbose=4 "$APP_PATH" 2>&1 | grep -E 'Identifier=|Authority=|TeamIdentifier=|Runtime Version=|flags=' || true ACTUAL_TEAM="$(codesign -dv --verbose=4 "$APP_PATH" 2>&1 | sed -n 's/^TeamIdentifier=//p' | head -1)" [[ "$ACTUAL_TEAM" == "$TEAM_ID" ]] || { echo "ERROR: Unexpected signing team: $ACTUAL_TEAM" >&2; exit 1; } codesign -dv --verbose=4 "$APP_PATH" 2>&1 | grep -q 'runtime' || { echo 'ERROR: App is not signed with the hardened runtime required for notarization.' >&2 exit 1 } echo '==> Notarizing application...' ditto -c -k --keepParent "$APP_PATH" "$APP_ZIP" xcrun notarytool submit "$APP_ZIP" --keychain-profile "$NOTARY_PROFILE" --wait xcrun stapler staple "$APP_PATH" xcrun stapler validate "$APP_PATH" spctl --assess --type execute --verbose=4 "$APP_PATH" echo '==> Creating installer DMG...' ditto "$APP_PATH" "$DMG_STAGE/$APP_NAME.app" ln -s /Applications "$DMG_STAGE/Applications" TMP_DMG="$BUILD_DIR/$APP_NAME.dmg" hdiutil create -volname "$APP_NAME" -srcfolder "$DMG_STAGE" -ov -format UDZO "$TMP_DMG" echo '==> Signing and notarizing DMG...' codesign --force --timestamp --sign "$SIGNING_IDENTITY" "$TMP_DMG" codesign --verify --verbose=2 "$TMP_DMG" xcrun notarytool submit "$TMP_DMG" --keychain-profile "$NOTARY_PROFILE" --wait xcrun stapler staple "$TMP_DMG" xcrun stapler validate "$TMP_DMG" spctl --assess --type open --context context:primary-signature --verbose=4 "$TMP_DMG" # Publish only after all checks have passed. cp -f "$TMP_DMG" "$DMG_PATH" echo '==> Release ready:' ls -lh "$DMG_PATH" shasum -a 256 "$DMG_PATH" printf '\n========== DBSyn RELEASE COMPLETE ==========\n%s\n' "$DMG_PATH"