From 8ba6636341dc862373afd1bcff0318bb1dfe5baf Mon Sep 17 00:00:00 2001 From: Steven Enamakel Date: Thu, 5 Feb 2026 14:36:58 +0530 Subject: [PATCH] chore: standardize quote styles and add new scripts for macOS app handling - Updated quote styles in package-and-publish.yml for consistency by converting single quotes to double quotes. - Introduced new scripts: recreate-dmg-macos.sh for DMG recreation after TDLib bundling and resign-macos.sh for re-signing the macOS app bundle, ensuring proper code signing after modifications. --- .github/workflows/package-and-publish.yml | 161 +++++----------------- src-tauri/scripts/recreate-dmg-macos.sh | 81 +++++++++++ src-tauri/scripts/resign-macos.sh | 113 +++++++++++++++ 3 files changed, 226 insertions(+), 129 deletions(-) create mode 100755 src-tauri/scripts/recreate-dmg-macos.sh create mode 100755 src-tauri/scripts/resign-macos.sh diff --git a/.github/workflows/package-and-publish.yml b/.github/workflows/package-and-publish.yml index fa511fc4a..4f4a48fdd 100644 --- a/.github/workflows/package-and-publish.yml +++ b/.github/workflows/package-and-publish.yml @@ -14,7 +14,7 @@ on: branches: - develop workflow_run: - workflows: ['Version Bump'] + workflows: ["Version Bump"] types: - completed branches: @@ -169,15 +169,15 @@ jobs: fail-fast: false matrix: settings: - - platform: 'macos-latest' - args: '--target aarch64-apple-darwin' - target: 'aarch64-apple-darwin' - - platform: 'macos-latest' - args: '--target x86_64-apple-darwin' - target: 'x86_64-apple-darwin' - - platform: 'ubuntu-22.04' - args: '' - target: '' + - platform: "macos-latest" + args: "--target aarch64-apple-darwin" + target: "aarch64-apple-darwin" + - platform: "macos-latest" + args: "--target x86_64-apple-darwin" + target: "x86_64-apple-darwin" + - platform: "ubuntu-22.04" + args: "" + target: "" runs-on: ${{ matrix.settings.platform }} steps: - name: Checkout @@ -197,7 +197,7 @@ jobs: uses: actions/setup-node@v4 with: node-version: 24.x - cache: 'yarn' + cache: "yarn" - name: Install Rust stable uses: dtolnay/rust-toolchain@stable @@ -318,7 +318,7 @@ jobs: # macOS 10.15+ required for std::filesystem used by llama.cpp MACOSX_DEPLOYMENT_TARGET: ${{ matrix.settings.platform == 'macos-latest' && '10.15' || '' }} with: - args: '-c ${{ steps.config-overrides.outputs.json }} ${{ matrix.settings.args }}' + args: "-c ${{ steps.config-overrides.outputs.json }} ${{ matrix.settings.args }}" includeDebug: ${{ needs.get-version.outputs.should-publish == '' && inputs.forceRelease != 'true' }} includeRelease: ${{ needs.get-version.outputs.should-publish != '' || inputs.forceRelease == 'true' }} # Don't let tauri-action upload for macOS - we need to bundle TDLib first and recreate the DMG @@ -327,125 +327,28 @@ jobs: owner: alphahumanxyz repo: alphahuman - # Bundle TDLib dylib into macOS app (fixes "Library not loaded" crash) - - name: Bundle TDLib for macOS - if: matrix.settings.platform == 'macos-latest' - run: | - TARGET="${{ matrix.settings.target }}" - echo "Bundling TDLib for target: $TARGET" - chmod +x ./src-tauri/scripts/bundle-tdlib-macos.sh - ./src-tauri/scripts/bundle-tdlib-macos.sh release "$TARGET" + # # Bundle TDLib dylib into macOS app (fixes "Library not loaded" crash) + # - name: Bundle TDLib for macOS + # if: matrix.settings.platform == 'macos-latest' + # run: | + # TARGET="${{ matrix.settings.target }}" + # echo "Bundling TDLib for target: $TARGET" + # chmod +x ./src-tauri/scripts/bundle-tdlib-macos.sh + # ./src-tauri/scripts/bundle-tdlib-macos.sh release "$TARGET" - # Re-sign the app after modifying the bundle (required for notarization) - - name: Re-sign macOS app after TDLib bundling - if: matrix.settings.platform == 'macos-latest' - env: - APPLE_CERTIFICATE: ${{ secrets.APPLE_CERTIFICATE_BASE64 }} - APPLE_CERTIFICATE_PASSWORD: ${{ secrets.APPLE_CERTIFICATE_PASSWORD }} - APPLE_SIGNING_IDENTITY: ${{ secrets.APPLE_SIGNING_IDENTITY }} - run: | - TARGET="${{ matrix.settings.target }}" - echo "Re-signing for target: $TARGET" + # # Re-sign the app after modifying the bundle (required for notarization) + # - name: Re-sign macOS app after TDLib bundling + # if: matrix.settings.platform == 'macos-latest' + # env: + # APPLE_CERTIFICATE: ${{ secrets.APPLE_CERTIFICATE_BASE64 }} + # APPLE_CERTIFICATE_PASSWORD: ${{ secrets.APPLE_CERTIFICATE_PASSWORD }} + # APPLE_SIGNING_IDENTITY: ${{ secrets.APPLE_SIGNING_IDENTITY }} + # run: bash ./src-tauri/scripts/resign-macos.sh release "${{ matrix.settings.target }}" - if [ -z "$APPLE_SIGNING_IDENTITY" ] || [ -z "$APPLE_CERTIFICATE" ]; then - echo "No signing identity or certificate provided, skipping re-sign" - exit 0 - fi - - # Import certificate into a temporary keychain (same approach as tauri-action) - KEYCHAIN_PATH="$RUNNER_TEMP/tdlib-signing.keychain-db" - KEYCHAIN_PASSWORD=$(openssl rand -base64 32) - - # Create and configure keychain - security create-keychain -p "$KEYCHAIN_PASSWORD" "$KEYCHAIN_PATH" - security set-keychain-settings -lut 21600 "$KEYCHAIN_PATH" - security unlock-keychain -p "$KEYCHAIN_PASSWORD" "$KEYCHAIN_PATH" - - # Import certificate - CERT_PATH="$RUNNER_TEMP/certificate.p12" - echo "$APPLE_CERTIFICATE" | base64 --decode > "$CERT_PATH" - security import "$CERT_PATH" -P "$APPLE_CERTIFICATE_PASSWORD" -A -t cert -f pkcs12 -k "$KEYCHAIN_PATH" - rm "$CERT_PATH" - - # Add keychain to search list - security list-keychains -d user -s "$KEYCHAIN_PATH" $(security list-keychains -d user | tr -d '"') - security set-key-partition-list -S apple-tool:,apple:,codesign: -s -k "$KEYCHAIN_PASSWORD" "$KEYCHAIN_PATH" - - # Find app bundle in target-specific or default location - if [ -n "$TARGET" ]; then - APP_BUNDLE=$(find "src-tauri/target/$TARGET/release/bundle/macos" -name "*.app" -type d 2>/dev/null | head -1) - fi - if [ -z "$APP_BUNDLE" ]; then - APP_BUNDLE=$(find "src-tauri/target/release/bundle/macos" -name "*.app" -type d 2>/dev/null | head -1) - fi - - if [ -n "$APP_BUNDLE" ]; then - echo "Re-signing app bundle: $APP_BUNDLE" - # Sign the bundled dylibs first - for dylib in "$APP_BUNDLE/Contents/Frameworks/"*.dylib; do - if [ -f "$dylib" ]; then - echo "Signing: $dylib" - codesign --force --options runtime --sign "$APPLE_SIGNING_IDENTITY" "$dylib" - fi - done - # Re-sign the entire app bundle - codesign --force --deep --options runtime --sign "$APPLE_SIGNING_IDENTITY" "$APP_BUNDLE" - echo "App re-signed successfully" - - # Verify signature - codesign --verify --verbose=2 "$APP_BUNDLE" || echo "Warning: Signature verification had issues" - else - echo "Warning: No app bundle found to re-sign" - fi - - # Cleanup keychain - security delete-keychain "$KEYCHAIN_PATH" || true - - # Re-create DMG after TDLib bundling (the original DMG was created before bundling) - - name: Recreate DMG with bundled TDLib - if: matrix.settings.platform == 'macos-latest' - run: | - TARGET="${{ matrix.settings.target }}" - echo "Recreating DMG for target: $TARGET" - - # Tauri v2 puts .app in bundle/macos/ and .dmg in bundle/dmg/ - if [ -n "$TARGET" ]; then - BASE_BUNDLE_DIR="src-tauri/target/$TARGET/release/bundle" - else - BASE_BUNDLE_DIR="src-tauri/target/release/bundle" - fi - - MACOS_DIR="$BASE_BUNDLE_DIR/macos" - DMG_DIR="$BASE_BUNDLE_DIR/dmg" - - APP_BUNDLE=$(find "$MACOS_DIR" -name "*.app" -type d 2>/dev/null | head -1) - if [ -z "$APP_BUNDLE" ]; then - echo "Error: No app bundle found in $MACOS_DIR" - exit 1 - fi - - APP_NAME=$(basename "$APP_BUNDLE" .app) - - # Find the original DMG in bundle/dmg/ (NOT bundle/macos/) - ORIGINAL_DMG=$(find "$DMG_DIR" -name "*.dmg" -type f 2>/dev/null | head -1) - if [ -z "$ORIGINAL_DMG" ]; then - echo "Warning: No original DMG found in $DMG_DIR, skipping DMG recreation" - exit 0 - fi - - echo "Recreating DMG with bundled TDLib..." - echo "App bundle: $APP_BUNDLE" - echo "Original DMG: $ORIGINAL_DMG" - - # Remove the old DMG - rm -f "$ORIGINAL_DMG" - - # Create new DMG with the updated app bundle - DMG_NAME=$(basename "$ORIGINAL_DMG") - hdiutil create -volname "$APP_NAME" -srcfolder "$APP_BUNDLE" -ov -format UDZO "$DMG_DIR/$DMG_NAME" - - echo "DMG recreated successfully: $DMG_DIR/$DMG_NAME" - ls -la "$DMG_DIR/$DMG_NAME" + # # Re-create DMG after TDLib bundling (the original DMG was created before bundling) + # - name: Recreate DMG with bundled TDLib + # if: matrix.settings.platform == 'macos-latest' + # run: bash ./src-tauri/scripts/recreate-dmg-macos.sh release "${{ matrix.settings.target }}" - name: Get file info id: file-info diff --git a/src-tauri/scripts/recreate-dmg-macos.sh b/src-tauri/scripts/recreate-dmg-macos.sh new file mode 100755 index 000000000..e8cd3ca42 --- /dev/null +++ b/src-tauri/scripts/recreate-dmg-macos.sh @@ -0,0 +1,81 @@ +#!/bin/bash +# Recreate macOS DMG after TDLib bundling +# The original DMG is created by tauri-action BEFORE we bundle TDLib, +# so we need to recreate it with the updated .app bundle. +# +# Usage: +# ./recreate-dmg-macos.sh [target] +# +# Arguments: +# build_type - "release" or "debug" (default: release) +# target - Optional cross-compilation target (e.g., aarch64-apple-darwin) +# +# Examples: +# ./recreate-dmg-macos.sh release +# ./recreate-dmg-macos.sh release aarch64-apple-darwin + +set -e + +BUILD_TYPE="${1:-release}" +TARGET="${2:-}" + +SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" +TAURI_DIR="$(dirname "$SCRIPT_DIR")" + +echo "=== macOS DMG Recreation ===" +echo "Build type: ${BUILD_TYPE}" +echo "Target: ${TARGET:-default}" + +# --- Determine bundle directories --- +# Tauri v2 puts .app in bundle/macos/ and .dmg in bundle/dmg/ +BASE_BUNDLE_DIR="" +for search_dir in \ + "${TAURI_DIR}/target/${TARGET}/${BUILD_TYPE}/bundle" \ + "${TAURI_DIR}/target/${BUILD_TYPE}/bundle" \ + "${TAURI_DIR}/target/release/bundle" \ + "${TAURI_DIR}/target/debug/bundle"; do + if [ -d "$search_dir/macos" ]; then + BASE_BUNDLE_DIR="$search_dir" + break + fi +done + +if [ -z "$BASE_BUNDLE_DIR" ]; then + echo "Warning: No bundle directory found" + exit 0 +fi + +MACOS_DIR="$BASE_BUNDLE_DIR/macos" +DMG_DIR="$BASE_BUNDLE_DIR/dmg" + +echo "Bundle base: $BASE_BUNDLE_DIR" + +# --- Find the app bundle --- +APP_BUNDLE=$(find "$MACOS_DIR" -name "*.app" -type d 2>/dev/null | head -1) +if [ -z "$APP_BUNDLE" ]; then + echo "Error: No .app bundle found in $MACOS_DIR" + exit 1 +fi + +APP_NAME=$(basename "$APP_BUNDLE" .app) +echo "App bundle: $APP_BUNDLE" + +# --- Find the original DMG --- +ORIGINAL_DMG=$(find "$DMG_DIR" -name "*.dmg" -type f 2>/dev/null | head -1) +if [ -z "$ORIGINAL_DMG" ]; then + echo "Warning: No original DMG found in $DMG_DIR, skipping" + exit 0 +fi + +DMG_NAME=$(basename "$ORIGINAL_DMG") +echo "Original DMG: $ORIGINAL_DMG" + +# --- Remove old DMG and create new one --- +echo "" +echo "Creating new DMG..." +rm -f "$ORIGINAL_DMG" +hdiutil create -volname "$APP_NAME" -srcfolder "$APP_BUNDLE" -ov -format UDZO "$DMG_DIR/$DMG_NAME" + +echo "" +echo "=== DMG recreation complete ===" +ls -lh "$DMG_DIR/$DMG_NAME" diff --git a/src-tauri/scripts/resign-macos.sh b/src-tauri/scripts/resign-macos.sh new file mode 100755 index 000000000..7d57fb989 --- /dev/null +++ b/src-tauri/scripts/resign-macos.sh @@ -0,0 +1,113 @@ +#!/bin/bash +# Re-sign macOS app bundle after TDLib bundling +# Required because modifying the bundle invalidates the original code signature. +# +# Usage: +# ./resign-macos.sh [target] +# +# Arguments: +# build_type - "release" or "debug" (default: release) +# target - Optional cross-compilation target (e.g., aarch64-apple-darwin) +# +# Environment variables: +# APPLE_SIGNING_IDENTITY - Signing identity (e.g., "Developer ID Application: ...") +# If unset, uses ad-hoc signing ("-") for local testing. +# APPLE_CERTIFICATE - Base64-encoded .p12 certificate (CI only) +# APPLE_CERTIFICATE_PASSWORD - Password for the .p12 certificate (CI only) +# +# Examples: +# # Local testing (ad-hoc signing) +# ./resign-macos.sh release +# +# # CI with identity +# APPLE_SIGNING_IDENTITY="Developer ID Application: ..." ./resign-macos.sh release aarch64-apple-darwin + +set -e + +BUILD_TYPE="${1:-release}" +TARGET="${2:-}" + +SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" +TAURI_DIR="$(dirname "$SCRIPT_DIR")" + +SIGNING_IDENTITY="${APPLE_SIGNING_IDENTITY:--}" + +echo "=== macOS App Re-signing ===" +echo "Build type: ${BUILD_TYPE}" +echo "Target: ${TARGET:-default}" +echo "Signing identity: ${SIGNING_IDENTITY}" + +# --- CI keychain setup (only when APPLE_CERTIFICATE is provided) --- +KEYCHAIN_PATH="" +if [ -n "$APPLE_CERTIFICATE" ] && [ -n "$APPLE_CERTIFICATE_PASSWORD" ]; then + echo "" + echo "Importing certificate into temporary keychain..." + TEMP_DIR="${RUNNER_TEMP:-/tmp}" + KEYCHAIN_PATH="$TEMP_DIR/tdlib-signing.keychain-db" + KEYCHAIN_PASSWORD=$(openssl rand -base64 32) + + security create-keychain -p "$KEYCHAIN_PASSWORD" "$KEYCHAIN_PATH" + security set-keychain-settings -lut 21600 "$KEYCHAIN_PATH" + security unlock-keychain -p "$KEYCHAIN_PASSWORD" "$KEYCHAIN_PATH" + + CERT_PATH="$TEMP_DIR/certificate.p12" + echo "$APPLE_CERTIFICATE" | base64 --decode > "$CERT_PATH" + security import "$CERT_PATH" -P "$APPLE_CERTIFICATE_PASSWORD" -A -t cert -f pkcs12 -k "$KEYCHAIN_PATH" + rm "$CERT_PATH" + + security list-keychains -d user -s "$KEYCHAIN_PATH" $(security list-keychains -d user | tr -d '"') + security set-key-partition-list -S apple-tool:,apple:,codesign: -s -k "$KEYCHAIN_PASSWORD" "$KEYCHAIN_PATH" + echo "Certificate imported" +fi + +# --- Find the app bundle --- +APP_BUNDLE="" +for search_dir in \ + "${TAURI_DIR}/target/${TARGET}/${BUILD_TYPE}/bundle/macos" \ + "${TAURI_DIR}/target/${BUILD_TYPE}/bundle/macos" \ + "${TAURI_DIR}/target/release/bundle/macos" \ + "${TAURI_DIR}/target/debug/bundle/macos"; do + if [ -d "$search_dir" ]; then + found=$(find "$search_dir" -name "*.app" -type d 2>/dev/null | head -1) + if [ -n "$found" ]; then + APP_BUNDLE="$found" + break + fi + fi +done + +if [ -z "$APP_BUNDLE" ]; then + echo "Warning: No .app bundle found, nothing to sign" + exit 0 +fi + +echo "" +echo "Signing app bundle: $APP_BUNDLE" + +# --- Sign bundled dylibs first (inner-to-outer signing order) --- +FRAMEWORKS_DIR="$APP_BUNDLE/Contents/Frameworks" +if [ -d "$FRAMEWORKS_DIR" ]; then + for dylib in "$FRAMEWORKS_DIR"/*.dylib; do + if [ -f "$dylib" ]; then + echo " Signing: $(basename "$dylib")" + codesign --force --options runtime --sign "$SIGNING_IDENTITY" "$dylib" + fi + done +fi + +# --- Sign the app bundle --- +echo " Signing: $(basename "$APP_BUNDLE")" +codesign --force --deep --options runtime --sign "$SIGNING_IDENTITY" "$APP_BUNDLE" + +# --- Verify --- +echo "" +echo "Verifying signature..." +codesign --verify --verbose=2 "$APP_BUNDLE" 2>&1 || echo "Warning: Signature verification had issues" + +# --- Cleanup CI keychain --- +if [ -n "$KEYCHAIN_PATH" ]; then + security delete-keychain "$KEYCHAIN_PATH" || true +fi + +echo "" +echo "=== Re-signing complete ==="