#!/bin/bash # # release.sh — Metrika # Author: Simon-Pierre Boucher # Contact: contact@spboucher.ai # Copyright © 2026 Simon-Pierre Boucher. All rights reserved. # # Release pipeline (CLAUDE.md §10): archive → export → verify → DMG → # sign → notarize → staple. The team ID and keychain-profile NAME are # configuration, not credentials — the actual Apple ID and app-specific # password live only in the login keychain (stored once via # `xcrun notarytool store-credentials "MacLustr-Notarize"`). # set -euo pipefail APP="Metrika" SCHEME="Metrika" BUILD_DIR="build" DMG="${APP}.dmg" TEAM_ID="3YM54G49SN" NOTARY_PROFILE="MacLustr-Notarize" SIGN_IDENTITY="Developer ID Application: Simon-Pierre Boucher (${TEAM_ID})" cd "$(dirname "$0")/.." rm -rf "$BUILD_DIR" "$DMG" # 0. Regenerate the Xcode project and the icon from their sources. xcodegen generate ./scripts/make_icns.sh # 1. Archive (Developer ID signing; mlx-swift needs the plugin skip). xcodebuild -project "$APP.xcodeproj" -scheme "$SCHEME" \ -configuration Release -arch arm64 \ -archivePath "$BUILD_DIR/$APP.xcarchive" \ -skipPackagePluginValidation \ DEVELOPMENT_TEAM="$TEAM_ID" \ CODE_SIGN_IDENTITY="$SIGN_IDENTITY" \ CODE_SIGN_STYLE=Manual \ OTHER_CODE_SIGN_FLAGS="--timestamp --options runtime" \ archive # 2. Export with Developer ID xcodebuild -exportArchive \ -archivePath "$BUILD_DIR/$APP.xcarchive" \ -exportOptionsPlist scripts/ExportOptions.plist \ -exportPath "$BUILD_DIR/export" # 3. Verify hardened runtime + entitlements codesign -dv --verbose=4 "$BUILD_DIR/export/$APP.app" codesign --verify --deep --strict "$BUILD_DIR/export/$APP.app" # 4. Build DMG (create-dmg, background art in Assets/DMG/). Stage only # the .app — the export folder also contains packaging logs that must # not ship inside the image. STAGE="$BUILD_DIR/dmg-stage" rm -rf "$STAGE" && mkdir -p "$STAGE" cp -R "$BUILD_DIR/export/$APP.app" "$STAGE/" create-dmg \ --volname "$APP" \ --window-size 540 380 \ --icon-size 128 \ --icon "$APP.app" 130 190 \ --app-drop-link 400 190 \ --background "Assets/DMG/background.png" \ --no-internet-enable \ "$DMG" "$STAGE/" # 5. Sign the DMG itself codesign --sign "$SIGN_IDENTITY" --timestamp "$DMG" # 6. Notarize & wait xcrun notarytool submit "$DMG" \ --keychain-profile "$NOTARY_PROFILE" \ --wait # 7. Staple xcrun stapler staple "$DMG" xcrun stapler validate "$DMG" echo "✅ $DMG notarized and stapled."