name: "Artcraft MacOS Publish" on: push: branches: - release - artcraft-release - artcraft-macos # Additional branch for MacOS testing # This workflow creates Universal macOS builds with signing certificate support. # On each push to the release branches it will create or update a GitHub release, build your app, and upload the artifacts to the release. jobs: publish-artcraft: permissions: contents: write strategy: fail-fast: false matrix: include: # Universal macOS builds (arm64 and x86_64) - platform: 'macos-latest-xlarge' args: '--target universal-apple-darwin' # Uncomment below for additional platforms # - platform: 'ubuntu-22.04' # args: '' # - platform: 'windows-latest' # args: '' runs-on: ${{ matrix.platform }} steps: - uses: actions/checkout@v4 - name: setup node uses: actions/setup-node@v4 with: node-version: lts/* - name: install Rust stable uses: dtolnay/rust-toolchain@stable with: targets: ${{ matrix.platform == 'macos-latest-xlarge' && 'aarch64-apple-darwin,x86_64-apple-darwin' || '' }} - name: install dependencies (ubuntu only) if: matrix.platform == 'ubuntu-22.04' run: | sudo apt-get update sudo apt-get install -y libwebkit2gtk-4.1-dev libappindicator3-dev librsvg2-dev patchelf - name: replace tauri config with mac-specific version run: | pushd ${{ github.workspace }}/crates/desktop/artcraft # Use the mac-specific tauri conf for the build # TODO(bt): Replace this with the platform-specific naming conventions cp tauri-mac.conf.json tauri.conf.json popd - name: install frontend dependencies run: | # Navigate to the frontend directory to install dependencies cd ./frontend npm cache clean --force echo "Installing all workspace dependencies..." npm ci echo "=== Version Information ===" echo "Node version:" node --version echo "NPM version:" npm --version echo "=== Nx versions from lockfile ===" npm list --depth=0 | grep nx - name: import Apple Developer Certificate if: matrix.platform == 'macos-latest-xlarge' env: APPLE_CERTIFICATE: ${{ secrets.APPLE_CERTIFICATE }} APPLE_CERTIFICATE_PASSWORD: ${{ secrets.APPLE_CERTIFICATE_PASSWORD }} KEYCHAIN_PASSWORD: ${{ secrets.KEYCHAIN_PASSWORD }} run: | echo "Starting certificate import process..." # Create certificate file echo $APPLE_CERTIFICATE | base64 --decode > certificate.p12 # Debug: Check if certificate file exists and has content echo "Certificate file info:" ls -la certificate.p12 file certificate.p12 # Debug: Check certificate contents without password (just structure) echo "Certificate structure (may show error if password protected):" openssl pkcs12 -info -in certificate.p12 -passin pass:$APPLE_CERTIFICATE_PASSWORD -noout || echo "Could not read certificate structure" # Debug: Try to list what's in the p12 file echo "Attempting to list certificate contents:" security cms -D -i certificate.p12 || echo "Not a CMS file, trying PKCS12..." openssl pkcs12 -in certificate.p12 -passin pass:$APPLE_CERTIFICATE_PASSWORD -info -nodes 2>&1 | head -20 || echo "Failed to read PKCS12 contents" # Debug: Extract certificate details to verify type and expiration echo "Extracting certificate details..." # Extract just the certificate portion and examine it openssl pkcs12 -in certificate.p12 -passin pass:$APPLE_CERTIFICATE_PASSWORD -nokeys 2>/dev/null | openssl x509 -text -noout | grep -E "(Subject:|Issuer:|Not Before|Not After)" || echo "Failed to parse certificate details" # Also try to see what type of certificate this is echo "Certificate type check:" openssl pkcs12 -in certificate.p12 -passin pass:$APPLE_CERTIFICATE_PASSWORD -nokeys 2>/dev/null | openssl x509 -text -noout | grep -E "(CN=|OU=)" || echo "Could not determine certificate type" # Debug: Check if private key exists echo "Checking for private key..." openssl pkcs12 -in certificate.p12 -passin pass:$APPLE_CERTIFICATE_PASSWORD -nocerts -nodes 2>&1 | grep -E "(PRIVATE KEY|RSA KEY)" | head -5 || echo "No private key found" # Create temporary keychain security create-keychain -p "$KEYCHAIN_PASSWORD" build.keychain security default-keychain -s build.keychain security unlock-keychain -p "$KEYCHAIN_PASSWORD" build.keychain security set-keychain-settings -t 3600 -u build.keychain # Import certificate - ensure both certificate and private key are imported echo "Importing certificate into keychain..." # Import the p12 directly - this is the most reliable method security import certificate.p12 -k build.keychain -P "$APPLE_CERTIFICATE_PASSWORD" -T /usr/bin/codesign -T /usr/bin/security -T /usr/bin/productbuild # Alternative: Try with additional flags if the first import didn't create an identity echo "Verifying import..." if ! security find-identity -v build.keychain | grep -q "1 valid identities found"; then echo "First import didn't create identity, trying with -A flag..." security import certificate.p12 -k build.keychain -P "$APPLE_CERTIFICATE_PASSWORD" -A fi # Set trust settings for the certificate echo "Setting trust settings..." security set-key-partition-list -S apple-tool:,apple:,codesign: -s -k "$KEYCHAIN_PASSWORD" build.keychain # Unlock the keychain again to ensure it's accessible security unlock-keychain -p "$KEYCHAIN_PASSWORD" build.keychain # Add the keychain to the search list security list-keychains -d user -s build.keychain $(security list-keychains -d user | sed 's/^[[:space:]]*"//;s/"$//') # List all certificates to debug echo "Listing all keychains:" security list-keychains echo "Listing all certificates in build keychain:" security find-certificate -a -p build.keychain || echo "No certificates found" echo "Detailed certificate info:" security find-certificate -c "Learning Machines" build.keychain || echo "Certificate 'Learning Machines' not found" # Check certificate trust settings echo "Checking certificate trust settings:" security dump-trust-settings || echo "No custom trust settings" # Try to find codesigning identities echo "Finding all identities in keychain:" security find-identity -v build.keychain || echo "No identities found" echo "Finding codesigning identities:" security find-identity -v -p codesigning build.keychain || echo "No codesigning identities found" # Additional debug: Check if this is a valid Developer ID cert echo "Checking for Developer ID certificates:" security find-certificate -a build.keychain | grep -A 5 -B 5 "Developer ID" || echo "No Developer ID certificates found" - name: verify certificate if: matrix.platform == 'macos-latest-xlarge' run: | echo "=== Certificate Verification ===" echo "1. Checking codesigning identities:" security find-identity -v -p codesigning build.keychain || echo "No codesigning identities found" echo -e "\n2. Checking all identities:" security find-identity -v build.keychain || echo "No identities found" echo -e "\n3. Checking certificates in keychain:" security find-certificate -c "Learning Machines" build.keychain -p | openssl x509 -text -noout | grep -E "(Subject:|CN=)" || echo "Could not parse certificate" # Set the correct signing identity echo "APPLE_SIGNING_IDENTITY=Developer ID Application: Learning Machines LLC (DJ6XS33FX8)" >> $GITHUB_ENV echo "Proceeding with identity: Developer ID Application: Learning Machines LLC (DJ6XS33FX8)" # Also set the team ID echo "APPLE_DEVELOPMENT_TEAM=DJ6XS33FX8" >> $GITHUB_ENV - name: Pre-build frontend to avoid Tauri build issues run: | # Build the frontend app from the correct directory cd ./frontend # Increase Node.js memory limit for the build export NODE_OPTIONS="--max-old-space-size=8192" # Use npx to ensure we use the local nx version echo "Building with npx nx..." npx nx run artcraft:build echo "Checking build output..." ls -la apps/artcraft/dist/ | head -10 # Update Tauri config to skip the build (since we already built) cd ${{ github.workspace }}/crates/desktop/artcraft cp tauri.conf.json tauri.conf.json.bak # Set beforeBuildCommand to empty or a no-op command if command -v jq &> /dev/null; then jq '.build.beforeBuildCommand = ""' tauri.conf.json > tauri.conf.json.tmp mv tauri.conf.json.tmp tauri.conf.json else node -e "const fs = require('fs'); const config = JSON.parse(fs.readFileSync('tauri.conf.json', 'utf8')); config.build.beforeBuildCommand = ''; fs.writeFileSync('tauri.conf.json', JSON.stringify(config, null, 2));" fi - name: build and publish uses: tauri-apps/tauri-action@v0 env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} APPLE_ID: ${{ secrets.APPLE_ID }} APPLE_ID_PASSWORD: ${{ secrets.APPLE_ID_PASSWORD }} APPLE_PASSWORD: ${{ secrets.APPLE_PASSWORD }} APPLE_TEAM_ID: ${{ secrets.APPLE_TEAM_ID }} APPLE_CERTIFICATE_PASSWORD: ${{ secrets.APPLE_CERTIFICATE_PASSWORD }} APPLE_SIGNING_IDENTITY: ${{ env.APPLE_SIGNING_IDENTITY }} APPLE_DEVELOPMENT_TEAM: ${{ env.APPLE_DEVELOPMENT_TEAM }} # Use the SQLx query cache for SQLite SQLX_OFFLINE: true with: projectPath: ./crates/desktop/artcraft tagName: artcraft-v__VERSION__ # the action automatically replaces __VERSION__ with the app version. releaseName: "ArtCraft v__VERSION__" releaseBody: "See the assets below to download this version and install." releaseDraft: true prerelease: false args: ${{ matrix.args }}