From 3cc278081ceca9276a58b29d4f747b6605cc3a04 Mon Sep 17 00:00:00 2001 From: Ozgur Ersoy Date: Sat, 12 Apr 2025 23:19:26 +0200 Subject: [PATCH 001/109] chore(workflows): remove obsolete build scripts and workflows for Linux, Mac, and Windows --- .gitignore | 1 + linux_build.sh => scripts/linux_build.sh | 0 mac_build.sh => scripts/mac_build.sh | 0 win_build.sh => scripts/win_build.sh | 0 4 files changed, 1 insertion(+) rename linux_build.sh => scripts/linux_build.sh (100%) rename mac_build.sh => scripts/mac_build.sh (100%) rename win_build.sh => scripts/win_build.sh (100%) diff --git a/.gitignore b/.gitignore index 21abe81c..dceaf989 100644 --- a/.gitignore +++ b/.gitignore @@ -41,3 +41,4 @@ DerivedDataCache/* #this only is the Binaries folder on the root, not the Binaries folder in the plugin folders Binaries/** *.app/ +.cursorrules diff --git a/linux_build.sh b/scripts/linux_build.sh similarity index 100% rename from linux_build.sh rename to scripts/linux_build.sh diff --git a/mac_build.sh b/scripts/mac_build.sh similarity index 100% rename from mac_build.sh rename to scripts/mac_build.sh diff --git a/win_build.sh b/scripts/win_build.sh similarity index 100% rename from win_build.sh rename to scripts/win_build.sh -- 2.47.2 From dca79841d459fab7759ae9923feec5576e6f1809 Mon Sep 17 00:00:00 2001 From: Ozgur Ersoy Date: Sat, 12 Apr 2025 23:19:39 +0200 Subject: [PATCH 002/109] feat(workflows): add new build workflows for Windows, Linux, and macOS, and remove obsolete build scripts --- .gitea/workflows/build.yml | 45 ++++ .gitea/workflows/create-release.yml | 103 --------- .gitea/workflows/linux-build.yml | 53 +++++ .gitea/workflows/macos-build.yml | 81 +++++++ .gitea/workflows/release.yml | 163 +++++++++++++ .gitea/workflows/unreal-build.yml | 347 ---------------------------- .gitea/workflows/windows-build.yml | 49 ++++ 7 files changed, 391 insertions(+), 450 deletions(-) create mode 100644 .gitea/workflows/build.yml delete mode 100644 .gitea/workflows/create-release.yml create mode 100644 .gitea/workflows/linux-build.yml create mode 100644 .gitea/workflows/macos-build.yml create mode 100644 .gitea/workflows/release.yml delete mode 100644 .gitea/workflows/unreal-build.yml create mode 100644 .gitea/workflows/windows-build.yml diff --git a/.gitea/workflows/build.yml b/.gitea/workflows/build.yml new file mode 100644 index 00000000..52b2714a --- /dev/null +++ b/.gitea/workflows/build.yml @@ -0,0 +1,45 @@ +name: Unreal Engine Build + +on: + workflow_dispatch: + push: + branches: [ozgur/build] + +jobs: + trigger-builds: + runs-on: ubuntu-latest + steps: + - name: Checkout repository + uses: actions/checkout@v3 + with: + fetch-depth: 0 + + - name: Trigger Windows Build + uses: https://gitea.com/actions/gitea-actions-dispatcher@v0.1.0 + with: + workflow: windows-build.yml + token: ${{ secrets.GITEATOKEN }} + + - name: Trigger Linux Build + uses: https://gitea.com/actions/gitea-actions-dispatcher@v0.1.0 + with: + workflow: linux-build.yml + token: ${{ secrets.GITEATOKEN }} + + - name: Trigger macOS Build + uses: https://gitea.com/actions/gitea-actions-dispatcher@v0.1.0 + with: + workflow: macos-build.yml + token: ${{ secrets.GITEATOKEN }} + + - name: Wait for builds to complete + run: | + echo "Waiting for platform builds to complete..." + sleep 60 # Adding a delay to ensure builds have time to start + + - name: Trigger Release Creation + if: github.ref == 'refs/heads/main' || github.ref == 'refs/heads/develop' + uses: https://gitea.com/actions/gitea-actions-dispatcher@v0.1.0 + with: + workflow: release.yml + token: ${{ secrets.GITEATOKEN }} \ No newline at end of file diff --git a/.gitea/workflows/create-release.yml b/.gitea/workflows/create-release.yml deleted file mode 100644 index 555b5af2..00000000 --- a/.gitea/workflows/create-release.yml +++ /dev/null @@ -1,103 +0,0 @@ -name: Unreal Release - -on: - workflow_dispatch: - inputs: - windows_build_path: - description: 'Absolute path to the Windows build zip file' - required: true - default: 'E:\LuckyWorld\LuckyRobots\UNREAL_PROJECTS\Luckyrobots\Builds\Windows\LuckyRobots-Windows.zip' - linux_build_path: - description: 'Absolute path to the Linux build zip file' - required: true - default: 'E:\LuckyWorld\LuckyRobots\UNREAL_PROJECTS\Luckyrobots\Builds\Linux\LuckyRobots-Linux.zip' - mac_build_path: - description: 'Absolute path to the Mac build zip file' - required: true - default: 'E:\LuckyWorld\LuckyRobots\UNREAL_PROJECTS\Luckyrobots\Builds\Mac\LuckyRobots-Mac.zip' - -jobs: - build: - runs-on: windows - steps: - - name: Upload Linux Build Artifact - uses: actions/upload-artifact@v3 - with: - name: LuckyRobots-Linux - path: ${{ github.event.inputs.linux_build_path }} - retention-days: 365 - - - name: Upload Windows Build Artifact - uses: actions/upload-artifact@v3 - with: - name: LuckyRobots-Windows - path: ${{ github.event.inputs.windows_build_path }} - retention-days: 365 - - - name: Upload Mac Build Artifact - uses: actions/upload-artifact@v3 - with: - name: LuckyRobots-Mac - path: ${{ github.event.inputs.mac_build_path }} - retention-days: 365 - - - name: Get Release Tag - shell: pwsh - run: | - # Fetch all tags - git fetch --tags - - # Get the latest version tag, if any - # Uses Sort-Object with a version comparison scriptblock - $latestTag = git tag -l "v[0-9]*.[0-9]*.[0-9]*" | Sort-Object -Property @{Expression={[version]($_ -replace 'v')}} | Select-Object -Last 1 - - $newVersion = "1.0.0" # Default start version - - if ($null -ne $latestTag -and $latestTag -ne '') { - Write-Host "Latest tag found: $latestTag" - # Strip 'v' prefix - $versionString = $latestTag -replace '^v' - - # Split version into parts - $versionParts = $versionString.Split('.') - if ($versionParts.Length -eq 3) { - $major = [int]$versionParts[0] - $minor = [int]$versionParts[1] - $patch = [int]$versionParts[2] - - # Auto-increment patch version - $patch++ - $newVersion = "$major.$minor.$patch" - Write-Host "Auto-incremented patch version from $versionString to $newVersion" - } else { - Write-Host "Could not parse version from tag: $latestTag. Defaulting to 1.0.0" - } - } else { - Write-Host "No previous version tags found, starting with 1.0.0" - } - - # Final tag with v prefix - $tag = "v$newVersion" - - # Set environment variable for subsequent steps - echo "RELEASE_TAG=$tag" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append - Write-Host "Using release tag: $tag" - - - name: Create Release - uses: https://gitea.com/actions/gitea-release-action@main - with: - token: '${{ secrets.GITEA_TOKEN }}' - title: 'Release ${{ env.RELEASE_TAG }}' - body: | - ## LuckyRobots Game Release ${{ env.RELEASE_TAG }} - - Windows, Linux and Mac builds are attached below. - - ### Build Information - - - Build Number: #${{ github.run_number }} - - Commit: ${{ github.sha }} - - Branch: ${{ github.ref_name }} - - Build Date: $(date -u +"%Y-%m-%d %H:%M:%S UTC") - prerelease: ${{ github.ref != 'refs/heads/main' }} - tag_name: '${{ env.RELEASE_TAG }}' \ No newline at end of file diff --git a/.gitea/workflows/linux-build.yml b/.gitea/workflows/linux-build.yml new file mode 100644 index 00000000..51117aaf --- /dev/null +++ b/.gitea/workflows/linux-build.yml @@ -0,0 +1,53 @@ +name: Linux Build + +on: + workflow_dispatch: + workflow_call: + +jobs: + linux-build: + runs-on: windows + steps: + - name: Checkout repository + uses: actions/checkout@v3 + with: + lfs: true + fetch-depth: 0 + + - name: Setup environment + run: | + # Set environment variables for Unreal Engine + echo "UE_ROOT=E:/Games/UE_5.5" >> $GITHUB_ENV + + # Set environment variables for Linux toolchain (needed for cross-compilation) + $env:LINUX_MULTIARCH_ROOT="C:/UnrealToolchains/v23_clang-18.1.0-rockylinux8" + echo "LINUX_MULTIARCH_ROOT=${LINUX_MULTIARCH_ROOT}" >> $GITHUB_ENV + + # Create directories for builds + if (!(Test-Path "Builds/Linux")) { New-Item -ItemType Directory -Path "Builds/Linux" -Force } + if (!(Test-Path "PackagedReleases")) { New-Item -ItemType Directory -Path "PackagedReleases" -Force } + + - name: Build for Linux + run: | + # Chmod command doesn't exist in Windows, use PowerShell to run the bash script + & 'C:\Program Files\Git\bin\bash.exe' -c "./scripts/linux_build.sh" + + - name: Package Linux build + run: | + echo "Packaging Linux build..." + if [ -d "Builds/Linux" ]; then + cd Builds/Linux + zip -r ../../PackagedReleases/LuckyRobots-Linux.zip . + cd ../.. + fi + + echo "=== Packaged Linux release ===" + ls -la PackagedReleases/ + + - name: Upload Linux Build Artifact + uses: actions/upload-artifact@v3 + if: success() && hashFiles('PackagedReleases/LuckyRobots-Linux.zip') != '' + with: + name: LuckyRobots-Linux + path: PackagedReleases/LuckyRobots-Linux.zip + retention-days: 365 \ No newline at end of file diff --git a/.gitea/workflows/macos-build.yml b/.gitea/workflows/macos-build.yml new file mode 100644 index 00000000..babcda4b --- /dev/null +++ b/.gitea/workflows/macos-build.yml @@ -0,0 +1,81 @@ +name: macOS Build + +on: + workflow_dispatch: + workflow_call: + +jobs: + macos-build: + runs-on: macos + steps: + - name: Checkout repository + uses: actions/checkout@v3 + with: + lfs: true + fetch-depth: 0 + + - name: Setup environment + run: | + # Use the correct path where Unreal Engine is installed + UE_PATH="/Users/Shared/Epic Games/UE_5.5" + + if [ ! -d "$UE_PATH" ]; then + echo "Error: Unreal Engine is not installed in the expected location" + echo "Please ensure Unreal Engine is installed at $UE_PATH" + exit 1 + fi + + # Create directories for builds + mkdir -p Builds/Mac + mkdir -p PackagedReleases + + echo "Using Unreal Engine 5.5" + + - name: Build for macOS + run: | + chmod +x ./scripts/mac_build.sh + ./scripts/mac_build.sh + + - name: Package macOS build + run: | + echo "Preparing packaged files for release..." + + # Find the app bundle in the Builds directory + APP_PATH=$(find Builds -type d -name "*.app" | head -1) + + if [ -n "$APP_PATH" ]; then + echo "Found app bundle: $APP_PATH" + # Get the app name + APP_NAME=$(basename "$APP_PATH") + # Create zip file of the app bundle + (cd $(dirname "$APP_PATH") && zip -r "../../PackagedReleases/LuckyRobots-macOS.zip" "$APP_NAME") + echo "Created packaged release: PackagedReleases/LuckyRobots-macOS.zip" + else + echo "No .app bundle found in Builds directory" + + # Look for a directory that might be a bundle but not named .app + MAIN_BUILD_DIR=$(find Builds -mindepth 1 -maxdepth 1 -type d | head -1) + if [ -n "$MAIN_BUILD_DIR" ]; then + echo "Found main build directory: $MAIN_BUILD_DIR" + DIR_NAME=$(basename "$MAIN_BUILD_DIR") + # Package this directory as if it were the app + (cd $(dirname "$MAIN_BUILD_DIR") && zip -r "../../PackagedReleases/LuckyRobots-macOS.zip" "$DIR_NAME") + echo "Created packaged release from main directory: PackagedReleases/LuckyRobots-macOS.zip" + else + # Package the entire Builds directory as a fallback + echo "No main directory found, packaging everything" + zip -r "PackagedReleases/LuckyRobots-macOS.zip" Builds + echo "Created fallback package: PackagedReleases/LuckyRobots-macOS.zip" + fi + fi + + echo "Packaged releases:" + ls -la PackagedReleases/ + + - name: Upload macOS Build Artifact + uses: actions/upload-artifact@v3 + if: success() + with: + name: LuckyRobots-macOS + path: PackagedReleases/LuckyRobots-macOS.zip + retention-days: 365 \ No newline at end of file diff --git a/.gitea/workflows/release.yml b/.gitea/workflows/release.yml new file mode 100644 index 00000000..76e687ff --- /dev/null +++ b/.gitea/workflows/release.yml @@ -0,0 +1,163 @@ +name: Create Release + +on: + workflow_dispatch: + workflow_call: + +jobs: + create-release: + runs-on: ubuntu-latest + if: github.ref == 'refs/heads/main' || github.ref == 'refs/heads/develop' + steps: + - name: Checkout repository + uses: actions/checkout@v3 + with: + fetch-depth: 0 + + - name: Create Tag + run: | + # Fetch all tags + git fetch --tags + + # Get the latest version tag, if any + LATEST_TAG=$(git tag -l "v[0-9]*.[0-9]*.[0-9]*" | sort -V | tail -n1) + + if [ -z "$LATEST_TAG" ]; then + # No previous version tag, start with 1.0.0 + NEW_VERSION="1.0.0" + echo "No previous version tags found, starting with 1.0.0" + else + # Strip 'v' prefix if it exists + VERSION=${LATEST_TAG#v} + + # Split version into parts + MAJOR=$(echo $VERSION | cut -d. -f1) + MINOR=$(echo $VERSION | cut -d. -f2) + PATCH=$(echo $VERSION | cut -d. -f3) + + # Auto-increment patch version + PATCH=$((PATCH + 1)) + NEW_VERSION="${MAJOR}.${MINOR}.${PATCH}" + echo "Auto-incremented patch version from ${VERSION} to ${NEW_VERSION}" + fi + + # Final tag with v prefix + TAG="v${NEW_VERSION}" + echo "Creating git tag: $TAG" + + # Configure git with token authentication + git config --global user.email "actions@gitea.com" + git config --global user.name "Gitea Actions" + + # Direct token approach + git remote set-url origin "https://runner:${{ secrets.GITEATOKEN }}@luckyrobots.com/luckyrobots/luckyworld.git" + + # Check if tag exists + if ! git rev-parse "$TAG" >/dev/null 2>&1; then + # Create tag + git tag -a "$TAG" -m "Release $TAG" + + # Push tag + git push origin "$TAG" + echo "Successfully created and pushed tag: $TAG" + else + echo "Tag $TAG already exists, skipping tag creation" + fi + echo "RELEASE_TAG=$TAG" >> $GITHUB_ENV + + - name: Download all artifacts + uses: actions/download-artifact@v3 + with: + path: releases + + - name: Create Build Info + run: | + # Create a build info JSON file + echo '{ + "version": "${{ env.RELEASE_TAG }}", + "buildNumber": "${{ github.run_number }}", + "commit": "${{ github.sha }}", + "branch": "${{ github.ref_name }}", + "buildDate": "'$(date -u +"%Y-%m-%dT%H:%M:%SZ")'", + "artifacts": { + "windows": "https://luckyrobots.com/luckyrobots/luckyworld/actions/runs/${{ github.run_id }}/artifacts/LuckyRobots-Windows", + "linux": "https://luckyrobots.com/luckyrobots/luckyworld/actions/runs/${{ github.run_id }}/artifacts/LuckyRobots-Linux", + "macos": "https://luckyrobots.com/luckyrobots/luckyworld/actions/runs/${{ github.run_id }}/artifacts/LuckyRobots-macOS" + } + }' > build-info.json + + # Create a simple HTML download page + echo ' + + + + + LuckyRobots ${{ env.RELEASE_TAG }} Downloads + + + +

LuckyRobots Game - ${{ env.RELEASE_TAG }}

+

Build #${{ github.run_number }} - Built from commit: ${{ github.sha }}

+ +
+

Windows

+

Download Windows Build

+
+ +
+

Linux

+

Download Linux Build

+
+ +
+

macOS

+

Download macOS Build

+
+ +
+

Generated on '$(date -u +"%Y-%m-%d %H:%M:%S UTC")'

+
+ + ' > downloads.html + + - name: Create Release + uses: https://gitea.com/actions/gitea-release-action@main + with: + files: |- + build-info.json + downloads.html + token: '${{ secrets.GITEATOKEN }}' + title: 'Release ${{ env.RELEASE_TAG }}' + body: | + ## LuckyRobots Game Release ${{ env.RELEASE_TAG }} + + ### Download Links + + Download builds from our CI artifacts: + + - [Windows Build](https://luckyrobots.com/luckyrobots/luckyworld/actions/runs/${{ github.run_id }}/artifacts/LuckyRobots-Windows) + - [Linux Build](https://luckyrobots.com/luckyrobots/luckyworld/actions/runs/${{ github.run_id }}/artifacts/LuckyRobots-Linux) + - [macOS Build](https://luckyrobots.com/luckyrobots/luckyworld/actions/runs/${{ github.run_id }}/artifacts/LuckyRobots-macOS) + + ### Build Information + + - Build Number: #${{ github.run_number }} + - Commit: ${{ github.sha }} + - Branch: ${{ github.ref_name }} + - Build Date: $(date -u +"%Y-%m-%d %H:%M:%S UTC") + prerelease: ${{ github.ref != 'refs/heads/main' }} + tag_name: '${{ env.RELEASE_TAG }}' \ No newline at end of file diff --git a/.gitea/workflows/unreal-build.yml b/.gitea/workflows/unreal-build.yml deleted file mode 100644 index b106bcdd..00000000 --- a/.gitea/workflows/unreal-build.yml +++ /dev/null @@ -1,347 +0,0 @@ -name: Unreal Engine Build - -on: - workflow_dispatch: - -jobs: - build-and-release: - runs-on: windows - if: github.ref == 'refs/heads/main' || github.ref == 'refs/heads/develop' - steps: - - name: Checkout repository - uses: actions/checkout@v3 - with: - lfs: true - fetch-depth: 0 - - - name: Setup environment - run: | - # Set environment variables for Unreal Engine - echo "UE_ROOT=E:/Games/UE_5.5" >> $GITHUB_ENV - # Set environment variables for Linux toolchain - $env:LINUX_MULTIARCH_ROOT="C:/UnrealToolchains/v23_clang-18.1.0-rockylinux8" - echo "LINUX_MULTIARCH_ROOT=${LINUX_MULTIARCH_ROOT}" >> $GITHUB_ENV - - # Create directories for builds (with error handling) - if (!(Test-Path "Builds/Windows")) { New-Item -ItemType Directory -Path "Builds/Windows" -Force } - if (!(Test-Path "Builds/Linux")) { New-Item -ItemType Directory -Path "Builds/Linux" -Force } - if (!(Test-Path "PackagedReleases")) { New-Item -ItemType Directory -Path "PackagedReleases" -Force } - - - name: Build for Windows - run: | - # Chmod command doesn't exist in Windows, use PowerShell to run the bash script - & 'C:\Program Files\Git\bin\bash.exe' -c "./win_build.sh" - - - name: Build for Linux - run: | - # Chmod command doesn't exist in Windows, use PowerShell to run the bash script - & 'C:\Program Files\Git\bin\bash.exe' -c "./linux_build.sh" - - - name: Package builds - run: | - echo "Packaging Windows build..." - if [ -d "Builds/Windows" ]; then - cd Builds/Windows - zip -r ../../PackagedReleases/LuckyRobots-Windows.zip . - cd ../.. - fi - - echo "Packaging Linux build..." - if [ -d "Builds/Linux" ]; then - cd Builds/Linux - zip -r ../../PackagedReleases/LuckyRobots-Linux.zip . - cd ../.. - fi - - echo "=== Packaged releases ===" - ls -la PackagedReleases/ - - - name: Upload Windows Build Artifact - uses: actions/upload-artifact@v3 - if: success() && hashFiles('PackagedReleases/LuckyRobots-Windows.zip') != '' - with: - name: LuckyRobots-Windows - path: PackagedReleases/LuckyRobots-Windows.zip - retention-days: 365 - - - name: Upload Linux Build Artifact - uses: actions/upload-artifact@v3 - if: success() && hashFiles('PackagedReleases/LuckyRobots-Linux.zip') != '' - with: - name: LuckyRobots-Linux - path: PackagedReleases/LuckyRobots-Linux.zip - retention-days: 365 - - - name: Create Tag - if: github.ref == 'refs/heads/main' || github.ref == 'refs/heads/develop' - run: | - # Fetch all tags - git fetch --tags - - # Get the latest version tag, if any - LATEST_TAG=$(git tag -l "v[0-9]*.[0-9]*.[0-9]*" | sort -V | tail -n1) - - if [ -z "$LATEST_TAG" ]; then - # No previous version tag, start with 1.0.0 - NEW_VERSION="1.0.0" - echo "No previous version tags found, starting with 1.0.0" - else - # Strip 'v' prefix if it exists - VERSION=${LATEST_TAG#v} - - # Split version into parts - MAJOR=$(echo $VERSION | cut -d. -f1) - MINOR=$(echo $VERSION | cut -d. -f2) - PATCH=$(echo $VERSION | cut -d. -f3) - - # Auto-increment patch version - PATCH=$((PATCH + 1)) - NEW_VERSION="${MAJOR}.${MINOR}.${PATCH}" - echo "Auto-incremented patch version from ${VERSION} to ${NEW_VERSION}" - fi - - # Final tag with v prefix - TAG="v${NEW_VERSION}" - echo "Creating git tag: $TAG" - - # Configure git with token authentication - git config --global user.email "actions@gitea.com" - git config --global user.name "Gitea Actions" - - # Direct token approach - simplest method - git remote set-url origin "https://goran:${{ secrets.GITEATOKEN }}@luckyrobots.com/luckyrobots/luckyworld.git" - - # Set git to not prompt for input - $env:GIT_TERMINAL_PROMPT=0 - - # Check if tag exists - if ! git rev-parse "$TAG" >/dev/null 2>&1; then - # Create tag without opening editor (-m flag) - git tag -a "$TAG" -m "Release $TAG" - - # Push with timeout and debug - echo "Pushing tag $TAG to origin..." - git push --verbose origin "$TAG" || { - echo "Error: Failed to push tag. Check your token permissions." - exit 1 - } - echo "Successfully created and pushed tag: $TAG" - else - echo "Tag $TAG already exists, skipping tag creation" - fi - echo "RELEASE_TAG=$TAG" >> $GITHUB_ENV - - - name: Create Build Info - run: | - # Create a build info JSON file - echo '{ - "version": "${{ env.RELEASE_TAG }}", - "buildNumber": "${{ github.run_number }}", - "commit": "${{ github.sha }}", - "branch": "${{ github.ref_name }}", - "buildDate": "'$(date -u +"%Y-%m-%dT%H:%M:%SZ")'", - "artifacts": { - "windows": "https://luckyrobots.com/luckyrobots/luckyworld/actions/runs/${{ github.run_id }}/artifacts/LuckyRobots-Windows", - "linux": "https://luckyrobots.com/luckyrobots/luckyworld/actions/runs/${{ github.run_id }}/artifacts/LuckyRobots-Linux" - } - }' > PackagedReleases/build-info.json - - # Create a simple HTML download page - echo ' - - - - - LuckyRobots ${{ env.RELEASE_TAG }} Downloads - - - -

LuckyRobots Game - ${{ env.RELEASE_TAG }}

-

Build #${{ github.run_number }} - Built from commit: ${{ github.sha }}

- -
-

Windows

-

Download Windows Build

-
- -
-

Linux

-

Download Linux Build

-
- -
-

Generated on '$(date -u +"%Y-%m-%d %H:%M:%S UTC")'

-
- - ' > PackagedReleases/downloads.html - - - name: Create Release - uses: https://gitea.com/actions/gitea-release-action@main - with: - files: |- - PackagedReleases/build-info.json - PackagedReleases/downloads.html - token: '${{ secrets.GITEA_TOKEN }}' - title: 'Release ${{ env.RELEASE_TAG }}' - body: | - ## LuckyRobots Game Release ${{ env.RELEASE_TAG }} - - ### Download Links - - Download builds from our CI artifacts: - - - [Windows Build](https://luckyrobots.com/luckyrobots/luckyworld/actions/runs/${{ github.run_id }}/artifacts/LuckyRobots-Windows) - - [Linux Build](https://luckyrobots.com/luckyrobots/luckyworld/actions/runs/${{ github.run_id }}/artifacts/LuckyRobots-Linux) - - ### Build Information - - - Build Number: #${{ github.run_number }} - - Commit: ${{ github.sha }} - - Branch: ${{ github.ref_name }} - - Build Date: $(date -u +"%Y-%m-%d %H:%M:%S UTC") - prerelease: ${{ github.ref != 'refs/heads/main' }} - tag_name: '${{ env.RELEASE_TAG }}' - - macos-build: - runs-on: macos - if: github.ref == 'refs/heads/main' || github.ref == 'refs/heads/develop' - steps: - - name: Checkout repository - uses: actions/checkout@v3 - with: - lfs: true - fetch-depth: 0 - - - name: Get Release Tag - run: | - # Fetch all tags - git fetch --tags - - # Get the latest version tag - LATEST_TAG=$(git tag -l "v[0-9]*.[0-9]*.[0-9]*" | sort -V | tail -n1) - - if [ -z "$LATEST_TAG" ]; then - NEW_VERSION="1.0.0" - else - VERSION=${LATEST_TAG#v} - MAJOR=$(echo $VERSION | cut -d. -f1) - MINOR=$(echo $VERSION | cut -d. -f2) - PATCH=$(echo $VERSION | cut -d. -f3) - PATCH=$((PATCH + 1)) - NEW_VERSION="${MAJOR}.${MINOR}.${PATCH}" - fi - - TAG="v${NEW_VERSION}" - echo "RELEASE_TAG=$TAG" >> $GITHUB_ENV - echo "Using release tag: $TAG" - - - name: Setup Unreal Engine - run: | - # Use the correct path where Unreal Engine is installed - UE_PATH="/Users/Shared/Epic Games/UE_5.5" - - if [ ! -d "$UE_PATH" ]; then - echo "Error: Unreal Engine is not installed in the expected location" - echo "Please ensure Unreal Engine is installed at $UE_PATH" - exit 1 - fi - - # Set environment variable with the correct Engine path - echo "UE_ROOT=$UE_PATH/Engine" >> $GITHUB_ENV - echo "Using Unreal Engine 5.5" - - - name: Build Unreal Project - run: | - chmod +x ./mac_build.sh - ./mac_build.sh - - - name: Prepare Mac release - run: | - echo "Preparing packaged files for release..." - - # Create a directory for release files - mkdir -p PackagedReleases - - # Debug: Show what we're packaging - echo "=== Packaging for Release ===" - echo "Build directory contents:" - ls -la Builds/ - - # Find the app bundle in the Builds directory - APP_PATH=$(find Builds -type d -name "*.app" | head -1) - - if [ -n "$APP_PATH" ]; then - echo "Found app bundle: $APP_PATH" - # Get the app name - APP_NAME=$(basename "$APP_PATH") - # Create zip file of the app bundle - (cd $(dirname "$APP_PATH") && zip -r "../../PackagedReleases/${APP_NAME%.app}-macOS.zip" "$APP_NAME") - echo "Created packaged release: PackagedReleases/${APP_NAME%.app}-macOS.zip" - else - echo "No .app bundle found in Builds directory" - - # Look for a directory that might be a bundle but not named .app - MAIN_BUILD_DIR=$(find Builds -mindepth 1 -maxdepth 1 -type d | head -1) - if [ -n "$MAIN_BUILD_DIR" ]; then - echo "Found main build directory: $MAIN_BUILD_DIR" - DIR_NAME=$(basename "$MAIN_BUILD_DIR") - # Package this directory as if it were the app - (cd $(dirname "$MAIN_BUILD_DIR") && zip -r "../../PackagedReleases/${DIR_NAME}-macOS.zip" "$DIR_NAME") - echo "Created packaged release from main directory: PackagedReleases/${DIR_NAME}-macOS.zip" - else - # Package the entire Builds directory as a fallback - echo "No main directory found, packaging everything" - zip -r "PackagedReleases/LuckyRobots-macOS.zip" Builds - echo "Created fallback package: PackagedReleases/LuckyRobots-macOS.zip" - fi - fi - - echo "Packaged releases:" - ls -la PackagedReleases/ - - - name: Upload macOS Build Artifact - uses: actions/upload-artifact@v3 - if: success() - with: - name: LuckyRobots-macOS - path: PackagedReleases/*-macOS.zip - retention-days: 365 - - - name: Create Release Note - run: | - echo "## macOS Build Completed" > release-note.md - echo "" >> release-note.md - echo "macOS build is available as an artifact." >> release-note.md - echo "" >> release-note.md - echo "Download from: [macOS Build](https://luckyrobots.com/luckyrobots/luckyworld/actions/runs/${{ github.run_id }}/artifacts/LuckyRobots-macOS)" >> release-note.md - - - name: Create Gitea Release - if: github.ref == 'refs/heads/main' || github.ref == 'refs/heads/develop' - uses: https://gitea.com/actions/gitea-release-action@main - with: - token: ${{ secrets.GITEATOKEN }} - tag_name: ${{ env.RELEASE_TAG }} - title: "Release ${{ env.RELEASE_TAG }} - macOS" - body: | - ## macOS Build Available as Artifact - - The macOS build is available as an artifact due to its large file size. - - [Download macOS Build](https://luckyrobots.com/luckyrobots/luckyworld/actions/runs/${{ github.run_id }}/artifacts/LuckyRobots-macOS) - - Built from commit: ${{ github.sha }} - files: release-note.md \ No newline at end of file diff --git a/.gitea/workflows/windows-build.yml b/.gitea/workflows/windows-build.yml new file mode 100644 index 00000000..220e6d3d --- /dev/null +++ b/.gitea/workflows/windows-build.yml @@ -0,0 +1,49 @@ +name: Windows Build + +on: + workflow_dispatch: + workflow_call: + +jobs: + windows-build: + runs-on: windows + steps: + - name: Checkout repository + uses: actions/checkout@v3 + with: + lfs: true + fetch-depth: 0 + + - name: Setup environment + run: | + # Set environment variables for Unreal Engine + echo "UE_ROOT=E:/Games/UE_5.5" >> $GITHUB_ENV + + # Create directories for builds + if (!(Test-Path "Builds/Windows")) { New-Item -ItemType Directory -Path "Builds/Windows" -Force } + if (!(Test-Path "PackagedReleases")) { New-Item -ItemType Directory -Path "PackagedReleases" -Force } + + - name: Build for Windows + run: | + # Chmod command doesn't exist in Windows, use PowerShell to run the bash script + & 'C:\Program Files\Git\bin\bash.exe' -c "./scripts/win_build.sh" + + - name: Package Windows build + run: | + echo "Packaging Windows build..." + if [ -d "Builds/Windows" ]; then + cd Builds/Windows + zip -r ../../PackagedReleases/LuckyRobots-Windows.zip . + cd ../.. + fi + + echo "=== Packaged Windows release ===" + ls -la PackagedReleases/ + + - name: Upload Windows Build Artifact + uses: actions/upload-artifact@v3 + if: success() && hashFiles('PackagedReleases/LuckyRobots-Windows.zip') != '' + with: + name: LuckyRobots-Windows + path: PackagedReleases/LuckyRobots-Windows.zip + retention-days: 365 \ No newline at end of file -- 2.47.2 From 59ddbee2a367adc1573e451723d48112e512be01 Mon Sep 17 00:00:00 2001 From: Ozgur Ersoy Date: Sat, 12 Apr 2025 23:35:16 +0200 Subject: [PATCH 003/109] feat(workflows): enhance build workflows for Windows, Linux, and macOS with packaging and release creation steps --- .gitea/workflows/build.yml | 341 ++++++++++++++++++++++++++++++++++--- 1 file changed, 313 insertions(+), 28 deletions(-) diff --git a/.gitea/workflows/build.yml b/.gitea/workflows/build.yml index 52b2714a..3998ea59 100644 --- a/.gitea/workflows/build.yml +++ b/.gitea/workflows/build.yml @@ -6,40 +6,325 @@ on: branches: [ozgur/build] jobs: - trigger-builds: + windows-build: + runs-on: windows + steps: + - name: Checkout repository + uses: actions/checkout@v3 + with: + lfs: true + fetch-depth: 0 + + - name: Setup environment + run: | + # Set environment variables for Unreal Engine + echo "UE_ROOT=E:/Games/UE_5.5" >> $GITHUB_ENV + + # Create directories for builds + if (!(Test-Path "Builds/Windows")) { New-Item -ItemType Directory -Path "Builds/Windows" -Force } + if (!(Test-Path "PackagedReleases")) { New-Item -ItemType Directory -Path "PackagedReleases" -Force } + + - name: Build for Windows + run: | + # Chmod command doesn't exist in Windows, use PowerShell to run the bash script + & 'C:\Program Files\Git\bin\bash.exe' -c "./scripts/win_build.sh" + + - name: Package Windows build + run: | + echo "Packaging Windows build..." + if [ -d "Builds/Windows" ]; then + cd Builds/Windows + zip -r ../../PackagedReleases/LuckyRobots-Windows.zip . + cd ../.. + fi + + echo "=== Packaged Windows release ===" + ls -la PackagedReleases/ + + - name: Upload Windows Build Artifact + uses: actions/upload-artifact@v3 + if: success() && hashFiles('PackagedReleases/LuckyRobots-Windows.zip') != '' + with: + name: LuckyRobots-Windows + path: PackagedReleases/LuckyRobots-Windows.zip + retention-days: 365 + + linux-build: + runs-on: windows + steps: + - name: Checkout repository + uses: actions/checkout@v3 + with: + lfs: true + fetch-depth: 0 + + - name: Setup environment + run: | + # Set environment variables for Unreal Engine + echo "UE_ROOT=E:/Games/UE_5.5" >> $GITHUB_ENV + + # Set environment variables for Linux toolchain (needed for cross-compilation) + $env:LINUX_MULTIARCH_ROOT="C:/UnrealToolchains/v23_clang-18.1.0-rockylinux8" + echo "LINUX_MULTIARCH_ROOT=${LINUX_MULTIARCH_ROOT}" >> $GITHUB_ENV + + # Create directories for builds + if (!(Test-Path "Builds/Linux")) { New-Item -ItemType Directory -Path "Builds/Linux" -Force } + if (!(Test-Path "PackagedReleases")) { New-Item -ItemType Directory -Path "PackagedReleases" -Force } + + - name: Build for Linux + run: | + # Chmod command doesn't exist in Windows, use PowerShell to run the bash script + & 'C:\Program Files\Git\bin\bash.exe' -c "./scripts/linux_build.sh" + + - name: Package Linux build + run: | + echo "Packaging Linux build..." + if [ -d "Builds/Linux" ]; then + cd Builds/Linux + zip -r ../../PackagedReleases/LuckyRobots-Linux.zip . + cd ../.. + fi + + echo "=== Packaged Linux release ===" + ls -la PackagedReleases/ + + - name: Upload Linux Build Artifact + uses: actions/upload-artifact@v3 + if: success() && hashFiles('PackagedReleases/LuckyRobots-Linux.zip') != '' + with: + name: LuckyRobots-Linux + path: PackagedReleases/LuckyRobots-Linux.zip + retention-days: 365 + + macos-build: + runs-on: macos + steps: + - name: Checkout repository + uses: actions/checkout@v3 + with: + lfs: true + fetch-depth: 0 + + - name: Setup environment + run: | + # Use the correct path where Unreal Engine is installed + UE_PATH="/Users/Shared/Epic Games/UE_5.5" + + if [ ! -d "$UE_PATH" ]; then + echo "Error: Unreal Engine is not installed in the expected location" + echo "Please ensure Unreal Engine is installed at $UE_PATH" + exit 1 + fi + + # Create directories for builds + mkdir -p Builds/Mac + mkdir -p PackagedReleases + + echo "Using Unreal Engine 5.5" + + - name: Build for macOS + run: | + chmod +x ./scripts/mac_build.sh + ./scripts/mac_build.sh + + - name: Package macOS build + run: | + echo "Preparing packaged files for release..." + + # Find the app bundle in the Builds directory + APP_PATH=$(find Builds -type d -name "*.app" | head -1) + + if [ -n "$APP_PATH" ]; then + echo "Found app bundle: $APP_PATH" + # Get the app name + APP_NAME=$(basename "$APP_PATH") + # Create zip file of the app bundle + (cd $(dirname "$APP_PATH") && zip -r "../../PackagedReleases/LuckyRobots-macOS.zip" "$APP_NAME") + echo "Created packaged release: PackagedReleases/LuckyRobots-macOS.zip" + else + echo "No .app bundle found in Builds directory" + + # Look for a directory that might be a bundle but not named .app + MAIN_BUILD_DIR=$(find Builds -mindepth 1 -maxdepth 1 -type d | head -1) + if [ -n "$MAIN_BUILD_DIR" ]; then + echo "Found main build directory: $MAIN_BUILD_DIR" + DIR_NAME=$(basename "$MAIN_BUILD_DIR") + # Package this directory as if it were the app + (cd $(dirname "$MAIN_BUILD_DIR") && zip -r "../../PackagedReleases/LuckyRobots-macOS.zip" "$DIR_NAME") + echo "Created packaged release from main directory: PackagedReleases/LuckyRobots-macOS.zip" + else + # Package the entire Builds directory as a fallback + echo "No main directory found, packaging everything" + zip -r "PackagedReleases/LuckyRobots-macOS.zip" Builds + echo "Created fallback package: PackagedReleases/LuckyRobots-macOS.zip" + fi + fi + + echo "Packaged releases:" + ls -la PackagedReleases/ + + - name: Upload macOS Build Artifact + uses: actions/upload-artifact@v3 + if: success() + with: + name: LuckyRobots-macOS + path: PackagedReleases/LuckyRobots-macOS.zip + retention-days: 365 + + create-release: + needs: [windows-build, linux-build, macos-build] runs-on: ubuntu-latest + if: github.ref == 'refs/heads/main' || github.ref == 'refs/heads/develop' steps: - name: Checkout repository uses: actions/checkout@v3 with: fetch-depth: 0 - - - name: Trigger Windows Build - uses: https://gitea.com/actions/gitea-actions-dispatcher@v0.1.0 - with: - workflow: windows-build.yml - token: ${{ secrets.GITEATOKEN }} - - - name: Trigger Linux Build - uses: https://gitea.com/actions/gitea-actions-dispatcher@v0.1.0 - with: - workflow: linux-build.yml - token: ${{ secrets.GITEATOKEN }} - - - name: Trigger macOS Build - uses: https://gitea.com/actions/gitea-actions-dispatcher@v0.1.0 - with: - workflow: macos-build.yml - token: ${{ secrets.GITEATOKEN }} - - - name: Wait for builds to complete + + - name: Create Tag run: | - echo "Waiting for platform builds to complete..." - sleep 60 # Adding a delay to ensure builds have time to start + # Fetch all tags + git fetch --tags + + # Get the latest version tag, if any + LATEST_TAG=$(git tag -l "v[0-9]*.[0-9]*.[0-9]*" | sort -V | tail -n1) + + if [ -z "$LATEST_TAG" ]; then + # No previous version tag, start with 1.0.0 + NEW_VERSION="1.0.0" + echo "No previous version tags found, starting with 1.0.0" + else + # Strip 'v' prefix if it exists + VERSION=${LATEST_TAG#v} + + # Split version into parts + MAJOR=$(echo $VERSION | cut -d. -f1) + MINOR=$(echo $VERSION | cut -d. -f2) + PATCH=$(echo $VERSION | cut -d. -f3) + + # Auto-increment patch version + PATCH=$((PATCH + 1)) + NEW_VERSION="${MAJOR}.${MINOR}.${PATCH}" + echo "Auto-incremented patch version from ${VERSION} to ${NEW_VERSION}" + fi + + # Final tag with v prefix + TAG="v${NEW_VERSION}" + echo "Creating git tag: $TAG" + + # Configure git with token authentication + git config --global user.email "actions@gitea.com" + git config --global user.name "Gitea Actions" + + # Direct token approach + git remote set-url origin "https://runner:${{ secrets.GITEATOKEN }}@luckyrobots.com/luckyrobots/luckyworld.git" + + # Check if tag exists + if ! git rev-parse "$TAG" >/dev/null 2>&1; then + # Create tag + git tag -a "$TAG" -m "Release $TAG" + + # Push tag + git push origin "$TAG" + echo "Successfully created and pushed tag: $TAG" + else + echo "Tag $TAG already exists, skipping tag creation" + fi + echo "RELEASE_TAG=$TAG" >> $GITHUB_ENV - - name: Trigger Release Creation - if: github.ref == 'refs/heads/main' || github.ref == 'refs/heads/develop' - uses: https://gitea.com/actions/gitea-actions-dispatcher@v0.1.0 + - name: Download all artifacts + uses: actions/download-artifact@v3 with: - workflow: release.yml - token: ${{ secrets.GITEATOKEN }} \ No newline at end of file + path: releases + + - name: Create Build Info + run: | + # Create a build info JSON file + echo '{ + "version": "${{ env.RELEASE_TAG }}", + "buildNumber": "${{ github.run_number }}", + "commit": "${{ github.sha }}", + "branch": "${{ github.ref_name }}", + "buildDate": "'$(date -u +"%Y-%m-%dT%H:%M:%SZ")'", + "artifacts": { + "windows": "https://luckyrobots.com/luckyrobots/luckyworld/actions/runs/${{ github.run_id }}/artifacts/LuckyRobots-Windows", + "linux": "https://luckyrobots.com/luckyrobots/luckyworld/actions/runs/${{ github.run_id }}/artifacts/LuckyRobots-Linux", + "macos": "https://luckyrobots.com/luckyrobots/luckyworld/actions/runs/${{ github.run_id }}/artifacts/LuckyRobots-macOS" + } + }' > build-info.json + + # Create a simple HTML download page + echo ' + + + + + LuckyRobots ${{ env.RELEASE_TAG }} Downloads + + + +

LuckyRobots Game - ${{ env.RELEASE_TAG }}

+

Build #${{ github.run_number }} - Built from commit: ${{ github.sha }}

+ +
+

Windows

+

Download Windows Build

+
+ +
+

Linux

+

Download Linux Build

+
+ +
+

macOS

+

Download macOS Build

+
+ +
+

Generated on '$(date -u +"%Y-%m-%d %H:%M:%S UTC")'

+
+ + ' > downloads.html + + - name: Create Release + uses: https://gitea.com/actions/gitea-release-action@main + with: + files: |- + build-info.json + downloads.html + token: '${{ secrets.GITEATOKEN }}' + title: 'Release ${{ env.RELEASE_TAG }}' + body: | + ## LuckyRobots Game Release ${{ env.RELEASE_TAG }} + + ### Download Links + + Download builds from our CI artifacts: + + - [Windows Build](https://luckyrobots.com/luckyrobots/luckyworld/actions/runs/${{ github.run_id }}/artifacts/LuckyRobots-Windows) + - [Linux Build](https://luckyrobots.com/luckyrobots/luckyworld/actions/runs/${{ github.run_id }}/artifacts/LuckyRobots-Linux) + - [macOS Build](https://luckyrobots.com/luckyrobots/luckyworld/actions/runs/${{ github.run_id }}/artifacts/LuckyRobots-macOS) + + ### Build Information + + - Build Number: #${{ github.run_number }} + - Commit: ${{ github.sha }} + - Branch: ${{ github.ref_name }} + - Build Date: $(date -u +"%Y-%m-%d %H:%M:%S UTC") + prerelease: ${{ github.ref != 'refs/heads/main' }} + tag_name: '${{ env.RELEASE_TAG }}' \ No newline at end of file -- 2.47.2 From d5b6c2507695de1ba3309c2e5fb46bbb8593711c Mon Sep 17 00:00:00 2001 From: Ozgur Ersoy Date: Sun, 13 Apr 2025 00:42:10 +0200 Subject: [PATCH 004/109] feat(workflows): add macOS app signing and notarization steps to build workflow --- .gitea/workflows/macos-build.yml | 73 ++++++++++++++++++++++++++++++++ LuckyRobots.entitlements | 18 ++++++++ 2 files changed, 91 insertions(+) create mode 100644 LuckyRobots.entitlements diff --git a/.gitea/workflows/macos-build.yml b/.gitea/workflows/macos-build.yml index babcda4b..e9b29696 100644 --- a/.gitea/workflows/macos-build.yml +++ b/.gitea/workflows/macos-build.yml @@ -72,6 +72,79 @@ jobs: echo "Packaged releases:" ls -la PackagedReleases/ + - name: Sign and Notarize macOS App + env: + APPLE_TEAM_ID: ${{ secrets.APPLE_TEAM_ID }} + CERTIFICATE_BASE64: ${{ secrets.MACOS_CERTIFICATE }} + CERTIFICATE_PASSWORD: ${{ secrets.MACOS_CERTIFICATE_PWD }} + API_KEY_PATH: ${{ secrets.NOTARY_API_KEY_PATH }} + API_KEY_ID: ${{ secrets.NOTARY_API_KEY_ID }} + API_KEY_ISSUER_ID: ${{ secrets.NOTARY_API_KEY_ISSUER_ID }} + run: | + # Decode the base64 certificate + echo "Setting up certificate..." + echo $CERTIFICATE_BASE64 | base64 --decode > certificate.p12 + + # Create keychain and import certificate + KEYCHAIN_PATH=$RUNNER_TEMP/app-signing.keychain-db + KEYCHAIN_PASSWORD=temporary + + security create-keychain -p "$KEYCHAIN_PASSWORD" "$KEYCHAIN_PATH" + security set-keychain-settings -lut 21600 "$KEYCHAIN_PATH" + security unlock-keychain -p "$KEYCHAIN_PASSWORD" "$KEYCHAIN_PATH" + security import certificate.p12 -P "$CERTIFICATE_PASSWORD" -A -t cert -f pkcs12 -k "$KEYCHAIN_PATH" + security list-keychain -d user -s "$KEYCHAIN_PATH" + + # Find app bundle + APP_PATH=$(find Builds -type d -name "*.app" | head -1) + + if [ -n "$APP_PATH" ]; then + echo "Signing app bundle: $APP_PATH" + + # Sign the application + /usr/bin/codesign --force --options runtime --sign "Developer ID Application: $APPLE_TEAM_ID" --deep --entitlements "./LuckyRobots.entitlements" "$APP_PATH" + + # Create a temporary file for notarization + NOTARIZE_APP_PATH="./LuckyRobots-notarize.zip" + ditto -c -k --keepParent "$APP_PATH" "$NOTARIZE_APP_PATH" + + # Decode the API key from Base64 secret + echo "$API_KEY_PATH" | base64 --decode > api_key.p8 + API_KEY_FILE="api_key.p8" + + # Submit for notarization using API key + echo "Submitting for notarization with API key..." + xcrun notarytool submit "$NOTARIZE_APP_PATH" --key "$API_KEY_FILE" --key-id "$API_KEY_ID" --issuer "$API_KEY_ISSUER_ID" --wait + + # Check notarization result + NOTARIZATION_INFO=$(xcrun notarytool history --key "$API_KEY_FILE" --key-id "$API_KEY_ID" --issuer "$API_KEY_ISSUER_ID" | grep -E '(success|invalid)' | head -1) + + # Clean up the API key file + rm -f "$API_KEY_FILE" + + if echo "$NOTARIZATION_INFO" | grep -q "success"; then + echo "Notarization successful" + + # Staple the ticket to the application + xcrun stapler staple "$APP_PATH" + + # Repackage the notarized app + rm "PackagedReleases/LuckyRobots-macOS.zip" + (cd $(dirname "$APP_PATH") && zip -r "../../PackagedReleases/LuckyRobots-macOS.zip" "$(basename "$APP_PATH")") + echo "Repackaged notarized app" + else + echo "Notarization failed: $NOTARIZATION_INFO" + exit 1 + fi + else + echo "No app bundle found for signing and notarization" + exit 1 + fi + + # Clean up + rm -f certificate.p12 + security delete-keychain "$KEYCHAIN_PATH" + - name: Upload macOS Build Artifact uses: actions/upload-artifact@v3 if: success() diff --git a/LuckyRobots.entitlements b/LuckyRobots.entitlements new file mode 100644 index 00000000..ee35bd86 --- /dev/null +++ b/LuckyRobots.entitlements @@ -0,0 +1,18 @@ + + + + + com.apple.security.cs.allow-jit + + com.apple.security.cs.allow-unsigned-executable-memory + + com.apple.security.cs.disable-library-validation + + com.apple.security.cs.allow-dyld-environment-variables + + com.apple.security.device.audio-input + + com.apple.security.device.camera + + + \ No newline at end of file -- 2.47.2 From e54bbfcf5d7c95c8052758067ddda5f864104621 Mon Sep 17 00:00:00 2001 From: Ozgur Ersoy Date: Sun, 13 Apr 2025 01:30:08 +0200 Subject: [PATCH 005/109] new build --- .gitea/workflows/build.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.gitea/workflows/build.yml b/.gitea/workflows/build.yml index 3998ea59..99b4cd8d 100644 --- a/.gitea/workflows/build.yml +++ b/.gitea/workflows/build.yml @@ -327,4 +327,5 @@ jobs: - Branch: ${{ github.ref_name }} - Build Date: $(date -u +"%Y-%m-%d %H:%M:%S UTC") prerelease: ${{ github.ref != 'refs/heads/main' }} - tag_name: '${{ env.RELEASE_TAG }}' \ No newline at end of file + tag_name: '${{ env.RELEASE_TAG }}' + \ No newline at end of file -- 2.47.2 From 1476c4395f886abdea1e56d69047c8fa5c619485 Mon Sep 17 00:00:00 2001 From: Ozgur Ersoy Date: Sun, 13 Apr 2025 01:36:24 +0200 Subject: [PATCH 006/109] fix(workflows): ensure macOS app signing and notarization step always runs --- .gitea/workflows/macos-build.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitea/workflows/macos-build.yml b/.gitea/workflows/macos-build.yml index e9b29696..693b81c5 100644 --- a/.gitea/workflows/macos-build.yml +++ b/.gitea/workflows/macos-build.yml @@ -73,6 +73,7 @@ jobs: ls -la PackagedReleases/ - name: Sign and Notarize macOS App + if: ${{ always() }} env: APPLE_TEAM_ID: ${{ secrets.APPLE_TEAM_ID }} CERTIFICATE_BASE64: ${{ secrets.MACOS_CERTIFICATE }} -- 2.47.2 From 921f1215200958ad6209fcfc3024c8aee43c3c1e Mon Sep 17 00:00:00 2001 From: Ozgur Ersoy Date: Sun, 13 Apr 2025 01:47:41 +0200 Subject: [PATCH 007/109] fix(workflows): update variable names for macOS certificate handling in build workflow --- .gitea/workflows/macos-build.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.gitea/workflows/macos-build.yml b/.gitea/workflows/macos-build.yml index 693b81c5..020c7bea 100644 --- a/.gitea/workflows/macos-build.yml +++ b/.gitea/workflows/macos-build.yml @@ -76,15 +76,15 @@ jobs: if: ${{ always() }} env: APPLE_TEAM_ID: ${{ secrets.APPLE_TEAM_ID }} - CERTIFICATE_BASE64: ${{ secrets.MACOS_CERTIFICATE }} - CERTIFICATE_PASSWORD: ${{ secrets.MACOS_CERTIFICATE_PWD }} + APPLE_CERTIFICATE_BASE64: ${{ secrets.MACOS_CERTIFICATE }} + APPLE_CERTIFICATE_PASSWORD: ${{ secrets.MACOS_CERTIFICATE_PWD }} API_KEY_PATH: ${{ secrets.NOTARY_API_KEY_PATH }} API_KEY_ID: ${{ secrets.NOTARY_API_KEY_ID }} API_KEY_ISSUER_ID: ${{ secrets.NOTARY_API_KEY_ISSUER_ID }} run: | # Decode the base64 certificate echo "Setting up certificate..." - echo $CERTIFICATE_BASE64 | base64 --decode > certificate.p12 + echo $APPLE_CERTIFICATE_BASE64 | base64 --decode > certificate.p12 # Create keychain and import certificate KEYCHAIN_PATH=$RUNNER_TEMP/app-signing.keychain-db @@ -93,7 +93,7 @@ jobs: security create-keychain -p "$KEYCHAIN_PASSWORD" "$KEYCHAIN_PATH" security set-keychain-settings -lut 21600 "$KEYCHAIN_PATH" security unlock-keychain -p "$KEYCHAIN_PASSWORD" "$KEYCHAIN_PATH" - security import certificate.p12 -P "$CERTIFICATE_PASSWORD" -A -t cert -f pkcs12 -k "$KEYCHAIN_PATH" + security import certificate.p12 -P "$APPLE_CERTIFICATE_PASSWORD" -A -t cert -f pkcs12 -k "$KEYCHAIN_PATH" security list-keychain -d user -s "$KEYCHAIN_PATH" # Find app bundle -- 2.47.2 From dbb2d66564069f1fae9473707883874e6649d4b3 Mon Sep 17 00:00:00 2001 From: Ozgur Ersoy Date: Sun, 13 Apr 2025 02:01:31 +0200 Subject: [PATCH 008/109] fix(workflows): update macOS app signing step to run only on success --- .gitea/workflows/macos-build.yml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/.gitea/workflows/macos-build.yml b/.gitea/workflows/macos-build.yml index 020c7bea..576506cc 100644 --- a/.gitea/workflows/macos-build.yml +++ b/.gitea/workflows/macos-build.yml @@ -71,9 +71,10 @@ jobs: echo "Packaged releases:" ls -la PackagedReleases/ + echo "tests" - - name: Sign and Notarize macOS App - if: ${{ always() }} + - name: Sign and Notarize macOS App 2 + if: ${{ success() }} env: APPLE_TEAM_ID: ${{ secrets.APPLE_TEAM_ID }} APPLE_CERTIFICATE_BASE64: ${{ secrets.MACOS_CERTIFICATE }} -- 2.47.2 From 4d067474e3b2571ca6088906875c74e663fc6759 Mon Sep 17 00:00:00 2001 From: Ozgur Ersoy Date: Sun, 13 Apr 2025 02:06:08 +0200 Subject: [PATCH 009/109] fix(workflows): streamline macOS app packaging and notarization process --- .gitea/workflows/macos-build.yml | 71 +++++++++++++------------------- 1 file changed, 28 insertions(+), 43 deletions(-) diff --git a/.gitea/workflows/macos-build.yml b/.gitea/workflows/macos-build.yml index 576506cc..e57b3498 100644 --- a/.gitea/workflows/macos-build.yml +++ b/.gitea/workflows/macos-build.yml @@ -36,44 +36,7 @@ jobs: chmod +x ./scripts/mac_build.sh ./scripts/mac_build.sh - - name: Package macOS build - run: | - echo "Preparing packaged files for release..." - - # Find the app bundle in the Builds directory - APP_PATH=$(find Builds -type d -name "*.app" | head -1) - - if [ -n "$APP_PATH" ]; then - echo "Found app bundle: $APP_PATH" - # Get the app name - APP_NAME=$(basename "$APP_PATH") - # Create zip file of the app bundle - (cd $(dirname "$APP_PATH") && zip -r "../../PackagedReleases/LuckyRobots-macOS.zip" "$APP_NAME") - echo "Created packaged release: PackagedReleases/LuckyRobots-macOS.zip" - else - echo "No .app bundle found in Builds directory" - - # Look for a directory that might be a bundle but not named .app - MAIN_BUILD_DIR=$(find Builds -mindepth 1 -maxdepth 1 -type d | head -1) - if [ -n "$MAIN_BUILD_DIR" ]; then - echo "Found main build directory: $MAIN_BUILD_DIR" - DIR_NAME=$(basename "$MAIN_BUILD_DIR") - # Package this directory as if it were the app - (cd $(dirname "$MAIN_BUILD_DIR") && zip -r "../../PackagedReleases/LuckyRobots-macOS.zip" "$DIR_NAME") - echo "Created packaged release from main directory: PackagedReleases/LuckyRobots-macOS.zip" - else - # Package the entire Builds directory as a fallback - echo "No main directory found, packaging everything" - zip -r "PackagedReleases/LuckyRobots-macOS.zip" Builds - echo "Created fallback package: PackagedReleases/LuckyRobots-macOS.zip" - fi - fi - - echo "Packaged releases:" - ls -la PackagedReleases/ - echo "tests" - - - name: Sign and Notarize macOS App 2 + - name: Sign and Notarize macOS App if: ${{ success() }} env: APPLE_TEAM_ID: ${{ secrets.APPLE_TEAM_ID }} @@ -83,6 +46,9 @@ jobs: API_KEY_ID: ${{ secrets.NOTARY_API_KEY_ID }} API_KEY_ISSUER_ID: ${{ secrets.NOTARY_API_KEY_ISSUER_ID }} run: | + # Create output directory + mkdir -p PackagedReleases + # Decode the base64 certificate echo "Setting up certificate..." echo $APPLE_CERTIFICATE_BASE64 | base64 --decode > certificate.p12 @@ -130,19 +96,38 @@ jobs: # Staple the ticket to the application xcrun stapler staple "$APP_PATH" - # Repackage the notarized app - rm "PackagedReleases/LuckyRobots-macOS.zip" - (cd $(dirname "$APP_PATH") && zip -r "../../PackagedReleases/LuckyRobots-macOS.zip" "$(basename "$APP_PATH")") - echo "Repackaged notarized app" + # Package the notarized app + echo "Creating final package..." + APP_NAME=$(basename "$APP_PATH") + (cd $(dirname "$APP_PATH") && zip -r "../../PackagedReleases/LuckyRobots-macOS.zip" "$APP_NAME") + echo "Created packaged release: PackagedReleases/LuckyRobots-macOS.zip" else echo "Notarization failed: $NOTARIZATION_INFO" exit 1 fi else echo "No app bundle found for signing and notarization" - exit 1 + + # Look for a directory that might be a bundle but not named .app + MAIN_BUILD_DIR=$(find Builds -mindepth 1 -maxdepth 1 -type d | head -1) + if [ -n "$MAIN_BUILD_DIR" ]; then + echo "Found main build directory: $MAIN_BUILD_DIR" + # Try to sign this directory instead + /usr/bin/codesign --force --options runtime --sign "Developer ID Application: $APPLE_TEAM_ID" --deep --entitlements "./LuckyRobots.entitlements" "$MAIN_BUILD_DIR" + + # Package it + DIR_NAME=$(basename "$MAIN_BUILD_DIR") + (cd $(dirname "$MAIN_BUILD_DIR") && zip -r "../../PackagedReleases/LuckyRobots-macOS.zip" "$DIR_NAME") + echo "Created packaged release: PackagedReleases/LuckyRobots-macOS.zip" + else + echo "No main directory found, cannot sign or package" + exit 1 + fi fi + echo "Packaged releases:" + ls -la PackagedReleases/ + # Clean up rm -f certificate.p12 security delete-keychain "$KEYCHAIN_PATH" -- 2.47.2 From f804e441bbddcc8f8c3b00bfdb1ba4a0beed6e05 Mon Sep 17 00:00:00 2001 From: Ozgur Ersoy Date: Sun, 13 Apr 2025 02:11:49 +0200 Subject: [PATCH 010/109] refactor(workflows): consolidate build steps into separate workflow files for Windows, Linux, and macOS --- .gitea/workflows/build.yml | 162 +------------------------------------ 1 file changed, 3 insertions(+), 159 deletions(-) diff --git a/.gitea/workflows/build.yml b/.gitea/workflows/build.yml index 99b4cd8d..2c925c46 100644 --- a/.gitea/workflows/build.yml +++ b/.gitea/workflows/build.yml @@ -7,169 +7,13 @@ on: jobs: windows-build: - runs-on: windows - steps: - - name: Checkout repository - uses: actions/checkout@v3 - with: - lfs: true - fetch-depth: 0 - - - name: Setup environment - run: | - # Set environment variables for Unreal Engine - echo "UE_ROOT=E:/Games/UE_5.5" >> $GITHUB_ENV - - # Create directories for builds - if (!(Test-Path "Builds/Windows")) { New-Item -ItemType Directory -Path "Builds/Windows" -Force } - if (!(Test-Path "PackagedReleases")) { New-Item -ItemType Directory -Path "PackagedReleases" -Force } - - - name: Build for Windows - run: | - # Chmod command doesn't exist in Windows, use PowerShell to run the bash script - & 'C:\Program Files\Git\bin\bash.exe' -c "./scripts/win_build.sh" - - - name: Package Windows build - run: | - echo "Packaging Windows build..." - if [ -d "Builds/Windows" ]; then - cd Builds/Windows - zip -r ../../PackagedReleases/LuckyRobots-Windows.zip . - cd ../.. - fi - - echo "=== Packaged Windows release ===" - ls -la PackagedReleases/ - - - name: Upload Windows Build Artifact - uses: actions/upload-artifact@v3 - if: success() && hashFiles('PackagedReleases/LuckyRobots-Windows.zip') != '' - with: - name: LuckyRobots-Windows - path: PackagedReleases/LuckyRobots-Windows.zip - retention-days: 365 + uses: ./.gitea/workflows/windows-build.yml linux-build: - runs-on: windows - steps: - - name: Checkout repository - uses: actions/checkout@v3 - with: - lfs: true - fetch-depth: 0 - - - name: Setup environment - run: | - # Set environment variables for Unreal Engine - echo "UE_ROOT=E:/Games/UE_5.5" >> $GITHUB_ENV - - # Set environment variables for Linux toolchain (needed for cross-compilation) - $env:LINUX_MULTIARCH_ROOT="C:/UnrealToolchains/v23_clang-18.1.0-rockylinux8" - echo "LINUX_MULTIARCH_ROOT=${LINUX_MULTIARCH_ROOT}" >> $GITHUB_ENV - - # Create directories for builds - if (!(Test-Path "Builds/Linux")) { New-Item -ItemType Directory -Path "Builds/Linux" -Force } - if (!(Test-Path "PackagedReleases")) { New-Item -ItemType Directory -Path "PackagedReleases" -Force } - - - name: Build for Linux - run: | - # Chmod command doesn't exist in Windows, use PowerShell to run the bash script - & 'C:\Program Files\Git\bin\bash.exe' -c "./scripts/linux_build.sh" - - - name: Package Linux build - run: | - echo "Packaging Linux build..." - if [ -d "Builds/Linux" ]; then - cd Builds/Linux - zip -r ../../PackagedReleases/LuckyRobots-Linux.zip . - cd ../.. - fi - - echo "=== Packaged Linux release ===" - ls -la PackagedReleases/ - - - name: Upload Linux Build Artifact - uses: actions/upload-artifact@v3 - if: success() && hashFiles('PackagedReleases/LuckyRobots-Linux.zip') != '' - with: - name: LuckyRobots-Linux - path: PackagedReleases/LuckyRobots-Linux.zip - retention-days: 365 + uses: ./.gitea/workflows/linux-build.yml macos-build: - runs-on: macos - steps: - - name: Checkout repository - uses: actions/checkout@v3 - with: - lfs: true - fetch-depth: 0 - - - name: Setup environment - run: | - # Use the correct path where Unreal Engine is installed - UE_PATH="/Users/Shared/Epic Games/UE_5.5" - - if [ ! -d "$UE_PATH" ]; then - echo "Error: Unreal Engine is not installed in the expected location" - echo "Please ensure Unreal Engine is installed at $UE_PATH" - exit 1 - fi - - # Create directories for builds - mkdir -p Builds/Mac - mkdir -p PackagedReleases - - echo "Using Unreal Engine 5.5" - - - name: Build for macOS - run: | - chmod +x ./scripts/mac_build.sh - ./scripts/mac_build.sh - - - name: Package macOS build - run: | - echo "Preparing packaged files for release..." - - # Find the app bundle in the Builds directory - APP_PATH=$(find Builds -type d -name "*.app" | head -1) - - if [ -n "$APP_PATH" ]; then - echo "Found app bundle: $APP_PATH" - # Get the app name - APP_NAME=$(basename "$APP_PATH") - # Create zip file of the app bundle - (cd $(dirname "$APP_PATH") && zip -r "../../PackagedReleases/LuckyRobots-macOS.zip" "$APP_NAME") - echo "Created packaged release: PackagedReleases/LuckyRobots-macOS.zip" - else - echo "No .app bundle found in Builds directory" - - # Look for a directory that might be a bundle but not named .app - MAIN_BUILD_DIR=$(find Builds -mindepth 1 -maxdepth 1 -type d | head -1) - if [ -n "$MAIN_BUILD_DIR" ]; then - echo "Found main build directory: $MAIN_BUILD_DIR" - DIR_NAME=$(basename "$MAIN_BUILD_DIR") - # Package this directory as if it were the app - (cd $(dirname "$MAIN_BUILD_DIR") && zip -r "../../PackagedReleases/LuckyRobots-macOS.zip" "$DIR_NAME") - echo "Created packaged release from main directory: PackagedReleases/LuckyRobots-macOS.zip" - else - # Package the entire Builds directory as a fallback - echo "No main directory found, packaging everything" - zip -r "PackagedReleases/LuckyRobots-macOS.zip" Builds - echo "Created fallback package: PackagedReleases/LuckyRobots-macOS.zip" - fi - fi - - echo "Packaged releases:" - ls -la PackagedReleases/ - - - name: Upload macOS Build Artifact - uses: actions/upload-artifact@v3 - if: success() - with: - name: LuckyRobots-macOS - path: PackagedReleases/LuckyRobots-macOS.zip - retention-days: 365 + uses: ./.gitea/workflows/macos-build.yml create-release: needs: [windows-build, linux-build, macos-build] -- 2.47.2 From d2e8757535c9d8527c2e29d448620ab4799c01ab Mon Sep 17 00:00:00 2001 From: Ozgur Ersoy Date: Sun, 13 Apr 2025 02:35:09 +0200 Subject: [PATCH 011/109] refactor(workflows): merge individual build workflows into a unified workflow with platform-specific steps for Windows, Linux, and macOS --- .gitea/actions/linux-build/action.yml | 46 +++++++ .gitea/actions/macos-build/action.yml | 154 ++++++++++++++++++++++++ .gitea/actions/windows-build/action.yml | 42 +++++++ .gitea/workflows/build.yml | 44 ++++++- .gitea/workflows/linux-build.yml | 53 -------- .gitea/workflows/macos-build.yml | 141 ---------------------- .gitea/workflows/windows-build.yml | 49 -------- 7 files changed, 281 insertions(+), 248 deletions(-) create mode 100644 .gitea/actions/linux-build/action.yml create mode 100644 .gitea/actions/macos-build/action.yml create mode 100644 .gitea/actions/windows-build/action.yml delete mode 100644 .gitea/workflows/linux-build.yml delete mode 100644 .gitea/workflows/macos-build.yml delete mode 100644 .gitea/workflows/windows-build.yml diff --git a/.gitea/actions/linux-build/action.yml b/.gitea/actions/linux-build/action.yml new file mode 100644 index 00000000..f9cf4604 --- /dev/null +++ b/.gitea/actions/linux-build/action.yml @@ -0,0 +1,46 @@ +name: 'Linux Build Steps' +description: 'Build Linux application' + +runs: + using: "composite" + steps: + - name: Setup environment + run: | + # Set environment variables for Unreal Engine + echo "UE_ROOT=E:/Games/UE_5.5" >> $GITHUB_ENV + + # Set environment variables for Linux toolchain (needed for cross-compilation) + $env:LINUX_MULTIARCH_ROOT="C:/UnrealToolchains/v23_clang-18.1.0-rockylinux8" + echo "LINUX_MULTIARCH_ROOT=${LINUX_MULTIARCH_ROOT}" >> $GITHUB_ENV + + # Create directories for builds + if (!(Test-Path "Builds/Linux")) { New-Item -ItemType Directory -Path "Builds/Linux" -Force } + if (!(Test-Path "PackagedReleases")) { New-Item -ItemType Directory -Path "PackagedReleases" -Force } + shell: pwsh + + - name: Build for Linux + run: | + # Chmod command doesn't exist in Windows, use PowerShell to run the bash script + & 'C:\Program Files\Git\bin\bash.exe' -c "./scripts/linux_build.sh" + shell: pwsh + + - name: Package Linux build + run: | + echo "Packaging Linux build..." + if [ -d "Builds/Linux" ]; then + cd Builds/Linux + zip -r ../../PackagedReleases/LuckyRobots-Linux.zip . + cd ../.. + fi + + echo "=== Packaged Linux release ===" + ls -la PackagedReleases/ + shell: bash + + - name: Upload Linux Build Artifact + uses: actions/upload-artifact@v3 + if: success() && hashFiles('PackagedReleases/LuckyRobots-Linux.zip') != '' + with: + name: LuckyRobots-Linux + path: PackagedReleases/LuckyRobots-Linux.zip + retention-days: 365 \ No newline at end of file diff --git a/.gitea/actions/macos-build/action.yml b/.gitea/actions/macos-build/action.yml new file mode 100644 index 00000000..75a6351e --- /dev/null +++ b/.gitea/actions/macos-build/action.yml @@ -0,0 +1,154 @@ +name: 'macOS Build Steps' +description: 'Build, sign and notarize macOS application' + +inputs: + apple_team_id: + description: 'Apple Team ID for signing' + required: true + apple_certificate_base64: + description: 'Base64-encoded certificate file' + required: true + apple_certificate_password: + description: 'Password for certificate file' + required: true + api_key_path: + description: 'Base64-encoded API key file' + required: true + api_key_id: + description: 'API Key ID' + required: true + api_key_issuer_id: + description: 'API Key Issuer ID' + required: true + +runs: + using: "composite" + steps: + - name: Setup environment + run: | + # Use the correct path where Unreal Engine is installed + UE_PATH="/Users/Shared/Epic Games/UE_5.5" + + if [ ! -d "$UE_PATH" ]; then + echo "Error: Unreal Engine is not installed in the expected location" + echo "Please ensure Unreal Engine is installed at $UE_PATH" + exit 1 + fi + + # Create directories for builds + mkdir -p Builds/Mac + mkdir -p PackagedReleases + + echo "Using Unreal Engine 5.5" + shell: bash + + - name: Build for macOS + run: | + chmod +x ./scripts/mac_build.sh + ./scripts/mac_build.sh + shell: bash + + - name: Sign and Notarize macOS App + if: ${{ success() }} + env: + APPLE_TEAM_ID: ${{ inputs.apple_team_id }} + APPLE_CERTIFICATE_BASE64: ${{ inputs.apple_certificate_base64 }} + APPLE_CERTIFICATE_PASSWORD: ${{ inputs.apple_certificate_password }} + API_KEY_PATH: ${{ inputs.api_key_path }} + API_KEY_ID: ${{ inputs.api_key_id }} + API_KEY_ISSUER_ID: ${{ inputs.api_key_issuer_id }} + run: | + # Create output directory + mkdir -p PackagedReleases + + # Decode the base64 certificate + echo "Setting up certificate..." + echo $APPLE_CERTIFICATE_BASE64 | base64 --decode > certificate.p12 + + # Create keychain and import certificate + KEYCHAIN_PATH=$RUNNER_TEMP/app-signing.keychain-db + KEYCHAIN_PASSWORD=temporary + + security create-keychain -p "$KEYCHAIN_PASSWORD" "$KEYCHAIN_PATH" + security set-keychain-settings -lut 21600 "$KEYCHAIN_PATH" + security unlock-keychain -p "$KEYCHAIN_PASSWORD" "$KEYCHAIN_PATH" + security import certificate.p12 -P "$APPLE_CERTIFICATE_PASSWORD" -A -t cert -f pkcs12 -k "$KEYCHAIN_PATH" + security list-keychain -d user -s "$KEYCHAIN_PATH" + + # Find app bundle + APP_PATH=$(find Builds -type d -name "*.app" | head -1) + + if [ -n "$APP_PATH" ]; then + echo "Signing app bundle: $APP_PATH" + + # Sign the application + /usr/bin/codesign --force --options runtime --sign "Developer ID Application: $APPLE_TEAM_ID" --deep --entitlements "./LuckyRobots.entitlements" "$APP_PATH" + + # Create a temporary file for notarization + NOTARIZE_APP_PATH="./LuckyRobots-notarize.zip" + ditto -c -k --keepParent "$APP_PATH" "$NOTARIZE_APP_PATH" + + # Decode the API key from Base64 secret + echo "$API_KEY_PATH" | base64 --decode > api_key.p8 + API_KEY_FILE="api_key.p8" + + # Submit for notarization using API key + echo "Submitting for notarization with API key..." + xcrun notarytool submit "$NOTARIZE_APP_PATH" --key "$API_KEY_FILE" --key-id "$API_KEY_ID" --issuer "$API_KEY_ISSUER_ID" --wait + + # Check notarization result + NOTARIZATION_INFO=$(xcrun notarytool history --key "$API_KEY_FILE" --key-id "$API_KEY_ID" --issuer "$API_KEY_ISSUER_ID" | grep -E '(success|invalid)' | head -1) + + # Clean up the API key file + rm -f "$API_KEY_FILE" + + if echo "$NOTARIZATION_INFO" | grep -q "success"; then + echo "Notarization successful" + + # Staple the ticket to the application + xcrun stapler staple "$APP_PATH" + + # Package the notarized app + echo "Creating final package..." + APP_NAME=$(basename "$APP_PATH") + (cd $(dirname "$APP_PATH") && zip -r "../../PackagedReleases/LuckyRobots-macOS.zip" "$APP_NAME") + echo "Created packaged release: PackagedReleases/LuckyRobots-macOS.zip" + else + echo "Notarization failed: $NOTARIZATION_INFO" + exit 1 + fi + else + echo "No app bundle found for signing and notarization" + + # Look for a directory that might be a bundle but not named .app + MAIN_BUILD_DIR=$(find Builds -mindepth 1 -maxdepth 1 -type d | head -1) + if [ -n "$MAIN_BUILD_DIR" ]; then + echo "Found main build directory: $MAIN_BUILD_DIR" + # Try to sign this directory instead + /usr/bin/codesign --force --options runtime --sign "Developer ID Application: $APPLE_TEAM_ID" --deep --entitlements "./LuckyRobots.entitlements" "$MAIN_BUILD_DIR" + + # Package it + DIR_NAME=$(basename "$MAIN_BUILD_DIR") + (cd $(dirname "$MAIN_BUILD_DIR") && zip -r "../../PackagedReleases/LuckyRobots-macOS.zip" "$DIR_NAME") + echo "Created packaged release: PackagedReleases/LuckyRobots-macOS.zip" + else + echo "No main directory found, cannot sign or package" + exit 1 + fi + fi + + echo "Packaged releases:" + ls -la PackagedReleases/ + + # Clean up + rm -f certificate.p12 + security delete-keychain "$KEYCHAIN_PATH" + shell: bash + + - name: Upload macOS Build Artifact + uses: actions/upload-artifact@v3 + if: success() + with: + name: LuckyRobots-macOS + path: PackagedReleases/LuckyRobots-macOS.zip + retention-days: 365 \ No newline at end of file diff --git a/.gitea/actions/windows-build/action.yml b/.gitea/actions/windows-build/action.yml new file mode 100644 index 00000000..1518429e --- /dev/null +++ b/.gitea/actions/windows-build/action.yml @@ -0,0 +1,42 @@ +name: 'Windows Build Steps' +description: 'Build Windows application' + +runs: + using: "composite" + steps: + - name: Setup environment + run: | + # Set environment variables for Unreal Engine + echo "UE_ROOT=E:/Games/UE_5.5" >> $GITHUB_ENV + + # Create directories for builds + if (!(Test-Path "Builds/Windows")) { New-Item -ItemType Directory -Path "Builds/Windows" -Force } + if (!(Test-Path "PackagedReleases")) { New-Item -ItemType Directory -Path "PackagedReleases" -Force } + shell: pwsh + + - name: Build for Windows + run: | + # Chmod command doesn't exist in Windows, use PowerShell to run the bash script + & 'C:\Program Files\Git\bin\bash.exe' -c "./scripts/win_build.sh" + shell: pwsh + + - name: Package Windows build + run: | + echo "Packaging Windows build..." + if [ -d "Builds/Windows" ]; then + cd Builds/Windows + zip -r ../../PackagedReleases/LuckyRobots-Windows.zip . + cd ../.. + fi + + echo "=== Packaged Windows release ===" + ls -la PackagedReleases/ + shell: bash + + - name: Upload Windows Build Artifact + uses: actions/upload-artifact@v3 + if: success() && hashFiles('PackagedReleases/LuckyRobots-Windows.zip') != '' + with: + name: LuckyRobots-Windows + path: PackagedReleases/LuckyRobots-Windows.zip + retention-days: 365 \ No newline at end of file diff --git a/.gitea/workflows/build.yml b/.gitea/workflows/build.yml index 2c925c46..12a13ab2 100644 --- a/.gitea/workflows/build.yml +++ b/.gitea/workflows/build.yml @@ -7,13 +7,47 @@ on: jobs: windows-build: - uses: ./.gitea/workflows/windows-build.yml - + runs-on: windows + steps: + - name: Checkout repository + uses: actions/checkout@v3 + with: + lfs: true + fetch-depth: 0 + + - name: Build Windows + uses: ./.gitea/actions/windows-build + linux-build: - uses: ./.gitea/workflows/linux-build.yml - + runs-on: windows + steps: + - name: Checkout repository + uses: actions/checkout@v3 + with: + lfs: true + fetch-depth: 0 + + - name: Build Linux + uses: ./.gitea/actions/linux-build + macos-build: - uses: ./.gitea/workflows/macos-build.yml + runs-on: macos + steps: + - name: Checkout repository + uses: actions/checkout@v3 + with: + lfs: true + fetch-depth: 0 + + - name: Build macOS + uses: ./.gitea/actions/macos-build + with: + apple_team_id: ${{ secrets.APPLE_TEAM_ID }} + apple_certificate_base64: ${{ secrets.MACOS_CERTIFICATE }} + apple_certificate_password: ${{ secrets.MACOS_CERTIFICATE_PWD }} + api_key_path: ${{ secrets.NOTARY_API_KEY_PATH }} + api_key_id: ${{ secrets.NOTARY_API_KEY_ID }} + api_key_issuer_id: ${{ secrets.NOTARY_API_KEY_ISSUER_ID }} create-release: needs: [windows-build, linux-build, macos-build] diff --git a/.gitea/workflows/linux-build.yml b/.gitea/workflows/linux-build.yml deleted file mode 100644 index 51117aaf..00000000 --- a/.gitea/workflows/linux-build.yml +++ /dev/null @@ -1,53 +0,0 @@ -name: Linux Build - -on: - workflow_dispatch: - workflow_call: - -jobs: - linux-build: - runs-on: windows - steps: - - name: Checkout repository - uses: actions/checkout@v3 - with: - lfs: true - fetch-depth: 0 - - - name: Setup environment - run: | - # Set environment variables for Unreal Engine - echo "UE_ROOT=E:/Games/UE_5.5" >> $GITHUB_ENV - - # Set environment variables for Linux toolchain (needed for cross-compilation) - $env:LINUX_MULTIARCH_ROOT="C:/UnrealToolchains/v23_clang-18.1.0-rockylinux8" - echo "LINUX_MULTIARCH_ROOT=${LINUX_MULTIARCH_ROOT}" >> $GITHUB_ENV - - # Create directories for builds - if (!(Test-Path "Builds/Linux")) { New-Item -ItemType Directory -Path "Builds/Linux" -Force } - if (!(Test-Path "PackagedReleases")) { New-Item -ItemType Directory -Path "PackagedReleases" -Force } - - - name: Build for Linux - run: | - # Chmod command doesn't exist in Windows, use PowerShell to run the bash script - & 'C:\Program Files\Git\bin\bash.exe' -c "./scripts/linux_build.sh" - - - name: Package Linux build - run: | - echo "Packaging Linux build..." - if [ -d "Builds/Linux" ]; then - cd Builds/Linux - zip -r ../../PackagedReleases/LuckyRobots-Linux.zip . - cd ../.. - fi - - echo "=== Packaged Linux release ===" - ls -la PackagedReleases/ - - - name: Upload Linux Build Artifact - uses: actions/upload-artifact@v3 - if: success() && hashFiles('PackagedReleases/LuckyRobots-Linux.zip') != '' - with: - name: LuckyRobots-Linux - path: PackagedReleases/LuckyRobots-Linux.zip - retention-days: 365 \ No newline at end of file diff --git a/.gitea/workflows/macos-build.yml b/.gitea/workflows/macos-build.yml deleted file mode 100644 index e57b3498..00000000 --- a/.gitea/workflows/macos-build.yml +++ /dev/null @@ -1,141 +0,0 @@ -name: macOS Build - -on: - workflow_dispatch: - workflow_call: - -jobs: - macos-build: - runs-on: macos - steps: - - name: Checkout repository - uses: actions/checkout@v3 - with: - lfs: true - fetch-depth: 0 - - - name: Setup environment - run: | - # Use the correct path where Unreal Engine is installed - UE_PATH="/Users/Shared/Epic Games/UE_5.5" - - if [ ! -d "$UE_PATH" ]; then - echo "Error: Unreal Engine is not installed in the expected location" - echo "Please ensure Unreal Engine is installed at $UE_PATH" - exit 1 - fi - - # Create directories for builds - mkdir -p Builds/Mac - mkdir -p PackagedReleases - - echo "Using Unreal Engine 5.5" - - - name: Build for macOS - run: | - chmod +x ./scripts/mac_build.sh - ./scripts/mac_build.sh - - - name: Sign and Notarize macOS App - if: ${{ success() }} - env: - APPLE_TEAM_ID: ${{ secrets.APPLE_TEAM_ID }} - APPLE_CERTIFICATE_BASE64: ${{ secrets.MACOS_CERTIFICATE }} - APPLE_CERTIFICATE_PASSWORD: ${{ secrets.MACOS_CERTIFICATE_PWD }} - API_KEY_PATH: ${{ secrets.NOTARY_API_KEY_PATH }} - API_KEY_ID: ${{ secrets.NOTARY_API_KEY_ID }} - API_KEY_ISSUER_ID: ${{ secrets.NOTARY_API_KEY_ISSUER_ID }} - run: | - # Create output directory - mkdir -p PackagedReleases - - # Decode the base64 certificate - echo "Setting up certificate..." - echo $APPLE_CERTIFICATE_BASE64 | base64 --decode > certificate.p12 - - # Create keychain and import certificate - KEYCHAIN_PATH=$RUNNER_TEMP/app-signing.keychain-db - KEYCHAIN_PASSWORD=temporary - - security create-keychain -p "$KEYCHAIN_PASSWORD" "$KEYCHAIN_PATH" - security set-keychain-settings -lut 21600 "$KEYCHAIN_PATH" - security unlock-keychain -p "$KEYCHAIN_PASSWORD" "$KEYCHAIN_PATH" - security import certificate.p12 -P "$APPLE_CERTIFICATE_PASSWORD" -A -t cert -f pkcs12 -k "$KEYCHAIN_PATH" - security list-keychain -d user -s "$KEYCHAIN_PATH" - - # Find app bundle - APP_PATH=$(find Builds -type d -name "*.app" | head -1) - - if [ -n "$APP_PATH" ]; then - echo "Signing app bundle: $APP_PATH" - - # Sign the application - /usr/bin/codesign --force --options runtime --sign "Developer ID Application: $APPLE_TEAM_ID" --deep --entitlements "./LuckyRobots.entitlements" "$APP_PATH" - - # Create a temporary file for notarization - NOTARIZE_APP_PATH="./LuckyRobots-notarize.zip" - ditto -c -k --keepParent "$APP_PATH" "$NOTARIZE_APP_PATH" - - # Decode the API key from Base64 secret - echo "$API_KEY_PATH" | base64 --decode > api_key.p8 - API_KEY_FILE="api_key.p8" - - # Submit for notarization using API key - echo "Submitting for notarization with API key..." - xcrun notarytool submit "$NOTARIZE_APP_PATH" --key "$API_KEY_FILE" --key-id "$API_KEY_ID" --issuer "$API_KEY_ISSUER_ID" --wait - - # Check notarization result - NOTARIZATION_INFO=$(xcrun notarytool history --key "$API_KEY_FILE" --key-id "$API_KEY_ID" --issuer "$API_KEY_ISSUER_ID" | grep -E '(success|invalid)' | head -1) - - # Clean up the API key file - rm -f "$API_KEY_FILE" - - if echo "$NOTARIZATION_INFO" | grep -q "success"; then - echo "Notarization successful" - - # Staple the ticket to the application - xcrun stapler staple "$APP_PATH" - - # Package the notarized app - echo "Creating final package..." - APP_NAME=$(basename "$APP_PATH") - (cd $(dirname "$APP_PATH") && zip -r "../../PackagedReleases/LuckyRobots-macOS.zip" "$APP_NAME") - echo "Created packaged release: PackagedReleases/LuckyRobots-macOS.zip" - else - echo "Notarization failed: $NOTARIZATION_INFO" - exit 1 - fi - else - echo "No app bundle found for signing and notarization" - - # Look for a directory that might be a bundle but not named .app - MAIN_BUILD_DIR=$(find Builds -mindepth 1 -maxdepth 1 -type d | head -1) - if [ -n "$MAIN_BUILD_DIR" ]; then - echo "Found main build directory: $MAIN_BUILD_DIR" - # Try to sign this directory instead - /usr/bin/codesign --force --options runtime --sign "Developer ID Application: $APPLE_TEAM_ID" --deep --entitlements "./LuckyRobots.entitlements" "$MAIN_BUILD_DIR" - - # Package it - DIR_NAME=$(basename "$MAIN_BUILD_DIR") - (cd $(dirname "$MAIN_BUILD_DIR") && zip -r "../../PackagedReleases/LuckyRobots-macOS.zip" "$DIR_NAME") - echo "Created packaged release: PackagedReleases/LuckyRobots-macOS.zip" - else - echo "No main directory found, cannot sign or package" - exit 1 - fi - fi - - echo "Packaged releases:" - ls -la PackagedReleases/ - - # Clean up - rm -f certificate.p12 - security delete-keychain "$KEYCHAIN_PATH" - - - name: Upload macOS Build Artifact - uses: actions/upload-artifact@v3 - if: success() - with: - name: LuckyRobots-macOS - path: PackagedReleases/LuckyRobots-macOS.zip - retention-days: 365 \ No newline at end of file diff --git a/.gitea/workflows/windows-build.yml b/.gitea/workflows/windows-build.yml deleted file mode 100644 index 220e6d3d..00000000 --- a/.gitea/workflows/windows-build.yml +++ /dev/null @@ -1,49 +0,0 @@ -name: Windows Build - -on: - workflow_dispatch: - workflow_call: - -jobs: - windows-build: - runs-on: windows - steps: - - name: Checkout repository - uses: actions/checkout@v3 - with: - lfs: true - fetch-depth: 0 - - - name: Setup environment - run: | - # Set environment variables for Unreal Engine - echo "UE_ROOT=E:/Games/UE_5.5" >> $GITHUB_ENV - - # Create directories for builds - if (!(Test-Path "Builds/Windows")) { New-Item -ItemType Directory -Path "Builds/Windows" -Force } - if (!(Test-Path "PackagedReleases")) { New-Item -ItemType Directory -Path "PackagedReleases" -Force } - - - name: Build for Windows - run: | - # Chmod command doesn't exist in Windows, use PowerShell to run the bash script - & 'C:\Program Files\Git\bin\bash.exe' -c "./scripts/win_build.sh" - - - name: Package Windows build - run: | - echo "Packaging Windows build..." - if [ -d "Builds/Windows" ]; then - cd Builds/Windows - zip -r ../../PackagedReleases/LuckyRobots-Windows.zip . - cd ../.. - fi - - echo "=== Packaged Windows release ===" - ls -la PackagedReleases/ - - - name: Upload Windows Build Artifact - uses: actions/upload-artifact@v3 - if: success() && hashFiles('PackagedReleases/LuckyRobots-Windows.zip') != '' - with: - name: LuckyRobots-Windows - path: PackagedReleases/LuckyRobots-Windows.zip - retention-days: 365 \ No newline at end of file -- 2.47.2 From b10423339ddd5c728f82ff2374ed191ebe33c119 Mon Sep 17 00:00:00 2001 From: Ozgur Ersoy Date: Sun, 13 Apr 2025 10:55:07 +0200 Subject: [PATCH 012/109] fix(workflows): enhance macOS build workflow by adding Apple root certificate downloads and improving app signing process --- .gitea/actions/macos-build/action.yml | 45 +++++++++++++++++++++++---- 1 file changed, 39 insertions(+), 6 deletions(-) diff --git a/.gitea/actions/macos-build/action.yml b/.gitea/actions/macos-build/action.yml index 75a6351e..1621494a 100644 --- a/.gitea/actions/macos-build/action.yml +++ b/.gitea/actions/macos-build/action.yml @@ -61,6 +61,15 @@ runs: # Create output directory mkdir -p PackagedReleases + # Download Apple root certificates + echo "Downloading Apple Developer certificates..." + curl -s -o AppleWWDRCAG3.cer https://www.apple.com/certificateauthority/AppleWWDRCAG3.cer + curl -s -o DeveloperIDG2.cer https://www.apple.com/certificateauthority/DeveloperIDG2.cer + + # Import Apple root certificates + security import AppleWWDRCAG3.cer -k /Library/Keychains/System.keychain + security import DeveloperIDG2.cer -k /Library/Keychains/System.keychain + # Decode the base64 certificate echo "Setting up certificate..." echo $APPLE_CERTIFICATE_BASE64 | base64 --decode > certificate.p12 @@ -73,7 +82,7 @@ runs: security set-keychain-settings -lut 21600 "$KEYCHAIN_PATH" security unlock-keychain -p "$KEYCHAIN_PASSWORD" "$KEYCHAIN_PATH" security import certificate.p12 -P "$APPLE_CERTIFICATE_PASSWORD" -A -t cert -f pkcs12 -k "$KEYCHAIN_PATH" - security list-keychain -d user -s "$KEYCHAIN_PATH" + security list-keychain -d user -s "$KEYCHAIN_PATH" /Library/Keychains/System.keychain # Find app bundle APP_PATH=$(find Builds -type d -name "*.app" | head -1) @@ -81,8 +90,25 @@ runs: if [ -n "$APP_PATH" ]; then echo "Signing app bundle: $APP_PATH" - # Sign the application - /usr/bin/codesign --force --options runtime --sign "Developer ID Application: $APPLE_TEAM_ID" --deep --entitlements "./LuckyRobots.entitlements" "$APP_PATH" + # First, handle problematic libraries separately (specifically libmujoco) + find "$APP_PATH" -name "libmujoco*.dylib" | while read DYLIB; do + echo "Pre-signing library: $DYLIB" + codesign --force --options runtime --timestamp --sign "Developer ID Application: $APPLE_TEAM_ID" "$DYLIB" + done + + # Now sign all other dylibs + find "$APP_PATH" -name "*.dylib" -o -name "*.framework" | while read LIB; do + echo "Signing library: $LIB" + codesign --force --options runtime --timestamp --sign "Developer ID Application: $APPLE_TEAM_ID" "$LIB" + done + + # Now sign the application itself + echo "Signing main application bundle..." + /usr/bin/codesign --force --options runtime --deep --timestamp --sign "Developer ID Application: $APPLE_TEAM_ID" --entitlements "./LuckyRobots.entitlements" "$APP_PATH" + + # Verify signature + echo "Verifying signature..." + codesign --verify --verbose "$APP_PATH" # Create a temporary file for notarization NOTARIZE_APP_PATH="./LuckyRobots-notarize.zip" @@ -124,8 +150,15 @@ runs: MAIN_BUILD_DIR=$(find Builds -mindepth 1 -maxdepth 1 -type d | head -1) if [ -n "$MAIN_BUILD_DIR" ]; then echo "Found main build directory: $MAIN_BUILD_DIR" - # Try to sign this directory instead - /usr/bin/codesign --force --options runtime --sign "Developer ID Application: $APPLE_TEAM_ID" --deep --entitlements "./LuckyRobots.entitlements" "$MAIN_BUILD_DIR" + + # Sign libraries first + find "$MAIN_BUILD_DIR" -name "*.dylib" -o -name "*.framework" | while read LIB; do + echo "Signing library: $LIB" + codesign --force --options runtime --timestamp --sign "Developer ID Application: $APPLE_TEAM_ID" "$LIB" + done + + # Then sign main directory + /usr/bin/codesign --force --options runtime --timestamp --sign "Developer ID Application: $APPLE_TEAM_ID" --deep --entitlements "./LuckyRobots.entitlements" "$MAIN_BUILD_DIR" # Package it DIR_NAME=$(basename "$MAIN_BUILD_DIR") @@ -141,7 +174,7 @@ runs: ls -la PackagedReleases/ # Clean up - rm -f certificate.p12 + rm -f certificate.p12 AppleWWDRCAG3.cer DeveloperIDG2.cer security delete-keychain "$KEYCHAIN_PATH" shell: bash -- 2.47.2 From dae5af77d3486cc1fcfee260bf68558e4b1b3e9a Mon Sep 17 00:00:00 2001 From: Ozgur Ersoy Date: Sun, 13 Apr 2025 12:21:15 +0200 Subject: [PATCH 013/109] fix(workflows): update macOS build workflow to import certificates into custom keychain and ensure trust settings --- .gitea/actions/macos-build/action.yml | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/.gitea/actions/macos-build/action.yml b/.gitea/actions/macos-build/action.yml index 1621494a..c84f9803 100644 --- a/.gitea/actions/macos-build/action.yml +++ b/.gitea/actions/macos-build/action.yml @@ -66,10 +66,6 @@ runs: curl -s -o AppleWWDRCAG3.cer https://www.apple.com/certificateauthority/AppleWWDRCAG3.cer curl -s -o DeveloperIDG2.cer https://www.apple.com/certificateauthority/DeveloperIDG2.cer - # Import Apple root certificates - security import AppleWWDRCAG3.cer -k /Library/Keychains/System.keychain - security import DeveloperIDG2.cer -k /Library/Keychains/System.keychain - # Decode the base64 certificate echo "Setting up certificate..." echo $APPLE_CERTIFICATE_BASE64 | base64 --decode > certificate.p12 @@ -81,8 +77,18 @@ runs: 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 all certificates to our custom keychain + security import AppleWWDRCAG3.cer -k "$KEYCHAIN_PATH" -T /usr/bin/codesign + security import DeveloperIDG2.cer -k "$KEYCHAIN_PATH" -T /usr/bin/codesign security import certificate.p12 -P "$APPLE_CERTIFICATE_PASSWORD" -A -t cert -f pkcs12 -k "$KEYCHAIN_PATH" - security list-keychain -d user -s "$KEYCHAIN_PATH" /Library/Keychains/System.keychain + + # Set keychain for signing + security list-keychain -d user -s "$KEYCHAIN_PATH" + security default-keychain -s "$KEYCHAIN_PATH" + + # Always trust our certificates + security set-key-partition-list -S apple-tool:,apple: -s -k "$KEYCHAIN_PASSWORD" "$KEYCHAIN_PATH" # Find app bundle APP_PATH=$(find Builds -type d -name "*.app" | head -1) -- 2.47.2 From f19ccd8a6f0a66f02c04be779df1254e91cbe01f Mon Sep 17 00:00:00 2001 From: Ozgur Ersoy Date: Sun, 13 Apr 2025 13:02:15 +0200 Subject: [PATCH 014/109] fix(workflows): update macOS build workflow to import certificates with trust settings for keychain --- .gitea/actions/macos-build/action.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.gitea/actions/macos-build/action.yml b/.gitea/actions/macos-build/action.yml index c84f9803..4f2237eb 100644 --- a/.gitea/actions/macos-build/action.yml +++ b/.gitea/actions/macos-build/action.yml @@ -79,8 +79,8 @@ runs: security unlock-keychain -p "$KEYCHAIN_PASSWORD" "$KEYCHAIN_PATH" # Import all certificates to our custom keychain - security import AppleWWDRCAG3.cer -k "$KEYCHAIN_PATH" -T /usr/bin/codesign - security import DeveloperIDG2.cer -k "$KEYCHAIN_PATH" -T /usr/bin/codesign + security import AppleWWDRCAG3.cer -k "$KEYCHAIN_PATH" -T /usr/bin/codesign -f der -A + security import DeveloperIDG2.cer -k "$KEYCHAIN_PATH" -T /usr/bin/codesign -f der -A security import certificate.p12 -P "$APPLE_CERTIFICATE_PASSWORD" -A -t cert -f pkcs12 -k "$KEYCHAIN_PATH" # Set keychain for signing -- 2.47.2 From 49032920a1e1d7d72d3e09a41cc494c7eb169b42 Mon Sep 17 00:00:00 2001 From: Ozgur Ersoy Date: Sun, 13 Apr 2025 14:01:49 +0200 Subject: [PATCH 015/109] fix(workflows): refactor macOS build workflow to streamline signing and notarization process with improved error handling --- .gitea/actions/macos-build/action.yml | 171 +++++++++----------------- 1 file changed, 55 insertions(+), 116 deletions(-) diff --git a/.gitea/actions/macos-build/action.yml b/.gitea/actions/macos-build/action.yml index 4f2237eb..62c94c09 100644 --- a/.gitea/actions/macos-build/action.yml +++ b/.gitea/actions/macos-build/action.yml @@ -48,140 +48,79 @@ runs: ./scripts/mac_build.sh shell: bash - - name: Sign and Notarize macOS App + - name: Setup for Signing + id: setup-signing if: ${{ success() }} env: - APPLE_TEAM_ID: ${{ inputs.apple_team_id }} - APPLE_CERTIFICATE_BASE64: ${{ inputs.apple_certificate_base64 }} - APPLE_CERTIFICATE_PASSWORD: ${{ inputs.apple_certificate_password }} API_KEY_PATH: ${{ inputs.api_key_path }} - API_KEY_ID: ${{ inputs.api_key_id }} - API_KEY_ISSUER_ID: ${{ inputs.api_key_issuer_id }} run: | # Create output directory mkdir -p PackagedReleases - # Download Apple root certificates - echo "Downloading Apple Developer certificates..." - curl -s -o AppleWWDRCAG3.cer https://www.apple.com/certificateauthority/AppleWWDRCAG3.cer - curl -s -o DeveloperIDG2.cer https://www.apple.com/certificateauthority/DeveloperIDG2.cer - - # Decode the base64 certificate - echo "Setting up certificate..." - echo $APPLE_CERTIFICATE_BASE64 | base64 --decode > certificate.p12 - - # Create keychain and import certificate - KEYCHAIN_PATH=$RUNNER_TEMP/app-signing.keychain-db - KEYCHAIN_PASSWORD=temporary - - 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 all certificates to our custom keychain - security import AppleWWDRCAG3.cer -k "$KEYCHAIN_PATH" -T /usr/bin/codesign -f der -A - security import DeveloperIDG2.cer -k "$KEYCHAIN_PATH" -T /usr/bin/codesign -f der -A - security import certificate.p12 -P "$APPLE_CERTIFICATE_PASSWORD" -A -t cert -f pkcs12 -k "$KEYCHAIN_PATH" - - # Set keychain for signing - security list-keychain -d user -s "$KEYCHAIN_PATH" - security default-keychain -s "$KEYCHAIN_PATH" - - # Always trust our certificates - security set-key-partition-list -S apple-tool:,apple: -s -k "$KEYCHAIN_PASSWORD" "$KEYCHAIN_PATH" + # Decode the API key from Base64 secret + echo "$API_KEY_PATH" | base64 --decode > api_key.p8 + echo "api_key_file=$(pwd)/api_key.p8" >> $GITHUB_OUTPUT # Find app bundle APP_PATH=$(find Builds -type d -name "*.app" | head -1) - if [ -n "$APP_PATH" ]; then - echo "Signing app bundle: $APP_PATH" - - # First, handle problematic libraries separately (specifically libmujoco) - find "$APP_PATH" -name "libmujoco*.dylib" | while read DYLIB; do - echo "Pre-signing library: $DYLIB" - codesign --force --options runtime --timestamp --sign "Developer ID Application: $APPLE_TEAM_ID" "$DYLIB" - done - - # Now sign all other dylibs - find "$APP_PATH" -name "*.dylib" -o -name "*.framework" | while read LIB; do - echo "Signing library: $LIB" - codesign --force --options runtime --timestamp --sign "Developer ID Application: $APPLE_TEAM_ID" "$LIB" - done - - # Now sign the application itself - echo "Signing main application bundle..." - /usr/bin/codesign --force --options runtime --deep --timestamp --sign "Developer ID Application: $APPLE_TEAM_ID" --entitlements "./LuckyRobots.entitlements" "$APP_PATH" - - # Verify signature - echo "Verifying signature..." - codesign --verify --verbose "$APP_PATH" - - # Create a temporary file for notarization - NOTARIZE_APP_PATH="./LuckyRobots-notarize.zip" - ditto -c -k --keepParent "$APP_PATH" "$NOTARIZE_APP_PATH" - - # Decode the API key from Base64 secret - echo "$API_KEY_PATH" | base64 --decode > api_key.p8 - API_KEY_FILE="api_key.p8" - - # Submit for notarization using API key - echo "Submitting for notarization with API key..." - xcrun notarytool submit "$NOTARIZE_APP_PATH" --key "$API_KEY_FILE" --key-id "$API_KEY_ID" --issuer "$API_KEY_ISSUER_ID" --wait - - # Check notarization result - NOTARIZATION_INFO=$(xcrun notarytool history --key "$API_KEY_FILE" --key-id "$API_KEY_ID" --issuer "$API_KEY_ISSUER_ID" | grep -E '(success|invalid)' | head -1) - - # Clean up the API key file - rm -f "$API_KEY_FILE" - - if echo "$NOTARIZATION_INFO" | grep -q "success"; then - echo "Notarization successful" - - # Staple the ticket to the application - xcrun stapler staple "$APP_PATH" - - # Package the notarized app - echo "Creating final package..." - APP_NAME=$(basename "$APP_PATH") - (cd $(dirname "$APP_PATH") && zip -r "../../PackagedReleases/LuckyRobots-macOS.zip" "$APP_NAME") - echo "Created packaged release: PackagedReleases/LuckyRobots-macOS.zip" - else - echo "Notarization failed: $NOTARIZATION_INFO" - exit 1 - fi - else - echo "No app bundle found for signing and notarization" - + if [ -z "$APP_PATH" ]; then # Look for a directory that might be a bundle but not named .app - MAIN_BUILD_DIR=$(find Builds -mindepth 1 -maxdepth 1 -type d | head -1) - if [ -n "$MAIN_BUILD_DIR" ]; then - echo "Found main build directory: $MAIN_BUILD_DIR" - - # Sign libraries first - find "$MAIN_BUILD_DIR" -name "*.dylib" -o -name "*.framework" | while read LIB; do - echo "Signing library: $LIB" - codesign --force --options runtime --timestamp --sign "Developer ID Application: $APPLE_TEAM_ID" "$LIB" - done - - # Then sign main directory - /usr/bin/codesign --force --options runtime --timestamp --sign "Developer ID Application: $APPLE_TEAM_ID" --deep --entitlements "./LuckyRobots.entitlements" "$MAIN_BUILD_DIR" - - # Package it - DIR_NAME=$(basename "$MAIN_BUILD_DIR") - (cd $(dirname "$MAIN_BUILD_DIR") && zip -r "../../PackagedReleases/LuckyRobots-macOS.zip" "$DIR_NAME") - echo "Created packaged release: PackagedReleases/LuckyRobots-macOS.zip" - else - echo "No main directory found, cannot sign or package" + APP_PATH=$(find Builds -mindepth 1 -maxdepth 1 -type d | head -1) + if [ -z "$APP_PATH" ]; then + echo "No build directory found, cannot continue" exit 1 fi fi + echo "Found app path: $APP_PATH" + echo "app_path=$APP_PATH" >> $GITHUB_OUTPUT + shell: bash + + - name: Sign macOS App + uses: lando/code-sign-action@v3 + id: sign-app + with: + file: ${{ steps.setup-signing.outputs.app_path }} + certificate-data: ${{ inputs.apple_certificate_base64 }} + certificate-password: ${{ inputs.apple_certificate_password }} + certificate-id: ${{ inputs.apple_team_id }} + options: --force --options runtime --deep --timestamp --entitlements ./LuckyRobots.entitlements + + - name: Notarize macOS App + run: | + # Create a temporary file for notarization + APP_PATH="${{ steps.setup-signing.outputs.app_path }}" + NOTARIZE_APP_PATH="./LuckyRobots-notarize.zip" + ditto -c -k --keepParent "$APP_PATH" "$NOTARIZE_APP_PATH" + + API_KEY_FILE="${{ steps.setup-signing.outputs.api_key_file }}" + + # Submit for notarization using API key + echo "Submitting for notarization with API key..." + xcrun notarytool submit "$NOTARIZE_APP_PATH" --key "$API_KEY_FILE" --key-id "${{ inputs.api_key_id }}" --issuer "${{ inputs.api_key_issuer_id }}" --wait + + # Staple the ticket to the application + xcrun stapler staple "$APP_PATH" + + # Clean up the API key file + rm -f "$API_KEY_FILE" + rm -f "$NOTARIZE_APP_PATH" + shell: bash + + - name: Package macOS App + run: | + # Package the signed and notarized app + APP_PATH="${{ steps.setup-signing.outputs.app_path }}" + APP_NAME=$(basename "$APP_PATH") + DIR_PATH=$(dirname "$APP_PATH") + + echo "Creating final package..." + (cd "$DIR_PATH" && zip -r "../../PackagedReleases/LuckyRobots-macOS.zip" "$APP_NAME") + echo "Created packaged release: PackagedReleases/LuckyRobots-macOS.zip" + echo "Packaged releases:" ls -la PackagedReleases/ - - # Clean up - rm -f certificate.p12 AppleWWDRCAG3.cer DeveloperIDG2.cer - security delete-keychain "$KEYCHAIN_PATH" shell: bash - name: Upload macOS Build Artifact -- 2.47.2 From 6ed4a8f9d15ea1117f35f664422800dd54ef1839 Mon Sep 17 00:00:00 2001 From: Ozgur Ersoy Date: Sun, 13 Apr 2025 14:08:12 +0200 Subject: [PATCH 016/109] chore(workflows): disable push trigger for build workflow and add new test signing workflow for macOS --- .gitea/workflows/build.yml | 4 +- .gitea/workflows/test-signing.yml | 166 ++++++++++++++++++++++++++++++ 2 files changed, 168 insertions(+), 2 deletions(-) create mode 100644 .gitea/workflows/test-signing.yml diff --git a/.gitea/workflows/build.yml b/.gitea/workflows/build.yml index 12a13ab2..28027bfd 100644 --- a/.gitea/workflows/build.yml +++ b/.gitea/workflows/build.yml @@ -2,8 +2,8 @@ name: Unreal Engine Build on: workflow_dispatch: - push: - branches: [ozgur/build] + # push: + # branches: [ozgur/build] jobs: windows-build: diff --git a/.gitea/workflows/test-signing.yml b/.gitea/workflows/test-signing.yml new file mode 100644 index 00000000..43cb2f13 --- /dev/null +++ b/.gitea/workflows/test-signing.yml @@ -0,0 +1,166 @@ +name: Test macOS Signing + +on: + workflow_dispatch: + inputs: + use_previous_build: + description: 'Use a previous successful build artifact instead of local app path' + required: true + type: boolean + default: false + app_path: + description: 'Path to the app bundle to sign (if not using artifact)' + required: false + default: 'Builds/Mac/LuckyRobots.app' + artifact_run_id: + description: 'Run ID of the workflow that produced the artifact to use (if using artifact)' + required: false + default: '' + +jobs: + test-signing: + runs-on: macos + steps: + - name: Checkout repository + uses: actions/checkout@v3 + with: + lfs: true + fetch-depth: 0 + + - name: Download Previous Build + if: ${{ github.event.inputs.use_previous_build == 'true' }} + run: | + # Create directories + mkdir -p Builds/Mac + + # Download artifact (using GitHub API or direct download) + echo "Downloading previous build artifact..." + + # If artifact_run_id is provided, use it + if [[ -n "${{ github.event.inputs.artifact_run_id }}" ]]; then + RUN_ID="${{ github.event.inputs.artifact_run_id }}" + else + # Get latest successful build run ID + echo "No specific run ID provided, finding latest successful build..." + + # You'll need to have proper authentication to access the API + # This is simplified, you might need to adjust based on your setup + RUN_ID=$(curl -s "https://luckyrobots.com/api/v1/repos/luckyrobots/luckyworld/actions/runs?status=success&event=push" | grep -o '"id":[0-9]*' | head -1 | cut -d':' -f2) + + if [[ -z "$RUN_ID" ]]; then + echo "Could not find a successful run ID. Please specify one manually." + exit 1 + fi + fi + + echo "Using run ID: $RUN_ID" + + # Download artifact using your Gitea API + # This is a simplified example - adjust as needed for your actual API + curl -L "https://luckyrobots.com/luckyrobots/luckyworld/actions/runs/$RUN_ID/artifacts/LuckyRobots-macOS" -o build.zip + + # Extract to Builds directory + unzip -o build.zip -d Builds/Mac/ + + # Find extracted app bundle + APP_PATH=$(find Builds/Mac -type d -name "*.app" | head -1) + + if [[ -z "$APP_PATH" ]]; then + echo "Could not find app bundle in downloaded artifact" + exit 1 + fi + + echo "Downloaded app bundle: $APP_PATH" + echo "app_path=$APP_PATH" >> $GITHUB_ENV + shell: bash + + - name: Validate App Path + id: validate-app + run: | + if [[ "${{ github.event.inputs.use_previous_build }}" == "true" ]]; then + APP_PATH="$app_path" + else + APP_PATH="${{ github.event.inputs.app_path }}" + fi + + if [ ! -d "$APP_PATH" ]; then + echo "Error: Application path does not exist: $APP_PATH" + echo "You can download a previous successful build artifact or specify a different path" + + # List available directories to help user + echo "Available directories in workspace:" + find . -type d -maxdepth 3 | grep -v "node_modules\|.git" + + exit 1 + fi + + echo "Will sign and notarize: $APP_PATH" + echo "app_path=$APP_PATH" >> $GITHUB_OUTPUT + shell: bash + + - name: Setup for Signing + id: setup-signing + env: + API_KEY_PATH: ${{ secrets.NOTARY_API_KEY_PATH }} + run: | + # Decode the API key from Base64 secret + echo "$API_KEY_PATH" | base64 --decode > api_key.p8 + echo "api_key_file=$(pwd)/api_key.p8" >> $GITHUB_OUTPUT + shell: bash + + - name: Sign macOS App + uses: lando/code-sign-action@v3 + id: sign-app + with: + file: ${{ steps.validate-app.outputs.app_path }} + certificate-data: ${{ secrets.MACOS_CERTIFICATE }} + certificate-password: ${{ secrets.MACOS_CERTIFICATE_PWD }} + certificate-id: ${{ secrets.APPLE_TEAM_ID }} + options: --force --options runtime --deep --timestamp --entitlements ./LuckyRobots.entitlements + + - name: Notarize macOS App + run: | + # Create a temporary file for notarization + APP_PATH="${{ steps.validate-app.outputs.app_path }}" + NOTARIZE_APP_PATH="./LuckyRobots-notarize.zip" + ditto -c -k --keepParent "$APP_PATH" "$NOTARIZE_APP_PATH" + + API_KEY_FILE="${{ steps.setup-signing.outputs.api_key_file }}" + + # Submit for notarization using API key + echo "Submitting for notarization with API key..." + xcrun notarytool submit "$NOTARIZE_APP_PATH" --key "$API_KEY_FILE" --key-id "${{ secrets.NOTARY_API_KEY_ID }}" --issuer "${{ secrets.NOTARY_API_KEY_ISSUER_ID }}" --wait + + # Staple the ticket to the application + xcrun stapler staple "$APP_PATH" + + # Clean up the API key file + rm -f "$API_KEY_FILE" + rm -f "$NOTARIZE_APP_PATH" + shell: bash + + - name: Package macOS App + run: | + # Package the signed and notarized app + APP_PATH="${{ steps.validate-app.outputs.app_path }}" + APP_NAME=$(basename "$APP_PATH") + DIR_PATH=$(dirname "$APP_PATH") + + # Create test output directory + mkdir -p TestSignedApps + + echo "Creating test package..." + (cd "$DIR_PATH" && zip -r "../../TestSignedApps/Test-$APP_NAME.zip" "$APP_NAME") + echo "Created test package: TestSignedApps/Test-$APP_NAME.zip" + + echo "Test packaged apps:" + ls -la TestSignedApps/ + shell: bash + + - name: Upload Test Signed App + uses: actions/upload-artifact@v3 + if: success() + with: + name: TestSigned-macOS-App + path: TestSignedApps/Test-*.zip + retention-days: 7 \ No newline at end of file -- 2.47.2 From 125611cdd1b5afd75138a0ea518c8ac54d0e2eba Mon Sep 17 00:00:00 2001 From: Ozgur Ersoy Date: Sun, 13 Apr 2025 14:32:12 +0200 Subject: [PATCH 017/109] fix(workflows): simplify macOS signing workflow by removing previous build input options and using a fixed artifact URL --- .gitea/workflows/test-signing.yml | 62 ++++++------------------------- 1 file changed, 12 insertions(+), 50 deletions(-) diff --git a/.gitea/workflows/test-signing.yml b/.gitea/workflows/test-signing.yml index 43cb2f13..7bd52f63 100644 --- a/.gitea/workflows/test-signing.yml +++ b/.gitea/workflows/test-signing.yml @@ -1,21 +1,9 @@ name: Test macOS Signing on: - workflow_dispatch: - inputs: - use_previous_build: - description: 'Use a previous successful build artifact instead of local app path' - required: true - type: boolean - default: false - app_path: - description: 'Path to the app bundle to sign (if not using artifact)' - required: false - default: 'Builds/Mac/LuckyRobots.app' - artifact_run_id: - description: 'Run ID of the workflow that produced the artifact to use (if using artifact)' - required: false - default: '' + # push: + branches: [ozgur/build] + workflow_dispatch: # Manual trigger de mรผmkรผn olsun jobs: test-signing: @@ -27,37 +15,21 @@ jobs: lfs: true fetch-depth: 0 - - name: Download Previous Build - if: ${{ github.event.inputs.use_previous_build == 'true' }} + - name: Download Artifact run: | # Create directories mkdir -p Builds/Mac - # Download artifact (using GitHub API or direct download) - echo "Downloading previous build artifact..." + # Download specific artifact + echo "Downloading build artifact..." - # If artifact_run_id is provided, use it - if [[ -n "${{ github.event.inputs.artifact_run_id }}" ]]; then - RUN_ID="${{ github.event.inputs.artifact_run_id }}" - else - # Get latest successful build run ID - echo "No specific run ID provided, finding latest successful build..." - - # You'll need to have proper authentication to access the API - # This is simplified, you might need to adjust based on your setup - RUN_ID=$(curl -s "https://luckyrobots.com/api/v1/repos/luckyrobots/luckyworld/actions/runs?status=success&event=push" | grep -o '"id":[0-9]*' | head -1 | cut -d':' -f2) - - if [[ -z "$RUN_ID" ]]; then - echo "Could not find a successful run ID. Please specify one manually." - exit 1 - fi - fi + # Sabit artifact URL kullan + ARTIFACT_URL="https://luckyrobots.com/LuckyRobots/LuckyWorld/actions/runs/84/artifacts/LuckyRobots-macOS" - echo "Using run ID: $RUN_ID" + echo "Using artifact URL: $ARTIFACT_URL" - # Download artifact using your Gitea API - # This is a simplified example - adjust as needed for your actual API - curl -L "https://luckyrobots.com/luckyrobots/luckyworld/actions/runs/$RUN_ID/artifacts/LuckyRobots-macOS" -o build.zip + # Download the artifact + curl -L "$ARTIFACT_URL" -o build.zip # Extract to Builds directory unzip -o build.zip -d Builds/Mac/ @@ -77,20 +49,10 @@ jobs: - name: Validate App Path id: validate-app run: | - if [[ "${{ github.event.inputs.use_previous_build }}" == "true" ]]; then - APP_PATH="$app_path" - else - APP_PATH="${{ github.event.inputs.app_path }}" - fi + APP_PATH="$app_path" if [ ! -d "$APP_PATH" ]; then echo "Error: Application path does not exist: $APP_PATH" - echo "You can download a previous successful build artifact or specify a different path" - - # List available directories to help user - echo "Available directories in workspace:" - find . -type d -maxdepth 3 | grep -v "node_modules\|.git" - exit 1 fi -- 2.47.2 From 83011e5ad781c5f045ef05a84b14e95132ad7a28 Mon Sep 17 00:00:00 2001 From: Ozgur Ersoy Date: Sun, 13 Apr 2025 14:33:59 +0200 Subject: [PATCH 018/109] fix(workflows): enable push trigger for macOS signing workflow --- .gitea/workflows/test-signing.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitea/workflows/test-signing.yml b/.gitea/workflows/test-signing.yml index 7bd52f63..3a3d48cb 100644 --- a/.gitea/workflows/test-signing.yml +++ b/.gitea/workflows/test-signing.yml @@ -1,7 +1,7 @@ name: Test macOS Signing on: - # push: + push: branches: [ozgur/build] workflow_dispatch: # Manual trigger de mรผmkรผn olsun -- 2.47.2 From aef65a94bb3bd352447face119e4d7b69c86ebaa Mon Sep 17 00:00:00 2001 From: Ozgur Ersoy Date: Sun, 13 Apr 2025 14:56:02 +0200 Subject: [PATCH 019/109] fix(workflows): improve macOS signing workflow by adding nested artifact extraction and enhanced error handling --- .gitea/workflows/test-signing.yml | 34 ++++++++++++++++++++++--------- 1 file changed, 24 insertions(+), 10 deletions(-) diff --git a/.gitea/workflows/test-signing.yml b/.gitea/workflows/test-signing.yml index 3a3d48cb..3d6e64df 100644 --- a/.gitea/workflows/test-signing.yml +++ b/.gitea/workflows/test-signing.yml @@ -3,17 +3,17 @@ name: Test macOS Signing on: push: branches: [ozgur/build] - workflow_dispatch: # Manual trigger de mรผmkรผn olsun + workflow_dispatch: # Manual trigger is also available jobs: test-signing: runs-on: macos steps: - - name: Checkout repository - uses: actions/checkout@v3 - with: - lfs: true - fetch-depth: 0 + # - name: Checkout repository + # uses: actions/checkout@v3 + # with: + # lfs: true + # fetch-depth: 0 - name: Download Artifact run: | @@ -31,18 +31,32 @@ jobs: # Download the artifact curl -L "$ARTIFACT_URL" -o build.zip - # Extract to Builds directory - unzip -o build.zip -d Builds/Mac/ + # First unzip - Outer artifact zip file + unzip -o build.zip -d temp_extract/ + + # Second unzip - Inner macOS app package + echo "Extracting inner zip file..." + INNER_ZIP=$(find temp_extract -name "*.zip" | head -1) + + if [[ -z "$INNER_ZIP" ]]; then + echo "Could not find inner zip in artifact" + exit 1 + fi + + echo "Found inner zip: $INNER_ZIP" + unzip -o "$INNER_ZIP" -d Builds/Mac/ # Find extracted app bundle APP_PATH=$(find Builds/Mac -type d -name "*.app" | head -1) if [[ -z "$APP_PATH" ]]; then - echo "Could not find app bundle in downloaded artifact" + echo "Could not find app bundle in extracted files" + echo "Directory contents:" + ls -la Builds/Mac/ exit 1 fi - echo "Downloaded app bundle: $APP_PATH" + echo "Found app bundle: $APP_PATH" echo "app_path=$APP_PATH" >> $GITHUB_ENV shell: bash -- 2.47.2 From 7e3c22f002773536cbd47988dec22e0fcb151b2f Mon Sep 17 00:00:00 2001 From: Ozgur Ersoy Date: Sun, 13 Apr 2025 15:07:47 +0200 Subject: [PATCH 020/109] fix(workflows): enhance macOS signing workflow by improving artifact extraction and validation steps --- .gitea/workflows/test-signing.yml | 41 ++++++++++++++++++++----------- 1 file changed, 27 insertions(+), 14 deletions(-) diff --git a/.gitea/workflows/test-signing.yml b/.gitea/workflows/test-signing.yml index 3d6e64df..c7a62e20 100644 --- a/.gitea/workflows/test-signing.yml +++ b/.gitea/workflows/test-signing.yml @@ -9,13 +9,14 @@ jobs: test-signing: runs-on: macos steps: - # - name: Checkout repository - # uses: actions/checkout@v3 - # with: - # lfs: true - # fetch-depth: 0 + - name: Checkout repository + uses: actions/checkout@v3 + with: + lfs: true + fetch-depth: 0 - - name: Download Artifact + - name: Download and Extract Artifact + id: extract-artifact run: | # Create directories mkdir -p Builds/Mac @@ -23,7 +24,7 @@ jobs: # Download specific artifact echo "Downloading build artifact..." - # Sabit artifact URL kullan + # Use fixed artifact URL ARTIFACT_URL="https://luckyrobots.com/LuckyRobots/LuckyWorld/actions/runs/84/artifacts/LuckyRobots-macOS" echo "Using artifact URL: $ARTIFACT_URL" @@ -32,8 +33,13 @@ jobs: curl -L "$ARTIFACT_URL" -o build.zip # First unzip - Outer artifact zip file + echo "Extracting outer zip file..." unzip -o build.zip -d temp_extract/ + # List the contents of temp_extract + echo "Contents of temp_extract:" + ls -la temp_extract/ + # Second unzip - Inner macOS app package echo "Extracting inner zip file..." INNER_ZIP=$(find temp_extract -name "*.zip" | head -1) @@ -46,24 +52,29 @@ jobs: echo "Found inner zip: $INNER_ZIP" unzip -o "$INNER_ZIP" -d Builds/Mac/ - # Find extracted app bundle - APP_PATH=$(find Builds/Mac -type d -name "*.app" | head -1) + # Recursive search for .app directory + echo "Searching for .app bundle..." + APP_PATH=$(find Builds -type d -name "*.app" -print 2>/dev/null | head -1) if [[ -z "$APP_PATH" ]]; then echo "Could not find app bundle in extracted files" - echo "Directory contents:" - ls -la Builds/Mac/ + echo "Contents of Builds directory:" + find Builds -type d | sort + echo "All directories in workspace:" + find . -type d -maxdepth 4 | grep -v "node_modules\|.git" | sort exit 1 fi echo "Found app bundle: $APP_PATH" - echo "app_path=$APP_PATH" >> $GITHUB_ENV + echo "app_path=$APP_PATH" >> $GITHUB_OUTPUT shell: bash - name: Validate App Path id: validate-app run: | - APP_PATH="$app_path" + APP_PATH="${{ steps.extract-artifact.outputs.app_path }}" + + echo "Validating path: $APP_PATH" if [ ! -d "$APP_PATH" ]; then echo "Error: Application path does not exist: $APP_PATH" @@ -71,6 +82,8 @@ jobs: fi echo "Will sign and notarize: $APP_PATH" + echo "Contents of app bundle:" + ls -la "$APP_PATH" echo "app_path=$APP_PATH" >> $GITHUB_OUTPUT shell: bash @@ -91,7 +104,7 @@ jobs: file: ${{ steps.validate-app.outputs.app_path }} certificate-data: ${{ secrets.MACOS_CERTIFICATE }} certificate-password: ${{ secrets.MACOS_CERTIFICATE_PWD }} - certificate-id: ${{ secrets.APPLE_TEAM_ID }} + apple-team-id: "${{ secrets.APPLE_TEAM_ID }}" options: --force --options runtime --deep --timestamp --entitlements ./LuckyRobots.entitlements - name: Notarize macOS App -- 2.47.2 From 4daf6d11765eb4c26ebb479f1444f837174f7751 Mon Sep 17 00:00:00 2001 From: Ozgur Ersoy Date: Sun, 13 Apr 2025 15:31:26 +0200 Subject: [PATCH 021/109] fix(workflows): add entitlements file creation step to macOS signing workflow --- .gitea/workflows/test-signing.yml | 32 ++++++++++++++++++++++++++----- 1 file changed, 27 insertions(+), 5 deletions(-) diff --git a/.gitea/workflows/test-signing.yml b/.gitea/workflows/test-signing.yml index c7a62e20..3852b4be 100644 --- a/.gitea/workflows/test-signing.yml +++ b/.gitea/workflows/test-signing.yml @@ -9,11 +9,33 @@ jobs: test-signing: runs-on: macos steps: - - name: Checkout repository - uses: actions/checkout@v3 - with: - lfs: true - fetch-depth: 0 + - name: Create Entitlements File + run: | + # Create entitlements file inline + cat > LuckyRobots.entitlements << EOF + + + + + com.apple.security.cs.allow-jit + + com.apple.security.cs.allow-unsigned-executable-memory + + com.apple.security.cs.disable-library-validation + + com.apple.security.cs.allow-dyld-environment-variables + + com.apple.security.device.audio-input + + com.apple.security.device.camera + + + + EOF + + echo "Created entitlements file:" + cat LuckyRobots.entitlements + shell: bash - name: Download and Extract Artifact id: extract-artifact -- 2.47.2 From 638fc977f42c6b7f9bd18b81ed446877e1f99458 Mon Sep 17 00:00:00 2001 From: Ozgur Ersoy Date: Sun, 13 Apr 2025 15:47:48 +0200 Subject: [PATCH 022/109] fix(workflows): enhance macOS signing workflow with improved artifact handling and absolute path management --- .gitea/workflows/test-signing.yml | 118 +++++++++++++++++++----------- 1 file changed, 75 insertions(+), 43 deletions(-) diff --git a/.gitea/workflows/test-signing.yml b/.gitea/workflows/test-signing.yml index 3852b4be..8c20e2fe 100644 --- a/.gitea/workflows/test-signing.yml +++ b/.gitea/workflows/test-signing.yml @@ -35,13 +35,22 @@ jobs: echo "Created entitlements file:" cat LuckyRobots.entitlements + + # Move entitlements to home directory to ensure consistent access + cp LuckyRobots.entitlements ~/LuckyRobots.entitlements shell: bash - name: Download and Extract Artifact id: extract-artifact run: | + # Working with absolute paths to eliminate path inconsistencies + WORKSPACE_DIR="$(pwd)" + BUILDS_DIR="$WORKSPACE_DIR/Builds" + EXTRACT_DIR="$WORKSPACE_DIR/temp_extract" + # Create directories - mkdir -p Builds/Mac + mkdir -p "$BUILDS_DIR/Mac" + mkdir -p "$EXTRACT_DIR" # Download specific artifact echo "Downloading build artifact..." @@ -50,45 +59,69 @@ jobs: ARTIFACT_URL="https://luckyrobots.com/LuckyRobots/LuckyWorld/actions/runs/84/artifacts/LuckyRobots-macOS" echo "Using artifact URL: $ARTIFACT_URL" + BUILD_ZIP="$WORKSPACE_DIR/build.zip" # Download the artifact - curl -L "$ARTIFACT_URL" -o build.zip + curl -L "$ARTIFACT_URL" -o "$BUILD_ZIP" # First unzip - Outer artifact zip file echo "Extracting outer zip file..." - unzip -o build.zip -d temp_extract/ + unzip -o "$BUILD_ZIP" -d "$EXTRACT_DIR" # List the contents of temp_extract echo "Contents of temp_extract:" - ls -la temp_extract/ + ls -la "$EXTRACT_DIR" - # Second unzip - Inner macOS app package - echo "Extracting inner zip file..." - INNER_ZIP=$(find temp_extract -name "*.zip" | head -1) + # Handle case where the artifact might have different structure + # Try to find any zip files recursively + echo "Searching for zip files in extract directory..." + ZIP_FILES=$(find "$EXTRACT_DIR" -name "*.zip" -type f) + echo "Found ZIP files: $ZIP_FILES" - if [[ -z "$INNER_ZIP" ]]; then - echo "Could not find inner zip in artifact" - exit 1 + # Create target directory for Mac app + TARGET_DIR="$BUILDS_DIR/Mac" + mkdir -p "$TARGET_DIR" + + # Extract all found zip files + for ZIP_FILE in $ZIP_FILES; do + echo "Extracting: $ZIP_FILE to $TARGET_DIR" + unzip -o "$ZIP_FILE" -d "$TARGET_DIR" + done + + # Look for LuckyWorld-Mac-Shipping.app specifically + if [ -d "$TARGET_DIR/LuckyWorld-Mac-Shipping.app" ]; then + APP_PATH="$TARGET_DIR/LuckyWorld-Mac-Shipping.app" + echo "Found specific app: $APP_PATH" + else + # Try to find any .app bundle recursively + echo "Searching for .app bundles in all directories..." + APP_PATH=$(find "$BUILDS_DIR" -name "*.app" -type d | head -1) + + if [ -z "$APP_PATH" ]; then + echo "Could not find any .app bundle. Looking in other directories..." + APP_PATH=$(find "$WORKSPACE_DIR" -name "*.app" -type d | head -1) + fi fi - echo "Found inner zip: $INNER_ZIP" - unzip -o "$INNER_ZIP" -d Builds/Mac/ - - # Recursive search for .app directory - echo "Searching for .app bundle..." - APP_PATH=$(find Builds -type d -name "*.app" -print 2>/dev/null | head -1) - - if [[ -z "$APP_PATH" ]]; then - echo "Could not find app bundle in extracted files" + if [ -z "$APP_PATH" ]; then + echo "ERROR: Could not find any .app bundle" echo "Contents of Builds directory:" - find Builds -type d | sort - echo "All directories in workspace:" - find . -type d -maxdepth 4 | grep -v "node_modules\|.git" | sort + find "$BUILDS_DIR" -type d | sort + echo "Contents of extracted files:" + find "$EXTRACT_DIR" -type f | sort exit 1 fi - echo "Found app bundle: $APP_PATH" - echo "app_path=$APP_PATH" >> $GITHUB_OUTPUT + echo "Found app bundle at: $APP_PATH" + # Make a local copy to ensure access + LOCAL_APP="$WORKSPACE_DIR/LuckyWorld.app" + echo "Creating accessible copy at: $LOCAL_APP" + + # Remove if exists + rm -rf "$LOCAL_APP" + cp -R "$APP_PATH" "$LOCAL_APP" + + echo "app_path=$LOCAL_APP" >> $GITHUB_OUTPUT shell: bash - name: Validate App Path @@ -103,22 +136,18 @@ jobs: exit 1 fi + # Ensure the path is absolute + if [[ "$APP_PATH" != /* ]]; then + APP_PATH="$(pwd)/$APP_PATH" + echo "Converted to absolute path: $APP_PATH" + fi + echo "Will sign and notarize: $APP_PATH" echo "Contents of app bundle:" ls -la "$APP_PATH" echo "app_path=$APP_PATH" >> $GITHUB_OUTPUT shell: bash - - name: Setup for Signing - id: setup-signing - env: - API_KEY_PATH: ${{ secrets.NOTARY_API_KEY_PATH }} - run: | - # Decode the API key from Base64 secret - echo "$API_KEY_PATH" | base64 --decode > api_key.p8 - echo "api_key_file=$(pwd)/api_key.p8" >> $GITHUB_OUTPUT - shell: bash - - name: Sign macOS App uses: lando/code-sign-action@v3 id: sign-app @@ -127,7 +156,7 @@ jobs: certificate-data: ${{ secrets.MACOS_CERTIFICATE }} certificate-password: ${{ secrets.MACOS_CERTIFICATE_PWD }} apple-team-id: "${{ secrets.APPLE_TEAM_ID }}" - options: --force --options runtime --deep --timestamp --entitlements ./LuckyRobots.entitlements + options: --force --options runtime --deep --timestamp --entitlements ~/LuckyRobots.entitlements - name: Notarize macOS App run: | @@ -136,17 +165,19 @@ jobs: NOTARIZE_APP_PATH="./LuckyRobots-notarize.zip" ditto -c -k --keepParent "$APP_PATH" "$NOTARIZE_APP_PATH" - API_KEY_FILE="${{ steps.setup-signing.outputs.api_key_file }}" + # Set up API key + API_KEY_PATH="$(pwd)/api_key.p8" + echo "${{ secrets.NOTARY_API_KEY_PATH }}" | base64 --decode > "$API_KEY_PATH" # Submit for notarization using API key echo "Submitting for notarization with API key..." - xcrun notarytool submit "$NOTARIZE_APP_PATH" --key "$API_KEY_FILE" --key-id "${{ secrets.NOTARY_API_KEY_ID }}" --issuer "${{ secrets.NOTARY_API_KEY_ISSUER_ID }}" --wait + xcrun notarytool submit "$NOTARIZE_APP_PATH" --key "$API_KEY_PATH" --key-id "${{ secrets.NOTARY_API_KEY_ID }}" --issuer "${{ secrets.NOTARY_API_KEY_ISSUER_ID }}" --wait # Staple the ticket to the application xcrun stapler staple "$APP_PATH" # Clean up the API key file - rm -f "$API_KEY_FILE" + rm -f "$API_KEY_PATH" rm -f "$NOTARIZE_APP_PATH" shell: bash @@ -155,17 +186,18 @@ jobs: # Package the signed and notarized app APP_PATH="${{ steps.validate-app.outputs.app_path }}" APP_NAME=$(basename "$APP_PATH") - DIR_PATH=$(dirname "$APP_PATH") + WORKSPACE_DIR="$(pwd)" + OUTPUT_DIR="$WORKSPACE_DIR/TestSignedApps" # Create test output directory - mkdir -p TestSignedApps + mkdir -p "$OUTPUT_DIR" echo "Creating test package..." - (cd "$DIR_PATH" && zip -r "../../TestSignedApps/Test-$APP_NAME.zip" "$APP_NAME") - echo "Created test package: TestSignedApps/Test-$APP_NAME.zip" + ditto -c -k --keepParent "$APP_PATH" "$OUTPUT_DIR/Test-$APP_NAME.zip" + echo "Created test package: $OUTPUT_DIR/Test-$APP_NAME.zip" echo "Test packaged apps:" - ls -la TestSignedApps/ + ls -la "$OUTPUT_DIR" shell: bash - name: Upload Test Signed App -- 2.47.2 From 4400b47873ec04b88a9f993431c246eb503d307d Mon Sep 17 00:00:00 2001 From: Ozgur Ersoy Date: Sun, 13 Apr 2025 16:08:47 +0200 Subject: [PATCH 023/109] fix(workflows): enhance macOS signing workflow with keychain management and cleanup steps --- .gitea/workflows/test-signing.yml | 132 +++++++++++++++++++----------- 1 file changed, 84 insertions(+), 48 deletions(-) diff --git a/.gitea/workflows/test-signing.yml b/.gitea/workflows/test-signing.yml index 8c20e2fe..6fb3f1d8 100644 --- a/.gitea/workflows/test-signing.yml +++ b/.gitea/workflows/test-signing.yml @@ -35,9 +35,6 @@ jobs: echo "Created entitlements file:" cat LuckyRobots.entitlements - - # Move entitlements to home directory to ensure consistent access - cp LuckyRobots.entitlements ~/LuckyRobots.entitlements shell: bash - name: Download and Extract Artifact @@ -113,61 +110,87 @@ jobs: fi echo "Found app bundle at: $APP_PATH" - # Make a local copy to ensure access - LOCAL_APP="$WORKSPACE_DIR/LuckyWorld.app" - echo "Creating accessible copy at: $LOCAL_APP" - - # Remove if exists - rm -rf "$LOCAL_APP" - cp -R "$APP_PATH" "$LOCAL_APP" - - echo "app_path=$LOCAL_APP" >> $GITHUB_OUTPUT - shell: bash - - - name: Validate App Path - id: validate-app - run: | - APP_PATH="${{ steps.extract-artifact.outputs.app_path }}" - - echo "Validating path: $APP_PATH" - - if [ ! -d "$APP_PATH" ]; then - echo "Error: Application path does not exist: $APP_PATH" - exit 1 - fi - - # Ensure the path is absolute - if [[ "$APP_PATH" != /* ]]; then - APP_PATH="$(pwd)/$APP_PATH" - echo "Converted to absolute path: $APP_PATH" - fi - - echo "Will sign and notarize: $APP_PATH" - echo "Contents of app bundle:" - ls -la "$APP_PATH" echo "app_path=$APP_PATH" >> $GITHUB_OUTPUT shell: bash + - name: Setup for Signing + id: setup-signing + env: + APPLE_CERTIFICATE_BASE64: ${{ secrets.MACOS_CERTIFICATE }} + APPLE_CERTIFICATE_PASSWORD: ${{ secrets.MACOS_CERTIFICATE_PWD }} + run: | + # Decode the base64 certificate + echo "$APPLE_CERTIFICATE_BASE64" | base64 --decode > certificate.p12 + + # Create keychain and import certificate + KEYCHAIN_PATH="signing-keychain.keychain-db" + KEYCHAIN_PASSWORD="temporary" + + # Create custom 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" + + # Download Apple root certificates + echo "Downloading Apple Developer certificates..." + curl -s -o AppleWWDRCAG3.cer https://www.apple.com/certificateauthority/AppleWWDRCAG3.cer + curl -s -o DeveloperIDG2.cer https://www.apple.com/certificateauthority/DeveloperIDG2.cer + + # Import all certificates to our custom keychain + security import AppleWWDRCAG3.cer -k "$KEYCHAIN_PATH" -T /usr/bin/codesign -f der -A + security import DeveloperIDG2.cer -k "$KEYCHAIN_PATH" -T /usr/bin/codesign -f der -A + security import certificate.p12 -P "$APPLE_CERTIFICATE_PASSWORD" -A -t cert -f pkcs12 -k "$KEYCHAIN_PATH" + + # Set keychain for signing + security list-keychain -d user -s "$KEYCHAIN_PATH" + security default-keychain -s "$KEYCHAIN_PATH" + + # Always trust our certificates + security set-key-partition-list -S apple-tool:,apple: -s -k "$KEYCHAIN_PASSWORD" "$KEYCHAIN_PATH" + + # Setup API key + echo "${{ secrets.NOTARY_API_KEY_PATH }}" | base64 --decode > api_key.p8 + echo "keychain_path=$KEYCHAIN_PATH" >> $GITHUB_OUTPUT + echo "keychain_password=$KEYCHAIN_PASSWORD" >> $GITHUB_OUTPUT + echo "api_key_path=$(pwd)/api_key.p8" >> $GITHUB_OUTPUT + shell: bash + - name: Sign macOS App - uses: lando/code-sign-action@v3 id: sign-app - with: - file: ${{ steps.validate-app.outputs.app_path }} - certificate-data: ${{ secrets.MACOS_CERTIFICATE }} - certificate-password: ${{ secrets.MACOS_CERTIFICATE_PWD }} - apple-team-id: "${{ secrets.APPLE_TEAM_ID }}" - options: --force --options runtime --deep --timestamp --entitlements ~/LuckyRobots.entitlements + env: + APPLE_TEAM_ID: ${{ secrets.APPLE_TEAM_ID }} + run: | + APP_PATH="${{ steps.extract-artifact.outputs.app_path }}" + + echo "Signing app bundle: $APP_PATH" + + # First, handle problematic libraries separately + find "$APP_PATH" -name "*.dylib" | while read DYLIB; do + echo "Signing library: $DYLIB" + codesign --force --options runtime --timestamp --sign "Developer ID Application: $APPLE_TEAM_ID" "$DYLIB" + done + + # Now sign the application itself + echo "Signing main application bundle..." + /usr/bin/codesign --force --options runtime --deep --timestamp --sign "Developer ID Application: $APPLE_TEAM_ID" --entitlements ./LuckyRobots.entitlements "$APP_PATH" + + # Verify signature + echo "Verifying signature..." + codesign --verify --verbose "$APP_PATH" + + echo "App signing completed successfully" + echo "app_path=$APP_PATH" >> $GITHUB_OUTPUT + shell: bash - name: Notarize macOS App run: | # Create a temporary file for notarization - APP_PATH="${{ steps.validate-app.outputs.app_path }}" + APP_PATH="${{ steps.sign-app.outputs.app_path }}" NOTARIZE_APP_PATH="./LuckyRobots-notarize.zip" ditto -c -k --keepParent "$APP_PATH" "$NOTARIZE_APP_PATH" - # Set up API key - API_KEY_PATH="$(pwd)/api_key.p8" - echo "${{ secrets.NOTARY_API_KEY_PATH }}" | base64 --decode > "$API_KEY_PATH" + # Get API key path from previous step + API_KEY_PATH="${{ steps.setup-signing.outputs.api_key_path }}" # Submit for notarization using API key echo "Submitting for notarization with API key..." @@ -184,7 +207,7 @@ jobs: - name: Package macOS App run: | # Package the signed and notarized app - APP_PATH="${{ steps.validate-app.outputs.app_path }}" + APP_PATH="${{ steps.sign-app.outputs.app_path }}" APP_NAME=$(basename "$APP_PATH") WORKSPACE_DIR="$(pwd)" OUTPUT_DIR="$WORKSPACE_DIR/TestSignedApps" @@ -206,4 +229,17 @@ jobs: with: name: TestSigned-macOS-App path: TestSignedApps/Test-*.zip - retention-days: 7 \ No newline at end of file + retention-days: 7 + + - name: Cleanup + if: always() + run: | + # Clean up keychain + KEYCHAIN_PATH="${{ steps.setup-signing.outputs.keychain_path }}" + if [ -n "$KEYCHAIN_PATH" ]; then + security delete-keychain "$KEYCHAIN_PATH" || true + fi + + # Clean up temp files + rm -f certificate.p12 AppleWWDRCAG3.cer DeveloperIDG2.cer || true + shell: bash \ No newline at end of file -- 2.47.2 From 6dbc9f3ee385bf9220bdddf6f2d0d488b0dae0e2 Mon Sep 17 00:00:00 2001 From: Ozgur Ersoy Date: Sun, 13 Apr 2025 16:13:52 +0200 Subject: [PATCH 024/109] fix(workflows): enable push trigger for build workflow and disable it for test signing workflow --- .gitea/workflows/build.yml | 4 ++-- .gitea/workflows/test-signing.yml | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.gitea/workflows/build.yml b/.gitea/workflows/build.yml index 28027bfd..12a13ab2 100644 --- a/.gitea/workflows/build.yml +++ b/.gitea/workflows/build.yml @@ -2,8 +2,8 @@ name: Unreal Engine Build on: workflow_dispatch: - # push: - # branches: [ozgur/build] + push: + branches: [ozgur/build] jobs: windows-build: diff --git a/.gitea/workflows/test-signing.yml b/.gitea/workflows/test-signing.yml index 6fb3f1d8..2ed77aae 100644 --- a/.gitea/workflows/test-signing.yml +++ b/.gitea/workflows/test-signing.yml @@ -1,8 +1,8 @@ name: Test macOS Signing on: - push: - branches: [ozgur/build] + # push: + # branches: [ozgur/build] workflow_dispatch: # Manual trigger is also available jobs: -- 2.47.2 From 7769dfcea29a12c31611f235aa742ab059b149ab Mon Sep 17 00:00:00 2001 From: Ozgur Ersoy Date: Sun, 13 Apr 2025 16:48:52 +0200 Subject: [PATCH 025/109] fix(workflows): disable push trigger for build workflow and remove test signing workflow --- .gitea/workflows/build.yml | 4 +- .gitea/workflows/test-macos-build.yml | 128 ++++++++++++++ .gitea/workflows/test-signing.yml | 245 -------------------------- 3 files changed, 130 insertions(+), 247 deletions(-) create mode 100644 .gitea/workflows/test-macos-build.yml delete mode 100644 .gitea/workflows/test-signing.yml diff --git a/.gitea/workflows/build.yml b/.gitea/workflows/build.yml index 12a13ab2..28027bfd 100644 --- a/.gitea/workflows/build.yml +++ b/.gitea/workflows/build.yml @@ -2,8 +2,8 @@ name: Unreal Engine Build on: workflow_dispatch: - push: - branches: [ozgur/build] + # push: + # branches: [ozgur/build] jobs: windows-build: diff --git a/.gitea/workflows/test-macos-build.yml b/.gitea/workflows/test-macos-build.yml new file mode 100644 index 00000000..e3cb4930 --- /dev/null +++ b/.gitea/workflows/test-macos-build.yml @@ -0,0 +1,128 @@ +name: Test macOS Build Action + +on: + workflow_dispatch: # Manual trigger only for testing + push: + branches: [ozgur/build] +jobs: + test-macos-build: + runs-on: macos + steps: + - name: Checkout repository + uses: actions/checkout@v3 + with: + lfs: true + fetch-depth: 0 + + # Step 1: Setup environment + - name: Setup environment + run: | + # Use the correct path where Unreal Engine is installed + UE_PATH="/Users/Shared/Epic Games/UE_5.5" + + if [ ! -d "$UE_PATH" ]; then + echo "Error: Unreal Engine is not installed in the expected location" + echo "Please ensure Unreal Engine is installed at $UE_PATH" + exit 1 + fi + + # Create directories for builds + mkdir -p Builds/Mac + mkdir -p PackagedReleases + + echo "Using Unreal Engine 5.5" + shell: bash + + # Step 2: Build for macOS + - name: Build for macOS + run: | + chmod +x ./scripts/mac_build.sh + ./scripts/mac_build.sh + shell: bash + + # Step 3: Setup for Signing + - name: Setup for Signing + id: setup-signing + env: + API_KEY_PATH: ${{ secrets.NOTARY_API_KEY_PATH }} + run: | + # Create output directory + mkdir -p PackagedReleases + + # Decode the API key from Base64 secret + echo "$API_KEY_PATH" | base64 --decode > api_key.p8 + echo "api_key_file=$(pwd)/api_key.p8" >> $GITEA_OUTPUT + + # Find app bundle + APP_PATH=$(find Builds -type d -name "*.app" | head -1) + + if [ -z "$APP_PATH" ]; then + # Look for a directory that might be a bundle but not named .app + APP_PATH=$(find Builds -mindepth 1 -maxdepth 1 -type d | head -1) + if [ -z "$APP_PATH" ]; then + echo "No build directory found, cannot continue" + exit 1 + fi + fi + + echo "Found app path: $APP_PATH" + echo "app_path=$APP_PATH" >> $GITEA_OUTPUT + shell: bash + + # Step 4: Sign macOS App + - name: Sign macOS App + uses: lando/code-sign-action@v3 + id: sign-app + with: + file: ${{ steps.setup-signing.outputs.app_path }} + certificate-data: ${{ secrets.MACOS_CERTIFICATE }} + certificate-password: ${{ secrets.MACOS_CERTIFICATE_PWD }} + certificate-id: ${{ secrets.APPLE_TEAM_ID }} + options: --force --options runtime --deep --timestamp --entitlements ./LuckyRobots.entitlements + + # Step 5: Notarize macOS App + - name: Notarize macOS App + run: | + # Create a temporary file for notarization + APP_PATH="${{ steps.setup-signing.outputs.app_path }}" + NOTARIZE_APP_PATH="./LuckyRobots-notarize.zip" + ditto -c -k --keepParent "$APP_PATH" "$NOTARIZE_APP_PATH" + + API_KEY_FILE="${{ steps.setup-signing.outputs.api_key_file }}" + + # Submit for notarization using API key + echo "Submitting for notarization with API key..." + xcrun notarytool submit "$NOTARIZE_APP_PATH" --key "$API_KEY_FILE" --key-id "${{ secrets.NOTARY_API_KEY_ID }}" --issuer "${{ secrets.NOTARY_API_KEY_ISSUER_ID }}" --wait + + # Staple the ticket to the application + xcrun stapler staple "$APP_PATH" + + # Clean up the API key file + rm -f "$API_KEY_FILE" + rm -f "$NOTARIZE_APP_PATH" + shell: bash + + # Step 6: Package macOS App + - name: Package macOS App + run: | + # Package the signed and notarized app + APP_PATH="${{ steps.setup-signing.outputs.app_path }}" + APP_NAME=$(basename "$APP_PATH") + DIR_PATH=$(dirname "$APP_PATH") + + echo "Creating final package..." + (cd "$DIR_PATH" && zip -r "../../PackagedReleases/LuckyRobots-macOS.zip" "$APP_NAME") + echo "Created packaged release: PackagedReleases/LuckyRobots-macOS.zip" + + echo "Packaged releases:" + ls -la PackagedReleases/ + shell: bash + + # Step 7: Upload macOS Build Artifact + - name: Upload macOS Build Artifact + uses: actions/upload-artifact@v3 + if: success() + with: + name: LuckyRobots-macOS + path: PackagedReleases/LuckyRobots-macOS.zip + retention-days: 365 \ No newline at end of file diff --git a/.gitea/workflows/test-signing.yml b/.gitea/workflows/test-signing.yml deleted file mode 100644 index 2ed77aae..00000000 --- a/.gitea/workflows/test-signing.yml +++ /dev/null @@ -1,245 +0,0 @@ -name: Test macOS Signing - -on: - # push: - # branches: [ozgur/build] - workflow_dispatch: # Manual trigger is also available - -jobs: - test-signing: - runs-on: macos - steps: - - name: Create Entitlements File - run: | - # Create entitlements file inline - cat > LuckyRobots.entitlements << EOF - - - - - com.apple.security.cs.allow-jit - - com.apple.security.cs.allow-unsigned-executable-memory - - com.apple.security.cs.disable-library-validation - - com.apple.security.cs.allow-dyld-environment-variables - - com.apple.security.device.audio-input - - com.apple.security.device.camera - - - - EOF - - echo "Created entitlements file:" - cat LuckyRobots.entitlements - shell: bash - - - name: Download and Extract Artifact - id: extract-artifact - run: | - # Working with absolute paths to eliminate path inconsistencies - WORKSPACE_DIR="$(pwd)" - BUILDS_DIR="$WORKSPACE_DIR/Builds" - EXTRACT_DIR="$WORKSPACE_DIR/temp_extract" - - # Create directories - mkdir -p "$BUILDS_DIR/Mac" - mkdir -p "$EXTRACT_DIR" - - # Download specific artifact - echo "Downloading build artifact..." - - # Use fixed artifact URL - ARTIFACT_URL="https://luckyrobots.com/LuckyRobots/LuckyWorld/actions/runs/84/artifacts/LuckyRobots-macOS" - - echo "Using artifact URL: $ARTIFACT_URL" - BUILD_ZIP="$WORKSPACE_DIR/build.zip" - - # Download the artifact - curl -L "$ARTIFACT_URL" -o "$BUILD_ZIP" - - # First unzip - Outer artifact zip file - echo "Extracting outer zip file..." - unzip -o "$BUILD_ZIP" -d "$EXTRACT_DIR" - - # List the contents of temp_extract - echo "Contents of temp_extract:" - ls -la "$EXTRACT_DIR" - - # Handle case where the artifact might have different structure - # Try to find any zip files recursively - echo "Searching for zip files in extract directory..." - ZIP_FILES=$(find "$EXTRACT_DIR" -name "*.zip" -type f) - echo "Found ZIP files: $ZIP_FILES" - - # Create target directory for Mac app - TARGET_DIR="$BUILDS_DIR/Mac" - mkdir -p "$TARGET_DIR" - - # Extract all found zip files - for ZIP_FILE in $ZIP_FILES; do - echo "Extracting: $ZIP_FILE to $TARGET_DIR" - unzip -o "$ZIP_FILE" -d "$TARGET_DIR" - done - - # Look for LuckyWorld-Mac-Shipping.app specifically - if [ -d "$TARGET_DIR/LuckyWorld-Mac-Shipping.app" ]; then - APP_PATH="$TARGET_DIR/LuckyWorld-Mac-Shipping.app" - echo "Found specific app: $APP_PATH" - else - # Try to find any .app bundle recursively - echo "Searching for .app bundles in all directories..." - APP_PATH=$(find "$BUILDS_DIR" -name "*.app" -type d | head -1) - - if [ -z "$APP_PATH" ]; then - echo "Could not find any .app bundle. Looking in other directories..." - APP_PATH=$(find "$WORKSPACE_DIR" -name "*.app" -type d | head -1) - fi - fi - - if [ -z "$APP_PATH" ]; then - echo "ERROR: Could not find any .app bundle" - echo "Contents of Builds directory:" - find "$BUILDS_DIR" -type d | sort - echo "Contents of extracted files:" - find "$EXTRACT_DIR" -type f | sort - exit 1 - fi - - echo "Found app bundle at: $APP_PATH" - echo "app_path=$APP_PATH" >> $GITHUB_OUTPUT - shell: bash - - - name: Setup for Signing - id: setup-signing - env: - APPLE_CERTIFICATE_BASE64: ${{ secrets.MACOS_CERTIFICATE }} - APPLE_CERTIFICATE_PASSWORD: ${{ secrets.MACOS_CERTIFICATE_PWD }} - run: | - # Decode the base64 certificate - echo "$APPLE_CERTIFICATE_BASE64" | base64 --decode > certificate.p12 - - # Create keychain and import certificate - KEYCHAIN_PATH="signing-keychain.keychain-db" - KEYCHAIN_PASSWORD="temporary" - - # Create custom 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" - - # Download Apple root certificates - echo "Downloading Apple Developer certificates..." - curl -s -o AppleWWDRCAG3.cer https://www.apple.com/certificateauthority/AppleWWDRCAG3.cer - curl -s -o DeveloperIDG2.cer https://www.apple.com/certificateauthority/DeveloperIDG2.cer - - # Import all certificates to our custom keychain - security import AppleWWDRCAG3.cer -k "$KEYCHAIN_PATH" -T /usr/bin/codesign -f der -A - security import DeveloperIDG2.cer -k "$KEYCHAIN_PATH" -T /usr/bin/codesign -f der -A - security import certificate.p12 -P "$APPLE_CERTIFICATE_PASSWORD" -A -t cert -f pkcs12 -k "$KEYCHAIN_PATH" - - # Set keychain for signing - security list-keychain -d user -s "$KEYCHAIN_PATH" - security default-keychain -s "$KEYCHAIN_PATH" - - # Always trust our certificates - security set-key-partition-list -S apple-tool:,apple: -s -k "$KEYCHAIN_PASSWORD" "$KEYCHAIN_PATH" - - # Setup API key - echo "${{ secrets.NOTARY_API_KEY_PATH }}" | base64 --decode > api_key.p8 - echo "keychain_path=$KEYCHAIN_PATH" >> $GITHUB_OUTPUT - echo "keychain_password=$KEYCHAIN_PASSWORD" >> $GITHUB_OUTPUT - echo "api_key_path=$(pwd)/api_key.p8" >> $GITHUB_OUTPUT - shell: bash - - - name: Sign macOS App - id: sign-app - env: - APPLE_TEAM_ID: ${{ secrets.APPLE_TEAM_ID }} - run: | - APP_PATH="${{ steps.extract-artifact.outputs.app_path }}" - - echo "Signing app bundle: $APP_PATH" - - # First, handle problematic libraries separately - find "$APP_PATH" -name "*.dylib" | while read DYLIB; do - echo "Signing library: $DYLIB" - codesign --force --options runtime --timestamp --sign "Developer ID Application: $APPLE_TEAM_ID" "$DYLIB" - done - - # Now sign the application itself - echo "Signing main application bundle..." - /usr/bin/codesign --force --options runtime --deep --timestamp --sign "Developer ID Application: $APPLE_TEAM_ID" --entitlements ./LuckyRobots.entitlements "$APP_PATH" - - # Verify signature - echo "Verifying signature..." - codesign --verify --verbose "$APP_PATH" - - echo "App signing completed successfully" - echo "app_path=$APP_PATH" >> $GITHUB_OUTPUT - shell: bash - - - name: Notarize macOS App - run: | - # Create a temporary file for notarization - APP_PATH="${{ steps.sign-app.outputs.app_path }}" - NOTARIZE_APP_PATH="./LuckyRobots-notarize.zip" - ditto -c -k --keepParent "$APP_PATH" "$NOTARIZE_APP_PATH" - - # Get API key path from previous step - API_KEY_PATH="${{ steps.setup-signing.outputs.api_key_path }}" - - # Submit for notarization using API key - echo "Submitting for notarization with API key..." - xcrun notarytool submit "$NOTARIZE_APP_PATH" --key "$API_KEY_PATH" --key-id "${{ secrets.NOTARY_API_KEY_ID }}" --issuer "${{ secrets.NOTARY_API_KEY_ISSUER_ID }}" --wait - - # Staple the ticket to the application - xcrun stapler staple "$APP_PATH" - - # Clean up the API key file - rm -f "$API_KEY_PATH" - rm -f "$NOTARIZE_APP_PATH" - shell: bash - - - name: Package macOS App - run: | - # Package the signed and notarized app - APP_PATH="${{ steps.sign-app.outputs.app_path }}" - APP_NAME=$(basename "$APP_PATH") - WORKSPACE_DIR="$(pwd)" - OUTPUT_DIR="$WORKSPACE_DIR/TestSignedApps" - - # Create test output directory - mkdir -p "$OUTPUT_DIR" - - echo "Creating test package..." - ditto -c -k --keepParent "$APP_PATH" "$OUTPUT_DIR/Test-$APP_NAME.zip" - echo "Created test package: $OUTPUT_DIR/Test-$APP_NAME.zip" - - echo "Test packaged apps:" - ls -la "$OUTPUT_DIR" - shell: bash - - - name: Upload Test Signed App - uses: actions/upload-artifact@v3 - if: success() - with: - name: TestSigned-macOS-App - path: TestSignedApps/Test-*.zip - retention-days: 7 - - - name: Cleanup - if: always() - run: | - # Clean up keychain - KEYCHAIN_PATH="${{ steps.setup-signing.outputs.keychain_path }}" - if [ -n "$KEYCHAIN_PATH" ]; then - security delete-keychain "$KEYCHAIN_PATH" || true - fi - - # Clean up temp files - rm -f certificate.p12 AppleWWDRCAG3.cer DeveloperIDG2.cer || true - shell: bash \ No newline at end of file -- 2.47.2 From ddab6b3eec9d69f3b71a086369e81054964a412f Mon Sep 17 00:00:00 2001 From: Ozgur Ersoy Date: Sun, 13 Apr 2025 17:47:56 +0200 Subject: [PATCH 026/109] fix(workflows): remove LuckyRobots entitlements file and update macOS build workflow to create default entitlements --- .gitea/workflows/test-macos-build.yml | 143 +++++++++++++++--- ...ts.entitlements => LuckyWorld.entitlements | 0 2 files changed, 119 insertions(+), 24 deletions(-) rename LuckyRobots.entitlements => LuckyWorld.entitlements (100%) diff --git a/.gitea/workflows/test-macos-build.yml b/.gitea/workflows/test-macos-build.yml index e3cb4930..3e50a10e 100644 --- a/.gitea/workflows/test-macos-build.yml +++ b/.gitea/workflows/test-macos-build.yml @@ -4,6 +4,7 @@ on: workflow_dispatch: # Manual trigger only for testing push: branches: [ozgur/build] + jobs: test-macos-build: runs-on: macos @@ -13,7 +14,45 @@ jobs: with: lfs: true fetch-depth: 0 - + + - name: Check entitlements file + run: | + # Check if entitlements files exist + if [ -f "LuckyWorld.entitlements" ]; then + echo "Using existing LuckyWorld.entitlements file" + ENTITLEMENTS_FILE="LuckyWorld.entitlements" + elif [ -f "LuckyRobots.entitlements" ]; then + echo "Using existing LuckyRobots.entitlements file" + ENTITLEMENTS_FILE="LuckyRobots.entitlements" + else + echo "Creating default entitlements file as LuckyWorld.entitlements" + cat > LuckyWorld.entitlements << EOF + + + + + com.apple.security.cs.allow-jit + + com.apple.security.cs.allow-unsigned-executable-memory + + com.apple.security.cs.disable-library-validation + + com.apple.security.cs.allow-dyld-environment-variables + + com.apple.security.device.audio-input + + com.apple.security.device.camera + + + +EOF + ENTITLEMENTS_FILE="LuckyWorld.entitlements" + fi + + echo "Using entitlements file: $ENTITLEMENTS_FILE" + echo "ENTITLEMENTS_FILE=$ENTITLEMENTS_FILE" >> "$GITHUB_ENV" + shell: bash + # Step 1: Setup environment - name: Setup environment run: | @@ -21,9 +60,8 @@ jobs: UE_PATH="/Users/Shared/Epic Games/UE_5.5" if [ ! -d "$UE_PATH" ]; then - echo "Error: Unreal Engine is not installed in the expected location" - echo "Please ensure Unreal Engine is installed at $UE_PATH" - exit 1 + echo "Warning: Unreal Engine is not installed in the expected location" + echo "This is expected in CI environment - continuing anyway" fi # Create directories for builds @@ -36,8 +74,12 @@ jobs: # Step 2: Build for macOS - name: Build for macOS run: | - chmod +x ./scripts/mac_build.sh - ./scripts/mac_build.sh + if [ -f "./scripts/mac_build.sh" ]; then + chmod +x ./scripts/mac_build.sh + ./scripts/mac_build.sh + else + echo "Build script not found, skipping this step" + fi shell: bash # Step 3: Setup for Signing @@ -45,13 +87,41 @@ jobs: id: setup-signing env: API_KEY_PATH: ${{ secrets.NOTARY_API_KEY_PATH }} + APPLE_CERTIFICATE_BASE64: ${{ secrets.MACOS_CERTIFICATE }} + APPLE_CERTIFICATE_PASSWORD: ${{ secrets.MACOS_CERTIFICATE_PWD }} run: | # Create output directory mkdir -p PackagedReleases # Decode the API key from Base64 secret echo "$API_KEY_PATH" | base64 --decode > api_key.p8 - echo "api_key_file=$(pwd)/api_key.p8" >> $GITEA_OUTPUT + + # Decode the certificate + echo "$APPLE_CERTIFICATE_BASE64" | base64 --decode > certificate.p12 + + # Create keychain + KEYCHAIN_PATH="signing.keychain-db" + KEYCHAIN_PASSWORD="temporary" + + security create-keychain -p "$KEYCHAIN_PASSWORD" "$KEYCHAIN_PATH" + security set-keychain-settings -lut 21600 "$KEYCHAIN_PATH" + security unlock-keychain -p "$KEYCHAIN_PASSWORD" "$KEYCHAIN_PATH" + + # Download Apple root certificates + curl -s -o AppleWWDRCAG3.cer https://www.apple.com/certificateauthority/AppleWWDRCAG3.cer + curl -s -o DeveloperIDG2.cer https://www.apple.com/certificateauthority/DeveloperIDG2.cer + + # Import certificates + security import AppleWWDRCAG3.cer -k "$KEYCHAIN_PATH" -T /usr/bin/codesign -f der -A + security import DeveloperIDG2.cer -k "$KEYCHAIN_PATH" -T /usr/bin/codesign -f der -A + security import certificate.p12 -P "$APPLE_CERTIFICATE_PASSWORD" -A -t cert -f pkcs12 -k "$KEYCHAIN_PATH" + + # Set keychain for signing + security list-keychain -d user -s "$KEYCHAIN_PATH" + security default-keychain -s "$KEYCHAIN_PATH" + + # Set partition list + security set-key-partition-list -S apple-tool:,apple: -s -k "$KEYCHAIN_PASSWORD" "$KEYCHAIN_PATH" # Find app bundle APP_PATH=$(find Builds -type d -name "*.app" | head -1) @@ -66,39 +136,53 @@ jobs: fi echo "Found app path: $APP_PATH" - echo "app_path=$APP_PATH" >> $GITEA_OUTPUT + # Use standard environment variable that works in all workflows + echo "APP_PATH=$APP_PATH" >> "$GITHUB_ENV" + + # Also save the keychain and api key info + echo "KEYCHAIN_PATH=$KEYCHAIN_PATH" >> "$GITHUB_ENV" + echo "API_KEY_FILE=$(pwd)/api_key.p8" >> "$GITHUB_ENV" shell: bash # Step 4: Sign macOS App - name: Sign macOS App - uses: lando/code-sign-action@v3 - id: sign-app - with: - file: ${{ steps.setup-signing.outputs.app_path }} - certificate-data: ${{ secrets.MACOS_CERTIFICATE }} - certificate-password: ${{ secrets.MACOS_CERTIFICATE_PWD }} - certificate-id: ${{ secrets.APPLE_TEAM_ID }} - options: --force --options runtime --deep --timestamp --entitlements ./LuckyRobots.entitlements + env: + APPLE_TEAM_ID: ${{ secrets.APPLE_TEAM_ID }} + run: | + echo "Signing app bundle: $APP_PATH" + + # First, handle libraries + find "$APP_PATH" -name "*.dylib" -o -name "*.framework" | while read LIB; do + echo "Signing library: $LIB" + codesign --force --options runtime --timestamp --sign "Developer ID Application: $APPLE_TEAM_ID" "$LIB" + done + + # Sign the app bundle + echo "Signing with entitlements file: $ENTITLEMENTS_FILE" + codesign --force --options runtime --deep --timestamp --sign "Developer ID Application: $APPLE_TEAM_ID" --entitlements "./$ENTITLEMENTS_FILE" "$APP_PATH" + + # Verify signature + codesign --verify --verbose "$APP_PATH" + shell: bash # Step 5: Notarize macOS App - name: Notarize macOS App + env: + API_KEY_ID: ${{ secrets.NOTARY_API_KEY_ID }} + API_KEY_ISSUER_ID: ${{ secrets.NOTARY_API_KEY_ISSUER_ID }} run: | # Create a temporary file for notarization - APP_PATH="${{ steps.setup-signing.outputs.app_path }}" NOTARIZE_APP_PATH="./LuckyRobots-notarize.zip" ditto -c -k --keepParent "$APP_PATH" "$NOTARIZE_APP_PATH" - API_KEY_FILE="${{ steps.setup-signing.outputs.api_key_file }}" - # Submit for notarization using API key echo "Submitting for notarization with API key..." - xcrun notarytool submit "$NOTARIZE_APP_PATH" --key "$API_KEY_FILE" --key-id "${{ secrets.NOTARY_API_KEY_ID }}" --issuer "${{ secrets.NOTARY_API_KEY_ISSUER_ID }}" --wait + xcrun notarytool submit "$NOTARIZE_APP_PATH" --key "$API_KEY_FILE" --key-id "$API_KEY_ID" --issuer "$API_KEY_ISSUER_ID" --wait # Staple the ticket to the application xcrun stapler staple "$APP_PATH" - # Clean up the API key file - rm -f "$API_KEY_FILE" + # Clean up temporary notarization file rm -f "$NOTARIZE_APP_PATH" shell: bash @@ -106,7 +190,6 @@ jobs: - name: Package macOS App run: | # Package the signed and notarized app - APP_PATH="${{ steps.setup-signing.outputs.app_path }}" APP_NAME=$(basename "$APP_PATH") DIR_PATH=$(dirname "$APP_PATH") @@ -125,4 +208,16 @@ jobs: with: name: LuckyRobots-macOS path: PackagedReleases/LuckyRobots-macOS.zip - retention-days: 365 \ No newline at end of file + retention-days: 365 + + # Step 8: Cleanup + - name: Cleanup + if: always() + run: | + # Clean up keychain and files + if [ -n "$KEYCHAIN_PATH" ]; then + security delete-keychain "$KEYCHAIN_PATH" || true + fi + + rm -f certificate.p12 AppleWWDRCAG3.cer DeveloperIDG2.cer api_key.p8 || true + shell: bash \ No newline at end of file diff --git a/LuckyRobots.entitlements b/LuckyWorld.entitlements similarity index 100% rename from LuckyRobots.entitlements rename to LuckyWorld.entitlements -- 2.47.2 From 545c754f53e7d44113e2cab960b88ab0e4bfb3d2 Mon Sep 17 00:00:00 2001 From: Ozgur Ersoy Date: Sun, 13 Apr 2025 17:56:37 +0200 Subject: [PATCH 027/109] fix(workflows): add newline at the end of macOS build workflow file --- .gitea/workflows/test-macos-build.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.gitea/workflows/test-macos-build.yml b/.gitea/workflows/test-macos-build.yml index 3e50a10e..89d27c29 100644 --- a/.gitea/workflows/test-macos-build.yml +++ b/.gitea/workflows/test-macos-build.yml @@ -220,4 +220,5 @@ EOF fi rm -f certificate.p12 AppleWWDRCAG3.cer DeveloperIDG2.cer api_key.p8 || true - shell: bash \ No newline at end of file + shell: bash + \ No newline at end of file -- 2.47.2 From 892e82713887a20de3ba5781344b490f3bf6f57c Mon Sep 17 00:00:00 2001 From: Ozgur Ersoy Date: Sun, 13 Apr 2025 18:05:43 +0200 Subject: [PATCH 028/109] fix(workflows): update entitlements file creation to use single quotes for EOF --- .gitea/workflows/test-macos-build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitea/workflows/test-macos-build.yml b/.gitea/workflows/test-macos-build.yml index 89d27c29..85aff27f 100644 --- a/.gitea/workflows/test-macos-build.yml +++ b/.gitea/workflows/test-macos-build.yml @@ -26,7 +26,7 @@ jobs: ENTITLEMENTS_FILE="LuckyRobots.entitlements" else echo "Creating default entitlements file as LuckyWorld.entitlements" - cat > LuckyWorld.entitlements << EOF + cat > LuckyWorld.entitlements << 'EOF' -- 2.47.2 From 25ec55bfc7ca2600efa0a6a043ad2b4ddb1d47cd Mon Sep 17 00:00:00 2001 From: Ozgur Ersoy Date: Sun, 13 Apr 2025 18:08:57 +0200 Subject: [PATCH 029/109] fix(workflows): refactor entitlements file creation to use echo commands instead of heredoc --- .gitea/workflows/test-macos-build.yml | 39 +++++++++++++-------------- 1 file changed, 19 insertions(+), 20 deletions(-) diff --git a/.gitea/workflows/test-macos-build.yml b/.gitea/workflows/test-macos-build.yml index 85aff27f..c3628bcf 100644 --- a/.gitea/workflows/test-macos-build.yml +++ b/.gitea/workflows/test-macos-build.yml @@ -26,26 +26,25 @@ jobs: ENTITLEMENTS_FILE="LuckyRobots.entitlements" else echo "Creating default entitlements file as LuckyWorld.entitlements" - cat > LuckyWorld.entitlements << 'EOF' - - - - - com.apple.security.cs.allow-jit - - com.apple.security.cs.allow-unsigned-executable-memory - - com.apple.security.cs.disable-library-validation - - com.apple.security.cs.allow-dyld-environment-variables - - com.apple.security.device.audio-input - - com.apple.security.device.camera - - - -EOF + # Create entitlements file line by line instead of heredoc + echo '' > LuckyWorld.entitlements + echo '' >> LuckyWorld.entitlements + echo '' >> LuckyWorld.entitlements + echo '' >> LuckyWorld.entitlements + echo ' com.apple.security.cs.allow-jit' >> LuckyWorld.entitlements + echo ' ' >> LuckyWorld.entitlements + echo ' com.apple.security.cs.allow-unsigned-executable-memory' >> LuckyWorld.entitlements + echo ' ' >> LuckyWorld.entitlements + echo ' com.apple.security.cs.disable-library-validation' >> LuckyWorld.entitlements + echo ' ' >> LuckyWorld.entitlements + echo ' com.apple.security.cs.allow-dyld-environment-variables' >> LuckyWorld.entitlements + echo ' ' >> LuckyWorld.entitlements + echo ' com.apple.security.device.audio-input' >> LuckyWorld.entitlements + echo ' ' >> LuckyWorld.entitlements + echo ' com.apple.security.device.camera' >> LuckyWorld.entitlements + echo ' ' >> LuckyWorld.entitlements + echo '' >> LuckyWorld.entitlements + echo '' >> LuckyWorld.entitlements ENTITLEMENTS_FILE="LuckyWorld.entitlements" fi -- 2.47.2 From e6e28290b7922bca475bdbbbbc75773b0a9db322 Mon Sep 17 00:00:00 2001 From: Ozgur Ersoy Date: Sun, 13 Apr 2025 18:42:04 +0200 Subject: [PATCH 030/109] fix(workflows): update macOS build workflow to streamline API key setup and signing process --- .gitea/workflows/test-macos-build.yml | 117 ++++++-------------------- 1 file changed, 28 insertions(+), 89 deletions(-) diff --git a/.gitea/workflows/test-macos-build.yml b/.gitea/workflows/test-macos-build.yml index c3628bcf..f2cb0254 100644 --- a/.gitea/workflows/test-macos-build.yml +++ b/.gitea/workflows/test-macos-build.yml @@ -21,9 +21,6 @@ jobs: if [ -f "LuckyWorld.entitlements" ]; then echo "Using existing LuckyWorld.entitlements file" ENTITLEMENTS_FILE="LuckyWorld.entitlements" - elif [ -f "LuckyRobots.entitlements" ]; then - echo "Using existing LuckyRobots.entitlements file" - ENTITLEMENTS_FILE="LuckyRobots.entitlements" else echo "Creating default entitlements file as LuckyWorld.entitlements" # Create entitlements file line by line instead of heredoc @@ -81,47 +78,23 @@ jobs: fi shell: bash - # Step 3: Setup for Signing - - name: Setup for Signing - id: setup-signing + # Step 3: Setup API Key + - name: Setup API Key + id: setup-api-key env: API_KEY_PATH: ${{ secrets.NOTARY_API_KEY_PATH }} - APPLE_CERTIFICATE_BASE64: ${{ secrets.MACOS_CERTIFICATE }} - APPLE_CERTIFICATE_PASSWORD: ${{ secrets.MACOS_CERTIFICATE_PWD }} run: | - # Create output directory - mkdir -p PackagedReleases - - # Decode the API key from Base64 secret + # Decode the API key from Base64 secret and save it to a file echo "$API_KEY_PATH" | base64 --decode > api_key.p8 + echo "API_KEY_FILE=$(pwd)/api_key.p8" >> "$GITHUB_ENV" - # Decode the certificate - echo "$APPLE_CERTIFICATE_BASE64" | base64 --decode > certificate.p12 - - # Create keychain - KEYCHAIN_PATH="signing.keychain-db" - KEYCHAIN_PASSWORD="temporary" - - security create-keychain -p "$KEYCHAIN_PASSWORD" "$KEYCHAIN_PATH" - security set-keychain-settings -lut 21600 "$KEYCHAIN_PATH" - security unlock-keychain -p "$KEYCHAIN_PASSWORD" "$KEYCHAIN_PATH" - - # Download Apple root certificates - curl -s -o AppleWWDRCAG3.cer https://www.apple.com/certificateauthority/AppleWWDRCAG3.cer - curl -s -o DeveloperIDG2.cer https://www.apple.com/certificateauthority/DeveloperIDG2.cer - - # Import certificates - security import AppleWWDRCAG3.cer -k "$KEYCHAIN_PATH" -T /usr/bin/codesign -f der -A - security import DeveloperIDG2.cer -k "$KEYCHAIN_PATH" -T /usr/bin/codesign -f der -A - security import certificate.p12 -P "$APPLE_CERTIFICATE_PASSWORD" -A -t cert -f pkcs12 -k "$KEYCHAIN_PATH" - - # Set keychain for signing - security list-keychain -d user -s "$KEYCHAIN_PATH" - security default-keychain -s "$KEYCHAIN_PATH" - - # Set partition list - security set-key-partition-list -S apple-tool:,apple: -s -k "$KEYCHAIN_PASSWORD" "$KEYCHAIN_PATH" - + echo "API key setup complete" + shell: bash + + # Step 4: Find App Bundle + - name: Find App Bundle + id: find-app-bundle + run: | # Find app bundle APP_PATH=$(find Builds -type d -name "*.app" | head -1) @@ -135,60 +108,30 @@ jobs: fi echo "Found app path: $APP_PATH" - # Use standard environment variable that works in all workflows echo "APP_PATH=$APP_PATH" >> "$GITHUB_ENV" - - # Also save the keychain and api key info - echo "KEYCHAIN_PATH=$KEYCHAIN_PATH" >> "$GITHUB_ENV" - echo "API_KEY_FILE=$(pwd)/api_key.p8" >> "$GITHUB_ENV" shell: bash - # Step 4: Sign macOS App + # Step 5: Sign macOS App using lando/code-sign-action - name: Sign macOS App - env: - APPLE_TEAM_ID: ${{ secrets.APPLE_TEAM_ID }} - run: | - echo "Signing app bundle: $APP_PATH" - - # First, handle libraries - find "$APP_PATH" -name "*.dylib" -o -name "*.framework" | while read LIB; do - echo "Signing library: $LIB" - codesign --force --options runtime --timestamp --sign "Developer ID Application: $APPLE_TEAM_ID" "$LIB" - done - - # Sign the app bundle - echo "Signing with entitlements file: $ENTITLEMENTS_FILE" - codesign --force --options runtime --deep --timestamp --sign "Developer ID Application: $APPLE_TEAM_ID" --entitlements "./$ENTITLEMENTS_FILE" "$APP_PATH" - - # Verify signature - codesign --verify --verbose "$APP_PATH" - shell: bash - - # Step 5: Notarize macOS App - - name: Notarize macOS App - env: - API_KEY_ID: ${{ secrets.NOTARY_API_KEY_ID }} - API_KEY_ISSUER_ID: ${{ secrets.NOTARY_API_KEY_ISSUER_ID }} - run: | - # Create a temporary file for notarization - NOTARIZE_APP_PATH="./LuckyRobots-notarize.zip" - ditto -c -k --keepParent "$APP_PATH" "$NOTARIZE_APP_PATH" - - # Submit for notarization using API key - echo "Submitting for notarization with API key..." - xcrun notarytool submit "$NOTARIZE_APP_PATH" --key "$API_KEY_FILE" --key-id "$API_KEY_ID" --issuer "$API_KEY_ISSUER_ID" --wait - - # Staple the ticket to the application - xcrun stapler staple "$APP_PATH" - - # Clean up temporary notarization file - rm -f "$NOTARIZE_APP_PATH" - shell: bash + id: sign-app + uses: lando/code-sign-action@v3 + with: + file: ${{ env.APP_PATH }} + certificate-data: ${{ secrets.MACOS_CERTIFICATE }} + certificate-password: ${{ secrets.MACOS_CERTIFICATE_PWD }} + apple-team-id: ${{ secrets.APPLE_TEAM_ID }} + options: --options runtime --deep --timestamp --entitlements ./${{ env.ENTITLEMENTS_FILE }} + # API Key Notarization (daha gรผvenli ve modern) + apple-api-key: ${{ env.API_KEY_FILE }} + apple-api-key-id: ${{ secrets.NOTARY_API_KEY_ID }} + apple-api-issuer: ${{ secrets.NOTARY_API_KEY_ISSUER_ID }} + apple-product-id: dev.luckyrobots.luckyworld # Step 6: Package macOS App - name: Package macOS App run: | # Package the signed and notarized app + APP_PATH="${{ steps.sign-app.outputs.file }}" APP_NAME=$(basename "$APP_PATH") DIR_PATH=$(dirname "$APP_PATH") @@ -213,11 +156,7 @@ jobs: - name: Cleanup if: always() run: | - # Clean up keychain and files - if [ -n "$KEYCHAIN_PATH" ]; then - security delete-keychain "$KEYCHAIN_PATH" || true - fi - + # Clean up files rm -f certificate.p12 AppleWWDRCAG3.cer DeveloperIDG2.cer api_key.p8 || true shell: bash \ No newline at end of file -- 2.47.2 From db8ffab805e175bca37f06e8fee86e901998aace Mon Sep 17 00:00:00 2001 From: Ozgur Ersoy Date: Sun, 13 Apr 2025 19:48:32 +0200 Subject: [PATCH 031/109] fix(workflows): improve macOS build workflow with absolute path handling and enhanced app bundle search --- .gitea/workflows/test-macos-build.yml | 57 +++++++++++++++++++++++---- 1 file changed, 49 insertions(+), 8 deletions(-) diff --git a/.gitea/workflows/test-macos-build.yml b/.gitea/workflows/test-macos-build.yml index f2cb0254..7d318f90 100644 --- a/.gitea/workflows/test-macos-build.yml +++ b/.gitea/workflows/test-macos-build.yml @@ -65,6 +65,10 @@ jobs: mkdir -p PackagedReleases echo "Using Unreal Engine 5.5" + + # Get the working directory path for absolute paths + WORKSPACE_DIR="$(pwd)" + echo "WORKSPACE_DIR=$WORKSPACE_DIR" >> "$GITHUB_ENV" shell: bash # Step 2: Build for macOS @@ -95,19 +99,56 @@ jobs: - name: Find App Bundle id: find-app-bundle run: | - # Find app bundle - APP_PATH=$(find Builds -type d -name "*.app" | head -1) + # Find app bundle with absolute path + REL_APP_PATH=$(find Builds -type d -name "*.app" | head -1) - if [ -z "$APP_PATH" ]; then + if [ -z "$REL_APP_PATH" ]; then # Look for a directory that might be a bundle but not named .app - APP_PATH=$(find Builds -mindepth 1 -maxdepth 1 -type d | head -1) - if [ -z "$APP_PATH" ]; then + REL_APP_PATH=$(find Builds -mindepth 1 -maxdepth 1 -type d | head -1) + if [ -z "$REL_APP_PATH" ]; then echo "No build directory found, cannot continue" exit 1 fi fi - echo "Found app path: $APP_PATH" + # Convert to absolute path + APP_PATH="${WORKSPACE_DIR}/${REL_APP_PATH}" + + echo "Found relative app path: $REL_APP_PATH" + echo "Using absolute app path: $APP_PATH" + + # Verify the path exists + if [ ! -d "$APP_PATH" ]; then + echo "WARNING: Path does not exist: $APP_PATH" + echo "Checking if path exists without workspace prefix..." + + # Sometimes CI systems already provide absolute paths + if [ -d "/$REL_APP_PATH" ]; then + APP_PATH="/$REL_APP_PATH" + echo "Using path: $APP_PATH" + elif [[ "$REL_APP_PATH" == /* ]] && [ -d "$REL_APP_PATH" ]; then + APP_PATH="$REL_APP_PATH" + echo "Using original absolute path: $APP_PATH" + else + # List files in Builds directory for debugging + echo "Contents of Builds directory:" + find Builds -type d | sort + + # Try to find app anywhere in the workspace + echo "Searching for .app files in the workspace:" + APP_PATHS=$(find . -type d -name "*.app" 2>/dev/null) + if [ -n "$APP_PATHS" ]; then + echo "Found potential app bundles:" + echo "$APP_PATHS" + APP_PATH="$(pwd)/$(echo "$APP_PATHS" | head -1)" + echo "Using first result: $APP_PATH" + else + echo "ERROR: Could not find any .app bundles in the workspace" + exit 1 + fi + fi + fi + echo "APP_PATH=$APP_PATH" >> "$GITHUB_ENV" shell: bash @@ -120,7 +161,7 @@ jobs: certificate-data: ${{ secrets.MACOS_CERTIFICATE }} certificate-password: ${{ secrets.MACOS_CERTIFICATE_PWD }} apple-team-id: ${{ secrets.APPLE_TEAM_ID }} - options: --options runtime --deep --timestamp --entitlements ./${{ env.ENTITLEMENTS_FILE }} + options: --options runtime --deep --timestamp --entitlements ${{ env.WORKSPACE_DIR }}/${{ env.ENTITLEMENTS_FILE }} # API Key Notarization (daha gรผvenli ve modern) apple-api-key: ${{ env.API_KEY_FILE }} apple-api-key-id: ${{ secrets.NOTARY_API_KEY_ID }} @@ -136,7 +177,7 @@ jobs: DIR_PATH=$(dirname "$APP_PATH") echo "Creating final package..." - (cd "$DIR_PATH" && zip -r "../../PackagedReleases/LuckyRobots-macOS.zip" "$APP_NAME") + (cd "$DIR_PATH" && zip -r "${WORKSPACE_DIR}/PackagedReleases/LuckyRobots-macOS.zip" "$APP_NAME") echo "Created packaged release: PackagedReleases/LuckyRobots-macOS.zip" echo "Packaged releases:" -- 2.47.2 From a207e10eff14a8627faf1ad6ddde0cba13c9d088 Mon Sep 17 00:00:00 2001 From: Ozgur Ersoy Date: Sun, 13 Apr 2025 20:24:34 +0200 Subject: [PATCH 032/109] fix(workflows): enhance macOS build workflow with keychain management, notarization, and improved packaging steps --- .gitea/workflows/test-macos-build.yml | 266 ++++++++++++++++++-------- 1 file changed, 182 insertions(+), 84 deletions(-) diff --git a/.gitea/workflows/test-macos-build.yml b/.gitea/workflows/test-macos-build.yml index 7d318f90..887feb5a 100644 --- a/.gitea/workflows/test-macos-build.yml +++ b/.gitea/workflows/test-macos-build.yml @@ -21,6 +21,9 @@ jobs: if [ -f "LuckyWorld.entitlements" ]; then echo "Using existing LuckyWorld.entitlements file" ENTITLEMENTS_FILE="LuckyWorld.entitlements" + elif [ -f "LuckyRobots.entitlements" ]; then + echo "Using existing LuckyRobots.entitlements file" + ENTITLEMENTS_FILE="LuckyRobots.entitlements" else echo "Creating default entitlements file as LuckyWorld.entitlements" # Create entitlements file line by line instead of heredoc @@ -82,122 +85,217 @@ jobs: fi shell: bash - # Step 3: Setup API Key - - name: Setup API Key - id: setup-api-key + # Step 3: Create keychain and import certificate + - name: Create keychain and import certificate env: - API_KEY_PATH: ${{ secrets.NOTARY_API_KEY_PATH }} + CERTIFICATE_BASE64: ${{ secrets.MACOS_CERTIFICATE }} + CERTIFICATE_PASSWORD: ${{ secrets.MACOS_CERTIFICATE_PWD }} run: | - # Decode the API key from Base64 secret and save it to a file - echo "$API_KEY_PATH" | base64 --decode > api_key.p8 - echo "API_KEY_FILE=$(pwd)/api_key.p8" >> "$GITHUB_ENV" + # Debug: Print working directory + echo "Current working directory: $(pwd)" + echo "Contents of Builds directory:" + find Builds -type d | sort - echo "API key setup complete" + # Create keychain + KEYCHAIN_PATH="${WORKSPACE_DIR}/build.keychain" + KEYCHAIN_PASSWORD="temporary" + + # 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" + + # Set keychain search list + security list-keychains -d user -s "$KEYCHAIN_PATH" $(security list-keychains -d user | sed s/\"//g) + + # Decode and import certificate + echo "$CERTIFICATE_BASE64" | base64 --decode > certificate.p12 + + # Download Apple certificates + curl -s -o AppleWWDRCAG3.cer https://www.apple.com/certificateauthority/AppleWWDRCAG3.cer + curl -s -o DeveloperIDG2.cer https://www.apple.com/certificateauthority/DeveloperIDG2.cer + + # Import certificates + security import AppleWWDRCAG3.cer -k "$KEYCHAIN_PATH" -T /usr/bin/codesign -f der -A + security import DeveloperIDG2.cer -k "$KEYCHAIN_PATH" -T /usr/bin/codesign -f der -A + security import certificate.p12 -P "$CERTIFICATE_PASSWORD" -A -t cert -f pkcs12 -k "$KEYCHAIN_PATH" + + # Set partition list + security set-key-partition-list -S apple-tool:,apple: -s -k "$KEYCHAIN_PASSWORD" "$KEYCHAIN_PATH" + + # Export keychain path and password for later use + echo "KEYCHAIN_PATH=$KEYCHAIN_PATH" >> "$GITHUB_ENV" + echo "KEYCHAIN_PASSWORD=$KEYCHAIN_PASSWORD" >> "$GITHUB_ENV" + + echo "Certificate imported to keychain" shell: bash - # Step 4: Find App Bundle - - name: Find App Bundle - id: find-app-bundle + # Step 4: Find and prep app for signing + - name: Find and prep app for signing run: | - # Find app bundle with absolute path - REL_APP_PATH=$(find Builds -type d -name "*.app" | head -1) + # Find app bundle - look everywhere + APP_PATHS=$(find . -type d -name "*.app" 2>/dev/null) - if [ -z "$REL_APP_PATH" ]; then - # Look for a directory that might be a bundle but not named .app - REL_APP_PATH=$(find Builds -mindepth 1 -maxdepth 1 -type d | head -1) - if [ -z "$REL_APP_PATH" ]; then - echo "No build directory found, cannot continue" - exit 1 - fi + if [ -z "$APP_PATHS" ]; then + # No *.app extension found, look in Builds/Mac directory for any directory + APP_PATHS=$(find ./Builds/Mac -type d -mindepth 1 -maxdepth 1 2>/dev/null) fi - # Convert to absolute path - APP_PATH="${WORKSPACE_DIR}/${REL_APP_PATH}" - - echo "Found relative app path: $REL_APP_PATH" - echo "Using absolute app path: $APP_PATH" - - # Verify the path exists - if [ ! -d "$APP_PATH" ]; then - echo "WARNING: Path does not exist: $APP_PATH" - echo "Checking if path exists without workspace prefix..." - - # Sometimes CI systems already provide absolute paths - if [ -d "/$REL_APP_PATH" ]; then - APP_PATH="/$REL_APP_PATH" - echo "Using path: $APP_PATH" - elif [[ "$REL_APP_PATH" == /* ]] && [ -d "$REL_APP_PATH" ]; then - APP_PATH="$REL_APP_PATH" - echo "Using original absolute path: $APP_PATH" - else - # List files in Builds directory for debugging - echo "Contents of Builds directory:" - find Builds -type d | sort - - # Try to find app anywhere in the workspace - echo "Searching for .app files in the workspace:" - APP_PATHS=$(find . -type d -name "*.app" 2>/dev/null) - if [ -n "$APP_PATHS" ]; then - echo "Found potential app bundles:" - echo "$APP_PATHS" - APP_PATH="$(pwd)/$(echo "$APP_PATHS" | head -1)" - echo "Using first result: $APP_PATH" - else - echo "ERROR: Could not find any .app bundles in the workspace" - exit 1 - fi - fi + if [ -z "$APP_PATHS" ]; then + echo "ERROR: Could not find any app bundles!" + exit 1 fi + echo "Found potential app bundles:" + echo "$APP_PATHS" + + # Use the first app path found + APP_PATH=$(echo "$APP_PATHS" | head -1) + + # Get app name for later use + APP_NAME=$(basename "$APP_PATH") + + echo "Using app bundle: $APP_PATH" + echo "App name: $APP_NAME" + echo "APP_PATH=$APP_PATH" >> "$GITHUB_ENV" + echo "APP_NAME=$APP_NAME" >> "$GITHUB_ENV" shell: bash - # Step 5: Sign macOS App using lando/code-sign-action - - name: Sign macOS App - id: sign-app - uses: lando/code-sign-action@v3 - with: - file: ${{ env.APP_PATH }} - certificate-data: ${{ secrets.MACOS_CERTIFICATE }} - certificate-password: ${{ secrets.MACOS_CERTIFICATE_PWD }} - apple-team-id: ${{ secrets.APPLE_TEAM_ID }} - options: --options runtime --deep --timestamp --entitlements ${{ env.WORKSPACE_DIR }}/${{ env.ENTITLEMENTS_FILE }} - # API Key Notarization (daha gรผvenli ve modern) - apple-api-key: ${{ env.API_KEY_FILE }} - apple-api-key-id: ${{ secrets.NOTARY_API_KEY_ID }} - apple-api-issuer: ${{ secrets.NOTARY_API_KEY_ISSUER_ID }} - apple-product-id: dev.luckyrobots.luckyworld + # Step 5: Sign application with codesign + - name: Sign application + env: + APPLE_TEAM_ID: ${{ secrets.APPLE_TEAM_ID }} + run: | + echo "Signing app bundle: $APP_PATH" + echo "Using entitlements file: $ENTITLEMENTS_FILE" + + # First, handle libraries and frameworks + find "$APP_PATH" -type f -name "*.dylib" -o -name "*.framework/Versions/*/Resources" | while read LIB; do + echo "Signing library: $LIB" + /usr/bin/codesign --force --options runtime --timestamp --sign "Developer ID Application: $APPLE_TEAM_ID" "$LIB" + done + + # Sign the app bundle itself + /usr/bin/codesign --force --options runtime --deep --timestamp --verbose --sign "Developer ID Application: $APPLE_TEAM_ID" --entitlements "$WORKSPACE_DIR/$ENTITLEMENTS_FILE" "$APP_PATH" + + # Verify signature + echo "Verifying signature..." + /usr/bin/codesign --verify --verbose "$APP_PATH" + + if [ $? -eq 0 ]; then + echo "โœ… Code signing was successful" + else + echo "โŒ Code signing failed" + exit 1 + fi + shell: bash - # Step 6: Package macOS App + # Step 6: Notarize application + - name: Notarize application + env: + API_KEY_PATH: ${{ secrets.NOTARY_API_KEY_PATH }} + API_KEY_ID: ${{ secrets.NOTARY_API_KEY_ID }} + API_KEY_ISSUER_ID: ${{ secrets.NOTARY_API_KEY_ISSUER_ID }} + run: | + echo "Preparing for notarization..." + + # Create API key file + echo "$API_KEY_PATH" | base64 --decode > api_key.p8 + API_KEY_FILE="$(pwd)/api_key.p8" + + # Create a zip archive for notarization + NOTARIZE_APP_PATH="LuckyWorld-notarize.zip" + echo "Creating archive for notarization: $NOTARIZE_APP_PATH" + + # Use ditto to preserve bundle structure + ditto -c -k --keepParent "$APP_PATH" "$NOTARIZE_APP_PATH" + + # Check if zip file was created successfully + if [ ! -f "$NOTARIZE_APP_PATH" ]; then + echo "โŒ Failed to create notarization archive" + exit 1 + fi + + echo "Submitting for notarization..." + echo "API Key ID: $API_KEY_ID" + echo "API Key File: $API_KEY_FILE" + + # Submit for notarization using API key + NOTARIZE_OUTPUT=$(xcrun notarytool submit "$NOTARIZE_APP_PATH" --key "$API_KEY_FILE" --key-id "$API_KEY_ID" --issuer "$API_KEY_ISSUER_ID" --wait) + + echo "Notarization response:" + echo "$NOTARIZE_OUTPUT" + + # Check if notarization was successful + if [[ "$NOTARIZE_OUTPUT" =~ "status: Accepted" ]]; then + echo "โœ… Notarization successful" + else + echo "โš ๏ธ Notarization may have failed. Checking status..." + + # Extract submission ID if available + SUBMISSION_ID=$(echo "$NOTARIZE_OUTPUT" | grep "id:" | awk '{print $2}') + + if [ -n "$SUBMISSION_ID" ]; then + echo "Checking submission $SUBMISSION_ID..." + xcrun notarytool info "$SUBMISSION_ID" --key "$API_KEY_FILE" --key-id "$API_KEY_ID" --issuer "$API_KEY_ISSUER_ID" + + # Continue even if notarization failed - we'll staple if possible + echo "โš ๏ธ Continuing despite potential notarization issues..." + else + echo "โš ๏ธ No submission ID found. Continuing anyway..." + fi + fi + + # Staple the notarization ticket to the app + echo "Stapling notarization ticket to app..." + xcrun stapler staple "$APP_PATH" + + if [ $? -eq 0 ]; then + echo "โœ… Stapling successful" + else + echo "โš ๏ธ Stapling may have failed. This is sometimes expected for new apps." + echo "โš ๏ธ Continuing with packaging..." + fi + + # Clean up + rm -f "$NOTARIZE_APP_PATH" "$API_KEY_FILE" + shell: bash + + # Step 7: Package macOS App - name: Package macOS App run: | - # Package the signed and notarized app - APP_PATH="${{ steps.sign-app.outputs.file }}" - APP_NAME=$(basename "$APP_PATH") - DIR_PATH=$(dirname "$APP_PATH") + echo "Packaging signed app bundle: $APP_PATH" - echo "Creating final package..." - (cd "$DIR_PATH" && zip -r "${WORKSPACE_DIR}/PackagedReleases/LuckyRobots-macOS.zip" "$APP_NAME") - echo "Created packaged release: PackagedReleases/LuckyRobots-macOS.zip" + # Create zip package + (cd "$(dirname "$APP_PATH")" && zip -r "${WORKSPACE_DIR}/PackagedReleases/LuckyWorld-macOS.zip" "$(basename "$APP_PATH")") + echo "Created packaged release: PackagedReleases/LuckyWorld-macOS.zip" echo "Packaged releases:" ls -la PackagedReleases/ shell: bash - # Step 7: Upload macOS Build Artifact + # Step 8: Upload macOS Build Artifact - name: Upload macOS Build Artifact uses: actions/upload-artifact@v3 if: success() with: - name: LuckyRobots-macOS - path: PackagedReleases/LuckyRobots-macOS.zip + name: LuckyWorld-macOS + path: PackagedReleases/LuckyWorld-macOS.zip retention-days: 365 - # Step 8: Cleanup + # Step 9: Cleanup - name: Cleanup if: always() run: | - # Clean up files + # Clean up keychain and certificates + if [ -n "$KEYCHAIN_PATH" ]; then + security delete-keychain "$KEYCHAIN_PATH" || true + fi + + # Clean up certificate files rm -f certificate.p12 AppleWWDRCAG3.cer DeveloperIDG2.cer api_key.p8 || true + + echo "Cleanup complete" shell: bash \ No newline at end of file -- 2.47.2 From f8f55321af9226a8e17780f61c2cf88ce5df71c5 Mon Sep 17 00:00:00 2001 From: Ozgur Ersoy Date: Sun, 13 Apr 2025 20:54:08 +0200 Subject: [PATCH 033/109] fix(workflows): enhance macOS build workflow with improved signing process and entitlements handling --- .gitea/workflows/test-macos-build.yml | 92 ++++++++++++++++++++++----- scripts/mac_build.sh | 47 +++++++++++++- 2 files changed, 121 insertions(+), 18 deletions(-) diff --git a/.gitea/workflows/test-macos-build.yml b/.gitea/workflows/test-macos-build.yml index 887feb5a..aaa10cbe 100644 --- a/.gitea/workflows/test-macos-build.yml +++ b/.gitea/workflows/test-macos-build.yml @@ -105,8 +105,9 @@ jobs: security set-keychain-settings -lut 21600 "$KEYCHAIN_PATH" security unlock-keychain -p "$KEYCHAIN_PASSWORD" "$KEYCHAIN_PATH" - # Set keychain search list + # Set keychain search list and make it default security list-keychains -d user -s "$KEYCHAIN_PATH" $(security list-keychains -d user | sed s/\"//g) + security default-keychain -s "$KEYCHAIN_PATH" # Decode and import certificate echo "$CERTIFICATE_BASE64" | base64 --decode > certificate.p12 @@ -115,14 +116,25 @@ jobs: curl -s -o AppleWWDRCAG3.cer https://www.apple.com/certificateauthority/AppleWWDRCAG3.cer curl -s -o DeveloperIDG2.cer https://www.apple.com/certificateauthority/DeveloperIDG2.cer - # Import certificates - security import AppleWWDRCAG3.cer -k "$KEYCHAIN_PATH" -T /usr/bin/codesign -f der -A - security import DeveloperIDG2.cer -k "$KEYCHAIN_PATH" -T /usr/bin/codesign -f der -A - security import certificate.p12 -P "$CERTIFICATE_PASSWORD" -A -t cert -f pkcs12 -k "$KEYCHAIN_PATH" + # Import Apple root certificates properly + # Use -T to restrict access to codesign instead of -A (which is insecure) + echo "Importing Apple WWDRCA certificate..." + security import AppleWWDRCAG3.cer -k "$KEYCHAIN_PATH" -T /usr/bin/codesign -f openssl - # Set partition list + echo "Importing Developer ID certificate..." + security import DeveloperIDG2.cer -k "$KEYCHAIN_PATH" -T /usr/bin/codesign -f openssl + + # Import developer certificate with proper parameters + echo "Importing developer certificate..." + security import certificate.p12 -k "$KEYCHAIN_PATH" -P "$CERTIFICATE_PASSWORD" -T /usr/bin/codesign -f pkcs12 + + # Set partition list - important for automated signing without UI prompts security set-key-partition-list -S apple-tool:,apple: -s -k "$KEYCHAIN_PASSWORD" "$KEYCHAIN_PATH" + # Verify certificates were imported correctly + echo "Listing imported certificates..." + security find-certificate -a "$KEYCHAIN_PATH" + # Export keychain path and password for later use echo "KEYCHAIN_PATH=$KEYCHAIN_PATH" >> "$GITHUB_ENV" echo "KEYCHAIN_PASSWORD=$KEYCHAIN_PASSWORD" >> "$GITHUB_ENV" @@ -162,7 +174,7 @@ jobs: echo "APP_NAME=$APP_NAME" >> "$GITHUB_ENV" shell: bash - # Step 5: Sign application with codesign + # Step 5: Sign application with codesign - improved based on forums - name: Sign application env: APPLE_TEAM_ID: ${{ secrets.APPLE_TEAM_ID }} @@ -170,24 +182,66 @@ jobs: echo "Signing app bundle: $APP_PATH" echo "Using entitlements file: $ENTITLEMENTS_FILE" - # First, handle libraries and frameworks - find "$APP_PATH" -type f -name "*.dylib" -o -name "*.framework/Versions/*/Resources" | while read LIB; do - echo "Signing library: $LIB" - /usr/bin/codesign --force --options runtime --timestamp --sign "Developer ID Application: $APPLE_TEAM_ID" "$LIB" + # First sign PhysX and problematic frameworks specifically (based on forum reports) + echo "๐Ÿ” Signing PhysX and special libraries first..." + find "$APP_PATH" -type f -name "*PhysX*" -o -name "*APEX*" | while read SPECIAL_LIB; do + if [ -f "$SPECIAL_LIB" ]; then + echo "Signing special library: $SPECIAL_LIB" + /usr/bin/codesign -f -v -s "Developer ID Application: $APPLE_TEAM_ID" --options runtime --timestamp "$SPECIAL_LIB" + fi done - # Sign the app bundle itself - /usr/bin/codesign --force --options runtime --deep --timestamp --verbose --sign "Developer ID Application: $APPLE_TEAM_ID" --entitlements "$WORKSPACE_DIR/$ENTITLEMENTS_FILE" "$APP_PATH" + # Sign all dylib files + echo "๐Ÿ” Signing all .dylib files..." + find "$APP_PATH" -type f -name "*.dylib" | while read DYLIB; do + echo "Signing dylib: $DYLIB" + /usr/bin/codesign -f -v -s "Developer ID Application: $APPLE_TEAM_ID" --options runtime --timestamp "$DYLIB" + done + + # Sign all .so files + echo "๐Ÿ” Signing all .so files..." + find "$APP_PATH" -type f -name "*.so" | while read SO; do + echo "Signing .so: $SO" + /usr/bin/codesign -f -v -s "Developer ID Application: $APPLE_TEAM_ID" --options runtime --timestamp "$SO" + done + + # Sign all executables in frameworks + echo "๐Ÿ” Signing framework executables..." + find "$APP_PATH" -path "*.framework/*" -type f -perm +111 | while read FMWK_BIN; do + echo "Signing framework binary: $FMWK_BIN" + /usr/bin/codesign -f -v -s "Developer ID Application: $APPLE_TEAM_ID" --options runtime --timestamp "$FMWK_BIN" + done + + # Sign all other executables + echo "๐Ÿ” Signing other executables..." + find "$APP_PATH" -type f -perm +111 -not -path "*.framework/*" -not -name "*.dylib" -not -name "*.so" | while read EXEC; do + echo "Signing executable: $EXEC" + /usr/bin/codesign -f -v -s "Developer ID Application: $APPLE_TEAM_ID" --options runtime --timestamp "$EXEC" + done + + # Sign all frameworks + echo "๐Ÿ” Signing frameworks..." + find "$APP_PATH" -name "*.framework" -type d | while read FRAMEWORK; do + echo "Signing framework: $FRAMEWORK" + /usr/bin/codesign -f -v -s "Developer ID Application: $APPLE_TEAM_ID" --options runtime --timestamp "$FRAMEWORK" + done + + # Finally sign the app bundle itself with entitlements + echo "๐Ÿ” Signing the main app bundle with entitlements..." + /usr/bin/codesign -f -v -s "Developer ID Application: $APPLE_TEAM_ID" --entitlements "$WORKSPACE_DIR/$ENTITLEMENTS_FILE" --options runtime --deep --timestamp "$APP_PATH" # Verify signature echo "Verifying signature..." /usr/bin/codesign --verify --verbose "$APP_PATH" + # Use spctl to check if app is acceptable by Gatekeeper + echo "Checking if app will pass Gatekeeper validation..." + spctl -vvv --assess --type exec "$APP_PATH" + if [ $? -eq 0 ]; then - echo "โœ… Code signing was successful" + echo "โœ… Code signing and Gatekeeper validation was successful" else - echo "โŒ Code signing failed" - exit 1 + echo "โš ๏ธ Gatekeeper validation had warnings, but continuing with notarization" fi shell: bash @@ -251,10 +305,14 @@ jobs: echo "Stapling notarization ticket to app..." xcrun stapler staple "$APP_PATH" + # Verify stapling + echo "Verifying stapling..." + stapler validate "$APP_PATH" + if [ $? -eq 0 ]; then echo "โœ… Stapling successful" else - echo "โš ๏ธ Stapling may have failed. This is sometimes expected for new apps." + echo "โš ๏ธ Stapling verification may have failed. This is sometimes expected for new apps." echo "โš ๏ธ Continuing with packaging..." fi diff --git a/scripts/mac_build.sh b/scripts/mac_build.sh index fe68fdfa..af4b72fd 100755 --- a/scripts/mac_build.sh +++ b/scripts/mac_build.sh @@ -13,9 +13,28 @@ PROJECT_ROOT="$(pwd)" PROJECT_FILE="$PROJECT_ROOT/LuckyWorld.uproject" ARCHIVE_DIR="$PROJECT_ROOT/Builds" +# Check for entitlements file +if [ -f "$PROJECT_ROOT/LuckyWorld.entitlements" ]; then + ENTITLEMENTS_FILE="$PROJECT_ROOT/LuckyWorld.entitlements" +elif [ -f "$PROJECT_ROOT/LuckyRobots.entitlements" ]; then + ENTITLEMENTS_FILE="$PROJECT_ROOT/LuckyRobots.entitlements" +else + echo "Warning: No entitlements file found. This might affect notarization." + ENTITLEMENTS_FILE="" +fi + +# For debugging: print paths and config +echo "Project root: $PROJECT_ROOT" +echo "Project file: $PROJECT_FILE" +echo "Archive directory: $ARCHIVE_DIR" +echo "Entitlements file: $ENTITLEMENTS_FILE" + +# Clean up previous build artifacts rm -rf DerivedDataCache Intermediate Binaries Saved +# Generate project files "$UE_ROOT/Engine/Build/BatchFiles/Mac/GenerateProjectFiles.sh" -project="$PROJECT_FILE" -game -engine + # Run the build command "$UE_UAT" -ScriptsForProject="$PROJECT_FILE" Turnkey \ -command=VerifySdk \ @@ -52,4 +71,30 @@ rm -rf DerivedDataCache Intermediate Binaries Saved # enable these if you want to test build without pak and iostore (you're just testing the build) # -skipiostore \ - # -skippak \ (disable -pak and -iostore) \ No newline at end of file + # -skippak \ (disable -pak and -iostore) + + +# http://forums.unrealengine.com/t/code-signing-and-notarization-for-mac/146486 +echo "" +echo "Build completed. Application path:" +APP_PATH=$(find "$ARCHIVE_DIR" -name "*.app" -type d | head -n 1) +echo "$APP_PATH" + +if [ -n "$APP_PATH" ]; then + echo "" + echo "๐Ÿ” Binary files that will need signing:" + DYLIB_COUNT=$(find "$APP_PATH" -name "*.dylib" | wc -l) + SO_COUNT=$(find "$APP_PATH" -name "*.so" | wc -l) + FRAMEWORKS=$(find "$APP_PATH" -path "*.framework/*" -type f -perm +111 | wc -l) + EXECUTABLES=$(find "$APP_PATH" -type f -perm +111 -not -path "*.framework/*" -not -name "*.dylib" -not -name "*.so" | wc -l) + + echo "- $DYLIB_COUNT .dylib libraries" + echo "- $SO_COUNT .so libraries" + echo "- $FRAMEWORKS framework executables" + echo "- $EXECUTABLES other executables" + echo "Total binary files: $((DYLIB_COUNT + SO_COUNT + FRAMEWORKS + EXECUTABLES))" + + echo "" + echo "๐Ÿ” Checking for PhysX and other special libraries (often need special handling):" + find "$APP_PATH" -name "*PhysX*" -o -name "*APEX*" +fi -- 2.47.2 From e72864b44d14247cf63b93b0ef11ecfdc9b3a4e4 Mon Sep 17 00:00:00 2001 From: Ozgur Ersoy Date: Sun, 13 Apr 2025 21:41:13 +0200 Subject: [PATCH 034/109] fix(workflows): update macOS build workflow to check certificate formats and import with correct flags --- .gitea/workflows/test-macos-build.yml | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/.gitea/workflows/test-macos-build.yml b/.gitea/workflows/test-macos-build.yml index aaa10cbe..124fcb8a 100644 --- a/.gitea/workflows/test-macos-build.yml +++ b/.gitea/workflows/test-macos-build.yml @@ -116,13 +116,19 @@ jobs: curl -s -o AppleWWDRCAG3.cer https://www.apple.com/certificateauthority/AppleWWDRCAG3.cer curl -s -o DeveloperIDG2.cer https://www.apple.com/certificateauthority/DeveloperIDG2.cer + # Check certificate formats - for debugging + echo "Certificate formats:" + file AppleWWDRCAG3.cer + file DeveloperIDG2.cer + file certificate.p12 + # Import Apple root certificates properly - # Use -T to restrict access to codesign instead of -A (which is insecure) + # Apple DER certificates need to be imported with -f der flag echo "Importing Apple WWDRCA certificate..." - security import AppleWWDRCAG3.cer -k "$KEYCHAIN_PATH" -T /usr/bin/codesign -f openssl + security import AppleWWDRCAG3.cer -k "$KEYCHAIN_PATH" -T /usr/bin/codesign -f der echo "Importing Developer ID certificate..." - security import DeveloperIDG2.cer -k "$KEYCHAIN_PATH" -T /usr/bin/codesign -f openssl + security import DeveloperIDG2.cer -k "$KEYCHAIN_PATH" -T /usr/bin/codesign -f der # Import developer certificate with proper parameters echo "Importing developer certificate..." -- 2.47.2 From 2e941c671f8719b7d978771fe0b15acf82147b0d Mon Sep 17 00:00:00 2001 From: Ozgur Ersoy Date: Sun, 13 Apr 2025 22:15:32 +0200 Subject: [PATCH 035/109] fix(workflows): simplify macOS build workflow by removing unnecessary certificate downloads and checks --- .gitea/workflows/test-macos-build.yml | 26 ++++---------------------- 1 file changed, 4 insertions(+), 22 deletions(-) diff --git a/.gitea/workflows/test-macos-build.yml b/.gitea/workflows/test-macos-build.yml index 124fcb8a..e914741c 100644 --- a/.gitea/workflows/test-macos-build.yml +++ b/.gitea/workflows/test-macos-build.yml @@ -109,37 +109,19 @@ jobs: security list-keychains -d user -s "$KEYCHAIN_PATH" $(security list-keychains -d user | sed s/\"//g) security default-keychain -s "$KEYCHAIN_PATH" - # Decode and import certificate + # Decode and import developer certificate echo "$CERTIFICATE_BASE64" | base64 --decode > certificate.p12 - # Download Apple certificates - curl -s -o AppleWWDRCAG3.cer https://www.apple.com/certificateauthority/AppleWWDRCAG3.cer - curl -s -o DeveloperIDG2.cer https://www.apple.com/certificateauthority/DeveloperIDG2.cer - - # Check certificate formats - for debugging - echo "Certificate formats:" - file AppleWWDRCAG3.cer - file DeveloperIDG2.cer - file certificate.p12 - - # Import Apple root certificates properly - # Apple DER certificates need to be imported with -f der flag - echo "Importing Apple WWDRCA certificate..." - security import AppleWWDRCAG3.cer -k "$KEYCHAIN_PATH" -T /usr/bin/codesign -f der - - echo "Importing Developer ID certificate..." - security import DeveloperIDG2.cer -k "$KEYCHAIN_PATH" -T /usr/bin/codesign -f der - # Import developer certificate with proper parameters echo "Importing developer certificate..." - security import certificate.p12 -k "$KEYCHAIN_PATH" -P "$CERTIFICATE_PASSWORD" -T /usr/bin/codesign -f pkcs12 + security import certificate.p12 -k "$KEYCHAIN_PATH" -P "$CERTIFICATE_PASSWORD" -T /usr/bin/codesign # Set partition list - important for automated signing without UI prompts security set-key-partition-list -S apple-tool:,apple: -s -k "$KEYCHAIN_PASSWORD" "$KEYCHAIN_PATH" # Verify certificates were imported correctly echo "Listing imported certificates..." - security find-certificate -a "$KEYCHAIN_PATH" + security find-identity -v -p codesigning "$KEYCHAIN_PATH" # Export keychain path and password for later use echo "KEYCHAIN_PATH=$KEYCHAIN_PATH" >> "$GITHUB_ENV" @@ -358,7 +340,7 @@ jobs: fi # Clean up certificate files - rm -f certificate.p12 AppleWWDRCAG3.cer DeveloperIDG2.cer api_key.p8 || true + rm -f certificate.p12 api_key.p8 || true echo "Cleanup complete" shell: bash -- 2.47.2 From c98b68281eedbf817264f55207d1111d3d6c5183 Mon Sep 17 00:00:00 2001 From: Ozgur Ersoy Date: Sun, 13 Apr 2025 22:52:54 +0200 Subject: [PATCH 036/109] fix(workflows): enhance macOS build workflow with improved keychain handling and certificate management --- .gitea/workflows/test-macos-build.yml | 90 +++++++++++++++++---------- 1 file changed, 56 insertions(+), 34 deletions(-) diff --git a/.gitea/workflows/test-macos-build.yml b/.gitea/workflows/test-macos-build.yml index e914741c..ec8be996 100644 --- a/.gitea/workflows/test-macos-build.yml +++ b/.gitea/workflows/test-macos-build.yml @@ -90,59 +90,85 @@ jobs: env: CERTIFICATE_BASE64: ${{ secrets.MACOS_CERTIFICATE }} CERTIFICATE_PASSWORD: ${{ secrets.MACOS_CERTIFICATE_PWD }} + APPLE_TEAM_ID: ${{ secrets.APPLE_TEAM_ID }} run: | # Debug: Print working directory echo "Current working directory: $(pwd)" echo "Contents of Builds directory:" find Builds -type d | sort - # Create keychain - KEYCHAIN_PATH="${WORKSPACE_DIR}/build.keychain" - KEYCHAIN_PASSWORD="temporary" + # Check what saved builds we have + echo "Contents of Saved/StagedBuilds directory (if exists):" + find ./Saved -type d -name "*.app" 2>/dev/null || echo "No .app bundles found in Saved/" + + # Create temporary directory for keychain and certificates + TEMP_DIR=$(mktemp -d) + KEYCHAIN_PATH="$TEMP_DIR/build.keychain" + KEYCHAIN_PASSWORD="temporary$(date +%s)" + + echo "Creating keychain at: $KEYCHAIN_PATH" # 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" - # Set keychain search list and make it default + # Add to keychain list and make it default security list-keychains -d user -s "$KEYCHAIN_PATH" $(security list-keychains -d user | sed s/\"//g) security default-keychain -s "$KEYCHAIN_PATH" - # Decode and import developer certificate - echo "$CERTIFICATE_BASE64" | base64 --decode > certificate.p12 + # Decode certificate to temporary directory + CERT_PATH="$TEMP_DIR/certificate.p12" + echo "$CERTIFICATE_BASE64" | base64 --decode > "$CERT_PATH" - # Import developer certificate with proper parameters - echo "Importing developer certificate..." - security import certificate.p12 -k "$KEYCHAIN_PATH" -P "$CERTIFICATE_PASSWORD" -T /usr/bin/codesign + # Import certificate with correct flags for automated use + security import "$CERT_PATH" -k "$KEYCHAIN_PATH" -P "$CERTIFICATE_PASSWORD" -A -t cert -f pkcs12 # Set partition list - important for automated signing without UI prompts security set-key-partition-list -S apple-tool:,apple: -s -k "$KEYCHAIN_PASSWORD" "$KEYCHAIN_PATH" - # Verify certificates were imported correctly - echo "Listing imported certificates..." + # Get the certificate's Common Name and SHA-1 fingerprint for signing + echo "Listing available codesigning identities:" security find-identity -v -p codesigning "$KEYCHAIN_PATH" - # Export keychain path and password for later use - echo "KEYCHAIN_PATH=$KEYCHAIN_PATH" >> "$GITHUB_ENV" - echo "KEYCHAIN_PASSWORD=$KEYCHAIN_PASSWORD" >> "$GITHUB_ENV" + # Get the certificate ID (SHA-1 fingerprint) - this is more reliable than using the name + CERT_ID=$(security find-identity -v -p codesigning "$KEYCHAIN_PATH" | grep -o '[0-9A-F]\{40\}' | head -1) - echo "Certificate imported to keychain" + if [ -z "$CERT_ID" ]; then + echo "โš ๏ธ No valid signing certificate found in keychain" + exit 1 + fi + + echo "Using certificate ID: $CERT_ID" + echo "CERT_ID=$CERT_ID" >> "$GITHUB_ENV" + echo "KEYCHAIN_PATH=$KEYCHAIN_PATH" >> "$GITHUB_ENV" + + echo "Certificate imported successfully" shell: bash # Step 4: Find and prep app for signing - name: Find and prep app for signing run: | - # Find app bundle - look everywhere - APP_PATHS=$(find . -type d -name "*.app" 2>/dev/null) + # First check Saved/StagedBuilds directory - where Unreal often places built apps + echo "Checking Saved/StagedBuilds directory..." + APP_PATHS=$(find ./Saved/StagedBuilds -type d -name "*.app" 2>/dev/null) + # If not found, check Builds directory if [ -z "$APP_PATHS" ]; then - # No *.app extension found, look in Builds/Mac directory for any directory - APP_PATHS=$(find ./Builds/Mac -type d -mindepth 1 -maxdepth 1 2>/dev/null) + echo "Checking Builds directory..." + APP_PATHS=$(find ./Builds -type d -name "*.app" 2>/dev/null) + fi + + # If still not found, check the whole workspace + if [ -z "$APP_PATHS" ]; then + echo "Checking entire workspace..." + APP_PATHS=$(find . -type d -name "*.app" -not -path "*/\.*" 2>/dev/null) fi if [ -z "$APP_PATHS" ]; then echo "ERROR: Could not find any app bundles!" + echo "Listing all directories to help debug:" + find . -type d -maxdepth 3 | sort exit 1 fi @@ -169,58 +195,54 @@ jobs: run: | echo "Signing app bundle: $APP_PATH" echo "Using entitlements file: $ENTITLEMENTS_FILE" + echo "Using certificate ID: $CERT_ID" - # First sign PhysX and problematic frameworks specifically (based on forum reports) - echo "๐Ÿ” Signing PhysX and special libraries first..." - find "$APP_PATH" -type f -name "*PhysX*" -o -name "*APEX*" | while read SPECIAL_LIB; do - if [ -f "$SPECIAL_LIB" ]; then - echo "Signing special library: $SPECIAL_LIB" - /usr/bin/codesign -f -v -s "Developer ID Application: $APPLE_TEAM_ID" --options runtime --timestamp "$SPECIAL_LIB" - fi - done + # Make sure keychain is accessible + security unlock-keychain -p "$(security find-generic-password -a ${USER} -s login -w)" login.keychain + security unlock-keychain -p "temporary" "$KEYCHAIN_PATH" || true # Sign all dylib files echo "๐Ÿ” Signing all .dylib files..." find "$APP_PATH" -type f -name "*.dylib" | while read DYLIB; do echo "Signing dylib: $DYLIB" - /usr/bin/codesign -f -v -s "Developer ID Application: $APPLE_TEAM_ID" --options runtime --timestamp "$DYLIB" + codesign --force --options runtime --timestamp --sign "$CERT_ID" "$DYLIB" done # Sign all .so files echo "๐Ÿ” Signing all .so files..." find "$APP_PATH" -type f -name "*.so" | while read SO; do echo "Signing .so: $SO" - /usr/bin/codesign -f -v -s "Developer ID Application: $APPLE_TEAM_ID" --options runtime --timestamp "$SO" + codesign --force --options runtime --timestamp --sign "$CERT_ID" "$SO" done # Sign all executables in frameworks echo "๐Ÿ” Signing framework executables..." find "$APP_PATH" -path "*.framework/*" -type f -perm +111 | while read FMWK_BIN; do echo "Signing framework binary: $FMWK_BIN" - /usr/bin/codesign -f -v -s "Developer ID Application: $APPLE_TEAM_ID" --options runtime --timestamp "$FMWK_BIN" + codesign --force --options runtime --timestamp --sign "$CERT_ID" "$FMWK_BIN" done # Sign all other executables echo "๐Ÿ” Signing other executables..." find "$APP_PATH" -type f -perm +111 -not -path "*.framework/*" -not -name "*.dylib" -not -name "*.so" | while read EXEC; do echo "Signing executable: $EXEC" - /usr/bin/codesign -f -v -s "Developer ID Application: $APPLE_TEAM_ID" --options runtime --timestamp "$EXEC" + codesign --force --options runtime --timestamp --sign "$CERT_ID" "$EXEC" done # Sign all frameworks echo "๐Ÿ” Signing frameworks..." find "$APP_PATH" -name "*.framework" -type d | while read FRAMEWORK; do echo "Signing framework: $FRAMEWORK" - /usr/bin/codesign -f -v -s "Developer ID Application: $APPLE_TEAM_ID" --options runtime --timestamp "$FRAMEWORK" + codesign --force --options runtime --timestamp --sign "$CERT_ID" "$FRAMEWORK" done # Finally sign the app bundle itself with entitlements echo "๐Ÿ” Signing the main app bundle with entitlements..." - /usr/bin/codesign -f -v -s "Developer ID Application: $APPLE_TEAM_ID" --entitlements "$WORKSPACE_DIR/$ENTITLEMENTS_FILE" --options runtime --deep --timestamp "$APP_PATH" + codesign --force --options runtime --deep --timestamp --verbose --sign "$CERT_ID" --entitlements "$WORKSPACE_DIR/$ENTITLEMENTS_FILE" "$APP_PATH" # Verify signature echo "Verifying signature..." - /usr/bin/codesign --verify --verbose "$APP_PATH" + codesign --verify --verbose "$APP_PATH" # Use spctl to check if app is acceptable by Gatekeeper echo "Checking if app will pass Gatekeeper validation..." -- 2.47.2 From 515c4c34b57edcf08082aec0b1be72862945e7aa Mon Sep 17 00:00:00 2001 From: Ozgur Ersoy Date: Sun, 13 Apr 2025 23:52:42 +0200 Subject: [PATCH 037/109] fix(workflows): simplify macOS build workflow with enhanced debugging and direct signing approach --- .gitea/workflows/test-macos-build.yml | 140 +++++++++++--------------- 1 file changed, 56 insertions(+), 84 deletions(-) diff --git a/.gitea/workflows/test-macos-build.yml b/.gitea/workflows/test-macos-build.yml index ec8be996..2dda1929 100644 --- a/.gitea/workflows/test-macos-build.yml +++ b/.gitea/workflows/test-macos-build.yml @@ -85,65 +85,70 @@ jobs: fi shell: bash - # Step 3: Create keychain and import certificate + # Step 3: Create keychain and import certificate - SIMPLIFIED for debugging - name: Create keychain and import certificate env: CERTIFICATE_BASE64: ${{ secrets.MACOS_CERTIFICATE }} CERTIFICATE_PASSWORD: ${{ secrets.MACOS_CERTIFICATE_PWD }} APPLE_TEAM_ID: ${{ secrets.APPLE_TEAM_ID }} run: | - # Debug: Print working directory + # Debug: Print working directory and available resources echo "Current working directory: $(pwd)" echo "Contents of Builds directory:" find Builds -type d | sort - # Check what saved builds we have echo "Contents of Saved/StagedBuilds directory (if exists):" find ./Saved -type d -name "*.app" 2>/dev/null || echo "No .app bundles found in Saved/" - # Create temporary directory for keychain and certificates - TEMP_DIR=$(mktemp -d) - KEYCHAIN_PATH="$TEMP_DIR/build.keychain" - KEYCHAIN_PASSWORD="temporary$(date +%s)" + # Decode certificate to working directory for simplicity + echo "Decoding certificate..." + echo "$CERTIFICATE_BASE64" | base64 --decode > certificate.p12 + ls -la certificate.p12 - echo "Creating keychain at: $KEYCHAIN_PATH" + # Create a simple local keychain + echo "Creating login keychain..." + KEYCHAIN_PATH="$HOME/Library/Keychains/build.keychain-db" + KEYCHAIN_PASSWORD="temp$(date +%s)" - # Create and configure keychain security create-keychain -p "$KEYCHAIN_PASSWORD" "$KEYCHAIN_PATH" - security set-keychain-settings -lut 21600 "$KEYCHAIN_PATH" + security default-keychain -s "$KEYCHAIN_PATH" security unlock-keychain -p "$KEYCHAIN_PASSWORD" "$KEYCHAIN_PATH" - # Add to keychain list and make it default - security list-keychains -d user -s "$KEYCHAIN_PATH" $(security list-keychains -d user | sed s/\"//g) - security default-keychain -s "$KEYCHAIN_PATH" + # Debug import step + echo "Importing certificate with flags: -P [PWD] -k $KEYCHAIN_PATH" + security import certificate.p12 -P "$CERTIFICATE_PASSWORD" -k "$KEYCHAIN_PATH" -T /usr/bin/codesign - # Decode certificate to temporary directory - CERT_PATH="$TEMP_DIR/certificate.p12" - echo "$CERTIFICATE_BASE64" | base64 --decode > "$CERT_PATH" - - # Import certificate with correct flags for automated use - security import "$CERT_PATH" -k "$KEYCHAIN_PATH" -P "$CERTIFICATE_PASSWORD" -A -t cert -f pkcs12 - - # Set partition list - important for automated signing without UI prompts + # Set partition list for automation + echo "Setting key partition list..." security set-key-partition-list -S apple-tool:,apple: -s -k "$KEYCHAIN_PASSWORD" "$KEYCHAIN_PATH" - # Get the certificate's Common Name and SHA-1 fingerprint for signing - echo "Listing available codesigning identities:" + # Check for identities - DEBUG + echo "Listing identities after import:" security find-identity -v -p codesigning "$KEYCHAIN_PATH" - # Get the certificate ID (SHA-1 fingerprint) - this is more reliable than using the name - CERT_ID=$(security find-identity -v -p codesigning "$KEYCHAIN_PATH" | grep -o '[0-9A-F]\{40\}' | head -1) + # Verify Apple Team ID matches certificate + echo "Expected Apple Team ID: $APPLE_TEAM_ID" - if [ -z "$CERT_ID" ]; then - echo "โš ๏ธ No valid signing certificate found in keychain" - exit 1 + # Get a more detailed certificate info for debugging + echo "Certificate details:" + security find-certificate -a -c "Developer ID" -p "$KEYCHAIN_PATH" | openssl x509 -text | grep -E "Subject:|Issuer:|Not Before:|Not After :|Serial Number:" || echo "No certificate details found" + + # Use alternative approach to get signing identity + SIGNING_IDENTITY=$(security find-identity -v -p codesigning "$KEYCHAIN_PATH" | grep "Developer ID Application" | sed -E 's/.*\"Developer ID Application: ([^\"]+).*/\1/g' || echo "") + if [ -z "$SIGNING_IDENTITY" ]; then + # Try with certificate CN directly + SIGNING_IDENTITY="Developer ID Application: $APPLE_TEAM_ID" + echo "Using APPLE_TEAM_ID directly: $SIGNING_IDENTITY" + else + echo "Found signing identity: $SIGNING_IDENTITY" fi - echo "Using certificate ID: $CERT_ID" - echo "CERT_ID=$CERT_ID" >> "$GITHUB_ENV" echo "KEYCHAIN_PATH=$KEYCHAIN_PATH" >> "$GITHUB_ENV" + echo "SIGNING_IDENTITY=$SIGNING_IDENTITY" >> "$GITHUB_ENV" + echo "KEYCHAIN_PASSWORD=$KEYCHAIN_PASSWORD" >> "$GITHUB_ENV" - echo "Certificate imported successfully" + # Add to search list if needed + security list-keychains -d user -s "$KEYCHAIN_PATH" $(security list-keychains -d user | sed s/\"//g) shell: bash # Step 4: Find and prep app for signing @@ -175,83 +180,50 @@ jobs: echo "Found potential app bundles:" echo "$APP_PATHS" - # Use the first app path found - APP_PATH=$(echo "$APP_PATHS" | head -1) + # Use the first app path found (preferably the main app, not a child app) + MAIN_APP_PATH=$(echo "$APP_PATHS" | grep -v "CrashReportClient" | head -1 || echo "$APP_PATHS" | head -1) # Get app name for later use - APP_NAME=$(basename "$APP_PATH") + APP_NAME=$(basename "$MAIN_APP_PATH") - echo "Using app bundle: $APP_PATH" + echo "Using app bundle: $MAIN_APP_PATH" echo "App name: $APP_NAME" - echo "APP_PATH=$APP_PATH" >> "$GITHUB_ENV" + echo "APP_PATH=$MAIN_APP_PATH" >> "$GITHUB_ENV" echo "APP_NAME=$APP_NAME" >> "$GITHUB_ENV" shell: bash - # Step 5: Sign application with codesign - improved based on forums + # Step 5: Sign application with codesign - DIRECT METHOD - name: Sign application env: APPLE_TEAM_ID: ${{ secrets.APPLE_TEAM_ID }} run: | + # Debug info echo "Signing app bundle: $APP_PATH" echo "Using entitlements file: $ENTITLEMENTS_FILE" - echo "Using certificate ID: $CERT_ID" + echo "Using signing identity: $SIGNING_IDENTITY" # Make sure keychain is accessible - security unlock-keychain -p "$(security find-generic-password -a ${USER} -s login -w)" login.keychain - security unlock-keychain -p "temporary" "$KEYCHAIN_PATH" || true + echo "Unlocking keychains..." + security unlock-keychain -p "$KEYCHAIN_PASSWORD" "$KEYCHAIN_PATH" || true - # Sign all dylib files - echo "๐Ÿ” Signing all .dylib files..." - find "$APP_PATH" -type f -name "*.dylib" | while read DYLIB; do - echo "Signing dylib: $DYLIB" - codesign --force --options runtime --timestamp --sign "$CERT_ID" "$DYLIB" - done + # Verify signing identity accessibility + echo "Verifying codesigning identities..." + security find-identity -v -p codesigning "$KEYCHAIN_PATH" - # Sign all .so files - echo "๐Ÿ” Signing all .so files..." - find "$APP_PATH" -type f -name "*.so" | while read SO; do - echo "Signing .so: $SO" - codesign --force --options runtime --timestamp --sign "$CERT_ID" "$SO" - done - - # Sign all executables in frameworks - echo "๐Ÿ” Signing framework executables..." - find "$APP_PATH" -path "*.framework/*" -type f -perm +111 | while read FMWK_BIN; do - echo "Signing framework binary: $FMWK_BIN" - codesign --force --options runtime --timestamp --sign "$CERT_ID" "$FMWK_BIN" - done - - # Sign all other executables - echo "๐Ÿ” Signing other executables..." - find "$APP_PATH" -type f -perm +111 -not -path "*.framework/*" -not -name "*.dylib" -not -name "*.so" | while read EXEC; do - echo "Signing executable: $EXEC" - codesign --force --options runtime --timestamp --sign "$CERT_ID" "$EXEC" - done - - # Sign all frameworks - echo "๐Ÿ” Signing frameworks..." - find "$APP_PATH" -name "*.framework" -type d | while read FRAMEWORK; do - echo "Signing framework: $FRAMEWORK" - codesign --force --options runtime --timestamp --sign "$CERT_ID" "$FRAMEWORK" - done - - # Finally sign the app bundle itself with entitlements - echo "๐Ÿ” Signing the main app bundle with entitlements..." - codesign --force --options runtime --deep --timestamp --verbose --sign "$CERT_ID" --entitlements "$WORKSPACE_DIR/$ENTITLEMENTS_FILE" "$APP_PATH" + # Sign the app directly, with a more direct approach + echo "๐Ÿ” Signing the app bundle with its contents..." + /usr/bin/codesign --force --options runtime --sign "$SIGNING_IDENTITY" --entitlements "$WORKSPACE_DIR/$ENTITLEMENTS_FILE" --deep --verbose "$APP_PATH" # Verify signature echo "Verifying signature..." - codesign --verify --verbose "$APP_PATH" - - # Use spctl to check if app is acceptable by Gatekeeper - echo "Checking if app will pass Gatekeeper validation..." - spctl -vvv --assess --type exec "$APP_PATH" + /usr/bin/codesign --verify --verbose "$APP_PATH" + # Check the result if [ $? -eq 0 ]; then - echo "โœ… Code signing and Gatekeeper validation was successful" + echo "โœ… Code signing was successful" else - echo "โš ๏ธ Gatekeeper validation had warnings, but continuing with notarization" + echo "โš ๏ธ Code signing verification had issues, but continuing with notarization..." fi shell: bash -- 2.47.2 From 80b9aafa69eebb45684518190200b8bca43e625f Mon Sep 17 00:00:00 2001 From: Ozgur Ersoy Date: Mon, 14 Apr 2025 00:28:06 +0200 Subject: [PATCH 038/109] fix(workflows): refine macOS build workflow with improved certificate handling and ad-hoc signing fallback --- .gitea/workflows/test-macos-build.yml | 263 ++++++++------------------ 1 file changed, 82 insertions(+), 181 deletions(-) diff --git a/.gitea/workflows/test-macos-build.yml b/.gitea/workflows/test-macos-build.yml index 2dda1929..8d2fa513 100644 --- a/.gitea/workflows/test-macos-build.yml +++ b/.gitea/workflows/test-macos-build.yml @@ -85,8 +85,8 @@ jobs: fi shell: bash - # Step 3: Create keychain and import certificate - SIMPLIFIED for debugging - - name: Create keychain and import certificate + # Step 3: Try both certificate & Ad-Hoc signing + - name: Prepare certificate or use Ad-Hoc signing env: CERTIFICATE_BASE64: ${{ secrets.MACOS_CERTIFICATE }} CERTIFICATE_PASSWORD: ${{ secrets.MACOS_CERTIFICATE_PWD }} @@ -94,215 +94,116 @@ jobs: run: | # Debug: Print working directory and available resources echo "Current working directory: $(pwd)" - echo "Contents of Builds directory:" - find Builds -type d | sort - echo "Contents of Saved/StagedBuilds directory (if exists):" - find ./Saved -type d -name "*.app" 2>/dev/null || echo "No .app bundles found in Saved/" - - # Decode certificate to working directory for simplicity - echo "Decoding certificate..." - echo "$CERTIFICATE_BASE64" | base64 --decode > certificate.p12 - ls -la certificate.p12 - - # Create a simple local keychain - echo "Creating login keychain..." - KEYCHAIN_PATH="$HOME/Library/Keychains/build.keychain-db" - KEYCHAIN_PASSWORD="temp$(date +%s)" - - security create-keychain -p "$KEYCHAIN_PASSWORD" "$KEYCHAIN_PATH" - security default-keychain -s "$KEYCHAIN_PATH" - security unlock-keychain -p "$KEYCHAIN_PASSWORD" "$KEYCHAIN_PATH" - - # Debug import step - echo "Importing certificate with flags: -P [PWD] -k $KEYCHAIN_PATH" - security import certificate.p12 -P "$CERTIFICATE_PASSWORD" -k "$KEYCHAIN_PATH" -T /usr/bin/codesign - - # Set partition list for automation - echo "Setting key partition list..." - security set-key-partition-list -S apple-tool:,apple: -s -k "$KEYCHAIN_PASSWORD" "$KEYCHAIN_PATH" - - # Check for identities - DEBUG - echo "Listing identities after import:" - security find-identity -v -p codesigning "$KEYCHAIN_PATH" - - # Verify Apple Team ID matches certificate - echo "Expected Apple Team ID: $APPLE_TEAM_ID" - - # Get a more detailed certificate info for debugging - echo "Certificate details:" - security find-certificate -a -c "Developer ID" -p "$KEYCHAIN_PATH" | openssl x509 -text | grep -E "Subject:|Issuer:|Not Before:|Not After :|Serial Number:" || echo "No certificate details found" - - # Use alternative approach to get signing identity - SIGNING_IDENTITY=$(security find-identity -v -p codesigning "$KEYCHAIN_PATH" | grep "Developer ID Application" | sed -E 's/.*\"Developer ID Application: ([^\"]+).*/\1/g' || echo "") - if [ -z "$SIGNING_IDENTITY" ]; then - # Try with certificate CN directly - SIGNING_IDENTITY="Developer ID Application: $APPLE_TEAM_ID" - echo "Using APPLE_TEAM_ID directly: $SIGNING_IDENTITY" - else - echo "Found signing identity: $SIGNING_IDENTITY" - fi - - echo "KEYCHAIN_PATH=$KEYCHAIN_PATH" >> "$GITHUB_ENV" - echo "SIGNING_IDENTITY=$SIGNING_IDENTITY" >> "$GITHUB_ENV" - echo "KEYCHAIN_PASSWORD=$KEYCHAIN_PASSWORD" >> "$GITHUB_ENV" - - # Add to search list if needed - security list-keychains -d user -s "$KEYCHAIN_PATH" $(security list-keychains -d user | sed s/\"//g) - shell: bash - - # Step 4: Find and prep app for signing - - name: Find and prep app for signing - run: | - # First check Saved/StagedBuilds directory - where Unreal often places built apps - echo "Checking Saved/StagedBuilds directory..." + # Find the app bundle to sign APP_PATHS=$(find ./Saved/StagedBuilds -type d -name "*.app" 2>/dev/null) - - # If not found, check Builds directory if [ -z "$APP_PATHS" ]; then - echo "Checking Builds directory..." APP_PATHS=$(find ./Builds -type d -name "*.app" 2>/dev/null) fi - - # If still not found, check the whole workspace if [ -z "$APP_PATHS" ]; then - echo "Checking entire workspace..." - APP_PATHS=$(find . -type d -name "*.app" -not -path "*/\.*" 2>/dev/null) - fi - - if [ -z "$APP_PATHS" ]; then - echo "ERROR: Could not find any app bundles!" - echo "Listing all directories to help debug:" - find . -type d -maxdepth 3 | sort + echo "ERROR: No .app bundle found to sign!" exit 1 fi - echo "Found potential app bundles:" - echo "$APP_PATHS" - # Use the first app path found (preferably the main app, not a child app) MAIN_APP_PATH=$(echo "$APP_PATHS" | grep -v "CrashReportClient" | head -1 || echo "$APP_PATHS" | head -1) - - # Get app name for later use APP_NAME=$(basename "$MAIN_APP_PATH") echo "Using app bundle: $MAIN_APP_PATH" - echo "App name: $APP_NAME" - echo "APP_PATH=$MAIN_APP_PATH" >> "$GITHUB_ENV" echo "APP_NAME=$APP_NAME" >> "$GITHUB_ENV" + + # Create a simple keychain + KEYCHAIN_PASSWORD="temp$(date +%s)" + KEYCHAIN_PATH="$HOME/Library/Keychains/build-temp.keychain-db" + + # First, try to use the provided certificate + echo "Attempting to use provided certificate..." + if [ -n "$CERTIFICATE_BASE64" ] && [ -n "$CERTIFICATE_PASSWORD" ]; then + echo "Certificate data provided, attempting import..." + + # Decode certificate and check format + echo "$CERTIFICATE_BASE64" | base64 --decode > temp-cert.p12 + echo "Certificate file info:" + file temp-cert.p12 + + # Create keychain + security create-keychain -p "$KEYCHAIN_PASSWORD" "$KEYCHAIN_PATH" + security default-keychain -s "$KEYCHAIN_PATH" + security unlock-keychain -p "$KEYCHAIN_PASSWORD" "$KEYCHAIN_PATH" + + # Import with debugging info + echo "Importing certificate into keychain..." + if security import temp-cert.p12 -k "$KEYCHAIN_PATH" -P "$CERTIFICATE_PASSWORD" -T /usr/bin/codesign; then + echo "Certificate imported successfully!" + + # Set partition list + security set-key-partition-list -S apple-tool:,apple: -s -k "$KEYCHAIN_PASSWORD" "$KEYCHAIN_PATH" + + # Check certificate details + echo "Certificate details:" + security find-identity -v -p codesigning "$KEYCHAIN_PATH" + + # If we have a valid identity, use it + if security find-identity -v -p codesigning "$KEYCHAIN_PATH" | grep -q "valid identities found"; then + IDENTITY=$(security find-identity -v -p codesigning "$KEYCHAIN_PATH" | grep -o '"[^"]*"' | head -1 | sed 's/"//g') + echo "Using certificate identity: $IDENTITY" + echo "SIGNING_METHOD=certificate" >> "$GITHUB_ENV" + echo "SIGNING_IDENTITY=$IDENTITY" >> "$GITHUB_ENV" + else + echo "No valid identities found in keychain" + echo "SIGNING_METHOD=ad-hoc" >> "$GITHUB_ENV" + fi + else + echo "Failed to import certificate, will use ad-hoc signing instead" + echo "SIGNING_METHOD=ad-hoc" >> "$GITHUB_ENV" + fi + + # Cleanup certificate file + rm -f temp-cert.p12 + else + echo "Certificate data not provided, will use ad-hoc signing" + echo "SIGNING_METHOD=ad-hoc" >> "$GITHUB_ENV" + fi + + echo "KEYCHAIN_PATH=$KEYCHAIN_PATH" >> "$GITHUB_ENV" + echo "KEYCHAIN_PASSWORD=$KEYCHAIN_PASSWORD" >> "$GITHUB_ENV" shell: bash - # Step 5: Sign application with codesign - DIRECT METHOD + # Step 4: Sign application (with certificate or ad-hoc) - name: Sign application - env: - APPLE_TEAM_ID: ${{ secrets.APPLE_TEAM_ID }} run: | # Debug info echo "Signing app bundle: $APP_PATH" echo "Using entitlements file: $ENTITLEMENTS_FILE" - echo "Using signing identity: $SIGNING_IDENTITY" + echo "Signing method: $SIGNING_METHOD" - # Make sure keychain is accessible - echo "Unlocking keychains..." - security unlock-keychain -p "$KEYCHAIN_PASSWORD" "$KEYCHAIN_PATH" || true - - # Verify signing identity accessibility - echo "Verifying codesigning identities..." - security find-identity -v -p codesigning "$KEYCHAIN_PATH" - - # Sign the app directly, with a more direct approach - echo "๐Ÿ” Signing the app bundle with its contents..." - /usr/bin/codesign --force --options runtime --sign "$SIGNING_IDENTITY" --entitlements "$WORKSPACE_DIR/$ENTITLEMENTS_FILE" --deep --verbose "$APP_PATH" - - # Verify signature - echo "Verifying signature..." - /usr/bin/codesign --verify --verbose "$APP_PATH" - - # Check the result - if [ $? -eq 0 ]; then - echo "โœ… Code signing was successful" - else - echo "โš ๏ธ Code signing verification had issues, but continuing with notarization..." - fi - shell: bash - - # Step 6: Notarize application - - name: Notarize application - env: - API_KEY_PATH: ${{ secrets.NOTARY_API_KEY_PATH }} - API_KEY_ID: ${{ secrets.NOTARY_API_KEY_ID }} - API_KEY_ISSUER_ID: ${{ secrets.NOTARY_API_KEY_ISSUER_ID }} - run: | - echo "Preparing for notarization..." - - # Create API key file - echo "$API_KEY_PATH" | base64 --decode > api_key.p8 - API_KEY_FILE="$(pwd)/api_key.p8" - - # Create a zip archive for notarization - NOTARIZE_APP_PATH="LuckyWorld-notarize.zip" - echo "Creating archive for notarization: $NOTARIZE_APP_PATH" - - # Use ditto to preserve bundle structure - ditto -c -k --keepParent "$APP_PATH" "$NOTARIZE_APP_PATH" - - # Check if zip file was created successfully - if [ ! -f "$NOTARIZE_APP_PATH" ]; then - echo "โŒ Failed to create notarization archive" - exit 1 - fi - - echo "Submitting for notarization..." - echo "API Key ID: $API_KEY_ID" - echo "API Key File: $API_KEY_FILE" - - # Submit for notarization using API key - NOTARIZE_OUTPUT=$(xcrun notarytool submit "$NOTARIZE_APP_PATH" --key "$API_KEY_FILE" --key-id "$API_KEY_ID" --issuer "$API_KEY_ISSUER_ID" --wait) - - echo "Notarization response:" - echo "$NOTARIZE_OUTPUT" - - # Check if notarization was successful - if [[ "$NOTARIZE_OUTPUT" =~ "status: Accepted" ]]; then - echo "โœ… Notarization successful" - else - echo "โš ๏ธ Notarization may have failed. Checking status..." + if [ "$SIGNING_METHOD" = "certificate" ]; then + # Certificate signing + echo "Using certificate signing with identity: $SIGNING_IDENTITY" - # Extract submission ID if available - SUBMISSION_ID=$(echo "$NOTARIZE_OUTPUT" | grep "id:" | awk '{print $2}') + # Unlock keychain + security unlock-keychain -p "$KEYCHAIN_PASSWORD" "$KEYCHAIN_PATH" - if [ -n "$SUBMISSION_ID" ]; then - echo "Checking submission $SUBMISSION_ID..." - xcrun notarytool info "$SUBMISSION_ID" --key "$API_KEY_FILE" --key-id "$API_KEY_ID" --issuer "$API_KEY_ISSUER_ID" - - # Continue even if notarization failed - we'll staple if possible - echo "โš ๏ธ Continuing despite potential notarization issues..." + # Sign the app + if /usr/bin/codesign --force --options runtime --sign "$SIGNING_IDENTITY" --entitlements "$WORKSPACE_DIR/$ENTITLEMENTS_FILE" --deep --verbose "$APP_PATH"; then + echo "โœ… Code signing with certificate was successful" else - echo "โš ๏ธ No submission ID found. Continuing anyway..." + echo "โš ๏ธ Certificate signing failed, falling back to ad-hoc signing" + /usr/bin/codesign --force --options runtime --sign - --entitlements "$WORKSPACE_DIR/$ENTITLEMENTS_FILE" --deep --verbose "$APP_PATH" fi - fi - - # Staple the notarization ticket to the app - echo "Stapling notarization ticket to app..." - xcrun stapler staple "$APP_PATH" - - # Verify stapling - echo "Verifying stapling..." - stapler validate "$APP_PATH" - - if [ $? -eq 0 ]; then - echo "โœ… Stapling successful" else - echo "โš ๏ธ Stapling verification may have failed. This is sometimes expected for new apps." - echo "โš ๏ธ Continuing with packaging..." + # Ad-hoc signing + echo "Using ad-hoc signing (for testing only)" + /usr/bin/codesign --force --options runtime --sign - --entitlements "$WORKSPACE_DIR/$ENTITLEMENTS_FILE" --deep --verbose "$APP_PATH" fi - # Clean up - rm -f "$NOTARIZE_APP_PATH" "$API_KEY_FILE" + # Verify signature (ignore errors) + echo "Verifying signature..." + /usr/bin/codesign --verify --verbose "$APP_PATH" || echo "Verification errors are expected with ad-hoc signing" shell: bash - # Step 7: Package macOS App + # Step 5: Package macOS App - name: Package macOS App run: | echo "Packaging signed app bundle: $APP_PATH" @@ -315,7 +216,7 @@ jobs: ls -la PackagedReleases/ shell: bash - # Step 8: Upload macOS Build Artifact + # Step 6: Upload macOS Build Artifact - name: Upload macOS Build Artifact uses: actions/upload-artifact@v3 if: success() @@ -324,7 +225,7 @@ jobs: path: PackagedReleases/LuckyWorld-macOS.zip retention-days: 365 - # Step 9: Cleanup + # Step 7: Cleanup - name: Cleanup if: always() run: | @@ -334,7 +235,7 @@ jobs: fi # Clean up certificate files - rm -f certificate.p12 api_key.p8 || true + rm -f certificate.p12 api_key.p8 temp-cert.p12 || true echo "Cleanup complete" shell: bash -- 2.47.2 From a7bb4f0bd6a3fdba1c66d774ce06ef1fe953c64b Mon Sep 17 00:00:00 2001 From: Ozgur Ersoy Date: Mon, 14 Apr 2025 00:59:16 +0200 Subject: [PATCH 039/109] fix(workflows): enhance macOS build workflow with detailed debugging for certificate import and fallback signing method --- .gitea/workflows/test-macos-build.yml | 240 ++++++++++++++------------ 1 file changed, 131 insertions(+), 109 deletions(-) diff --git a/.gitea/workflows/test-macos-build.yml b/.gitea/workflows/test-macos-build.yml index 8d2fa513..0ee596fc 100644 --- a/.gitea/workflows/test-macos-build.yml +++ b/.gitea/workflows/test-macos-build.yml @@ -85,8 +85,8 @@ jobs: fi shell: bash - # Step 3: Try both certificate & Ad-Hoc signing - - name: Prepare certificate or use Ad-Hoc signing + # Step 3: Enhanced Debug for Certificate Import + - name: Debug Certificate Import env: CERTIFICATE_BASE64: ${{ secrets.MACOS_CERTIFICATE }} CERTIFICATE_PASSWORD: ${{ secrets.MACOS_CERTIFICATE_PWD }} @@ -94,148 +94,170 @@ jobs: run: | # Debug: Print working directory and available resources echo "Current working directory: $(pwd)" + echo "Contents of Saved/StagedBuilds directory (if exists):" + find ./Saved -type d -name "*.app" 2>/dev/null || echo "No .app bundles found in Saved/" - # Find the app bundle to sign - APP_PATHS=$(find ./Saved/StagedBuilds -type d -name "*.app" 2>/dev/null) - if [ -z "$APP_PATHS" ]; then - APP_PATHS=$(find ./Builds -type d -name "*.app" 2>/dev/null) - fi - if [ -z "$APP_PATHS" ]; then - echo "ERROR: No .app bundle found to sign!" + # Checking system keychains + echo "Examining system keychains and certificates..." + security list-keychains + security default-keychain + + # Decode certificate and examine format - DEBUG + echo "Decoding certificate to debug..." + CERT_DIR="$HOME/certificates" + mkdir -p "$CERT_DIR" + CERT_PATH="$CERT_DIR/developer_certificate.p12" + echo "$CERTIFICATE_BASE64" | base64 --decode > "$CERT_PATH" + + # Check if certificate was properly decoded + if [ -f "$CERT_PATH" ]; then + echo "Certificate was decoded, size: $(wc -c < "$CERT_PATH") bytes" + echo "Certificate file type: $(file "$CERT_PATH")" + else + echo "ERROR: Failed to decode certificate" exit 1 fi + # Trying import with different methods + echo "ATTEMPT 1: Using login keychain" + KEYCHAIN_PASSWORD="$(security find-generic-password -a ${USER} -s login -w)" + security unlock-keychain -p "$KEYCHAIN_PASSWORD" login.keychain + security import "$CERT_PATH" -P "$CERTIFICATE_PASSWORD" -k login.keychain -T /usr/bin/codesign || echo "Import to login keychain failed" + + echo "ATTEMPT 2: Creating custom keychain" + CUSTOM_KEYCHAIN="$CERT_DIR/build.keychain" + CUSTOM_PASSWORD="temppassword123" + security create-keychain -p "$CUSTOM_PASSWORD" "$CUSTOM_KEYCHAIN" + security default-keychain -s "$CUSTOM_KEYCHAIN" + security unlock-keychain -p "$CUSTOM_PASSWORD" "$CUSTOM_KEYCHAIN" + security import "$CERT_PATH" -P "$CERTIFICATE_PASSWORD" -k "$CUSTOM_KEYCHAIN" -T /usr/bin/codesign || echo "Import to custom keychain failed" + + # Add to search list + security list-keychains -d user -s "$CUSTOM_KEYCHAIN" login.keychain + security set-key-partition-list -S apple-tool:,apple: -s -k "$CUSTOM_PASSWORD" "$CUSTOM_KEYCHAIN" + + # Check available identities in both keychains + echo "Checking login keychain for identities:" + security find-identity -v -p codesigning login.keychain || echo "No identities in login keychain" + + echo "Checking custom keychain for identities:" + security find-identity -v -p codesigning "$CUSTOM_KEYCHAIN" || echo "No identities in custom keychain" + + # Fallback solution - use adhoc signing for testing + echo "FALLBACK: Setting up adhoc signing option" + echo "KEYCHAIN_PATH=$CUSTOM_KEYCHAIN" >> "$GITHUB_ENV" + echo "KEYCHAIN_PASSWORD=$CUSTOM_PASSWORD" >> "$GITHUB_ENV" + echo "DIRECT_SIGNING_AVAILABLE=false" >> "$GITHUB_ENV" + + # For debugging only, use a specific team ID if needed + echo "APPLE_TEAM=$APPLE_TEAM_ID" >> "$GITHUB_ENV" + shell: bash + + # Step 4: Find and prep app for signing + - name: Find and prep app for signing + run: | + # First check Saved/StagedBuilds directory - where Unreal often places built apps + echo "Checking Saved/StagedBuilds directory..." + APP_PATHS=$(find ./Saved/StagedBuilds -type d -name "*.app" 2>/dev/null) + + # If not found, check Builds directory + if [ -z "$APP_PATHS" ]; then + echo "Checking Builds directory..." + APP_PATHS=$(find ./Builds -type d -name "*.app" 2>/dev/null) + fi + + # If still not found, check the whole workspace + if [ -z "$APP_PATHS" ]; then + echo "Checking entire workspace..." + APP_PATHS=$(find . -type d -name "*.app" -not -path "*/\.*" 2>/dev/null) + fi + + if [ -z "$APP_PATHS" ]; then + echo "ERROR: Could not find any app bundles!" + echo "Listing all directories to help debug:" + find . -type d -maxdepth 3 | sort + exit 1 + fi + + echo "Found potential app bundles:" + echo "$APP_PATHS" + # Use the first app path found (preferably the main app, not a child app) MAIN_APP_PATH=$(echo "$APP_PATHS" | grep -v "CrashReportClient" | head -1 || echo "$APP_PATHS" | head -1) + + # Get app name for later use APP_NAME=$(basename "$MAIN_APP_PATH") echo "Using app bundle: $MAIN_APP_PATH" + echo "App name: $APP_NAME" + echo "APP_PATH=$MAIN_APP_PATH" >> "$GITHUB_ENV" echo "APP_NAME=$APP_NAME" >> "$GITHUB_ENV" - - # Create a simple keychain - KEYCHAIN_PASSWORD="temp$(date +%s)" - KEYCHAIN_PATH="$HOME/Library/Keychains/build-temp.keychain-db" - - # First, try to use the provided certificate - echo "Attempting to use provided certificate..." - if [ -n "$CERTIFICATE_BASE64" ] && [ -n "$CERTIFICATE_PASSWORD" ]; then - echo "Certificate data provided, attempting import..." - - # Decode certificate and check format - echo "$CERTIFICATE_BASE64" | base64 --decode > temp-cert.p12 - echo "Certificate file info:" - file temp-cert.p12 - - # Create keychain - security create-keychain -p "$KEYCHAIN_PASSWORD" "$KEYCHAIN_PATH" - security default-keychain -s "$KEYCHAIN_PATH" - security unlock-keychain -p "$KEYCHAIN_PASSWORD" "$KEYCHAIN_PATH" - - # Import with debugging info - echo "Importing certificate into keychain..." - if security import temp-cert.p12 -k "$KEYCHAIN_PATH" -P "$CERTIFICATE_PASSWORD" -T /usr/bin/codesign; then - echo "Certificate imported successfully!" - - # Set partition list - security set-key-partition-list -S apple-tool:,apple: -s -k "$KEYCHAIN_PASSWORD" "$KEYCHAIN_PATH" - - # Check certificate details - echo "Certificate details:" - security find-identity -v -p codesigning "$KEYCHAIN_PATH" - - # If we have a valid identity, use it - if security find-identity -v -p codesigning "$KEYCHAIN_PATH" | grep -q "valid identities found"; then - IDENTITY=$(security find-identity -v -p codesigning "$KEYCHAIN_PATH" | grep -o '"[^"]*"' | head -1 | sed 's/"//g') - echo "Using certificate identity: $IDENTITY" - echo "SIGNING_METHOD=certificate" >> "$GITHUB_ENV" - echo "SIGNING_IDENTITY=$IDENTITY" >> "$GITHUB_ENV" - else - echo "No valid identities found in keychain" - echo "SIGNING_METHOD=ad-hoc" >> "$GITHUB_ENV" - fi - else - echo "Failed to import certificate, will use ad-hoc signing instead" - echo "SIGNING_METHOD=ad-hoc" >> "$GITHUB_ENV" - fi - - # Cleanup certificate file - rm -f temp-cert.p12 - else - echo "Certificate data not provided, will use ad-hoc signing" - echo "SIGNING_METHOD=ad-hoc" >> "$GITHUB_ENV" - fi - - echo "KEYCHAIN_PATH=$KEYCHAIN_PATH" >> "$GITHUB_ENV" - echo "KEYCHAIN_PASSWORD=$KEYCHAIN_PASSWORD" >> "$GITHUB_ENV" shell: bash - # Step 4: Sign application (with certificate or ad-hoc) - - name: Sign application + # Step 5: Sign application with alternative fallback + - name: Sign application + env: + APPLE_TEAM_ID: ${{ secrets.APPLE_TEAM_ID }} run: | # Debug info echo "Signing app bundle: $APP_PATH" echo "Using entitlements file: $ENTITLEMENTS_FILE" - echo "Signing method: $SIGNING_METHOD" - if [ "$SIGNING_METHOD" = "certificate" ]; then - # Certificate signing - echo "Using certificate signing with identity: $SIGNING_IDENTITY" - - # Unlock keychain - security unlock-keychain -p "$KEYCHAIN_PASSWORD" "$KEYCHAIN_PATH" - - # Sign the app - if /usr/bin/codesign --force --options runtime --sign "$SIGNING_IDENTITY" --entitlements "$WORKSPACE_DIR/$ENTITLEMENTS_FILE" --deep --verbose "$APP_PATH"; then - echo "โœ… Code signing with certificate was successful" - else - echo "โš ๏ธ Certificate signing failed, falling back to ad-hoc signing" - /usr/bin/codesign --force --options runtime --sign - --entitlements "$WORKSPACE_DIR/$ENTITLEMENTS_FILE" --deep --verbose "$APP_PATH" - fi - else - # Ad-hoc signing - echo "Using ad-hoc signing (for testing only)" - /usr/bin/codesign --force --options runtime --sign - --entitlements "$WORKSPACE_DIR/$ENTITLEMENTS_FILE" --deep --verbose "$APP_PATH" - fi + # === TEST MODE: Using -SIGNED TEST ONLY- === # + echo "โš ๏ธ CERTIFICATE IMPORT FAILED: Using test-only signing approach" + echo "This is for testing the workflow only and will NOT produce a valid signed build" - # Verify signature (ignore errors) - echo "Verifying signature..." - /usr/bin/codesign --verify --verbose "$APP_PATH" || echo "Verification errors are expected with ad-hoc signing" + # For testing ONLY - using `-` identity (ad-hoc signing) + # This doesn't require a certificate but won't pass notarization + echo "๐Ÿ” Test-signing the app with ad-hoc identity..." + /usr/bin/codesign --force --deep --verbose --sign "-" --entitlements "$WORKSPACE_DIR/$ENTITLEMENTS_FILE" "$APP_PATH" || true + + echo "โœ… Test signing completed. Note: This is NOT a properly signed app!" + echo "NEEDS_REAL_CERT=true" >> "$GITHUB_ENV" + + # Recommendation for production + echo "โš ๏ธ IMPORTANT: For production builds, please ensure your certificate is correctly configured." + echo "โš ๏ธ Check the following:" + echo " 1. Certificate format is correct (PKCS#12)" + echo " 2. Certificate password is correct" + echo " 3. Team ID matches the certificate" shell: bash - # Step 5: Package macOS App - - name: Package macOS App + # Step 6: Skip Notarization (since we're not properly signed) + - name: Package macOS App (Test Only) run: | - echo "Packaging signed app bundle: $APP_PATH" + echo "โš ๏ธ SKIPPING NOTARIZATION - test build only" + echo "Packaging unsigned test app bundle: $APP_PATH" # Create zip package - (cd "$(dirname "$APP_PATH")" && zip -r "${WORKSPACE_DIR}/PackagedReleases/LuckyWorld-macOS.zip" "$(basename "$APP_PATH")") + (cd "$(dirname "$APP_PATH")" && zip -r "${WORKSPACE_DIR}/PackagedReleases/LuckyWorld-macOS-UNSIGNED-TEST.zip" "$(basename "$APP_PATH")") - echo "Created packaged release: PackagedReleases/LuckyWorld-macOS.zip" - echo "Packaged releases:" - ls -la PackagedReleases/ + echo "Created test package: PackagedReleases/LuckyWorld-macOS-UNSIGNED-TEST.zip" + echo "NOTE: This package is NOT properly signed and will NOT pass Gatekeeper!" + + echo "Debug certificate summary:" + echo "- Check if your p12 file is valid" + echo "- Verify certificate password in secrets" + echo "- Confirm Apple Developer Team ID is correct" shell: bash - # Step 6: Upload macOS Build Artifact - - name: Upload macOS Build Artifact + # Step 7: Upload test artifact + - name: Upload Test Build Artifact uses: actions/upload-artifact@v3 if: success() with: - name: LuckyWorld-macOS - path: PackagedReleases/LuckyWorld-macOS.zip - retention-days: 365 + name: LuckyWorld-macOS-UNSIGNED-TEST + path: PackagedReleases/LuckyWorld-macOS-UNSIGNED-TEST.zip + retention-days: 7 - # Step 7: Cleanup + # Step 8: Cleanup - name: Cleanup if: always() run: | # Clean up keychain and certificates - if [ -n "$KEYCHAIN_PATH" ]; then - security delete-keychain "$KEYCHAIN_PATH" || true - fi - - # Clean up certificate files - rm -f certificate.p12 api_key.p8 temp-cert.p12 || true + rm -rf "$HOME/certificates" || true + security delete-keychain "$HOME/certificates/build.keychain" || true echo "Cleanup complete" shell: bash -- 2.47.2 From 4088c8d37a13caa3931cf13a20ecabb10d473d23 Mon Sep 17 00:00:00 2001 From: Ozgur Date: Mon, 14 Apr 2025 11:08:01 +0000 Subject: [PATCH 040/109] Update .gitea/workflows/test-macos-build.yml --- .gitea/workflows/test-macos-build.yml | 49 +++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) diff --git a/.gitea/workflows/test-macos-build.yml b/.gitea/workflows/test-macos-build.yml index 0ee596fc..22750983 100644 --- a/.gitea/workflows/test-macos-build.yml +++ b/.gitea/workflows/test-macos-build.yml @@ -85,6 +85,55 @@ jobs: fi shell: bash +- name: Debug Certificate Import2 + env: + CERTIFICATE_BASE64: ${{ secrets.MACOS_CERTIFICATE }} + CERTIFICATE_PASSWORD: ${{ secrets.MACOS_CERTIFICATE_PWD }} + APPLE_TEAM_ID: ${{ secrets.APPLE_TEAM_ID }} + run: | + set -e # Fail on any error + + echo "Current working directory: $(pwd)" + echo "Checking for .app bundles in Saved directory..." + find ./Saved -type d -name "*.app" || echo "No app bundles found." + + echo "Decoding certificate..." + CERT_DIR="$HOME/certificates" + mkdir -p "$CERT_DIR" + CERT_PATH="$CERT_DIR/developer_certificate.p12" + echo "$CERTIFICATE_BASE64" | base64 --decode > "$CERT_PATH" + + echo "Decoded certificate size: $(wc -c < "$CERT_PATH") bytes" + echo "Type: $(file "$CERT_PATH")" + + echo "Creating and configuring custom keychain..." + CUSTOM_KEYCHAIN="$CERT_DIR/build.keychain" + CUSTOM_PASSWORD="temppassword123" + + security create-keychain -p "$CUSTOM_PASSWORD" "$CUSTOM_KEYCHAIN" + security set-keychain-settings "$CUSTOM_KEYCHAIN" + security unlock-keychain -p "$CUSTOM_PASSWORD" "$CUSTOM_KEYCHAIN" + + echo "Setting only this keychain as active..." + security list-keychains -s "$CUSTOM_KEYCHAIN" + security default-keychain -s "$CUSTOM_KEYCHAIN" + + echo "Importing certificate..." + security import "$CERT_PATH" -P "$CERTIFICATE_PASSWORD" -k "$CUSTOM_KEYCHAIN" -T /usr/bin/codesign + + echo "Granting access to codesign..." + security set-key-partition-list -S apple-tool:,apple: -s -k "$CUSTOM_PASSWORD" "$CUSTOM_KEYCHAIN" + + echo "Verifying imported identities..." + security find-identity -v -p codesigning "$CUSTOM_KEYCHAIN" + + echo "Setting environment variables for future steps..." + echo "KEYCHAIN_PATH=$CUSTOM_KEYCHAIN" >> "$GITHUB_ENV" + echo "KEYCHAIN_PASSWORD=$CUSTOM_PASSWORD" >> "$GITHUB_ENV" + echo "DIRECT_SIGNING_AVAILABLE=true" >> "$GITHUB_ENV" + echo "APPLE_TEAM=$APPLE_TEAM_ID" >> "$GITHUB_ENV" + shell: bash + # Step 3: Enhanced Debug for Certificate Import - name: Debug Certificate Import env: -- 2.47.2 From 8c02d550fba0c799791b27d37118f9a7129de35e Mon Sep 17 00:00:00 2001 From: Ozgur Ersoy Date: Mon, 14 Apr 2025 13:50:05 +0200 Subject: [PATCH 041/109] fix(workflows): add detailed debugging for certificate import in macOS build workflow --- .gitea/workflows/test-macos-build.yml | 97 ++++++++++++++------------- 1 file changed, 49 insertions(+), 48 deletions(-) diff --git a/.gitea/workflows/test-macos-build.yml b/.gitea/workflows/test-macos-build.yml index 22750983..00a14dc1 100644 --- a/.gitea/workflows/test-macos-build.yml +++ b/.gitea/workflows/test-macos-build.yml @@ -73,6 +73,55 @@ jobs: WORKSPACE_DIR="$(pwd)" echo "WORKSPACE_DIR=$WORKSPACE_DIR" >> "$GITHUB_ENV" shell: bash + + - name: Debug Certificate Import (Test) + env: + CERTIFICATE_BASE64: ${{ secrets.MACOS_CERTIFICATE }} + CERTIFICATE_PASSWORD: ${{ secrets.MACOS_CERTIFICATE_PWD }} + APPLE_TEAM_ID: ${{ secrets.APPLE_TEAM_ID }} + run: | + set -e # Fail on any error + + echo "Current working directory: $(pwd)" + echo "Checking for .app bundles in Saved directory..." + find ./Saved -type d -name "*.app" || echo "No app bundles found." + + echo "Decoding certificate..." + CERT_DIR="$HOME/certificates" + mkdir -p "$CERT_DIR" + CERT_PATH="$CERT_DIR/developer_certificate.p12" + echo "$CERTIFICATE_BASE64" | base64 --decode > "$CERT_PATH" + + echo "Decoded certificate size: $(wc -c < "$CERT_PATH") bytes" + echo "Type: $(file "$CERT_PATH")" + + echo "Creating and configuring custom keychain..." + CUSTOM_KEYCHAIN="$CERT_DIR/build.keychain" + CUSTOM_PASSWORD="temppassword123" + + security create-keychain -p "$CUSTOM_PASSWORD" "$CUSTOM_KEYCHAIN" + security set-keychain-settings "$CUSTOM_KEYCHAIN" + security unlock-keychain -p "$CUSTOM_PASSWORD" "$CUSTOM_KEYCHAIN" + + echo "Setting only this keychain as active..." + security list-keychains -s "$CUSTOM_KEYCHAIN" + security default-keychain -s "$CUSTOM_KEYCHAIN" + + echo "Importing certificate..." + security import "$CERT_PATH" -P "$CERTIFICATE_PASSWORD" -k "$CUSTOM_KEYCHAIN" -T /usr/bin/codesign + + echo "Granting access to codesign..." + security set-key-partition-list -S apple-tool:,apple: -s -k "$CUSTOM_PASSWORD" "$CUSTOM_KEYCHAIN" + + echo "Verifying imported identities..." + security find-identity -v -p codesigning "$CUSTOM_KEYCHAIN" + + echo "Setting environment variables for future steps..." + echo "KEYCHAIN_PATH=$CUSTOM_KEYCHAIN" >> "$GITHUB_ENV" + echo "KEYCHAIN_PASSWORD=$CUSTOM_PASSWORD" >> "$GITHUB_ENV" + echo "DIRECT_SIGNING_AVAILABLE=true" >> "$GITHUB_ENV" + echo "APPLE_TEAM=$APPLE_TEAM_ID" >> "$GITHUB_ENV" + shell: bash # Step 2: Build for macOS - name: Build for macOS @@ -84,55 +133,7 @@ jobs: echo "Build script not found, skipping this step" fi shell: bash - -- name: Debug Certificate Import2 - env: - CERTIFICATE_BASE64: ${{ secrets.MACOS_CERTIFICATE }} - CERTIFICATE_PASSWORD: ${{ secrets.MACOS_CERTIFICATE_PWD }} - APPLE_TEAM_ID: ${{ secrets.APPLE_TEAM_ID }} - run: | - set -e # Fail on any error - echo "Current working directory: $(pwd)" - echo "Checking for .app bundles in Saved directory..." - find ./Saved -type d -name "*.app" || echo "No app bundles found." - - echo "Decoding certificate..." - CERT_DIR="$HOME/certificates" - mkdir -p "$CERT_DIR" - CERT_PATH="$CERT_DIR/developer_certificate.p12" - echo "$CERTIFICATE_BASE64" | base64 --decode > "$CERT_PATH" - - echo "Decoded certificate size: $(wc -c < "$CERT_PATH") bytes" - echo "Type: $(file "$CERT_PATH")" - - echo "Creating and configuring custom keychain..." - CUSTOM_KEYCHAIN="$CERT_DIR/build.keychain" - CUSTOM_PASSWORD="temppassword123" - - security create-keychain -p "$CUSTOM_PASSWORD" "$CUSTOM_KEYCHAIN" - security set-keychain-settings "$CUSTOM_KEYCHAIN" - security unlock-keychain -p "$CUSTOM_PASSWORD" "$CUSTOM_KEYCHAIN" - - echo "Setting only this keychain as active..." - security list-keychains -s "$CUSTOM_KEYCHAIN" - security default-keychain -s "$CUSTOM_KEYCHAIN" - - echo "Importing certificate..." - security import "$CERT_PATH" -P "$CERTIFICATE_PASSWORD" -k "$CUSTOM_KEYCHAIN" -T /usr/bin/codesign - - echo "Granting access to codesign..." - security set-key-partition-list -S apple-tool:,apple: -s -k "$CUSTOM_PASSWORD" "$CUSTOM_KEYCHAIN" - - echo "Verifying imported identities..." - security find-identity -v -p codesigning "$CUSTOM_KEYCHAIN" - - echo "Setting environment variables for future steps..." - echo "KEYCHAIN_PATH=$CUSTOM_KEYCHAIN" >> "$GITHUB_ENV" - echo "KEYCHAIN_PASSWORD=$CUSTOM_PASSWORD" >> "$GITHUB_ENV" - echo "DIRECT_SIGNING_AVAILABLE=true" >> "$GITHUB_ENV" - echo "APPLE_TEAM=$APPLE_TEAM_ID" >> "$GITHUB_ENV" - shell: bash # Step 3: Enhanced Debug for Certificate Import - name: Debug Certificate Import -- 2.47.2 From 70e17b52ecb4625539d4e2afa5901e485ce7b1aa Mon Sep 17 00:00:00 2001 From: Ozgur Ersoy Date: Mon, 14 Apr 2025 14:10:12 +0200 Subject: [PATCH 042/109] feat(workflows): add test local signing workflow for macOS --- .gitea/workflows/test-local-signing-2.yml | 195 ++++++++++++++++++++++ .gitea/workflows/test-macos-build.yml | 4 +- 2 files changed, 197 insertions(+), 2 deletions(-) create mode 100644 .gitea/workflows/test-local-signing-2.yml diff --git a/.gitea/workflows/test-local-signing-2.yml b/.gitea/workflows/test-local-signing-2.yml new file mode 100644 index 00000000..11ea73e1 --- /dev/null +++ b/.gitea/workflows/test-local-signing-2.yml @@ -0,0 +1,195 @@ +name: Test Local Signing + +on: + workflow_dispatch: # Manuel tetikleme + push: + branches: [ozgur/build] + +jobs: + test-local-signing: + runs-on: macos + steps: + - name: Checkout repository + uses: actions/checkout@v3 + + - name: Create Test Certificate + run: | + echo "๐Ÿ”‘ Creating test certificate and keychain..." + + # Test iรงin gerekli dizinleri oluลŸtur + CERT_DIR="$HOME/certificates" + mkdir -p "$CERT_DIR" + + # Test keychain oluลŸtur + KEYCHAIN_PATH="$CERT_DIR/test.keychain" + KEYCHAIN_PASSWORD="test123" + + security create-keychain -p "$KEYCHAIN_PASSWORD" "$KEYCHAIN_PATH" + security default-keychain -s "$KEYCHAIN_PATH" + security unlock-keychain -p "$KEYCHAIN_PASSWORD" "$KEYCHAIN_PATH" + + # Test sertifikasฤฑ oluลŸtur + cd "$CERT_DIR" + + echo "๐Ÿ“œ Creating self-signed certificate..." + CERT_NAME="Test LuckyWorld Developer" + openssl req -x509 -newkey rsa:2048 \ + -keyout test_key.pem \ + -out test_cert.pem \ + -days 365 \ + -nodes \ + -subj "/CN=$CERT_NAME" + + echo "๐Ÿ” Converting to P12 format..." + CERT_PASSWORD="test123" + openssl pkcs12 -export \ + -out test_cert.p12 \ + -inkey test_key.pem \ + -in test_cert.pem \ + -password pass:$CERT_PASSWORD + + echo "๐Ÿ“‹ Creating base64 version for reference..." + cat test_cert.p12 | base64 > test_cert_base64.txt + + echo "๐Ÿ”„ Importing certificate to keychain..." + security import test_cert.p12 \ + -k "$KEYCHAIN_PATH" \ + -P "$CERT_PASSWORD" \ + -T /usr/bin/codesign + + # Keychain'i codesign iรงin hazฤฑrla + security set-key-partition-list \ + -S apple-tool:,apple: \ + -s \ + -k "$KEYCHAIN_PASSWORD" "$KEYCHAIN_PATH" + + # Environment variables kaydet + echo "KEYCHAIN_PATH=$KEYCHAIN_PATH" >> "$GITHUB_ENV" + echo "CERT_NAME=$CERT_NAME" >> "$GITHUB_ENV" + echo "WORKSPACE_DIR=$(pwd)" >> "$GITHUB_ENV" + + echo "โœ… Certificate setup complete" + + # Debug: Sertifika bilgilerini gรถster + echo "๐Ÿ” Checking codesigning identities..." + security find-identity -v -p codesigning "$KEYCHAIN_PATH" + shell: bash + + - name: Verify Certificate + run: | + echo "๐Ÿ” Verifying certificate in keychain..." + security find-identity -v -p codesigning "$KEYCHAIN_PATH" + + # Detaylฤฑ sertifika bilgilerini gรถster + echo "๐Ÿ“‹ Certificate details:" + security find-certificate -a -c "$CERT_NAME" -p "$KEYCHAIN_PATH" | \ + openssl x509 -text | \ + grep -E "Subject:|Issuer:|Not Before:|Not After:|Serial Number:" + shell: bash + + - name: Create Test Entitlements + run: | + echo "๐Ÿ“ Creating test entitlements file..." + cat > LuckyWorld.entitlements << EOF + + + + + com.apple.security.cs.allow-jit + + com.apple.security.cs.allow-unsigned-executable-memory + + com.apple.security.cs.disable-library-validation + + com.apple.security.cs.allow-dyld-environment-variables + + com.apple.security.device.audio-input + + com.apple.security.device.camera + + + + EOF + + echo "โœ… Created entitlements file" + cat LuckyWorld.entitlements + shell: bash + + - name: Create Test App Bundle + run: | + echo "๐Ÿ“ฆ Creating test app bundle..." + + # Test app bundle oluลŸtur + TEST_APP_DIR="TestApp.app" + mkdir -p "$TEST_APP_DIR/Contents/MacOS" + + # Basit bir test executable oluลŸtur + echo '#!/bin/bash + echo "Hello from TestApp!"' > "$TEST_APP_DIR/Contents/MacOS/TestApp" + chmod +x "$TEST_APP_DIR/Contents/MacOS/TestApp" + + # Info.plist oluลŸtur + cat > "$TEST_APP_DIR/Contents/Info.plist" << EOF + + + + + CFBundleExecutable + TestApp + CFBundleIdentifier + com.luckyworld.testapp + CFBundleName + TestApp + CFBundlePackageType + APPL + CFBundleShortVersionString + 1.0 + LSMinimumSystemVersion + 10.10 + + + EOF + + echo "โœ… Created test app bundle" + echo "APP_PATH=$TEST_APP_DIR" >> "$GITHUB_ENV" + shell: bash + + - name: Test Signing + run: | + echo "๐Ÿ” Testing code signing..." + + # Keychain'i hazฤฑrla + security unlock-keychain -p "test123" "$KEYCHAIN_PATH" + + echo "๐Ÿ“ Signing app bundle with test certificate..." + /usr/bin/codesign --force --deep --verbose \ + --sign "$CERT_NAME" \ + --entitlements "LuckyWorld.entitlements" \ + "$APP_PATH" + + echo "โœ… Signing complete" + + echo "๐Ÿ” Verifying signature..." + codesign -vv -d "$APP_PATH" + + echo "๐Ÿ“‹ Checking entitlements..." + codesign -d --entitlements :- "$APP_PATH" + + echo "๐Ÿ”’ Testing Gatekeeper assessment (will fail, this is expected)..." + spctl --assess --type exec "$APP_PATH" || true + shell: bash + + - name: Cleanup + if: always() + run: | + echo "๐Ÿงน Cleaning up..." + + # Keychain temizle + security delete-keychain "$KEYCHAIN_PATH" || true + + # Test dosyalarฤฑnฤฑ temizle + rm -rf "$HOME/certificates" || true + rm -rf TestApp.app || true + + echo "โœ… Cleanup complete" + shell: bash \ No newline at end of file diff --git a/.gitea/workflows/test-macos-build.yml b/.gitea/workflows/test-macos-build.yml index 00a14dc1..f179daf4 100644 --- a/.gitea/workflows/test-macos-build.yml +++ b/.gitea/workflows/test-macos-build.yml @@ -2,8 +2,8 @@ name: Test macOS Build Action on: workflow_dispatch: # Manual trigger only for testing - push: - branches: [ozgur/build] + # push: + # branches: [ozgur/build] jobs: test-macos-build: -- 2.47.2 From ca648fa87102a1c4ebb58a8f6f0688d9456060db Mon Sep 17 00:00:00 2001 From: Ozgur Ersoy Date: Mon, 14 Apr 2025 14:11:32 +0200 Subject: [PATCH 043/109] feat(workflows): create test local signing workflow for macOS with certificate setup and notarization --- ...l-signing-2.yml => test-local-signing.yml} | 133 ++++++++++-------- 1 file changed, 78 insertions(+), 55 deletions(-) rename .gitea/workflows/{test-local-signing-2.yml => test-local-signing.yml} (59%) diff --git a/.gitea/workflows/test-local-signing-2.yml b/.gitea/workflows/test-local-signing.yml similarity index 59% rename from .gitea/workflows/test-local-signing-2.yml rename to .gitea/workflows/test-local-signing.yml index 11ea73e1..4fc1920b 100644 --- a/.gitea/workflows/test-local-signing-2.yml +++ b/.gitea/workflows/test-local-signing.yml @@ -1,9 +1,9 @@ name: Test Local Signing on: - workflow_dispatch: # Manuel tetikleme + workflow_dispatch: # Manual trigger push: - branches: [ozgur/build] + branches: [test/signing] jobs: test-local-signing: @@ -12,66 +12,57 @@ jobs: - name: Checkout repository uses: actions/checkout@v3 - - name: Create Test Certificate + - name: Setup Certificate + env: + CERTIFICATE_BASE64: ${{ secrets.MACOS_CERTIFICATE }} + CERTIFICATE_PASSWORD: ${{ secrets.MACOS_CERTIFICATE_PWD }} + APPLE_TEAM_ID: ${{ secrets.APPLE_TEAM_ID }} run: | - echo "๐Ÿ”‘ Creating test certificate and keychain..." + echo "๐Ÿ”‘ Setting up certificate and keychain..." - # Test iรงin gerekli dizinleri oluลŸtur + # Create working directory CERT_DIR="$HOME/certificates" mkdir -p "$CERT_DIR" + cd "$CERT_DIR" - # Test keychain oluลŸtur - KEYCHAIN_PATH="$CERT_DIR/test.keychain" - KEYCHAIN_PASSWORD="test123" + # Decode certificate + echo "๐Ÿ“œ Decoding certificate..." + echo "$CERTIFICATE_BASE64" | base64 --decode > certificate.p12 + # Check certificate info + echo "๐Ÿ” Certificate info:" + file certificate.p12 + + # Create keychain + KEYCHAIN_PATH="$CERT_DIR/build.keychain" + KEYCHAIN_PASSWORD="temporary$(date +%s)" + + echo "๐Ÿ” Creating keychain: $KEYCHAIN_PATH" security create-keychain -p "$KEYCHAIN_PASSWORD" "$KEYCHAIN_PATH" security default-keychain -s "$KEYCHAIN_PATH" security unlock-keychain -p "$KEYCHAIN_PASSWORD" "$KEYCHAIN_PATH" - # Test sertifikasฤฑ oluลŸtur - cd "$CERT_DIR" - - echo "๐Ÿ“œ Creating self-signed certificate..." - CERT_NAME="Test LuckyWorld Developer" - openssl req -x509 -newkey rsa:2048 \ - -keyout test_key.pem \ - -out test_cert.pem \ - -days 365 \ - -nodes \ - -subj "/CN=$CERT_NAME" - - echo "๐Ÿ” Converting to P12 format..." - CERT_PASSWORD="test123" - openssl pkcs12 -export \ - -out test_cert.p12 \ - -inkey test_key.pem \ - -in test_cert.pem \ - -password pass:$CERT_PASSWORD - - echo "๐Ÿ“‹ Creating base64 version for reference..." - cat test_cert.p12 | base64 > test_cert_base64.txt - - echo "๐Ÿ”„ Importing certificate to keychain..." - security import test_cert.p12 \ + # Import certificate + echo "๐Ÿ“ฅ Importing certificate..." + security import certificate.p12 \ -k "$KEYCHAIN_PATH" \ - -P "$CERT_PASSWORD" \ + -P "$CERTIFICATE_PASSWORD" \ -T /usr/bin/codesign - # Keychain'i codesign iรงin hazฤฑrla + # Configure keychain settings security set-key-partition-list \ -S apple-tool:,apple: \ -s \ -k "$KEYCHAIN_PASSWORD" "$KEYCHAIN_PATH" - # Environment variables kaydet + # Save environment variables echo "KEYCHAIN_PATH=$KEYCHAIN_PATH" >> "$GITHUB_ENV" - echo "CERT_NAME=$CERT_NAME" >> "$GITHUB_ENV" + echo "KEYCHAIN_PASSWORD=$KEYCHAIN_PASSWORD" >> "$GITHUB_ENV" + echo "APPLE_TEAM_ID=$APPLE_TEAM_ID" >> "$GITHUB_ENV" echo "WORKSPACE_DIR=$(pwd)" >> "$GITHUB_ENV" - echo "โœ… Certificate setup complete" - - # Debug: Sertifika bilgilerini gรถster - echo "๐Ÿ” Checking codesigning identities..." + # Check certificate status + echo "โœ… Checking codesigning identities..." security find-identity -v -p codesigning "$KEYCHAIN_PATH" shell: bash @@ -80,16 +71,15 @@ jobs: echo "๐Ÿ” Verifying certificate in keychain..." security find-identity -v -p codesigning "$KEYCHAIN_PATH" - # Detaylฤฑ sertifika bilgilerini gรถster echo "๐Ÿ“‹ Certificate details:" - security find-certificate -a -c "$CERT_NAME" -p "$KEYCHAIN_PATH" | \ + security find-certificate -a -c "Developer ID Application" -p "$KEYCHAIN_PATH" | \ openssl x509 -text | \ grep -E "Subject:|Issuer:|Not Before:|Not After:|Serial Number:" shell: bash - name: Create Test Entitlements run: | - echo "๐Ÿ“ Creating test entitlements file..." + echo "๐Ÿ“ Creating entitlements file..." cat > LuckyWorld.entitlements << EOF @@ -119,16 +109,16 @@ jobs: run: | echo "๐Ÿ“ฆ Creating test app bundle..." - # Test app bundle oluลŸtur + # Create test app bundle structure TEST_APP_DIR="TestApp.app" mkdir -p "$TEST_APP_DIR/Contents/MacOS" - # Basit bir test executable oluลŸtur + # Create a simple test executable echo '#!/bin/bash echo "Hello from TestApp!"' > "$TEST_APP_DIR/Contents/MacOS/TestApp" chmod +x "$TEST_APP_DIR/Contents/MacOS/TestApp" - # Info.plist oluลŸtur + # Create Info.plist cat > "$TEST_APP_DIR/Contents/Info.plist" << EOF @@ -158,12 +148,16 @@ jobs: run: | echo "๐Ÿ” Testing code signing..." - # Keychain'i hazฤฑrla - security unlock-keychain -p "test123" "$KEYCHAIN_PATH" + # Prepare keychain + security unlock-keychain -p "$KEYCHAIN_PASSWORD" "$KEYCHAIN_PATH" - echo "๐Ÿ“ Signing app bundle with test certificate..." + # Find signing identity + SIGNING_IDENTITY="Developer ID Application: $APPLE_TEAM_ID" + echo "Using signing identity: $SIGNING_IDENTITY" + + echo "๐Ÿ“ Signing app bundle..." /usr/bin/codesign --force --deep --verbose \ - --sign "$CERT_NAME" \ + --sign "$SIGNING_IDENTITY" \ --entitlements "LuckyWorld.entitlements" \ "$APP_PATH" @@ -175,8 +169,37 @@ jobs: echo "๐Ÿ“‹ Checking entitlements..." codesign -d --entitlements :- "$APP_PATH" - echo "๐Ÿ”’ Testing Gatekeeper assessment (will fail, this is expected)..." - spctl --assess --type exec "$APP_PATH" || true + echo "๐Ÿ”’ Testing Gatekeeper assessment..." + spctl --assess --type exec "$APP_PATH" + shell: bash + + - name: Test Notarization + env: + API_KEY_PATH: ${{ secrets.NOTARY_API_KEY_PATH }} + API_KEY_ID: ${{ secrets.NOTARY_API_KEY_ID }} + API_KEY_ISSUER_ID: ${{ secrets.NOTARY_API_KEY_ISSUER_ID }} + run: | + if [ -n "$API_KEY_PATH" ] && [ -n "$API_KEY_ID" ] && [ -n "$API_KEY_ISSUER_ID" ]; then + echo "๐Ÿ” Testing notarization..." + + # Create API key file + echo "$API_KEY_PATH" | base64 --decode > api_key.p8 + + # Zip test app + ditto -c -k --keepParent "$APP_PATH" "TestApp.zip" + + # Test notarization + xcrun notarytool submit "TestApp.zip" \ + --key "api_key.p8" \ + --key-id "$API_KEY_ID" \ + --issuer "$API_KEY_ISSUER_ID" \ + --wait + + # Cleanup + rm -f api_key.p8 TestApp.zip + else + echo "โš ๏ธ Notarization secrets not found, skipping notarization test" + fi shell: bash - name: Cleanup @@ -184,10 +207,10 @@ jobs: run: | echo "๐Ÿงน Cleaning up..." - # Keychain temizle + # Clean up keychain security delete-keychain "$KEYCHAIN_PATH" || true - # Test dosyalarฤฑnฤฑ temizle + # Clean up test files rm -rf "$HOME/certificates" || true rm -rf TestApp.app || true -- 2.47.2 From 52bb9a0f7b432f5cd342a6ab7753652fc9789c07 Mon Sep 17 00:00:00 2001 From: Ozgur Ersoy Date: Mon, 14 Apr 2025 14:12:36 +0200 Subject: [PATCH 044/109] trigger --- .gitea/workflows/test-local-signing.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitea/workflows/test-local-signing.yml b/.gitea/workflows/test-local-signing.yml index 4fc1920b..46aea581 100644 --- a/.gitea/workflows/test-local-signing.yml +++ b/.gitea/workflows/test-local-signing.yml @@ -3,7 +3,7 @@ name: Test Local Signing on: workflow_dispatch: # Manual trigger push: - branches: [test/signing] + branches: [ozgur/build] jobs: test-local-signing: -- 2.47.2 From 8dcb496b3c30f8db014ca6e504eee117bdf02672 Mon Sep 17 00:00:00 2001 From: Ozgur Ersoy Date: Mon, 14 Apr 2025 14:14:51 +0200 Subject: [PATCH 045/109] fix(workflows): improve keychain handling and identity extraction in local signing workflow --- .gitea/workflows/test-local-signing.yml | 46 +++++++++++++++++-------- 1 file changed, 32 insertions(+), 14 deletions(-) diff --git a/.gitea/workflows/test-local-signing.yml b/.gitea/workflows/test-local-signing.yml index 46aea581..2645638d 100644 --- a/.gitea/workflows/test-local-signing.yml +++ b/.gitea/workflows/test-local-signing.yml @@ -33,25 +33,33 @@ jobs: echo "๐Ÿ” Certificate info:" file certificate.p12 - # Create keychain - KEYCHAIN_PATH="$CERT_DIR/build.keychain" - KEYCHAIN_PASSWORD="temporary$(date +%s)" + # Create keychain with a fixed password + KEYCHAIN_PATH="$CERT_DIR/build.keychain-db" + KEYCHAIN_PASSWORD="keychainpassword" echo "๐Ÿ” Creating keychain: $KEYCHAIN_PATH" security create-keychain -p "$KEYCHAIN_PASSWORD" "$KEYCHAIN_PATH" + + # Configure keychain settings + security set-keychain-settings -t 3600 -l "$KEYCHAIN_PATH" + + # Add to keychain list and make it default + security list-keychains -d user -s "$KEYCHAIN_PATH" $(security list-keychains -d user | sed s/\"//g) security default-keychain -s "$KEYCHAIN_PATH" security unlock-keychain -p "$KEYCHAIN_PASSWORD" "$KEYCHAIN_PATH" - # Import certificate + # Import certificate with all access rights echo "๐Ÿ“ฅ Importing certificate..." security import certificate.p12 \ -k "$KEYCHAIN_PATH" \ -P "$CERTIFICATE_PASSWORD" \ - -T /usr/bin/codesign + -T "/usr/bin/codesign" \ + -T "/usr/bin/security" \ + -T "/usr/bin/xcrun" - # Configure keychain settings + # Update keychain partition list security set-key-partition-list \ - -S apple-tool:,apple: \ + -S apple-tool:,apple:,codesign: \ -s \ -k "$KEYCHAIN_PASSWORD" "$KEYCHAIN_PATH" @@ -61,14 +69,26 @@ jobs: echo "APPLE_TEAM_ID=$APPLE_TEAM_ID" >> "$GITHUB_ENV" echo "WORKSPACE_DIR=$(pwd)" >> "$GITHUB_ENV" - # Check certificate status + # Check certificate status and get identity echo "โœ… Checking codesigning identities..." security find-identity -v -p codesigning "$KEYCHAIN_PATH" + + # Extract the identity hash for signing + IDENTITY_HASH=$(security find-identity -v -p codesigning "$KEYCHAIN_PATH" | grep "Developer ID Application" | head -1 | awk '{print $2}') + if [ -n "$IDENTITY_HASH" ]; then + echo "Found identity hash: $IDENTITY_HASH" + echo "IDENTITY_HASH=$IDENTITY_HASH" >> "$GITHUB_ENV" + else + echo "No valid identity hash found" + security find-identity -v -p codesigning "$KEYCHAIN_PATH" + exit 1 + fi shell: bash - name: Verify Certificate run: | echo "๐Ÿ” Verifying certificate in keychain..." + security unlock-keychain -p "$KEYCHAIN_PASSWORD" "$KEYCHAIN_PATH" security find-identity -v -p codesigning "$KEYCHAIN_PATH" echo "๐Ÿ“‹ Certificate details:" @@ -151,13 +171,11 @@ jobs: # Prepare keychain security unlock-keychain -p "$KEYCHAIN_PASSWORD" "$KEYCHAIN_PATH" - # Find signing identity - SIGNING_IDENTITY="Developer ID Application: $APPLE_TEAM_ID" - echo "Using signing identity: $SIGNING_IDENTITY" - - echo "๐Ÿ“ Signing app bundle..." + # Use identity hash directly for signing + echo "๐Ÿ“ Signing app bundle with identity hash: $IDENTITY_HASH" /usr/bin/codesign --force --deep --verbose \ - --sign "$SIGNING_IDENTITY" \ + --keychain "$KEYCHAIN_PATH" \ + --sign "$IDENTITY_HASH" \ --entitlements "LuckyWorld.entitlements" \ "$APP_PATH" -- 2.47.2 From adfc8fc5493119ca7fc1a4299cf48621846ab42c Mon Sep 17 00:00:00 2001 From: Ozgur Ersoy Date: Mon, 14 Apr 2025 14:15:29 +0200 Subject: [PATCH 046/109] fix(workflows): update environment variable references from GITHUB_ENV to GITEA_ENV in local signing workflow --- .gitea/workflows/test-local-signing.yml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/.gitea/workflows/test-local-signing.yml b/.gitea/workflows/test-local-signing.yml index 2645638d..8a6e0b9f 100644 --- a/.gitea/workflows/test-local-signing.yml +++ b/.gitea/workflows/test-local-signing.yml @@ -64,10 +64,10 @@ jobs: -k "$KEYCHAIN_PASSWORD" "$KEYCHAIN_PATH" # Save environment variables - echo "KEYCHAIN_PATH=$KEYCHAIN_PATH" >> "$GITHUB_ENV" - echo "KEYCHAIN_PASSWORD=$KEYCHAIN_PASSWORD" >> "$GITHUB_ENV" - echo "APPLE_TEAM_ID=$APPLE_TEAM_ID" >> "$GITHUB_ENV" - echo "WORKSPACE_DIR=$(pwd)" >> "$GITHUB_ENV" + echo "KEYCHAIN_PATH=$KEYCHAIN_PATH" >> "$GITEA_ENV" + echo "KEYCHAIN_PASSWORD=$KEYCHAIN_PASSWORD" >> "$GITEA_ENV" + echo "APPLE_TEAM_ID=$APPLE_TEAM_ID" >> "$GITEA_ENV" + echo "WORKSPACE_DIR=$(pwd)" >> "$GITEA_ENV" # Check certificate status and get identity echo "โœ… Checking codesigning identities..." @@ -77,7 +77,7 @@ jobs: IDENTITY_HASH=$(security find-identity -v -p codesigning "$KEYCHAIN_PATH" | grep "Developer ID Application" | head -1 | awk '{print $2}') if [ -n "$IDENTITY_HASH" ]; then echo "Found identity hash: $IDENTITY_HASH" - echo "IDENTITY_HASH=$IDENTITY_HASH" >> "$GITHUB_ENV" + echo "IDENTITY_HASH=$IDENTITY_HASH" >> "$GITEA_ENV" else echo "No valid identity hash found" security find-identity -v -p codesigning "$KEYCHAIN_PATH" @@ -161,7 +161,7 @@ jobs: EOF echo "โœ… Created test app bundle" - echo "APP_PATH=$TEST_APP_DIR" >> "$GITHUB_ENV" + echo "APP_PATH=$TEST_APP_DIR" >> "$GITEA_ENV" shell: bash - name: Test Signing -- 2.47.2 From 7a15d3e35a6306558f53ca6321bb8ddd06331056 Mon Sep 17 00:00:00 2001 From: Ozgur Ersoy Date: Mon, 14 Apr 2025 14:18:24 +0200 Subject: [PATCH 047/109] fix(workflows): update environment variable references from GITEA_ENV to GITHUB_ENV in local signing workflow --- .gitea/workflows/test-local-signing.yml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/.gitea/workflows/test-local-signing.yml b/.gitea/workflows/test-local-signing.yml index 8a6e0b9f..2645638d 100644 --- a/.gitea/workflows/test-local-signing.yml +++ b/.gitea/workflows/test-local-signing.yml @@ -64,10 +64,10 @@ jobs: -k "$KEYCHAIN_PASSWORD" "$KEYCHAIN_PATH" # Save environment variables - echo "KEYCHAIN_PATH=$KEYCHAIN_PATH" >> "$GITEA_ENV" - echo "KEYCHAIN_PASSWORD=$KEYCHAIN_PASSWORD" >> "$GITEA_ENV" - echo "APPLE_TEAM_ID=$APPLE_TEAM_ID" >> "$GITEA_ENV" - echo "WORKSPACE_DIR=$(pwd)" >> "$GITEA_ENV" + echo "KEYCHAIN_PATH=$KEYCHAIN_PATH" >> "$GITHUB_ENV" + echo "KEYCHAIN_PASSWORD=$KEYCHAIN_PASSWORD" >> "$GITHUB_ENV" + echo "APPLE_TEAM_ID=$APPLE_TEAM_ID" >> "$GITHUB_ENV" + echo "WORKSPACE_DIR=$(pwd)" >> "$GITHUB_ENV" # Check certificate status and get identity echo "โœ… Checking codesigning identities..." @@ -77,7 +77,7 @@ jobs: IDENTITY_HASH=$(security find-identity -v -p codesigning "$KEYCHAIN_PATH" | grep "Developer ID Application" | head -1 | awk '{print $2}') if [ -n "$IDENTITY_HASH" ]; then echo "Found identity hash: $IDENTITY_HASH" - echo "IDENTITY_HASH=$IDENTITY_HASH" >> "$GITEA_ENV" + echo "IDENTITY_HASH=$IDENTITY_HASH" >> "$GITHUB_ENV" else echo "No valid identity hash found" security find-identity -v -p codesigning "$KEYCHAIN_PATH" @@ -161,7 +161,7 @@ jobs: EOF echo "โœ… Created test app bundle" - echo "APP_PATH=$TEST_APP_DIR" >> "$GITEA_ENV" + echo "APP_PATH=$TEST_APP_DIR" >> "$GITHUB_ENV" shell: bash - name: Test Signing -- 2.47.2 From 87f14be9a657ef8105ef2ddd13b996fe3441b8ea Mon Sep 17 00:00:00 2001 From: Ozgur Ersoy Date: Mon, 14 Apr 2025 14:19:21 +0200 Subject: [PATCH 048/109] fix(workflows): enhance local signing workflow with keychain access verification and debugging --- .gitea/workflows/test-local-signing.yml | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/.gitea/workflows/test-local-signing.yml b/.gitea/workflows/test-local-signing.yml index 2645638d..091bee06 100644 --- a/.gitea/workflows/test-local-signing.yml +++ b/.gitea/workflows/test-local-signing.yml @@ -55,7 +55,8 @@ jobs: -P "$CERTIFICATE_PASSWORD" \ -T "/usr/bin/codesign" \ -T "/usr/bin/security" \ - -T "/usr/bin/xcrun" + -T "/usr/bin/xcrun" \ + -A # Update keychain partition list security set-key-partition-list \ @@ -63,6 +64,14 @@ jobs: -s \ -k "$KEYCHAIN_PASSWORD" "$KEYCHAIN_PATH" + # Allow codesign to access the keychain + security unlock-keychain -p "$KEYCHAIN_PASSWORD" "$KEYCHAIN_PATH" + security set-key-partition-list -S apple-tool:,apple:,codesign: -s -k "$KEYCHAIN_PASSWORD" "$KEYCHAIN_PATH" + + # Verify certificate access + echo "๐Ÿ” Verifying certificate access..." + security find-identity -v -p codesigning "$KEYCHAIN_PATH" + # Save environment variables echo "KEYCHAIN_PATH=$KEYCHAIN_PATH" >> "$GITHUB_ENV" echo "KEYCHAIN_PASSWORD=$KEYCHAIN_PASSWORD" >> "$GITHUB_ENV" @@ -80,7 +89,9 @@ jobs: echo "IDENTITY_HASH=$IDENTITY_HASH" >> "$GITHUB_ENV" else echo "No valid identity hash found" + echo "๐Ÿ” Debugging certificate access..." security find-identity -v -p codesigning "$KEYCHAIN_PATH" + security find-certificate -a -c "Developer ID Application" -p "$KEYCHAIN_PATH" exit 1 fi shell: bash -- 2.47.2 From 26e782b4b1ac466d820c8c76cd0cf3fc32a8f2d0 Mon Sep 17 00:00:00 2001 From: Ozgur Ersoy Date: Mon, 14 Apr 2025 14:20:18 +0200 Subject: [PATCH 049/109] fix(workflows): add Apple root certificates download and import to local signing workflow --- .gitea/workflows/test-local-signing.yml | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/.gitea/workflows/test-local-signing.yml b/.gitea/workflows/test-local-signing.yml index 091bee06..cc74e870 100644 --- a/.gitea/workflows/test-local-signing.yml +++ b/.gitea/workflows/test-local-signing.yml @@ -48,15 +48,23 @@ jobs: security default-keychain -s "$KEYCHAIN_PATH" security unlock-keychain -p "$KEYCHAIN_PASSWORD" "$KEYCHAIN_PATH" + # Download and import Apple root certificates + echo "๐Ÿ“ฅ Downloading Apple root certificates..." + curl -O https://www.apple.com/certificateauthority/AppleWWDRCAG3.cer + curl -O https://www.apple.com/certificateauthority/DeveloperIDG2.cer + + echo "๐Ÿ” Importing Apple root certificates..." + security import AppleWWDRCAG3.cer -k "$KEYCHAIN_PATH" -T /usr/bin/codesign + security import DeveloperIDG2.cer -k "$KEYCHAIN_PATH" -T /usr/bin/codesign + # Import certificate with all access rights - echo "๐Ÿ“ฅ Importing certificate..." + echo "๐Ÿ“ฅ Importing developer certificate..." security import certificate.p12 \ -k "$KEYCHAIN_PATH" \ -P "$CERTIFICATE_PASSWORD" \ -T "/usr/bin/codesign" \ -T "/usr/bin/security" \ - -T "/usr/bin/xcrun" \ - -A + -T "/usr/bin/xcrun" # Update keychain partition list security set-key-partition-list \ -- 2.47.2 From 4125cb2ff4080dcbab965824e8c0c085514eacbc Mon Sep 17 00:00:00 2001 From: Ozgur Ersoy Date: Mon, 14 Apr 2025 14:21:31 +0200 Subject: [PATCH 050/109] fix(workflows): update Apple certificate import commands to include format flags in local signing workflow --- .gitea/workflows/test-local-signing.yml | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/.gitea/workflows/test-local-signing.yml b/.gitea/workflows/test-local-signing.yml index cc74e870..01ab80da 100644 --- a/.gitea/workflows/test-local-signing.yml +++ b/.gitea/workflows/test-local-signing.yml @@ -54,8 +54,8 @@ jobs: curl -O https://www.apple.com/certificateauthority/DeveloperIDG2.cer echo "๐Ÿ” Importing Apple root certificates..." - security import AppleWWDRCAG3.cer -k "$KEYCHAIN_PATH" -T /usr/bin/codesign - security import DeveloperIDG2.cer -k "$KEYCHAIN_PATH" -T /usr/bin/codesign + security import AppleWWDRCAG3.cer -k "$KEYCHAIN_PATH" -T /usr/bin/codesign -f der + security import DeveloperIDG2.cer -k "$KEYCHAIN_PATH" -T /usr/bin/codesign -f der # Import certificate with all access rights echo "๐Ÿ“ฅ Importing developer certificate..." @@ -64,7 +64,8 @@ jobs: -P "$CERTIFICATE_PASSWORD" \ -T "/usr/bin/codesign" \ -T "/usr/bin/security" \ - -T "/usr/bin/xcrun" + -T "/usr/bin/xcrun" \ + -f pkcs12 # Update keychain partition list security set-key-partition-list \ -- 2.47.2 From 8b1443bbadf83dc650a384770191f390b8b556b9 Mon Sep 17 00:00:00 2001 From: Ozgur Ersoy Date: Mon, 14 Apr 2025 14:22:14 +0200 Subject: [PATCH 051/109] trigger --- .gitea/workflows/test-local-signing.yml | 178 ++---------------------- 1 file changed, 11 insertions(+), 167 deletions(-) diff --git a/.gitea/workflows/test-local-signing.yml b/.gitea/workflows/test-local-signing.yml index 01ab80da..f7e91941 100644 --- a/.gitea/workflows/test-local-signing.yml +++ b/.gitea/workflows/test-local-signing.yml @@ -12,111 +12,6 @@ jobs: - name: Checkout repository uses: actions/checkout@v3 - - name: Setup Certificate - env: - CERTIFICATE_BASE64: ${{ secrets.MACOS_CERTIFICATE }} - CERTIFICATE_PASSWORD: ${{ secrets.MACOS_CERTIFICATE_PWD }} - APPLE_TEAM_ID: ${{ secrets.APPLE_TEAM_ID }} - run: | - echo "๐Ÿ”‘ Setting up certificate and keychain..." - - # Create working directory - CERT_DIR="$HOME/certificates" - mkdir -p "$CERT_DIR" - cd "$CERT_DIR" - - # Decode certificate - echo "๐Ÿ“œ Decoding certificate..." - echo "$CERTIFICATE_BASE64" | base64 --decode > certificate.p12 - - # Check certificate info - echo "๐Ÿ” Certificate info:" - file certificate.p12 - - # Create keychain with a fixed password - KEYCHAIN_PATH="$CERT_DIR/build.keychain-db" - KEYCHAIN_PASSWORD="keychainpassword" - - echo "๐Ÿ” Creating keychain: $KEYCHAIN_PATH" - security create-keychain -p "$KEYCHAIN_PASSWORD" "$KEYCHAIN_PATH" - - # Configure keychain settings - security set-keychain-settings -t 3600 -l "$KEYCHAIN_PATH" - - # Add to keychain list and make it default - security list-keychains -d user -s "$KEYCHAIN_PATH" $(security list-keychains -d user | sed s/\"//g) - security default-keychain -s "$KEYCHAIN_PATH" - security unlock-keychain -p "$KEYCHAIN_PASSWORD" "$KEYCHAIN_PATH" - - # Download and import Apple root certificates - echo "๐Ÿ“ฅ Downloading Apple root certificates..." - curl -O https://www.apple.com/certificateauthority/AppleWWDRCAG3.cer - curl -O https://www.apple.com/certificateauthority/DeveloperIDG2.cer - - echo "๐Ÿ” Importing Apple root certificates..." - security import AppleWWDRCAG3.cer -k "$KEYCHAIN_PATH" -T /usr/bin/codesign -f der - security import DeveloperIDG2.cer -k "$KEYCHAIN_PATH" -T /usr/bin/codesign -f der - - # Import certificate with all access rights - echo "๐Ÿ“ฅ Importing developer certificate..." - security import certificate.p12 \ - -k "$KEYCHAIN_PATH" \ - -P "$CERTIFICATE_PASSWORD" \ - -T "/usr/bin/codesign" \ - -T "/usr/bin/security" \ - -T "/usr/bin/xcrun" \ - -f pkcs12 - - # Update keychain partition list - security set-key-partition-list \ - -S apple-tool:,apple:,codesign: \ - -s \ - -k "$KEYCHAIN_PASSWORD" "$KEYCHAIN_PATH" - - # Allow codesign to access the keychain - security unlock-keychain -p "$KEYCHAIN_PASSWORD" "$KEYCHAIN_PATH" - security set-key-partition-list -S apple-tool:,apple:,codesign: -s -k "$KEYCHAIN_PASSWORD" "$KEYCHAIN_PATH" - - # Verify certificate access - echo "๐Ÿ” Verifying certificate access..." - security find-identity -v -p codesigning "$KEYCHAIN_PATH" - - # Save environment variables - echo "KEYCHAIN_PATH=$KEYCHAIN_PATH" >> "$GITHUB_ENV" - echo "KEYCHAIN_PASSWORD=$KEYCHAIN_PASSWORD" >> "$GITHUB_ENV" - echo "APPLE_TEAM_ID=$APPLE_TEAM_ID" >> "$GITHUB_ENV" - echo "WORKSPACE_DIR=$(pwd)" >> "$GITHUB_ENV" - - # Check certificate status and get identity - echo "โœ… Checking codesigning identities..." - security find-identity -v -p codesigning "$KEYCHAIN_PATH" - - # Extract the identity hash for signing - IDENTITY_HASH=$(security find-identity -v -p codesigning "$KEYCHAIN_PATH" | grep "Developer ID Application" | head -1 | awk '{print $2}') - if [ -n "$IDENTITY_HASH" ]; then - echo "Found identity hash: $IDENTITY_HASH" - echo "IDENTITY_HASH=$IDENTITY_HASH" >> "$GITHUB_ENV" - else - echo "No valid identity hash found" - echo "๐Ÿ” Debugging certificate access..." - security find-identity -v -p codesigning "$KEYCHAIN_PATH" - security find-certificate -a -c "Developer ID Application" -p "$KEYCHAIN_PATH" - exit 1 - fi - shell: bash - - - name: Verify Certificate - run: | - echo "๐Ÿ” Verifying certificate in keychain..." - security unlock-keychain -p "$KEYCHAIN_PASSWORD" "$KEYCHAIN_PATH" - security find-identity -v -p codesigning "$KEYCHAIN_PATH" - - echo "๐Ÿ“‹ Certificate details:" - security find-certificate -a -c "Developer ID Application" -p "$KEYCHAIN_PATH" | \ - openssl x509 -text | \ - grep -E "Subject:|Issuer:|Not Before:|Not After:|Serial Number:" - shell: bash - - name: Create Test Entitlements run: | echo "๐Ÿ“ Creating entitlements file..." @@ -184,73 +79,22 @@ jobs: echo "APP_PATH=$TEST_APP_DIR" >> "$GITHUB_ENV" shell: bash - - name: Test Signing - run: | - echo "๐Ÿ” Testing code signing..." - - # Prepare keychain - security unlock-keychain -p "$KEYCHAIN_PASSWORD" "$KEYCHAIN_PATH" - - # Use identity hash directly for signing - echo "๐Ÿ“ Signing app bundle with identity hash: $IDENTITY_HASH" - /usr/bin/codesign --force --deep --verbose \ - --keychain "$KEYCHAIN_PATH" \ - --sign "$IDENTITY_HASH" \ - --entitlements "LuckyWorld.entitlements" \ - "$APP_PATH" - - echo "โœ… Signing complete" - - echo "๐Ÿ” Verifying signature..." - codesign -vv -d "$APP_PATH" - - echo "๐Ÿ“‹ Checking entitlements..." - codesign -d --entitlements :- "$APP_PATH" - - echo "๐Ÿ”’ Testing Gatekeeper assessment..." - spctl --assess --type exec "$APP_PATH" - shell: bash - - - name: Test Notarization - env: - API_KEY_PATH: ${{ secrets.NOTARY_API_KEY_PATH }} - API_KEY_ID: ${{ secrets.NOTARY_API_KEY_ID }} - API_KEY_ISSUER_ID: ${{ secrets.NOTARY_API_KEY_ISSUER_ID }} - run: | - if [ -n "$API_KEY_PATH" ] && [ -n "$API_KEY_ID" ] && [ -n "$API_KEY_ISSUER_ID" ]; then - echo "๐Ÿ” Testing notarization..." - - # Create API key file - echo "$API_KEY_PATH" | base64 --decode > api_key.p8 - - # Zip test app - ditto -c -k --keepParent "$APP_PATH" "TestApp.zip" - - # Test notarization - xcrun notarytool submit "TestApp.zip" \ - --key "api_key.p8" \ - --key-id "$API_KEY_ID" \ - --issuer "$API_KEY_ISSUER_ID" \ - --wait - - # Cleanup - rm -f api_key.p8 TestApp.zip - else - echo "โš ๏ธ Notarization secrets not found, skipping notarization test" - fi - shell: bash + - name: Sign and Notarize App + uses: lando/code-sign-action@v3 + with: + file: ${{ env.APP_PATH }} + certificate-data: ${{ secrets.MACOS_CERTIFICATE }} + certificate-password: ${{ secrets.MACOS_CERTIFICATE_PWD }} + apple-team-id: ${{ secrets.APPLE_TEAM_ID }} + apple-notary-user: ${{ secrets.APPLE_NOTARY_USER }} + apple-notary-password: ${{ secrets.APPLE_NOTARY_PASSWORD }} + apple-product-id: com.luckyworld.testapp + options: --options runtime --entitlements LuckyWorld.entitlements - name: Cleanup if: always() run: | echo "๐Ÿงน Cleaning up..." - - # Clean up keychain - security delete-keychain "$KEYCHAIN_PATH" || true - - # Clean up test files - rm -rf "$HOME/certificates" || true rm -rf TestApp.app || true - echo "โœ… Cleanup complete" shell: bash \ No newline at end of file -- 2.47.2 From c1c352f30c1eb8076e1c19264a3cee3b2715ce00 Mon Sep 17 00:00:00 2001 From: Ozgur Ersoy Date: Mon, 14 Apr 2025 14:23:07 +0200 Subject: [PATCH 052/109] trigger 2 --- .gitea/workflows/test-local-signing.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitea/workflows/test-local-signing.yml b/.gitea/workflows/test-local-signing.yml index f7e91941..e5c4ca5c 100644 --- a/.gitea/workflows/test-local-signing.yml +++ b/.gitea/workflows/test-local-signing.yml @@ -76,7 +76,7 @@ jobs: EOF echo "โœ… Created test app bundle" - echo "APP_PATH=$TEST_APP_DIR" >> "$GITHUB_ENV" + echo "APP_PATH=$(pwd)/$TEST_APP_DIR" >> "$GITHUB_ENV" shell: bash - name: Sign and Notarize App -- 2.47.2 From 24d51f2c4003a9b76a733ce6844b3ba67b245d18 Mon Sep 17 00:00:00 2001 From: Ozgur Ersoy Date: Mon, 14 Apr 2025 14:24:08 +0200 Subject: [PATCH 053/109] fix(workflows): improve app bundle verification and logging in local signing workflow --- .gitea/workflows/test-local-signing.yml | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/.gitea/workflows/test-local-signing.yml b/.gitea/workflows/test-local-signing.yml index e5c4ca5c..46840e11 100644 --- a/.gitea/workflows/test-local-signing.yml +++ b/.gitea/workflows/test-local-signing.yml @@ -76,13 +76,22 @@ jobs: EOF echo "โœ… Created test app bundle" - echo "APP_PATH=$(pwd)/$TEST_APP_DIR" >> "$GITHUB_ENV" + echo "APP_PATH=$TEST_APP_DIR" >> "$GITHUB_ENV" + + # Verify app bundle exists + if [ ! -d "$TEST_APP_DIR" ]; then + echo "โŒ Error: App bundle not found at $TEST_APP_DIR" + exit 1 + fi + + echo "๐Ÿ” App bundle contents:" + ls -la "$TEST_APP_DIR" shell: bash - name: Sign and Notarize App uses: lando/code-sign-action@v3 with: - file: ${{ env.APP_PATH }} + file: TestApp.app certificate-data: ${{ secrets.MACOS_CERTIFICATE }} certificate-password: ${{ secrets.MACOS_CERTIFICATE_PWD }} apple-team-id: ${{ secrets.APPLE_TEAM_ID }} -- 2.47.2 From 30b3e678cac41693a505971845b7c064fa4a8279 Mon Sep 17 00:00:00 2001 From: Ozgur Ersoy Date: Mon, 14 Apr 2025 14:28:18 +0200 Subject: [PATCH 054/109] fix(workflows): update local signing workflow to include App Store Connect API key handling and improve notarization process --- .gitea/workflows/test-local-signing.yml | 26 ++++++++++++++++--------- 1 file changed, 17 insertions(+), 9 deletions(-) diff --git a/.gitea/workflows/test-local-signing.yml b/.gitea/workflows/test-local-signing.yml index 46840e11..3134c1e0 100644 --- a/.gitea/workflows/test-local-signing.yml +++ b/.gitea/workflows/test-local-signing.yml @@ -88,22 +88,30 @@ jobs: ls -la "$TEST_APP_DIR" shell: bash + - name: Install App Store Connect API Key + run: | + mkdir -p private_keys/ + echo '${{ secrets.APPLE_NOTARY_API_KEY }}' > private_keys/AuthKey_${{ secrets.APPLE_NOTARY_API_KEY_ID }}.p8 + shell: bash + - name: Sign and Notarize App - uses: lando/code-sign-action@v3 + uses: indygreg/apple-code-sign-action@v1 with: - file: TestApp.app - certificate-data: ${{ secrets.MACOS_CERTIFICATE }} - certificate-password: ${{ secrets.MACOS_CERTIFICATE_PWD }} - apple-team-id: ${{ secrets.APPLE_TEAM_ID }} - apple-notary-user: ${{ secrets.APPLE_NOTARY_USER }} - apple-notary-password: ${{ secrets.APPLE_NOTARY_PASSWORD }} - apple-product-id: com.luckyworld.testapp - options: --options runtime --entitlements LuckyWorld.entitlements + input_path: TestApp.app + output_path: TestApp.app + notarize: true + staple: true + p12_file: certificate.p12 + p12_password: ${{ secrets.MACOS_CERTIFICATE_PWD }} + app_store_connect_api_issuer: ${{ secrets.APPLE_NOTARY_API_ISSUER_ID }} + app_store_connect_api_key: ${{ secrets.APPLE_NOTARY_API_KEY_ID }} + entitlements: LuckyWorld.entitlements - name: Cleanup if: always() run: | echo "๐Ÿงน Cleaning up..." rm -rf TestApp.app || true + rm -rf private_keys || true echo "โœ… Cleanup complete" shell: bash \ No newline at end of file -- 2.47.2 From 3711f6db96731950232de2aba71f067b9db80100 Mon Sep 17 00:00:00 2001 From: Ozgur Ersoy Date: Mon, 14 Apr 2025 14:29:58 +0200 Subject: [PATCH 055/109] fix(workflows): update local signing workflow to use new code signing action and improve notarization options --- .gitea/workflows/test-local-signing.yml | 26 +++++++++---------------- 1 file changed, 9 insertions(+), 17 deletions(-) diff --git a/.gitea/workflows/test-local-signing.yml b/.gitea/workflows/test-local-signing.yml index 3134c1e0..46840e11 100644 --- a/.gitea/workflows/test-local-signing.yml +++ b/.gitea/workflows/test-local-signing.yml @@ -88,30 +88,22 @@ jobs: ls -la "$TEST_APP_DIR" shell: bash - - name: Install App Store Connect API Key - run: | - mkdir -p private_keys/ - echo '${{ secrets.APPLE_NOTARY_API_KEY }}' > private_keys/AuthKey_${{ secrets.APPLE_NOTARY_API_KEY_ID }}.p8 - shell: bash - - name: Sign and Notarize App - uses: indygreg/apple-code-sign-action@v1 + uses: lando/code-sign-action@v3 with: - input_path: TestApp.app - output_path: TestApp.app - notarize: true - staple: true - p12_file: certificate.p12 - p12_password: ${{ secrets.MACOS_CERTIFICATE_PWD }} - app_store_connect_api_issuer: ${{ secrets.APPLE_NOTARY_API_ISSUER_ID }} - app_store_connect_api_key: ${{ secrets.APPLE_NOTARY_API_KEY_ID }} - entitlements: LuckyWorld.entitlements + file: TestApp.app + certificate-data: ${{ secrets.MACOS_CERTIFICATE }} + certificate-password: ${{ secrets.MACOS_CERTIFICATE_PWD }} + apple-team-id: ${{ secrets.APPLE_TEAM_ID }} + apple-notary-user: ${{ secrets.APPLE_NOTARY_USER }} + apple-notary-password: ${{ secrets.APPLE_NOTARY_PASSWORD }} + apple-product-id: com.luckyworld.testapp + options: --options runtime --entitlements LuckyWorld.entitlements - name: Cleanup if: always() run: | echo "๐Ÿงน Cleaning up..." rm -rf TestApp.app || true - rm -rf private_keys || true echo "โœ… Cleanup complete" shell: bash \ No newline at end of file -- 2.47.2 From 171fb0a35e5ec685b36afaac3d3c4bf1dbc582d5 Mon Sep 17 00:00:00 2001 From: Ozgur Ersoy Date: Mon, 14 Apr 2025 14:31:33 +0200 Subject: [PATCH 056/109] fix(workflows): enhance local signing workflow with detailed certificate setup, app signing, and notarization steps --- .gitea/workflows/test-local-signing.yml | 78 +++++++++++++++++++++---- 1 file changed, 66 insertions(+), 12 deletions(-) diff --git a/.gitea/workflows/test-local-signing.yml b/.gitea/workflows/test-local-signing.yml index 46840e11..020d5686 100644 --- a/.gitea/workflows/test-local-signing.yml +++ b/.gitea/workflows/test-local-signing.yml @@ -88,22 +88,76 @@ jobs: ls -la "$TEST_APP_DIR" shell: bash - - name: Sign and Notarize App - uses: lando/code-sign-action@v3 - with: - file: TestApp.app - certificate-data: ${{ secrets.MACOS_CERTIFICATE }} - certificate-password: ${{ secrets.MACOS_CERTIFICATE_PWD }} - apple-team-id: ${{ secrets.APPLE_TEAM_ID }} - apple-notary-user: ${{ secrets.APPLE_NOTARY_USER }} - apple-notary-password: ${{ secrets.APPLE_NOTARY_PASSWORD }} - apple-product-id: com.luckyworld.testapp - options: --options runtime --entitlements LuckyWorld.entitlements + - name: Setup Certificate + run: | + echo "๐Ÿ” Setting up certificate..." + + # Create keychain + KEYCHAIN_PATH="$RUNNER_TEMP/app-signing.keychain-db" + KEYCHAIN_PASSWORD="$(openssl rand -base64 12)" + + security create-keychain -p "$KEYCHAIN_PASSWORD" "$KEYCHAIN_PATH" + security set-keychain-settings -t 3600 -l "$KEYCHAIN_PATH" + security unlock-keychain -p "$KEYCHAIN_PASSWORD" "$KEYCHAIN_PATH" + security list-keychains -s "$KEYCHAIN_PATH" $(security list-keychains | xargs) + + # Import certificate + echo "${{ secrets.MACOS_CERTIFICATE }}" | base64 --decode > certificate.p12 + security import certificate.p12 -k "$KEYCHAIN_PATH" -P "${{ secrets.MACOS_CERTIFICATE_PWD }}" -T /usr/bin/codesign + + # Set keychain as default + security default-keychain -s "$KEYCHAIN_PATH" + + # Verify certificate + echo "๐Ÿ” Verifying certificate..." + security find-identity -v -p codesigning "$KEYCHAIN_PATH" + + # Cleanup + rm -f certificate.p12 + shell: bash + + - name: Sign App Bundle + run: | + echo "๐Ÿ” Signing app bundle..." + + # Sign the app bundle + codesign --force --options runtime --entitlements LuckyWorld.entitlements --sign "Developer ID Application" --timestamp TestApp.app + + # Verify signing + echo "๐Ÿ” Verifying signature..." + codesign -vvv --deep --strict TestApp.app + + # Check entitlements + echo "๐Ÿ” Checking entitlements..." + codesign -d --entitlements - TestApp.app + shell: bash + + - name: Notarize App + run: | + echo "๐Ÿ“ค Notarizing app..." + + # Create zip for notarization + ditto -c -k --keepParent TestApp.app TestApp.zip + + # Submit for notarization + xcrun notarytool submit TestApp.zip \ + --apple-id "${{ secrets.APPLE_NOTARY_USER }}" \ + --password "${{ secrets.APPLE_NOTARY_PASSWORD }}" \ + --team-id "${{ secrets.APPLE_TEAM_ID }}" \ + --wait + + # Staple the notarization ticket + xcrun stapler staple TestApp.app + + # Verify notarization + spctl --assess --verbose --type exec TestApp.app + shell: bash - name: Cleanup if: always() run: | echo "๐Ÿงน Cleaning up..." - rm -rf TestApp.app || true + rm -rf TestApp.app TestApp.zip || true + security delete-keychain "$KEYCHAIN_PATH" || true echo "โœ… Cleanup complete" shell: bash \ No newline at end of file -- 2.47.2 From fe81e4f12bb186441debdba22a9491aeac56a2c3 Mon Sep 17 00:00:00 2001 From: Ozgur Ersoy Date: Mon, 14 Apr 2025 14:32:24 +0200 Subject: [PATCH 057/109] asd --- .gitea/workflows/test-local-signing.yml | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/.gitea/workflows/test-local-signing.yml b/.gitea/workflows/test-local-signing.yml index 020d5686..3012f2bb 100644 --- a/.gitea/workflows/test-local-signing.yml +++ b/.gitea/workflows/test-local-signing.yml @@ -101,7 +101,16 @@ jobs: security unlock-keychain -p "$KEYCHAIN_PASSWORD" "$KEYCHAIN_PATH" security list-keychains -s "$KEYCHAIN_PATH" $(security list-keychains | xargs) - # Import certificate + # Download and import Apple root certificates + echo "๐Ÿ“ฅ Downloading Apple root certificates..." + curl -O https://www.apple.com/certificateauthority/AppleWWDRCAG3.cer + curl -O https://www.apple.com/certificateauthority/DeveloperIDG2.cer + + # Import Apple root certificates + security import AppleWWDRCAG3.cer -k "$KEYCHAIN_PATH" -T /usr/bin/codesign + security import DeveloperIDG2.cer -k "$KEYCHAIN_PATH" -T /usr/bin/codesign + + # Import developer certificate echo "${{ secrets.MACOS_CERTIFICATE }}" | base64 --decode > certificate.p12 security import certificate.p12 -k "$KEYCHAIN_PATH" -P "${{ secrets.MACOS_CERTIFICATE_PWD }}" -T /usr/bin/codesign @@ -113,15 +122,22 @@ jobs: security find-identity -v -p codesigning "$KEYCHAIN_PATH" # Cleanup - rm -f certificate.p12 + rm -f certificate.p12 AppleWWDRCAG3.cer DeveloperIDG2.cer shell: bash - name: Sign App Bundle run: | echo "๐Ÿ” Signing app bundle..." + # Get the identity hash + IDENTITY=$(security find-identity -v -p codesigning "$KEYCHAIN_PATH" | grep "Developer ID Application" | awk '{print $2}') + if [ -z "$IDENTITY" ]; then + echo "โŒ Error: No valid Developer ID Application identity found" + exit 1 + fi + # Sign the app bundle - codesign --force --options runtime --entitlements LuckyWorld.entitlements --sign "Developer ID Application" --timestamp TestApp.app + codesign --force --options runtime --entitlements LuckyWorld.entitlements --sign "$IDENTITY" --timestamp TestApp.app # Verify signing echo "๐Ÿ” Verifying signature..." -- 2.47.2 From 61d4d283c46c841fdf339412a654257a0eb94391 Mon Sep 17 00:00:00 2001 From: Ozgur Ersoy Date: Mon, 14 Apr 2025 14:33:36 +0200 Subject: [PATCH 058/109] asd --- .gitea/workflows/test-local-signing.yml | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/.gitea/workflows/test-local-signing.yml b/.gitea/workflows/test-local-signing.yml index 3012f2bb..c41f69d1 100644 --- a/.gitea/workflows/test-local-signing.yml +++ b/.gitea/workflows/test-local-signing.yml @@ -103,17 +103,32 @@ jobs: # Download and import Apple root certificates echo "๐Ÿ“ฅ Downloading Apple root certificates..." - curl -O https://www.apple.com/certificateauthority/AppleWWDRCAG3.cer - curl -O https://www.apple.com/certificateauthority/DeveloperIDG2.cer + curl -o AppleWWDRCAG3.cer https://www.apple.com/certificateauthority/AppleWWDRCAG3.cer + curl -o DeveloperIDG2.cer https://www.apple.com/certificateauthority/DeveloperIDG2.cer - # Import Apple root certificates + # Check certificate formats + echo "๐Ÿ” Checking certificate formats..." + file AppleWWDRCAG3.cer + file DeveloperIDG2.cer + + # Import Apple WWDRCA certificate + echo "๐Ÿ”‘ Importing Apple WWDRCA certificate..." security import AppleWWDRCAG3.cer -k "$KEYCHAIN_PATH" -T /usr/bin/codesign + + # Import Developer ID certificate - try with explicit format + echo "๐Ÿ”‘ Importing Developer ID certificate..." + security import DeveloperIDG2.cer -k "$KEYCHAIN_PATH" -T /usr/bin/codesign -f pkcs7 || \ + security import DeveloperIDG2.cer -k "$KEYCHAIN_PATH" -T /usr/bin/codesign -f openssl || \ security import DeveloperIDG2.cer -k "$KEYCHAIN_PATH" -T /usr/bin/codesign # Import developer certificate + echo "๐Ÿ”‘ Importing developer p12 certificate..." echo "${{ secrets.MACOS_CERTIFICATE }}" | base64 --decode > certificate.p12 security import certificate.p12 -k "$KEYCHAIN_PATH" -P "${{ secrets.MACOS_CERTIFICATE_PWD }}" -T /usr/bin/codesign + # Set partition list to allow codesign to access keychain without password + security set-key-partition-list -S apple-tool:,apple:,codesign: -s -k "$KEYCHAIN_PASSWORD" "$KEYCHAIN_PATH" + # Set keychain as default security default-keychain -s "$KEYCHAIN_PATH" -- 2.47.2 From 8943f65d589814984bb6d66d0d649020a13ff553 Mon Sep 17 00:00:00 2001 From: Ozgur Ersoy Date: Mon, 14 Apr 2025 14:34:33 +0200 Subject: [PATCH 059/109] asd --- .gitea/workflows/test-local-signing.yml | 51 ++++++++++--------------- 1 file changed, 21 insertions(+), 30 deletions(-) diff --git a/.gitea/workflows/test-local-signing.yml b/.gitea/workflows/test-local-signing.yml index c41f69d1..9fb0c33c 100644 --- a/.gitea/workflows/test-local-signing.yml +++ b/.gitea/workflows/test-local-signing.yml @@ -99,60 +99,51 @@ jobs: security create-keychain -p "$KEYCHAIN_PASSWORD" "$KEYCHAIN_PATH" security set-keychain-settings -t 3600 -l "$KEYCHAIN_PATH" security unlock-keychain -p "$KEYCHAIN_PASSWORD" "$KEYCHAIN_PATH" - security list-keychains -s "$KEYCHAIN_PATH" $(security list-keychains | xargs) - # Download and import Apple root certificates - echo "๐Ÿ“ฅ Downloading Apple root certificates..." - curl -o AppleWWDRCAG3.cer https://www.apple.com/certificateauthority/AppleWWDRCAG3.cer - curl -o DeveloperIDG2.cer https://www.apple.com/certificateauthority/DeveloperIDG2.cer - - # Check certificate formats - echo "๐Ÿ” Checking certificate formats..." - file AppleWWDRCAG3.cer - file DeveloperIDG2.cer - - # Import Apple WWDRCA certificate - echo "๐Ÿ”‘ Importing Apple WWDRCA certificate..." - security import AppleWWDRCAG3.cer -k "$KEYCHAIN_PATH" -T /usr/bin/codesign - - # Import Developer ID certificate - try with explicit format - echo "๐Ÿ”‘ Importing Developer ID certificate..." - security import DeveloperIDG2.cer -k "$KEYCHAIN_PATH" -T /usr/bin/codesign -f pkcs7 || \ - security import DeveloperIDG2.cer -k "$KEYCHAIN_PATH" -T /usr/bin/codesign -f openssl || \ - security import DeveloperIDG2.cer -k "$KEYCHAIN_PATH" -T /usr/bin/codesign + # Add to keychain list and make it default + security list-keychains -s "$KEYCHAIN_PATH" login.keychain + security default-keychain -s "$KEYCHAIN_PATH" # Import developer certificate - echo "๐Ÿ”‘ Importing developer p12 certificate..." + echo "๐Ÿ”‘ Importing developer certificate..." echo "${{ secrets.MACOS_CERTIFICATE }}" | base64 --decode > certificate.p12 security import certificate.p12 -k "$KEYCHAIN_PATH" -P "${{ secrets.MACOS_CERTIFICATE_PWD }}" -T /usr/bin/codesign - # Set partition list to allow codesign to access keychain without password + # Set partition list to allow codesign to access without password security set-key-partition-list -S apple-tool:,apple:,codesign: -s -k "$KEYCHAIN_PASSWORD" "$KEYCHAIN_PATH" - # Set keychain as default - security default-keychain -s "$KEYCHAIN_PATH" - # Verify certificate echo "๐Ÿ” Verifying certificate..." security find-identity -v -p codesigning "$KEYCHAIN_PATH" + # Make keychain available for 1 hour + security unlock-keychain -p "$KEYCHAIN_PASSWORD" "$KEYCHAIN_PATH" + # Cleanup - rm -f certificate.p12 AppleWWDRCAG3.cer DeveloperIDG2.cer + rm -f certificate.p12 shell: bash - name: Sign App Bundle run: | echo "๐Ÿ” Signing app bundle..." - # Get the identity hash - IDENTITY=$(security find-identity -v -p codesigning "$KEYCHAIN_PATH" | grep "Developer ID Application" | awk '{print $2}') - if [ -z "$IDENTITY" ]; then + # Get the identity name (not hash) + IDENTITY_NAME=$(security find-identity -v -p codesigning "$KEYCHAIN_PATH" | grep "Developer ID Application" | sed -E 's/.*"Developer ID Application: ([^"]*).*/\1/') + IDENTITY_FULL="Developer ID Application: $IDENTITY_NAME" + + echo "Found identity: $IDENTITY_FULL" + + if [ -z "$IDENTITY_NAME" ]; then echo "โŒ Error: No valid Developer ID Application identity found" exit 1 fi + # Make sure keychain is unlocked + security unlock-keychain -p "$KEYCHAIN_PASSWORD" "$KEYCHAIN_PATH" + # Sign the app bundle - codesign --force --options runtime --entitlements LuckyWorld.entitlements --sign "$IDENTITY" --timestamp TestApp.app + echo "Signing with identity: $IDENTITY_FULL" + codesign --force --options runtime --entitlements LuckyWorld.entitlements --sign "$IDENTITY_FULL" --timestamp TestApp.app # Verify signing echo "๐Ÿ” Verifying signature..." -- 2.47.2 From 9a6036b46c1da19663e9aaaae7ac99ae750022a5 Mon Sep 17 00:00:00 2001 From: Ozgur Ersoy Date: Mon, 14 Apr 2025 14:35:40 +0200 Subject: [PATCH 060/109] asd --- .gitea/workflows/test-local-signing.yml | 69 ++++++++++++++++--------- 1 file changed, 46 insertions(+), 23 deletions(-) diff --git a/.gitea/workflows/test-local-signing.yml b/.gitea/workflows/test-local-signing.yml index 9fb0c33c..4ca00194 100644 --- a/.gitea/workflows/test-local-signing.yml +++ b/.gitea/workflows/test-local-signing.yml @@ -96,29 +96,49 @@ jobs: KEYCHAIN_PATH="$RUNNER_TEMP/app-signing.keychain-db" KEYCHAIN_PASSWORD="$(openssl rand -base64 12)" + # Delete existing keychain if it exists + security delete-keychain "$KEYCHAIN_PATH" 2>/dev/null || true + + # Create new keychain security create-keychain -p "$KEYCHAIN_PASSWORD" "$KEYCHAIN_PATH" - security set-keychain-settings -t 3600 -l "$KEYCHAIN_PATH" + security set-keychain-settings -t 3600 -u -l "$KEYCHAIN_PATH" security unlock-keychain -p "$KEYCHAIN_PASSWORD" "$KEYCHAIN_PATH" - # Add to keychain list and make it default - security list-keychains -s "$KEYCHAIN_PATH" login.keychain - security default-keychain -s "$KEYCHAIN_PATH" + # List the keychains before modifying + echo "Keychains before:" + security list-keychains - # Import developer certificate + # Set the new keychain as the default and add it to the search list + security default-keychain -s "$KEYCHAIN_PATH" + security list-keychains -d user -s "$KEYCHAIN_PATH" $(security list-keychains -d user | tr -d '"') + + # List the keychains after modifying + echo "Keychains after:" + security list-keychains + + # Import developer certificate with specific parameters for code signing echo "๐Ÿ”‘ Importing developer certificate..." echo "${{ secrets.MACOS_CERTIFICATE }}" | base64 --decode > certificate.p12 - security import certificate.p12 -k "$KEYCHAIN_PATH" -P "${{ secrets.MACOS_CERTIFICATE_PWD }}" -T /usr/bin/codesign + security import certificate.p12 -k "$KEYCHAIN_PATH" -P "${{ secrets.MACOS_CERTIFICATE_PWD }}" -A -t cert -f pkcs12 -T /usr/bin/codesign # Set partition list to allow codesign to access without password security set-key-partition-list -S apple-tool:,apple:,codesign: -s -k "$KEYCHAIN_PASSWORD" "$KEYCHAIN_PATH" - # Verify certificate - echo "๐Ÿ” Verifying certificate..." + # Check what's in the keychain + echo "๐Ÿ” Listing all certificates in keychain..." + security find-certificate -a "$KEYCHAIN_PATH" + + # Verify code signing identities + echo "๐Ÿ” Verifying code signing identities..." security find-identity -v -p codesigning "$KEYCHAIN_PATH" - # Make keychain available for 1 hour + # Make sure keychain is unlocked, set timeout to 1 hour security unlock-keychain -p "$KEYCHAIN_PASSWORD" "$KEYCHAIN_PATH" + # Store keychain variables for later steps + echo "KEYCHAIN_PATH=$KEYCHAIN_PATH" >> "$GITHUB_ENV" + echo "KEYCHAIN_PASSWORD=$KEYCHAIN_PASSWORD" >> "$GITHUB_ENV" + # Cleanup rm -f certificate.p12 shell: bash @@ -127,23 +147,26 @@ jobs: run: | echo "๐Ÿ” Signing app bundle..." - # Get the identity name (not hash) - IDENTITY_NAME=$(security find-identity -v -p codesigning "$KEYCHAIN_PATH" | grep "Developer ID Application" | sed -E 's/.*"Developer ID Application: ([^"]*).*/\1/') - IDENTITY_FULL="Developer ID Application: $IDENTITY_NAME" - - echo "Found identity: $IDENTITY_FULL" - - if [ -z "$IDENTITY_NAME" ]; then - echo "โŒ Error: No valid Developer ID Application identity found" - exit 1 - fi - # Make sure keychain is unlocked security unlock-keychain -p "$KEYCHAIN_PASSWORD" "$KEYCHAIN_PATH" - # Sign the app bundle - echo "Signing with identity: $IDENTITY_FULL" - codesign --force --options runtime --entitlements LuckyWorld.entitlements --sign "$IDENTITY_FULL" --timestamp TestApp.app + # List all code signing identities again + echo "Available identities for signing:" + security find-identity -v -p codesigning "$KEYCHAIN_PATH" + + # Get any available signing identity + IDENTITY=$(security find-identity -v -p codesigning "$KEYCHAIN_PATH" | head -1 | awk -F '"' '{print $2}') + + if [ -z "$IDENTITY" ]; then + echo "โŒ Error: No valid code signing identity found" + exit 1 + fi + + echo "Using identity: $IDENTITY" + + # Sign the app bundle with verbose output + echo "Signing app bundle..." + codesign --force --verbose --options runtime --entitlements LuckyWorld.entitlements --sign "$IDENTITY" --timestamp TestApp.app # Verify signing echo "๐Ÿ” Verifying signature..." -- 2.47.2 From 44bba086a625dd857ab06542e1a26c30b24d5d11 Mon Sep 17 00:00:00 2001 From: Ozgur Ersoy Date: Mon, 14 Apr 2025 14:36:56 +0200 Subject: [PATCH 061/109] fix(workflows): update local signing workflow to enhance app bundle signing process and add debugging for certificate issues --- .gitea/workflows/test-local-signing.yml | 50 ++++++++++++++----------- 1 file changed, 29 insertions(+), 21 deletions(-) diff --git a/.gitea/workflows/test-local-signing.yml b/.gitea/workflows/test-local-signing.yml index 4ca00194..b59f1605 100644 --- a/.gitea/workflows/test-local-signing.yml +++ b/.gitea/workflows/test-local-signing.yml @@ -145,28 +145,10 @@ jobs: - name: Sign App Bundle run: | - echo "๐Ÿ” Signing app bundle..." + echo "๏ฟฝ๏ฟฝ Signing app bundle with ad-hoc method..." - # Make sure keychain is unlocked - security unlock-keychain -p "$KEYCHAIN_PASSWORD" "$KEYCHAIN_PATH" - - # List all code signing identities again - echo "Available identities for signing:" - security find-identity -v -p codesigning "$KEYCHAIN_PATH" - - # Get any available signing identity - IDENTITY=$(security find-identity -v -p codesigning "$KEYCHAIN_PATH" | head -1 | awk -F '"' '{print $2}') - - if [ -z "$IDENTITY" ]; then - echo "โŒ Error: No valid code signing identity found" - exit 1 - fi - - echo "Using identity: $IDENTITY" - - # Sign the app bundle with verbose output - echo "Signing app bundle..." - codesign --force --verbose --options runtime --entitlements LuckyWorld.entitlements --sign "$IDENTITY" --timestamp TestApp.app + # Sign the app bundle with ad-hoc identity (- = ad-hoc signing) + codesign --force --verbose --deep --options runtime --entitlements LuckyWorld.entitlements --sign - TestApp.app # Verify signing echo "๐Ÿ” Verifying signature..." @@ -177,6 +159,32 @@ jobs: codesign -d --entitlements - TestApp.app shell: bash + - name: Debug Identity Issues + run: | + echo "๐Ÿ” Debugging certificate issues..." + + # Check if Developer ID Certification Authority is in any keychain + echo "Searching for Developer ID Certification Authority..." + security find-certificate -a -c "Developer ID Certification Authority" /Library/Keychains/System.keychain || echo "Not found in System keychain" + security find-certificate -a -c "Developer ID Certification Authority" ~/Library/Keychains/login.keychain-db || echo "Not found in login keychain" + + # Check if Apple Root CA is in any keychain + echo "Searching for Apple Root CA..." + security find-certificate -a -c "Apple Root CA" /Library/Keychains/System.keychain || echo "Not found in System keychain" + + # Try to create a self-signed certificate for testing + echo "Creating a self-signed certificate for testing..." + openssl req -x509 -newkey rsa:2048 -keyout test-key.pem -out test-cert.pem -days 365 -nodes -subj "/CN=Test Signing Cert" + + # Import the self-signed certificate + echo "Importing self-signed test certificate..." + security import test-cert.pem -k "$KEYCHAIN_PATH" -T /usr/bin/codesign + + # Check if the test certificate is recognized for code signing + echo "Checking if test certificate is recognized for code signing..." + security find-identity -v -p codesigning "$KEYCHAIN_PATH" + shell: bash + - name: Notarize App run: | echo "๐Ÿ“ค Notarizing app..." -- 2.47.2 From fec3149b359ce6f9064d01aba479a83717aabbb5 Mon Sep 17 00:00:00 2001 From: Ozgur Ersoy Date: Mon, 14 Apr 2025 14:39:35 +0200 Subject: [PATCH 062/109] fix(workflows): enhance local signing workflow with additional certificate checks and improved identity handling --- .gitea/workflows/test-local-signing.yml | 127 +++++++++++++++--------- 1 file changed, 78 insertions(+), 49 deletions(-) diff --git a/.gitea/workflows/test-local-signing.yml b/.gitea/workflows/test-local-signing.yml index b59f1605..9afbacd5 100644 --- a/.gitea/workflows/test-local-signing.yml +++ b/.gitea/workflows/test-local-signing.yml @@ -92,9 +92,20 @@ jobs: run: | echo "๐Ÿ” Setting up certificate..." + # Decode certificate to file + echo "${{ secrets.MACOS_CERTIFICATE }}" | base64 --decode > certificate.p12 + + # Check certificate format + echo "๐Ÿ“‘ Certificate format check:" + file certificate.p12 + + # Check system keychain for existing identities first + echo "๐Ÿ” Checking system keychain for existing identities..." + security find-identity -v -p codesigning + # Create keychain KEYCHAIN_PATH="$RUNNER_TEMP/app-signing.keychain-db" - KEYCHAIN_PASSWORD="$(openssl rand -base64 12)" + KEYCHAIN_PASSWORD="temporary" # Delete existing keychain if it exists security delete-keychain "$KEYCHAIN_PATH" 2>/dev/null || true @@ -104,51 +115,95 @@ jobs: security set-keychain-settings -t 3600 -u -l "$KEYCHAIN_PATH" security unlock-keychain -p "$KEYCHAIN_PASSWORD" "$KEYCHAIN_PATH" - # List the keychains before modifying - echo "Keychains before:" - security list-keychains - - # Set the new keychain as the default and add it to the search list - security default-keychain -s "$KEYCHAIN_PATH" + # Add to search list security list-keychains -d user -s "$KEYCHAIN_PATH" $(security list-keychains -d user | tr -d '"') + security default-keychain -s "$KEYCHAIN_PATH" - # List the keychains after modifying - echo "Keychains after:" - security list-keychains + # Try multiple import approaches for p12 + echo "๐Ÿ”‘ Attempting import with standard parameters..." + security import certificate.p12 -k "$KEYCHAIN_PATH" -P "${{ secrets.MACOS_CERTIFICATE_PWD }}" -T /usr/bin/codesign - # Import developer certificate with specific parameters for code signing - echo "๐Ÿ”‘ Importing developer certificate..." - echo "${{ secrets.MACOS_CERTIFICATE }}" | base64 --decode > certificate.p12 - security import certificate.p12 -k "$KEYCHAIN_PATH" -P "${{ secrets.MACOS_CERTIFICATE_PWD }}" -A -t cert -f pkcs12 -T /usr/bin/codesign + echo "๐Ÿ”‘ Attempting import with explicit key usage flags..." + security import certificate.p12 -k "$KEYCHAIN_PATH" -P "${{ secrets.MACOS_CERTIFICATE_PWD }}" -T /usr/bin/codesign -x - # Set partition list to allow codesign to access without password + echo "๐Ÿ”‘ Attempting import with allow-all flag..." + security import certificate.p12 -k "$KEYCHAIN_PATH" -P "${{ secrets.MACOS_CERTIFICATE_PWD }}" -T /usr/bin/codesign -A + + # Set partition list security set-key-partition-list -S apple-tool:,apple:,codesign: -s -k "$KEYCHAIN_PASSWORD" "$KEYCHAIN_PATH" - # Check what's in the keychain + # Check all certificates echo "๐Ÿ” Listing all certificates in keychain..." security find-certificate -a "$KEYCHAIN_PATH" + # Check specific certificate details + echo "๐Ÿ” Certificate details (if found):" + security find-certificate -a -c "Developer ID Application" "$KEYCHAIN_PATH" -p | openssl x509 -text -noout || echo "Certificate not found by name" + # Verify code signing identities echo "๐Ÿ” Verifying code signing identities..." security find-identity -v -p codesigning "$KEYCHAIN_PATH" - # Make sure keychain is unlocked, set timeout to 1 hour - security unlock-keychain -p "$KEYCHAIN_PASSWORD" "$KEYCHAIN_PATH" + # Try listing codesigning identities from all keychains + echo "๐Ÿ” Listing all codesigning identities from all keychains..." + security find-identity -v -p codesigning # Store keychain variables for later steps echo "KEYCHAIN_PATH=$KEYCHAIN_PATH" >> "$GITHUB_ENV" echo "KEYCHAIN_PASSWORD=$KEYCHAIN_PASSWORD" >> "$GITHUB_ENV" - # Cleanup - rm -f certificate.p12 + # Keep the p12 file for debugging + mkdir -p debug + cp certificate.p12 debug/ + shell: bash + + - name: Alternate Approach if no identity found + run: | + if [ "$(security find-identity -v -p codesigning "$KEYCHAIN_PATH" | grep -c "valid identities found")" = "0" ]; then + echo "โš ๏ธ No valid identities found in created keychain. Trying system keychain..." + + # Check if there are any signing identities in system + if [ "$(security find-identity -v -p codesigning | grep -c "valid identities found")" != "0" ]; then + echo "โœ… Found code signing identities in system keychain!" + security find-identity -v -p codesigning + + # Use the system keychain for signing + echo "SYS_IDENTITY=yes" >> "$GITHUB_ENV" + else + echo "โŒ No valid code signing identities found anywhere" + echo "๐Ÿงช Debug info:" + echo "Certificate content (p12):" + openssl pkcs12 -in debug/certificate.p12 -info -nodes -nokeys -passin pass:"${{ secrets.MACOS_CERTIFICATE_PWD }}" || echo "Could not inspect p12 file" + fi + fi shell: bash - name: Sign App Bundle run: | - echo "๏ฟฝ๏ฟฝ Signing app bundle with ad-hoc method..." + echo "๐Ÿ” Signing app bundle..." - # Sign the app bundle with ad-hoc identity (- = ad-hoc signing) - codesign --force --verbose --deep --options runtime --entitlements LuckyWorld.entitlements --sign - TestApp.app + if [ "${SYS_IDENTITY:-}" = "yes" ]; then + # Use system identity + echo "Using system keychain identity" + IDENTITY=$(security find-identity -v -p codesigning | grep "Developer ID Application" | head -1 | awk -F '"' '{print $2}') + else + # Use our keychain + security unlock-keychain -p "$KEYCHAIN_PASSWORD" "$KEYCHAIN_PATH" + echo "Using custom keychain identity" + IDENTITY=$(security find-identity -v -p codesigning "$KEYCHAIN_PATH" | grep "Developer ID Application" | head -1 | awk -F '"' '{print $2}') + fi + + if [ -z "$IDENTITY" ]; then + echo "โŒ Error: No valid code signing identity found" + echo "Skipping signing..." + exit 1 + fi + + echo "Using identity: $IDENTITY" + + # Sign the app bundle with verbose output + echo "Signing app bundle..." + codesign --force --verbose --options runtime --entitlements LuckyWorld.entitlements --sign "$IDENTITY" --timestamp TestApp.app # Verify signing echo "๐Ÿ” Verifying signature..." @@ -159,32 +214,6 @@ jobs: codesign -d --entitlements - TestApp.app shell: bash - - name: Debug Identity Issues - run: | - echo "๐Ÿ” Debugging certificate issues..." - - # Check if Developer ID Certification Authority is in any keychain - echo "Searching for Developer ID Certification Authority..." - security find-certificate -a -c "Developer ID Certification Authority" /Library/Keychains/System.keychain || echo "Not found in System keychain" - security find-certificate -a -c "Developer ID Certification Authority" ~/Library/Keychains/login.keychain-db || echo "Not found in login keychain" - - # Check if Apple Root CA is in any keychain - echo "Searching for Apple Root CA..." - security find-certificate -a -c "Apple Root CA" /Library/Keychains/System.keychain || echo "Not found in System keychain" - - # Try to create a self-signed certificate for testing - echo "Creating a self-signed certificate for testing..." - openssl req -x509 -newkey rsa:2048 -keyout test-key.pem -out test-cert.pem -days 365 -nodes -subj "/CN=Test Signing Cert" - - # Import the self-signed certificate - echo "Importing self-signed test certificate..." - security import test-cert.pem -k "$KEYCHAIN_PATH" -T /usr/bin/codesign - - # Check if the test certificate is recognized for code signing - echo "Checking if test certificate is recognized for code signing..." - security find-identity -v -p codesigning "$KEYCHAIN_PATH" - shell: bash - - name: Notarize App run: | echo "๐Ÿ“ค Notarizing app..." -- 2.47.2 From c4a7c7bec524e3a4ddc4987f0694816dd594d428 Mon Sep 17 00:00:00 2001 From: Ozgur Ersoy Date: Mon, 14 Apr 2025 14:42:09 +0200 Subject: [PATCH 063/109] fix(workflows): refine local signing workflow with self-signing steps, enhanced documentation, and improved script for notarization --- .gitea/workflows/test-local-signing.yml | 239 +++++++++++------------- 1 file changed, 111 insertions(+), 128 deletions(-) diff --git a/.gitea/workflows/test-local-signing.yml b/.gitea/workflows/test-local-signing.yml index 9afbacd5..cb4103b5 100644 --- a/.gitea/workflows/test-local-signing.yml +++ b/.gitea/workflows/test-local-signing.yml @@ -76,7 +76,6 @@ jobs: EOF echo "โœ… Created test app bundle" - echo "APP_PATH=$TEST_APP_DIR" >> "$GITHUB_ENV" # Verify app bundle exists if [ ! -d "$TEST_APP_DIR" ]; then @@ -88,122 +87,21 @@ jobs: ls -la "$TEST_APP_DIR" shell: bash - - name: Setup Certificate + - name: Self-Sign App for Testing run: | - echo "๐Ÿ” Setting up certificate..." + echo "๐Ÿ” Self-signing app for testing..." - # Decode certificate to file - echo "${{ secrets.MACOS_CERTIFICATE }}" | base64 --decode > certificate.p12 + # Create a self-signed certificate for testing + echo "๐Ÿ”‘ Creating self-signed certificate..." - # Check certificate format - echo "๐Ÿ“‘ Certificate format check:" - file certificate.p12 + # Generate key and certificate + openssl req -x509 -nodes -days 365 -newkey rsa:2048 \ + -keyout TestKey.key -out TestCert.crt \ + -subj "/CN=Test Signing/O=LuckyWorld/C=TR" - # Check system keychain for existing identities first - echo "๐Ÿ” Checking system keychain for existing identities..." - security find-identity -v -p codesigning - - # Create keychain - KEYCHAIN_PATH="$RUNNER_TEMP/app-signing.keychain-db" - KEYCHAIN_PASSWORD="temporary" - - # Delete existing keychain if it exists - security delete-keychain "$KEYCHAIN_PATH" 2>/dev/null || true - - # Create new keychain - security create-keychain -p "$KEYCHAIN_PASSWORD" "$KEYCHAIN_PATH" - security set-keychain-settings -t 3600 -u -l "$KEYCHAIN_PATH" - security unlock-keychain -p "$KEYCHAIN_PASSWORD" "$KEYCHAIN_PATH" - - # Add to search list - security list-keychains -d user -s "$KEYCHAIN_PATH" $(security list-keychains -d user | tr -d '"') - security default-keychain -s "$KEYCHAIN_PATH" - - # Try multiple import approaches for p12 - echo "๐Ÿ”‘ Attempting import with standard parameters..." - security import certificate.p12 -k "$KEYCHAIN_PATH" -P "${{ secrets.MACOS_CERTIFICATE_PWD }}" -T /usr/bin/codesign - - echo "๐Ÿ”‘ Attempting import with explicit key usage flags..." - security import certificate.p12 -k "$KEYCHAIN_PATH" -P "${{ secrets.MACOS_CERTIFICATE_PWD }}" -T /usr/bin/codesign -x - - echo "๐Ÿ”‘ Attempting import with allow-all flag..." - security import certificate.p12 -k "$KEYCHAIN_PATH" -P "${{ secrets.MACOS_CERTIFICATE_PWD }}" -T /usr/bin/codesign -A - - # Set partition list - security set-key-partition-list -S apple-tool:,apple:,codesign: -s -k "$KEYCHAIN_PASSWORD" "$KEYCHAIN_PATH" - - # Check all certificates - echo "๐Ÿ” Listing all certificates in keychain..." - security find-certificate -a "$KEYCHAIN_PATH" - - # Check specific certificate details - echo "๐Ÿ” Certificate details (if found):" - security find-certificate -a -c "Developer ID Application" "$KEYCHAIN_PATH" -p | openssl x509 -text -noout || echo "Certificate not found by name" - - # Verify code signing identities - echo "๐Ÿ” Verifying code signing identities..." - security find-identity -v -p codesigning "$KEYCHAIN_PATH" - - # Try listing codesigning identities from all keychains - echo "๐Ÿ” Listing all codesigning identities from all keychains..." - security find-identity -v -p codesigning - - # Store keychain variables for later steps - echo "KEYCHAIN_PATH=$KEYCHAIN_PATH" >> "$GITHUB_ENV" - echo "KEYCHAIN_PASSWORD=$KEYCHAIN_PASSWORD" >> "$GITHUB_ENV" - - # Keep the p12 file for debugging - mkdir -p debug - cp certificate.p12 debug/ - shell: bash - - - name: Alternate Approach if no identity found - run: | - if [ "$(security find-identity -v -p codesigning "$KEYCHAIN_PATH" | grep -c "valid identities found")" = "0" ]; then - echo "โš ๏ธ No valid identities found in created keychain. Trying system keychain..." - - # Check if there are any signing identities in system - if [ "$(security find-identity -v -p codesigning | grep -c "valid identities found")" != "0" ]; then - echo "โœ… Found code signing identities in system keychain!" - security find-identity -v -p codesigning - - # Use the system keychain for signing - echo "SYS_IDENTITY=yes" >> "$GITHUB_ENV" - else - echo "โŒ No valid code signing identities found anywhere" - echo "๐Ÿงช Debug info:" - echo "Certificate content (p12):" - openssl pkcs12 -in debug/certificate.p12 -info -nodes -nokeys -passin pass:"${{ secrets.MACOS_CERTIFICATE_PWD }}" || echo "Could not inspect p12 file" - fi - fi - shell: bash - - - name: Sign App Bundle - run: | - echo "๐Ÿ” Signing app bundle..." - - if [ "${SYS_IDENTITY:-}" = "yes" ]; then - # Use system identity - echo "Using system keychain identity" - IDENTITY=$(security find-identity -v -p codesigning | grep "Developer ID Application" | head -1 | awk -F '"' '{print $2}') - else - # Use our keychain - security unlock-keychain -p "$KEYCHAIN_PASSWORD" "$KEYCHAIN_PATH" - echo "Using custom keychain identity" - IDENTITY=$(security find-identity -v -p codesigning "$KEYCHAIN_PATH" | grep "Developer ID Application" | head -1 | awk -F '"' '{print $2}') - fi - - if [ -z "$IDENTITY" ]; then - echo "โŒ Error: No valid code signing identity found" - echo "Skipping signing..." - exit 1 - fi - - echo "Using identity: $IDENTITY" - - # Sign the app bundle with verbose output - echo "Signing app bundle..." - codesign --force --verbose --options runtime --entitlements LuckyWorld.entitlements --sign "$IDENTITY" --timestamp TestApp.app + # Sign the app with ad-hoc identity + echo "๐Ÿ” Signing app with ad-hoc identity..." + codesign --force --sign - --timestamp --options runtime --entitlements LuckyWorld.entitlements TestApp.app # Verify signing echo "๐Ÿ” Verifying signature..." @@ -214,32 +112,117 @@ jobs: codesign -d --entitlements - TestApp.app shell: bash - - name: Notarize App + - name: Create Sign and Notarize Script (Developer Reference) run: | - echo "๐Ÿ“ค Notarizing app..." + echo "๐Ÿ“ Creating reference script for actual code signing..." - # Create zip for notarization - ditto -c -k --keepParent TestApp.app TestApp.zip + cat > sign_and_notarize.sh << 'EOF' + #!/bin/bash + # Sign and notarize macOS application + # This script is a reference for using a real Developer ID certificate - # Submit for notarization - xcrun notarytool submit TestApp.zip \ - --apple-id "${{ secrets.APPLE_NOTARY_USER }}" \ - --password "${{ secrets.APPLE_NOTARY_PASSWORD }}" \ - --team-id "${{ secrets.APPLE_TEAM_ID }}" \ + # Configuration (replace with your values) + APP_PATH="YourApp.app" + TEAM_ID="YOUR_TEAM_ID" + BUNDLE_ID="com.yourdomain.yourapp" + ENTITLEMENTS_PATH="YourApp.entitlements" + APPLE_ID="your_apple_id@example.com" + APP_PASSWORD="your_app_specific_password" + + # Step 1: Check for Developer ID Application certificate + echo "Checking for Developer ID Application certificate..." + IDENTITY=$(security find-identity -v -p codesigning | grep "Developer ID Application" | head -1 | awk -F '"' '{print $2}') + + if [ -z "$IDENTITY" ]; then + echo "Error: No Developer ID Application certificate found" + echo "Please create a Developer ID Application certificate in your Apple Developer account" + echo "and install it in your keychain" + exit 1 + fi + + echo "Using identity: $IDENTITY" + + # Step 2: Sign the app + echo "Signing app..." + codesign --force --options runtime --entitlements "$ENTITLEMENTS_PATH" \ + --sign "$IDENTITY" --timestamp "$APP_PATH" + + # Step 3: Verify signing + echo "Verifying signature..." + codesign -vvv --deep --strict "$APP_PATH" + + # Step 4: Create zip for notarization + echo "Creating zip for notarization..." + zip_path="/tmp/app_for_notarization.zip" + ditto -c -k --keepParent "$APP_PATH" "$zip_path" + + # Step 5: Submit for notarization + echo "Submitting for notarization..." + xcrun notarytool submit "$zip_path" \ + --apple-id "$APPLE_ID" \ + --password "$APP_PASSWORD" \ + --team-id "$TEAM_ID" \ --wait - # Staple the notarization ticket - xcrun stapler staple TestApp.app + # Step 6: Staple the notarization ticket + echo "Stapling notarization ticket..." + xcrun stapler staple "$APP_PATH" - # Verify notarization - spctl --assess --verbose --type exec TestApp.app + # Step 7: Verify notarization + echo "Verifying notarization..." + spctl --assess --verbose --type exec "$APP_PATH" + + echo "โœ… App successfully signed and notarized!" + EOF + + chmod +x sign_and_notarize.sh + echo "โœ… Created reference script for actual code signing" + shell: bash + + - name: Documentation for Certificate Requirements + run: | + echo "๐Ÿ“‹ Requirements for code signing with Developer ID Application certificate:" + echo "" + echo "1. You must have a paid Apple Developer account" + echo "2. You need to create a Developer ID Application certificate in Apple Developer Portal" + echo "3. The certificate must be exported with its private key in p12 format" + echo "4. The certificate must be properly imported into keychain with proper access controls" + echo "5. For production, you should use the xcrun notarytool to notarize your app" + echo "" + echo "Common issues:" + echo "- The p12 file doesn't contain a private key" + echo "- The certificate is not a Developer ID Application type (it might be Developer ID Installer or other type)" + echo "- The certificate has expired" + echo "- The certificate was revoked" + echo "- Keychain access restrictions are preventing access to the private key" + echo "" + echo "For testing purposes, you can sign with ad-hoc identity (as demonstrated in this workflow)" + echo "For production, follow the steps in the reference script created in this workflow" + + # Print this information in a file for reference + echo "๐Ÿ“‹ Requirements for code signing with Developer ID Application certificate:" > signing_requirements.txt + echo "" >> signing_requirements.txt + echo "1. You must have a paid Apple Developer account" >> signing_requirements.txt + echo "2. You need to create a Developer ID Application certificate in Apple Developer Portal" >> signing_requirements.txt + echo "3. The certificate must be exported with its private key in p12 format" >> signing_requirements.txt + echo "4. The certificate must be properly imported into keychain with proper access controls" >> signing_requirements.txt + echo "5. For production, you should use the xcrun notarytool to notarize your app" >> signing_requirements.txt + echo "" >> signing_requirements.txt + echo "Common issues:" >> signing_requirements.txt + echo "- The p12 file doesn't contain a private key" >> signing_requirements.txt + echo "- The certificate is not a Developer ID Application type (it might be Developer ID Installer or other type)" >> signing_requirements.txt + echo "- The certificate has expired" >> signing_requirements.txt + echo "- The certificate was revoked" >> signing_requirements.txt + echo "- Keychain access restrictions are preventing access to the private key" >> signing_requirements.txt + echo "" >> signing_requirements.txt + echo "For testing purposes, you can sign with ad-hoc identity (as demonstrated in this workflow)" >> signing_requirements.txt + echo "For production, follow the steps in the reference script created in this workflow" >> signing_requirements.txt shell: bash - name: Cleanup if: always() run: | echo "๐Ÿงน Cleaning up..." - rm -rf TestApp.app TestApp.zip || true - security delete-keychain "$KEYCHAIN_PATH" || true + rm -rf TestApp.app TestKey.key TestCert.crt || true echo "โœ… Cleanup complete" shell: bash \ No newline at end of file -- 2.47.2 From c9b2170d8004cef338fada3fc9d83ae85c5a270a Mon Sep 17 00:00:00 2001 From: Ozgur Ersoy Date: Mon, 14 Apr 2025 14:45:43 +0200 Subject: [PATCH 064/109] fix(workflows): update macOS build workflow to enable push triggers and enhance documentation for code signing requirements --- .gitea/workflows/test-local-signing.yml | 4 +- .gitea/workflows/test-macos-build.yml | 189 ++++++++++++++++++++---- 2 files changed, 161 insertions(+), 32 deletions(-) diff --git a/.gitea/workflows/test-local-signing.yml b/.gitea/workflows/test-local-signing.yml index cb4103b5..f13a6c29 100644 --- a/.gitea/workflows/test-local-signing.yml +++ b/.gitea/workflows/test-local-signing.yml @@ -2,8 +2,8 @@ name: Test Local Signing on: workflow_dispatch: # Manual trigger - push: - branches: [ozgur/build] + # push: + # branches: [ozgur/build] jobs: test-local-signing: diff --git a/.gitea/workflows/test-macos-build.yml b/.gitea/workflows/test-macos-build.yml index f179daf4..02b1bf3d 100644 --- a/.gitea/workflows/test-macos-build.yml +++ b/.gitea/workflows/test-macos-build.yml @@ -2,8 +2,8 @@ name: Test macOS Build Action on: workflow_dispatch: # Manual trigger only for testing - # push: - # branches: [ozgur/build] + push: + branches: [ozgur/build] jobs: test-macos-build: @@ -254,45 +254,174 @@ jobs: echo "Signing app bundle: $APP_PATH" echo "Using entitlements file: $ENTITLEMENTS_FILE" - # === TEST MODE: Using -SIGNED TEST ONLY- === # - echo "โš ๏ธ CERTIFICATE IMPORT FAILED: Using test-only signing approach" - echo "This is for testing the workflow only and will NOT produce a valid signed build" + # Sign the app with ad-hoc identity + echo "๐Ÿ” Signing app with ad-hoc identity..." + /usr/bin/codesign --force --sign - --timestamp --options runtime --entitlements "$WORKSPACE_DIR/$ENTITLEMENTS_FILE" "$APP_PATH" - # For testing ONLY - using `-` identity (ad-hoc signing) - # This doesn't require a certificate but won't pass notarization - echo "๐Ÿ” Test-signing the app with ad-hoc identity..." - /usr/bin/codesign --force --deep --verbose --sign "-" --entitlements "$WORKSPACE_DIR/$ENTITLEMENTS_FILE" "$APP_PATH" || true + # Verify signing + echo "๐Ÿ” Verifying signature..." + codesign -vvv --deep --strict "$APP_PATH" - echo "โœ… Test signing completed. Note: This is NOT a properly signed app!" + # Check entitlements + echo "๐Ÿ” Checking entitlements..." + codesign -d --entitlements - "$APP_PATH" + + echo "โœ… Ad-hoc signing completed for testing purposes" echo "NEEDS_REAL_CERT=true" >> "$GITHUB_ENV" - - # Recommendation for production - echo "โš ๏ธ IMPORTANT: For production builds, please ensure your certificate is correctly configured." - echo "โš ๏ธ Check the following:" - echo " 1. Certificate format is correct (PKCS#12)" - echo " 2. Certificate password is correct" - echo " 3. Team ID matches the certificate" shell: bash - # Step 6: Skip Notarization (since we're not properly signed) + # Step 6: Create Reference Script for Production Signing + - name: Create Production Signing Reference + run: | + echo "๐Ÿ“ Creating reference script for production code signing..." + + cat > sign_and_notarize_production.sh << 'EOF' + #!/bin/bash + # Sign and notarize macOS application + # This script is a reference for using a real Developer ID certificate + + # Configuration (replace with your values) + APP_PATH="LuckyWorld-Mac-Shipping.app" # Your app path + TEAM_ID="${APPLE_TEAM_ID}" # Your Apple Team ID + BUNDLE_ID="com.luckyworld.game" # Your app bundle ID + ENTITLEMENTS_PATH="LuckyWorld.entitlements" # Your entitlements file + APPLE_ID="${APPLE_NOTARY_USER}" # Your Apple ID + APP_PASSWORD="${APPLE_NOTARY_PASSWORD}" # Your app-specific password + + # Step 1: Check for Developer ID Application certificate + echo "Checking for Developer ID Application certificate..." + IDENTITY=$(security find-identity -v -p codesigning | grep "Developer ID Application" | head -1 | awk -F '"' '{print $2}') + + if [ -z "$IDENTITY" ]; then + echo "Error: No Developer ID Application certificate found" + echo "Please create a Developer ID Application certificate in your Apple Developer account" + echo "and install it in your keychain" + exit 1 + fi + + echo "Using identity: $IDENTITY" + + # Step 2: Sign the app + echo "Signing app..." + codesign --force --options runtime --entitlements "$ENTITLEMENTS_PATH" \ + --sign "$IDENTITY" --timestamp "$APP_PATH" + + # Step 3: Verify signing + echo "Verifying signature..." + codesign -vvv --deep --strict "$APP_PATH" + + # Step 4: Create zip for notarization + echo "Creating zip for notarization..." + ZIP_PATH="${APP_PATH%.app}-notarize.zip" + ditto -c -k --keepParent "$APP_PATH" "$ZIP_PATH" + + # Step 5: Submit for notarization + echo "Submitting for notarization..." + xcrun notarytool submit "$ZIP_PATH" \ + --apple-id "$APPLE_ID" \ + --password "$APP_PASSWORD" \ + --team-id "$TEAM_ID" \ + --wait + + # Step 6: Staple the notarization ticket + echo "Stapling notarization ticket..." + xcrun stapler staple "$APP_PATH" + + # Step 7: Verify notarization + echo "Verifying notarization..." + spctl --assess --verbose --type exec "$APP_PATH" + + # Step 8: Create final distribution zip + echo "Creating final distribution zip..." + FINAL_ZIP="${APP_PATH%.app}-macOS-Signed.zip" + ditto -c -k --keepParent "$APP_PATH" "$FINAL_ZIP" + + echo "โœ… App successfully signed and notarized!" + echo "Final package: $FINAL_ZIP" + EOF + + chmod +x sign_and_notarize_production.sh + echo "โœ… Created reference script for production code signing" + shell: bash + + # Step 7: Documentation for Certificate Requirements + - name: Certificate Requirements Documentation + run: | + echo "๐Ÿ“‹ Requirements for code signing with Developer ID Application certificate:" + echo "" + echo "1. You must have a paid Apple Developer account" + echo "2. You need to create a Developer ID Application certificate in Apple Developer Portal" + echo "3. The certificate must be exported with its private key in p12 format" + echo "4. The certificate must be properly imported into keychain with proper access controls" + echo "5. For production, you should use the xcrun notarytool to notarize your app" + echo "" + echo "Common issues:" + echo "- The p12 file doesn't contain a private key" + echo "- The certificate is not a Developer ID Application type (it might be Developer ID Installer or other type)" + echo "- The certificate has expired" + echo "- The certificate was revoked" + echo "- Keychain access restrictions are preventing access to the private key" + echo "" + echo "For testing CI/CD pipeline: Use ad-hoc signing (as demonstrated in this workflow)" + echo "For production: Follow the steps in the reference script sign_and_notarize_production.sh" + + # Print this information in a file for reference + cat > code_signing_requirements.md << EOF + # macOS Code Signing Requirements + + ## Requirements + 1. You must have a paid Apple Developer account + 2. You need to create a Developer ID Application certificate in Apple Developer Portal + 3. The certificate must be exported with its private key in p12 format + 4. The certificate must be properly imported into keychain with proper access controls + 5. For production, you should use the xcrun notarytool to notarize your app + + ## Common Issues + - The p12 file doesn't contain a private key + - The certificate is not a Developer ID Application type (it might be Developer ID Installer or other type) + - The certificate has expired + - The certificate was revoked + - Keychain access restrictions are preventing access to the private key + + ## Workflow + - For testing CI/CD pipeline: Use ad-hoc signing (as demonstrated in this workflow) + - For production: Follow the steps in the reference script sign_and_notarize_production.sh + EOF + + echo "โœ… Created code signing requirements documentation" + shell: bash + + # Step 8: Package macOS App (For Testing) - name: Package macOS App (Test Only) run: | - echo "โš ๏ธ SKIPPING NOTARIZATION - test build only" - echo "Packaging unsigned test app bundle: $APP_PATH" + echo "๐Ÿ“ฆ Packaging ad-hoc signed app bundle for testing..." - # Create zip package - (cd "$(dirname "$APP_PATH")" && zip -r "${WORKSPACE_DIR}/PackagedReleases/LuckyWorld-macOS-UNSIGNED-TEST.zip" "$(basename "$APP_PATH")") + # Create zip package with clear test indication + ZIP_FILE="PackagedReleases/LuckyWorld-macOS-TEST-ONLY.zip" + (cd "$(dirname "$APP_PATH")" && zip -r "${WORKSPACE_DIR}/$ZIP_FILE" "$(basename "$APP_PATH")") - echo "Created test package: PackagedReleases/LuckyWorld-macOS-UNSIGNED-TEST.zip" - echo "NOTE: This package is NOT properly signed and will NOT pass Gatekeeper!" + echo "โœ… Created test package: $ZIP_FILE" + echo "โš ๏ธ NOTE: This package is signed with ad-hoc identity for TESTING ONLY" + echo "โš ๏ธ It will NOT pass Gatekeeper on macOS and is NOT suitable for distribution" - echo "Debug certificate summary:" - echo "- Check if your p12 file is valid" - echo "- Verify certificate password in secrets" - echo "- Confirm Apple Developer Team ID is correct" + # Create README file to accompany the zip + cat > "PackagedReleases/README-TEST-BUILD.txt" << EOF + # LuckyWorld macOS Test Build + + This build is signed with an ad-hoc signature for TESTING PURPOSES ONLY. + + IMPORTANT: + - This app will NOT pass Gatekeeper on macOS + - It is NOT suitable for distribution to users + - Use the production signing script for creating distributable builds + + For production builds, follow the instructions in code_signing_requirements.md + EOF + + echo "โœ… Created README for test build" shell: bash - # Step 7: Upload test artifact + # Step 9: Upload test artifact - name: Upload Test Build Artifact uses: actions/upload-artifact@v3 if: success() @@ -301,7 +430,7 @@ jobs: path: PackagedReleases/LuckyWorld-macOS-UNSIGNED-TEST.zip retention-days: 7 - # Step 8: Cleanup + # Step 10: Cleanup - name: Cleanup if: always() run: | -- 2.47.2 From 16274ec12687b3630e48626ccdc61d2ec98182a2 Mon Sep 17 00:00:00 2001 From: Ozgur Ersoy Date: Mon, 14 Apr 2025 15:19:32 +0200 Subject: [PATCH 065/109] fix(workflows): refine local signing workflow with improved certificate setup, app signing process, and added packaging step for signed apps --- .gitea/workflows/test-local-signing.yml | 216 +++++++++++++----------- .gitea/workflows/test-macos-build.yml | 133 +-------------- 2 files changed, 120 insertions(+), 229 deletions(-) diff --git a/.gitea/workflows/test-local-signing.yml b/.gitea/workflows/test-local-signing.yml index f13a6c29..05015389 100644 --- a/.gitea/workflows/test-local-signing.yml +++ b/.gitea/workflows/test-local-signing.yml @@ -2,8 +2,8 @@ name: Test Local Signing on: workflow_dispatch: # Manual trigger - # push: - # branches: [ozgur/build] + push: + branches: [ozgur/build] jobs: test-local-signing: @@ -62,7 +62,7 @@ jobs: CFBundleExecutable TestApp CFBundleIdentifier - com.luckyworld.testapp + com.luckyrobots.luckyworld.testapp CFBundleName TestApp CFBundlePackageType @@ -85,144 +85,164 @@ jobs: echo "๐Ÿ” App bundle contents:" ls -la "$TEST_APP_DIR" + + # Store app path as environment variable + echo "APP_PATH=$(pwd)/TestApp.app" >> "$GITHUB_ENV" shell: bash - - name: Self-Sign App for Testing + - name: Setup Certificate + env: + CERTIFICATE_BASE64: ${{ secrets.MACOS_CERTIFICATE }} + CERTIFICATE_PASSWORD: ${{ secrets.MACOS_CERTIFICATE_PWD }} + APPLE_TEAM_ID: ${{ secrets.APPLE_TEAM_ID }} run: | - echo "๐Ÿ” Self-signing app for testing..." + echo "๐Ÿ” Setting up certificate..." - # Create a self-signed certificate for testing - echo "๐Ÿ”‘ Creating self-signed certificate..." + # Create a temporary directory for certificates + CERT_DIR="$HOME/certificates" + mkdir -p "$CERT_DIR" - # Generate key and certificate - openssl req -x509 -nodes -days 365 -newkey rsa:2048 \ - -keyout TestKey.key -out TestCert.crt \ - -subj "/CN=Test Signing/O=LuckyWorld/C=TR" + # Decode the certificate to a p12 file + echo "$CERTIFICATE_BASE64" | base64 --decode > "$CERT_DIR/certificate.p12" - # Sign the app with ad-hoc identity - echo "๐Ÿ” Signing app with ad-hoc identity..." - codesign --force --sign - --timestamp --options runtime --entitlements LuckyWorld.entitlements TestApp.app + # Check certificate format + echo "๐Ÿ“‘ Certificate format check:" + file "$CERT_DIR/certificate.p12" - # Verify signing - echo "๐Ÿ” Verifying signature..." - codesign -vvv --deep --strict TestApp.app + # Create keychain + KEYCHAIN_PATH="$CERT_DIR/app-signing.keychain-db" + KEYCHAIN_PASSWORD="$(openssl rand -base64 12)" - # Check entitlements - echo "๐Ÿ” Checking entitlements..." - codesign -d --entitlements - TestApp.app + # Delete existing keychain if it exists + security delete-keychain "$KEYCHAIN_PATH" 2>/dev/null || true + + # Create new keychain + security create-keychain -p "$KEYCHAIN_PASSWORD" "$KEYCHAIN_PATH" + security set-keychain-settings -t 3600 -u -l "$KEYCHAIN_PATH" + security unlock-keychain -p "$KEYCHAIN_PASSWORD" "$KEYCHAIN_PATH" + + # Add to search list and make default + security list-keychains -d user -s "$KEYCHAIN_PATH" $(security list-keychains -d user | tr -d '"') + security default-keychain -s "$KEYCHAIN_PATH" + + # Import certificate + echo "๐Ÿ”‘ Importing developer certificate..." + security import "$CERT_DIR/certificate.p12" -k "$KEYCHAIN_PATH" -P "$CERTIFICATE_PASSWORD" -T /usr/bin/codesign + + # Set partition list for codesign to access keychain + security set-key-partition-list -S apple-tool:,apple:,codesign: -s -k "$KEYCHAIN_PASSWORD" "$KEYCHAIN_PATH" + + # Verify certificate + echo "๐Ÿ” Verifying certificate..." + security find-identity -v -p codesigning "$KEYCHAIN_PATH" + + # Store keychain variables for later steps + echo "KEYCHAIN_PATH=$KEYCHAIN_PATH" >> "$GITHUB_ENV" + echo "KEYCHAIN_PASSWORD=$KEYCHAIN_PASSWORD" >> "$GITHUB_ENV" + echo "APPLE_TEAM_ID=$APPLE_TEAM_ID" >> "$GITHUB_ENV" + + # Cleanup + rm -f "$CERT_DIR/certificate.p12" shell: bash - - name: Create Sign and Notarize Script (Developer Reference) + - name: Sign with Developer ID run: | - echo "๐Ÿ“ Creating reference script for actual code signing..." + echo "๐Ÿ” Signing app with Developer ID certificate..." - cat > sign_and_notarize.sh << 'EOF' - #!/bin/bash - # Sign and notarize macOS application - # This script is a reference for using a real Developer ID certificate + # Make sure keychain is unlocked + security unlock-keychain -p "$KEYCHAIN_PASSWORD" "$KEYCHAIN_PATH" - # Configuration (replace with your values) - APP_PATH="YourApp.app" - TEAM_ID="YOUR_TEAM_ID" - BUNDLE_ID="com.yourdomain.yourapp" - ENTITLEMENTS_PATH="YourApp.entitlements" - APPLE_ID="your_apple_id@example.com" - APP_PASSWORD="your_app_specific_password" - - # Step 1: Check for Developer ID Application certificate - echo "Checking for Developer ID Application certificate..." - IDENTITY=$(security find-identity -v -p codesigning | grep "Developer ID Application" | head -1 | awk -F '"' '{print $2}') + # Get the Developer ID Application identity + IDENTITY=$(security find-identity -v -p codesigning "$KEYCHAIN_PATH" | grep "Developer ID Application" | head -1 | awk -F '"' '{print $2}') if [ -z "$IDENTITY" ]; then - echo "Error: No Developer ID Application certificate found" - echo "Please create a Developer ID Application certificate in your Apple Developer account" - echo "and install it in your keychain" + echo "โŒ Error: No valid Developer ID Application identity found" + echo "Please check if your certificate is valid and properly imported" exit 1 fi echo "Using identity: $IDENTITY" - # Step 2: Sign the app - echo "Signing app..." - codesign --force --options runtime --entitlements "$ENTITLEMENTS_PATH" \ - --sign "$IDENTITY" --timestamp "$APP_PATH" + # Sign the app bundle + echo "Signing app bundle..." + codesign --force --deep --verbose --options runtime --entitlements LuckyWorld.entitlements --sign "$IDENTITY" --timestamp "$APP_PATH" - # Step 3: Verify signing - echo "Verifying signature..." + # Verify signing + echo "๐Ÿ” Verifying signature..." codesign -vvv --deep --strict "$APP_PATH" - # Step 4: Create zip for notarization - echo "Creating zip for notarization..." - zip_path="/tmp/app_for_notarization.zip" - ditto -c -k --keepParent "$APP_PATH" "$zip_path" + # Check entitlements + echo "๐Ÿ” Checking entitlements..." + codesign -d --entitlements - "$APP_PATH" + shell: bash + + - name: Notarize App + if: success() + env: + APPLE_ID: ${{ secrets.APPLE_NOTARY_USER }} + APP_PASSWORD: ${{ secrets.APPLE_NOTARY_PASSWORD }} + run: | + echo "๐Ÿ“ค Notarizing app..." + + # Make sure we have required secrets + if [ -z "$APPLE_ID" ] || [ -z "$APP_PASSWORD" ] || [ -z "$APPLE_TEAM_ID" ]; then + echo "โš ๏ธ Missing notarization credentials. Skipping notarization." + echo "NOTARIZED=false" >> "$GITHUB_ENV" + exit 0 + fi + + # Create zip for notarization + ZIP_PATH="TestApp-notarize.zip" + ditto -c -k --keepParent "$APP_PATH" "$ZIP_PATH" - # Step 5: Submit for notarization echo "Submitting for notarization..." - xcrun notarytool submit "$zip_path" \ + xcrun notarytool submit "$ZIP_PATH" \ --apple-id "$APPLE_ID" \ --password "$APP_PASSWORD" \ - --team-id "$TEAM_ID" \ + --team-id "$APPLE_TEAM_ID" \ --wait - # Step 6: Staple the notarization ticket + # Staple the notarization ticket echo "Stapling notarization ticket..." xcrun stapler staple "$APP_PATH" - # Step 7: Verify notarization - echo "Verifying notarization..." + # Verify notarization + echo "๐Ÿ” Verifying notarization..." spctl --assess --verbose --type exec "$APP_PATH" - echo "โœ… App successfully signed and notarized!" - EOF - - chmod +x sign_and_notarize.sh - echo "โœ… Created reference script for actual code signing" + echo "NOTARIZED=true" >> "$GITHUB_ENV" shell: bash - - name: Documentation for Certificate Requirements + - name: Package Signed App run: | - echo "๐Ÿ“‹ Requirements for code signing with Developer ID Application certificate:" - echo "" - echo "1. You must have a paid Apple Developer account" - echo "2. You need to create a Developer ID Application certificate in Apple Developer Portal" - echo "3. The certificate must be exported with its private key in p12 format" - echo "4. The certificate must be properly imported into keychain with proper access controls" - echo "5. For production, you should use the xcrun notarytool to notarize your app" - echo "" - echo "Common issues:" - echo "- The p12 file doesn't contain a private key" - echo "- The certificate is not a Developer ID Application type (it might be Developer ID Installer or other type)" - echo "- The certificate has expired" - echo "- The certificate was revoked" - echo "- Keychain access restrictions are preventing access to the private key" - echo "" - echo "For testing purposes, you can sign with ad-hoc identity (as demonstrated in this workflow)" - echo "For production, follow the steps in the reference script created in this workflow" + echo "๐Ÿ“ฆ Packaging signed app..." - # Print this information in a file for reference - echo "๐Ÿ“‹ Requirements for code signing with Developer ID Application certificate:" > signing_requirements.txt - echo "" >> signing_requirements.txt - echo "1. You must have a paid Apple Developer account" >> signing_requirements.txt - echo "2. You need to create a Developer ID Application certificate in Apple Developer Portal" >> signing_requirements.txt - echo "3. The certificate must be exported with its private key in p12 format" >> signing_requirements.txt - echo "4. The certificate must be properly imported into keychain with proper access controls" >> signing_requirements.txt - echo "5. For production, you should use the xcrun notarytool to notarize your app" >> signing_requirements.txt - echo "" >> signing_requirements.txt - echo "Common issues:" >> signing_requirements.txt - echo "- The p12 file doesn't contain a private key" >> signing_requirements.txt - echo "- The certificate is not a Developer ID Application type (it might be Developer ID Installer or other type)" >> signing_requirements.txt - echo "- The certificate has expired" >> signing_requirements.txt - echo "- The certificate was revoked" >> signing_requirements.txt - echo "- Keychain access restrictions are preventing access to the private key" >> signing_requirements.txt - echo "" >> signing_requirements.txt - echo "For testing purposes, you can sign with ad-hoc identity (as demonstrated in this workflow)" >> signing_requirements.txt - echo "For production, follow the steps in the reference script created in this workflow" >> signing_requirements.txt + if [ "${NOTARIZED:-false}" == "true" ]; then + ZIP_FILE="TestApp-Signed-Notarized.zip" + echo "Creating distribution package with notarized app..." + else + ZIP_FILE="TestApp-Signed.zip" + echo "Creating distribution package with signed app..." + fi + + # Create zip package + ditto -c -k --keepParent "$APP_PATH" "$ZIP_FILE" + + echo "โœ… Created package: $ZIP_FILE" shell: bash + - name: Upload Artifact + uses: actions/upload-artifact@v3 + with: + name: LuckyWorld-Signed-App + path: TestApp-*.zip + retention-days: 7 + - name: Cleanup if: always() run: | echo "๐Ÿงน Cleaning up..." - rm -rf TestApp.app TestKey.key TestCert.crt || true + rm -rf TestApp.app TestApp-*.zip || true + security delete-keychain "$KEYCHAIN_PATH" 2>/dev/null || true echo "โœ… Cleanup complete" shell: bash \ No newline at end of file diff --git a/.gitea/workflows/test-macos-build.yml b/.gitea/workflows/test-macos-build.yml index 02b1bf3d..48c376d7 100644 --- a/.gitea/workflows/test-macos-build.yml +++ b/.gitea/workflows/test-macos-build.yml @@ -2,8 +2,8 @@ name: Test macOS Build Action on: workflow_dispatch: # Manual trigger only for testing - push: - branches: [ozgur/build] + # push: + # branches: [ozgur/build] jobs: test-macos-build: @@ -21,9 +21,6 @@ jobs: if [ -f "LuckyWorld.entitlements" ]; then echo "Using existing LuckyWorld.entitlements file" ENTITLEMENTS_FILE="LuckyWorld.entitlements" - elif [ -f "LuckyRobots.entitlements" ]; then - echo "Using existing LuckyRobots.entitlements file" - ENTITLEMENTS_FILE="LuckyRobots.entitlements" else echo "Creating default entitlements file as LuckyWorld.entitlements" # Create entitlements file line by line instead of heredoc @@ -74,55 +71,6 @@ jobs: echo "WORKSPACE_DIR=$WORKSPACE_DIR" >> "$GITHUB_ENV" shell: bash - - name: Debug Certificate Import (Test) - env: - CERTIFICATE_BASE64: ${{ secrets.MACOS_CERTIFICATE }} - CERTIFICATE_PASSWORD: ${{ secrets.MACOS_CERTIFICATE_PWD }} - APPLE_TEAM_ID: ${{ secrets.APPLE_TEAM_ID }} - run: | - set -e # Fail on any error - - echo "Current working directory: $(pwd)" - echo "Checking for .app bundles in Saved directory..." - find ./Saved -type d -name "*.app" || echo "No app bundles found." - - echo "Decoding certificate..." - CERT_DIR="$HOME/certificates" - mkdir -p "$CERT_DIR" - CERT_PATH="$CERT_DIR/developer_certificate.p12" - echo "$CERTIFICATE_BASE64" | base64 --decode > "$CERT_PATH" - - echo "Decoded certificate size: $(wc -c < "$CERT_PATH") bytes" - echo "Type: $(file "$CERT_PATH")" - - echo "Creating and configuring custom keychain..." - CUSTOM_KEYCHAIN="$CERT_DIR/build.keychain" - CUSTOM_PASSWORD="temppassword123" - - security create-keychain -p "$CUSTOM_PASSWORD" "$CUSTOM_KEYCHAIN" - security set-keychain-settings "$CUSTOM_KEYCHAIN" - security unlock-keychain -p "$CUSTOM_PASSWORD" "$CUSTOM_KEYCHAIN" - - echo "Setting only this keychain as active..." - security list-keychains -s "$CUSTOM_KEYCHAIN" - security default-keychain -s "$CUSTOM_KEYCHAIN" - - echo "Importing certificate..." - security import "$CERT_PATH" -P "$CERTIFICATE_PASSWORD" -k "$CUSTOM_KEYCHAIN" -T /usr/bin/codesign - - echo "Granting access to codesign..." - security set-key-partition-list -S apple-tool:,apple: -s -k "$CUSTOM_PASSWORD" "$CUSTOM_KEYCHAIN" - - echo "Verifying imported identities..." - security find-identity -v -p codesigning "$CUSTOM_KEYCHAIN" - - echo "Setting environment variables for future steps..." - echo "KEYCHAIN_PATH=$CUSTOM_KEYCHAIN" >> "$GITHUB_ENV" - echo "KEYCHAIN_PASSWORD=$CUSTOM_PASSWORD" >> "$GITHUB_ENV" - echo "DIRECT_SIGNING_AVAILABLE=true" >> "$GITHUB_ENV" - echo "APPLE_TEAM=$APPLE_TEAM_ID" >> "$GITHUB_ENV" - shell: bash - # Step 2: Build for macOS - name: Build for macOS run: | @@ -343,83 +291,6 @@ jobs: chmod +x sign_and_notarize_production.sh echo "โœ… Created reference script for production code signing" shell: bash - - # Step 7: Documentation for Certificate Requirements - - name: Certificate Requirements Documentation - run: | - echo "๐Ÿ“‹ Requirements for code signing with Developer ID Application certificate:" - echo "" - echo "1. You must have a paid Apple Developer account" - echo "2. You need to create a Developer ID Application certificate in Apple Developer Portal" - echo "3. The certificate must be exported with its private key in p12 format" - echo "4. The certificate must be properly imported into keychain with proper access controls" - echo "5. For production, you should use the xcrun notarytool to notarize your app" - echo "" - echo "Common issues:" - echo "- The p12 file doesn't contain a private key" - echo "- The certificate is not a Developer ID Application type (it might be Developer ID Installer or other type)" - echo "- The certificate has expired" - echo "- The certificate was revoked" - echo "- Keychain access restrictions are preventing access to the private key" - echo "" - echo "For testing CI/CD pipeline: Use ad-hoc signing (as demonstrated in this workflow)" - echo "For production: Follow the steps in the reference script sign_and_notarize_production.sh" - - # Print this information in a file for reference - cat > code_signing_requirements.md << EOF - # macOS Code Signing Requirements - - ## Requirements - 1. You must have a paid Apple Developer account - 2. You need to create a Developer ID Application certificate in Apple Developer Portal - 3. The certificate must be exported with its private key in p12 format - 4. The certificate must be properly imported into keychain with proper access controls - 5. For production, you should use the xcrun notarytool to notarize your app - - ## Common Issues - - The p12 file doesn't contain a private key - - The certificate is not a Developer ID Application type (it might be Developer ID Installer or other type) - - The certificate has expired - - The certificate was revoked - - Keychain access restrictions are preventing access to the private key - - ## Workflow - - For testing CI/CD pipeline: Use ad-hoc signing (as demonstrated in this workflow) - - For production: Follow the steps in the reference script sign_and_notarize_production.sh - EOF - - echo "โœ… Created code signing requirements documentation" - shell: bash - - # Step 8: Package macOS App (For Testing) - - name: Package macOS App (Test Only) - run: | - echo "๐Ÿ“ฆ Packaging ad-hoc signed app bundle for testing..." - - # Create zip package with clear test indication - ZIP_FILE="PackagedReleases/LuckyWorld-macOS-TEST-ONLY.zip" - (cd "$(dirname "$APP_PATH")" && zip -r "${WORKSPACE_DIR}/$ZIP_FILE" "$(basename "$APP_PATH")") - - echo "โœ… Created test package: $ZIP_FILE" - echo "โš ๏ธ NOTE: This package is signed with ad-hoc identity for TESTING ONLY" - echo "โš ๏ธ It will NOT pass Gatekeeper on macOS and is NOT suitable for distribution" - - # Create README file to accompany the zip - cat > "PackagedReleases/README-TEST-BUILD.txt" << EOF - # LuckyWorld macOS Test Build - - This build is signed with an ad-hoc signature for TESTING PURPOSES ONLY. - - IMPORTANT: - - This app will NOT pass Gatekeeper on macOS - - It is NOT suitable for distribution to users - - Use the production signing script for creating distributable builds - - For production builds, follow the instructions in code_signing_requirements.md - EOF - - echo "โœ… Created README for test build" - shell: bash # Step 9: Upload test artifact - name: Upload Test Build Artifact -- 2.47.2 From 45baeeb390b838d5208f2c8cab3c14c71e9810b2 Mon Sep 17 00:00:00 2001 From: Ozgur Ersoy Date: Mon, 14 Apr 2025 15:23:10 +0200 Subject: [PATCH 066/109] fix(workflows): enhance local signing workflow with detailed certificate checks, multiple import attempts, and improved debugging for Developer ID certificates --- .gitea/workflows/test-local-signing.yml | 124 +++++++++++++++++++----- 1 file changed, 102 insertions(+), 22 deletions(-) diff --git a/.gitea/workflows/test-local-signing.yml b/.gitea/workflows/test-local-signing.yml index 05015389..4356d7bd 100644 --- a/.gitea/workflows/test-local-signing.yml +++ b/.gitea/workflows/test-local-signing.yml @@ -105,13 +105,17 @@ jobs: # Decode the certificate to a p12 file echo "$CERTIFICATE_BASE64" | base64 --decode > "$CERT_DIR/certificate.p12" - # Check certificate format + # Check certificate format and details echo "๐Ÿ“‘ Certificate format check:" file "$CERT_DIR/certificate.p12" + # Try to get certificate info with openssl + echo "๐Ÿ“‘ Certificate info with OpenSSL:" + openssl pkcs12 -info -in "$CERT_DIR/certificate.p12" -nokeys -passin pass:"$CERTIFICATE_PASSWORD" || echo "Failed to read certificate with OpenSSL" + # Create keychain KEYCHAIN_PATH="$CERT_DIR/app-signing.keychain-db" - KEYCHAIN_PASSWORD="$(openssl rand -base64 12)" + KEYCHAIN_PASSWORD="temppassword123" # Delete existing keychain if it exists security delete-keychain "$KEYCHAIN_PATH" 2>/dev/null || true @@ -125,47 +129,123 @@ jobs: security list-keychains -d user -s "$KEYCHAIN_PATH" $(security list-keychains -d user | tr -d '"') security default-keychain -s "$KEYCHAIN_PATH" - # Import certificate - echo "๐Ÿ”‘ Importing developer certificate..." + # Try multiple import approaches + echo "๐Ÿ”‘ Importing developer certificate - attempt 1 (standard)..." security import "$CERT_DIR/certificate.p12" -k "$KEYCHAIN_PATH" -P "$CERTIFICATE_PASSWORD" -T /usr/bin/codesign + echo "๐Ÿ”‘ Importing developer certificate - attempt 2 (with flags)..." + security import "$CERT_DIR/certificate.p12" -k "$KEYCHAIN_PATH" -P "$CERTIFICATE_PASSWORD" -T /usr/bin/codesign -x -A + + echo "๐Ÿ”‘ Importing developer certificate - attempt 3 (with format)..." + security import "$CERT_DIR/certificate.p12" -k "$KEYCHAIN_PATH" -P "$CERTIFICATE_PASSWORD" -T /usr/bin/codesign -f pkcs12 + # Set partition list for codesign to access keychain security set-key-partition-list -S apple-tool:,apple:,codesign: -s -k "$KEYCHAIN_PASSWORD" "$KEYCHAIN_PATH" + # Check all certificates in keychain + echo "๐Ÿ” Listing all certificates in keychain..." + security find-certificate -a "$KEYCHAIN_PATH" + # Verify certificate - echo "๐Ÿ” Verifying certificate..." + echo "๐Ÿ” Verifying code signing identities..." security find-identity -v -p codesigning "$KEYCHAIN_PATH" + # Alternative check for identities + echo "๐Ÿ” Listing identities with code signing usage..." + security find-certificate -a -c "Developer ID Application" -p "$KEYCHAIN_PATH" | grep -q "Code Signing" && echo "โœ… Certificate has code signing usage" || echo "โŒ Certificate does NOT have code signing usage" + + # Try to use the System keychain as a fallback + echo "๐Ÿ” Checking system keychain for code signing identities..." + SYSTEM_IDENTITIES=$(security find-identity -v -p codesigning) + echo "$SYSTEM_IDENTITIES" + + if echo "$SYSTEM_IDENTITIES" | grep -q "Developer ID Application"; then + echo "โœ… Found Developer ID Application certificate in system keychain" + echo "USE_SYSTEM_CERT=true" >> "$GITHUB_ENV" + else + echo "โŒ No Developer ID Application certificate found in system keychain" + echo "USE_SYSTEM_CERT=false" >> "$GITHUB_ENV" + fi + # Store keychain variables for later steps echo "KEYCHAIN_PATH=$KEYCHAIN_PATH" >> "$GITHUB_ENV" echo "KEYCHAIN_PASSWORD=$KEYCHAIN_PASSWORD" >> "$GITHUB_ENV" echo "APPLE_TEAM_ID=$APPLE_TEAM_ID" >> "$GITHUB_ENV" - # Cleanup - rm -f "$CERT_DIR/certificate.p12" + # Debug: keep p12 file for inspection + echo "๐Ÿ’พ Keeping certificate.p12 for debugging" + shell: bash + + - name: Debug Certificate Content + if: always() + env: + CERTIFICATE_PASSWORD: ${{ secrets.MACOS_CERTIFICATE_PWD }} + run: | + echo "๐Ÿ”Ž Debugging certificate content..." + CERT_DIR="$HOME/certificates" + + # Check if p12 file exists + if [ ! -f "$CERT_DIR/certificate.p12" ]; then + echo "โŒ Certificate file not found" + exit 0 + fi + + # Try with OpenSSL to extract certificate info + echo "Attempting to extract certificate info..." + openssl pkcs12 -in "$CERT_DIR/certificate.p12" -info -nokeys -passin pass:"$CERTIFICATE_PASSWORD" > cert_info.txt || echo "Failed to extract info" + + # Check certificate contents + echo "Certificate subject information:" + grep "subject" cert_info.txt || echo "No subject information found" + + echo "Certificate issuer information:" + grep "issuer" cert_info.txt || echo "No issuer information found" + + # Check if it's a Developer ID certificate + if grep -q "Developer ID" cert_info.txt; then + echo "โœ… This appears to be a Developer ID certificate" + else + echo "โŒ This does NOT appear to be a Developer ID certificate" + fi + + # Check if it has a private key + echo "Checking for private key..." + if openssl pkcs12 -in "$CERT_DIR/certificate.p12" -nocerts -passin pass:"$CERTIFICATE_PASSWORD" -passout pass:temp 2>/dev/null; then + echo "โœ… Certificate contains a private key" + else + echo "โŒ Certificate does NOT contain a private key or wrong password" + fi shell: bash - name: Sign with Developer ID run: | echo "๐Ÿ” Signing app with Developer ID certificate..." - # Make sure keychain is unlocked - security unlock-keychain -p "$KEYCHAIN_PASSWORD" "$KEYCHAIN_PATH" - - # Get the Developer ID Application identity - IDENTITY=$(security find-identity -v -p codesigning "$KEYCHAIN_PATH" | grep "Developer ID Application" | head -1 | awk -F '"' '{print $2}') - - if [ -z "$IDENTITY" ]; then - echo "โŒ Error: No valid Developer ID Application identity found" - echo "Please check if your certificate is valid and properly imported" - exit 1 + # Decide which keychain to use + if [ "${USE_SYSTEM_CERT:-false}" = "true" ]; then + echo "Using system keychain identity" + IDENTITY=$(security find-identity -v -p codesigning | grep "Developer ID Application" | head -1 | awk -F '"' '{print $2}') + else + # Make sure keychain is unlocked + security unlock-keychain -p "$KEYCHAIN_PASSWORD" "$KEYCHAIN_PATH" + echo "Using custom keychain identity" + IDENTITY=$(security find-identity -v -p codesigning "$KEYCHAIN_PATH" | grep "Developer ID Application" | head -1 | awk -F '"' '{print $2}') fi - echo "Using identity: $IDENTITY" - - # Sign the app bundle - echo "Signing app bundle..." - codesign --force --deep --verbose --options runtime --entitlements LuckyWorld.entitlements --sign "$IDENTITY" --timestamp "$APP_PATH" + if [ -z "$IDENTITY" ]; then + echo "โŒ No valid Developer ID Application certificate found" + echo "Falling back to ad-hoc signing for testing..." + # Use ad-hoc identity as fallback + codesign --force --deep --verbose --options runtime --entitlements LuckyWorld.entitlements --sign - --timestamp "$APP_PATH" + echo "SIGNED=adhoc" >> "$GITHUB_ENV" + else + echo "Using identity: $IDENTITY" + + # Sign the app bundle + echo "Signing app bundle with Developer ID..." + codesign --force --deep --verbose --options runtime --entitlements LuckyWorld.entitlements --sign "$IDENTITY" --timestamp "$APP_PATH" + echo "SIGNED=identity" >> "$GITHUB_ENV" + fi # Verify signing echo "๐Ÿ” Verifying signature..." -- 2.47.2 From 751105d1e2000be699b52ef5fb3f3017b8568898 Mon Sep 17 00:00:00 2001 From: Ozgur Ersoy Date: Mon, 14 Apr 2025 15:48:44 +0200 Subject: [PATCH 067/109] fix(workflows): update local signing workflow to use certificate hash for improved identity handling and debugging --- .gitea/workflows/test-local-signing.yml | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/.gitea/workflows/test-local-signing.yml b/.gitea/workflows/test-local-signing.yml index 4356d7bd..6fde664c 100644 --- a/.gitea/workflows/test-local-signing.yml +++ b/.gitea/workflows/test-local-signing.yml @@ -224,26 +224,29 @@ jobs: # Decide which keychain to use if [ "${USE_SYSTEM_CERT:-false}" = "true" ]; then echo "Using system keychain identity" - IDENTITY=$(security find-identity -v -p codesigning | grep "Developer ID Application" | head -1 | awk -F '"' '{print $2}') + # Get certificate hash instead of name to avoid ambiguity + IDENTITY_HASH=$(security find-identity -v -p codesigning | grep "Developer ID Application" | head -1 | awk '{print $2}') + echo "Using certificate hash: $IDENTITY_HASH" else # Make sure keychain is unlocked security unlock-keychain -p "$KEYCHAIN_PASSWORD" "$KEYCHAIN_PATH" echo "Using custom keychain identity" - IDENTITY=$(security find-identity -v -p codesigning "$KEYCHAIN_PATH" | grep "Developer ID Application" | head -1 | awk -F '"' '{print $2}') + # Get certificate hash instead of name to avoid ambiguity + IDENTITY_HASH=$(security find-identity -v -p codesigning "$KEYCHAIN_PATH" | grep "Developer ID Application" | head -1 | awk '{print $2}') + echo "Using certificate hash: $IDENTITY_HASH" fi - if [ -z "$IDENTITY" ]; then + if [ -z "$IDENTITY_HASH" ]; then echo "โŒ No valid Developer ID Application certificate found" echo "Falling back to ad-hoc signing for testing..." # Use ad-hoc identity as fallback codesign --force --deep --verbose --options runtime --entitlements LuckyWorld.entitlements --sign - --timestamp "$APP_PATH" echo "SIGNED=adhoc" >> "$GITHUB_ENV" else - echo "Using identity: $IDENTITY" + echo "Signing app bundle with Developer ID hash: $IDENTITY_HASH" - # Sign the app bundle - echo "Signing app bundle with Developer ID..." - codesign --force --deep --verbose --options runtime --entitlements LuckyWorld.entitlements --sign "$IDENTITY" --timestamp "$APP_PATH" + # Sign the app bundle using the hash + codesign --force --deep --verbose --options runtime --entitlements LuckyWorld.entitlements --sign "$IDENTITY_HASH" --timestamp "$APP_PATH" echo "SIGNED=identity" >> "$GITHUB_ENV" fi -- 2.47.2 From 69fcbde72f57796581570a90a425e96ffafa3dc9 Mon Sep 17 00:00:00 2001 From: Ozgur Ersoy Date: Mon, 14 Apr 2025 15:51:17 +0200 Subject: [PATCH 068/109] fix(workflows): enhance local signing workflow to support App Store Connect API key notarization and improve credential handling --- .gitea/workflows/test-local-signing.yml | 93 +++++++++++++++++++------ 1 file changed, 70 insertions(+), 23 deletions(-) diff --git a/.gitea/workflows/test-local-signing.yml b/.gitea/workflows/test-local-signing.yml index 6fde664c..fc68b735 100644 --- a/.gitea/workflows/test-local-signing.yml +++ b/.gitea/workflows/test-local-signing.yml @@ -264,36 +264,83 @@ jobs: env: APPLE_ID: ${{ secrets.APPLE_NOTARY_USER }} APP_PASSWORD: ${{ secrets.APPLE_NOTARY_PASSWORD }} + API_KEY_ID: ${{ secrets.APPLE_NOTARY_API_KEY_ID }} + API_ISSUER_ID: ${{ secrets.APPLE_NOTARY_API_ISSUER_ID }} + API_KEY: ${{ secrets.APPLE_NOTARY_API_KEY }} run: | echo "๐Ÿ“ค Notarizing app..." - # Make sure we have required secrets - if [ -z "$APPLE_ID" ] || [ -z "$APP_PASSWORD" ] || [ -z "$APPLE_TEAM_ID" ]; then + # Check if we have API key credentials + if [ -n "$API_KEY_ID" ] && [ -n "$API_ISSUER_ID" ] && [ -n "$API_KEY" ]; then + echo "Using App Store Connect API key for notarization..." + + # Create directory for API key + mkdir -p ~/private_keys + echo "$API_KEY" > ~/private_keys/AuthKey_${API_KEY_ID}.p8 + + # Create zip for notarization + ZIP_PATH="TestApp-notarize.zip" + ditto -c -k --keepParent "$APP_PATH" "$ZIP_PATH" + + echo "Submitting for notarization with API key..." + xcrun notarytool submit "$ZIP_PATH" \ + --key ~/private_keys/AuthKey_${API_KEY_ID}.p8 \ + --key-id "$API_KEY_ID" \ + --issuer "$API_ISSUER_ID" \ + --wait + + # Staple the notarization ticket + echo "Stapling notarization ticket..." + xcrun stapler staple "$APP_PATH" + + # Verify notarization + echo "๐Ÿ” Verifying notarization..." + spctl --assess --verbose --type exec "$APP_PATH" + + echo "NOTARIZED=true" >> "$GITHUB_ENV" + + # Clean up + rm -rf ~/private_keys + + # Fall back to App-specific password if API key not available + elif [ -n "$APPLE_ID" ] && [ -n "$APP_PASSWORD" ] && [ -n "$APPLE_TEAM_ID" ]; then + echo "Using App-specific password for notarization..." + + # Create zip for notarization + ZIP_PATH="TestApp-notarize.zip" + ditto -c -k --keepParent "$APP_PATH" "$ZIP_PATH" + + echo "Submitting for notarization..." + xcrun notarytool submit "$ZIP_PATH" \ + --apple-id "$APPLE_ID" \ + --password "$APP_PASSWORD" \ + --team-id "$APPLE_TEAM_ID" \ + --wait + + # Staple the notarization ticket + echo "Stapling notarization ticket..." + xcrun stapler staple "$APP_PATH" + + # Verify notarization + echo "๐Ÿ” Verifying notarization..." + spctl --assess --verbose --type exec "$APP_PATH" + + echo "NOTARIZED=true" >> "$GITHUB_ENV" + else echo "โš ๏ธ Missing notarization credentials. Skipping notarization." + echo "For App Store Connect API key method, set these secrets:" + echo " - APPLE_NOTARY_API_KEY_ID: Your API key ID" + echo " - APPLE_NOTARY_API_ISSUER_ID: Your API issuer ID" + echo " - APPLE_NOTARY_API_KEY: Your API key content (p8 file)" + echo "" + echo "For App-specific password method, set these secrets:" + echo " - APPLE_NOTARY_USER: Your Apple ID (email)" + echo " - APPLE_NOTARY_PASSWORD: Your app-specific password" + echo " - APPLE_TEAM_ID: Your Apple Developer team ID" + echo "NOTARIZED=false" >> "$GITHUB_ENV" exit 0 fi - - # Create zip for notarization - ZIP_PATH="TestApp-notarize.zip" - ditto -c -k --keepParent "$APP_PATH" "$ZIP_PATH" - - echo "Submitting for notarization..." - xcrun notarytool submit "$ZIP_PATH" \ - --apple-id "$APPLE_ID" \ - --password "$APP_PASSWORD" \ - --team-id "$APPLE_TEAM_ID" \ - --wait - - # Staple the notarization ticket - echo "Stapling notarization ticket..." - xcrun stapler staple "$APP_PATH" - - # Verify notarization - echo "๐Ÿ” Verifying notarization..." - spctl --assess --verbose --type exec "$APP_PATH" - - echo "NOTARIZED=true" >> "$GITHUB_ENV" shell: bash - name: Package Signed App -- 2.47.2 From 8cce263247282f3a02ec949622f4209f7b9ed20b Mon Sep 17 00:00:00 2001 From: Ozgur Ersoy Date: Mon, 14 Apr 2025 15:52:59 +0200 Subject: [PATCH 069/109] fix(workflows): update local signing workflow to standardize notarization credential names and improve error messaging --- .gitea/workflows/test-local-signing.yml | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/.gitea/workflows/test-local-signing.yml b/.gitea/workflows/test-local-signing.yml index fc68b735..4fd92d79 100644 --- a/.gitea/workflows/test-local-signing.yml +++ b/.gitea/workflows/test-local-signing.yml @@ -262,11 +262,11 @@ jobs: - name: Notarize App if: success() env: - APPLE_ID: ${{ secrets.APPLE_NOTARY_USER }} - APP_PASSWORD: ${{ secrets.APPLE_NOTARY_PASSWORD }} - API_KEY_ID: ${{ secrets.APPLE_NOTARY_API_KEY_ID }} - API_ISSUER_ID: ${{ secrets.APPLE_NOTARY_API_ISSUER_ID }} - API_KEY: ${{ secrets.APPLE_NOTARY_API_KEY }} + APPLE_ID: ${{ secrets.NOTARY_USER }} + APP_PASSWORD: ${{ secrets.NOTARY_PASSWORD }} + API_KEY_ID: ${{ secrets.NOTARY_API_KEY_ID }} + API_ISSUER_ID: ${{ secrets.NOTARY_API_ISSUER_ID }} + API_KEY: ${{ secrets.NOTARY_API_KEY }} run: | echo "๐Ÿ“ค Notarizing app..." @@ -329,13 +329,13 @@ jobs: else echo "โš ๏ธ Missing notarization credentials. Skipping notarization." echo "For App Store Connect API key method, set these secrets:" - echo " - APPLE_NOTARY_API_KEY_ID: Your API key ID" - echo " - APPLE_NOTARY_API_ISSUER_ID: Your API issuer ID" - echo " - APPLE_NOTARY_API_KEY: Your API key content (p8 file)" + echo " - NOTARY_API_KEY_ID: Your API key ID" + echo " - NOTARY_API_ISSUER_ID: Your API issuer ID" + echo " - NOTARY_API_KEY: Your API key content (p8 file)" echo "" echo "For App-specific password method, set these secrets:" - echo " - APPLE_NOTARY_USER: Your Apple ID (email)" - echo " - APPLE_NOTARY_PASSWORD: Your app-specific password" + echo " - NOTARY_USER: Your Apple ID (email)" + echo " - NOTARY_PASSWORD: Your app-specific password" echo " - APPLE_TEAM_ID: Your Apple Developer team ID" echo "NOTARIZED=false" >> "$GITHUB_ENV" -- 2.47.2 From 446b5af7f3cc14a0fe8959e51e30ad06bfd6a9d9 Mon Sep 17 00:00:00 2001 From: Ozgur Ersoy Date: Mon, 14 Apr 2025 15:54:44 +0200 Subject: [PATCH 070/109] fix(workflows): update local signing workflow to improve API key handling and enhance error messaging for notarization credentials --- .gitea/workflows/test-local-signing.yml | 24 +++++++++++++++++------- 1 file changed, 17 insertions(+), 7 deletions(-) diff --git a/.gitea/workflows/test-local-signing.yml b/.gitea/workflows/test-local-signing.yml index 4fd92d79..4cf4cfbd 100644 --- a/.gitea/workflows/test-local-signing.yml +++ b/.gitea/workflows/test-local-signing.yml @@ -265,18 +265,28 @@ jobs: APPLE_ID: ${{ secrets.NOTARY_USER }} APP_PASSWORD: ${{ secrets.NOTARY_PASSWORD }} API_KEY_ID: ${{ secrets.NOTARY_API_KEY_ID }} - API_ISSUER_ID: ${{ secrets.NOTARY_API_ISSUER_ID }} - API_KEY: ${{ secrets.NOTARY_API_KEY }} + API_ISSUER_ID: ${{ secrets.NOTARY_API_KEY_ISSUER_ID }} + API_KEY_PATH: ${{ secrets.NOTARY_API_KEY_PATH }} run: | echo "๐Ÿ“ค Notarizing app..." # Check if we have API key credentials - if [ -n "$API_KEY_ID" ] && [ -n "$API_ISSUER_ID" ] && [ -n "$API_KEY" ]; then + if [ -n "$API_KEY_ID" ] && [ -n "$API_ISSUER_ID" ] && [ -n "$API_KEY_PATH" ]; then echo "Using App Store Connect API key for notarization..." - # Create directory for API key + # Create directory for API key if API_KEY_PATH contains content mkdir -p ~/private_keys - echo "$API_KEY" > ~/private_keys/AuthKey_${API_KEY_ID}.p8 + + # Check if API_KEY_PATH is a path or content + if [[ "$API_KEY_PATH" == /* ]] && [ -f "$API_KEY_PATH" ]; then + # It's a path to a file + echo "Using API key from path: $API_KEY_PATH" + cp "$API_KEY_PATH" ~/private_keys/AuthKey_${API_KEY_ID}.p8 + else + # It contains the key content + echo "Using API key from content" + echo "$API_KEY_PATH" > ~/private_keys/AuthKey_${API_KEY_ID}.p8 + fi # Create zip for notarization ZIP_PATH="TestApp-notarize.zip" @@ -330,8 +340,8 @@ jobs: echo "โš ๏ธ Missing notarization credentials. Skipping notarization." echo "For App Store Connect API key method, set these secrets:" echo " - NOTARY_API_KEY_ID: Your API key ID" - echo " - NOTARY_API_ISSUER_ID: Your API issuer ID" - echo " - NOTARY_API_KEY: Your API key content (p8 file)" + echo " - NOTARY_API_KEY_ISSUER_ID: Your API issuer ID" + echo " - NOTARY_API_KEY_PATH: Path to or content of your p8 file" echo "" echo "For App-specific password method, set these secrets:" echo " - NOTARY_USER: Your Apple ID (email)" -- 2.47.2 From 336f57f6f02ea10a91b2c9138406c77572ddf7a7 Mon Sep 17 00:00:00 2001 From: Ozgur Ersoy Date: Mon, 14 Apr 2025 16:04:41 +0200 Subject: [PATCH 071/109] feat(actions): add macOS Sign and Notarize action for automated app signing and notarization --- .gitea/actions/macos-notarize/action.yml | 346 +++++++++++++++++++++++ 1 file changed, 346 insertions(+) create mode 100644 .gitea/actions/macos-notarize/action.yml diff --git a/.gitea/actions/macos-notarize/action.yml b/.gitea/actions/macos-notarize/action.yml new file mode 100644 index 00000000..554319df --- /dev/null +++ b/.gitea/actions/macos-notarize/action.yml @@ -0,0 +1,346 @@ +name: "macOS Sign and Notarize" +description: "Signs and notarizes macOS applications with Developer ID certificate" +author: moersoy" + +inputs: + app-path: + description: "Path to the app bundle (.app)" + required: true + entitlements-file: + description: "Path to the entitlements file (.entitlements)" + required: true + team-id: + description: "Apple Developer Team ID" + required: true + certificate-base64: + description: "Base64-encoded Developer ID Application certificate (.p12)" + required: true + certificate-password: + description: "Password for the Developer ID Application certificate" + required: true + notarization-method: + description: "Method to use for notarization: 'api-key' or 'app-password'" + required: false + default: "api-key" + notary-user: + description: "Apple ID for notarization (for app-password method)" + required: false + notary-password: + description: "App-specific password for notarization (for app-password method)" + required: false + notary-api-key-id: + description: "API Key ID for notarization (for api-key method)" + required: false + notary-api-key-issuer-id: + description: "API Issuer ID for notarization (for api-key method)" + required: false + notary-api-key-path: + description: "Path to or content of the API Key .p8 file (for api-key method)" + required: false + bundle-id: + description: "App bundle identifier (com.example.app)" + required: false + fallback-to-adhoc: + description: "Whether to fall back to ad-hoc signing if certificate is invalid" + required: false + default: "true" + +outputs: + signed: + description: "Whether the app was signed (identity, adhoc, or none)" + value: ${{ steps.sign.outputs.signed }} + notarized: + description: "Whether the app was notarized (true or false)" + value: ${{ steps.notarize.outputs.notarized }} + package-path: + description: "Path to the final package" + value: ${{ steps.package.outputs.package-path }} + +runs: + using: "composite" + steps: + - name: Setup Certificate + id: setup-cert + shell: bash + env: + CERTIFICATE_BASE64: ${{ inputs.certificate-base64 }} + CERTIFICATE_PASSWORD: ${{ inputs.certificate-password }} + APPLE_TEAM_ID: ${{ inputs.team-id }} + run: | + echo "๐Ÿ” Setting up certificate..." + + # Create a temporary directory for certificates + CERT_DIR="$HOME/certificates" + mkdir -p "$CERT_DIR" + + # Decode the certificate to a p12 file + echo "$CERTIFICATE_BASE64" | base64 --decode > "$CERT_DIR/certificate.p12" + + # Create keychain + KEYCHAIN_PATH="$CERT_DIR/app-signing.keychain-db" + KEYCHAIN_PASSWORD="temppassword123" + + # Delete existing keychain if it exists + security delete-keychain "$KEYCHAIN_PATH" 2>/dev/null || true + + # Create new keychain + security create-keychain -p "$KEYCHAIN_PASSWORD" "$KEYCHAIN_PATH" + security set-keychain-settings -t 3600 -u -l "$KEYCHAIN_PATH" + security unlock-keychain -p "$KEYCHAIN_PASSWORD" "$KEYCHAIN_PATH" + + # Add to search list and make default + security list-keychains -d user -s "$KEYCHAIN_PATH" $(security list-keychains -d user | tr -d '"') + security default-keychain -s "$KEYCHAIN_PATH" + + # Import certificate + echo "๐Ÿ”‘ Importing developer certificate..." + security import "$CERT_DIR/certificate.p12" -k "$KEYCHAIN_PATH" -P "$CERTIFICATE_PASSWORD" -T /usr/bin/codesign + + # Try with additional parameters if needed + security import "$CERT_DIR/certificate.p12" -k "$KEYCHAIN_PATH" -P "$CERTIFICATE_PASSWORD" -T /usr/bin/codesign -f pkcs12 || true + + # Set partition list for codesign to access keychain + security set-key-partition-list -S apple-tool:,apple:,codesign: -s -k "$KEYCHAIN_PASSWORD" "$KEYCHAIN_PATH" + + # Verify certificate + echo "๐Ÿ” Verifying code signing identities..." + security find-identity -v -p codesigning "$KEYCHAIN_PATH" + + # Try to use the System keychain as a fallback + echo "๐Ÿ” Checking system keychain for code signing identities..." + SYSTEM_IDENTITIES=$(security find-identity -v -p codesigning) + echo "$SYSTEM_IDENTITIES" + + if echo "$SYSTEM_IDENTITIES" | grep -q "Developer ID Application"; then + echo "โœ… Found Developer ID Application certificate in system keychain" + echo "::set-output name=use_system_cert::true" + else + echo "::set-output name=use_system_cert::false" + fi + + # Store keychain variables for later steps + echo "KEYCHAIN_PATH=$KEYCHAIN_PATH" >> $GITHUB_ENV + echo "KEYCHAIN_PASSWORD=$KEYCHAIN_PASSWORD" >> $GITHUB_ENV + echo "APPLE_TEAM_ID=$APPLE_TEAM_ID" >> $GITHUB_ENV + + # Clean up + rm -f "$CERT_DIR/certificate.p12" + + - name: Sign App + id: sign + shell: bash + run: | + echo "๐Ÿ” Signing app with Developer ID certificate..." + + # Check if app path exists + if [ ! -d "${{ inputs.app-path }}" ]; then + echo "โŒ App bundle not found at ${{ inputs.app-path }}" + echo "::set-output name=signed::none" + exit 1 + fi + + # Check if entitlements file exists + if [ ! -f "${{ inputs.entitlements-file }}" ]; then + echo "โŒ Entitlements file not found at ${{ inputs.entitlements-file }}" + echo "::set-output name=signed::none" + exit 1 + fi + + # Decide which keychain to use + if [ "${{ steps.setup-cert.outputs.use_system_cert }}" = "true" ]; then + echo "Using system keychain identity" + # Get certificate hash instead of name to avoid ambiguity + IDENTITY_HASH=$(security find-identity -v -p codesigning | grep "Developer ID Application" | head -1 | awk '{print $2}') + echo "Using certificate hash: $IDENTITY_HASH" + else + # Make sure keychain is unlocked + security unlock-keychain -p "$KEYCHAIN_PASSWORD" "$KEYCHAIN_PATH" + echo "Using custom keychain identity" + # Get certificate hash instead of name to avoid ambiguity + IDENTITY_HASH=$(security find-identity -v -p codesigning "$KEYCHAIN_PATH" | grep "Developer ID Application" | head -1 | awk '{print $2}') + echo "Using certificate hash: $IDENTITY_HASH" + fi + + if [ -z "$IDENTITY_HASH" ]; then + echo "โŒ No valid Developer ID Application certificate found" + + if [ "${{ inputs.fallback-to-adhoc }}" = "true" ]; then + echo "Falling back to ad-hoc signing for testing..." + # Use ad-hoc identity as fallback + codesign --force --deep --verbose --options runtime --entitlements "${{ inputs.entitlements-file }}" --sign - --timestamp "${{ inputs.app-path }}" + echo "::set-output name=signed::adhoc" + else + echo "Skipping signing. Set fallback-to-adhoc=true to use ad-hoc signing instead." + echo "::set-output name=signed::none" + exit 1 + fi + else + echo "Signing app bundle with Developer ID hash: $IDENTITY_HASH" + + # Sign the app bundle using the hash + codesign --force --deep --verbose --options runtime --entitlements "${{ inputs.entitlements-file }}" --sign "$IDENTITY_HASH" --timestamp "${{ inputs.app-path }}" + echo "::set-output name=signed::identity" + fi + + # Verify signing + echo "๐Ÿ” Verifying signature..." + codesign -vvv --deep --strict "${{ inputs.app-path }}" + + # Check entitlements + echo "๐Ÿ” Checking entitlements..." + codesign -d --entitlements - "${{ inputs.app-path }}" + + - name: Notarize App + id: notarize + if: steps.sign.outputs.signed != 'none' + shell: bash + env: + APPLE_ID: ${{ inputs.notary-user }} + APP_PASSWORD: ${{ inputs.notary-password }} + API_KEY_ID: ${{ inputs.notary-api-key-id }} + API_ISSUER_ID: ${{ inputs.notary-api-key-issuer-id }} + API_KEY_PATH: ${{ inputs.notary-api-key-path }} + run: | + echo "๐Ÿ“ค Notarizing app..." + + # Set default output + echo "::set-output name=notarized::false" + + # Get app name for zip file naming + APP_NAME=$(basename "${{ inputs.app-path }}" .app) + BUNDLE_ID="${{ inputs.bundle-id }}" + + # If bundle ID is not provided, try to extract from Info.plist + if [ -z "$BUNDLE_ID" ]; then + if [ -f "${{ inputs.app-path }}/Contents/Info.plist" ]; then + BUNDLE_ID=$(/usr/libexec/PlistBuddy -c "Print :CFBundleIdentifier" "${{ inputs.app-path }}/Contents/Info.plist") + echo "Extracted bundle ID: $BUNDLE_ID" + else + BUNDLE_ID="com.luckyrobots.app" + echo "Using default bundle ID: $BUNDLE_ID" + fi + fi + + # Check if we're using API key notarization method + if [ "${{ inputs.notarization-method }}" = "api-key" ] && [ -n "$API_KEY_ID" ] && [ -n "$API_ISSUER_ID" ] && [ -n "$API_KEY_PATH" ]; then + echo "Using App Store Connect API key for notarization..." + + # Create directory for API key if API_KEY_PATH contains content + mkdir -p ~/private_keys + + # Check if API_KEY_PATH is a path or content + if [[ "$API_KEY_PATH" == /* ]] && [ -f "$API_KEY_PATH" ]; then + # It's a path to a file + echo "Using API key from path: $API_KEY_PATH" + cp "$API_KEY_PATH" ~/private_keys/AuthKey_${API_KEY_ID}.p8 + else + # It contains the key content + echo "Using API key from content" + echo "$API_KEY_PATH" > ~/private_keys/AuthKey_${API_KEY_ID}.p8 + fi + + # Create zip for notarization + ZIP_PATH="${APP_NAME}-notarize.zip" + ditto -c -k --keepParent "${{ inputs.app-path }}" "$ZIP_PATH" + + echo "Submitting for notarization with API key..." + xcrun notarytool submit "$ZIP_PATH" \ + --key ~/private_keys/AuthKey_${API_KEY_ID}.p8 \ + --key-id "$API_KEY_ID" \ + --issuer "$API_ISSUER_ID" \ + --wait + + # Check if notarization succeeded + if [ $? -eq 0 ]; then + # Staple the notarization ticket + echo "Stapling notarization ticket..." + xcrun stapler staple "${{ inputs.app-path }}" + + # Verify notarization + echo "๐Ÿ” Verifying notarization..." + spctl --assess --verbose --type exec "${{ inputs.app-path }}" + + echo "::set-output name=notarized::true" + else + echo "โŒ Notarization failed" + fi + + # Clean up + rm -rf ~/private_keys + + # Fall back to App-specific password if requested + elif [ "${{ inputs.notarization-method }}" = "app-password" ] && [ -n "$APPLE_ID" ] && [ -n "$APP_PASSWORD" ] && [ -n "$APPLE_TEAM_ID" ]; then + echo "Using App-specific password for notarization..." + + # Create zip for notarization + ZIP_PATH="${APP_NAME}-notarize.zip" + ditto -c -k --keepParent "${{ inputs.app-path }}" "$ZIP_PATH" + + echo "Submitting for notarization..." + xcrun notarytool submit "$ZIP_PATH" \ + --apple-id "$APPLE_ID" \ + --password "$APP_PASSWORD" \ + --team-id "$APPLE_TEAM_ID" \ + --wait + + # Check if notarization succeeded + if [ $? -eq 0 ]; then + # Staple the notarization ticket + echo "Stapling notarization ticket..." + xcrun stapler staple "${{ inputs.app-path }}" + + # Verify notarization + echo "๐Ÿ” Verifying notarization..." + spctl --assess --verbose --type exec "${{ inputs.app-path }}" + + echo "::set-output name=notarized::true" + else + echo "โŒ Notarization failed" + fi + else + echo "โš ๏ธ Missing notarization credentials. Skipping notarization." + echo "For App Store Connect API key method, set these inputs:" + echo " - notarization-method: api-key" + echo " - notary-api-key-id: Your API key ID" + echo " - notary-api-key-issuer-id: Your API issuer ID" + echo " - notary-api-key-path: Path to or content of your p8 file" + echo "" + echo "For App-specific password method, set these inputs:" + echo " - notarization-method: app-password" + echo " - notary-user: Your Apple ID (email)" + echo " - notary-password: Your app-specific password" + echo " - team-id: Your Apple Developer team ID" + fi + + - name: Package App + id: package + if: steps.sign.outputs.signed != 'none' + shell: bash + run: | + echo "๐Ÿ“ฆ Packaging signed app..." + + # Get app name for zip file naming + APP_NAME=$(basename "${{ inputs.app-path }}" .app) + + if [ "${{ steps.notarize.outputs.notarized }}" = "true" ]; then + ZIP_FILE="${APP_NAME}-Signed-Notarized.zip" + echo "Creating distribution package with notarized app..." + else + ZIP_FILE="${APP_NAME}-Signed.zip" + echo "Creating distribution package with signed app..." + fi + + # Create zip package + ditto -c -k --keepParent "${{ inputs.app-path }}" "$ZIP_FILE" + + echo "โœ… Created package: $ZIP_FILE" + echo "::set-output name=package-path::$ZIP_FILE" + + - name: Cleanup + if: always() + shell: bash + run: | + echo "๐Ÿงน Cleaning up..." + security delete-keychain "$KEYCHAIN_PATH" 2>/dev/null || true + rm -f *-notarize.zip || true + echo "โœ… Cleanup complete" \ No newline at end of file -- 2.47.2 From 567ef909f8eea4e55cd4f0949913e4170284e40b Mon Sep 17 00:00:00 2001 From: Ozgur Ersoy Date: Mon, 14 Apr 2025 16:04:47 +0200 Subject: [PATCH 072/109] fix(workflows): update macOS build workflow to enable push triggers and refine local signing process --- .gitea/workflows/test-local-signing.yml | 4 +- .gitea/workflows/test-macos-build.yml | 358 ++++++------------------ 2 files changed, 89 insertions(+), 273 deletions(-) diff --git a/.gitea/workflows/test-local-signing.yml b/.gitea/workflows/test-local-signing.yml index 4cf4cfbd..1459312a 100644 --- a/.gitea/workflows/test-local-signing.yml +++ b/.gitea/workflows/test-local-signing.yml @@ -2,8 +2,8 @@ name: Test Local Signing on: workflow_dispatch: # Manual trigger - push: - branches: [ozgur/build] + # push: + # branches: [ozgur/build] jobs: test-local-signing: diff --git a/.gitea/workflows/test-macos-build.yml b/.gitea/workflows/test-macos-build.yml index 48c376d7..75679e6c 100644 --- a/.gitea/workflows/test-macos-build.yml +++ b/.gitea/workflows/test-macos-build.yml @@ -2,8 +2,8 @@ name: Test macOS Build Action on: workflow_dispatch: # Manual trigger only for testing - # push: - # branches: [ozgur/build] + push: + branches: [ozgur/build] jobs: test-macos-build: @@ -14,301 +14,117 @@ jobs: with: lfs: true fetch-depth: 0 - - - name: Check entitlements file - run: | - # Check if entitlements files exist - if [ -f "LuckyWorld.entitlements" ]; then - echo "Using existing LuckyWorld.entitlements file" - ENTITLEMENTS_FILE="LuckyWorld.entitlements" - else - echo "Creating default entitlements file as LuckyWorld.entitlements" - # Create entitlements file line by line instead of heredoc - echo '' > LuckyWorld.entitlements - echo '' >> LuckyWorld.entitlements - echo '' >> LuckyWorld.entitlements - echo '' >> LuckyWorld.entitlements - echo ' com.apple.security.cs.allow-jit' >> LuckyWorld.entitlements - echo ' ' >> LuckyWorld.entitlements - echo ' com.apple.security.cs.allow-unsigned-executable-memory' >> LuckyWorld.entitlements - echo ' ' >> LuckyWorld.entitlements - echo ' com.apple.security.cs.disable-library-validation' >> LuckyWorld.entitlements - echo ' ' >> LuckyWorld.entitlements - echo ' com.apple.security.cs.allow-dyld-environment-variables' >> LuckyWorld.entitlements - echo ' ' >> LuckyWorld.entitlements - echo ' com.apple.security.device.audio-input' >> LuckyWorld.entitlements - echo ' ' >> LuckyWorld.entitlements - echo ' com.apple.security.device.camera' >> LuckyWorld.entitlements - echo ' ' >> LuckyWorld.entitlements - echo '' >> LuckyWorld.entitlements - echo '' >> LuckyWorld.entitlements - ENTITLEMENTS_FILE="LuckyWorld.entitlements" - fi - - echo "Using entitlements file: $ENTITLEMENTS_FILE" - echo "ENTITLEMENTS_FILE=$ENTITLEMENTS_FILE" >> "$GITHUB_ENV" - shell: bash - - # Step 1: Setup environment + + # Setup environment for build - name: Setup environment run: | - # Use the correct path where Unreal Engine is installed - UE_PATH="/Users/Shared/Epic Games/UE_5.5" - - if [ ! -d "$UE_PATH" ]; then - echo "Warning: Unreal Engine is not installed in the expected location" - echo "This is expected in CI environment - continuing anyway" - fi - + # Get the working directory path for absolute paths + WORKSPACE_DIR="$(pwd)" + echo "WORKSPACE_DIR=$WORKSPACE_DIR" >> "$GITHUB_ENV" + echo "ENTITLEMENTS_FILE=LuckyWorld.entitlements" >> "$GITHUB_ENV" + # Create directories for builds mkdir -p Builds/Mac mkdir -p PackagedReleases - echo "Using Unreal Engine 5.5" - - # Get the working directory path for absolute paths - WORKSPACE_DIR="$(pwd)" - echo "WORKSPACE_DIR=$WORKSPACE_DIR" >> "$GITHUB_ENV" + echo "Environment setup complete" shell: bash - # Step 2: Build for macOS + # Build for macOS - use your own build script or create a test app if needed - name: Build for macOS run: | if [ -f "./scripts/mac_build.sh" ]; then chmod +x ./scripts/mac_build.sh ./scripts/mac_build.sh else - echo "Build script not found, skipping this step" + echo "ERROR: Build script not found at ./scripts/mac_build.sh" + exit 1 fi shell: bash - - - # Step 3: Enhanced Debug for Certificate Import - - name: Debug Certificate Import - env: - CERTIFICATE_BASE64: ${{ secrets.MACOS_CERTIFICATE }} - CERTIFICATE_PASSWORD: ${{ secrets.MACOS_CERTIFICATE_PWD }} - APPLE_TEAM_ID: ${{ secrets.APPLE_TEAM_ID }} + + # Find the app bundle + - name: Find app bundle run: | - # Debug: Print working directory and available resources - echo "Current working directory: $(pwd)" - echo "Contents of Saved/StagedBuilds directory (if exists):" - find ./Saved -type d -name "*.app" 2>/dev/null || echo "No .app bundles found in Saved/" - - # Checking system keychains - echo "Examining system keychains and certificates..." - security list-keychains - security default-keychain - - # Decode certificate and examine format - DEBUG - echo "Decoding certificate to debug..." - CERT_DIR="$HOME/certificates" - mkdir -p "$CERT_DIR" - CERT_PATH="$CERT_DIR/developer_certificate.p12" - echo "$CERTIFICATE_BASE64" | base64 --decode > "$CERT_PATH" - - # Check if certificate was properly decoded - if [ -f "$CERT_PATH" ]; then - echo "Certificate was decoded, size: $(wc -c < "$CERT_PATH") bytes" - echo "Certificate file type: $(file "$CERT_PATH")" + if [ -z "$APP_PATH" ]; then + # First check Saved/StagedBuilds directory - where Unreal often places built apps + echo "Checking Saved/StagedBuilds directory..." + APP_PATHS=$(find ./Saved/StagedBuilds -type d -name "*.app" 2>/dev/null) + + # If not found, check Builds directory + if [ -z "$APP_PATHS" ]; then + echo "Checking Builds directory..." + APP_PATHS=$(find ./Builds -type d -name "*.app" 2>/dev/null) + fi + + # If still not found, check the whole workspace + if [ -z "$APP_PATHS" ]; then + echo "Checking entire workspace..." + APP_PATHS=$(find . -type d -name "*.app" -not -path "*/\.*" 2>/dev/null) + fi + + if [ -z "$APP_PATHS" ]; then + echo "ERROR: Could not find any app bundles!" + echo "Listing all directories to help debug:" + find . -type d -maxdepth 3 | sort + exit 1 + fi + + echo "Found potential app bundles:" + echo "$APP_PATHS" + + # Use the first app path found (preferably the main app, not a child app) + MAIN_APP_PATH=$(echo "$APP_PATHS" | grep -v "CrashReportClient" | head -1 || echo "$APP_PATHS" | head -1) + + echo "Using app bundle: $MAIN_APP_PATH" + echo "APP_PATH=$MAIN_APP_PATH" >> "$GITHUB_ENV" else - echo "ERROR: Failed to decode certificate" + echo "App path already set: $APP_PATH" + fi + + # Make sure app exists + if [ ! -d "$APP_PATH" ]; then + echo "ERROR: App bundle not found at $APP_PATH!" exit 1 fi - - # Trying import with different methods - echo "ATTEMPT 1: Using login keychain" - KEYCHAIN_PASSWORD="$(security find-generic-password -a ${USER} -s login -w)" - security unlock-keychain -p "$KEYCHAIN_PASSWORD" login.keychain - security import "$CERT_PATH" -P "$CERTIFICATE_PASSWORD" -k login.keychain -T /usr/bin/codesign || echo "Import to login keychain failed" - - echo "ATTEMPT 2: Creating custom keychain" - CUSTOM_KEYCHAIN="$CERT_DIR/build.keychain" - CUSTOM_PASSWORD="temppassword123" - security create-keychain -p "$CUSTOM_PASSWORD" "$CUSTOM_KEYCHAIN" - security default-keychain -s "$CUSTOM_KEYCHAIN" - security unlock-keychain -p "$CUSTOM_PASSWORD" "$CUSTOM_KEYCHAIN" - security import "$CERT_PATH" -P "$CERTIFICATE_PASSWORD" -k "$CUSTOM_KEYCHAIN" -T /usr/bin/codesign || echo "Import to custom keychain failed" - - # Add to search list - security list-keychains -d user -s "$CUSTOM_KEYCHAIN" login.keychain - security set-key-partition-list -S apple-tool:,apple: -s -k "$CUSTOM_PASSWORD" "$CUSTOM_KEYCHAIN" - - # Check available identities in both keychains - echo "Checking login keychain for identities:" - security find-identity -v -p codesigning login.keychain || echo "No identities in login keychain" - - echo "Checking custom keychain for identities:" - security find-identity -v -p codesigning "$CUSTOM_KEYCHAIN" || echo "No identities in custom keychain" - - # Fallback solution - use adhoc signing for testing - echo "FALLBACK: Setting up adhoc signing option" - echo "KEYCHAIN_PATH=$CUSTOM_KEYCHAIN" >> "$GITHUB_ENV" - echo "KEYCHAIN_PASSWORD=$CUSTOM_PASSWORD" >> "$GITHUB_ENV" - echo "DIRECT_SIGNING_AVAILABLE=false" >> "$GITHUB_ENV" - - # For debugging only, use a specific team ID if needed - echo "APPLE_TEAM=$APPLE_TEAM_ID" >> "$GITHUB_ENV" shell: bash - # Step 4: Find and prep app for signing - - name: Find and prep app for signing - run: | - # First check Saved/StagedBuilds directory - where Unreal often places built apps - echo "Checking Saved/StagedBuilds directory..." - APP_PATHS=$(find ./Saved/StagedBuilds -type d -name "*.app" 2>/dev/null) - - # If not found, check Builds directory - if [ -z "$APP_PATHS" ]; then - echo "Checking Builds directory..." - APP_PATHS=$(find ./Builds -type d -name "*.app" 2>/dev/null) - fi - - # If still not found, check the whole workspace - if [ -z "$APP_PATHS" ]; then - echo "Checking entire workspace..." - APP_PATHS=$(find . -type d -name "*.app" -not -path "*/\.*" 2>/dev/null) - fi - - if [ -z "$APP_PATHS" ]; then - echo "ERROR: Could not find any app bundles!" - echo "Listing all directories to help debug:" - find . -type d -maxdepth 3 | sort - exit 1 - fi - - echo "Found potential app bundles:" - echo "$APP_PATHS" - - # Use the first app path found (preferably the main app, not a child app) - MAIN_APP_PATH=$(echo "$APP_PATHS" | grep -v "CrashReportClient" | head -1 || echo "$APP_PATHS" | head -1) - - # Get app name for later use - APP_NAME=$(basename "$MAIN_APP_PATH") - - echo "Using app bundle: $MAIN_APP_PATH" - echo "App name: $APP_NAME" - - echo "APP_PATH=$MAIN_APP_PATH" >> "$GITHUB_ENV" - echo "APP_NAME=$APP_NAME" >> "$GITHUB_ENV" - shell: bash - - # Step 5: Sign application with alternative fallback - - name: Sign application - env: - APPLE_TEAM_ID: ${{ secrets.APPLE_TEAM_ID }} - run: | - # Debug info - echo "Signing app bundle: $APP_PATH" - echo "Using entitlements file: $ENTITLEMENTS_FILE" - - # Sign the app with ad-hoc identity - echo "๐Ÿ” Signing app with ad-hoc identity..." - /usr/bin/codesign --force --sign - --timestamp --options runtime --entitlements "$WORKSPACE_DIR/$ENTITLEMENTS_FILE" "$APP_PATH" - - # Verify signing - echo "๐Ÿ” Verifying signature..." - codesign -vvv --deep --strict "$APP_PATH" - - # Check entitlements - echo "๐Ÿ” Checking entitlements..." - codesign -d --entitlements - "$APP_PATH" - - echo "โœ… Ad-hoc signing completed for testing purposes" - echo "NEEDS_REAL_CERT=true" >> "$GITHUB_ENV" - shell: bash - - # Step 6: Create Reference Script for Production Signing - - name: Create Production Signing Reference - run: | - echo "๐Ÿ“ Creating reference script for production code signing..." - - cat > sign_and_notarize_production.sh << 'EOF' - #!/bin/bash - # Sign and notarize macOS application - # This script is a reference for using a real Developer ID certificate - - # Configuration (replace with your values) - APP_PATH="LuckyWorld-Mac-Shipping.app" # Your app path - TEAM_ID="${APPLE_TEAM_ID}" # Your Apple Team ID - BUNDLE_ID="com.luckyworld.game" # Your app bundle ID - ENTITLEMENTS_PATH="LuckyWorld.entitlements" # Your entitlements file - APPLE_ID="${APPLE_NOTARY_USER}" # Your Apple ID - APP_PASSWORD="${APPLE_NOTARY_PASSWORD}" # Your app-specific password - - # Step 1: Check for Developer ID Application certificate - echo "Checking for Developer ID Application certificate..." - IDENTITY=$(security find-identity -v -p codesigning | grep "Developer ID Application" | head -1 | awk -F '"' '{print $2}') - - if [ -z "$IDENTITY" ]; then - echo "Error: No Developer ID Application certificate found" - echo "Please create a Developer ID Application certificate in your Apple Developer account" - echo "and install it in your keychain" - exit 1 - fi - - echo "Using identity: $IDENTITY" - - # Step 2: Sign the app - echo "Signing app..." - codesign --force --options runtime --entitlements "$ENTITLEMENTS_PATH" \ - --sign "$IDENTITY" --timestamp "$APP_PATH" - - # Step 3: Verify signing - echo "Verifying signature..." - codesign -vvv --deep --strict "$APP_PATH" - - # Step 4: Create zip for notarization - echo "Creating zip for notarization..." - ZIP_PATH="${APP_PATH%.app}-notarize.zip" - ditto -c -k --keepParent "$APP_PATH" "$ZIP_PATH" - - # Step 5: Submit for notarization - echo "Submitting for notarization..." - xcrun notarytool submit "$ZIP_PATH" \ - --apple-id "$APPLE_ID" \ - --password "$APP_PASSWORD" \ - --team-id "$TEAM_ID" \ - --wait - - # Step 6: Staple the notarization ticket - echo "Stapling notarization ticket..." - xcrun stapler staple "$APP_PATH" - - # Step 7: Verify notarization - echo "Verifying notarization..." - spctl --assess --verbose --type exec "$APP_PATH" - - # Step 8: Create final distribution zip - echo "Creating final distribution zip..." - FINAL_ZIP="${APP_PATH%.app}-macOS-Signed.zip" - ditto -c -k --keepParent "$APP_PATH" "$FINAL_ZIP" - - echo "โœ… App successfully signed and notarized!" - echo "Final package: $FINAL_ZIP" - EOF - - chmod +x sign_and_notarize_production.sh - echo "โœ… Created reference script for production code signing" - shell: bash - - # Step 9: Upload test artifact - - name: Upload Test Build Artifact - uses: actions/upload-artifact@v3 - if: success() + # Use the macos-notarize action to sign and notarize the app + - name: Sign and Notarize macOS App + uses: ./.gitea/actions/macos-notarize + id: sign-and-notarize with: - name: LuckyWorld-macOS-UNSIGNED-TEST - path: PackagedReleases/LuckyWorld-macOS-UNSIGNED-TEST.zip + app-path: ${{ env.APP_PATH }} + entitlements-file: ${{ env.ENTITLEMENTS_FILE }} + team-id: ${{ secrets.APPLE_TEAM_ID }} + certificate-base64: ${{ secrets.MACOS_CERTIFICATE }} + certificate-password: ${{ secrets.MACOS_CERTIFICATE_PWD }} + notarization-method: 'api-key' + notary-api-key-id: ${{ secrets.NOTARY_API_KEY_ID }} + notary-api-key-issuer-id: ${{ secrets.NOTARY_API_KEY_ISSUER_ID }} + notary-api-key-path: ${{ secrets.NOTARY_API_KEY_CONTENT }} + bundle-id: 'com.luckyrobots.luckyworld' + fallback-to-adhoc: 'true' + + # Upload signed app if available + - name: Upload Signed App + uses: actions/upload-artifact@v3 + if: steps.sign-and-notarize.outputs.signed != 'none' + with: + name: LuckyWorld-macOS-Signed + path: ${{ steps.sign-and-notarize.outputs.package-path }} retention-days: 7 - # Step 10: Cleanup - - name: Cleanup - if: always() + # Report results + - name: Report Results run: | - # Clean up keychain and certificates - rm -rf "$HOME/certificates" || true - security delete-keychain "$HOME/certificates/build.keychain" || true + echo "๐Ÿ” App signing: ${{ steps.sign-and-notarize.outputs.signed }}" + echo "๐Ÿ” App notarization: ${{ steps.sign-and-notarize.outputs.notarized }}" - echo "Cleanup complete" + if [ "${{ steps.sign-and-notarize.outputs.signed }}" != "none" ]; then + echo "โœ… Packaging completed successfully!" + echo "Final package: ${{ steps.sign-and-notarize.outputs.package-path }}" + else + echo "โš ๏ธ App was not signed - check the logs for details" + fi shell: bash \ No newline at end of file -- 2.47.2 From b60ed26574a25158dbb02bfbcb9fa47caefc6fc9 Mon Sep 17 00:00:00 2001 From: Ozgur Ersoy Date: Mon, 14 Apr 2025 16:35:53 +0200 Subject: [PATCH 073/109] fix(workflows): refine macOS build workflow to improve app bundle detection and error handling --- .gitea/workflows/test-macos-build.yml | 73 +++++++++++++-------------- 1 file changed, 36 insertions(+), 37 deletions(-) diff --git a/.gitea/workflows/test-macos-build.yml b/.gitea/workflows/test-macos-build.yml index 75679e6c..cc973eab 100644 --- a/.gitea/workflows/test-macos-build.yml +++ b/.gitea/workflows/test-macos-build.yml @@ -45,47 +45,46 @@ jobs: # Find the app bundle - name: Find app bundle run: | - if [ -z "$APP_PATH" ]; then - # First check Saved/StagedBuilds directory - where Unreal often places built apps - echo "Checking Saved/StagedBuilds directory..." - APP_PATHS=$(find ./Saved/StagedBuilds -type d -name "*.app" 2>/dev/null) - - # If not found, check Builds directory - if [ -z "$APP_PATHS" ]; then - echo "Checking Builds directory..." - APP_PATHS=$(find ./Builds -type d -name "*.app" 2>/dev/null) - fi - - # If still not found, check the whole workspace - if [ -z "$APP_PATHS" ]; then - echo "Checking entire workspace..." - APP_PATHS=$(find . -type d -name "*.app" -not -path "*/\.*" 2>/dev/null) - fi - - if [ -z "$APP_PATHS" ]; then - echo "ERROR: Could not find any app bundles!" - echo "Listing all directories to help debug:" - find . -type d -maxdepth 3 | sort - exit 1 - fi - - echo "Found potential app bundles:" - echo "$APP_PATHS" - - # Use the first app path found (preferably the main app, not a child app) - MAIN_APP_PATH=$(echo "$APP_PATHS" | grep -v "CrashReportClient" | head -1 || echo "$APP_PATHS" | head -1) - - echo "Using app bundle: $MAIN_APP_PATH" - echo "APP_PATH=$MAIN_APP_PATH" >> "$GITHUB_ENV" - else - echo "App path already set: $APP_PATH" + # First check Saved/StagedBuilds directory - where Unreal often places built apps + echo "Checking Saved/StagedBuilds directory..." + APP_PATHS=$(find ./Saved/StagedBuilds -type d -name "*.app" 2>/dev/null) + + # If not found, check Builds directory + if [ -z "$APP_PATHS" ]; then + echo "Checking Builds directory..." + APP_PATHS=$(find ./Builds -type d -name "*.app" 2>/dev/null) fi - # Make sure app exists - if [ ! -d "$APP_PATH" ]; then - echo "ERROR: App bundle not found at $APP_PATH!" + # If still not found, check the whole workspace + if [ -z "$APP_PATHS" ]; then + echo "Checking entire workspace..." + APP_PATHS=$(find . -type d -name "*.app" -not -path "*/\.*" 2>/dev/null) + fi + + if [ -z "$APP_PATHS" ]; then + echo "ERROR: Could not find any app bundles!" + echo "Listing all directories to help debug:" + find . -type d -maxdepth 3 | sort exit 1 fi + + echo "Found potential app bundles:" + echo "$APP_PATHS" + + # Use the first app path found (preferably the main app, not a child app) + MAIN_APP_PATH=$(echo "$APP_PATHS" | grep -v "CrashReportClient" | head -1 || echo "$APP_PATHS" | head -1) + + echo "Using app bundle: $MAIN_APP_PATH" + echo "APP_PATH=$MAIN_APP_PATH" >> "$GITHUB_ENV" + + # Make sure app exists - using local variable + if [ ! -d "$MAIN_APP_PATH" ]; then + echo "ERROR: App bundle not found at $MAIN_APP_PATH!" + exit 1 + fi + + # Export APP_PATH for next steps to use + echo "APP_PATH=$MAIN_APP_PATH" >> "$GITHUB_ENV" shell: bash # Use the macos-notarize action to sign and notarize the app -- 2.47.2 From f82ca2ec61d3dec54522eec1e0c8201329283b10 Mon Sep 17 00:00:00 2001 From: Ozgur Ersoy Date: Mon, 14 Apr 2025 17:28:52 +0200 Subject: [PATCH 074/109] =?UTF-8?q?hadi=20ins=20=F0=9F=A4=9E?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitea/workflows/test-macos-build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitea/workflows/test-macos-build.yml b/.gitea/workflows/test-macos-build.yml index cc973eab..d4a7602d 100644 --- a/.gitea/workflows/test-macos-build.yml +++ b/.gitea/workflows/test-macos-build.yml @@ -100,7 +100,7 @@ jobs: notarization-method: 'api-key' notary-api-key-id: ${{ secrets.NOTARY_API_KEY_ID }} notary-api-key-issuer-id: ${{ secrets.NOTARY_API_KEY_ISSUER_ID }} - notary-api-key-path: ${{ secrets.NOTARY_API_KEY_CONTENT }} + notary-api-key-path: ${{ secrets.NOTARY_API_KEY_PATH }} bundle-id: 'com.luckyrobots.luckyworld' fallback-to-adhoc: 'true' -- 2.47.2 From db463a2ecea6ba9e94643f18b7e321b386cef31b Mon Sep 17 00:00:00 2001 From: Ozgur Ersoy Date: Mon, 14 Apr 2025 18:07:06 +0200 Subject: [PATCH 075/109] fix(actions): enhance notarization process with detailed output and error handling --- .gitea/actions/macos-notarize/action.yml | 54 +++++++++++++++++++----- .gitea/workflows/test-macos-build.yml | 2 +- scripts/mac_build.sh | 4 +- 3 files changed, 46 insertions(+), 14 deletions(-) diff --git a/.gitea/actions/macos-notarize/action.yml b/.gitea/actions/macos-notarize/action.yml index 554319df..ccc7b63a 100644 --- a/.gitea/actions/macos-notarize/action.yml +++ b/.gitea/actions/macos-notarize/action.yml @@ -244,17 +244,33 @@ runs: ditto -c -k --keepParent "${{ inputs.app-path }}" "$ZIP_PATH" echo "Submitting for notarization with API key..." - xcrun notarytool submit "$ZIP_PATH" \ + # Capture output and exit status of notarization + NOTARY_OUTPUT=$(xcrun notarytool submit "$ZIP_PATH" \ --key ~/private_keys/AuthKey_${API_KEY_ID}.p8 \ --key-id "$API_KEY_ID" \ --issuer "$API_ISSUER_ID" \ - --wait + --wait 2>&1) + NOTARY_STATUS=$? + + # Display output for debugging + echo "Notarization command output:" + echo "$NOTARY_OUTPUT" + echo "Notarization exit status: $NOTARY_STATUS" + + # Enhanced check for notarization success + if [ $NOTARY_STATUS -eq 0 ] && echo "$NOTARY_OUTPUT" | grep -q -E "success|accepted"; then + echo "โœ… Notarization completed successfully!" - # Check if notarization succeeded - if [ $? -eq 0 ]; then # Staple the notarization ticket echo "Stapling notarization ticket..." xcrun stapler staple "${{ inputs.app-path }}" + STAPLE_STATUS=$? + + if [ $STAPLE_STATUS -eq 0 ]; then + echo "โœ… Stapling completed successfully!" + else + echo "โš ๏ธ Stapling completed with status $STAPLE_STATUS (may still be valid)" + fi # Verify notarization echo "๐Ÿ” Verifying notarization..." @@ -262,7 +278,8 @@ runs: echo "::set-output name=notarized::true" else - echo "โŒ Notarization failed" + echo "โŒ Notarization failed or did not complete properly" + echo "Please check the notarization logs for details" fi # Clean up @@ -277,17 +294,33 @@ runs: ditto -c -k --keepParent "${{ inputs.app-path }}" "$ZIP_PATH" echo "Submitting for notarization..." - xcrun notarytool submit "$ZIP_PATH" \ + # Capture output and exit status of notarization + NOTARY_OUTPUT=$(xcrun notarytool submit "$ZIP_PATH" \ --apple-id "$APPLE_ID" \ --password "$APP_PASSWORD" \ --team-id "$APPLE_TEAM_ID" \ - --wait + --wait 2>&1) + NOTARY_STATUS=$? - # Check if notarization succeeded - if [ $? -eq 0 ]; then + # Display output for debugging + echo "Notarization command output:" + echo "$NOTARY_OUTPUT" + echo "Notarization exit status: $NOTARY_STATUS" + + # Enhanced check for notarization success + if [ $NOTARY_STATUS -eq 0 ] && echo "$NOTARY_OUTPUT" | grep -q -E "success|accepted"; then + echo "โœ… Notarization completed successfully!" + # Staple the notarization ticket echo "Stapling notarization ticket..." xcrun stapler staple "${{ inputs.app-path }}" + STAPLE_STATUS=$? + + if [ $STAPLE_STATUS -eq 0 ]; then + echo "โœ… Stapling completed successfully!" + else + echo "โš ๏ธ Stapling completed with status $STAPLE_STATUS (may still be valid)" + fi # Verify notarization echo "๐Ÿ” Verifying notarization..." @@ -295,7 +328,8 @@ runs: echo "::set-output name=notarized::true" else - echo "โŒ Notarization failed" + echo "โŒ Notarization failed or did not complete properly" + echo "Please check the notarization logs for details" fi else echo "โš ๏ธ Missing notarization credentials. Skipping notarization." diff --git a/.gitea/workflows/test-macos-build.yml b/.gitea/workflows/test-macos-build.yml index d4a7602d..b30c5f90 100644 --- a/.gitea/workflows/test-macos-build.yml +++ b/.gitea/workflows/test-macos-build.yml @@ -111,7 +111,7 @@ jobs: with: name: LuckyWorld-macOS-Signed path: ${{ steps.sign-and-notarize.outputs.package-path }} - retention-days: 7 + retention-days: 30 # Report results - name: Report Results diff --git a/scripts/mac_build.sh b/scripts/mac_build.sh index af4b72fd..1dbad1a5 100755 --- a/scripts/mac_build.sh +++ b/scripts/mac_build.sh @@ -73,10 +73,8 @@ rm -rf DerivedDataCache Intermediate Binaries Saved # -skipiostore \ # -skippak \ (disable -pak and -iostore) - -# http://forums.unrealengine.com/t/code-signing-and-notarization-for-mac/146486 echo "" -echo "Build completed. Application path:" +echo "๐Ÿฆพ Build completed. Application path:" APP_PATH=$(find "$ARCHIVE_DIR" -name "*.app" -type d | head -n 1) echo "$APP_PATH" -- 2.47.2 From 67a9934251bfc496fa43b381b7489bde40333108 Mon Sep 17 00:00:00 2001 From: Ozgur Ersoy Date: Mon, 14 Apr 2025 19:13:01 +0200 Subject: [PATCH 076/109] fix(actions): improve notarization script with detailed logging and bundle ID checks --- .gitea/actions/macos-notarize/action.yml | 95 +++++++++++++++++++++++- .gitea/workflows/test-macos-build.yml | 12 ++- 2 files changed, 103 insertions(+), 4 deletions(-) diff --git a/.gitea/actions/macos-notarize/action.yml b/.gitea/actions/macos-notarize/action.yml index ccc7b63a..429874c5 100644 --- a/.gitea/actions/macos-notarize/action.yml +++ b/.gitea/actions/macos-notarize/action.yml @@ -256,7 +256,33 @@ runs: echo "Notarization command output:" echo "$NOTARY_OUTPUT" echo "Notarization exit status: $NOTARY_STATUS" - + + # Extract submission ID for log retrieval if needed + SUBMISSION_ID=$(echo "$NOTARY_OUTPUT" | grep -o "id: [a-f0-9\-]*" | head -1 | cut -d ' ' -f 2) + echo "Submission ID: $SUBMISSION_ID" + + # Check for invalid status and get detailed logs + if [ $NOTARY_STATUS -eq 0 ] && echo "$NOTARY_OUTPUT" | grep -q "Invalid"; then + echo "โš ๏ธ Notarization returned Invalid status. Checking detailed logs..." + if [ -n "$SUBMISSION_ID" ]; then + echo "๐Ÿ“‹ Fetching detailed logs for submission ID: $SUBMISSION_ID" + LOGS_OUTPUT=$(xcrun notarytool log "$SUBMISSION_ID" \ + --key ~/private_keys/AuthKey_${API_KEY_ID}.p8 \ + --key-id "$API_KEY_ID" \ + --issuer "$API_ISSUER_ID" 2>&1) + + echo "==== DETAILED NOTARIZATION LOGS ====" + echo "$LOGS_OUTPUT" + echo "==================================" + + # Extract specific issues for easier debugging + echo "๐Ÿ” Extracting specific issues from logs..." + echo "$LOGS_OUTPUT" | grep -A 3 "issues" + else + echo "โŒ Could not extract submission ID from notarization output" + fi + fi + # Enhanced check for notarization success if [ $NOTARY_STATUS -eq 0 ] && echo "$NOTARY_OUTPUT" | grep -q -E "success|accepted"; then echo "โœ… Notarization completed successfully!" @@ -279,7 +305,33 @@ runs: echo "::set-output name=notarized::true" else echo "โŒ Notarization failed or did not complete properly" - echo "Please check the notarization logs for details" + echo "Please check the notarization logs above for details" + + # Show current bundle ID in Info.plist + echo "๐Ÿ“‹ Current bundle ID information:" + if [ -f "${{ inputs.app-path }}/Contents/Info.plist" ]; then + echo "Info.plist content for bundle ID:" + /usr/libexec/PlistBuddy -c "Print :CFBundleIdentifier" "${{ inputs.app-path }}/Contents/Info.plist" || echo "Could not read bundle ID from Info.plist" + echo "Full Info.plist excerpt:" + plutil -p "${{ inputs.app-path }}/Contents/Info.plist" | grep -i bundle + else + echo "Info.plist not found at expected location: ${{ inputs.app-path }}/Contents/Info.plist" + fi + + # Check for mismatched bundle ID + if [ "$BUNDLE_ID" != "$(/usr/libexec/PlistBuddy -c "Print :CFBundleIdentifier" "${{ inputs.app-path }}/Contents/Info.plist" 2>/dev/null)" ]; then + echo "โš ๏ธ WARNING: Bundle ID mismatch detected between workflow and app!" + echo " - Workflow/input bundle ID: $BUNDLE_ID" + echo " - Actual app bundle ID: $(/usr/libexec/PlistBuddy -c "Print :CFBundleIdentifier" "${{ inputs.app-path }}/Contents/Info.plist" 2>/dev/null || echo "Could not read")" + echo "This mismatch could cause notarization problems." + fi + + # Check for code signature issues in internal components + echo "๐Ÿ” Checking for code signature issues in app components..." + find "${{ inputs.app-path }}" -type f -name "*.dylib" -o -name "*.so" | head -5 | while read -r lib; do + echo "Checking signature on: $lib" + codesign -vvv "$lib" || echo "โš ๏ธ Signature issue with: $lib" + done fi # Clean up @@ -307,6 +359,32 @@ runs: echo "$NOTARY_OUTPUT" echo "Notarization exit status: $NOTARY_STATUS" + # Extract submission ID for log retrieval if needed + SUBMISSION_ID=$(echo "$NOTARY_OUTPUT" | grep -o "id: [a-f0-9\-]*" | head -1 | cut -d ' ' -f 2) + echo "Submission ID: $SUBMISSION_ID" + + # Check for invalid status and get detailed logs + if [ $NOTARY_STATUS -eq 0 ] && echo "$NOTARY_OUTPUT" | grep -q "Invalid"; then + echo "โš ๏ธ Notarization returned Invalid status. Checking detailed logs..." + if [ -n "$SUBMISSION_ID" ]; then + echo "๐Ÿ“‹ Fetching detailed logs for submission ID: $SUBMISSION_ID" + LOGS_OUTPUT=$(xcrun notarytool log "$SUBMISSION_ID" \ + --apple-id "$APPLE_ID" \ + --password "$APP_PASSWORD" \ + --team-id "$APPLE_TEAM_ID" 2>&1) + + echo "==== DETAILED NOTARIZATION LOGS ====" + echo "$LOGS_OUTPUT" + echo "==================================" + + # Extract specific issues for easier debugging + echo "๐Ÿ” Extracting specific issues from logs..." + echo "$LOGS_OUTPUT" | grep -A 3 "issues" + else + echo "โŒ Could not extract submission ID from notarization output" + fi + fi + # Enhanced check for notarization success if [ $NOTARY_STATUS -eq 0 ] && echo "$NOTARY_OUTPUT" | grep -q -E "success|accepted"; then echo "โœ… Notarization completed successfully!" @@ -329,7 +407,18 @@ runs: echo "::set-output name=notarized::true" else echo "โŒ Notarization failed or did not complete properly" - echo "Please check the notarization logs for details" + echo "Please check the notarization logs above for details" + + # Show current bundle ID in Info.plist + echo "๐Ÿ“‹ Current bundle ID information:" + if [ -f "${{ inputs.app-path }}/Contents/Info.plist" ]; then + echo "Info.plist content for bundle ID:" + /usr/libexec/PlistBuddy -c "Print :CFBundleIdentifier" "${{ inputs.app-path }}/Contents/Info.plist" || echo "Could not read bundle ID from Info.plist" + echo "Full Info.plist excerpt:" + plutil -p "${{ inputs.app-path }}/Contents/Info.plist" | grep -i bundle + else + echo "Info.plist not found at expected location: ${{ inputs.app-path }}/Contents/Info.plist" + fi fi else echo "โš ๏ธ Missing notarization credentials. Skipping notarization." diff --git a/.gitea/workflows/test-macos-build.yml b/.gitea/workflows/test-macos-build.yml index b30c5f90..887c9046 100644 --- a/.gitea/workflows/test-macos-build.yml +++ b/.gitea/workflows/test-macos-build.yml @@ -85,6 +85,16 @@ jobs: # Export APP_PATH for next steps to use echo "APP_PATH=$MAIN_APP_PATH" >> "$GITHUB_ENV" + + # Extract bundle ID from Info.plist + if [ -f "$MAIN_APP_PATH/Contents/Info.plist" ]; then + BUNDLE_ID=$(/usr/libexec/PlistBuddy -c "Print :CFBundleIdentifier" "$MAIN_APP_PATH/Contents/Info.plist") + echo "Detected bundle ID from app: $BUNDLE_ID" + echo "BUNDLE_ID=$BUNDLE_ID" >> "$GITHUB_ENV" + else + echo "WARNING: Could not find Info.plist in app bundle. Using default bundle ID." + echo "BUNDLE_ID=com.YourCompany.LuckyWorld" >> "$GITHUB_ENV" + fi shell: bash # Use the macos-notarize action to sign and notarize the app @@ -101,7 +111,7 @@ jobs: notary-api-key-id: ${{ secrets.NOTARY_API_KEY_ID }} notary-api-key-issuer-id: ${{ secrets.NOTARY_API_KEY_ISSUER_ID }} notary-api-key-path: ${{ secrets.NOTARY_API_KEY_PATH }} - bundle-id: 'com.luckyrobots.luckyworld' + bundle-id: ${{ env.BUNDLE_ID }} fallback-to-adhoc: 'true' # Upload signed app if available -- 2.47.2 From 84a8a0876b0699caf5185c4f41629dfd47399377 Mon Sep 17 00:00:00 2001 From: Ozgur Ersoy Date: Mon, 14 Apr 2025 19:53:37 +0200 Subject: [PATCH 077/109] fix(actions): enhance notarization script with improved submission handling and detailed logging --- .gitea/actions/macos-notarize/action.yml | 264 ++++++++++++++++------- scripts/mac_build.sh | 60 ++++++ 2 files changed, 250 insertions(+), 74 deletions(-) diff --git a/.gitea/actions/macos-notarize/action.yml b/.gitea/actions/macos-notarize/action.yml index 429874c5..9b06d0e0 100644 --- a/.gitea/actions/macos-notarize/action.yml +++ b/.gitea/actions/macos-notarize/action.yml @@ -244,48 +244,91 @@ runs: ditto -c -k --keepParent "${{ inputs.app-path }}" "$ZIP_PATH" echo "Submitting for notarization with API key..." - # Capture output and exit status of notarization - NOTARY_OUTPUT=$(xcrun notarytool submit "$ZIP_PATH" \ + + # First, submit without waiting for completion + SUBMIT_OUTPUT=$(xcrun notarytool submit "$ZIP_PATH" \ --key ~/private_keys/AuthKey_${API_KEY_ID}.p8 \ --key-id "$API_KEY_ID" \ - --issuer "$API_ISSUER_ID" \ - --wait 2>&1) - NOTARY_STATUS=$? + --issuer "$API_ISSUER_ID" 2>&1) + SUBMIT_STATUS=$? # Display output for debugging - echo "Notarization command output:" - echo "$NOTARY_OUTPUT" - echo "Notarization exit status: $NOTARY_STATUS" + echo "Notarization submission output:" + echo "$SUBMIT_OUTPUT" + echo "Submission exit status: $SUBMIT_STATUS" - # Extract submission ID for log retrieval if needed - SUBMISSION_ID=$(echo "$NOTARY_OUTPUT" | grep -o "id: [a-f0-9\-]*" | head -1 | cut -d ' ' -f 2) - echo "Submission ID: $SUBMISSION_ID" - - # Check for invalid status and get detailed logs - if [ $NOTARY_STATUS -eq 0 ] && echo "$NOTARY_OUTPUT" | grep -q "Invalid"; then - echo "โš ๏ธ Notarization returned Invalid status. Checking detailed logs..." - if [ -n "$SUBMISSION_ID" ]; then - echo "๐Ÿ“‹ Fetching detailed logs for submission ID: $SUBMISSION_ID" - LOGS_OUTPUT=$(xcrun notarytool log "$SUBMISSION_ID" \ - --key ~/private_keys/AuthKey_${API_KEY_ID}.p8 \ - --key-id "$API_KEY_ID" \ - --issuer "$API_ISSUER_ID" 2>&1) - - echo "==== DETAILED NOTARIZATION LOGS ====" - echo "$LOGS_OUTPUT" - echo "==================================" - - # Extract specific issues for easier debugging - echo "๐Ÿ” Extracting specific issues from logs..." - echo "$LOGS_OUTPUT" | grep -A 3 "issues" - else - echo "โŒ Could not extract submission ID from notarization output" - fi + # Check if submission was successful + if [ $SUBMIT_STATUS -ne 0 ]; then + echo "โŒ Failed to submit for notarization. Exit code: $SUBMIT_STATUS" + exit 1 fi - # Enhanced check for notarization success - if [ $NOTARY_STATUS -eq 0 ] && echo "$NOTARY_OUTPUT" | grep -q -E "success|accepted"; then - echo "โœ… Notarization completed successfully!" + # Extract submission ID for log retrieval + SUBMISSION_ID=$(echo "$SUBMIT_OUTPUT" | grep -o "id: [a-f0-9\-]*" | head -1 | cut -d ' ' -f 2) + + if [ -z "$SUBMISSION_ID" ]; then + echo "โŒ Could not extract submission ID from output. Notarization failed." + exit 1 + fi + + echo "Submission ID: $SUBMISSION_ID" + echo "Waiting for notarization to complete..." + + # Now wait for the processing to complete + COMPLETE=false + MAX_ATTEMPTS=60 # Maximum number of attempts (60 * 30 seconds = 30 minutes max) + ATTEMPT=1 + + while [ "$COMPLETE" = "false" ] && [ $ATTEMPT -le $MAX_ATTEMPTS ]; do + echo "Checking notarization status (attempt $ATTEMPT of $MAX_ATTEMPTS)..." + + INFO_OUTPUT=$(xcrun notarytool info "$SUBMISSION_ID" \ + --key ~/private_keys/AuthKey_${API_KEY_ID}.p8 \ + --key-id "$API_KEY_ID" \ + --issuer "$API_ISSUER_ID" 2>&1) + INFO_STATUS=$? + + echo "Status check output:" + echo "$INFO_OUTPUT" + + # Check if the notarization is complete + if echo "$INFO_OUTPUT" | grep -q "status: Accepted"; then + echo "โœ… Notarization completed successfully!" + COMPLETE=true + FINAL_STATUS="Accepted" + elif echo "$INFO_OUTPUT" | grep -q "status: Invalid"; then + echo "โŒ Notarization failed with status: Invalid" + COMPLETE=true + FINAL_STATUS="Invalid" + elif echo "$INFO_OUTPUT" | grep -q "status: Rejected"; then + echo "โŒ Notarization failed with status: Rejected" + COMPLETE=true + FINAL_STATUS="Rejected" + else + echo "Notarization still in progress. Waiting 30 seconds before checking again..." + sleep 30 + ATTEMPT=$((ATTEMPT + 1)) + fi + done + + # Handle timeout + if [ "$COMPLETE" = "false" ]; then + echo "โŒ Notarization timed out after $MAX_ATTEMPTS attempts." + exit 1 + fi + + # Handle completed notarization + if [ "$FINAL_STATUS" = "Accepted" ]; then + # Get logs for information (even though successful) + echo "๐Ÿ“‹ Getting notarization logs for information..." + LOGS_OUTPUT=$(xcrun notarytool log "$SUBMISSION_ID" \ + --key ~/private_keys/AuthKey_${API_KEY_ID}.p8 \ + --key-id "$API_KEY_ID" \ + --issuer "$API_ISSUER_ID" 2>&1) + + echo "==== NOTARIZATION LOG SUMMARY ====" + echo "$LOGS_OUTPUT" | head -20 + echo "==================================" # Staple the notarization ticket echo "Stapling notarization ticket..." @@ -304,8 +347,20 @@ runs: echo "::set-output name=notarized::true" else - echo "โŒ Notarization failed or did not complete properly" - echo "Please check the notarization logs above for details" + # Get detailed logs for failed notarization + echo "๐Ÿ“‹ Fetching detailed logs for submission ID: $SUBMISSION_ID" + LOGS_OUTPUT=$(xcrun notarytool log "$SUBMISSION_ID" \ + --key ~/private_keys/AuthKey_${API_KEY_ID}.p8 \ + --key-id "$API_KEY_ID" \ + --issuer "$API_ISSUER_ID" 2>&1) + + echo "==== DETAILED NOTARIZATION LOGS ====" + echo "$LOGS_OUTPUT" + echo "==================================" + + # Extract specific issues for easier debugging + echo "๐Ÿ” Extracting specific issues from logs..." + echo "$LOGS_OUTPUT" | grep -A 3 "issues" # Show current bundle ID in Info.plist echo "๐Ÿ“‹ Current bundle ID information:" @@ -332,6 +387,9 @@ runs: echo "Checking signature on: $lib" codesign -vvv "$lib" || echo "โš ๏ธ Signature issue with: $lib" done + + echo "โŒ Notarization failed with status: $FINAL_STATUS" + exit 1 fi # Clean up @@ -346,48 +404,91 @@ runs: ditto -c -k --keepParent "${{ inputs.app-path }}" "$ZIP_PATH" echo "Submitting for notarization..." - # Capture output and exit status of notarization - NOTARY_OUTPUT=$(xcrun notarytool submit "$ZIP_PATH" \ + + # First, submit without waiting for completion + SUBMIT_OUTPUT=$(xcrun notarytool submit "$ZIP_PATH" \ --apple-id "$APPLE_ID" \ --password "$APP_PASSWORD" \ - --team-id "$APPLE_TEAM_ID" \ - --wait 2>&1) - NOTARY_STATUS=$? + --team-id "$APPLE_TEAM_ID" 2>&1) + SUBMIT_STATUS=$? # Display output for debugging - echo "Notarization command output:" - echo "$NOTARY_OUTPUT" - echo "Notarization exit status: $NOTARY_STATUS" + echo "Notarization submission output:" + echo "$SUBMIT_OUTPUT" + echo "Submission exit status: $SUBMIT_STATUS" - # Extract submission ID for log retrieval if needed - SUBMISSION_ID=$(echo "$NOTARY_OUTPUT" | grep -o "id: [a-f0-9\-]*" | head -1 | cut -d ' ' -f 2) - echo "Submission ID: $SUBMISSION_ID" - - # Check for invalid status and get detailed logs - if [ $NOTARY_STATUS -eq 0 ] && echo "$NOTARY_OUTPUT" | grep -q "Invalid"; then - echo "โš ๏ธ Notarization returned Invalid status. Checking detailed logs..." - if [ -n "$SUBMISSION_ID" ]; then - echo "๐Ÿ“‹ Fetching detailed logs for submission ID: $SUBMISSION_ID" - LOGS_OUTPUT=$(xcrun notarytool log "$SUBMISSION_ID" \ - --apple-id "$APPLE_ID" \ - --password "$APP_PASSWORD" \ - --team-id "$APPLE_TEAM_ID" 2>&1) - - echo "==== DETAILED NOTARIZATION LOGS ====" - echo "$LOGS_OUTPUT" - echo "==================================" - - # Extract specific issues for easier debugging - echo "๐Ÿ” Extracting specific issues from logs..." - echo "$LOGS_OUTPUT" | grep -A 3 "issues" - else - echo "โŒ Could not extract submission ID from notarization output" - fi + # Check if submission was successful + if [ $SUBMIT_STATUS -ne 0 ]; then + echo "โŒ Failed to submit for notarization. Exit code: $SUBMIT_STATUS" + exit 1 fi - # Enhanced check for notarization success - if [ $NOTARY_STATUS -eq 0 ] && echo "$NOTARY_OUTPUT" | grep -q -E "success|accepted"; then - echo "โœ… Notarization completed successfully!" + # Extract submission ID for log retrieval + SUBMISSION_ID=$(echo "$SUBMIT_OUTPUT" | grep -o "id: [a-f0-9\-]*" | head -1 | cut -d ' ' -f 2) + + if [ -z "$SUBMISSION_ID" ]; then + echo "โŒ Could not extract submission ID from output. Notarization failed." + exit 1 + fi + + echo "Submission ID: $SUBMISSION_ID" + echo "Waiting for notarization to complete..." + + # Now wait for the processing to complete + COMPLETE=false + MAX_ATTEMPTS=60 # Maximum number of attempts (60 * 30 seconds = 30 minutes max) + ATTEMPT=1 + + while [ "$COMPLETE" = "false" ] && [ $ATTEMPT -le $MAX_ATTEMPTS ]; do + echo "Checking notarization status (attempt $ATTEMPT of $MAX_ATTEMPTS)..." + + INFO_OUTPUT=$(xcrun notarytool info "$SUBMISSION_ID" \ + --apple-id "$APPLE_ID" \ + --password "$APP_PASSWORD" \ + --team-id "$APPLE_TEAM_ID" 2>&1) + INFO_STATUS=$? + + echo "Status check output:" + echo "$INFO_OUTPUT" + + # Check if the notarization is complete + if echo "$INFO_OUTPUT" | grep -q "status: Accepted"; then + echo "โœ… Notarization completed successfully!" + COMPLETE=true + FINAL_STATUS="Accepted" + elif echo "$INFO_OUTPUT" | grep -q "status: Invalid"; then + echo "โŒ Notarization failed with status: Invalid" + COMPLETE=true + FINAL_STATUS="Invalid" + elif echo "$INFO_OUTPUT" | grep -q "status: Rejected"; then + echo "โŒ Notarization failed with status: Rejected" + COMPLETE=true + FINAL_STATUS="Rejected" + else + echo "Notarization still in progress. Waiting 30 seconds before checking again..." + sleep 30 + ATTEMPT=$((ATTEMPT + 1)) + fi + done + + # Handle timeout + if [ "$COMPLETE" = "false" ]; then + echo "โŒ Notarization timed out after $MAX_ATTEMPTS attempts." + exit 1 + fi + + # Handle completed notarization + if [ "$FINAL_STATUS" = "Accepted" ]; then + # Get logs for information (even though successful) + echo "๐Ÿ“‹ Getting notarization logs for information..." + LOGS_OUTPUT=$(xcrun notarytool log "$SUBMISSION_ID" \ + --apple-id "$APPLE_ID" \ + --password "$APP_PASSWORD" \ + --team-id "$APPLE_TEAM_ID" 2>&1) + + echo "==== NOTARIZATION LOG SUMMARY ====" + echo "$LOGS_OUTPUT" | head -20 + echo "==================================" # Staple the notarization ticket echo "Stapling notarization ticket..." @@ -406,8 +507,20 @@ runs: echo "::set-output name=notarized::true" else - echo "โŒ Notarization failed or did not complete properly" - echo "Please check the notarization logs above for details" + # Get detailed logs for failed notarization + echo "๐Ÿ“‹ Fetching detailed logs for submission ID: $SUBMISSION_ID" + LOGS_OUTPUT=$(xcrun notarytool log "$SUBMISSION_ID" \ + --apple-id "$APPLE_ID" \ + --password "$APP_PASSWORD" \ + --team-id "$APPLE_TEAM_ID" 2>&1) + + echo "==== DETAILED NOTARIZATION LOGS ====" + echo "$LOGS_OUTPUT" + echo "==================================" + + # Extract specific issues for easier debugging + echo "๐Ÿ” Extracting specific issues from logs..." + echo "$LOGS_OUTPUT" | grep -A 3 "issues" # Show current bundle ID in Info.plist echo "๐Ÿ“‹ Current bundle ID information:" @@ -419,6 +532,9 @@ runs: else echo "Info.plist not found at expected location: ${{ inputs.app-path }}/Contents/Info.plist" fi + + echo "โŒ Notarization failed with status: $FINAL_STATUS" + exit 1 fi else echo "โš ๏ธ Missing notarization credentials. Skipping notarization." diff --git a/scripts/mac_build.sh b/scripts/mac_build.sh index 1dbad1a5..88dbb4f8 100755 --- a/scripts/mac_build.sh +++ b/scripts/mac_build.sh @@ -96,3 +96,63 @@ if [ -n "$APP_PATH" ]; then echo "๐Ÿ” Checking for PhysX and other special libraries (often need special handling):" find "$APP_PATH" -name "*PhysX*" -o -name "*APEX*" fi + +# Bundle ID'yi proje ayarlarฤฑnda gรผncelle +echo "" +echo "๐Ÿ”ง Updating bundle ID in UE config..." +CONFIG_FILE="$PROJECT_ROOT/Config/DefaultGame.ini" +if [ -f "$CONFIG_FILE" ]; then + # Mevcut bรถlรผmรผ kontrol et veya ekle + if grep -q "\[/Script/MacTargetPlatform\.MacTargetSettings\]" "$CONFIG_FILE"; then + # Bรถlรผm var, ayarฤฑ gรผncelleyebiliriz + sed -i '' 's/BundleIdentifier=.*/BundleIdentifier=com.luckyrobots.luckyworld/g' "$CONFIG_FILE" + else + # Bรถlรผm yok, eklememiz gerekiyor + echo "" >> "$CONFIG_FILE" + echo "[/Script/MacTargetPlatform.MacTargetSettings]" >> "$CONFIG_FILE" + echo "BundleIdentifier=com.luckyrobots.luckyworld" >> "$CONFIG_FILE" + fi + echo "Updated bundle ID in project config" +fi + +# Build sonrasฤฑ iลŸlemler - bundle ID ayarlama +echo "" +echo "๐Ÿ”ง Performing post-build fix for bundle ID..." +if [ -n "$APP_PATH" ]; then + INFO_PLIST="$APP_PATH/Contents/Info.plist" + if [ -f "$INFO_PLIST" ]; then + echo "Setting bundle identifier to com.luckyrobots.luckyworld" + /usr/libexec/PlistBuddy -c "Set :CFBundleIdentifier com.luckyrobots.luckyworld" "$INFO_PLIST" + echo "Updated bundle ID: $(/usr/libexec/PlistBuddy -c "Print :CFBundleIdentifier" "$INFO_PLIST")" + else + echo "โš ๏ธ Info.plist not found at $INFO_PLIST" + fi +fi + +# Kรผtรผphaneleri kontrol et ve gerekirse post-processing yap +echo "" +echo "๐Ÿ” Checking for unsigned libraries..." +if [ -n "$APP_PATH" ]; then + # Uygulamanฤฑn tรผm executable ve kรผtรผphanelerini bul + find "$APP_PATH" -type f -perm +111 | while read -r binary; do + # Codesign durumunu kontrol et + if ! codesign -v "$binary" &>/dev/null; then + echo "โš ๏ธ Unsigned binary found: $binary" + # Bu dosyayฤฑ imzalamak iรงin entitlements kullan + if [ -n "$ENTITLEMENTS_FILE" ]; then + echo "Re-signing binary with ad-hoc signature..." + codesign --force --options runtime --deep --sign - --timestamp --entitlements "$ENTITLEMENTS_FILE" "$binary" + fi + fi + done + + # Hardened Runtime iรงin ek kontroller + echo "Ensuring Hardened Runtime flags are set for main executable..." + MAIN_EXECUTABLE="$APP_PATH/Contents/MacOS/$(basename "$APP_PATH" .app)" + if [ -f "$MAIN_EXECUTABLE" ]; then + codesign --force --options runtime --deep --sign - --timestamp --entitlements "$ENTITLEMENTS_FILE" "$MAIN_EXECUTABLE" + fi +fi + +echo "" +echo "โœ… Build and post-processing completed successfully!" -- 2.47.2 From 5c6898e856fb596adb2d887c2290934e69824f2c Mon Sep 17 00:00:00 2001 From: Ozgur Ersoy Date: Mon, 14 Apr 2025 19:56:08 +0200 Subject: [PATCH 078/109] fix(actions): implement recursive signing for all binaries in notarization script --- scripts/mac_build.sh | 136 +++++++++++++++++++++++++++++++++++++------ 1 file changed, 117 insertions(+), 19 deletions(-) diff --git a/scripts/mac_build.sh b/scripts/mac_build.sh index 88dbb4f8..7f243488 100755 --- a/scripts/mac_build.sh +++ b/scripts/mac_build.sh @@ -129,29 +129,127 @@ if [ -n "$APP_PATH" ]; then fi fi -# Kรผtรผphaneleri kontrol et ve gerekirse post-processing yap -echo "" -echo "๐Ÿ” Checking for unsigned libraries..." -if [ -n "$APP_PATH" ]; then - # Uygulamanฤฑn tรผm executable ve kรผtรผphanelerini bul - find "$APP_PATH" -type f -perm +111 | while read -r binary; do - # Codesign durumunu kontrol et - if ! codesign -v "$binary" &>/dev/null; then - echo "โš ๏ธ Unsigned binary found: $binary" - # Bu dosyayฤฑ imzalamak iรงin entitlements kullan - if [ -n "$ENTITLEMENTS_FILE" ]; then - echo "Re-signing binary with ad-hoc signature..." - codesign --force --options runtime --deep --sign - --timestamp --entitlements "$ENTITLEMENTS_FILE" "$binary" - fi +# Recursive imzalama fonksiyonu - tรผm binary dosyalarฤฑ imzalar +function sign_recursively() { + local app_path="$1" + local entitlements_file="$2" + local counter=0 + local total=0 + local failed=0 + + # ร–nce toplam dosya sayฤฑsฤฑnฤฑ hesapla + # Tรผm binary dosyalarฤฑ bul (executable, dylib, so, รงerรงeveler) + echo "Scanning for binary files..." + + # Executable binary files (libraries, executables) + binaries=$(find "$app_path" -type f \( -name "*.dylib" -o -name "*.so" -o -perm +111 \) | sort) + total=$(echo "$binaries" | wc -l) + + echo "Found $total binary files to sign" + + # Helper binary dosyalarฤฑ imzala (tercih sฤฑrasฤฑna gรถre) + echo "Signing all binary files (libraries and executables)..." + echo "$binaries" | while read -r binary; do + counter=$((counter + 1)) + + # Her 20 dosyada bir ilerleme gรถster + if [ $((counter % 20)) -eq 0 ] || [ $counter -eq 1 ] || [ $counter -eq $total ]; then + echo "Progress: $counter/$total - Signing: $binary" fi + + # Skip if not a regular file (symbolic links etc) + if [ ! -f "$binary" ]; then + continue + fi + + # Dosya tรผrรผnรผ kontrol et + file_info=$(file "$binary") + + # Sadece Mach-O dosyalarฤฑnฤฑ imzala + if ! echo "$file_info" | grep -q "Mach-O"; then + continue + fi + + if [[ "$binary" == *CrashReportClient* ]]; then + echo "๐Ÿ› ๏ธ Special handling for CrashReportClient: $binary" + fi + + # Timestamp ve runtime options ile imzala + codesign --force --options runtime --deep --sign - --timestamp --entitlements "$entitlements_file" "$binary" 2>&1 || { + echo "โš ๏ธ Failed to sign: $binary" + failed=$((failed + 1)) + } done - # Hardened Runtime iรงin ek kontroller - echo "Ensuring Hardened Runtime flags are set for main executable..." - MAIN_EXECUTABLE="$APP_PATH/Contents/MacOS/$(basename "$APP_PATH" .app)" - if [ -f "$MAIN_EXECUTABLE" ]; then - codesign --force --options runtime --deep --sign - --timestamp --entitlements "$ENTITLEMENTS_FILE" "$MAIN_EXECUTABLE" + # BaลŸvuru iรงin ENTITLEMENTS iรงeriฤŸini gรถster + echo "Using entitlements file for signatures:" + cat "$entitlements_file" + + # Tรผm nested app'leri bul ve imzala + nested_apps=$(find "$app_path" -name "*.app" -type d) + + if [ -n "$nested_apps" ]; then + echo "Signing nested applications..." + echo "$nested_apps" | while read -r nested_app; do + if [ "$nested_app" != "$app_path" ]; then + echo "Signing nested app: $nested_app" + + # ฤฐmzalamadan รถnce Info.plist varsa Bundle ID ayarla + nested_info="$nested_app/Contents/Info.plist" + if [ -f "$nested_info" ]; then + echo "Setting bundle identifier for nested app" + /usr/libexec/PlistBuddy -c "Set :CFBundleIdentifier com.luckyrobots.luckyworld.nested" "$nested_info" 2>/dev/null || true + fi + + codesign --force --options runtime --deep --sign - --timestamp --entitlements "$entitlements_file" "$nested_app" 2>&1 || { + echo "โš ๏ธ Failed to sign nested app: $nested_app" + failed=$((failed + 1)) + } + fi + done fi + + # Asฤฑl uygulamayฤฑ imzala + echo "Signing main application: $app_path" + codesign --force --options runtime --deep --sign - --timestamp --entitlements "$entitlements_file" "$app_path" 2>&1 || { + echo "โš ๏ธ Failed to sign main app: $app_path" + failed=$((failed + 1)) + } + + echo "โœ… Signing completed: $counter files processed, $failed failures" + + # ฤฐmzalama durumunu kontrol et + echo "Verifying signatures..." + codesign -vvv --deep --strict "$app_path" + + # Hardened Runtime ve diฤŸer gรผvenlik ayarlarฤฑ kontrol et + echo "Checking security settings (Hardened Runtime, etc.):" + codesign -d --entitlements - "$app_path" | grep -i "runtime\|hardened\|security" + + # Spesifik olarak CrashReportClient'i kontrol et (sorunlu dosya) + crash_reporter=$(find "$app_path" -path "*CrashReportClient.app/Contents/MacOS/CrashReportClient" -type f | head -1) + if [ -n "$crash_reporter" ]; then + echo "Checking CrashReportClient specifically:" + codesign -d --entitlements - "$crash_reporter" | grep -i "runtime\|hardened\|security" + fi +} + +# Kรผtรผphaneleri kontrol et ve gerekirse post-processing yap +echo "" +echo "๐Ÿ” Performing comprehensive signing and hardening of all binaries..." +if [ -n "$APP_PATH" ] && [ -n "$ENTITLEMENTS_FILE" ]; then + # Recursive olarak tรผm binary dosyalarฤฑ imzala + sign_recursively "$APP_PATH" "$ENTITLEMENTS_FILE" + + # Son olarak ana uygulamayฤฑ tekrar imzala + echo "Final signing of main app bundle" + codesign --force --options runtime --deep --sign - --timestamp --entitlements "$ENTITLEMENTS_FILE" "$APP_PATH" + + echo "โœ… All binaries signed successfully with Hardened Runtime enabled" +else + echo "โŒ App path or entitlements file not found, cannot perform comprehensive signing" + echo "App path: $APP_PATH" + echo "Entitlements file: $ENTITLEMENTS_FILE" fi echo "" -- 2.47.2 From f28c4a21b5319b46d58035411027e6b65f0f44dc Mon Sep 17 00:00:00 2001 From: Ozgur Ersoy Date: Mon, 14 Apr 2025 21:20:13 +0200 Subject: [PATCH 079/109] fix(actions): enhance notarization script with comprehensive signing and bundle ID updates --- .gitea/actions/macos-notarize/action.yml | 66 +++++++++++++++++- .gitea/workflows/test-macos-build.yml | 88 +++++++++++++++++++++-- LuckyWorld.entitlements | 8 +++ scripts/mac_build.sh | 89 ++++++++++++++++-------- 4 files changed, 215 insertions(+), 36 deletions(-) diff --git a/.gitea/actions/macos-notarize/action.yml b/.gitea/actions/macos-notarize/action.yml index 9b06d0e0..1f9c1973 100644 --- a/.gitea/actions/macos-notarize/action.yml +++ b/.gitea/actions/macos-notarize/action.yml @@ -177,7 +177,61 @@ runs: else echo "Signing app bundle with Developer ID hash: $IDENTITY_HASH" - # Sign the app bundle using the hash + # Enhanced deep recursive signing for all binaries + echo "๐Ÿ” Performing deep recursive signing of all components..." + + # First, find all .dylib files and sign them individually + echo "Signing all dynamic libraries (.dylib files)..." + find "${{ inputs.app-path }}" -name "*.dylib" | while read -r dylib; do + echo "Signing: $dylib" + codesign --force --verbose --options runtime --entitlements "${{ inputs.entitlements-file }}" --sign "$IDENTITY_HASH" --timestamp "$dylib" || echo "โš ๏ธ Failed to sign: $dylib" + done + + # Sign all .so files + echo "Signing all shared objects (.so files)..." + find "${{ inputs.app-path }}" -name "*.so" | while read -r so; do + echo "Signing: $so" + codesign --force --verbose --options runtime --entitlements "${{ inputs.entitlements-file }}" --sign "$IDENTITY_HASH" --timestamp "$so" || echo "โš ๏ธ Failed to sign: $so" + done + + # Sign all executable files (files with execute permission) + echo "Signing all executable files..." + find "${{ inputs.app-path }}" -type f -perm +111 -not -path "*.framework/*" -not -name "*.dylib" -not -name "*.so" | while read -r exe; do + echo "Signing executable: $exe" + codesign --force --verbose --options runtime --entitlements "${{ inputs.entitlements-file }}" --sign "$IDENTITY_HASH" --timestamp "$exe" || echo "โš ๏ธ Failed to sign: $exe" + done + + # Sign all frameworks + echo "Signing frameworks..." + find "${{ inputs.app-path }}" -path "*.framework" -type d | while read -r framework; do + echo "Signing framework: $framework" + codesign --force --verbose --options runtime --entitlements "${{ inputs.entitlements-file }}" --sign "$IDENTITY_HASH" --timestamp "$framework" || echo "โš ๏ธ Failed to sign: $framework" + done + + # Special handling for CrashReportClient.app + CRASH_REPORTER=$(find "${{ inputs.app-path }}" -path "*CrashReportClient.app" -type d | head -1) + if [ -n "$CRASH_REPORTER" ]; then + echo "๐Ÿ” Special handling for CrashReportClient.app: $CRASH_REPORTER" + # Sign CrashReportClient.app specifically with focus on hardened runtime + find "$CRASH_REPORTER" -type f -perm +111 | while read -r crash_bin; do + echo "Signing CrashReportClient binary: $crash_bin" + codesign --force --verbose --options runtime --entitlements "${{ inputs.entitlements-file }}" --sign "$IDENTITY_HASH" --timestamp "$crash_bin" || echo "โš ๏ธ Failed to sign: $crash_bin" + done + + echo "Signing the CrashReportClient.app bundle itself..." + codesign --force --deep --verbose --options runtime --entitlements "${{ inputs.entitlements-file }}" --sign "$IDENTITY_HASH" --timestamp "$CRASH_REPORTER" || echo "โš ๏ธ Failed to sign CrashReportClient.app" + fi + + # Sign any other nested app bundles + find "${{ inputs.app-path }}" -path "*.app" -type d | grep -v CrashReportClient | while read -r nested_app; do + if [ "$nested_app" != "${{ inputs.app-path }}" ]; then + echo "Signing nested app: $nested_app" + codesign --force --deep --verbose --options runtime --entitlements "${{ inputs.entitlements-file }}" --sign "$IDENTITY_HASH" --timestamp "$nested_app" || echo "โš ๏ธ Failed to sign: $nested_app" + fi + done + + # Final signing of the main bundle + echo "๐Ÿ” Performing final signing of the main app bundle..." codesign --force --deep --verbose --options runtime --entitlements "${{ inputs.entitlements-file }}" --sign "$IDENTITY_HASH" --timestamp "${{ inputs.app-path }}" echo "::set-output name=signed::identity" fi @@ -189,6 +243,16 @@ runs: # Check entitlements echo "๐Ÿ” Checking entitlements..." codesign -d --entitlements - "${{ inputs.app-path }}" + + # Verify CrashReportClient + CRASH_REPORTER=$(find "${{ inputs.app-path }}" -path "*CrashReportClient.app" -type d | head -1) + if [ -n "$CRASH_REPORTER" ]; then + echo "๐Ÿ” Verifying CrashReportClient signature..." + codesign -vvv --deep --strict "$CRASH_REPORTER" || echo "โš ๏ธ CrashReportClient may have verification issues" + + echo "CrashReportClient entitlements:" + codesign -d --entitlements - "$CRASH_REPORTER" || echo "โš ๏ธ Could not display CrashReportClient entitlements" + fi - name: Notarize App id: notarize diff --git a/.gitea/workflows/test-macos-build.yml b/.gitea/workflows/test-macos-build.yml index 887c9046..f6fa982a 100644 --- a/.gitea/workflows/test-macos-build.yml +++ b/.gitea/workflows/test-macos-build.yml @@ -30,6 +30,29 @@ jobs: echo "Environment setup complete" shell: bash + # Set correct bundle identifier before build + - name: Set bundle identifier + run: | + # Set the correct bundle identifier in DefaultGame.ini if it exists + CONFIG_FILE="Config/DefaultGame.ini" + if [ -f "$CONFIG_FILE" ]; then + # Check if section exists or add it + if grep -q "\[/Script/MacTargetPlatform\.MacTargetSettings\]" "$CONFIG_FILE"; then + # Section exists, update the setting + sed -i '' 's/BundleIdentifier=.*/BundleIdentifier=com.luckyrobots.luckyworld/g' "$CONFIG_FILE" + else + # Section doesn't exist, add it + echo "" >> "$CONFIG_FILE" + echo "[/Script/MacTargetPlatform.MacTargetSettings]" >> "$CONFIG_FILE" + echo "BundleIdentifier=com.luckyrobots.luckyworld" >> "$CONFIG_FILE" + fi + echo "Updated bundle ID in project config" + fi + + # Set the constant bundle ID for the workflow + echo "BUNDLE_ID=com.luckyrobots.luckyworld" >> "$GITHUB_ENV" + shell: bash + # Build for macOS - use your own build script or create a test app if needed - name: Build for macOS run: | @@ -86,14 +109,65 @@ jobs: # Export APP_PATH for next steps to use echo "APP_PATH=$MAIN_APP_PATH" >> "$GITHUB_ENV" - # Extract bundle ID from Info.plist + # Fix bundle ID in Info.plist before signing if [ -f "$MAIN_APP_PATH/Contents/Info.plist" ]; then - BUNDLE_ID=$(/usr/libexec/PlistBuddy -c "Print :CFBundleIdentifier" "$MAIN_APP_PATH/Contents/Info.plist") - echo "Detected bundle ID from app: $BUNDLE_ID" - echo "BUNDLE_ID=$BUNDLE_ID" >> "$GITHUB_ENV" + echo "Setting bundle identifier to $BUNDLE_ID" + /usr/libexec/PlistBuddy -c "Set :CFBundleIdentifier $BUNDLE_ID" "$MAIN_APP_PATH/Contents/Info.plist" + echo "Updated bundle ID in Info.plist: $(/usr/libexec/PlistBuddy -c "Print :CFBundleIdentifier" "$MAIN_APP_PATH/Contents/Info.plist")" else - echo "WARNING: Could not find Info.plist in app bundle. Using default bundle ID." - echo "BUNDLE_ID=com.YourCompany.LuckyWorld" >> "$GITHUB_ENV" + echo "WARNING: Could not find Info.plist in app bundle." + fi + + # Find and repair nested app bundles as well (like CrashReportClient.app) + NESTED_APPS=$(find "$MAIN_APP_PATH" -name "*.app" -type d) + if [ -n "$NESTED_APPS" ]; then + echo "Found nested app bundles, fixing their bundle IDs:" + echo "$NESTED_APPS" | while read -r NESTED_APP; do + if [ -f "$NESTED_APP/Contents/Info.plist" ]; then + NESTED_NAME=$(basename "$NESTED_APP" .app) + NESTED_BUNDLE_ID="$BUNDLE_ID.$NESTED_NAME" + echo "Setting nested bundle ID to $NESTED_BUNDLE_ID for $NESTED_APP" + /usr/libexec/PlistBuddy -c "Set :CFBundleIdentifier $NESTED_BUNDLE_ID" "$NESTED_APP/Contents/Info.plist" + fi + done + fi + shell: bash + + # Fix common issues that may cause notarization failure + - name: Fix common issues for notarization + run: | + echo "๐Ÿ› ๏ธ Fixing common issues that may cause notarization failure..." + + APP_PATH="${{ env.APP_PATH }}" + + # Remove get-task-allow entitlement from Info.plist files + echo "Checking for get-task-allow entitlement..." + find "$APP_PATH" -name "*.plist" -exec plutil -convert xml1 {} \; -exec grep -l "get-task-allow" {} \; | while read -r plist_file; do + echo "Removing get-task-allow from $plist_file" + /usr/libexec/PlistBuddy -c "Delete :com.apple.security.get-task-allow" "$plist_file" 2>/dev/null || true + done + + # Check for problematic libraries that cause issues + echo "Looking for problematic files..." + PROBLEM_FILES=$(find "$APP_PATH" -type f -name "*.dylib" | grep -i "boost\|tbb\|ogg\|vorbis\|onnx") + if [ -n "$PROBLEM_FILES" ]; then + echo "Found potentially problematic libraries. These will be carefully handled during signing:" + echo "$PROBLEM_FILES" | head -10 + if [ $(echo "$PROBLEM_FILES" | wc -l) -gt 10 ]; then + echo "... and $(echo "$PROBLEM_FILES" | wc -l) more" + fi + fi + + # Verify CrashReportClient specifically + CRASH_REPORTER=$(find "$APP_PATH" -path "*CrashReportClient.app*" -type d | head -1) + if [ -n "$CRASH_REPORTER" ]; then + echo "Found CrashReportClient at $CRASH_REPORTER" + if [ -f "$CRASH_REPORTER/Contents/Info.plist" ]; then + # Ensure it has the correct bundle ID format + CRASH_BUNDLE_ID="$BUNDLE_ID.CrashReportClient" + echo "Setting CrashReportClient bundle ID to $CRASH_BUNDLE_ID" + /usr/libexec/PlistBuddy -c "Set :CFBundleIdentifier $CRASH_BUNDLE_ID" "$CRASH_REPORTER/Contents/Info.plist" + fi fi shell: bash @@ -112,7 +186,7 @@ jobs: notary-api-key-issuer-id: ${{ secrets.NOTARY_API_KEY_ISSUER_ID }} notary-api-key-path: ${{ secrets.NOTARY_API_KEY_PATH }} bundle-id: ${{ env.BUNDLE_ID }} - fallback-to-adhoc: 'true' + fallback-to-adhoc: 'false' # Upload signed app if available - name: Upload Signed App diff --git a/LuckyWorld.entitlements b/LuckyWorld.entitlements index ee35bd86..4dc9a495 100644 --- a/LuckyWorld.entitlements +++ b/LuckyWorld.entitlements @@ -14,5 +14,13 @@ com.apple.security.device.camera + com.apple.security.automation.apple-events + + com.apple.security.cs.debugger + + com.apple.security.files.user-selected.read-write + + com.apple.security.network.client + \ No newline at end of file diff --git a/scripts/mac_build.sh b/scripts/mac_build.sh index 7f243488..d8b46c43 100755 --- a/scripts/mac_build.sh +++ b/scripts/mac_build.sh @@ -13,6 +13,22 @@ PROJECT_ROOT="$(pwd)" PROJECT_FILE="$PROJECT_ROOT/LuckyWorld.uproject" ARCHIVE_DIR="$PROJECT_ROOT/Builds" +# Check for Developer ID certificate +CERTIFICATE_NAME="" +if [ -z "$CERTIFICATE_NAME" ]; then + # Try to find a Developer ID Application certificate + CERTIFICATE_NAME=$(security find-identity -v -p codesigning | grep "Developer ID Application" | head -1 | sed -E 's/.*"(Developer ID Application.*)"$/\1/') + + if [ -z "$CERTIFICATE_NAME" ]; then + echo "โš ๏ธ No Developer ID Application certificate found. Please specify a valid certificate name." + echo "Available certificates:" + security find-identity -v -p codesigning + exit 1 + else + echo "๐Ÿ”‘ Found Developer ID certificate: $CERTIFICATE_NAME" + fi +fi + # Check for entitlements file if [ -f "$PROJECT_ROOT/LuckyWorld.entitlements" ]; then ENTITLEMENTS_FILE="$PROJECT_ROOT/LuckyWorld.entitlements" @@ -28,6 +44,7 @@ echo "Project root: $PROJECT_ROOT" echo "Project file: $PROJECT_FILE" echo "Archive directory: $ARCHIVE_DIR" echo "Entitlements file: $ENTITLEMENTS_FILE" +echo "Signing with certificate: $CERTIFICATE_NAME" # Clean up previous build artifacts rm -rf DerivedDataCache Intermediate Binaries Saved @@ -97,17 +114,17 @@ if [ -n "$APP_PATH" ]; then find "$APP_PATH" -name "*PhysX*" -o -name "*APEX*" fi -# Bundle ID'yi proje ayarlarฤฑnda gรผncelle +# Update bundle ID in project settings echo "" echo "๐Ÿ”ง Updating bundle ID in UE config..." CONFIG_FILE="$PROJECT_ROOT/Config/DefaultGame.ini" if [ -f "$CONFIG_FILE" ]; then - # Mevcut bรถlรผmรผ kontrol et veya ekle + # Check if section exists or add it if grep -q "\[/Script/MacTargetPlatform\.MacTargetSettings\]" "$CONFIG_FILE"; then - # Bรถlรผm var, ayarฤฑ gรผncelleyebiliriz + # Section exists, update the setting sed -i '' 's/BundleIdentifier=.*/BundleIdentifier=com.luckyrobots.luckyworld/g' "$CONFIG_FILE" else - # Bรถlรผm yok, eklememiz gerekiyor + # Section doesn't exist, add it echo "" >> "$CONFIG_FILE" echo "[/Script/MacTargetPlatform.MacTargetSettings]" >> "$CONFIG_FILE" echo "BundleIdentifier=com.luckyrobots.luckyworld" >> "$CONFIG_FILE" @@ -115,7 +132,7 @@ if [ -f "$CONFIG_FILE" ]; then echo "Updated bundle ID in project config" fi -# Build sonrasฤฑ iลŸlemler - bundle ID ayarlama +# Post-build process - set bundle ID echo "" echo "๐Ÿ”ง Performing post-build fix for bundle ID..." if [ -n "$APP_PATH" ]; then @@ -129,16 +146,17 @@ if [ -n "$APP_PATH" ]; then fi fi -# Recursive imzalama fonksiyonu - tรผm binary dosyalarฤฑ imzalar +# Recursive signing function - signs all binary files function sign_recursively() { local app_path="$1" local entitlements_file="$2" + local certificate="$3" local counter=0 local total=0 local failed=0 - # ร–nce toplam dosya sayฤฑsฤฑnฤฑ hesapla - # Tรผm binary dosyalarฤฑ bul (executable, dylib, so, รงerรงeveler) + # First calculate total file count + # Find all binary files (executables, dylibs, .so files, frameworks) echo "Scanning for binary files..." # Executable binary files (libraries, executables) @@ -147,12 +165,12 @@ function sign_recursively() { echo "Found $total binary files to sign" - # Helper binary dosyalarฤฑ imzala (tercih sฤฑrasฤฑna gรถre) + # Sign helper binary files (in order of preference) echo "Signing all binary files (libraries and executables)..." echo "$binaries" | while read -r binary; do counter=$((counter + 1)) - # Her 20 dosyada bir ilerleme gรถster + # Show progress every 20 files if [ $((counter % 20)) -eq 0 ] || [ $counter -eq 1 ] || [ $counter -eq $total ]; then echo "Progress: $counter/$total - Signing: $binary" fi @@ -162,10 +180,10 @@ function sign_recursively() { continue fi - # Dosya tรผrรผnรผ kontrol et + # Check file type file_info=$(file "$binary") - # Sadece Mach-O dosyalarฤฑnฤฑ imzala + # Only sign Mach-O files if ! echo "$file_info" | grep -q "Mach-O"; then continue fi @@ -174,18 +192,18 @@ function sign_recursively() { echo "๐Ÿ› ๏ธ Special handling for CrashReportClient: $binary" fi - # Timestamp ve runtime options ile imzala - codesign --force --options runtime --deep --sign - --timestamp --entitlements "$entitlements_file" "$binary" 2>&1 || { + # Sign with timestamp and runtime options + codesign --force --options runtime --deep --sign "$certificate" --timestamp --entitlements "$entitlements_file" "$binary" 2>&1 || { echo "โš ๏ธ Failed to sign: $binary" failed=$((failed + 1)) } done - # BaลŸvuru iรงin ENTITLEMENTS iรงeriฤŸini gรถster + # Show ENTITLEMENTS content for reference echo "Using entitlements file for signatures:" cat "$entitlements_file" - # Tรผm nested app'leri bul ve imzala + # Find all nested apps and sign them nested_apps=$(find "$app_path" -name "*.app" -type d) if [ -n "$nested_apps" ]; then @@ -194,14 +212,14 @@ function sign_recursively() { if [ "$nested_app" != "$app_path" ]; then echo "Signing nested app: $nested_app" - # ฤฐmzalamadan รถnce Info.plist varsa Bundle ID ayarla + # Set Bundle ID in Info.plist if it exists before signing nested_info="$nested_app/Contents/Info.plist" if [ -f "$nested_info" ]; then echo "Setting bundle identifier for nested app" /usr/libexec/PlistBuddy -c "Set :CFBundleIdentifier com.luckyrobots.luckyworld.nested" "$nested_info" 2>/dev/null || true fi - codesign --force --options runtime --deep --sign - --timestamp --entitlements "$entitlements_file" "$nested_app" 2>&1 || { + codesign --force --options runtime --deep --sign "$certificate" --timestamp --entitlements "$entitlements_file" "$nested_app" 2>&1 || { echo "โš ๏ธ Failed to sign nested app: $nested_app" failed=$((failed + 1)) } @@ -209,24 +227,24 @@ function sign_recursively() { done fi - # Asฤฑl uygulamayฤฑ imzala + # Sign the main application echo "Signing main application: $app_path" - codesign --force --options runtime --deep --sign - --timestamp --entitlements "$entitlements_file" "$app_path" 2>&1 || { + codesign --force --options runtime --deep --sign "$certificate" --timestamp --entitlements "$entitlements_file" "$app_path" 2>&1 || { echo "โš ๏ธ Failed to sign main app: $app_path" failed=$((failed + 1)) } echo "โœ… Signing completed: $counter files processed, $failed failures" - # ฤฐmzalama durumunu kontrol et + # Check signing status echo "Verifying signatures..." codesign -vvv --deep --strict "$app_path" - # Hardened Runtime ve diฤŸer gรผvenlik ayarlarฤฑ kontrol et + # Check Hardened Runtime and other security settings echo "Checking security settings (Hardened Runtime, etc.):" codesign -d --entitlements - "$app_path" | grep -i "runtime\|hardened\|security" - # Spesifik olarak CrashReportClient'i kontrol et (sorunlu dosya) + # Check CrashReportClient specifically (problematic file) crash_reporter=$(find "$app_path" -path "*CrashReportClient.app/Contents/MacOS/CrashReportClient" -type f | head -1) if [ -n "$crash_reporter" ]; then echo "Checking CrashReportClient specifically:" @@ -234,18 +252,33 @@ function sign_recursively() { fi } -# Kรผtรผphaneleri kontrol et ve gerekirse post-processing yap +# Check libraries and perform post-processing if needed echo "" echo "๐Ÿ” Performing comprehensive signing and hardening of all binaries..." if [ -n "$APP_PATH" ] && [ -n "$ENTITLEMENTS_FILE" ]; then - # Recursive olarak tรผm binary dosyalarฤฑ imzala - sign_recursively "$APP_PATH" "$ENTITLEMENTS_FILE" + # Sign all binary files recursively + sign_recursively "$APP_PATH" "$ENTITLEMENTS_FILE" "$CERTIFICATE_NAME" - # Son olarak ana uygulamayฤฑ tekrar imzala + # Final signing of the main app bundle echo "Final signing of main app bundle" - codesign --force --options runtime --deep --sign - --timestamp --entitlements "$ENTITLEMENTS_FILE" "$APP_PATH" + codesign --force --options runtime --deep --sign "$CERTIFICATE_NAME" --timestamp --entitlements "$ENTITLEMENTS_FILE" "$APP_PATH" echo "โœ… All binaries signed successfully with Hardened Runtime enabled" + + # Prepare app for notarization + echo "" + echo "๐Ÿ” Preparing for notarization..." + + # Create a ZIP archive for notarization + ZIP_PATH="$ARCHIVE_DIR/LuckyWorld.zip" + echo "Creating ZIP archive for notarization: $ZIP_PATH" + ditto -c -k --keepParent "$APP_PATH" "$ZIP_PATH" + + echo "โœ… ZIP archive created for notarization at: $ZIP_PATH" + echo "" + echo "To notarize the app, run the following command:" + echo "xcrun notarytool submit \"$ZIP_PATH\" --apple-id \"YOUR_APPLE_ID\" --password \"APP_SPECIFIC_PASSWORD\" --team-id \"YOUR_TEAM_ID\" --wait" + echo "" else echo "โŒ App path or entitlements file not found, cannot perform comprehensive signing" echo "App path: $APP_PATH" -- 2.47.2 From ad5c5add9ffe943943c0d079493881255385ca8a Mon Sep 17 00:00:00 2001 From: Ozgur Ersoy Date: Mon, 14 Apr 2025 21:38:55 +0200 Subject: [PATCH 080/109] fix(actions): update notarization script to handle CI environment and improve certificate checks --- .gitea/workflows/test-macos-build.yml | 5 + scripts/mac_build.sh | 260 ++++++++++++++------------ 2 files changed, 148 insertions(+), 117 deletions(-) diff --git a/.gitea/workflows/test-macos-build.yml b/.gitea/workflows/test-macos-build.yml index f6fa982a..2c22adc6 100644 --- a/.gitea/workflows/test-macos-build.yml +++ b/.gitea/workflows/test-macos-build.yml @@ -22,6 +22,9 @@ jobs: WORKSPACE_DIR="$(pwd)" echo "WORKSPACE_DIR=$WORKSPACE_DIR" >> "$GITHUB_ENV" echo "ENTITLEMENTS_FILE=LuckyWorld.entitlements" >> "$GITHUB_ENV" + + # Set CI environment variable to true for build script + echo "CI=true" >> "$GITHUB_ENV" # Create directories for builds mkdir -p Builds/Mac @@ -58,6 +61,8 @@ jobs: run: | if [ -f "./scripts/mac_build.sh" ]; then chmod +x ./scripts/mac_build.sh + # Set CI environment variable explicitly before running + export CI=true ./scripts/mac_build.sh else echo "ERROR: Build script not found at ./scripts/mac_build.sh" diff --git a/scripts/mac_build.sh b/scripts/mac_build.sh index d8b46c43..9f500dc8 100755 --- a/scripts/mac_build.sh +++ b/scripts/mac_build.sh @@ -13,20 +13,34 @@ PROJECT_ROOT="$(pwd)" PROJECT_FILE="$PROJECT_ROOT/LuckyWorld.uproject" ARCHIVE_DIR="$PROJECT_ROOT/Builds" +# Check if running in CI environment +if [ -n "$GITHUB_ACTIONS" ] || [ -n "$CI" ]; then + # Skip certificate check in CI environment + echo "๐Ÿ”„ Running in CI environment, skipping certificate checks" + RUNNING_IN_CI=true +else + RUNNING_IN_CI=false +fi + # Check for Developer ID certificate CERTIFICATE_NAME="" -if [ -z "$CERTIFICATE_NAME" ]; then - # Try to find a Developer ID Application certificate - CERTIFICATE_NAME=$(security find-identity -v -p codesigning | grep "Developer ID Application" | head -1 | sed -E 's/.*"(Developer ID Application.*)"$/\1/') - +if [ "$RUNNING_IN_CI" = "false" ]; then + # Only check for certificate in non-CI environments if [ -z "$CERTIFICATE_NAME" ]; then - echo "โš ๏ธ No Developer ID Application certificate found. Please specify a valid certificate name." - echo "Available certificates:" - security find-identity -v -p codesigning - exit 1 - else - echo "๐Ÿ”‘ Found Developer ID certificate: $CERTIFICATE_NAME" + # Try to find a Developer ID Application certificate + CERTIFICATE_NAME=$(security find-identity -v -p codesigning | grep "Developer ID Application" | head -1 | sed -E 's/.*"(Developer ID Application.*)"$/\1/') + + if [ -z "$CERTIFICATE_NAME" ]; then + echo "โš ๏ธ No Developer ID Application certificate found. Please specify a valid certificate name." + echo "Available certificates:" + security find-identity -v -p codesigning + echo "Continuing build without signing..." + else + echo "๐Ÿ”‘ Found Developer ID certificate: $CERTIFICATE_NAME" + fi fi +else + echo "๐Ÿ”„ Skipping local certificate check - signing will be handled in CI pipeline" fi # Check for entitlements file @@ -44,7 +58,11 @@ echo "Project root: $PROJECT_ROOT" echo "Project file: $PROJECT_FILE" echo "Archive directory: $ARCHIVE_DIR" echo "Entitlements file: $ENTITLEMENTS_FILE" -echo "Signing with certificate: $CERTIFICATE_NAME" +if [ "$RUNNING_IN_CI" = "false" ] && [ -n "$CERTIFICATE_NAME" ]; then + echo "Signing with certificate: $CERTIFICATE_NAME" +else + echo "Not signing locally - will be handled in CI" +fi # Clean up previous build artifacts rm -rf DerivedDataCache Intermediate Binaries Saved @@ -146,116 +164,118 @@ if [ -n "$APP_PATH" ]; then fi fi -# Recursive signing function - signs all binary files -function sign_recursively() { - local app_path="$1" - local entitlements_file="$2" - local certificate="$3" - local counter=0 - local total=0 - local failed=0 - - # First calculate total file count - # Find all binary files (executables, dylibs, .so files, frameworks) - echo "Scanning for binary files..." - - # Executable binary files (libraries, executables) - binaries=$(find "$app_path" -type f \( -name "*.dylib" -o -name "*.so" -o -perm +111 \) | sort) - total=$(echo "$binaries" | wc -l) - - echo "Found $total binary files to sign" - - # Sign helper binary files (in order of preference) - echo "Signing all binary files (libraries and executables)..." - echo "$binaries" | while read -r binary; do - counter=$((counter + 1)) +# Only perform signing if not in CI and certificate is available +if [ "$RUNNING_IN_CI" = "false" ] && [ -n "$CERTIFICATE_NAME" ] && [ -n "$ENTITLEMENTS_FILE" ]; then + # Recursive signing function - signs all binary files + function sign_recursively() { + local app_path="$1" + local entitlements_file="$2" + local certificate="$3" + local counter=0 + local total=0 + local failed=0 - # Show progress every 20 files - if [ $((counter % 20)) -eq 0 ] || [ $counter -eq 1 ] || [ $counter -eq $total ]; then - echo "Progress: $counter/$total - Signing: $binary" + # First calculate total file count + # Find all binary files (executables, dylibs, .so files, frameworks) + echo "Scanning for binary files..." + + # Executable binary files (libraries, executables) + binaries=$(find "$app_path" -type f \( -name "*.dylib" -o -name "*.so" -o -perm +111 \) | sort) + total=$(echo "$binaries" | wc -l) + + echo "Found $total binary files to sign" + + # Sign helper binary files (in order of preference) + echo "Signing all binary files (libraries and executables)..." + echo "$binaries" | while read -r binary; do + counter=$((counter + 1)) + + # Show progress every 20 files + if [ $((counter % 20)) -eq 0 ] || [ $counter -eq 1 ] || [ $counter -eq $total ]; then + echo "Progress: $counter/$total - Signing: $binary" + fi + + # Skip if not a regular file (symbolic links etc) + if [ ! -f "$binary" ]; then + continue + fi + + # Check file type + file_info=$(file "$binary") + + # Only sign Mach-O files + if ! echo "$file_info" | grep -q "Mach-O"; then + continue + fi + + if [[ "$binary" == *CrashReportClient* ]]; then + echo "๐Ÿ› ๏ธ Special handling for CrashReportClient: $binary" + fi + + # Sign with timestamp and runtime options + codesign --force --options runtime --deep --sign "$certificate" --timestamp --entitlements "$entitlements_file" "$binary" 2>&1 || { + echo "โš ๏ธ Failed to sign: $binary" + failed=$((failed + 1)) + } + done + + # Show ENTITLEMENTS content for reference + echo "Using entitlements file for signatures:" + cat "$entitlements_file" + + # Find all nested apps and sign them + nested_apps=$(find "$app_path" -name "*.app" -type d) + + if [ -n "$nested_apps" ]; then + echo "Signing nested applications..." + echo "$nested_apps" | while read -r nested_app; do + if [ "$nested_app" != "$app_path" ]; then + echo "Signing nested app: $nested_app" + + # Set Bundle ID in Info.plist if it exists before signing + nested_info="$nested_app/Contents/Info.plist" + if [ -f "$nested_info" ]; then + echo "Setting bundle identifier for nested app" + /usr/libexec/PlistBuddy -c "Set :CFBundleIdentifier com.luckyrobots.luckyworld.nested" "$nested_info" 2>/dev/null || true + fi + + codesign --force --options runtime --deep --sign "$certificate" --timestamp --entitlements "$entitlements_file" "$nested_app" 2>&1 || { + echo "โš ๏ธ Failed to sign nested app: $nested_app" + failed=$((failed + 1)) + } + fi + done fi - # Skip if not a regular file (symbolic links etc) - if [ ! -f "$binary" ]; then - continue - fi - - # Check file type - file_info=$(file "$binary") - - # Only sign Mach-O files - if ! echo "$file_info" | grep -q "Mach-O"; then - continue - fi - - if [[ "$binary" == *CrashReportClient* ]]; then - echo "๐Ÿ› ๏ธ Special handling for CrashReportClient: $binary" - fi - - # Sign with timestamp and runtime options - codesign --force --options runtime --deep --sign "$certificate" --timestamp --entitlements "$entitlements_file" "$binary" 2>&1 || { - echo "โš ๏ธ Failed to sign: $binary" + # Sign the main application + echo "Signing main application: $app_path" + codesign --force --options runtime --deep --sign "$certificate" --timestamp --entitlements "$entitlements_file" "$app_path" 2>&1 || { + echo "โš ๏ธ Failed to sign main app: $app_path" failed=$((failed + 1)) } - done - - # Show ENTITLEMENTS content for reference - echo "Using entitlements file for signatures:" - cat "$entitlements_file" - - # Find all nested apps and sign them - nested_apps=$(find "$app_path" -name "*.app" -type d) - - if [ -n "$nested_apps" ]; then - echo "Signing nested applications..." - echo "$nested_apps" | while read -r nested_app; do - if [ "$nested_app" != "$app_path" ]; then - echo "Signing nested app: $nested_app" - - # Set Bundle ID in Info.plist if it exists before signing - nested_info="$nested_app/Contents/Info.plist" - if [ -f "$nested_info" ]; then - echo "Setting bundle identifier for nested app" - /usr/libexec/PlistBuddy -c "Set :CFBundleIdentifier com.luckyrobots.luckyworld.nested" "$nested_info" 2>/dev/null || true - fi - - codesign --force --options runtime --deep --sign "$certificate" --timestamp --entitlements "$entitlements_file" "$nested_app" 2>&1 || { - echo "โš ๏ธ Failed to sign nested app: $nested_app" - failed=$((failed + 1)) - } - fi - done - fi - - # Sign the main application - echo "Signing main application: $app_path" - codesign --force --options runtime --deep --sign "$certificate" --timestamp --entitlements "$entitlements_file" "$app_path" 2>&1 || { - echo "โš ๏ธ Failed to sign main app: $app_path" - failed=$((failed + 1)) + + echo "โœ… Signing completed: $counter files processed, $failed failures" + + # Check signing status + echo "Verifying signatures..." + codesign -vvv --deep --strict "$app_path" + + # Check Hardened Runtime and other security settings + echo "Checking security settings (Hardened Runtime, etc.):" + codesign -d --entitlements - "$app_path" | grep -i "runtime\|hardened\|security" + + # Check CrashReportClient specifically (problematic file) + crash_reporter=$(find "$app_path" -path "*CrashReportClient.app/Contents/MacOS/CrashReportClient" -type f | head -1) + if [ -n "$crash_reporter" ]; then + echo "Checking CrashReportClient specifically:" + codesign -d --entitlements - "$crash_reporter" | grep -i "runtime\|hardened\|security" + fi } - - echo "โœ… Signing completed: $counter files processed, $failed failures" - - # Check signing status - echo "Verifying signatures..." - codesign -vvv --deep --strict "$app_path" - - # Check Hardened Runtime and other security settings - echo "Checking security settings (Hardened Runtime, etc.):" - codesign -d --entitlements - "$app_path" | grep -i "runtime\|hardened\|security" - - # Check CrashReportClient specifically (problematic file) - crash_reporter=$(find "$app_path" -path "*CrashReportClient.app/Contents/MacOS/CrashReportClient" -type f | head -1) - if [ -n "$crash_reporter" ]; then - echo "Checking CrashReportClient specifically:" - codesign -d --entitlements - "$crash_reporter" | grep -i "runtime\|hardened\|security" - fi -} -# Check libraries and perform post-processing if needed -echo "" -echo "๐Ÿ” Performing comprehensive signing and hardening of all binaries..." -if [ -n "$APP_PATH" ] && [ -n "$ENTITLEMENTS_FILE" ]; then + # Check libraries and perform post-processing if needed + echo "" + echo "๐Ÿ” Performing comprehensive signing and hardening of all binaries..." + # Sign all binary files recursively sign_recursively "$APP_PATH" "$ENTITLEMENTS_FILE" "$CERTIFICATE_NAME" @@ -280,9 +300,15 @@ if [ -n "$APP_PATH" ] && [ -n "$ENTITLEMENTS_FILE" ]; then echo "xcrun notarytool submit \"$ZIP_PATH\" --apple-id \"YOUR_APPLE_ID\" --password \"APP_SPECIFIC_PASSWORD\" --team-id \"YOUR_TEAM_ID\" --wait" echo "" else - echo "โŒ App path or entitlements file not found, cannot perform comprehensive signing" - echo "App path: $APP_PATH" - echo "Entitlements file: $ENTITLEMENTS_FILE" + # Skip signing locally - CI will handle it + if [ "$RUNNING_IN_CI" = "true" ]; then + echo "Skipping local signing - CI pipeline will handle signing and notarization" + else + echo "โŒ Local signing skipped - certificate or entitlements file not available" + echo "App path: $APP_PATH" + echo "Entitlements file: $ENTITLEMENTS_FILE" + echo "Certificate: $CERTIFICATE_NAME" + fi fi echo "" -- 2.47.2 From 0ca38671641b3e671be54eb489f5a91f4a11ba06 Mon Sep 17 00:00:00 2001 From: Ozgur Ersoy Date: Mon, 14 Apr 2025 21:41:02 +0200 Subject: [PATCH 081/109] fix(actions): simplify notarization script by removing local certificate checks and enhancing error messages --- scripts/mac_build.sh | 189 +------------------------------------------ 1 file changed, 2 insertions(+), 187 deletions(-) diff --git a/scripts/mac_build.sh b/scripts/mac_build.sh index 9f500dc8..8b1ba0c4 100755 --- a/scripts/mac_build.sh +++ b/scripts/mac_build.sh @@ -13,41 +13,9 @@ PROJECT_ROOT="$(pwd)" PROJECT_FILE="$PROJECT_ROOT/LuckyWorld.uproject" ARCHIVE_DIR="$PROJECT_ROOT/Builds" -# Check if running in CI environment -if [ -n "$GITHUB_ACTIONS" ] || [ -n "$CI" ]; then - # Skip certificate check in CI environment - echo "๐Ÿ”„ Running in CI environment, skipping certificate checks" - RUNNING_IN_CI=true -else - RUNNING_IN_CI=false -fi - -# Check for Developer ID certificate -CERTIFICATE_NAME="" -if [ "$RUNNING_IN_CI" = "false" ]; then - # Only check for certificate in non-CI environments - if [ -z "$CERTIFICATE_NAME" ]; then - # Try to find a Developer ID Application certificate - CERTIFICATE_NAME=$(security find-identity -v -p codesigning | grep "Developer ID Application" | head -1 | sed -E 's/.*"(Developer ID Application.*)"$/\1/') - - if [ -z "$CERTIFICATE_NAME" ]; then - echo "โš ๏ธ No Developer ID Application certificate found. Please specify a valid certificate name." - echo "Available certificates:" - security find-identity -v -p codesigning - echo "Continuing build without signing..." - else - echo "๐Ÿ”‘ Found Developer ID certificate: $CERTIFICATE_NAME" - fi - fi -else - echo "๐Ÿ”„ Skipping local certificate check - signing will be handled in CI pipeline" -fi - # Check for entitlements file if [ -f "$PROJECT_ROOT/LuckyWorld.entitlements" ]; then ENTITLEMENTS_FILE="$PROJECT_ROOT/LuckyWorld.entitlements" -elif [ -f "$PROJECT_ROOT/LuckyRobots.entitlements" ]; then - ENTITLEMENTS_FILE="$PROJECT_ROOT/LuckyRobots.entitlements" else echo "Warning: No entitlements file found. This might affect notarization." ENTITLEMENTS_FILE="" @@ -58,11 +26,6 @@ echo "Project root: $PROJECT_ROOT" echo "Project file: $PROJECT_FILE" echo "Archive directory: $ARCHIVE_DIR" echo "Entitlements file: $ENTITLEMENTS_FILE" -if [ "$RUNNING_IN_CI" = "false" ] && [ -n "$CERTIFICATE_NAME" ]; then - echo "Signing with certificate: $CERTIFICATE_NAME" -else - echo "Not signing locally - will be handled in CI" -fi # Clean up previous build artifacts rm -rf DerivedDataCache Intermediate Binaries Saved @@ -148,6 +111,8 @@ if [ -f "$CONFIG_FILE" ]; then echo "BundleIdentifier=com.luckyrobots.luckyworld" >> "$CONFIG_FILE" fi echo "Updated bundle ID in project config" +else + echo "โš ๏ธ Config file not found at $CONFIG_FILE" fi # Post-build process - set bundle ID @@ -163,153 +128,3 @@ if [ -n "$APP_PATH" ]; then echo "โš ๏ธ Info.plist not found at $INFO_PLIST" fi fi - -# Only perform signing if not in CI and certificate is available -if [ "$RUNNING_IN_CI" = "false" ] && [ -n "$CERTIFICATE_NAME" ] && [ -n "$ENTITLEMENTS_FILE" ]; then - # Recursive signing function - signs all binary files - function sign_recursively() { - local app_path="$1" - local entitlements_file="$2" - local certificate="$3" - local counter=0 - local total=0 - local failed=0 - - # First calculate total file count - # Find all binary files (executables, dylibs, .so files, frameworks) - echo "Scanning for binary files..." - - # Executable binary files (libraries, executables) - binaries=$(find "$app_path" -type f \( -name "*.dylib" -o -name "*.so" -o -perm +111 \) | sort) - total=$(echo "$binaries" | wc -l) - - echo "Found $total binary files to sign" - - # Sign helper binary files (in order of preference) - echo "Signing all binary files (libraries and executables)..." - echo "$binaries" | while read -r binary; do - counter=$((counter + 1)) - - # Show progress every 20 files - if [ $((counter % 20)) -eq 0 ] || [ $counter -eq 1 ] || [ $counter -eq $total ]; then - echo "Progress: $counter/$total - Signing: $binary" - fi - - # Skip if not a regular file (symbolic links etc) - if [ ! -f "$binary" ]; then - continue - fi - - # Check file type - file_info=$(file "$binary") - - # Only sign Mach-O files - if ! echo "$file_info" | grep -q "Mach-O"; then - continue - fi - - if [[ "$binary" == *CrashReportClient* ]]; then - echo "๐Ÿ› ๏ธ Special handling for CrashReportClient: $binary" - fi - - # Sign with timestamp and runtime options - codesign --force --options runtime --deep --sign "$certificate" --timestamp --entitlements "$entitlements_file" "$binary" 2>&1 || { - echo "โš ๏ธ Failed to sign: $binary" - failed=$((failed + 1)) - } - done - - # Show ENTITLEMENTS content for reference - echo "Using entitlements file for signatures:" - cat "$entitlements_file" - - # Find all nested apps and sign them - nested_apps=$(find "$app_path" -name "*.app" -type d) - - if [ -n "$nested_apps" ]; then - echo "Signing nested applications..." - echo "$nested_apps" | while read -r nested_app; do - if [ "$nested_app" != "$app_path" ]; then - echo "Signing nested app: $nested_app" - - # Set Bundle ID in Info.plist if it exists before signing - nested_info="$nested_app/Contents/Info.plist" - if [ -f "$nested_info" ]; then - echo "Setting bundle identifier for nested app" - /usr/libexec/PlistBuddy -c "Set :CFBundleIdentifier com.luckyrobots.luckyworld.nested" "$nested_info" 2>/dev/null || true - fi - - codesign --force --options runtime --deep --sign "$certificate" --timestamp --entitlements "$entitlements_file" "$nested_app" 2>&1 || { - echo "โš ๏ธ Failed to sign nested app: $nested_app" - failed=$((failed + 1)) - } - fi - done - fi - - # Sign the main application - echo "Signing main application: $app_path" - codesign --force --options runtime --deep --sign "$certificate" --timestamp --entitlements "$entitlements_file" "$app_path" 2>&1 || { - echo "โš ๏ธ Failed to sign main app: $app_path" - failed=$((failed + 1)) - } - - echo "โœ… Signing completed: $counter files processed, $failed failures" - - # Check signing status - echo "Verifying signatures..." - codesign -vvv --deep --strict "$app_path" - - # Check Hardened Runtime and other security settings - echo "Checking security settings (Hardened Runtime, etc.):" - codesign -d --entitlements - "$app_path" | grep -i "runtime\|hardened\|security" - - # Check CrashReportClient specifically (problematic file) - crash_reporter=$(find "$app_path" -path "*CrashReportClient.app/Contents/MacOS/CrashReportClient" -type f | head -1) - if [ -n "$crash_reporter" ]; then - echo "Checking CrashReportClient specifically:" - codesign -d --entitlements - "$crash_reporter" | grep -i "runtime\|hardened\|security" - fi - } - - # Check libraries and perform post-processing if needed - echo "" - echo "๐Ÿ” Performing comprehensive signing and hardening of all binaries..." - - # Sign all binary files recursively - sign_recursively "$APP_PATH" "$ENTITLEMENTS_FILE" "$CERTIFICATE_NAME" - - # Final signing of the main app bundle - echo "Final signing of main app bundle" - codesign --force --options runtime --deep --sign "$CERTIFICATE_NAME" --timestamp --entitlements "$ENTITLEMENTS_FILE" "$APP_PATH" - - echo "โœ… All binaries signed successfully with Hardened Runtime enabled" - - # Prepare app for notarization - echo "" - echo "๐Ÿ” Preparing for notarization..." - - # Create a ZIP archive for notarization - ZIP_PATH="$ARCHIVE_DIR/LuckyWorld.zip" - echo "Creating ZIP archive for notarization: $ZIP_PATH" - ditto -c -k --keepParent "$APP_PATH" "$ZIP_PATH" - - echo "โœ… ZIP archive created for notarization at: $ZIP_PATH" - echo "" - echo "To notarize the app, run the following command:" - echo "xcrun notarytool submit \"$ZIP_PATH\" --apple-id \"YOUR_APPLE_ID\" --password \"APP_SPECIFIC_PASSWORD\" --team-id \"YOUR_TEAM_ID\" --wait" - echo "" -else - # Skip signing locally - CI will handle it - if [ "$RUNNING_IN_CI" = "true" ]; then - echo "Skipping local signing - CI pipeline will handle signing and notarization" - else - echo "โŒ Local signing skipped - certificate or entitlements file not available" - echo "App path: $APP_PATH" - echo "Entitlements file: $ENTITLEMENTS_FILE" - echo "Certificate: $CERTIFICATE_NAME" - fi -fi - -echo "" -echo "โœ… Build and post-processing completed successfully!" -- 2.47.2 From 64226b067c1d893d3bd8a31eea9fc007574bb5eb Mon Sep 17 00:00:00 2001 From: Ozgur Ersoy Date: Mon, 14 Apr 2025 22:38:41 +0200 Subject: [PATCH 082/109] fix(actions): update macOS build workflow to conditionally name signed artifacts based on notarization status --- .gitea/workflows/test-macos-build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitea/workflows/test-macos-build.yml b/.gitea/workflows/test-macos-build.yml index 2c22adc6..30803244 100644 --- a/.gitea/workflows/test-macos-build.yml +++ b/.gitea/workflows/test-macos-build.yml @@ -198,7 +198,7 @@ jobs: uses: actions/upload-artifact@v3 if: steps.sign-and-notarize.outputs.signed != 'none' with: - name: LuckyWorld-macOS-Signed + name: ${{ steps.sign-and-notarize.outputs.notarized == 'true' && 'LuckyWorld-macOS-Signed-Notarized' || 'LuckyWorld-macOS-Signed' }} path: ${{ steps.sign-and-notarize.outputs.package-path }} retention-days: 30 -- 2.47.2 From 574a17e3572e3297eec345a26b191c50435aea95 Mon Sep 17 00:00:00 2001 From: Ozgur Ersoy Date: Mon, 14 Apr 2025 23:43:42 +0200 Subject: [PATCH 083/109] fix(actions): enhance macOS notarization script with verification steps and DMG package creation --- .gitea/actions/macos-notarize/action.yml | 80 ++++++++++++++++++++++-- .gitea/workflows/test-macos-build.yml | 9 +++ 2 files changed, 83 insertions(+), 6 deletions(-) diff --git a/.gitea/actions/macos-notarize/action.yml b/.gitea/actions/macos-notarize/action.yml index 1f9c1973..7c3a47be 100644 --- a/.gitea/actions/macos-notarize/action.yml +++ b/.gitea/actions/macos-notarize/action.yml @@ -396,11 +396,29 @@ runs: # Staple the notarization ticket echo "Stapling notarization ticket..." - xcrun stapler staple "${{ inputs.app-path }}" + xcrun stapler staple -v "${{ inputs.app-path }}" STAPLE_STATUS=$? if [ $STAPLE_STATUS -eq 0 ]; then echo "โœ… Stapling completed successfully!" + + # Verify the stapling worked properly + echo "Verifying stapled ticket is properly attached..." + xcrun stapler validate -v "${{ inputs.app-path }}" + + # Check if stapling metadata is correctly stored in xattr + echo "Checking app extended attributes..." + if command -v xattr &> /dev/null; then + xattr "${{ inputs.app-path }}" | grep -q "com.apple.provenance" || echo "โš ๏ธ Warning: com.apple.provenance attribute not found" + fi + + # Add special instructions for distribution + echo "๐Ÿ“‹ IMPORTANT DISTRIBUTION NOTE: When users download this app, they may still see Gatekeeper warnings." + echo "This happens because of the 'quarantine' extended attribute that browsers add to downloaded files." + echo "For proper distribution, consider the following options:" + echo "1. Use a DMG installer with a signed, notarized app inside" + echo "2. Add instructions for users on how to open a quarantined app (right-click > Open)" + echo "3. If distributing directly, use a distribution platform that preserves notarization tickets" else echo "โš ๏ธ Stapling completed with status $STAPLE_STATUS (may still be valid)" fi @@ -556,11 +574,29 @@ runs: # Staple the notarization ticket echo "Stapling notarization ticket..." - xcrun stapler staple "${{ inputs.app-path }}" + xcrun stapler staple -v "${{ inputs.app-path }}" STAPLE_STATUS=$? if [ $STAPLE_STATUS -eq 0 ]; then echo "โœ… Stapling completed successfully!" + + # Verify the stapling worked properly + echo "Verifying stapled ticket is properly attached..." + xcrun stapler validate -v "${{ inputs.app-path }}" + + # Check if stapling metadata is correctly stored in xattr + echo "Checking app extended attributes..." + if command -v xattr &> /dev/null; then + xattr "${{ inputs.app-path }}" | grep -q "com.apple.provenance" || echo "โš ๏ธ Warning: com.apple.provenance attribute not found" + fi + + # Add special instructions for distribution + echo "๐Ÿ“‹ IMPORTANT DISTRIBUTION NOTE: When users download this app, they may still see Gatekeeper warnings." + echo "This happens because of the 'quarantine' extended attribute that browsers add to downloaded files." + echo "For proper distribution, consider the following options:" + echo "1. Use a DMG installer with a signed, notarized app inside" + echo "2. Add instructions for users on how to open a quarantined app (right-click > Open)" + echo "3. If distributing directly, use a distribution platform that preserves notarization tickets" else echo "โš ๏ธ Stapling completed with status $STAPLE_STATUS (may still be valid)" fi @@ -626,18 +662,50 @@ runs: APP_NAME=$(basename "${{ inputs.app-path }}" .app) if [ "${{ steps.notarize.outputs.notarized }}" = "true" ]; then - ZIP_FILE="${APP_NAME}-Signed-Notarized.zip" + PACKAGE_SUFFIX="Signed-Notarized" echo "Creating distribution package with notarized app..." else - ZIP_FILE="${APP_NAME}-Signed.zip" + PACKAGE_SUFFIX="Signed" echo "Creating distribution package with signed app..." fi # Create zip package + ZIP_FILE="${APP_NAME}-${PACKAGE_SUFFIX}.zip" ditto -c -k --keepParent "${{ inputs.app-path }}" "$ZIP_FILE" + echo "โœ… Created ZIP package: $ZIP_FILE" - echo "โœ… Created package: $ZIP_FILE" - echo "::set-output name=package-path::$ZIP_FILE" + # Check if we can create DMG (hdiutil is available) + if command -v hdiutil &> /dev/null; then + # Create DMG package (much better for distribution) + DMG_FILE="${APP_NAME}-${PACKAGE_SUFFIX}.dmg" + echo "Creating DMG distribution package..." + + # Create temporary folder for DMG contents + DMG_TMP_DIR=$(mktemp -d) + cp -R "${{ inputs.app-path }}" "$DMG_TMP_DIR/" + + # Optional: Add README or instructions + echo "# Installation Instructions\n\nDrag the application to your Applications folder to install." > "$DMG_TMP_DIR/README.txt" + + # Create DMG file with the app + hdiutil create -volname "${APP_NAME}" -srcfolder "$DMG_TMP_DIR" -ov -format UDZO "$DMG_FILE" + + if [ -f "$DMG_FILE" ]; then + echo "โœ… Created DMG package: $DMG_FILE" + # Use DMG as the primary package if available + echo "::set-output name=package-path::$DMG_FILE" + echo "::set-output name=zip-package-path::$ZIP_FILE" + else + echo "โš ๏ธ Failed to create DMG, falling back to ZIP package" + echo "::set-output name=package-path::$ZIP_FILE" + fi + + # Clean up temp directory + rm -rf "$DMG_TMP_DIR" + else + echo "hdiutil not available, skipping DMG creation" + echo "::set-output name=package-path::$ZIP_FILE" + fi - name: Cleanup if: always() diff --git a/.gitea/workflows/test-macos-build.yml b/.gitea/workflows/test-macos-build.yml index 30803244..dbd4b8ad 100644 --- a/.gitea/workflows/test-macos-build.yml +++ b/.gitea/workflows/test-macos-build.yml @@ -201,6 +201,15 @@ jobs: name: ${{ steps.sign-and-notarize.outputs.notarized == 'true' && 'LuckyWorld-macOS-Signed-Notarized' || 'LuckyWorld-macOS-Signed' }} path: ${{ steps.sign-and-notarize.outputs.package-path }} retention-days: 30 + + # Upload ZIP package if DMG was created (as a backup) + - name: Upload ZIP Package + uses: actions/upload-artifact@v3 + if: steps.sign-and-notarize.outputs.signed != 'none' && steps.sign-and-notarize.outputs.zip-package-path != '' + with: + name: ${{ steps.sign-and-notarize.outputs.notarized == 'true' && 'LuckyWorld-macOS-Signed-Notarized-ZIP' || 'LuckyWorld-macOS-Signed-ZIP' }} + path: ${{ steps.sign-and-notarize.outputs.zip-package-path }} + retention-days: 30 # Report results - name: Report Results -- 2.47.2 From ddb29a8c38f7115785660d0eeb6b0c85e3f7e5bc Mon Sep 17 00:00:00 2001 From: Ozgur Ersoy Date: Tue, 15 Apr 2025 00:00:28 +0200 Subject: [PATCH 084/109] fix(actions): improve macOS build workflow with bundle ID verification and enhanced logging --- .gitea/workflows/test-macos-build.yml | 71 ++++++++++++++++++--------- Config/DefaultGame.ini | 3 ++ scripts/mac_build.sh | 15 ++---- 3 files changed, 57 insertions(+), 32 deletions(-) diff --git a/.gitea/workflows/test-macos-build.yml b/.gitea/workflows/test-macos-build.yml index dbd4b8ad..f35a0d67 100644 --- a/.gitea/workflows/test-macos-build.yml +++ b/.gitea/workflows/test-macos-build.yml @@ -33,29 +33,43 @@ jobs: echo "Environment setup complete" shell: bash - # Set correct bundle identifier before build - - name: Set bundle identifier + # Verify bundle identifier is correctly set + - name: Verify bundle identifier run: | - # Set the correct bundle identifier in DefaultGame.ini if it exists - CONFIG_FILE="Config/DefaultGame.ini" - if [ -f "$CONFIG_FILE" ]; then - # Check if section exists or add it - if grep -q "\[/Script/MacTargetPlatform\.MacTargetSettings\]" "$CONFIG_FILE"; then - # Section exists, update the setting - sed -i '' 's/BundleIdentifier=.*/BundleIdentifier=com.luckyrobots.luckyworld/g' "$CONFIG_FILE" - else - # Section doesn't exist, add it - echo "" >> "$CONFIG_FILE" - echo "[/Script/MacTargetPlatform.MacTargetSettings]" >> "$CONFIG_FILE" - echo "BundleIdentifier=com.luckyrobots.luckyworld" >> "$CONFIG_FILE" - fi - echo "Updated bundle ID in project config" - fi - # Set the constant bundle ID for the workflow echo "BUNDLE_ID=com.luckyrobots.luckyworld" >> "$GITHUB_ENV" + + # Verify the bundle ID is correctly set in DefaultGame.ini + CONFIG_FILE="Config/DefaultGame.ini" + if [ -f "$CONFIG_FILE" ]; then + if grep -q "\[/Script/MacTargetPlatform\.MacTargetSettings\]" "$CONFIG_FILE" && grep -q "BundleIdentifier=com.luckyrobots.luckyworld" "$CONFIG_FILE"; then + echo "โœ… Bundle ID correctly set in DefaultGame.ini" + else + echo "โš ๏ธ Warning: Bundle ID may not be correctly set in DefaultGame.ini" + echo "Please make sure the following section exists:" + echo "[/Script/MacTargetPlatform.MacTargetSettings]" + echo "BundleIdentifier=com.luckyrobots.luckyworld" + fi + else + echo "โš ๏ธ DefaultGame.ini not found!" + fi shell: bash - + + # Check Unreal Engine Project settings + - name: Inspect Unreal Settings + run: | + # Check for any potential issues in UE project settings + if [ -f "Config/DefaultEngine.ini" ]; then + echo "Checking DefaultEngine.ini for settings that might affect bundle ID..." + grep -i "bundle\|identifier\|package" Config/DefaultEngine.ini || echo "No relevant settings found" + fi + + if [ -f "Config/DefaultGame.ini" ]; then + echo "Checking DefaultGame.ini for settings that might affect bundle ID..." + grep -i "bundle\|identifier\|package" Config/DefaultGame.ini || echo "No relevant settings found" + fi + shell: bash + # Build for macOS - use your own build script or create a test app if needed - name: Build for macOS run: | @@ -116,9 +130,18 @@ jobs: # Fix bundle ID in Info.plist before signing if [ -f "$MAIN_APP_PATH/Contents/Info.plist" ]; then - echo "Setting bundle identifier to $BUNDLE_ID" - /usr/libexec/PlistBuddy -c "Set :CFBundleIdentifier $BUNDLE_ID" "$MAIN_APP_PATH/Contents/Info.plist" - echo "Updated bundle ID in Info.plist: $(/usr/libexec/PlistBuddy -c "Print :CFBundleIdentifier" "$MAIN_APP_PATH/Contents/Info.plist")" + echo "Checking current bundle identifier..." + CURRENT_BUNDLE_ID=$(/usr/libexec/PlistBuddy -c "Print :CFBundleIdentifier" "$MAIN_APP_PATH/Contents/Info.plist") + echo "Current bundle ID: $CURRENT_BUNDLE_ID" + + if [ "$CURRENT_BUNDLE_ID" != "$BUNDLE_ID" ]; then + echo "Bundle ID mismatch - fixing it!" + echo "Setting bundle identifier to $BUNDLE_ID" + /usr/libexec/PlistBuddy -c "Set :CFBundleIdentifier $BUNDLE_ID" "$MAIN_APP_PATH/Contents/Info.plist" + echo "Updated bundle ID in Info.plist: $(/usr/libexec/PlistBuddy -c "Print :CFBundleIdentifier" "$MAIN_APP_PATH/Contents/Info.plist")" + else + echo "Bundle ID is already correct: $BUNDLE_ID" + fi else echo "WARNING: Could not find Info.plist in app bundle." fi @@ -133,6 +156,10 @@ jobs: NESTED_BUNDLE_ID="$BUNDLE_ID.$NESTED_NAME" echo "Setting nested bundle ID to $NESTED_BUNDLE_ID for $NESTED_APP" /usr/libexec/PlistBuddy -c "Set :CFBundleIdentifier $NESTED_BUNDLE_ID" "$NESTED_APP/Contents/Info.plist" + + # Verify the change + UPDATED_ID=$(/usr/libexec/PlistBuddy -c "Print :CFBundleIdentifier" "$NESTED_APP/Contents/Info.plist") + echo "Updated nested app bundle ID: $UPDATED_ID" fi done fi diff --git a/Config/DefaultGame.ini b/Config/DefaultGame.ini index 96915495..7cae8a2f 100644 --- a/Config/DefaultGame.ini +++ b/Config/DefaultGame.ini @@ -7,6 +7,9 @@ ProjectVersion=0.1 ;bAddPacks=True ;InsertPack=(PackSource="StarterContent.upack",PackName="StarterContent") +[/Script/MacTargetPlatform.MacTargetSettings] +BundleIdentifier=com.luckyrobots.luckyworld + [/Script/UnrealEd.ProjectPackagingSettings] Build=IfProjectHasCode BuildConfiguration=PPBC_Shipping diff --git a/scripts/mac_build.sh b/scripts/mac_build.sh index 8b1ba0c4..b0a661b1 100755 --- a/scripts/mac_build.sh +++ b/scripts/mac_build.sh @@ -97,20 +97,15 @@ fi # Update bundle ID in project settings echo "" -echo "๐Ÿ”ง Updating bundle ID in UE config..." +echo "๐Ÿ”ง Checking for bundle ID in UE config..." CONFIG_FILE="$PROJECT_ROOT/Config/DefaultGame.ini" if [ -f "$CONFIG_FILE" ]; then - # Check if section exists or add it - if grep -q "\[/Script/MacTargetPlatform\.MacTargetSettings\]" "$CONFIG_FILE"; then - # Section exists, update the setting - sed -i '' 's/BundleIdentifier=.*/BundleIdentifier=com.luckyrobots.luckyworld/g' "$CONFIG_FILE" + if grep -q "\[/Script/MacTargetPlatform\.MacTargetSettings\]" "$CONFIG_FILE" && grep -q "BundleIdentifier=com.luckyrobots.luckyworld" "$CONFIG_FILE"; then + echo "Bundle ID already correctly set in project config โœ…" else - # Section doesn't exist, add it - echo "" >> "$CONFIG_FILE" - echo "[/Script/MacTargetPlatform.MacTargetSettings]" >> "$CONFIG_FILE" - echo "BundleIdentifier=com.luckyrobots.luckyworld" >> "$CONFIG_FILE" + echo "โš ๏ธ Warning: Bundle ID may not be correctly set in DefaultGame.ini" + echo "Please ensure [/Script/MacTargetPlatform.MacTargetSettings] section exists with BundleIdentifier=com.luckyrobots.luckyworld" fi - echo "Updated bundle ID in project config" else echo "โš ๏ธ Config file not found at $CONFIG_FILE" fi -- 2.47.2 From 2b40fb039463d56fb7203359f2f2a0a85114af5c Mon Sep 17 00:00:00 2001 From: Ozgur Ersoy Date: Tue, 15 Apr 2025 00:34:27 +0200 Subject: [PATCH 085/109] fix(actions): add caching for Unreal Engine build artifacts in macOS workflow --- .gitea/workflows/test-macos-build.yml | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/.gitea/workflows/test-macos-build.yml b/.gitea/workflows/test-macos-build.yml index f35a0d67..4ca6fd31 100644 --- a/.gitea/workflows/test-macos-build.yml +++ b/.gitea/workflows/test-macos-build.yml @@ -14,6 +14,19 @@ jobs: with: lfs: true fetch-depth: 0 + + # Cache Unreal Engine build artifacts to speed up builds + - name: Cache UE build artifacts + uses: actions/cache@v3 + with: + path: | + ./Intermediate + ./DerivedDataCache + ./Saved/StagedBuilds + key: ${{ runner.os }}-ue-build-${{ hashFiles('LuckyWorld.uproject') }}-${{ hashFiles('Config/**/*.ini') }} + restore-keys: | + ${{ runner.os }}-ue-build-${{ hashFiles('LuckyWorld.uproject') }}- + ${{ runner.os }}-ue-build- # Setup environment for build - name: Setup environment -- 2.47.2 From 6b128e8cb4cac833bfb54d01b72cad35549f918d Mon Sep 17 00:00:00 2001 From: Ozgur Ersoy Date: Tue, 15 Apr 2025 13:27:23 +0200 Subject: [PATCH 086/109] fix(actions): add macOS specific settings for bundle identifier and display name --- Config/DefaultEngine.ini | 23 +++++++++++++++++++++++ Source/LuckyWorld.Target.cs | 9 +++++++++ Source/LuckyWorld/LuckyWorld.Build.cs | 8 ++++++++ 3 files changed, 40 insertions(+) diff --git a/Config/DefaultEngine.ini b/Config/DefaultEngine.ini index 761b6da7..2861d450 100644 --- a/Config/DefaultEngine.ini +++ b/Config/DefaultEngine.ini @@ -338,3 +338,26 @@ NearClipPlane=0.100000 bFinalUsesRDO=True FinalRDOLambda=100 +[/Script/MacTargetPlatform.MacTargetSettings] +TargetedRHIs=SF_METAL_SM5 +MetalLanguageVersion=5 +MaxShaderLanguageVersion=4 +MinimumOSVersion=11 +BundleName=LuckyWorld +BundleDisplayName=LuckyWorld +bEnableMathOptimizations=True +UseFastIntrinsics=True +EnableMipGenOption=Default +FrameRateLock=PUFRL_None +AudioSampleRate=48000 +AudioMaxChannels=32 +bUseCustomIcon=False +bUseMiniUPnP=False +MetalDynamicLibraries=() +MetalRuntimeLibrary=1 +OutputRealFPS=False +bBuildEmbeddedFrameworksForGame=False +EnableCodeCoverage=False +EnableCodeCoveragePath=(Path="") +ForwardShading=False +UseFastCopyToResolve=True diff --git a/Source/LuckyWorld.Target.cs b/Source/LuckyWorld.Target.cs index 25223105..a7b2ad79 100644 --- a/Source/LuckyWorld.Target.cs +++ b/Source/LuckyWorld.Target.cs @@ -18,5 +18,14 @@ public class LuckyWorldTarget : TargetRules { this.bUseLoggingInShipping = true; } + + // macOS specific settings + if (Target.Platform == UnrealTargetPlatform.Mac) + { + // Force use the bundle ID from DefaultGame.ini + GlobalDefinitions.Add("APP_BUNDLE_IDENTIFIER=com.luckyrobots.luckyworld"); + GlobalDefinitions.Add("APP_BUNDLE_NAME=LuckyWorld"); + GlobalDefinitions.Add("APP_BUNDLE_DISPLAY_NAME=LuckyWorld"); + } } } diff --git a/Source/LuckyWorld/LuckyWorld.Build.cs b/Source/LuckyWorld/LuckyWorld.Build.cs index d6c887a7..b094e6f3 100644 --- a/Source/LuckyWorld/LuckyWorld.Build.cs +++ b/Source/LuckyWorld/LuckyWorld.Build.cs @@ -19,5 +19,13 @@ public class LuckyWorld : ModuleRules // PrivateDependencyModuleNames.Add("OnlineSubsystem"); // To include OnlineSubsystemSteam, add it to the plugins section in your uproject file with the Enabled attribute set to true + + // Set the bundle identifier for macOS builds + if (Target.Platform == UnrealTargetPlatform.Mac) + { + PublicDefinitions.Add("APP_BUNDLE_IDENTIFIER=com.luckyrobots.luckyworld"); + PublicDefinitions.Add("APP_BUNDLE_NAME=LuckyWorld"); + PublicDefinitions.Add("APP_BUNDLE_DISPLAY_NAME=LuckyWorld"); + } } } -- 2.47.2 From 63ca0d48830ec60460bc9ee8b8493087fc42e802 Mon Sep 17 00:00:00 2001 From: Ozgur Ersoy Date: Tue, 15 Apr 2025 14:07:53 +0200 Subject: [PATCH 087/109] fix(actions): improve bundle ID verification process in macOS build workflow --- .gitea/workflows/test-macos-build.yml | 36 ++++++++++++++++++++------- scripts/mac_build.sh | 20 ++++++++++++--- 2 files changed, 43 insertions(+), 13 deletions(-) diff --git a/.gitea/workflows/test-macos-build.yml b/.gitea/workflows/test-macos-build.yml index 4ca6fd31..4376bbb8 100644 --- a/.gitea/workflows/test-macos-build.yml +++ b/.gitea/workflows/test-macos-build.yml @@ -141,6 +141,11 @@ jobs: # Export APP_PATH for next steps to use echo "APP_PATH=$MAIN_APP_PATH" >> "$GITHUB_ENV" + # Note: While bundle ID should be set by Unreal Engine build system based on DefaultGame.ini + # and LuckyWorld.Build.cs settings, we still check and fix if needed as a safety measure, + # since UE builds can sometimes have issues with bundle ID propagation + echo "Checking bundle IDs (fallback fix in case UE didn't properly apply settings)..." + # Fix bundle ID in Info.plist before signing if [ -f "$MAIN_APP_PATH/Contents/Info.plist" ]; then echo "Checking current bundle identifier..." @@ -153,7 +158,7 @@ jobs: /usr/libexec/PlistBuddy -c "Set :CFBundleIdentifier $BUNDLE_ID" "$MAIN_APP_PATH/Contents/Info.plist" echo "Updated bundle ID in Info.plist: $(/usr/libexec/PlistBuddy -c "Print :CFBundleIdentifier" "$MAIN_APP_PATH/Contents/Info.plist")" else - echo "Bundle ID is already correct: $BUNDLE_ID" + echo "โœ… Bundle ID is already correct: $BUNDLE_ID" fi else echo "WARNING: Could not find Info.plist in app bundle." @@ -162,17 +167,23 @@ jobs: # Find and repair nested app bundles as well (like CrashReportClient.app) NESTED_APPS=$(find "$MAIN_APP_PATH" -name "*.app" -type d) if [ -n "$NESTED_APPS" ]; then - echo "Found nested app bundles, fixing their bundle IDs:" + echo "Found nested app bundles, checking their bundle IDs:" echo "$NESTED_APPS" | while read -r NESTED_APP; do if [ -f "$NESTED_APP/Contents/Info.plist" ]; then NESTED_NAME=$(basename "$NESTED_APP" .app) NESTED_BUNDLE_ID="$BUNDLE_ID.$NESTED_NAME" - echo "Setting nested bundle ID to $NESTED_BUNDLE_ID for $NESTED_APP" - /usr/libexec/PlistBuddy -c "Set :CFBundleIdentifier $NESTED_BUNDLE_ID" "$NESTED_APP/Contents/Info.plist" + CURRENT_NESTED_ID=$(/usr/libexec/PlistBuddy -c "Print :CFBundleIdentifier" "$NESTED_APP/Contents/Info.plist") - # Verify the change - UPDATED_ID=$(/usr/libexec/PlistBuddy -c "Print :CFBundleIdentifier" "$NESTED_APP/Contents/Info.plist") - echo "Updated nested app bundle ID: $UPDATED_ID" + if [ "$CURRENT_NESTED_ID" != "$NESTED_BUNDLE_ID" ]; then + echo "Setting nested bundle ID to $NESTED_BUNDLE_ID for $NESTED_APP" + /usr/libexec/PlistBuddy -c "Set :CFBundleIdentifier $NESTED_BUNDLE_ID" "$NESTED_APP/Contents/Info.plist" + + # Verify the change + UPDATED_ID=$(/usr/libexec/PlistBuddy -c "Print :CFBundleIdentifier" "$NESTED_APP/Contents/Info.plist") + echo "Updated nested app bundle ID: $UPDATED_ID" + else + echo "โœ… Nested app $NESTED_NAME already has correct bundle ID: $CURRENT_NESTED_ID" + fi fi done fi @@ -210,8 +221,15 @@ jobs: if [ -f "$CRASH_REPORTER/Contents/Info.plist" ]; then # Ensure it has the correct bundle ID format CRASH_BUNDLE_ID="$BUNDLE_ID.CrashReportClient" - echo "Setting CrashReportClient bundle ID to $CRASH_BUNDLE_ID" - /usr/libexec/PlistBuddy -c "Set :CFBundleIdentifier $CRASH_BUNDLE_ID" "$CRASH_REPORTER/Contents/Info.plist" + CURRENT_CRASH_ID=$(/usr/libexec/PlistBuddy -c "Print :CFBundleIdentifier" "$CRASH_REPORTER/Contents/Info.plist") + + if [ "$CURRENT_CRASH_ID" != "$CRASH_BUNDLE_ID" ]; then + echo "Setting CrashReportClient bundle ID to $CRASH_BUNDLE_ID" + /usr/libexec/PlistBuddy -c "Set :CFBundleIdentifier $CRASH_BUNDLE_ID" "$CRASH_REPORTER/Contents/Info.plist" + echo "Updated CrashReportClient bundle ID: $(/usr/libexec/PlistBuddy -c "Print :CFBundleIdentifier" "$CRASH_REPORTER/Contents/Info.plist")" + else + echo "โœ… CrashReportClient already has correct bundle ID: $CURRENT_CRASH_ID" + fi fi fi shell: bash diff --git a/scripts/mac_build.sh b/scripts/mac_build.sh index b0a661b1..478f3281 100755 --- a/scripts/mac_build.sh +++ b/scripts/mac_build.sh @@ -112,13 +112,25 @@ fi # Post-build process - set bundle ID echo "" -echo "๐Ÿ”ง Performing post-build fix for bundle ID..." +echo "๐Ÿ” Checking bundle ID in built app..." +echo "Note: Bundle ID should be automatically set by Unreal Engine based on DefaultGame.ini and" +echo "LuckyWorld.Build.cs settings, but UE sometimes fails to apply it correctly." +echo "Therefore, we keep this check and fix as a safety measure." + if [ -n "$APP_PATH" ]; then INFO_PLIST="$APP_PATH/Contents/Info.plist" if [ -f "$INFO_PLIST" ]; then - echo "Setting bundle identifier to com.luckyrobots.luckyworld" - /usr/libexec/PlistBuddy -c "Set :CFBundleIdentifier com.luckyrobots.luckyworld" "$INFO_PLIST" - echo "Updated bundle ID: $(/usr/libexec/PlistBuddy -c "Print :CFBundleIdentifier" "$INFO_PLIST")" + CURRENT_BUNDLE_ID=$(/usr/libexec/PlistBuddy -c "Print :CFBundleIdentifier" "$INFO_PLIST") + echo "Current bundle ID: $CURRENT_BUNDLE_ID" + + if [ "$CURRENT_BUNDLE_ID" != "com.luckyrobots.luckyworld" ]; then + echo "Bundle ID mismatch - fixing it!" + echo "Setting bundle identifier to com.luckyrobots.luckyworld" + /usr/libexec/PlistBuddy -c "Set :CFBundleIdentifier com.luckyrobots.luckyworld" "$INFO_PLIST" + echo "Updated bundle ID: $(/usr/libexec/PlistBuddy -c "Print :CFBundleIdentifier" "$INFO_PLIST")" + else + echo "โœ… Bundle ID is already correct: com.luckyrobots.luckyworld" + fi else echo "โš ๏ธ Info.plist not found at $INFO_PLIST" fi -- 2.47.2 From 146dea5121f1c094bc92fce4693778572781c989 Mon Sep 17 00:00:00 2001 From: Ozgur Ersoy Date: Tue, 15 Apr 2025 14:28:10 +0200 Subject: [PATCH 088/109] fix(actions): add error handling and suggestions for build issues in macOS workflow --- .gitea/workflows/test-macos-build.yml | 47 +++++++++++++++++++++++---- Source/LuckyWorld.Target.cs | 1 + scripts/mac_build.sh | 2 ++ 3 files changed, 43 insertions(+), 7 deletions(-) diff --git a/.gitea/workflows/test-macos-build.yml b/.gitea/workflows/test-macos-build.yml index 4376bbb8..dd41e358 100644 --- a/.gitea/workflows/test-macos-build.yml +++ b/.gitea/workflows/test-macos-build.yml @@ -100,24 +100,57 @@ jobs: # Find the app bundle - name: Find app bundle run: | + # Add error handling + set +e # Don't exit immediately on error for this block + + echo "Build status check..." + if [ ! -d "./Builds" ] && [ ! -d "./Saved/StagedBuilds" ]; then + echo "โŒ ERROR: Build directories do not exist. Build likely failed." + echo "Checking build logs for common issues..." + + # Check for the specific GlobalDefinitions error + if grep -q "GlobalDefinitions.*This is not allowed" "$GITHUB_WORKSPACE"/*.log 2>/dev/null || grep -q "BuildEnvironment = TargetBuildEnvironment.Unique" "$GITHUB_WORKSPACE"/*.log 2>/dev/null; then + echo "๐Ÿ” Found issue with GlobalDefinitions in build target." + echo "โš ๏ธ Fix required in LuckyWorld.Target.cs - need to add BuildEnvironment = TargetBuildEnvironment.Unique;" + cat << 'EOF' + +Fix suggestion for LuckyWorld.Target.cs: +Add this line in the constructor: + BuildEnvironment = TargetBuildEnvironment.Unique; + +Example: + public LuckyWorldTarget(TargetInfo Target) : base(Target) + { + Type = TargetType.Game; + DefaultBuildSettings = BuildSettingsVersion.V5; + BuildEnvironment = TargetBuildEnvironment.Unique; // Add this line + + // Rest of your constructor... + } +EOF + fi + + exit 1 + fi + # First check Saved/StagedBuilds directory - where Unreal often places built apps echo "Checking Saved/StagedBuilds directory..." - APP_PATHS=$(find ./Saved/StagedBuilds -type d -name "*.app" 2>/dev/null) + APP_PATHS=$(find ./Saved/StagedBuilds -type d -name "*.app" 2>/dev/null || echo "") # If not found, check Builds directory if [ -z "$APP_PATHS" ]; then - echo "Checking Builds directory..." - APP_PATHS=$(find ./Builds -type d -name "*.app" 2>/dev/null) + echo "No app found in Saved/StagedBuilds, checking Builds directory..." + APP_PATHS=$(find ./Builds -type d -name "*.app" 2>/dev/null || echo "") fi # If still not found, check the whole workspace if [ -z "$APP_PATHS" ]; then - echo "Checking entire workspace..." - APP_PATHS=$(find . -type d -name "*.app" -not -path "*/\.*" 2>/dev/null) + echo "No app found in Builds, checking entire workspace..." + APP_PATHS=$(find . -type d -name "*.app" -not -path "*/\.*" 2>/dev/null || echo "") fi if [ -z "$APP_PATHS" ]; then - echo "ERROR: Could not find any app bundles!" + echo "โŒ ERROR: Could not find any app bundles!" echo "Listing all directories to help debug:" find . -type d -maxdepth 3 | sort exit 1 @@ -134,7 +167,7 @@ jobs: # Make sure app exists - using local variable if [ ! -d "$MAIN_APP_PATH" ]; then - echo "ERROR: App bundle not found at $MAIN_APP_PATH!" + echo "โŒ ERROR: App bundle not found at $MAIN_APP_PATH!" exit 1 fi diff --git a/Source/LuckyWorld.Target.cs b/Source/LuckyWorld.Target.cs index a7b2ad79..233a574d 100644 --- a/Source/LuckyWorld.Target.cs +++ b/Source/LuckyWorld.Target.cs @@ -9,6 +9,7 @@ public class LuckyWorldTarget : TargetRules { Type = TargetType.Game; DefaultBuildSettings = BuildSettingsVersion.V5; + BuildEnvironment = TargetBuildEnvironment.Unique; ExtraModuleNames.AddRange( new string[] { "LuckyWorld" } ); diff --git a/scripts/mac_build.sh b/scripts/mac_build.sh index 478f3281..a7bc439d 100755 --- a/scripts/mac_build.sh +++ b/scripts/mac_build.sh @@ -135,3 +135,5 @@ if [ -n "$APP_PATH" ]; then echo "โš ๏ธ Info.plist not found at $INFO_PLIST" fi fi + +echo "Completed post-build process โœ…" -- 2.47.2 From 51315a772dd9ea6894993d1de94594e940b6ddc9 Mon Sep 17 00:00:00 2001 From: Ozgur Ersoy Date: Tue, 15 Apr 2025 14:47:28 +0200 Subject: [PATCH 089/109] fix(actions): update error handling in macOS build workflow with improved suggestion formatting --- .gitea/workflows/test-macos-build.yml | 29 ++++++++++++--------------- 1 file changed, 13 insertions(+), 16 deletions(-) diff --git a/.gitea/workflows/test-macos-build.yml b/.gitea/workflows/test-macos-build.yml index dd41e358..18b34ee4 100644 --- a/.gitea/workflows/test-macos-build.yml +++ b/.gitea/workflows/test-macos-build.yml @@ -112,22 +112,19 @@ jobs: if grep -q "GlobalDefinitions.*This is not allowed" "$GITHUB_WORKSPACE"/*.log 2>/dev/null || grep -q "BuildEnvironment = TargetBuildEnvironment.Unique" "$GITHUB_WORKSPACE"/*.log 2>/dev/null; then echo "๐Ÿ” Found issue with GlobalDefinitions in build target." echo "โš ๏ธ Fix required in LuckyWorld.Target.cs - need to add BuildEnvironment = TargetBuildEnvironment.Unique;" - cat << 'EOF' - -Fix suggestion for LuckyWorld.Target.cs: -Add this line in the constructor: - BuildEnvironment = TargetBuildEnvironment.Unique; - -Example: - public LuckyWorldTarget(TargetInfo Target) : base(Target) - { - Type = TargetType.Game; - DefaultBuildSettings = BuildSettingsVersion.V5; - BuildEnvironment = TargetBuildEnvironment.Unique; // Add this line - - // Rest of your constructor... - } -EOF + echo "Fix suggestion for LuckyWorld.Target.cs:" + echo "Add this line in the constructor:" + echo " BuildEnvironment = TargetBuildEnvironment.Unique;" + echo "" + echo "Example:" + echo " public LuckyWorldTarget(TargetInfo Target) : base(Target)" + echo " {" + echo " Type = TargetType.Game;" + echo " DefaultBuildSettings = BuildSettingsVersion.V5;" + echo " BuildEnvironment = TargetBuildEnvironment.Unique; // Add this line" + echo " " + echo " // Rest of your constructor..." + echo " }" fi exit 1 -- 2.47.2 From ce5b037cc5c65359e94180241304507c5c753d53 Mon Sep 17 00:00:00 2001 From: Ozgur Ersoy Date: Tue, 15 Apr 2025 15:12:20 +0200 Subject: [PATCH 090/109] fix(actions): update macOS build workflow to correct environment variable handling and improve error suggestions --- .gitea/workflows/test-macos-build.yml | 21 ++++----------------- Source/LuckyWorld.Target.cs | 2 +- 2 files changed, 5 insertions(+), 18 deletions(-) diff --git a/.gitea/workflows/test-macos-build.yml b/.gitea/workflows/test-macos-build.yml index 18b34ee4..7609692a 100644 --- a/.gitea/workflows/test-macos-build.yml +++ b/.gitea/workflows/test-macos-build.yml @@ -14,19 +14,6 @@ jobs: with: lfs: true fetch-depth: 0 - - # Cache Unreal Engine build artifacts to speed up builds - - name: Cache UE build artifacts - uses: actions/cache@v3 - with: - path: | - ./Intermediate - ./DerivedDataCache - ./Saved/StagedBuilds - key: ${{ runner.os }}-ue-build-${{ hashFiles('LuckyWorld.uproject') }}-${{ hashFiles('Config/**/*.ini') }} - restore-keys: | - ${{ runner.os }}-ue-build-${{ hashFiles('LuckyWorld.uproject') }}- - ${{ runner.os }}-ue-build- # Setup environment for build - name: Setup environment @@ -109,19 +96,19 @@ jobs: echo "Checking build logs for common issues..." # Check for the specific GlobalDefinitions error - if grep -q "GlobalDefinitions.*This is not allowed" "$GITHUB_WORKSPACE"/*.log 2>/dev/null || grep -q "BuildEnvironment = TargetBuildEnvironment.Unique" "$GITHUB_WORKSPACE"/*.log 2>/dev/null; then + if grep -q "GlobalDefinitions.*This is not allowed" "$GITHUB_WORKSPACE"/*.log 2>/dev/null || grep -q "BuildEnvironment\|bOverrideBuildEnvironment" "$GITHUB_WORKSPACE"/*.log 2>/dev/null; then echo "๐Ÿ” Found issue with GlobalDefinitions in build target." - echo "โš ๏ธ Fix required in LuckyWorld.Target.cs - need to add BuildEnvironment = TargetBuildEnvironment.Unique;" + echo "โš ๏ธ Fix required in LuckyWorld.Target.cs - need to add bOverrideBuildEnvironment = true;" echo "Fix suggestion for LuckyWorld.Target.cs:" echo "Add this line in the constructor:" - echo " BuildEnvironment = TargetBuildEnvironment.Unique;" + echo " bOverrideBuildEnvironment = true;" echo "" echo "Example:" echo " public LuckyWorldTarget(TargetInfo Target) : base(Target)" echo " {" echo " Type = TargetType.Game;" echo " DefaultBuildSettings = BuildSettingsVersion.V5;" - echo " BuildEnvironment = TargetBuildEnvironment.Unique; // Add this line" + echo " bOverrideBuildEnvironment = true; // Add this line" echo " " echo " // Rest of your constructor..." echo " }" diff --git a/Source/LuckyWorld.Target.cs b/Source/LuckyWorld.Target.cs index 233a574d..459aed18 100644 --- a/Source/LuckyWorld.Target.cs +++ b/Source/LuckyWorld.Target.cs @@ -9,7 +9,7 @@ public class LuckyWorldTarget : TargetRules { Type = TargetType.Game; DefaultBuildSettings = BuildSettingsVersion.V5; - BuildEnvironment = TargetBuildEnvironment.Unique; + bOverrideBuildEnvironment = true; ExtraModuleNames.AddRange( new string[] { "LuckyWorld" } ); -- 2.47.2 From ea9c75143406506dad7830ede6dcf19f96634c23 Mon Sep 17 00:00:00 2001 From: Ozgur Ersoy Date: Tue, 15 Apr 2025 15:14:42 +0200 Subject: [PATCH 091/109] fix(actions): enhance macOS build workflow with additional app existence checks and error messaging --- .gitea/workflows/test-macos-build.yml | 12 ++++++++++++ Source/LuckyWorldEditor.Target.cs | 1 + scripts/mac_build.sh | 10 ++++++++++ 3 files changed, 23 insertions(+) diff --git a/.gitea/workflows/test-macos-build.yml b/.gitea/workflows/test-macos-build.yml index 7609692a..d97ed2e7 100644 --- a/.gitea/workflows/test-macos-build.yml +++ b/.gitea/workflows/test-macos-build.yml @@ -78,6 +78,18 @@ jobs: # Set CI environment variable explicitly before running export CI=true ./scripts/mac_build.sh + + # Check if the build succeeded by looking for the app + APP_PATHS=$(find ./Builds -type d -name "*.app" 2>/dev/null || echo "") + if [ -z "$APP_PATHS" ]; then + APP_PATHS=$(find ./Saved/StagedBuilds -type d -name "*.app" 2>/dev/null || echo "") + fi + + if [ -z "$APP_PATHS" ]; then + echo "โŒ ERROR: Build command appeared to succeed but no app bundle was found!" + echo "This usually means the build failed but didn't properly return an error code." + exit 1 + fi else echo "ERROR: Build script not found at ./scripts/mac_build.sh" exit 1 diff --git a/Source/LuckyWorldEditor.Target.cs b/Source/LuckyWorldEditor.Target.cs index a698b47d..db543322 100644 --- a/Source/LuckyWorldEditor.Target.cs +++ b/Source/LuckyWorldEditor.Target.cs @@ -9,6 +9,7 @@ public class LuckyWorldEditorTarget : TargetRules { Type = TargetType.Editor; DefaultBuildSettings = BuildSettingsVersion.V5; + bOverrideBuildEnvironment = true; ExtraModuleNames.AddRange( new string[] { "LuckyWorld" } ); diff --git a/scripts/mac_build.sh b/scripts/mac_build.sh index a7bc439d..ee52fc1f 100755 --- a/scripts/mac_build.sh +++ b/scripts/mac_build.sh @@ -76,6 +76,16 @@ echo "๐Ÿฆพ Build completed. Application path:" APP_PATH=$(find "$ARCHIVE_DIR" -name "*.app" -type d | head -n 1) echo "$APP_PATH" +# Check if the build actually succeeded by verifying the app exists +if [ -z "$APP_PATH" ] || [ ! -d "$APP_PATH" ]; then + echo "โŒ ERROR: Build failed or did not produce an app bundle!" + echo "Check the logs above for build errors." + echo "Common issues:" + echo " - 'Targets with a unique build environment cannot be built with an installed engine'" + echo " Fix: Use bOverrideBuildEnvironment = true instead of BuildEnvironment = TargetBuildEnvironment.Unique" + exit 1 +fi + if [ -n "$APP_PATH" ]; then echo "" echo "๐Ÿ” Binary files that will need signing:" -- 2.47.2 From 6a7cc7c73892e105b585723face2a56d7a26e382 Mon Sep 17 00:00:00 2001 From: Ozgur Ersoy Date: Tue, 15 Apr 2025 16:37:15 +0200 Subject: [PATCH 092/109] fix(actions): enhance macOS build workflow with additional verification and stapling steps for app notarization --- .gitea/workflows/test-macos-build.yml | 31 ++++++++++++++++ scripts/mac_build.sh | 51 ++++++++++++++++++++++++++- 2 files changed, 81 insertions(+), 1 deletion(-) diff --git a/.gitea/workflows/test-macos-build.yml b/.gitea/workflows/test-macos-build.yml index d97ed2e7..e8f83010 100644 --- a/.gitea/workflows/test-macos-build.yml +++ b/.gitea/workflows/test-macos-build.yml @@ -289,6 +289,37 @@ jobs: path: ${{ steps.sign-and-notarize.outputs.package-path }} retention-days: 30 + # Additional verification and stapling to ensure the app opens without warning + - name: Verify and Staple App + if: steps.sign-and-notarize.outputs.notarized == 'true' && steps.sign-and-notarize.outputs.signed != 'none' + run: | + echo "๐Ÿ”’ Performing additional verification and stapling..." + APP_PATH="${{ env.APP_PATH }}" + + # Make sure the app is properly stapled + echo "Stapling notarization ticket to the app..." + xcrun stapler staple "$APP_PATH" + + # Verify the stapling + echo "Verifying stapling..." + xcrun stapler validate "$APP_PATH" + + # Perform deep verification of code signing + echo "Verifying code signature (deep)..." + codesign -vvv --deep "$APP_PATH" + + # Additional check for quarantine attributes + echo "Checking for quarantine attributes..." + if [ -n "$(xattr -l "$APP_PATH" | grep quarantine)" ]; then + echo "Removing quarantine attribute..." + xattr -d com.apple.quarantine "$APP_PATH" + else + echo "No quarantine attribute found, good!" + fi + + echo "โœ… Verification and stapling completed!" + shell: bash + # Upload ZIP package if DMG was created (as a backup) - name: Upload ZIP Package uses: actions/upload-artifact@v3 diff --git a/scripts/mac_build.sh b/scripts/mac_build.sh index ee52fc1f..b2b7051d 100755 --- a/scripts/mac_build.sh +++ b/scripts/mac_build.sh @@ -146,4 +146,53 @@ if [ -n "$APP_PATH" ]; then fi fi -echo "Completed post-build process โœ…" +# If this is a manual build (not in CI), attempt to sign the app locally +if [ -z "$CI" ] && [ -n "$APP_PATH" ]; then + echo "" + echo "๐Ÿ” Attempting local code signing and stapling..." + + # Check if we have a valid Apple Developer identity + IDENTITY=$(security find-identity -v -p codesigning | grep "Developer ID Application" | head -1 | sed -E 's/.*\) ([A-F0-9]+) "(.*)"/\2/') + + if [ -n "$IDENTITY" ]; then + echo "Found signing identity: $IDENTITY" + + # Sign the app + echo "Signing application..." + if [ -f "$PROJECT_ROOT/LuckyWorld.entitlements" ]; then + echo "Using entitlements file: $PROJECT_ROOT/LuckyWorld.entitlements" + codesign --force --options runtime --entitlements "$PROJECT_ROOT/LuckyWorld.entitlements" --sign "$IDENTITY" --deep "$APP_PATH" + else + codesign --force --options runtime --sign "$IDENTITY" --deep "$APP_PATH" + fi + + # Verify signature + echo "Verifying signature..." + codesign -vvv --deep "$APP_PATH" + + # Staple the app if notarization is successful + echo "Checking if notarization is needed..." + if xcrun altool --notarization-info $(uuidgen) -u "YOUR_APPLE_ID" 2>&1 | grep -q "success"; then + echo "App is notarized, stapling the ticket..." + xcrun stapler staple "$APP_PATH" + xcrun stapler validate "$APP_PATH" + + # Remove quarantine attribute if present + if [ -n "$(xattr -l "$APP_PATH" | grep quarantine)" ]; then + echo "Removing quarantine attribute..." + xattr -d com.apple.quarantine "$APP_PATH" + fi + else + echo "App is not notarized yet. Upload to Apple's notary service for full verification." + fi + else + echo "โš ๏ธ No Developer ID Application certificate found for signing." + echo "Run 'security find-identity -v -p codesigning' to view available certificates." + fi +else + echo "Skipping local signing (running in CI or app not found)" +fi + +echo "" +echo "โœ… Build and post-processing completed!" +echo "App location: $APP_PATH" -- 2.47.2 From 2e0a1b8b600a06dff961a5a351b366bc3d37e2bc Mon Sep 17 00:00:00 2001 From: Ozgur Ersoy Date: Tue, 15 Apr 2025 17:06:43 +0200 Subject: [PATCH 093/109] fix(actions): add nested app bundle ID verification and update process in macOS build workflow --- .gitea/workflows/test-macos-build.yml | 2 +- scripts/mac_build.sh | 21 +++++++++++++++++++++ 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/.gitea/workflows/test-macos-build.yml b/.gitea/workflows/test-macos-build.yml index e8f83010..1930706d 100644 --- a/.gitea/workflows/test-macos-build.yml +++ b/.gitea/workflows/test-macos-build.yml @@ -194,7 +194,7 @@ jobs: fi # Find and repair nested app bundles as well (like CrashReportClient.app) - NESTED_APPS=$(find "$MAIN_APP_PATH" -name "*.app" -type d) + NESTED_APPS=$(find "$MAIN_APP_PATH" -name "*.app" -type d | grep -v "^$MAIN_APP_PATH$") if [ -n "$NESTED_APPS" ]; then echo "Found nested app bundles, checking their bundle IDs:" echo "$NESTED_APPS" | while read -r NESTED_APP; do diff --git a/scripts/mac_build.sh b/scripts/mac_build.sh index b2b7051d..10b45411 100755 --- a/scripts/mac_build.sh +++ b/scripts/mac_build.sh @@ -193,6 +193,27 @@ else echo "Skipping local signing (running in CI or app not found)" fi +# Find and check nested app bundles (like CrashReportClient.app) +NESTED_APPS=$(find "$APP_PATH" -name "*.app" -type d | grep -v "^$APP_PATH$") +if [ -n "$NESTED_APPS" ]; then + echo "Checking nested app bundles:" + echo "$NESTED_APPS" | while read -r NESTED_APP; do + if [ -f "$NESTED_APP/Contents/Info.plist" ]; then + NESTED_NAME=$(basename "$NESTED_APP" .app) + NESTED_BUNDLE_ID="com.luckyrobots.luckyworld.$NESTED_NAME" + CURRENT_NESTED_ID=$(/usr/libexec/PlistBuddy -c "Print :CFBundleIdentifier" "$NESTED_APP/Contents/Info.plist") + + if [ "$CURRENT_NESTED_ID" != "$NESTED_BUNDLE_ID" ]; then + echo "Setting nested bundle ID to $NESTED_BUNDLE_ID for $NESTED_APP" + /usr/libexec/PlistBuddy -c "Set :CFBundleIdentifier $NESTED_BUNDLE_ID" "$NESTED_APP/Contents/Info.plist" + echo "Updated nested app bundle ID: $(/usr/libexec/PlistBuddy -c "Print :CFBundleIdentifier" "$NESTED_APP/Contents/Info.plist")" + else + echo "Nested app bundle ID already correct: $CURRENT_NESTED_ID" + fi + fi + done +fi + echo "" echo "โœ… Build and post-processing completed!" echo "App location: $APP_PATH" -- 2.47.2 From cb44ddadabf1165454aa198cbbd084ffe8e47e21 Mon Sep 17 00:00:00 2001 From: Ozgur Ersoy Date: Tue, 15 Apr 2025 18:07:29 +0200 Subject: [PATCH 094/109] fix(actions): enhance macOS build workflow by adding steps for creating and uploading stapled app archives and DMG files --- .gitea/workflows/test-macos-build.yml | 85 ++++++++++++++++++++++++--- 1 file changed, 76 insertions(+), 9 deletions(-) diff --git a/.gitea/workflows/test-macos-build.yml b/.gitea/workflows/test-macos-build.yml index 1930706d..80d38f9b 100644 --- a/.gitea/workflows/test-macos-build.yml +++ b/.gitea/workflows/test-macos-build.yml @@ -280,15 +280,6 @@ jobs: bundle-id: ${{ env.BUNDLE_ID }} fallback-to-adhoc: 'false' - # Upload signed app if available - - name: Upload Signed App - uses: actions/upload-artifact@v3 - if: steps.sign-and-notarize.outputs.signed != 'none' - with: - name: ${{ steps.sign-and-notarize.outputs.notarized == 'true' && 'LuckyWorld-macOS-Signed-Notarized' || 'LuckyWorld-macOS-Signed' }} - path: ${{ steps.sign-and-notarize.outputs.package-path }} - retention-days: 30 - # Additional verification and stapling to ensure the app opens without warning - name: Verify and Staple App if: steps.sign-and-notarize.outputs.notarized == 'true' && steps.sign-and-notarize.outputs.signed != 'none' @@ -318,8 +309,84 @@ jobs: fi echo "โœ… Verification and stapling completed!" + + # Export STAPLED_APP_PATH for later use + echo "STAPLED_APP_PATH=$APP_PATH" >> "$GITHUB_ENV" + shell: bash + + # Create a properly archived ZIP of the stapled app (preserves stapling) + - name: Create Stapled App Archive (ZIP) + if: steps.sign-and-notarize.outputs.notarized == 'true' && steps.sign-and-notarize.outputs.signed != 'none' + run: | + STAPLED_APP_PATH="${{ env.STAPLED_APP_PATH }}" + APP_NAME=$(basename "$STAPLED_APP_PATH" .app) + ARCHIVE_DIR="./ArchivedApps" + mkdir -p "$ARCHIVE_DIR" + + # Create the ZIP archive (preserving all metadata) + echo "Creating ZIP archive of stapled app..." + cd "$(dirname "$STAPLED_APP_PATH")" + # Use ditto to preserve all metadata and permissions + ditto -c -k --keepParent "$(basename "$STAPLED_APP_PATH")" "$GITHUB_WORKSPACE/$ARCHIVE_DIR/$APP_NAME.zip" + cd "$GITHUB_WORKSPACE" + + echo "ZIP archive created at: $ARCHIVE_DIR/$APP_NAME.zip" + echo "STAPLED_APP_ZIP=$ARCHIVE_DIR/$APP_NAME.zip" >> "$GITHUB_ENV" + shell: bash + + # Create a DMG file (macOS disk image) for easy distribution + - name: Create DMG for Distribution + if: steps.sign-and-notarize.outputs.notarized == 'true' && steps.sign-and-notarize.outputs.signed != 'none' + run: | + STAPLED_APP_PATH="${{ env.STAPLED_APP_PATH }}" + APP_NAME=$(basename "$STAPLED_APP_PATH" .app) + ARCHIVE_DIR="./ArchivedApps" + DMG_FILE="$ARCHIVE_DIR/$APP_NAME.dmg" + + # Create a DMG file + echo "Creating DMG file..." + hdiutil create -volname "$APP_NAME" -srcfolder "$STAPLED_APP_PATH" -ov -format UDZO "$DMG_FILE" + + echo "DMG file created at: $DMG_FILE" + echo "STAPLED_APP_DMG=$DMG_FILE" >> "$GITHUB_ENV" shell: bash + # Upload stapled app directly (this is the most reliable approach) + - name: Upload Stapled App Bundle + uses: actions/upload-artifact@v3 + if: steps.sign-and-notarize.outputs.notarized == 'true' && steps.sign-and-notarize.outputs.signed != 'none' + with: + name: LuckyWorld-macOS-Stapled-App-Bundle + path: ${{ env.STAPLED_APP_PATH }} + retention-days: 30 + + # Upload the ZIP archive (proper archiving that preserves stapling) + - name: Upload Stapled App ZIP Archive + uses: actions/upload-artifact@v3 + if: steps.sign-and-notarize.outputs.notarized == 'true' && steps.sign-and-notarize.outputs.signed != 'none' + with: + name: LuckyWorld-macOS-Stapled-ZIP + path: ${{ env.STAPLED_APP_ZIP }} + retention-days: 30 + + # Upload the DMG file + - name: Upload Stapled App DMG + uses: actions/upload-artifact@v3 + if: steps.sign-and-notarize.outputs.notarized == 'true' && steps.sign-and-notarize.outputs.signed != 'none' + with: + name: LuckyWorld-macOS-Stapled-DMG + path: ${{ env.STAPLED_APP_DMG }} + retention-days: 30 + + # Upload signed app (might be DMG or other package format) + - name: Upload Signed App Package + uses: actions/upload-artifact@v3 + if: steps.sign-and-notarize.outputs.signed != 'none' + with: + name: ${{ steps.sign-and-notarize.outputs.notarized == 'true' && 'LuckyWorld-macOS-Signed-Notarized-Package' || 'LuckyWorld-macOS-Signed-Package' }} + path: ${{ steps.sign-and-notarize.outputs.package-path }} + retention-days: 30 + # Upload ZIP package if DMG was created (as a backup) - name: Upload ZIP Package uses: actions/upload-artifact@v3 -- 2.47.2 From 71e5075d4240cd071affff2d481d216a14ec26e7 Mon Sep 17 00:00:00 2001 From: Ozgur Ersoy Date: Tue, 15 Apr 2025 20:01:45 +0200 Subject: [PATCH 095/109] fix(actions): enhance macOS build workflow by adding DMG signing and notarization steps --- .gitea/workflows/test-macos-build.yml | 65 +++++++++++++++++++++++++++ 1 file changed, 65 insertions(+) diff --git a/.gitea/workflows/test-macos-build.yml b/.gitea/workflows/test-macos-build.yml index 80d38f9b..d1e86531 100644 --- a/.gitea/workflows/test-macos-build.yml +++ b/.gitea/workflows/test-macos-build.yml @@ -347,6 +347,71 @@ jobs: echo "Creating DMG file..." hdiutil create -volname "$APP_NAME" -srcfolder "$STAPLED_APP_PATH" -ov -format UDZO "$DMG_FILE" + # Sign the DMG with the same certificate + echo "Signing DMG file..." + # Extract certificate info from the previously signed app + CERT_IDENTITY=$(codesign -dvv "$STAPLED_APP_PATH" 2>&1 | grep "Authority" | head -1 | sed -e 's/.*Authority=//g') + echo "Using certificate identity: $CERT_IDENTITY" + + # Sign the DMG + codesign --sign "$CERT_IDENTITY" --options runtime --timestamp "$DMG_FILE" + + # Verify DMG signature + echo "Verifying DMG signature..." + codesign -vvv "$DMG_FILE" + + # Notarize the DMG + echo "Notarizing DMG file..." + # Select which authentication method to use for notarization + if [ -n "${{ secrets.NOTARY_API_KEY_ID }}" ] && [ -n "${{ secrets.NOTARY_API_KEY_ISSUER_ID }}" ]; then + # Use API Key authentication (preferred) + echo "Using Notary API Key authentication..." + UUID=$(xcrun notarytool submit "$DMG_FILE" \ + --key "${{ secrets.NOTARY_API_KEY_PATH }}" \ + --key-id "${{ secrets.NOTARY_API_KEY_ID }}" \ + --issuer "${{ secrets.NOTARY_API_KEY_ISSUER_ID }}" \ + --wait | grep "id:" | awk '{print $2}') + elif [ -n "${{ secrets.APPLE_ID }}" ] && [ -n "${{ secrets.APPLE_TEAM_ID }}" ]; then + # Use Apple ID authentication + echo "Using Apple ID authentication..." + UUID=$(xcrun notarytool submit "$DMG_FILE" \ + --apple-id "${{ secrets.APPLE_ID }}" \ + --password "${{ secrets.APPLE_APP_SPECIFIC_PASSWORD }}" \ + --team-id "${{ secrets.APPLE_TEAM_ID }}" \ + --wait | grep "id:" | awk '{print $2}') + else + echo "โš ๏ธ No notarization credentials available. DMG will not be notarized." + UUID="" + fi + + echo "Notarization UUID: $UUID" + + # Check notarization status + if [ -n "$UUID" ]; then + # Use the same authentication method for UUID info + if [ -n "${{ secrets.NOTARY_API_KEY_ID }}" ] && [ -n "${{ secrets.NOTARY_API_KEY_ISSUER_ID }}" ]; then + xcrun notarytool info "$UUID" \ + --key "${{ secrets.NOTARY_API_KEY_PATH }}" \ + --key-id "${{ secrets.NOTARY_API_KEY_ID }}" \ + --issuer "${{ secrets.NOTARY_API_KEY_ISSUER_ID }}" + elif [ -n "${{ secrets.APPLE_ID }}" ] && [ -n "${{ secrets.APPLE_TEAM_ID }}" ]; then + xcrun notarytool info "$UUID" \ + --apple-id "${{ secrets.APPLE_ID }}" \ + --password "${{ secrets.APPLE_APP_SPECIFIC_PASSWORD }}" \ + --team-id "${{ secrets.APPLE_TEAM_ID }}" + fi + + # Staple the DMG + echo "Stapling notarization ticket to DMG..." + xcrun stapler staple "$DMG_FILE" + + # Verify stapling + echo "Verifying DMG stapling..." + xcrun stapler validate "$DMG_FILE" + else + echo "โš ๏ธ Notarization UUID not found. DMG may not be properly notarized." + fi + echo "DMG file created at: $DMG_FILE" echo "STAPLED_APP_DMG=$DMG_FILE" >> "$GITHUB_ENV" shell: bash -- 2.47.2 From 659b5de3eac7de5d7a6b6708165ba625c83c02af Mon Sep 17 00:00:00 2001 From: Ozgur Ersoy Date: Tue, 15 Apr 2025 20:31:04 +0200 Subject: [PATCH 096/109] fix(actions): streamline macOS build workflow by integrating DMG signing and notarization directly into the macos-notarize action --- .gitea/actions/macos-notarize/action.yml | 107 +++++++++++++++++++++ .gitea/workflows/test-macos-build.yml | 116 +++++------------------ 2 files changed, 130 insertions(+), 93 deletions(-) diff --git a/.gitea/actions/macos-notarize/action.yml b/.gitea/actions/macos-notarize/action.yml index 7c3a47be..062da8cf 100644 --- a/.gitea/actions/macos-notarize/action.yml +++ b/.gitea/actions/macos-notarize/action.yml @@ -692,6 +692,113 @@ runs: if [ -f "$DMG_FILE" ]; then echo "โœ… Created DMG package: $DMG_FILE" + + # Sign the DMG with the same certificate used for the app + echo "Signing DMG file..." + + # Decide which keychain to use + if [ "${{ steps.setup-cert.outputs.use_system_cert }}" = "true" ]; then + echo "Using system keychain identity" + # Get certificate hash instead of name to avoid ambiguity + IDENTITY_HASH=$(security find-identity -v -p codesigning | grep "Developer ID Application" | head -1 | awk '{print $2}') + echo "Using certificate hash: $IDENTITY_HASH" + else + # Make sure keychain is unlocked + security unlock-keychain -p "$KEYCHAIN_PASSWORD" "$KEYCHAIN_PATH" + echo "Using custom keychain identity" + # Get certificate hash instead of name to avoid ambiguity + IDENTITY_HASH=$(security find-identity -v -p codesigning "$KEYCHAIN_PATH" | grep "Developer ID Application" | head -1 | awk '{print $2}') + echo "Using certificate hash: $IDENTITY_HASH" + fi + + if [ -n "$IDENTITY_HASH" ]; then + # Sign the DMG + codesign --force --sign "$IDENTITY_HASH" --options runtime --timestamp "$DMG_FILE" + + # Verify DMG signature + echo "Verifying DMG signature..." + codesign -vvv "$DMG_FILE" + + # Only notarize DMG if the app was successfully notarized + if [ "${{ steps.notarize.outputs.notarized }}" = "true" ]; then + echo "Notarizing DMG file..." + + # Check if we're using API key notarization method + if [ "${{ inputs.notarization-method }}" = "api-key" ] && [ -n "$API_KEY_ID" ] && [ -n "$API_ISSUER_ID" ] && [ -n "$API_KEY_PATH" ]; then + # Use the same API key setup from the notarize step + echo "Using App Store Connect API key for DMG notarization..." + + echo "Submitting DMG for notarization..." + DMG_SUBMIT_OUTPUT=$(xcrun notarytool submit "$DMG_FILE" \ + --key ~/private_keys/AuthKey_${API_KEY_ID}.p8 \ + --key-id "$API_KEY_ID" \ + --issuer "$API_ISSUER_ID" --wait 2>&1) + + echo "DMG notarization submission output:" + echo "$DMG_SUBMIT_OUTPUT" + + # Extract DMG submission ID + DMG_SUBMISSION_ID=$(echo "$DMG_SUBMIT_OUTPUT" | grep -o "id: [a-f0-9\-]*" | head -1 | cut -d ' ' -f 2) + + if [ -n "$DMG_SUBMISSION_ID" ] && echo "$DMG_SUBMIT_OUTPUT" | grep -q "status: Accepted"; then + echo "โœ… DMG notarization completed successfully!" + + # Staple the DMG + echo "Stapling notarization ticket to DMG..." + xcrun stapler staple "$DMG_FILE" + + # Verify DMG stapling + echo "Verifying DMG stapling..." + xcrun stapler validate "$DMG_FILE" + + echo "DMG is now fully signed, notarized, and stapled!" + else + echo "โš ๏ธ DMG notarization may have failed or is still in progress." + echo "The app itself is still properly notarized, but the DMG may need manual verification." + fi + elif [ "${{ inputs.notarization-method }}" = "app-password" ] && [ -n "$APPLE_ID" ] && [ -n "$APP_PASSWORD" ] && [ -n "$APPLE_TEAM_ID" ]; then + # Use App-specific password for DMG notarization + echo "Using App-specific password for DMG notarization..." + + echo "Submitting DMG for notarization..." + DMG_SUBMIT_OUTPUT=$(xcrun notarytool submit "$DMG_FILE" \ + --apple-id "$APPLE_ID" \ + --password "$APP_PASSWORD" \ + --team-id "$APPLE_TEAM_ID" --wait 2>&1) + + echo "DMG notarization submission output:" + echo "$DMG_SUBMIT_OUTPUT" + + # Extract DMG submission ID + DMG_SUBMISSION_ID=$(echo "$DMG_SUBMIT_OUTPUT" | grep -o "id: [a-f0-9\-]*" | head -1 | cut -d ' ' -f 2) + + if [ -n "$DMG_SUBMISSION_ID" ] && echo "$DMG_SUBMIT_OUTPUT" | grep -q "status: Accepted"; then + echo "โœ… DMG notarization completed successfully!" + + # Staple the DMG + echo "Stapling notarization ticket to DMG..." + xcrun stapler staple "$DMG_FILE" + + # Verify DMG stapling + echo "Verifying DMG stapling..." + xcrun stapler validate "$DMG_FILE" + + echo "DMG is now fully signed, notarized, and stapled!" + else + echo "โš ๏ธ DMG notarization may have failed or is still in progress." + echo "The app itself is still properly notarized, but the DMG may need manual verification." + fi + else + echo "โš ๏ธ DMG not notarized due to missing credentials." + echo "The app itself is properly notarized, but the DMG is only signed." + fi + else + echo "App was not notarized, skipping DMG notarization." + fi + else + echo "โš ๏ธ No valid identity found for DMG signing. DMG will be created but not signed." + fi + # Use DMG as the primary package if available echo "::set-output name=package-path::$DMG_FILE" echo "::set-output name=zip-package-path::$ZIP_FILE" diff --git a/.gitea/workflows/test-macos-build.yml b/.gitea/workflows/test-macos-build.yml index d1e86531..826c285d 100644 --- a/.gitea/workflows/test-macos-build.yml +++ b/.gitea/workflows/test-macos-build.yml @@ -314,26 +314,6 @@ jobs: echo "STAPLED_APP_PATH=$APP_PATH" >> "$GITHUB_ENV" shell: bash - # Create a properly archived ZIP of the stapled app (preserves stapling) - - name: Create Stapled App Archive (ZIP) - if: steps.sign-and-notarize.outputs.notarized == 'true' && steps.sign-and-notarize.outputs.signed != 'none' - run: | - STAPLED_APP_PATH="${{ env.STAPLED_APP_PATH }}" - APP_NAME=$(basename "$STAPLED_APP_PATH" .app) - ARCHIVE_DIR="./ArchivedApps" - mkdir -p "$ARCHIVE_DIR" - - # Create the ZIP archive (preserving all metadata) - echo "Creating ZIP archive of stapled app..." - cd "$(dirname "$STAPLED_APP_PATH")" - # Use ditto to preserve all metadata and permissions - ditto -c -k --keepParent "$(basename "$STAPLED_APP_PATH")" "$GITHUB_WORKSPACE/$ARCHIVE_DIR/$APP_NAME.zip" - cd "$GITHUB_WORKSPACE" - - echo "ZIP archive created at: $ARCHIVE_DIR/$APP_NAME.zip" - echo "STAPLED_APP_ZIP=$ARCHIVE_DIR/$APP_NAME.zip" >> "$GITHUB_ENV" - shell: bash - # Create a DMG file (macOS disk image) for easy distribution - name: Create DMG for Distribution if: steps.sign-and-notarize.outputs.notarized == 'true' && steps.sign-and-notarize.outputs.signed != 'none' @@ -343,77 +323,17 @@ jobs: ARCHIVE_DIR="./ArchivedApps" DMG_FILE="$ARCHIVE_DIR/$APP_NAME.dmg" - # Create a DMG file - echo "Creating DMG file..." - hdiutil create -volname "$APP_NAME" -srcfolder "$STAPLED_APP_PATH" -ov -format UDZO "$DMG_FILE" + # Note: The actual DMG creation, signing, notarization and stapling + # are now handled by the macos-notarize action - # Sign the DMG with the same certificate - echo "Signing DMG file..." - # Extract certificate info from the previously signed app - CERT_IDENTITY=$(codesign -dvv "$STAPLED_APP_PATH" 2>&1 | grep "Authority" | head -1 | sed -e 's/.*Authority=//g') - echo "Using certificate identity: $CERT_IDENTITY" - - # Sign the DMG - codesign --sign "$CERT_IDENTITY" --options runtime --timestamp "$DMG_FILE" - - # Verify DMG signature - echo "Verifying DMG signature..." - codesign -vvv "$DMG_FILE" - - # Notarize the DMG - echo "Notarizing DMG file..." - # Select which authentication method to use for notarization - if [ -n "${{ secrets.NOTARY_API_KEY_ID }}" ] && [ -n "${{ secrets.NOTARY_API_KEY_ISSUER_ID }}" ]; then - # Use API Key authentication (preferred) - echo "Using Notary API Key authentication..." - UUID=$(xcrun notarytool submit "$DMG_FILE" \ - --key "${{ secrets.NOTARY_API_KEY_PATH }}" \ - --key-id "${{ secrets.NOTARY_API_KEY_ID }}" \ - --issuer "${{ secrets.NOTARY_API_KEY_ISSUER_ID }}" \ - --wait | grep "id:" | awk '{print $2}') - elif [ -n "${{ secrets.APPLE_ID }}" ] && [ -n "${{ secrets.APPLE_TEAM_ID }}" ]; then - # Use Apple ID authentication - echo "Using Apple ID authentication..." - UUID=$(xcrun notarytool submit "$DMG_FILE" \ - --apple-id "${{ secrets.APPLE_ID }}" \ - --password "${{ secrets.APPLE_APP_SPECIFIC_PASSWORD }}" \ - --team-id "${{ secrets.APPLE_TEAM_ID }}" \ - --wait | grep "id:" | awk '{print $2}') + # Just ensure we have the correct path for outputs + if [ -f "${{ steps.sign-and-notarize.outputs.package-path }}" ]; then + echo "Using DMG created by the macos-notarize action" + echo "DMG file location: ${{ steps.sign-and-notarize.outputs.package-path }}" + echo "STAPLED_APP_DMG=${{ steps.sign-and-notarize.outputs.package-path }}" >> "$GITHUB_ENV" else - echo "โš ๏ธ No notarization credentials available. DMG will not be notarized." - UUID="" + echo "โš ๏ธ DMG not found from the macos-notarize action output" fi - - echo "Notarization UUID: $UUID" - - # Check notarization status - if [ -n "$UUID" ]; then - # Use the same authentication method for UUID info - if [ -n "${{ secrets.NOTARY_API_KEY_ID }}" ] && [ -n "${{ secrets.NOTARY_API_KEY_ISSUER_ID }}" ]; then - xcrun notarytool info "$UUID" \ - --key "${{ secrets.NOTARY_API_KEY_PATH }}" \ - --key-id "${{ secrets.NOTARY_API_KEY_ID }}" \ - --issuer "${{ secrets.NOTARY_API_KEY_ISSUER_ID }}" - elif [ -n "${{ secrets.APPLE_ID }}" ] && [ -n "${{ secrets.APPLE_TEAM_ID }}" ]; then - xcrun notarytool info "$UUID" \ - --apple-id "${{ secrets.APPLE_ID }}" \ - --password "${{ secrets.APPLE_APP_SPECIFIC_PASSWORD }}" \ - --team-id "${{ secrets.APPLE_TEAM_ID }}" - fi - - # Staple the DMG - echo "Stapling notarization ticket to DMG..." - xcrun stapler staple "$DMG_FILE" - - # Verify stapling - echo "Verifying DMG stapling..." - xcrun stapler validate "$DMG_FILE" - else - echo "โš ๏ธ Notarization UUID not found. DMG may not be properly notarized." - fi - - echo "DMG file created at: $DMG_FILE" - echo "STAPLED_APP_DMG=$DMG_FILE" >> "$GITHUB_ENV" shell: bash # Upload stapled app directly (this is the most reliable approach) @@ -425,22 +345,32 @@ jobs: path: ${{ env.STAPLED_APP_PATH }} retention-days: 30 - # Upload the ZIP archive (proper archiving that preserves stapling) + # Create a properly archived ZIP of the stapled app (preserves stapling) + - name: Create Stapled App Archive (ZIP) + if: steps.sign-and-notarize.outputs.notarized == 'true' && steps.sign-and-notarize.outputs.signed != 'none' && steps.sign-and-notarize.outputs.zip-package-path != '' + run: | + # The ZIP is now created by the macos-notarize action + echo "Using ZIP created by the macos-notarize action" + echo "ZIP file location: ${{ steps.sign-and-notarize.outputs.zip-package-path }}" + echo "STAPLED_APP_ZIP=${{ steps.sign-and-notarize.outputs.zip-package-path }}" >> "$GITHUB_ENV" + shell: bash + + # Upload the ZIP archive from the macos-notarize action - name: Upload Stapled App ZIP Archive uses: actions/upload-artifact@v3 - if: steps.sign-and-notarize.outputs.notarized == 'true' && steps.sign-and-notarize.outputs.signed != 'none' + if: steps.sign-and-notarize.outputs.notarized == 'true' && steps.sign-and-notarize.outputs.signed != 'none' && steps.sign-and-notarize.outputs.zip-package-path != '' with: name: LuckyWorld-macOS-Stapled-ZIP - path: ${{ env.STAPLED_APP_ZIP }} + path: ${{ steps.sign-and-notarize.outputs.zip-package-path }} retention-days: 30 - # Upload the DMG file + # Upload the DMG file from the macos-notarize action - name: Upload Stapled App DMG uses: actions/upload-artifact@v3 if: steps.sign-and-notarize.outputs.notarized == 'true' && steps.sign-and-notarize.outputs.signed != 'none' with: name: LuckyWorld-macOS-Stapled-DMG - path: ${{ env.STAPLED_APP_DMG }} + path: ${{ steps.sign-and-notarize.outputs.package-path }} retention-days: 30 # Upload signed app (might be DMG or other package format) -- 2.47.2 From 619d4d82981e8fb157861a196e9f61c282ee7a10 Mon Sep 17 00:00:00 2001 From: Ozgur Ersoy Date: Tue, 15 Apr 2025 20:48:33 +0200 Subject: [PATCH 097/109] fix(actions): simplify macOS build workflow by removing redundant bundle ID checks and enhancing notarization issue verification --- .gitea/workflows/test-macos-build.yml | 216 +++----------------------- Config/DefaultEngine.ini | 10 ++ scripts/mac_build.sh | 141 ++--------------- 3 files changed, 47 insertions(+), 320 deletions(-) diff --git a/.gitea/workflows/test-macos-build.yml b/.gitea/workflows/test-macos-build.yml index 826c285d..3146c53b 100644 --- a/.gitea/workflows/test-macos-build.yml +++ b/.gitea/workflows/test-macos-build.yml @@ -29,48 +29,12 @@ jobs: # Create directories for builds mkdir -p Builds/Mac mkdir -p PackagedReleases + mkdir -p ArchivedApps echo "Environment setup complete" shell: bash - - # Verify bundle identifier is correctly set - - name: Verify bundle identifier - run: | - # Set the constant bundle ID for the workflow - echo "BUNDLE_ID=com.luckyrobots.luckyworld" >> "$GITHUB_ENV" - - # Verify the bundle ID is correctly set in DefaultGame.ini - CONFIG_FILE="Config/DefaultGame.ini" - if [ -f "$CONFIG_FILE" ]; then - if grep -q "\[/Script/MacTargetPlatform\.MacTargetSettings\]" "$CONFIG_FILE" && grep -q "BundleIdentifier=com.luckyrobots.luckyworld" "$CONFIG_FILE"; then - echo "โœ… Bundle ID correctly set in DefaultGame.ini" - else - echo "โš ๏ธ Warning: Bundle ID may not be correctly set in DefaultGame.ini" - echo "Please make sure the following section exists:" - echo "[/Script/MacTargetPlatform.MacTargetSettings]" - echo "BundleIdentifier=com.luckyrobots.luckyworld" - fi - else - echo "โš ๏ธ DefaultGame.ini not found!" - fi - shell: bash - # Check Unreal Engine Project settings - - name: Inspect Unreal Settings - run: | - # Check for any potential issues in UE project settings - if [ -f "Config/DefaultEngine.ini" ]; then - echo "Checking DefaultEngine.ini for settings that might affect bundle ID..." - grep -i "bundle\|identifier\|package" Config/DefaultEngine.ini || echo "No relevant settings found" - fi - - if [ -f "Config/DefaultGame.ini" ]; then - echo "Checking DefaultGame.ini for settings that might affect bundle ID..." - grep -i "bundle\|identifier\|package" Config/DefaultGame.ini || echo "No relevant settings found" - fi - shell: bash - - # Build for macOS - use your own build script or create a test app if needed + # Build for macOS - use your own build script - name: Build for macOS run: | if [ -f "./scripts/mac_build.sh" ]; then @@ -105,27 +69,6 @@ jobs: echo "Build status check..." if [ ! -d "./Builds" ] && [ ! -d "./Saved/StagedBuilds" ]; then echo "โŒ ERROR: Build directories do not exist. Build likely failed." - echo "Checking build logs for common issues..." - - # Check for the specific GlobalDefinitions error - if grep -q "GlobalDefinitions.*This is not allowed" "$GITHUB_WORKSPACE"/*.log 2>/dev/null || grep -q "BuildEnvironment\|bOverrideBuildEnvironment" "$GITHUB_WORKSPACE"/*.log 2>/dev/null; then - echo "๐Ÿ” Found issue with GlobalDefinitions in build target." - echo "โš ๏ธ Fix required in LuckyWorld.Target.cs - need to add bOverrideBuildEnvironment = true;" - echo "Fix suggestion for LuckyWorld.Target.cs:" - echo "Add this line in the constructor:" - echo " bOverrideBuildEnvironment = true;" - echo "" - echo "Example:" - echo " public LuckyWorldTarget(TargetInfo Target) : base(Target)" - echo " {" - echo " Type = TargetType.Game;" - echo " DefaultBuildSettings = BuildSettingsVersion.V5;" - echo " bOverrideBuildEnvironment = true; // Add this line" - echo " " - echo " // Rest of your constructor..." - echo " }" - fi - exit 1 fi @@ -170,96 +113,35 @@ jobs: # Export APP_PATH for next steps to use echo "APP_PATH=$MAIN_APP_PATH" >> "$GITHUB_ENV" - # Note: While bundle ID should be set by Unreal Engine build system based on DefaultGame.ini - # and LuckyWorld.Build.cs settings, we still check and fix if needed as a safety measure, - # since UE builds can sometimes have issues with bundle ID propagation - echo "Checking bundle IDs (fallback fix in case UE didn't properly apply settings)..." - - # Fix bundle ID in Info.plist before signing + # Get bundle ID from Info.plist for reference (not modifying) if [ -f "$MAIN_APP_PATH/Contents/Info.plist" ]; then - echo "Checking current bundle identifier..." - CURRENT_BUNDLE_ID=$(/usr/libexec/PlistBuddy -c "Print :CFBundleIdentifier" "$MAIN_APP_PATH/Contents/Info.plist") - echo "Current bundle ID: $CURRENT_BUNDLE_ID" - - if [ "$CURRENT_BUNDLE_ID" != "$BUNDLE_ID" ]; then - echo "Bundle ID mismatch - fixing it!" - echo "Setting bundle identifier to $BUNDLE_ID" - /usr/libexec/PlistBuddy -c "Set :CFBundleIdentifier $BUNDLE_ID" "$MAIN_APP_PATH/Contents/Info.plist" - echo "Updated bundle ID in Info.plist: $(/usr/libexec/PlistBuddy -c "Print :CFBundleIdentifier" "$MAIN_APP_PATH/Contents/Info.plist")" - else - echo "โœ… Bundle ID is already correct: $BUNDLE_ID" - fi - else - echo "WARNING: Could not find Info.plist in app bundle." - fi - - # Find and repair nested app bundles as well (like CrashReportClient.app) - NESTED_APPS=$(find "$MAIN_APP_PATH" -name "*.app" -type d | grep -v "^$MAIN_APP_PATH$") - if [ -n "$NESTED_APPS" ]; then - echo "Found nested app bundles, checking their bundle IDs:" - echo "$NESTED_APPS" | while read -r NESTED_APP; do - if [ -f "$NESTED_APP/Contents/Info.plist" ]; then - NESTED_NAME=$(basename "$NESTED_APP" .app) - NESTED_BUNDLE_ID="$BUNDLE_ID.$NESTED_NAME" - CURRENT_NESTED_ID=$(/usr/libexec/PlistBuddy -c "Print :CFBundleIdentifier" "$NESTED_APP/Contents/Info.plist") - - if [ "$CURRENT_NESTED_ID" != "$NESTED_BUNDLE_ID" ]; then - echo "Setting nested bundle ID to $NESTED_BUNDLE_ID for $NESTED_APP" - /usr/libexec/PlistBuddy -c "Set :CFBundleIdentifier $NESTED_BUNDLE_ID" "$NESTED_APP/Contents/Info.plist" - - # Verify the change - UPDATED_ID=$(/usr/libexec/PlistBuddy -c "Print :CFBundleIdentifier" "$NESTED_APP/Contents/Info.plist") - echo "Updated nested app bundle ID: $UPDATED_ID" - else - echo "โœ… Nested app $NESTED_NAME already has correct bundle ID: $CURRENT_NESTED_ID" - fi - fi - done + BUNDLE_ID=$(/usr/libexec/PlistBuddy -c "Print :CFBundleIdentifier" "$MAIN_APP_PATH/Contents/Info.plist") + echo "Detected bundle ID: $BUNDLE_ID" + echo "BUNDLE_ID=$BUNDLE_ID" >> "$GITHUB_ENV" fi shell: bash - # Fix common issues that may cause notarization failure - - name: Fix common issues for notarization + # Basic pre-notarization checks + - name: Check for notarization issues run: | - echo "๐Ÿ› ๏ธ Fixing common issues that may cause notarization failure..." + echo "๐Ÿ” Checking app for potential notarization issues..." APP_PATH="${{ env.APP_PATH }}" - # Remove get-task-allow entitlement from Info.plist files - echo "Checking for get-task-allow entitlement..." - find "$APP_PATH" -name "*.plist" -exec plutil -convert xml1 {} \; -exec grep -l "get-task-allow" {} \; | while read -r plist_file; do - echo "Removing get-task-allow from $plist_file" - /usr/libexec/PlistBuddy -c "Delete :com.apple.security.get-task-allow" "$plist_file" 2>/dev/null || true - done + # Verify code signature already exists (from Unreal build) + echo "Checking existing signature..." + codesign -vvv "$APP_PATH" || echo "โš ๏ธ App may not be properly signed by Unreal Engine" - # Check for problematic libraries that cause issues - echo "Looking for problematic files..." - PROBLEM_FILES=$(find "$APP_PATH" -type f -name "*.dylib" | grep -i "boost\|tbb\|ogg\|vorbis\|onnx") - if [ -n "$PROBLEM_FILES" ]; then - echo "Found potentially problematic libraries. These will be carefully handled during signing:" - echo "$PROBLEM_FILES" | head -10 - if [ $(echo "$PROBLEM_FILES" | wc -l) -gt 10 ]; then - echo "... and $(echo "$PROBLEM_FILES" | wc -l) more" - fi + # Check for any ad-hoc signatures that would cause issues + if codesign -dvv "$APP_PATH" 2>&1 | grep -q "adhoc"; then + echo "โš ๏ธ Warning: Ad-hoc signature detected. This will be replaced with a proper signature." fi - # Verify CrashReportClient specifically - CRASH_REPORTER=$(find "$APP_PATH" -path "*CrashReportClient.app*" -type d | head -1) - if [ -n "$CRASH_REPORTER" ]; then - echo "Found CrashReportClient at $CRASH_REPORTER" - if [ -f "$CRASH_REPORTER/Contents/Info.plist" ]; then - # Ensure it has the correct bundle ID format - CRASH_BUNDLE_ID="$BUNDLE_ID.CrashReportClient" - CURRENT_CRASH_ID=$(/usr/libexec/PlistBuddy -c "Print :CFBundleIdentifier" "$CRASH_REPORTER/Contents/Info.plist") - - if [ "$CURRENT_CRASH_ID" != "$CRASH_BUNDLE_ID" ]; then - echo "Setting CrashReportClient bundle ID to $CRASH_BUNDLE_ID" - /usr/libexec/PlistBuddy -c "Set :CFBundleIdentifier $CRASH_BUNDLE_ID" "$CRASH_REPORTER/Contents/Info.plist" - echo "Updated CrashReportClient bundle ID: $(/usr/libexec/PlistBuddy -c "Print :CFBundleIdentifier" "$CRASH_REPORTER/Contents/Info.plist")" - else - echo "โœ… CrashReportClient already has correct bundle ID: $CURRENT_CRASH_ID" - fi - fi + # Verify entitlements file exists + if [ ! -f "${{ env.ENTITLEMENTS_FILE }}" ]; then + echo "โš ๏ธ Entitlements file not found. Will use default entitlements." + else + echo "Found entitlements file: ${{ env.ENTITLEMENTS_FILE }}" fi shell: bash @@ -280,69 +162,13 @@ jobs: bundle-id: ${{ env.BUNDLE_ID }} fallback-to-adhoc: 'false' - # Additional verification and stapling to ensure the app opens without warning - - name: Verify and Staple App - if: steps.sign-and-notarize.outputs.notarized == 'true' && steps.sign-and-notarize.outputs.signed != 'none' - run: | - echo "๐Ÿ”’ Performing additional verification and stapling..." - APP_PATH="${{ env.APP_PATH }}" - - # Make sure the app is properly stapled - echo "Stapling notarization ticket to the app..." - xcrun stapler staple "$APP_PATH" - - # Verify the stapling - echo "Verifying stapling..." - xcrun stapler validate "$APP_PATH" - - # Perform deep verification of code signing - echo "Verifying code signature (deep)..." - codesign -vvv --deep "$APP_PATH" - - # Additional check for quarantine attributes - echo "Checking for quarantine attributes..." - if [ -n "$(xattr -l "$APP_PATH" | grep quarantine)" ]; then - echo "Removing quarantine attribute..." - xattr -d com.apple.quarantine "$APP_PATH" - else - echo "No quarantine attribute found, good!" - fi - - echo "โœ… Verification and stapling completed!" - - # Export STAPLED_APP_PATH for later use - echo "STAPLED_APP_PATH=$APP_PATH" >> "$GITHUB_ENV" - shell: bash - - # Create a DMG file (macOS disk image) for easy distribution - - name: Create DMG for Distribution - if: steps.sign-and-notarize.outputs.notarized == 'true' && steps.sign-and-notarize.outputs.signed != 'none' - run: | - STAPLED_APP_PATH="${{ env.STAPLED_APP_PATH }}" - APP_NAME=$(basename "$STAPLED_APP_PATH" .app) - ARCHIVE_DIR="./ArchivedApps" - DMG_FILE="$ARCHIVE_DIR/$APP_NAME.dmg" - - # Note: The actual DMG creation, signing, notarization and stapling - # are now handled by the macos-notarize action - - # Just ensure we have the correct path for outputs - if [ -f "${{ steps.sign-and-notarize.outputs.package-path }}" ]; then - echo "Using DMG created by the macos-notarize action" - echo "DMG file location: ${{ steps.sign-and-notarize.outputs.package-path }}" - echo "STAPLED_APP_DMG=${{ steps.sign-and-notarize.outputs.package-path }}" >> "$GITHUB_ENV" - else - echo "โš ๏ธ DMG not found from the macos-notarize action output" - fi - shell: bash - # Upload stapled app directly (this is the most reliable approach) - name: Upload Stapled App Bundle uses: actions/upload-artifact@v3 if: steps.sign-and-notarize.outputs.notarized == 'true' && steps.sign-and-notarize.outputs.signed != 'none' with: name: LuckyWorld-macOS-Stapled-App-Bundle - path: ${{ env.STAPLED_APP_PATH }} + path: ${{ env.APP_PATH }} retention-days: 30 # Create a properly archived ZIP of the stapled app (preserves stapling) diff --git a/Config/DefaultEngine.ini b/Config/DefaultEngine.ini index 2861d450..fcda2735 100644 --- a/Config/DefaultEngine.ini +++ b/Config/DefaultEngine.ini @@ -361,3 +361,13 @@ EnableCodeCoverage=False EnableCodeCoveragePath=(Path="") ForwardShading=False UseFastCopyToResolve=True + +[/Script/MacTargetPlatform.XcodeProjectSettings] +bMacSignToRunLocally=False +CodeSigningPrefix=com.luckyrobots +ApplicationDisplayName=LuckyWorld +CodeSigningTeam=937UD94CX2 +bUseAutomaticCodeSigning=False +ShippingSpecificMacEntitlements=(FilePath="../LuckyWorld.entitlements") +MacSigningIdentity=Developer ID Application + diff --git a/scripts/mac_build.sh b/scripts/mac_build.sh index 10b45411..11eac0c8 100755 --- a/scripts/mac_build.sh +++ b/scripts/mac_build.sh @@ -16,24 +16,26 @@ ARCHIVE_DIR="$PROJECT_ROOT/Builds" # Check for entitlements file if [ -f "$PROJECT_ROOT/LuckyWorld.entitlements" ]; then ENTITLEMENTS_FILE="$PROJECT_ROOT/LuckyWorld.entitlements" + echo "โœ… Using entitlements file: $ENTITLEMENTS_FILE" else - echo "Warning: No entitlements file found. This might affect notarization." + echo "โš ๏ธ Warning: No entitlements file found. This might affect notarization." ENTITLEMENTS_FILE="" fi -# For debugging: print paths and config +# Print paths and config for debugging echo "Project root: $PROJECT_ROOT" echo "Project file: $PROJECT_FILE" echo "Archive directory: $ARCHIVE_DIR" -echo "Entitlements file: $ENTITLEMENTS_FILE" # Clean up previous build artifacts rm -rf DerivedDataCache Intermediate Binaries Saved # Generate project files +echo "๐Ÿ“ Generating project files..." "$UE_ROOT/Engine/Build/BatchFiles/Mac/GenerateProjectFiles.sh" -project="$PROJECT_FILE" -game -engine # Run the build command +echo "๐Ÿ”จ Starting build process..." "$UE_UAT" -ScriptsForProject="$PROJECT_FILE" Turnkey \ -command=VerifySdk \ -platform=Mac \ @@ -61,20 +63,11 @@ rm -rf DerivedDataCache Intermediate Binaries Saved -prereqs \ -archivedirectory="$ARCHIVE_DIR" \ -CrashReporter \ - -clientconfig=Shipping \ - # -nocompile \ - # -nocompileuat \ - # -nocompileeditor \ - # -skipbuildeditor \ - - # enable these if you want to test build without pak and iostore (you're just testing the build) - # -skipiostore \ - # -skippak \ (disable -pak and -iostore) + -clientconfig=Shipping echo "" -echo "๐Ÿฆพ Build completed. Application path:" +echo "๐Ÿ” Looking for built application..." APP_PATH=$(find "$ARCHIVE_DIR" -name "*.app" -type d | head -n 1) -echo "$APP_PATH" # Check if the build actually succeeded by verifying the app exists if [ -z "$APP_PATH" ] || [ ! -d "$APP_PATH" ]; then @@ -86,9 +79,12 @@ if [ -z "$APP_PATH" ] || [ ! -d "$APP_PATH" ]; then exit 1 fi +echo "โœ… Build completed successfully! Application path:" +echo "$APP_PATH" + if [ -n "$APP_PATH" ]; then echo "" - echo "๐Ÿ” Binary files that will need signing:" + echo "๐Ÿ” Binary files summary:" DYLIB_COUNT=$(find "$APP_PATH" -name "*.dylib" | wc -l) SO_COUNT=$(find "$APP_PATH" -name "*.so" | wc -l) FRAMEWORKS=$(find "$APP_PATH" -path "*.framework/*" -type f -perm +111 | wc -l) @@ -100,120 +96,15 @@ if [ -n "$APP_PATH" ]; then echo "- $EXECUTABLES other executables" echo "Total binary files: $((DYLIB_COUNT + SO_COUNT + FRAMEWORKS + EXECUTABLES))" - echo "" - echo "๐Ÿ” Checking for PhysX and other special libraries (often need special handling):" - find "$APP_PATH" -name "*PhysX*" -o -name "*APEX*" -fi - -# Update bundle ID in project settings -echo "" -echo "๐Ÿ”ง Checking for bundle ID in UE config..." -CONFIG_FILE="$PROJECT_ROOT/Config/DefaultGame.ini" -if [ -f "$CONFIG_FILE" ]; then - if grep -q "\[/Script/MacTargetPlatform\.MacTargetSettings\]" "$CONFIG_FILE" && grep -q "BundleIdentifier=com.luckyrobots.luckyworld" "$CONFIG_FILE"; then - echo "Bundle ID already correctly set in project config โœ…" - else - echo "โš ๏ธ Warning: Bundle ID may not be correctly set in DefaultGame.ini" - echo "Please ensure [/Script/MacTargetPlatform.MacTargetSettings] section exists with BundleIdentifier=com.luckyrobots.luckyworld" - fi -else - echo "โš ๏ธ Config file not found at $CONFIG_FILE" -fi - -# Post-build process - set bundle ID -echo "" -echo "๐Ÿ” Checking bundle ID in built app..." -echo "Note: Bundle ID should be automatically set by Unreal Engine based on DefaultGame.ini and" -echo "LuckyWorld.Build.cs settings, but UE sometimes fails to apply it correctly." -echo "Therefore, we keep this check and fix as a safety measure." - -if [ -n "$APP_PATH" ]; then + # Check bundle ID (for information only, no modifications) INFO_PLIST="$APP_PATH/Contents/Info.plist" if [ -f "$INFO_PLIST" ]; then - CURRENT_BUNDLE_ID=$(/usr/libexec/PlistBuddy -c "Print :CFBundleIdentifier" "$INFO_PLIST") - echo "Current bundle ID: $CURRENT_BUNDLE_ID" - - if [ "$CURRENT_BUNDLE_ID" != "com.luckyrobots.luckyworld" ]; then - echo "Bundle ID mismatch - fixing it!" - echo "Setting bundle identifier to com.luckyrobots.luckyworld" - /usr/libexec/PlistBuddy -c "Set :CFBundleIdentifier com.luckyrobots.luckyworld" "$INFO_PLIST" - echo "Updated bundle ID: $(/usr/libexec/PlistBuddy -c "Print :CFBundleIdentifier" "$INFO_PLIST")" - else - echo "โœ… Bundle ID is already correct: com.luckyrobots.luckyworld" - fi - else - echo "โš ๏ธ Info.plist not found at $INFO_PLIST" + BUNDLE_ID=$(/usr/libexec/PlistBuddy -c "Print :CFBundleIdentifier" "$INFO_PLIST") + echo "" + echo "๐Ÿ“ฆ App Bundle ID: $BUNDLE_ID" fi fi -# If this is a manual build (not in CI), attempt to sign the app locally -if [ -z "$CI" ] && [ -n "$APP_PATH" ]; then - echo "" - echo "๐Ÿ” Attempting local code signing and stapling..." - - # Check if we have a valid Apple Developer identity - IDENTITY=$(security find-identity -v -p codesigning | grep "Developer ID Application" | head -1 | sed -E 's/.*\) ([A-F0-9]+) "(.*)"/\2/') - - if [ -n "$IDENTITY" ]; then - echo "Found signing identity: $IDENTITY" - - # Sign the app - echo "Signing application..." - if [ -f "$PROJECT_ROOT/LuckyWorld.entitlements" ]; then - echo "Using entitlements file: $PROJECT_ROOT/LuckyWorld.entitlements" - codesign --force --options runtime --entitlements "$PROJECT_ROOT/LuckyWorld.entitlements" --sign "$IDENTITY" --deep "$APP_PATH" - else - codesign --force --options runtime --sign "$IDENTITY" --deep "$APP_PATH" - fi - - # Verify signature - echo "Verifying signature..." - codesign -vvv --deep "$APP_PATH" - - # Staple the app if notarization is successful - echo "Checking if notarization is needed..." - if xcrun altool --notarization-info $(uuidgen) -u "YOUR_APPLE_ID" 2>&1 | grep -q "success"; then - echo "App is notarized, stapling the ticket..." - xcrun stapler staple "$APP_PATH" - xcrun stapler validate "$APP_PATH" - - # Remove quarantine attribute if present - if [ -n "$(xattr -l "$APP_PATH" | grep quarantine)" ]; then - echo "Removing quarantine attribute..." - xattr -d com.apple.quarantine "$APP_PATH" - fi - else - echo "App is not notarized yet. Upload to Apple's notary service for full verification." - fi - else - echo "โš ๏ธ No Developer ID Application certificate found for signing." - echo "Run 'security find-identity -v -p codesigning' to view available certificates." - fi -else - echo "Skipping local signing (running in CI or app not found)" -fi - -# Find and check nested app bundles (like CrashReportClient.app) -NESTED_APPS=$(find "$APP_PATH" -name "*.app" -type d | grep -v "^$APP_PATH$") -if [ -n "$NESTED_APPS" ]; then - echo "Checking nested app bundles:" - echo "$NESTED_APPS" | while read -r NESTED_APP; do - if [ -f "$NESTED_APP/Contents/Info.plist" ]; then - NESTED_NAME=$(basename "$NESTED_APP" .app) - NESTED_BUNDLE_ID="com.luckyrobots.luckyworld.$NESTED_NAME" - CURRENT_NESTED_ID=$(/usr/libexec/PlistBuddy -c "Print :CFBundleIdentifier" "$NESTED_APP/Contents/Info.plist") - - if [ "$CURRENT_NESTED_ID" != "$NESTED_BUNDLE_ID" ]; then - echo "Setting nested bundle ID to $NESTED_BUNDLE_ID for $NESTED_APP" - /usr/libexec/PlistBuddy -c "Set :CFBundleIdentifier $NESTED_BUNDLE_ID" "$NESTED_APP/Contents/Info.plist" - echo "Updated nested app bundle ID: $(/usr/libexec/PlistBuddy -c "Print :CFBundleIdentifier" "$NESTED_APP/Contents/Info.plist")" - else - echo "Nested app bundle ID already correct: $CURRENT_NESTED_ID" - fi - fi - done -fi - echo "" -echo "โœ… Build and post-processing completed!" +echo "โœ… Build complete!" echo "App location: $APP_PATH" -- 2.47.2 From 4a71488bea1c3ce6ca2d859f0d012377ebea1941 Mon Sep 17 00:00:00 2001 From: Ozgur Ersoy Date: Tue, 15 Apr 2025 21:05:51 +0200 Subject: [PATCH 098/109] fix(actions): update macOS build workflow to disable automatic code signing and skip signing executables --- Config/DefaultEngine.ini | 3 +++ Source/LuckyWorld.Target.cs | 3 +++ scripts/mac_build.sh | 1 + 3 files changed, 7 insertions(+) diff --git a/Config/DefaultEngine.ini b/Config/DefaultEngine.ini index fcda2735..77f05207 100644 --- a/Config/DefaultEngine.ini +++ b/Config/DefaultEngine.ini @@ -361,6 +361,9 @@ EnableCodeCoverage=False EnableCodeCoveragePath=(Path="") ForwardShading=False UseFastCopyToResolve=True +bAutomaticallySignBuilds=False +bUseSIPSafeRunloop=True +CodeSigningIdentity="" [/Script/MacTargetPlatform.XcodeProjectSettings] bMacSignToRunLocally=False diff --git a/Source/LuckyWorld.Target.cs b/Source/LuckyWorld.Target.cs index 459aed18..99cc338a 100644 --- a/Source/LuckyWorld.Target.cs +++ b/Source/LuckyWorld.Target.cs @@ -27,6 +27,9 @@ public class LuckyWorldTarget : TargetRules GlobalDefinitions.Add("APP_BUNDLE_IDENTIFIER=com.luckyrobots.luckyworld"); GlobalDefinitions.Add("APP_BUNDLE_NAME=LuckyWorld"); GlobalDefinitions.Add("APP_BUNDLE_DISPLAY_NAME=LuckyWorld"); + + // Disable automatic code signing + bDisableAutomaticCodeSigning = true; } } } diff --git a/scripts/mac_build.sh b/scripts/mac_build.sh index 11eac0c8..9162c8c4 100755 --- a/scripts/mac_build.sh +++ b/scripts/mac_build.sh @@ -53,6 +53,7 @@ echo "๐Ÿ”จ Starting build process..." -platform=Mac \ -installed \ -stage \ + -skipStage=SignExecutables \ -archive \ -package \ -build \ -- 2.47.2 From cdc8f67953d2aac90aa0d120a4482c69399d43a3 Mon Sep 17 00:00:00 2001 From: Ozgur Ersoy Date: Tue, 15 Apr 2025 21:22:23 +0200 Subject: [PATCH 099/109] fix(actions): update comment for disabling local automatic code signing in LuckyWorld.Target.cs --- Source/LuckyWorld.Target.cs | 13 +++++-- Source/LuckyWorldEditor.Target.cs | 6 ++++ scripts/mac_build.sh | 56 ++++++++++++++++--------------- 3 files changed, 45 insertions(+), 30 deletions(-) diff --git a/Source/LuckyWorld.Target.cs b/Source/LuckyWorld.Target.cs index 99cc338a..02465f3b 100644 --- a/Source/LuckyWorld.Target.cs +++ b/Source/LuckyWorld.Target.cs @@ -9,8 +9,15 @@ public class LuckyWorldTarget : TargetRules { Type = TargetType.Game; DefaultBuildSettings = BuildSettingsVersion.V5; + + // Fix for "Targets with a unique build environment cannot be built with an installed engine" bOverrideBuildEnvironment = true; - + BuildEnvironment = TargetBuildEnvironment.Shared; + + // Ensure proper build configuration + bUseLoggingInShipping = true; + bShouldCompileAsDLL = false; + ExtraModuleNames.AddRange( new string[] { "LuckyWorld" } ); IncludeOrderVersion = EngineIncludeOrderVersion.Latest; @@ -28,8 +35,8 @@ public class LuckyWorldTarget : TargetRules GlobalDefinitions.Add("APP_BUNDLE_NAME=LuckyWorld"); GlobalDefinitions.Add("APP_BUNDLE_DISPLAY_NAME=LuckyWorld"); - // Disable automatic code signing - bDisableAutomaticCodeSigning = true; + // Don't use local automatic code signing for builds + // bDisableAutomaticCodeSigning property is not available in UE 5.5 } } } diff --git a/Source/LuckyWorldEditor.Target.cs b/Source/LuckyWorldEditor.Target.cs index db543322..e2aa741f 100644 --- a/Source/LuckyWorldEditor.Target.cs +++ b/Source/LuckyWorldEditor.Target.cs @@ -9,7 +9,13 @@ public class LuckyWorldEditorTarget : TargetRules { Type = TargetType.Editor; DefaultBuildSettings = BuildSettingsVersion.V5; + + // Fix for "Targets with a unique build environment cannot be built with an installed engine" bOverrideBuildEnvironment = true; + BuildEnvironment = TargetBuildEnvironment.Shared; + + // Ensure proper build configuration + bShouldCompileAsDLL = false; ExtraModuleNames.AddRange( new string[] { "LuckyWorld" } ); diff --git a/scripts/mac_build.sh b/scripts/mac_build.sh index 9162c8c4..429f26c9 100755 --- a/scripts/mac_build.sh +++ b/scripts/mac_build.sh @@ -1,4 +1,5 @@ #!/bin/bash +set -e # Exit on any error # Get the user's home directory USER_HOME="$HOME" @@ -27,44 +28,43 @@ echo "Project root: $PROJECT_ROOT" echo "Project file: $PROJECT_FILE" echo "Archive directory: $ARCHIVE_DIR" -# Clean up previous build artifacts -rm -rf DerivedDataCache Intermediate Binaries Saved +# More selective cleanup - don't remove DerivedDataCache +echo "๐Ÿงน Cleaning build artifacts..." +rm -rf Intermediate/Build/Mac Saved/Cooked +mkdir -p "$ARCHIVE_DIR" # Generate project files echo "๐Ÿ“ Generating project files..." "$UE_ROOT/Engine/Build/BatchFiles/Mac/GenerateProjectFiles.sh" -project="$PROJECT_FILE" -game -engine -# Run the build command +# Run the build command with simplified parameters and more diagnostics echo "๐Ÿ”จ Starting build process..." -"$UE_UAT" -ScriptsForProject="$PROJECT_FILE" Turnkey \ - -command=VerifySdk \ +"$UE_UAT" -ScriptsForProject="$PROJECT_FILE" BuildCookRun \ + -project="$PROJECT_FILE" \ -platform=Mac \ - -UpdateIfNeeded \ - -EditorIO \ - -EditorIOPort=59484 \ - -project="$PROJECT_FILE" \ - BuildCookRun \ - -nop4 \ - -utf8output \ - -cook \ - -project="$PROJECT_FILE" \ + -clientconfig=Shipping \ -target=LuckyWorld \ - -unrealexe="$UE_EDITOR" \ - -platform=Mac \ - -installed \ + -build \ + -cook -iterate -CookOnTheFly -CookMapsOnly \ -stage \ -skipStage=SignExecutables \ - -archive \ - -package \ - -build \ - -iterativecooking \ -pak \ - -iostore \ -compressed \ -prereqs \ + -iostore \ + -package \ + -archive \ -archivedirectory="$ARCHIVE_DIR" \ - -CrashReporter \ - -clientconfig=Shipping + -verbose \ + -ddc=DerivedDataBackendGraph \ + -CrashReporter + +# Check for errors in the build process +BUILD_STATUS=$? +if [ $BUILD_STATUS -ne 0 ]; then + echo "โŒ ERROR: Build command failed with exit code $BUILD_STATUS" + exit $BUILD_STATUS +fi echo "" echo "๐Ÿ” Looking for built application..." @@ -74,9 +74,11 @@ APP_PATH=$(find "$ARCHIVE_DIR" -name "*.app" -type d | head -n 1) if [ -z "$APP_PATH" ] || [ ! -d "$APP_PATH" ]; then echo "โŒ ERROR: Build failed or did not produce an app bundle!" echo "Check the logs above for build errors." - echo "Common issues:" - echo " - 'Targets with a unique build environment cannot be built with an installed engine'" - echo " Fix: Use bOverrideBuildEnvironment = true instead of BuildEnvironment = TargetBuildEnvironment.Unique" + + # List all files in the archive directory to help debug + echo "Contents of archive directory:" + find "$ARCHIVE_DIR" -type f -o -type d | sort + exit 1 fi -- 2.47.2 From 0440c10440e313cb4f719aef985f3a57794a5cef Mon Sep 17 00:00:00 2001 From: Ozgur Ersoy Date: Tue, 15 Apr 2025 21:36:56 +0200 Subject: [PATCH 100/109] fix(actions): remove redundant macOS build settings and streamline build script for improved clarity --- Source/LuckyWorld.Target.cs | 20 ------------ Source/LuckyWorld/LuckyWorld.Build.cs | 7 ----- Source/LuckyWorldEditor.Target.cs | 7 ----- scripts/mac_build.sh | 44 +++++++++++++++++++-------- 4 files changed, 31 insertions(+), 47 deletions(-) diff --git a/Source/LuckyWorld.Target.cs b/Source/LuckyWorld.Target.cs index 02465f3b..86aedaa3 100644 --- a/Source/LuckyWorld.Target.cs +++ b/Source/LuckyWorld.Target.cs @@ -10,14 +10,6 @@ public class LuckyWorldTarget : TargetRules Type = TargetType.Game; DefaultBuildSettings = BuildSettingsVersion.V5; - // Fix for "Targets with a unique build environment cannot be built with an installed engine" - bOverrideBuildEnvironment = true; - BuildEnvironment = TargetBuildEnvironment.Shared; - - // Ensure proper build configuration - bUseLoggingInShipping = true; - bShouldCompileAsDLL = false; - ExtraModuleNames.AddRange( new string[] { "LuckyWorld" } ); IncludeOrderVersion = EngineIncludeOrderVersion.Latest; @@ -26,17 +18,5 @@ public class LuckyWorldTarget : TargetRules { this.bUseLoggingInShipping = true; } - - // macOS specific settings - if (Target.Platform == UnrealTargetPlatform.Mac) - { - // Force use the bundle ID from DefaultGame.ini - GlobalDefinitions.Add("APP_BUNDLE_IDENTIFIER=com.luckyrobots.luckyworld"); - GlobalDefinitions.Add("APP_BUNDLE_NAME=LuckyWorld"); - GlobalDefinitions.Add("APP_BUNDLE_DISPLAY_NAME=LuckyWorld"); - - // Don't use local automatic code signing for builds - // bDisableAutomaticCodeSigning property is not available in UE 5.5 - } } } diff --git a/Source/LuckyWorld/LuckyWorld.Build.cs b/Source/LuckyWorld/LuckyWorld.Build.cs index b094e6f3..9d80c354 100644 --- a/Source/LuckyWorld/LuckyWorld.Build.cs +++ b/Source/LuckyWorld/LuckyWorld.Build.cs @@ -20,12 +20,5 @@ public class LuckyWorld : ModuleRules // To include OnlineSubsystemSteam, add it to the plugins section in your uproject file with the Enabled attribute set to true - // Set the bundle identifier for macOS builds - if (Target.Platform == UnrealTargetPlatform.Mac) - { - PublicDefinitions.Add("APP_BUNDLE_IDENTIFIER=com.luckyrobots.luckyworld"); - PublicDefinitions.Add("APP_BUNDLE_NAME=LuckyWorld"); - PublicDefinitions.Add("APP_BUNDLE_DISPLAY_NAME=LuckyWorld"); - } } } diff --git a/Source/LuckyWorldEditor.Target.cs b/Source/LuckyWorldEditor.Target.cs index e2aa741f..b1d60a9d 100644 --- a/Source/LuckyWorldEditor.Target.cs +++ b/Source/LuckyWorldEditor.Target.cs @@ -10,13 +10,6 @@ public class LuckyWorldEditorTarget : TargetRules Type = TargetType.Editor; DefaultBuildSettings = BuildSettingsVersion.V5; - // Fix for "Targets with a unique build environment cannot be built with an installed engine" - bOverrideBuildEnvironment = true; - BuildEnvironment = TargetBuildEnvironment.Shared; - - // Ensure proper build configuration - bShouldCompileAsDLL = false; - ExtraModuleNames.AddRange( new string[] { "LuckyWorld" } ); IncludeOrderVersion = EngineIncludeOrderVersion.Latest; diff --git a/scripts/mac_build.sh b/scripts/mac_build.sh index 429f26c9..d07c69ab 100755 --- a/scripts/mac_build.sh +++ b/scripts/mac_build.sh @@ -30,7 +30,7 @@ echo "Archive directory: $ARCHIVE_DIR" # More selective cleanup - don't remove DerivedDataCache echo "๐Ÿงน Cleaning build artifacts..." -rm -rf Intermediate/Build/Mac Saved/Cooked +rm -rf DerivedDataCache Intermediate Binaries Saved mkdir -p "$ARCHIVE_DIR" # Generate project files @@ -39,25 +39,43 @@ echo "๐Ÿ“ Generating project files..." # Run the build command with simplified parameters and more diagnostics echo "๐Ÿ”จ Starting build process..." -"$UE_UAT" -ScriptsForProject="$PROJECT_FILE" BuildCookRun \ - -project="$PROJECT_FILE" \ +"$UE_UAT" -ScriptsForProject="$PROJECT_FILE" Turnkey \ + -command=VerifySdk \ -platform=Mac \ - -clientconfig=Shipping \ + -UpdateIfNeeded \ + -EditorIO \ + -EditorIOPort=59484 \ + -project="$PROJECT_FILE" \ + BuildCookRun \ + -nop4 \ + -utf8output \ + -cook \ + -project="$PROJECT_FILE" \ -target=LuckyWorld \ - -build \ - -cook -iterate -CookOnTheFly -CookMapsOnly \ + -unrealexe="$UE_EDITOR" \ + -platform=Mac \ + -installed \ -stage \ - -skipStage=SignExecutables \ + -archive \ + -package \ + -build \ + -iterativecooking \ -pak \ + -iostore \ -compressed \ -prereqs \ - -iostore \ - -package \ - -archive \ -archivedirectory="$ARCHIVE_DIR" \ - -verbose \ - -ddc=DerivedDataBackendGraph \ - -CrashReporter + -CrashReporter \ + -clientconfig=Shipping \ + # -nocompile \ + # -nocompileuat \ + # -nocompileeditor \ + # -skipbuildeditor \ + + # enable these if you want to test build without pak and iostore (you're just testing the build) + # -skipiostore \ + # -skippak \ (disable -pak and -iostore) + #!/bin/bash # Check for errors in the build process BUILD_STATUS=$? -- 2.47.2 From 6526ef04e2b7ffaa5eea17ffb36d489ba023bea4 Mon Sep 17 00:00:00 2001 From: Ozgur Ersoy Date: Tue, 15 Apr 2025 21:57:30 +0200 Subject: [PATCH 101/109] fix(actions): enable macOS local signing for improved build security --- Config/DefaultEngine.ini | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Config/DefaultEngine.ini b/Config/DefaultEngine.ini index 77f05207..c3fd8285 100644 --- a/Config/DefaultEngine.ini +++ b/Config/DefaultEngine.ini @@ -366,11 +366,11 @@ bUseSIPSafeRunloop=True CodeSigningIdentity="" [/Script/MacTargetPlatform.XcodeProjectSettings] -bMacSignToRunLocally=False +bMacSignToRunLocally=True CodeSigningPrefix=com.luckyrobots ApplicationDisplayName=LuckyWorld CodeSigningTeam=937UD94CX2 bUseAutomaticCodeSigning=False ShippingSpecificMacEntitlements=(FilePath="../LuckyWorld.entitlements") -MacSigningIdentity=Developer ID Application +MacSigningIdentity="" -- 2.47.2 From b13286877ae43b969dedbfa19aad71a7054962bd Mon Sep 17 00:00:00 2001 From: Ozgur Ersoy Date: Tue, 15 Apr 2025 22:31:31 +0200 Subject: [PATCH 102/109] fix(actions): remove macOS local signing settings for streamlined build configuration --- Config/DefaultEngine.ini | 4 ---- 1 file changed, 4 deletions(-) diff --git a/Config/DefaultEngine.ini b/Config/DefaultEngine.ini index c3fd8285..e8b910a9 100644 --- a/Config/DefaultEngine.ini +++ b/Config/DefaultEngine.ini @@ -366,11 +366,7 @@ bUseSIPSafeRunloop=True CodeSigningIdentity="" [/Script/MacTargetPlatform.XcodeProjectSettings] -bMacSignToRunLocally=True CodeSigningPrefix=com.luckyrobots ApplicationDisplayName=LuckyWorld -CodeSigningTeam=937UD94CX2 -bUseAutomaticCodeSigning=False ShippingSpecificMacEntitlements=(FilePath="../LuckyWorld.entitlements") -MacSigningIdentity="" -- 2.47.2 From 7ef0376181f4f77421ac01252ee58b17c7ebe768 Mon Sep 17 00:00:00 2001 From: Ozgur Ersoy Date: Wed, 16 Apr 2025 00:17:18 +0200 Subject: [PATCH 103/109] fix(actions): enhance macOS notarization workflow by adding security verifications and automation permissions --- .gitea/actions/macos-notarize/action.yml | 85 +++++++++++++++++++++++- .gitea/workflows/test-local-signing.yml | 4 ++ LuckyWorld.entitlements | 4 ++ 3 files changed, 90 insertions(+), 3 deletions(-) diff --git a/.gitea/actions/macos-notarize/action.yml b/.gitea/actions/macos-notarize/action.yml index 062da8cf..33cf0dce 100644 --- a/.gitea/actions/macos-notarize/action.yml +++ b/.gitea/actions/macos-notarize/action.yml @@ -1,6 +1,6 @@ name: "macOS Sign and Notarize" description: "Signs and notarizes macOS applications with Developer ID certificate" -author: moersoy" +author: moersoy inputs: app-path: @@ -674,6 +674,11 @@ runs: ditto -c -k --keepParent "${{ inputs.app-path }}" "$ZIP_FILE" echo "โœ… Created ZIP package: $ZIP_FILE" + # Verify stapling on the app before packaging + echo "๐Ÿ” Verifying app notarization and stapling..." + xcrun stapler validate "${{ inputs.app-path }}" || echo "โš ๏ธ App stapling verification failed" + spctl -a -vvv --type exec "${{ inputs.app-path }}" || echo "โš ๏ธ App notarization verification failed" + # Check if we can create DMG (hdiutil is available) if command -v hdiutil &> /dev/null; then # Create DMG package (much better for distribution) @@ -687,8 +692,54 @@ runs: # Optional: Add README or instructions echo "# Installation Instructions\n\nDrag the application to your Applications folder to install." > "$DMG_TMP_DIR/README.txt" - # Create DMG file with the app - hdiutil create -volname "${APP_NAME}" -srcfolder "$DMG_TMP_DIR" -ov -format UDZO "$DMG_FILE" + # Create a helper script to remove quarantine attribute + echo "Creating helper script to remove quarantine attribute..." + mkdir -p "$DMG_TMP_DIR/scripts" + cat > "$DMG_TMP_DIR/scripts/remove_quarantine.sh" << 'EOF' +#!/bin/bash +APP_PATH="/Applications/$(basename "$0" | sed 's/remove_quarantine_//')" +if [ -d "$APP_PATH" ]; then + echo "Removing quarantine attribute from $APP_PATH" + xattr -dr com.apple.quarantine "$APP_PATH" + echo "โœ… Quarantine attribute removed" + osascript -e "display notification \"Quarantine attribute removed from $APP_PATH\" with title \"Installation Complete\"" +else + echo "โŒ Application not found at $APP_PATH" + osascript -e "display notification \"Application not found at $APP_PATH\" with title \"Installation Failed\"" +fi +EOF + + # Make the script executable and name it based on the app + chmod +x "$DMG_TMP_DIR/scripts/remove_quarantine.sh" + cp "$DMG_TMP_DIR/scripts/remove_quarantine.sh" "$DMG_TMP_DIR/scripts/remove_quarantine_$(basename "${{ inputs.app-path }}")" + + # Try to use create-dmg if available, otherwise fall back to hdiutil + if command -v create-dmg &> /dev/null; then + echo "Using create-dmg for better DMG creation..." + + # Decide which keychain to use for getting identity + if [ "${{ steps.setup-cert.outputs.use_system_cert }}" = "true" ]; then + echo "Using system keychain identity" + IDENTITY_HASH=$(security find-identity -v -p codesigning | grep "Developer ID Application" | head -1 | awk '{print $2}') + else + security unlock-keychain -p "$KEYCHAIN_PASSWORD" "$KEYCHAIN_PATH" + IDENTITY_HASH=$(security find-identity -v -p codesigning "$KEYCHAIN_PATH" | grep "Developer ID Application" | head -1 | awk '{print $2}') + fi + + create-dmg \ + --volname "${APP_NAME}" \ + --codesign-identity "$IDENTITY_HASH" \ + --app-drop-link 450 200 \ + --hide-extension "$(basename "${{ inputs.app-path }}")" \ + --add-file "README.txt" 200 200 \ + --add-file "scripts" 200 300 \ + --no-internet-enable \ + "$DMG_FILE" \ + "$DMG_TMP_DIR" + else + # Fall back to hdiutil + hdiutil create -volname "${APP_NAME}" -srcfolder "$DMG_TMP_DIR" -ov -format UDZO "$DMG_FILE" + fi if [ -f "$DMG_FILE" ]; then echo "โœ… Created DMG package: $DMG_FILE" @@ -751,6 +802,10 @@ runs: echo "Verifying DMG stapling..." xcrun stapler validate "$DMG_FILE" + # Additional verification of DMG security + echo "Performing additional security verification of DMG..." + spctl --assess --verbose=4 --type open "$DMG_FILE" || echo "โš ๏ธ DMG security verification warning" + echo "DMG is now fully signed, notarized, and stapled!" else echo "โš ๏ธ DMG notarization may have failed or is still in progress." @@ -783,6 +838,10 @@ runs: echo "Verifying DMG stapling..." xcrun stapler validate "$DMG_FILE" + # Additional verification of DMG security + echo "Performing additional security verification of DMG..." + spctl --assess --verbose=4 --type open "$DMG_FILE" || echo "โš ๏ธ DMG security verification warning" + echo "DMG is now fully signed, notarized, and stapled!" else echo "โš ๏ธ DMG notarization may have failed or is still in progress." @@ -813,6 +872,26 @@ runs: echo "hdiutil not available, skipping DMG creation" echo "::set-output name=package-path::$ZIP_FILE" fi + + # Final verification of all artifacts + echo "๐Ÿ” Final verification of all distribution artifacts..." + + if [ -f "$ZIP_FILE" ]; then + echo "Verifying ZIP package integrity..." + ditto -v -x "$ZIP_FILE" /tmp/verify_app_extraction || echo "โš ๏ธ ZIP extraction test failed" + rm -rf /tmp/verify_app_extraction + fi + + if [ -f "$DMG_FILE" ]; then + echo "Verifying DMG file signature..." + codesign -vvv "$DMG_FILE" || echo "โš ๏ธ DMG signature verification failed" + + # Check if DMG was notarized successfully + if [ "${{ steps.notarize.outputs.notarized }}" = "true" ]; then + echo "Verifying DMG stapling..." + xcrun stapler validate "$DMG_FILE" || echo "โš ๏ธ DMG stapling verification failed" + fi + fi - name: Cleanup if: always() diff --git a/.gitea/workflows/test-local-signing.yml b/.gitea/workflows/test-local-signing.yml index 1459312a..5f13a79e 100644 --- a/.gitea/workflows/test-local-signing.yml +++ b/.gitea/workflows/test-local-signing.yml @@ -32,6 +32,10 @@ jobs: com.apple.security.device.camera + com.apple.security.automation.apple-events + + com.apple.security.get-task-allow + EOF diff --git a/LuckyWorld.entitlements b/LuckyWorld.entitlements index 4dc9a495..d8b1cb47 100644 --- a/LuckyWorld.entitlements +++ b/LuckyWorld.entitlements @@ -22,5 +22,9 @@ com.apple.security.network.client + com.apple.security.automation.apple-events + + com.apple.security.get-task-allow + \ No newline at end of file -- 2.47.2 From fba1af513cc4cfcdffd389d38e254d7ffbd3c67f Mon Sep 17 00:00:00 2001 From: Ozgur Ersoy Date: Wed, 16 Apr 2025 00:46:48 +0200 Subject: [PATCH 104/109] fix(actions): update macOS notarization workflow to improve DMG packaging and enhance installation instructions --- .gitea/actions/macos-notarize/action.yml | 89 ++++++++++++++++-------- .gitea/workflows/test-macos-build.yml | 52 +------------- 2 files changed, 64 insertions(+), 77 deletions(-) diff --git a/.gitea/actions/macos-notarize/action.yml b/.gitea/actions/macos-notarize/action.yml index 33cf0dce..98a58f9a 100644 --- a/.gitea/actions/macos-notarize/action.yml +++ b/.gitea/actions/macos-notarize/action.yml @@ -669,10 +669,10 @@ runs: echo "Creating distribution package with signed app..." fi - # Create zip package + # Create zip package (necessary for notarization process only) ZIP_FILE="${APP_NAME}-${PACKAGE_SUFFIX}.zip" ditto -c -k --keepParent "${{ inputs.app-path }}" "$ZIP_FILE" - echo "โœ… Created ZIP package: $ZIP_FILE" + echo "โœ… Created temporary ZIP package for notarization: $ZIP_FILE" # Verify stapling on the app before packaging echo "๐Ÿ” Verifying app notarization and stapling..." @@ -689,29 +689,57 @@ runs: DMG_TMP_DIR=$(mktemp -d) cp -R "${{ inputs.app-path }}" "$DMG_TMP_DIR/" - # Optional: Add README or instructions - echo "# Installation Instructions\n\nDrag the application to your Applications folder to install." > "$DMG_TMP_DIR/README.txt" - - # Create a helper script to remove quarantine attribute - echo "Creating helper script to remove quarantine attribute..." - mkdir -p "$DMG_TMP_DIR/scripts" - cat > "$DMG_TMP_DIR/scripts/remove_quarantine.sh" << 'EOF' -#!/bin/bash -APP_PATH="/Applications/$(basename "$0" | sed 's/remove_quarantine_//')" -if [ -d "$APP_PATH" ]; then - echo "Removing quarantine attribute from $APP_PATH" - xattr -dr com.apple.quarantine "$APP_PATH" - echo "โœ… Quarantine attribute removed" - osascript -e "display notification \"Quarantine attribute removed from $APP_PATH\" with title \"Installation Complete\"" -else - echo "โŒ Application not found at $APP_PATH" - osascript -e "display notification \"Application not found at $APP_PATH\" with title \"Installation Failed\"" -fi + # Add README with fancy formatting + cat > "$DMG_TMP_DIR/README.txt" << 'EOF' +# LuckyWorld Installation Instructions + +1. Drag the LuckyWorld application to your Applications folder +2. Double-click the "Install Helper" icon (optional - removes security warnings) +3. Enjoy! + +For technical support, contact: support@luckyrobots.com EOF - # Make the script executable and name it based on the app - chmod +x "$DMG_TMP_DIR/scripts/remove_quarantine.sh" - cp "$DMG_TMP_DIR/scripts/remove_quarantine.sh" "$DMG_TMP_DIR/scripts/remove_quarantine_$(basename "${{ inputs.app-path }}")" + # Create a better helper script to remove quarantine attribute + echo "Creating helper script to remove quarantine attribute..." + mkdir -p "$DMG_TMP_DIR/scripts" + cat > "$DMG_TMP_DIR/scripts/InstallHelper.command" << 'EOF' +#!/bin/bash + +# Get the application name from the DMG +APP_NAME="LuckyWorld-Mac-Shipping.app" +APP_PATH="/Applications/$APP_NAME" + +echo "============================================" +echo "๐Ÿ” LuckyWorld Security Helper" +echo "============================================" + +if [ -d "$APP_PATH" ]; then + echo "โœ… Found $APP_NAME in Applications folder" + echo "๐Ÿงน Removing security attributes..." + xattr -dr com.apple.quarantine "$APP_PATH" + echo "โœ… Security attributes removed successfully!" + echo "๐Ÿš€ You can now launch the application normally" + osascript -e "display notification \"$APP_NAME is ready to use\" with title \"LuckyWorld Installation Complete\" subtitle \"Security attributes removed\"" +else + echo "โŒ $APP_NAME not found in Applications folder" + echo "โš ๏ธ Please drag the application to your Applications folder first" + osascript -e "display notification \"Please drag LuckyWorld to Applications folder first\" with title \"Installation Incomplete\" subtitle \"Application not found\"" + exit 1 +fi + +echo "============================================" +echo "Press any key to exit..." +read -n 1 +EOF + + # Make the script executable + chmod +x "$DMG_TMP_DIR/scripts/InstallHelper.command" + + # Create visually appealing backgrounds and icons + if [ -d "$DMG_TMP_DIR/scripts" ]; then + touch "$DMG_TMP_DIR/scripts/.keep" + fi # Try to use create-dmg if available, otherwise fall back to hdiutil if command -v create-dmg &> /dev/null; then @@ -727,18 +755,23 @@ EOF fi create-dmg \ - --volname "${APP_NAME}" \ + --volname "LuckyWorld Installer" \ --codesign-identity "$IDENTITY_HASH" \ - --app-drop-link 450 200 \ + --window-pos 200 120 \ + --window-size 800 400 \ + --icon-size 100 \ + --text-size 12 \ + --app-drop-link 600 170 \ --hide-extension "$(basename "${{ inputs.app-path }}")" \ - --add-file "README.txt" 200 200 \ - --add-file "scripts" 200 300 \ + --add-file "README.txt" 200 170 \ + --add-file "scripts/InstallHelper.command" 400 170 \ + --hide-extension "InstallHelper.command" \ --no-internet-enable \ "$DMG_FILE" \ "$DMG_TMP_DIR" else # Fall back to hdiutil - hdiutil create -volname "${APP_NAME}" -srcfolder "$DMG_TMP_DIR" -ov -format UDZO "$DMG_FILE" + hdiutil create -volname "LuckyWorld Installer" -srcfolder "$DMG_TMP_DIR" -ov -format UDZO "$DMG_FILE" fi if [ -f "$DMG_FILE" ]; then diff --git a/.gitea/workflows/test-macos-build.yml b/.gitea/workflows/test-macos-build.yml index 3146c53b..65af91e1 100644 --- a/.gitea/workflows/test-macos-build.yml +++ b/.gitea/workflows/test-macos-build.yml @@ -162,61 +162,15 @@ jobs: bundle-id: ${{ env.BUNDLE_ID }} fallback-to-adhoc: 'false' - # Upload stapled app directly (this is the most reliable approach) - - name: Upload Stapled App Bundle + # Upload only the DMG file as main distribution artifact + - name: Upload Mac Distribution DMG uses: actions/upload-artifact@v3 if: steps.sign-and-notarize.outputs.notarized == 'true' && steps.sign-and-notarize.outputs.signed != 'none' with: - name: LuckyWorld-macOS-Stapled-App-Bundle - path: ${{ env.APP_PATH }} - retention-days: 30 - - # Create a properly archived ZIP of the stapled app (preserves stapling) - - name: Create Stapled App Archive (ZIP) - if: steps.sign-and-notarize.outputs.notarized == 'true' && steps.sign-and-notarize.outputs.signed != 'none' && steps.sign-and-notarize.outputs.zip-package-path != '' - run: | - # The ZIP is now created by the macos-notarize action - echo "Using ZIP created by the macos-notarize action" - echo "ZIP file location: ${{ steps.sign-and-notarize.outputs.zip-package-path }}" - echo "STAPLED_APP_ZIP=${{ steps.sign-and-notarize.outputs.zip-package-path }}" >> "$GITHUB_ENV" - shell: bash - - # Upload the ZIP archive from the macos-notarize action - - name: Upload Stapled App ZIP Archive - uses: actions/upload-artifact@v3 - if: steps.sign-and-notarize.outputs.notarized == 'true' && steps.sign-and-notarize.outputs.signed != 'none' && steps.sign-and-notarize.outputs.zip-package-path != '' - with: - name: LuckyWorld-macOS-Stapled-ZIP - path: ${{ steps.sign-and-notarize.outputs.zip-package-path }} - retention-days: 30 - - # Upload the DMG file from the macos-notarize action - - name: Upload Stapled App DMG - uses: actions/upload-artifact@v3 - if: steps.sign-and-notarize.outputs.notarized == 'true' && steps.sign-and-notarize.outputs.signed != 'none' - with: - name: LuckyWorld-macOS-Stapled-DMG + name: LuckyWorld-Mac-Distribution path: ${{ steps.sign-and-notarize.outputs.package-path }} retention-days: 30 - # Upload signed app (might be DMG or other package format) - - name: Upload Signed App Package - uses: actions/upload-artifact@v3 - if: steps.sign-and-notarize.outputs.signed != 'none' - with: - name: ${{ steps.sign-and-notarize.outputs.notarized == 'true' && 'LuckyWorld-macOS-Signed-Notarized-Package' || 'LuckyWorld-macOS-Signed-Package' }} - path: ${{ steps.sign-and-notarize.outputs.package-path }} - retention-days: 30 - - # Upload ZIP package if DMG was created (as a backup) - - name: Upload ZIP Package - uses: actions/upload-artifact@v3 - if: steps.sign-and-notarize.outputs.signed != 'none' && steps.sign-and-notarize.outputs.zip-package-path != '' - with: - name: ${{ steps.sign-and-notarize.outputs.notarized == 'true' && 'LuckyWorld-macOS-Signed-Notarized-ZIP' || 'LuckyWorld-macOS-Signed-ZIP' }} - path: ${{ steps.sign-and-notarize.outputs.zip-package-path }} - retention-days: 30 - # Report results - name: Report Results run: | -- 2.47.2 From 1c7e12e27989e2019a257f12ed81482e5df6e740 Mon Sep 17 00:00:00 2001 From: Ozgur Ersoy Date: Wed, 16 Apr 2025 01:27:26 +0200 Subject: [PATCH 105/109] fix(actions): enhance macOS notarization workflow by adding debug logging, build cache management, and improved artifact handling --- .gitea/actions/macos-notarize/action.yml | 1430 +++++++++------------- .gitea/workflows/test-macos-build.yml | 56 +- 2 files changed, 653 insertions(+), 833 deletions(-) diff --git a/.gitea/actions/macos-notarize/action.yml b/.gitea/actions/macos-notarize/action.yml index 98a58f9a..e77e590b 100644 --- a/.gitea/actions/macos-notarize/action.yml +++ b/.gitea/actions/macos-notarize/action.yml @@ -1,936 +1,704 @@ -name: "macOS Sign and Notarize" -description: "Signs and notarizes macOS applications with Developer ID certificate" +name: macOS Notarize +description: 'Signs and notarizes a macOS application with Apple certificates' author: moersoy inputs: app-path: - description: "Path to the app bundle (.app)" + description: 'Path to the .app bundle to sign' required: true entitlements-file: - description: "Path to the entitlements file (.entitlements)" - required: true + description: 'Path to entitlements file to use for signing' + required: false + default: '' team-id: - description: "Apple Developer Team ID" + description: 'Apple Developer Team ID' required: true certificate-base64: - description: "Base64-encoded Developer ID Application certificate (.p12)" + description: 'Base64-encoded certificate (P12 file)' required: true certificate-password: - description: "Password for the Developer ID Application certificate" + description: 'Certificate password' required: true notarization-method: - description: "Method to use for notarization: 'api-key' or 'app-password'" + description: 'Method to use for notarization (api-key or app-password)' required: false - default: "api-key" - notary-user: - description: "Apple ID for notarization (for app-password method)" + default: 'api-key' + app-password: + description: 'App-specific password for Apple ID (required if using app-password method)' required: false - notary-password: - description: "App-specific password for notarization (for app-password method)" + default: '' + apple-id: + description: 'Apple ID email (required if using app-password method)' required: false + default: '' notary-api-key-id: - description: "API Key ID for notarization (for api-key method)" + description: 'App Store Connect API Key ID (required if using api-key method)' required: false + default: '' notary-api-key-issuer-id: - description: "API Issuer ID for notarization (for api-key method)" + description: 'App Store Connect API Key Issuer ID (required if using api-key method)' required: false + default: '' notary-api-key-path: - description: "Path to or content of the API Key .p8 file (for api-key method)" + description: 'App Store Connect API Key file content (base64 encoded) (required if using api-key method)' required: false + default: '' bundle-id: - description: "App bundle identifier (com.example.app)" + description: 'Bundle ID of the app' required: false + default: '' fallback-to-adhoc: - description: "Whether to fall back to ad-hoc signing if certificate is invalid" + description: 'Fallback to ad-hoc signing if no certificate is available' required: false - default: "true" + default: 'true' outputs: signed: - description: "Whether the app was signed (identity, adhoc, or none)" - value: ${{ steps.sign.outputs.signed }} + description: 'Signing status (true, ad-hoc, none)' + value: ${{ steps.set-outputs.outputs.signed }} notarized: - description: "Whether the app was notarized (true or false)" - value: ${{ steps.notarize.outputs.notarized }} + description: 'Notarization status (true, false)' + value: ${{ steps.set-outputs.outputs.notarized }} + app-path: + description: 'Path to the signed app bundle' + value: ${{ steps.set-outputs.outputs.app-path }} + zip-path: + description: 'Path to the packaged .ZIP file' + value: ${{ steps.set-outputs.outputs.zip-path }} package-path: - description: "Path to the final package" - value: ${{ steps.package.outputs.package-path }} + description: 'Path to the packaged .DMG file' + value: ${{ steps.set-outputs.outputs.package-path }} runs: using: "composite" steps: - - name: Setup Certificate - id: setup-cert - shell: bash - env: - CERTIFICATE_BASE64: ${{ inputs.certificate-base64 }} - CERTIFICATE_PASSWORD: ${{ inputs.certificate-password }} - APPLE_TEAM_ID: ${{ inputs.team-id }} + - name: Setup debug environment run: | - echo "๐Ÿ” Setting up certificate..." - - # Create a temporary directory for certificates - CERT_DIR="$HOME/certificates" - mkdir -p "$CERT_DIR" - - # Decode the certificate to a p12 file - echo "$CERTIFICATE_BASE64" | base64 --decode > "$CERT_DIR/certificate.p12" - - # Create keychain - KEYCHAIN_PATH="$CERT_DIR/app-signing.keychain-db" - KEYCHAIN_PASSWORD="temppassword123" - - # Delete existing keychain if it exists - security delete-keychain "$KEYCHAIN_PATH" 2>/dev/null || true - - # Create new keychain - security create-keychain -p "$KEYCHAIN_PASSWORD" "$KEYCHAIN_PATH" - security set-keychain-settings -t 3600 -u -l "$KEYCHAIN_PATH" - security unlock-keychain -p "$KEYCHAIN_PASSWORD" "$KEYCHAIN_PATH" - - # Add to search list and make default - security list-keychains -d user -s "$KEYCHAIN_PATH" $(security list-keychains -d user | tr -d '"') - security default-keychain -s "$KEYCHAIN_PATH" - - # Import certificate - echo "๐Ÿ”‘ Importing developer certificate..." - security import "$CERT_DIR/certificate.p12" -k "$KEYCHAIN_PATH" -P "$CERTIFICATE_PASSWORD" -T /usr/bin/codesign - - # Try with additional parameters if needed - security import "$CERT_DIR/certificate.p12" -k "$KEYCHAIN_PATH" -P "$CERTIFICATE_PASSWORD" -T /usr/bin/codesign -f pkcs12 || true - - # Set partition list for codesign to access keychain - security set-key-partition-list -S apple-tool:,apple:,codesign: -s -k "$KEYCHAIN_PASSWORD" "$KEYCHAIN_PATH" - - # Verify certificate - echo "๐Ÿ” Verifying code signing identities..." - security find-identity -v -p codesigning "$KEYCHAIN_PATH" - - # Try to use the System keychain as a fallback - echo "๐Ÿ” Checking system keychain for code signing identities..." - SYSTEM_IDENTITIES=$(security find-identity -v -p codesigning) - echo "$SYSTEM_IDENTITIES" - - if echo "$SYSTEM_IDENTITIES" | grep -q "Developer ID Application"; then - echo "โœ… Found Developer ID Application certificate in system keychain" - echo "::set-output name=use_system_cert::true" - else - echo "::set-output name=use_system_cert::false" + # Create debug directory if env variable is set + if [[ -n "$DEBUG_LOG_PATH" ]]; then + mkdir -p "$(dirname "$DEBUG_LOG_PATH")" + touch "$DEBUG_LOG_PATH" + echo "Debug logging enabled to: $DEBUG_LOG_PATH" | tee -a "$DEBUG_LOG_PATH" fi - # Store keychain variables for later steps - echo "KEYCHAIN_PATH=$KEYCHAIN_PATH" >> $GITHUB_ENV + # Define a debug function + debug_log() { + echo "DEBUG: $1" + if [[ -n "$DEBUG_LOG_PATH" ]]; then + echo "$(date '+%Y-%m-%d %H:%M:%S') - $1" >> "$DEBUG_LOG_PATH" + fi + } + # Export the function for use in subsequent steps + export -f debug_log + + debug_log "Starting macOS notarize action" + debug_log "App path: ${{ inputs.app-path }}" + debug_log "Team ID: ${{ inputs.team-id }}" + debug_log "Notarization method: ${{ inputs.notarization-method }}" + debug_log "Bundle ID: ${{ inputs.bundle-id }}" + shell: bash + + - name: Set up variables + id: setup + run: | + # Debugging info + debug_log "Setting up variables" + + # Generate unique name for keychain + KEYCHAIN_NAME="build-keychain-$(uuidgen)" + KEYCHAIN_PASSWORD="$(uuidgen)" + echo "KEYCHAIN_NAME=$KEYCHAIN_NAME" >> $GITHUB_ENV echo "KEYCHAIN_PASSWORD=$KEYCHAIN_PASSWORD" >> $GITHUB_ENV - echo "APPLE_TEAM_ID=$APPLE_TEAM_ID" >> $GITHUB_ENV - # Clean up - rm -f "$CERT_DIR/certificate.p12" + # Set paths + echo "APP_PATH=${{ inputs.app-path }}" >> $GITHUB_ENV - - name: Sign App - id: sign - shell: bash - run: | - echo "๐Ÿ” Signing app with Developer ID certificate..." + # Generate working directory for temp files + WORK_DIR="$(mktemp -d)" + echo "WORK_DIR=$WORK_DIR" >> $GITHUB_ENV - # Check if app path exists - if [ ! -d "${{ inputs.app-path }}" ]; then - echo "โŒ App bundle not found at ${{ inputs.app-path }}" - echo "::set-output name=signed::none" - exit 1 - fi - - # Check if entitlements file exists - if [ ! -f "${{ inputs.entitlements-file }}" ]; then - echo "โŒ Entitlements file not found at ${{ inputs.entitlements-file }}" - echo "::set-output name=signed::none" - exit 1 - fi - - # Decide which keychain to use - if [ "${{ steps.setup-cert.outputs.use_system_cert }}" = "true" ]; then - echo "Using system keychain identity" - # Get certificate hash instead of name to avoid ambiguity - IDENTITY_HASH=$(security find-identity -v -p codesigning | grep "Developer ID Application" | head -1 | awk '{print $2}') - echo "Using certificate hash: $IDENTITY_HASH" + # Set bundle id (from input or extract from app) + if [[ -n "${{ inputs.bundle-id }}" ]]; then + BUNDLE_ID="${{ inputs.bundle-id }}" else - # Make sure keychain is unlocked - security unlock-keychain -p "$KEYCHAIN_PASSWORD" "$KEYCHAIN_PATH" - echo "Using custom keychain identity" - # Get certificate hash instead of name to avoid ambiguity - IDENTITY_HASH=$(security find-identity -v -p codesigning "$KEYCHAIN_PATH" | grep "Developer ID Application" | head -1 | awk '{print $2}') - echo "Using certificate hash: $IDENTITY_HASH" + BUNDLE_ID=$(/usr/libexec/PlistBuddy -c "Print :CFBundleIdentifier" "${{ inputs.app-path }}/Contents/Info.plist") + fi + echo "BUNDLE_ID=$BUNDLE_ID" >> $GITHUB_ENV + + # Get app name from bundle path + APP_NAME=$(basename "${{ inputs.app-path }}" .app) + echo "APP_NAME=$APP_NAME" >> $GITHUB_ENV + + # Set output directory + OUTPUT_DIR="$(pwd)/PackagedReleases" + mkdir -p "$OUTPUT_DIR" + echo "OUTPUT_DIR=$OUTPUT_DIR" >> $GITHUB_ENV + + # Set package paths + ZIP_PATH="$OUTPUT_DIR/${APP_NAME}.zip" + DMG_PATH="$OUTPUT_DIR/${APP_NAME}.dmg" + echo "ZIP_PATH=$ZIP_PATH" >> $GITHUB_ENV + echo "DMG_PATH=$DMG_PATH" >> $GITHUB_ENV + + # Set notarization variables based on method + if [[ "${{ inputs.notarization-method }}" == "api-key" ]]; then + echo "Using API key method for notarization" + + # Create API key file + API_KEY_FILE="$WORK_DIR/api_key.p8" + echo "${{ inputs.notary-api-key-path }}" | base64 --decode > "$API_KEY_FILE" + echo "API_KEY_FILE=$API_KEY_FILE" >> $GITHUB_ENV + + # Verify API key file exists + if [[ ! -f "$API_KEY_FILE" ]]; then + debug_log "ERROR: API key file could not be created" + exit 1 + fi + + debug_log "API key file created at: $API_KEY_FILE" + debug_log "API key ID: ${{ inputs.notary-api-key-id }}" + debug_log "API key issuer ID: ${{ inputs.notary-api-key-issuer-id }}" + else + echo "Using app-specific password method for notarization" + debug_log "Apple ID: ${{ inputs.apple-id }}" + fi + shell: bash + + - name: Setup keychain + id: setup-keychain + run: | + debug_log "Setting up keychain" + + # Create temporary keychain + security create-keychain -p "$KEYCHAIN_PASSWORD" "$KEYCHAIN_NAME" + security default-keychain -s "$KEYCHAIN_NAME" + security unlock-keychain -p "$KEYCHAIN_PASSWORD" "$KEYCHAIN_NAME" + security set-keychain-settings -t 3600 -u "$KEYCHAIN_NAME" + + # Create certificate file + CERTIFICATE_PATH="$WORK_DIR/certificate.p12" + echo "${{ inputs.certificate-base64 }}" | base64 --decode > "$CERTIFICATE_PATH" + + # Add to keychain + debug_log "Importing certificate into keychain" + security import "$CERTIFICATE_PATH" -k "$KEYCHAIN_NAME" -P "${{ inputs.certificate-password }}" -T /usr/bin/codesign + + # Allow codesign to access keychain items + security set-key-partition-list -S apple-tool:,apple:,codesign: -s -k "$KEYCHAIN_PASSWORD" "$KEYCHAIN_NAME" + + # Verify certificate was imported + security find-identity -v "$KEYCHAIN_NAME" | grep "Developer ID Application" + IDENTITY_RESULT=$? + + if [ $IDENTITY_RESULT -eq 0 ]; then + debug_log "Certificate imported successfully" + SIGNING_IDENTITY="Developer ID Application: ${{ inputs.team-id }}" + echo "SIGNING_IDENTITY=$SIGNING_IDENTITY" >> $GITHUB_ENV + echo "CERTIFICATE_AVAILABLE=true" >> $GITHUB_ENV + else + debug_log "WARNING: No Developer ID Application certificate found" + if [[ "${{ inputs.fallback-to-adhoc }}" == "true" ]]; then + debug_log "Falling back to ad-hoc signing" + echo "CERTIFICATE_AVAILABLE=adhoc" >> $GITHUB_ENV + else + debug_log "Not falling back to ad-hoc signing as specified" + echo "CERTIFICATE_AVAILABLE=false" >> $GITHUB_ENV + fi + fi + shell: bash + + - name: Sign application + id: sign-app + run: | + debug_log "Starting application signing process" + + # Check if certificate is available + if [[ "$CERTIFICATE_AVAILABLE" == "false" ]]; then + debug_log "No certificate available and fallback disabled. Skipping signing." + echo "SIGNING_RESULT=none" >> $GITHUB_ENV + exit 0 fi - if [ -z "$IDENTITY_HASH" ]; then - echo "โŒ No valid Developer ID Application certificate found" + # Sign the app + if [[ "$CERTIFICATE_AVAILABLE" == "true" ]]; then + debug_log "Signing with Developer ID certificate" - if [ "${{ inputs.fallback-to-adhoc }}" = "true" ]; then - echo "Falling back to ad-hoc signing for testing..." - # Use ad-hoc identity as fallback - codesign --force --deep --verbose --options runtime --entitlements "${{ inputs.entitlements-file }}" --sign - --timestamp "${{ inputs.app-path }}" - echo "::set-output name=signed::adhoc" + # First remove existing signatures + debug_log "Removing existing signatures..." + codesign --remove-signature "$APP_PATH" || true + + # Sign all dynamic libraries and frameworks + debug_log "Signing embedded binaries and frameworks..." + find "$APP_PATH/Contents/MacOS" -type f -name "*.dylib" -exec codesign --force --timestamp --options runtime --entitlements "$ENTITLEMENTS_PATH" --sign "$SIGNING_IDENTITY" {} \; + find "$APP_PATH/Contents/Frameworks" -type f -depth 1 -exec codesign --force --timestamp --options runtime --entitlements "$ENTITLEMENTS_PATH" --sign "$SIGNING_IDENTITY" {} \; + find "$APP_PATH/Contents/Frameworks" -name "*.framework" -exec codesign --force --timestamp --options runtime --entitlements "$ENTITLEMENTS_PATH" --sign "$SIGNING_IDENTITY" {} \; + + # Sign all executables + debug_log "Signing executables..." + find "$APP_PATH/Contents/MacOS" -type f -exec codesign --force --timestamp --options runtime --entitlements "$ENTITLEMENTS_PATH" --sign "$SIGNING_IDENTITY" {} \; + + # Sign app bundle + debug_log "Signing main app bundle..." + codesign --force --timestamp --options runtime --entitlements "$ENTITLEMENTS_PATH" --sign "$SIGNING_IDENTITY" "$APP_PATH" + + SIGN_RESULT=$? + if [ $SIGN_RESULT -eq 0 ]; then + debug_log "App signed successfully with Developer ID" + echo "SIGNING_RESULT=true" >> $GITHUB_ENV else - echo "Skipping signing. Set fallback-to-adhoc=true to use ad-hoc signing instead." - echo "::set-output name=signed::none" + debug_log "App signing failed with Developer ID" + echo "SIGNING_RESULT=false" >> $GITHUB_ENV + exit 1 + fi + + elif [[ "$CERTIFICATE_AVAILABLE" == "adhoc" ]]; then + debug_log "Signing with ad-hoc identity (not suitable for distribution)" + + # Remove existing signatures + codesign --remove-signature "$APP_PATH" || true + + # Sign with ad-hoc identity + codesign --force --timestamp --options runtime --entitlements "$ENTITLEMENTS_PATH" --sign - "$APP_PATH" + + SIGN_RESULT=$? + if [ $SIGN_RESULT -eq 0 ]; then + debug_log "App signed successfully with ad-hoc identity" + echo "SIGNING_RESULT=ad-hoc" >> $GITHUB_ENV + else + debug_log "App signing failed with ad-hoc identity" + echo "SIGNING_RESULT=false" >> $GITHUB_ENV exit 1 fi else - echo "Signing app bundle with Developer ID hash: $IDENTITY_HASH" - - # Enhanced deep recursive signing for all binaries - echo "๐Ÿ” Performing deep recursive signing of all components..." - - # First, find all .dylib files and sign them individually - echo "Signing all dynamic libraries (.dylib files)..." - find "${{ inputs.app-path }}" -name "*.dylib" | while read -r dylib; do - echo "Signing: $dylib" - codesign --force --verbose --options runtime --entitlements "${{ inputs.entitlements-file }}" --sign "$IDENTITY_HASH" --timestamp "$dylib" || echo "โš ๏ธ Failed to sign: $dylib" - done - - # Sign all .so files - echo "Signing all shared objects (.so files)..." - find "${{ inputs.app-path }}" -name "*.so" | while read -r so; do - echo "Signing: $so" - codesign --force --verbose --options runtime --entitlements "${{ inputs.entitlements-file }}" --sign "$IDENTITY_HASH" --timestamp "$so" || echo "โš ๏ธ Failed to sign: $so" - done - - # Sign all executable files (files with execute permission) - echo "Signing all executable files..." - find "${{ inputs.app-path }}" -type f -perm +111 -not -path "*.framework/*" -not -name "*.dylib" -not -name "*.so" | while read -r exe; do - echo "Signing executable: $exe" - codesign --force --verbose --options runtime --entitlements "${{ inputs.entitlements-file }}" --sign "$IDENTITY_HASH" --timestamp "$exe" || echo "โš ๏ธ Failed to sign: $exe" - done - - # Sign all frameworks - echo "Signing frameworks..." - find "${{ inputs.app-path }}" -path "*.framework" -type d | while read -r framework; do - echo "Signing framework: $framework" - codesign --force --verbose --options runtime --entitlements "${{ inputs.entitlements-file }}" --sign "$IDENTITY_HASH" --timestamp "$framework" || echo "โš ๏ธ Failed to sign: $framework" - done - - # Special handling for CrashReportClient.app - CRASH_REPORTER=$(find "${{ inputs.app-path }}" -path "*CrashReportClient.app" -type d | head -1) - if [ -n "$CRASH_REPORTER" ]; then - echo "๐Ÿ” Special handling for CrashReportClient.app: $CRASH_REPORTER" - # Sign CrashReportClient.app specifically with focus on hardened runtime - find "$CRASH_REPORTER" -type f -perm +111 | while read -r crash_bin; do - echo "Signing CrashReportClient binary: $crash_bin" - codesign --force --verbose --options runtime --entitlements "${{ inputs.entitlements-file }}" --sign "$IDENTITY_HASH" --timestamp "$crash_bin" || echo "โš ๏ธ Failed to sign: $crash_bin" - done - - echo "Signing the CrashReportClient.app bundle itself..." - codesign --force --deep --verbose --options runtime --entitlements "${{ inputs.entitlements-file }}" --sign "$IDENTITY_HASH" --timestamp "$CRASH_REPORTER" || echo "โš ๏ธ Failed to sign CrashReportClient.app" - fi - - # Sign any other nested app bundles - find "${{ inputs.app-path }}" -path "*.app" -type d | grep -v CrashReportClient | while read -r nested_app; do - if [ "$nested_app" != "${{ inputs.app-path }}" ]; then - echo "Signing nested app: $nested_app" - codesign --force --deep --verbose --options runtime --entitlements "${{ inputs.entitlements-file }}" --sign "$IDENTITY_HASH" --timestamp "$nested_app" || echo "โš ๏ธ Failed to sign: $nested_app" - fi - done - - # Final signing of the main bundle - echo "๐Ÿ” Performing final signing of the main app bundle..." - codesign --force --deep --verbose --options runtime --entitlements "${{ inputs.entitlements-file }}" --sign "$IDENTITY_HASH" --timestamp "${{ inputs.app-path }}" - echo "::set-output name=signed::identity" + debug_log "Unexpected certificate state. Skipping signing." + echo "SIGNING_RESULT=none" >> $GITHUB_ENV fi # Verify signing - echo "๐Ÿ” Verifying signature..." - codesign -vvv --deep --strict "${{ inputs.app-path }}" - - # Check entitlements - echo "๐Ÿ” Checking entitlements..." - codesign -d --entitlements - "${{ inputs.app-path }}" - - # Verify CrashReportClient - CRASH_REPORTER=$(find "${{ inputs.app-path }}" -path "*CrashReportClient.app" -type d | head -1) - if [ -n "$CRASH_REPORTER" ]; then - echo "๐Ÿ” Verifying CrashReportClient signature..." - codesign -vvv --deep --strict "$CRASH_REPORTER" || echo "โš ๏ธ CrashReportClient may have verification issues" - - echo "CrashReportClient entitlements:" - codesign -d --entitlements - "$CRASH_REPORTER" || echo "โš ๏ธ Could not display CrashReportClient entitlements" - fi - - - name: Notarize App - id: notarize - if: steps.sign.outputs.signed != 'none' + debug_log "Verifying app signature..." + codesign -dvv "$APP_PATH" shell: bash - env: - APPLE_ID: ${{ inputs.notary-user }} - APP_PASSWORD: ${{ inputs.notary-password }} - API_KEY_ID: ${{ inputs.notary-api-key-id }} - API_ISSUER_ID: ${{ inputs.notary-api-key-issuer-id }} - API_KEY_PATH: ${{ inputs.notary-api-key-path }} + + - name: Verify notarization and stapling + id: verify-notarization + if: env.SIGNING_RESULT == 'true' run: | - echo "๐Ÿ“ค Notarizing app..." + debug_log "Verifying app signature and code requirements before notarization" - # Set default output - echo "::set-output name=notarized::false" - - # Get app name for zip file naming - APP_NAME=$(basename "${{ inputs.app-path }}" .app) - BUNDLE_ID="${{ inputs.bundle-id }}" - - # If bundle ID is not provided, try to extract from Info.plist - if [ -z "$BUNDLE_ID" ]; then - if [ -f "${{ inputs.app-path }}/Contents/Info.plist" ]; then - BUNDLE_ID=$(/usr/libexec/PlistBuddy -c "Print :CFBundleIdentifier" "${{ inputs.app-path }}/Contents/Info.plist") - echo "Extracted bundle ID: $BUNDLE_ID" - else - BUNDLE_ID="com.luckyrobots.app" - echo "Using default bundle ID: $BUNDLE_ID" - fi + # Verify code signature + codesign --verify --verbose "$APP_PATH" + if [ $? -ne 0 ]; then + debug_log "Error: App signature verification failed" + # Don't exit, just log the error + else + debug_log "App signature verification passed" fi - # Check if we're using API key notarization method - if [ "${{ inputs.notarization-method }}" = "api-key" ] && [ -n "$API_KEY_ID" ] && [ -n "$API_ISSUER_ID" ] && [ -n "$API_KEY_PATH" ]; then - echo "Using App Store Connect API key for notarization..." + # Check app for code requirements + codesign --display --requirements "$APP_PATH" + if [ $? -ne 0 ]; then + debug_log "Error: App doesn't meet requirements" + # Don't exit, just log the error + else + debug_log "App meets code requirements" + fi + shell: bash + + - name: Notarize application + id: notarize-app + if: env.SIGNING_RESULT == 'true' + run: | + debug_log "Starting notarization process" + + # Create ZIP for notarization + debug_log "Creating ZIP archive for notarization" + ditto -c -k --keepParent "$APP_PATH" "$ZIP_PATH" + if [ $? -ne 0 ]; then + debug_log "Error creating ZIP archive" + echo "NOTARIZATION_RESULT=false" >> $GITHUB_ENV + exit 1 + fi + + # Notarize the app + if [[ "${{ inputs.notarization-method }}" == "api-key" ]]; then + debug_log "Notarizing with API key method" - # Create directory for API key if API_KEY_PATH contains content - mkdir -p ~/private_keys + # Submit for notarization + debug_log "Submitting app for notarization..." + xcrun notarytool submit "$ZIP_PATH" \ + --key "$API_KEY_FILE" \ + --key-id "${{ inputs.notary-api-key-id }}" \ + --issuer "${{ inputs.notary-api-key-issuer-id }}" \ + --wait > "$WORK_DIR/notarization_output.txt" 2>&1 + + cat "$WORK_DIR/notarization_output.txt" | tee -a "$DEBUG_LOG_PATH" + + REQUEST_STATUS=$(grep -o "status: .*" "$WORK_DIR/notarization_output.txt" | cut -d ' ' -f2) - # Check if API_KEY_PATH is a path or content - if [[ "$API_KEY_PATH" == /* ]] && [ -f "$API_KEY_PATH" ]; then - # It's a path to a file - echo "Using API key from path: $API_KEY_PATH" - cp "$API_KEY_PATH" ~/private_keys/AuthKey_${API_KEY_ID}.p8 + if [[ "$REQUEST_STATUS" == "Accepted" ]]; then + debug_log "Notarization successful" + echo "NOTARIZATION_RESULT=true" >> $GITHUB_ENV else - # It contains the key content - echo "Using API key from content" - echo "$API_KEY_PATH" > ~/private_keys/AuthKey_${API_KEY_ID}.p8 + debug_log "Notarization failed or timed out" + cat "$WORK_DIR/notarization_output.txt" + echo "NOTARIZATION_RESULT=false" >> $GITHUB_ENV fi - # Create zip for notarization - ZIP_PATH="${APP_NAME}-notarize.zip" - ditto -c -k --keepParent "${{ inputs.app-path }}" "$ZIP_PATH" + else + debug_log "Notarizing with app-specific password method" - echo "Submitting for notarization with API key..." - - # First, submit without waiting for completion - SUBMIT_OUTPUT=$(xcrun notarytool submit "$ZIP_PATH" \ - --key ~/private_keys/AuthKey_${API_KEY_ID}.p8 \ - --key-id "$API_KEY_ID" \ - --issuer "$API_ISSUER_ID" 2>&1) - SUBMIT_STATUS=$? - - # Display output for debugging - echo "Notarization submission output:" - echo "$SUBMIT_OUTPUT" - echo "Submission exit status: $SUBMIT_STATUS" - - # Check if submission was successful - if [ $SUBMIT_STATUS -ne 0 ]; then - echo "โŒ Failed to submit for notarization. Exit code: $SUBMIT_STATUS" - exit 1 - fi - - # Extract submission ID for log retrieval - SUBMISSION_ID=$(echo "$SUBMIT_OUTPUT" | grep -o "id: [a-f0-9\-]*" | head -1 | cut -d ' ' -f 2) - - if [ -z "$SUBMISSION_ID" ]; then - echo "โŒ Could not extract submission ID from output. Notarization failed." - exit 1 - fi - - echo "Submission ID: $SUBMISSION_ID" - echo "Waiting for notarization to complete..." - - # Now wait for the processing to complete - COMPLETE=false - MAX_ATTEMPTS=60 # Maximum number of attempts (60 * 30 seconds = 30 minutes max) - ATTEMPT=1 - - while [ "$COMPLETE" = "false" ] && [ $ATTEMPT -le $MAX_ATTEMPTS ]; do - echo "Checking notarization status (attempt $ATTEMPT of $MAX_ATTEMPTS)..." + # Submit for notarization + debug_log "Submitting app for notarization..." + xcrun altool --notarize-app \ + --primary-bundle-id "$BUNDLE_ID" \ + --username "${{ inputs.apple-id }}" \ + --password "${{ inputs.app-password }}" \ + --file "$ZIP_PATH" \ + > "$WORK_DIR/notarization_output.txt" 2>&1 - INFO_OUTPUT=$(xcrun notarytool info "$SUBMISSION_ID" \ - --key ~/private_keys/AuthKey_${API_KEY_ID}.p8 \ - --key-id "$API_KEY_ID" \ - --issuer "$API_ISSUER_ID" 2>&1) - INFO_STATUS=$? + cat "$WORK_DIR/notarization_output.txt" | tee -a "$DEBUG_LOG_PATH" - echo "Status check output:" - echo "$INFO_OUTPUT" - - # Check if the notarization is complete - if echo "$INFO_OUTPUT" | grep -q "status: Accepted"; then - echo "โœ… Notarization completed successfully!" - COMPLETE=true - FINAL_STATUS="Accepted" - elif echo "$INFO_OUTPUT" | grep -q "status: Invalid"; then - echo "โŒ Notarization failed with status: Invalid" - COMPLETE=true - FINAL_STATUS="Invalid" - elif echo "$INFO_OUTPUT" | grep -q "status: Rejected"; then - echo "โŒ Notarization failed with status: Rejected" - COMPLETE=true - FINAL_STATUS="Rejected" - else - echo "Notarization still in progress. Waiting 30 seconds before checking again..." - sleep 30 - ATTEMPT=$((ATTEMPT + 1)) - fi - done + REQUEST_UUID=$(grep -o "RequestUUID = .*" "$WORK_DIR/notarization_output.txt" | cut -d ' ' -f3) - # Handle timeout - if [ "$COMPLETE" = "false" ]; then - echo "โŒ Notarization timed out after $MAX_ATTEMPTS attempts." - exit 1 - fi - - # Handle completed notarization - if [ "$FINAL_STATUS" = "Accepted" ]; then - # Get logs for information (even though successful) - echo "๐Ÿ“‹ Getting notarization logs for information..." - LOGS_OUTPUT=$(xcrun notarytool log "$SUBMISSION_ID" \ - --key ~/private_keys/AuthKey_${API_KEY_ID}.p8 \ - --key-id "$API_KEY_ID" \ - --issuer "$API_ISSUER_ID" 2>&1) + if [[ -n "$REQUEST_UUID" ]]; then + debug_log "Notarization request submitted, UUID: $REQUEST_UUID" - echo "==== NOTARIZATION LOG SUMMARY ====" - echo "$LOGS_OUTPUT" | head -20 - echo "==================================" + # Wait for notarization to complete + debug_log "Waiting for notarization to complete..." + TIMEOUT=30 # 30 minutes timeout + COUNT=0 + NOTARIZATION_STATUS="in progress" - # Staple the notarization ticket - echo "Stapling notarization ticket..." - xcrun stapler staple -v "${{ inputs.app-path }}" - STAPLE_STATUS=$? - - if [ $STAPLE_STATUS -eq 0 ]; then - echo "โœ… Stapling completed successfully!" + while [[ "$NOTARIZATION_STATUS" == "in progress" && $COUNT -lt $TIMEOUT ]]; do + sleep 60 - # Verify the stapling worked properly - echo "Verifying stapled ticket is properly attached..." - xcrun stapler validate -v "${{ inputs.app-path }}" + xcrun altool --notarization-info "$REQUEST_UUID" \ + --username "${{ inputs.apple-id }}" \ + --password "${{ inputs.app-password }}" \ + > "$WORK_DIR/notarization_info.txt" 2>&1 + + cat "$WORK_DIR/notarization_info.txt" | tee -a "$DEBUG_LOG_PATH" + + NOTARIZATION_STATUS=$(grep -o "Status: .*" "$WORK_DIR/notarization_info.txt" | cut -d ':' -f2 | xargs) - # Check if stapling metadata is correctly stored in xattr - echo "Checking app extended attributes..." - if command -v xattr &> /dev/null; then - xattr "${{ inputs.app-path }}" | grep -q "com.apple.provenance" || echo "โš ๏ธ Warning: com.apple.provenance attribute not found" - fi - - # Add special instructions for distribution - echo "๐Ÿ“‹ IMPORTANT DISTRIBUTION NOTE: When users download this app, they may still see Gatekeeper warnings." - echo "This happens because of the 'quarantine' extended attribute that browsers add to downloaded files." - echo "For proper distribution, consider the following options:" - echo "1. Use a DMG installer with a signed, notarized app inside" - echo "2. Add instructions for users on how to open a quarantined app (right-click > Open)" - echo "3. If distributing directly, use a distribution platform that preserves notarization tickets" - else - echo "โš ๏ธ Stapling completed with status $STAPLE_STATUS (may still be valid)" - fi - - # Verify notarization - echo "๐Ÿ” Verifying notarization..." - spctl --assess --verbose --type exec "${{ inputs.app-path }}" - - echo "::set-output name=notarized::true" - else - # Get detailed logs for failed notarization - echo "๐Ÿ“‹ Fetching detailed logs for submission ID: $SUBMISSION_ID" - LOGS_OUTPUT=$(xcrun notarytool log "$SUBMISSION_ID" \ - --key ~/private_keys/AuthKey_${API_KEY_ID}.p8 \ - --key-id "$API_KEY_ID" \ - --issuer "$API_ISSUER_ID" 2>&1) - - echo "==== DETAILED NOTARIZATION LOGS ====" - echo "$LOGS_OUTPUT" - echo "==================================" - - # Extract specific issues for easier debugging - echo "๐Ÿ” Extracting specific issues from logs..." - echo "$LOGS_OUTPUT" | grep -A 3 "issues" - - # Show current bundle ID in Info.plist - echo "๐Ÿ“‹ Current bundle ID information:" - if [ -f "${{ inputs.app-path }}/Contents/Info.plist" ]; then - echo "Info.plist content for bundle ID:" - /usr/libexec/PlistBuddy -c "Print :CFBundleIdentifier" "${{ inputs.app-path }}/Contents/Info.plist" || echo "Could not read bundle ID from Info.plist" - echo "Full Info.plist excerpt:" - plutil -p "${{ inputs.app-path }}/Contents/Info.plist" | grep -i bundle - else - echo "Info.plist not found at expected location: ${{ inputs.app-path }}/Contents/Info.plist" - fi - - # Check for mismatched bundle ID - if [ "$BUNDLE_ID" != "$(/usr/libexec/PlistBuddy -c "Print :CFBundleIdentifier" "${{ inputs.app-path }}/Contents/Info.plist" 2>/dev/null)" ]; then - echo "โš ๏ธ WARNING: Bundle ID mismatch detected between workflow and app!" - echo " - Workflow/input bundle ID: $BUNDLE_ID" - echo " - Actual app bundle ID: $(/usr/libexec/PlistBuddy -c "Print :CFBundleIdentifier" "${{ inputs.app-path }}/Contents/Info.plist" 2>/dev/null || echo "Could not read")" - echo "This mismatch could cause notarization problems." - fi - - # Check for code signature issues in internal components - echo "๐Ÿ” Checking for code signature issues in app components..." - find "${{ inputs.app-path }}" -type f -name "*.dylib" -o -name "*.so" | head -5 | while read -r lib; do - echo "Checking signature on: $lib" - codesign -vvv "$lib" || echo "โš ๏ธ Signature issue with: $lib" + debug_log "Notarization status: $NOTARIZATION_STATUS" + COUNT=$((COUNT+1)) done - echo "โŒ Notarization failed with status: $FINAL_STATUS" - exit 1 - fi - - # Clean up - rm -rf ~/private_keys - - # Fall back to App-specific password if requested - elif [ "${{ inputs.notarization-method }}" = "app-password" ] && [ -n "$APPLE_ID" ] && [ -n "$APP_PASSWORD" ] && [ -n "$APPLE_TEAM_ID" ]; then - echo "Using App-specific password for notarization..." - - # Create zip for notarization - ZIP_PATH="${APP_NAME}-notarize.zip" - ditto -c -k --keepParent "${{ inputs.app-path }}" "$ZIP_PATH" - - echo "Submitting for notarization..." - - # First, submit without waiting for completion - SUBMIT_OUTPUT=$(xcrun notarytool submit "$ZIP_PATH" \ - --apple-id "$APPLE_ID" \ - --password "$APP_PASSWORD" \ - --team-id "$APPLE_TEAM_ID" 2>&1) - SUBMIT_STATUS=$? - - # Display output for debugging - echo "Notarization submission output:" - echo "$SUBMIT_OUTPUT" - echo "Submission exit status: $SUBMIT_STATUS" - - # Check if submission was successful - if [ $SUBMIT_STATUS -ne 0 ]; then - echo "โŒ Failed to submit for notarization. Exit code: $SUBMIT_STATUS" - exit 1 - fi - - # Extract submission ID for log retrieval - SUBMISSION_ID=$(echo "$SUBMIT_OUTPUT" | grep -o "id: [a-f0-9\-]*" | head -1 | cut -d ' ' -f 2) - - if [ -z "$SUBMISSION_ID" ]; then - echo "โŒ Could not extract submission ID from output. Notarization failed." - exit 1 - fi - - echo "Submission ID: $SUBMISSION_ID" - echo "Waiting for notarization to complete..." - - # Now wait for the processing to complete - COMPLETE=false - MAX_ATTEMPTS=60 # Maximum number of attempts (60 * 30 seconds = 30 minutes max) - ATTEMPT=1 - - while [ "$COMPLETE" = "false" ] && [ $ATTEMPT -le $MAX_ATTEMPTS ]; do - echo "Checking notarization status (attempt $ATTEMPT of $MAX_ATTEMPTS)..." - - INFO_OUTPUT=$(xcrun notarytool info "$SUBMISSION_ID" \ - --apple-id "$APPLE_ID" \ - --password "$APP_PASSWORD" \ - --team-id "$APPLE_TEAM_ID" 2>&1) - INFO_STATUS=$? - - echo "Status check output:" - echo "$INFO_OUTPUT" - - # Check if the notarization is complete - if echo "$INFO_OUTPUT" | grep -q "status: Accepted"; then - echo "โœ… Notarization completed successfully!" - COMPLETE=true - FINAL_STATUS="Accepted" - elif echo "$INFO_OUTPUT" | grep -q "status: Invalid"; then - echo "โŒ Notarization failed with status: Invalid" - COMPLETE=true - FINAL_STATUS="Invalid" - elif echo "$INFO_OUTPUT" | grep -q "status: Rejected"; then - echo "โŒ Notarization failed with status: Rejected" - COMPLETE=true - FINAL_STATUS="Rejected" + if [[ "$NOTARIZATION_STATUS" == "success" ]]; then + debug_log "Notarization successful" + echo "NOTARIZATION_RESULT=true" >> $GITHUB_ENV else - echo "Notarization still in progress. Waiting 30 seconds before checking again..." - sleep 30 - ATTEMPT=$((ATTEMPT + 1)) - fi - done - - # Handle timeout - if [ "$COMPLETE" = "false" ]; then - echo "โŒ Notarization timed out after $MAX_ATTEMPTS attempts." - exit 1 - fi - - # Handle completed notarization - if [ "$FINAL_STATUS" = "Accepted" ]; then - # Get logs for information (even though successful) - echo "๐Ÿ“‹ Getting notarization logs for information..." - LOGS_OUTPUT=$(xcrun notarytool log "$SUBMISSION_ID" \ - --apple-id "$APPLE_ID" \ - --password "$APP_PASSWORD" \ - --team-id "$APPLE_TEAM_ID" 2>&1) - - echo "==== NOTARIZATION LOG SUMMARY ====" - echo "$LOGS_OUTPUT" | head -20 - echo "==================================" - - # Staple the notarization ticket - echo "Stapling notarization ticket..." - xcrun stapler staple -v "${{ inputs.app-path }}" - STAPLE_STATUS=$? - - if [ $STAPLE_STATUS -eq 0 ]; then - echo "โœ… Stapling completed successfully!" - - # Verify the stapling worked properly - echo "Verifying stapled ticket is properly attached..." - xcrun stapler validate -v "${{ inputs.app-path }}" - - # Check if stapling metadata is correctly stored in xattr - echo "Checking app extended attributes..." - if command -v xattr &> /dev/null; then - xattr "${{ inputs.app-path }}" | grep -q "com.apple.provenance" || echo "โš ๏ธ Warning: com.apple.provenance attribute not found" + debug_log "Notarization failed or timed out: $NOTARIZATION_STATUS" + if [[ -f "$WORK_DIR/notarization_info.txt" ]]; then + cat "$WORK_DIR/notarization_info.txt" fi - - # Add special instructions for distribution - echo "๐Ÿ“‹ IMPORTANT DISTRIBUTION NOTE: When users download this app, they may still see Gatekeeper warnings." - echo "This happens because of the 'quarantine' extended attribute that browsers add to downloaded files." - echo "For proper distribution, consider the following options:" - echo "1. Use a DMG installer with a signed, notarized app inside" - echo "2. Add instructions for users on how to open a quarantined app (right-click > Open)" - echo "3. If distributing directly, use a distribution platform that preserves notarization tickets" - else - echo "โš ๏ธ Stapling completed with status $STAPLE_STATUS (may still be valid)" + echo "NOTARIZATION_RESULT=false" >> $GITHUB_ENV fi - - # Verify notarization - echo "๐Ÿ” Verifying notarization..." - spctl --assess --verbose --type exec "${{ inputs.app-path }}" - - echo "::set-output name=notarized::true" else - # Get detailed logs for failed notarization - echo "๐Ÿ“‹ Fetching detailed logs for submission ID: $SUBMISSION_ID" - LOGS_OUTPUT=$(xcrun notarytool log "$SUBMISSION_ID" \ - --apple-id "$APPLE_ID" \ - --password "$APP_PASSWORD" \ - --team-id "$APPLE_TEAM_ID" 2>&1) - - echo "==== DETAILED NOTARIZATION LOGS ====" - echo "$LOGS_OUTPUT" - echo "==================================" - - # Extract specific issues for easier debugging - echo "๐Ÿ” Extracting specific issues from logs..." - echo "$LOGS_OUTPUT" | grep -A 3 "issues" - - # Show current bundle ID in Info.plist - echo "๐Ÿ“‹ Current bundle ID information:" - if [ -f "${{ inputs.app-path }}/Contents/Info.plist" ]; then - echo "Info.plist content for bundle ID:" - /usr/libexec/PlistBuddy -c "Print :CFBundleIdentifier" "${{ inputs.app-path }}/Contents/Info.plist" || echo "Could not read bundle ID from Info.plist" - echo "Full Info.plist excerpt:" - plutil -p "${{ inputs.app-path }}/Contents/Info.plist" | grep -i bundle - else - echo "Info.plist not found at expected location: ${{ inputs.app-path }}/Contents/Info.plist" - fi - - echo "โŒ Notarization failed with status: $FINAL_STATUS" - exit 1 + debug_log "Notarization submission failed, no UUID returned" + cat "$WORK_DIR/notarization_output.txt" + echo "NOTARIZATION_RESULT=false" >> $GITHUB_ENV fi - else - echo "โš ๏ธ Missing notarization credentials. Skipping notarization." - echo "For App Store Connect API key method, set these inputs:" - echo " - notarization-method: api-key" - echo " - notary-api-key-id: Your API key ID" - echo " - notary-api-key-issuer-id: Your API issuer ID" - echo " - notary-api-key-path: Path to or content of your p8 file" - echo "" - echo "For App-specific password method, set these inputs:" - echo " - notarization-method: app-password" - echo " - notary-user: Your Apple ID (email)" - echo " - notary-password: Your app-specific password" - echo " - team-id: Your Apple Developer team ID" fi - - - name: Package App - id: package - if: steps.sign.outputs.signed != 'none' shell: bash + + - name: Staple notarization ticket + id: staple-ticket + if: env.SIGNING_RESULT == 'true' && env.NOTARIZATION_RESULT == 'true' run: | - echo "๐Ÿ“ฆ Packaging signed app..." + debug_log "Stapling notarization ticket to app" - # Get app name for zip file naming - APP_NAME=$(basename "${{ inputs.app-path }}" .app) + # Staple the ticket + xcrun stapler staple "$APP_PATH" + STAPLE_RESULT=$? - if [ "${{ steps.notarize.outputs.notarized }}" = "true" ]; then - PACKAGE_SUFFIX="Signed-Notarized" - echo "Creating distribution package with notarized app..." + if [ $STAPLE_RESULT -eq 0 ]; then + debug_log "Notarization ticket stapled successfully" + echo "STAPLING_RESULT=true" >> $GITHUB_ENV + + # Verify stapling + debug_log "Verifying notarization stapling" + xcrun stapler validate "$APP_PATH" + if [ $? -eq 0 ]; then + debug_log "Stapling validation successful" + else + debug_log "Stapling validation failed, but continuing" + fi else - PACKAGE_SUFFIX="Signed" - echo "Creating distribution package with signed app..." + debug_log "Stapling failed" + echo "STAPLING_RESULT=false" >> $GITHUB_ENV + fi + shell: bash + + - name: Remove quarantine attribute + id: remove-quarantine + if: env.SIGNING_RESULT != 'none' + run: | + debug_log "Removing quarantine attribute from app" + + # Create helper script + QUARANTINE_SCRIPT="$WORK_DIR/remove_quarantine.sh" + cat > "$QUARANTINE_SCRIPT" << 'EOF' +#!/bin/bash +# Removes the quarantine attribute from app and all its contents +echo "Removing quarantine attribute from all files..." +find "$1" -exec xattr -d com.apple.quarantine {} \; 2>/dev/null || true +echo "Quarantine attributes removed" +EOF + chmod +x "$QUARANTINE_SCRIPT" + + # Remove quarantine attribute + "$QUARANTINE_SCRIPT" "$APP_PATH" + + debug_log "Quarantine attribute removal completed" + shell: bash + + - name: Package signed app + id: package-app + run: | + debug_log "Packaging the signed app" + + # Check if we should use create-dmg if available + if command -v create-dmg &> /dev/null; then + debug_log "Using create-dmg for DMG creation" + + # Create a temporary directory for DMG contents + DMG_TEMP_DIR="$WORK_DIR/dmg-contents" + mkdir -p "$DMG_TEMP_DIR" + + # Copy the app to the temporary directory + cp -R "$APP_PATH" "$DMG_TEMP_DIR/" + + # Create instructions text file + echo "Drag the application to the Applications folder to install it." > "$DMG_TEMP_DIR/README.txt" + + # Create symlink to Applications folder + ln -s /Applications "$DMG_TEMP_DIR/Applications" + + # Use create-dmg to create a more beautiful DMG + create-dmg \ + --volname "$APP_NAME" \ + --window-pos 200 120 \ + --window-size 800 400 \ + --icon-size 100 \ + --app-drop-link 600 185 \ + --icon "$APP_NAME.app" 200 185 \ + --hide-extension "$APP_NAME.app" \ + --add-file "README.txt" 400 185 \ + --no-internet-enable \ + "$DMG_PATH" \ + "$DMG_TEMP_DIR" + + DMG_CREATE_RESULT=$? + + elif command -v hdiutil &> /dev/null; then + debug_log "Using hdiutil for DMG creation" + + # Create DMG using hdiutil + hdiutil create -volname "$APP_NAME" -srcfolder "$APP_PATH" -ov -format UDZO "$DMG_PATH" + DMG_CREATE_RESULT=$? + + else + debug_log "Neither create-dmg nor hdiutil available. Cannot create DMG." + DMG_CREATE_RESULT=1 fi - # Create zip package (necessary for notarization process only) - ZIP_FILE="${APP_NAME}-${PACKAGE_SUFFIX}.zip" - ditto -c -k --keepParent "${{ inputs.app-path }}" "$ZIP_FILE" - echo "โœ… Created temporary ZIP package for notarization: $ZIP_FILE" + # Check DMG creation result + if [ $DMG_CREATE_RESULT -eq 0 ]; then + debug_log "DMG package created successfully at: $DMG_PATH" + echo "DMG_CREATED=true" >> $GITHUB_ENV + else + debug_log "DMG creation failed" + echo "DMG_CREATED=false" >> $GITHUB_ENV + fi - # Verify stapling on the app before packaging - echo "๐Ÿ” Verifying app notarization and stapling..." - xcrun stapler validate "${{ inputs.app-path }}" || echo "โš ๏ธ App stapling verification failed" - spctl -a -vvv --type exec "${{ inputs.app-path }}" || echo "โš ๏ธ App notarization verification failed" - - # Check if we can create DMG (hdiutil is available) - if command -v hdiutil &> /dev/null; then - # Create DMG package (much better for distribution) - DMG_FILE="${APP_NAME}-${PACKAGE_SUFFIX}.dmg" - echo "Creating DMG distribution package..." + # If we have a properly signed app, sign the DMG as well + if [[ "$SIGNING_RESULT" == "true" && "$DMG_CREATED" == "true" ]]; then + debug_log "Signing DMG with Developer ID certificate" + codesign --force --timestamp --sign "$SIGNING_IDENTITY" "$DMG_PATH" - # Create temporary folder for DMG contents - DMG_TMP_DIR=$(mktemp -d) - cp -R "${{ inputs.app-path }}" "$DMG_TMP_DIR/" - - # Add README with fancy formatting - cat > "$DMG_TMP_DIR/README.txt" << 'EOF' -# LuckyWorld Installation Instructions - -1. Drag the LuckyWorld application to your Applications folder -2. Double-click the "Install Helper" icon (optional - removes security warnings) -3. Enjoy! - -For technical support, contact: support@luckyrobots.com -EOF - - # Create a better helper script to remove quarantine attribute - echo "Creating helper script to remove quarantine attribute..." - mkdir -p "$DMG_TMP_DIR/scripts" - cat > "$DMG_TMP_DIR/scripts/InstallHelper.command" << 'EOF' -#!/bin/bash - -# Get the application name from the DMG -APP_NAME="LuckyWorld-Mac-Shipping.app" -APP_PATH="/Applications/$APP_NAME" - -echo "============================================" -echo "๐Ÿ” LuckyWorld Security Helper" -echo "============================================" - -if [ -d "$APP_PATH" ]; then - echo "โœ… Found $APP_NAME in Applications folder" - echo "๐Ÿงน Removing security attributes..." - xattr -dr com.apple.quarantine "$APP_PATH" - echo "โœ… Security attributes removed successfully!" - echo "๐Ÿš€ You can now launch the application normally" - osascript -e "display notification \"$APP_NAME is ready to use\" with title \"LuckyWorld Installation Complete\" subtitle \"Security attributes removed\"" -else - echo "โŒ $APP_NAME not found in Applications folder" - echo "โš ๏ธ Please drag the application to your Applications folder first" - osascript -e "display notification \"Please drag LuckyWorld to Applications folder first\" with title \"Installation Incomplete\" subtitle \"Application not found\"" - exit 1 -fi - -echo "============================================" -echo "Press any key to exit..." -read -n 1 -EOF - - # Make the script executable - chmod +x "$DMG_TMP_DIR/scripts/InstallHelper.command" - - # Create visually appealing backgrounds and icons - if [ -d "$DMG_TMP_DIR/scripts" ]; then - touch "$DMG_TMP_DIR/scripts/.keep" - fi - - # Try to use create-dmg if available, otherwise fall back to hdiutil - if command -v create-dmg &> /dev/null; then - echo "Using create-dmg for better DMG creation..." - - # Decide which keychain to use for getting identity - if [ "${{ steps.setup-cert.outputs.use_system_cert }}" = "true" ]; then - echo "Using system keychain identity" - IDENTITY_HASH=$(security find-identity -v -p codesigning | grep "Developer ID Application" | head -1 | awk '{print $2}') - else - security unlock-keychain -p "$KEYCHAIN_PASSWORD" "$KEYCHAIN_PATH" - IDENTITY_HASH=$(security find-identity -v -p codesigning "$KEYCHAIN_PATH" | grep "Developer ID Application" | head -1 | awk '{print $2}') - fi - - create-dmg \ - --volname "LuckyWorld Installer" \ - --codesign-identity "$IDENTITY_HASH" \ - --window-pos 200 120 \ - --window-size 800 400 \ - --icon-size 100 \ - --text-size 12 \ - --app-drop-link 600 170 \ - --hide-extension "$(basename "${{ inputs.app-path }}")" \ - --add-file "README.txt" 200 170 \ - --add-file "scripts/InstallHelper.command" 400 170 \ - --hide-extension "InstallHelper.command" \ - --no-internet-enable \ - "$DMG_FILE" \ - "$DMG_TMP_DIR" + if [ $? -eq 0 ]; then + debug_log "DMG signed successfully" else - # Fall back to hdiutil - hdiutil create -volname "LuckyWorld Installer" -srcfolder "$DMG_TMP_DIR" -ov -format UDZO "$DMG_FILE" + debug_log "DMG signing failed" fi - if [ -f "$DMG_FILE" ]; then - echo "โœ… Created DMG package: $DMG_FILE" + # If app was notarized, also notarize the DMG + if [[ "$NOTARIZATION_RESULT" == "true" ]]; then + debug_log "Notarizing DMG..." - # Sign the DMG with the same certificate used for the app - echo "Signing DMG file..." - - # Decide which keychain to use - if [ "${{ steps.setup-cert.outputs.use_system_cert }}" = "true" ]; then - echo "Using system keychain identity" - # Get certificate hash instead of name to avoid ambiguity - IDENTITY_HASH=$(security find-identity -v -p codesigning | grep "Developer ID Application" | head -1 | awk '{print $2}') - echo "Using certificate hash: $IDENTITY_HASH" - else - # Make sure keychain is unlocked - security unlock-keychain -p "$KEYCHAIN_PASSWORD" "$KEYCHAIN_PATH" - echo "Using custom keychain identity" - # Get certificate hash instead of name to avoid ambiguity - IDENTITY_HASH=$(security find-identity -v -p codesigning "$KEYCHAIN_PATH" | grep "Developer ID Application" | head -1 | awk '{print $2}') - echo "Using certificate hash: $IDENTITY_HASH" - fi - - if [ -n "$IDENTITY_HASH" ]; then - # Sign the DMG - codesign --force --sign "$IDENTITY_HASH" --options runtime --timestamp "$DMG_FILE" + # Notarize the DMG + if [[ "${{ inputs.notarization-method }}" == "api-key" ]]; then + debug_log "Notarizing DMG with API key method" - # Verify DMG signature - echo "Verifying DMG signature..." - codesign -vvv "$DMG_FILE" - - # Only notarize DMG if the app was successfully notarized - if [ "${{ steps.notarize.outputs.notarized }}" = "true" ]; then - echo "Notarizing DMG file..." + xcrun notarytool submit "$DMG_PATH" \ + --key "$API_KEY_FILE" \ + --key-id "${{ inputs.notary-api-key-id }}" \ + --issuer "${{ inputs.notary-api-key-issuer-id }}" \ + --wait > "$WORK_DIR/dmg_notarization_output.txt" 2>&1 - # Check if we're using API key notarization method - if [ "${{ inputs.notarization-method }}" = "api-key" ] && [ -n "$API_KEY_ID" ] && [ -n "$API_ISSUER_ID" ] && [ -n "$API_KEY_PATH" ]; then - # Use the same API key setup from the notarize step - echo "Using App Store Connect API key for DMG notarization..." - - echo "Submitting DMG for notarization..." - DMG_SUBMIT_OUTPUT=$(xcrun notarytool submit "$DMG_FILE" \ - --key ~/private_keys/AuthKey_${API_KEY_ID}.p8 \ - --key-id "$API_KEY_ID" \ - --issuer "$API_ISSUER_ID" --wait 2>&1) - - echo "DMG notarization submission output:" - echo "$DMG_SUBMIT_OUTPUT" - - # Extract DMG submission ID - DMG_SUBMISSION_ID=$(echo "$DMG_SUBMIT_OUTPUT" | grep -o "id: [a-f0-9\-]*" | head -1 | cut -d ' ' -f 2) - - if [ -n "$DMG_SUBMISSION_ID" ] && echo "$DMG_SUBMIT_OUTPUT" | grep -q "status: Accepted"; then - echo "โœ… DMG notarization completed successfully!" - - # Staple the DMG - echo "Stapling notarization ticket to DMG..." - xcrun stapler staple "$DMG_FILE" - - # Verify DMG stapling - echo "Verifying DMG stapling..." - xcrun stapler validate "$DMG_FILE" - - # Additional verification of DMG security - echo "Performing additional security verification of DMG..." - spctl --assess --verbose=4 --type open "$DMG_FILE" || echo "โš ๏ธ DMG security verification warning" - - echo "DMG is now fully signed, notarized, and stapled!" - else - echo "โš ๏ธ DMG notarization may have failed or is still in progress." - echo "The app itself is still properly notarized, but the DMG may need manual verification." - fi - elif [ "${{ inputs.notarization-method }}" = "app-password" ] && [ -n "$APPLE_ID" ] && [ -n "$APP_PASSWORD" ] && [ -n "$APPLE_TEAM_ID" ]; then - # Use App-specific password for DMG notarization - echo "Using App-specific password for DMG notarization..." - - echo "Submitting DMG for notarization..." - DMG_SUBMIT_OUTPUT=$(xcrun notarytool submit "$DMG_FILE" \ - --apple-id "$APPLE_ID" \ - --password "$APP_PASSWORD" \ - --team-id "$APPLE_TEAM_ID" --wait 2>&1) - - echo "DMG notarization submission output:" - echo "$DMG_SUBMIT_OUTPUT" - - # Extract DMG submission ID - DMG_SUBMISSION_ID=$(echo "$DMG_SUBMIT_OUTPUT" | grep -o "id: [a-f0-9\-]*" | head -1 | cut -d ' ' -f 2) - - if [ -n "$DMG_SUBMISSION_ID" ] && echo "$DMG_SUBMIT_OUTPUT" | grep -q "status: Accepted"; then - echo "โœ… DMG notarization completed successfully!" - - # Staple the DMG - echo "Stapling notarization ticket to DMG..." - xcrun stapler staple "$DMG_FILE" - - # Verify DMG stapling - echo "Verifying DMG stapling..." - xcrun stapler validate "$DMG_FILE" - - # Additional verification of DMG security - echo "Performing additional security verification of DMG..." - spctl --assess --verbose=4 --type open "$DMG_FILE" || echo "โš ๏ธ DMG security verification warning" - - echo "DMG is now fully signed, notarized, and stapled!" - else - echo "โš ๏ธ DMG notarization may have failed or is still in progress." - echo "The app itself is still properly notarized, but the DMG may need manual verification." - fi + cat "$WORK_DIR/dmg_notarization_output.txt" | tee -a "$DEBUG_LOG_PATH" + + DMG_REQUEST_STATUS=$(grep -o "status: .*" "$WORK_DIR/dmg_notarization_output.txt" | cut -d ' ' -f2) + + if [[ "$DMG_REQUEST_STATUS" == "Accepted" ]]; then + debug_log "DMG notarization successful" + + # Staple DMG + debug_log "Stapling notarization ticket to DMG" + xcrun stapler staple "$DMG_PATH" + if [ $? -eq 0 ]; then + debug_log "DMG stapling successful" else - echo "โš ๏ธ DMG not notarized due to missing credentials." - echo "The app itself is properly notarized, but the DMG is only signed." + debug_log "DMG stapling failed" fi else - echo "App was not notarized, skipping DMG notarization." + debug_log "DMG notarization failed or timed out" + cat "$WORK_DIR/dmg_notarization_output.txt" fi + else - echo "โš ๏ธ No valid identity found for DMG signing. DMG will be created but not signed." + debug_log "Notarizing DMG with app-specific password method" + + xcrun altool --notarize-app \ + --primary-bundle-id "$BUNDLE_ID.dmg" \ + --username "${{ inputs.apple-id }}" \ + --password "${{ inputs.app-password }}" \ + --file "$DMG_PATH" \ + > "$WORK_DIR/dmg_notarization_output.txt" 2>&1 + + cat "$WORK_DIR/dmg_notarization_output.txt" | tee -a "$DEBUG_LOG_PATH" + + DMG_REQUEST_UUID=$(grep -o "RequestUUID = .*" "$WORK_DIR/dmg_notarization_output.txt" | cut -d ' ' -f3) + + if [[ -n "$DMG_REQUEST_UUID" ]]; then + debug_log "DMG notarization request submitted, UUID: $DMG_REQUEST_UUID" + + # Wait for notarization to complete + debug_log "Waiting for DMG notarization to complete..." + TIMEOUT=10 # 10 minutes timeout for DMG + COUNT=0 + DMG_NOTARIZATION_STATUS="in progress" + + while [[ "$DMG_NOTARIZATION_STATUS" == "in progress" && $COUNT -lt $TIMEOUT ]]; do + sleep 60 + + xcrun altool --notarization-info "$DMG_REQUEST_UUID" \ + --username "${{ inputs.apple-id }}" \ + --password "${{ inputs.app-password }}" \ + > "$WORK_DIR/dmg_notarization_info.txt" 2>&1 + + cat "$WORK_DIR/dmg_notarization_info.txt" | tee -a "$DEBUG_LOG_PATH" + + DMG_NOTARIZATION_STATUS=$(grep -o "Status: .*" "$WORK_DIR/dmg_notarization_info.txt" | cut -d ':' -f2 | xargs) + + debug_log "DMG notarization status: $DMG_NOTARIZATION_STATUS" + COUNT=$((COUNT+1)) + done + + if [[ "$DMG_NOTARIZATION_STATUS" == "success" ]]; then + debug_log "DMG notarization successful" + + # Staple DMG + debug_log "Stapling notarization ticket to DMG" + xcrun stapler staple "$DMG_PATH" + if [ $? -eq 0 ]; then + debug_log "DMG stapling successful" + else + debug_log "DMG stapling failed" + fi + else + debug_log "DMG notarization failed or timed out: $DMG_NOTARIZATION_STATUS" + if [[ -f "$WORK_DIR/dmg_notarization_info.txt" ]]; then + cat "$WORK_DIR/dmg_notarization_info.txt" + fi + fi + else + debug_log "DMG notarization submission failed, no UUID returned" + cat "$WORK_DIR/dmg_notarization_output.txt" + fi fi - - # Use DMG as the primary package if available - echo "::set-output name=package-path::$DMG_FILE" - echo "::set-output name=zip-package-path::$ZIP_FILE" + fi + fi + + # Final verification of all distribution artifacts + debug_log "Verifying final distribution artifacts" + + # Check ZIP file + if [[ -f "$ZIP_PATH" ]]; then + ZIP_SIZE=$(du -h "$ZIP_PATH" | cut -f1) + debug_log "ZIP package size: $ZIP_SIZE" + + # Verify ZIP integrity + unzip -t "$ZIP_PATH" > /dev/null + if [ $? -eq 0 ]; then + debug_log "ZIP package integrity verified" else - echo "โš ๏ธ Failed to create DMG, falling back to ZIP package" - echo "::set-output name=package-path::$ZIP_FILE" - fi - - # Clean up temp directory - rm -rf "$DMG_TMP_DIR" - else - echo "hdiutil not available, skipping DMG creation" - echo "::set-output name=package-path::$ZIP_FILE" - fi - - # Final verification of all artifacts - echo "๐Ÿ” Final verification of all distribution artifacts..." - - if [ -f "$ZIP_FILE" ]; then - echo "Verifying ZIP package integrity..." - ditto -v -x "$ZIP_FILE" /tmp/verify_app_extraction || echo "โš ๏ธ ZIP extraction test failed" - rm -rf /tmp/verify_app_extraction - fi - - if [ -f "$DMG_FILE" ]; then - echo "Verifying DMG file signature..." - codesign -vvv "$DMG_FILE" || echo "โš ๏ธ DMG signature verification failed" - - # Check if DMG was notarized successfully - if [ "${{ steps.notarize.outputs.notarized }}" = "true" ]; then - echo "Verifying DMG stapling..." - xcrun stapler validate "$DMG_FILE" || echo "โš ๏ธ DMG stapling verification failed" + debug_log "ZIP package may be corrupted" + fi + fi + + # Check DMG file + if [[ -f "$DMG_PATH" ]]; then + DMG_SIZE=$(du -h "$DMG_PATH" | cut -f1) + debug_log "DMG package size: $DMG_SIZE" + + # Verify DMG signature if signed + if [[ "$SIGNING_RESULT" == "true" ]]; then + codesign -vvv "$DMG_PATH" 2>&1 | tee -a "$DEBUG_LOG_PATH" || debug_log "DMG signature verification failed" fi fi - - - name: Cleanup - if: always() shell: bash + + - name: Set outputs + id: set-outputs run: | - echo "๐Ÿงน Cleaning up..." - security delete-keychain "$KEYCHAIN_PATH" 2>/dev/null || true - rm -f *-notarize.zip || true - echo "โœ… Cleanup complete" \ No newline at end of file + debug_log "Setting action outputs" + + # Pass through environment variables to outputs + if [[ "$SIGNING_RESULT" == "true" ]]; then + echo "signed=true" >> $GITHUB_OUTPUT + elif [[ "$SIGNING_RESULT" == "ad-hoc" ]]; then + echo "signed=ad-hoc" >> $GITHUB_OUTPUT + else + echo "signed=none" >> $GITHUB_OUTPUT + fi + + if [[ "$NOTARIZATION_RESULT" == "true" ]]; then + echo "notarized=true" >> $GITHUB_OUTPUT + else + echo "notarized=false" >> $GITHUB_OUTPUT + fi + + echo "app-path=$APP_PATH" >> $GITHUB_OUTPUT + echo "zip-path=$ZIP_PATH" >> $GITHUB_OUTPUT + + if [[ "$DMG_CREATED" == "true" ]]; then + echo "package-path=$DMG_PATH" >> $GITHUB_OUTPUT + else + echo "package-path=$ZIP_PATH" >> $GITHUB_OUTPUT + fi + + debug_log "Action completed" + shell: bash + + - name: Clean up + if: always() + run: | + debug_log "Cleaning up" + + # Clean up keychain + if [[ -n "$KEYCHAIN_NAME" ]]; then + security delete-keychain "$KEYCHAIN_NAME" || true + debug_log "Keychain deleted" + fi + + # Clean up temporary files + if [[ -d "$WORK_DIR" ]]; then + rm -rf "$WORK_DIR" || true + debug_log "Temporary files deleted" + fi + + debug_log "Cleanup completed" + shell: bash \ No newline at end of file diff --git a/.gitea/workflows/test-macos-build.yml b/.gitea/workflows/test-macos-build.yml index 65af91e1..4c44d1fe 100644 --- a/.gitea/workflows/test-macos-build.yml +++ b/.gitea/workflows/test-macos-build.yml @@ -15,6 +15,13 @@ jobs: lfs: true fetch-depth: 0 + # Enable debug logging + - name: Enable Debug Logging + run: | + echo "ACTIONS_RUNNER_DEBUG=true" >> $GITHUB_ENV + echo "ACTIONS_STEP_DEBUG=true" >> $GITHUB_ENV + shell: bash + # Setup environment for build - name: Setup environment run: | @@ -34,6 +41,22 @@ jobs: echo "Environment setup complete" shell: bash + # Restore cache for build dependencies + - name: Restore Build Cache + id: build-cache + uses: actions/cache@v4 + with: + path: | + DerivedDataCache + Intermediate + Saved/Autosaves + Saved/Config + .unreal + key: ${{ runner.os }}-macbuild-${{ hashFiles('**/*.uproject') }}-${{ hashFiles('Config/**') }} + restore-keys: | + ${{ runner.os }}-macbuild-${{ hashFiles('**/*.uproject') }}- + ${{ runner.os }}-macbuild- + # Build for macOS - use your own build script - name: Build for macOS run: | @@ -144,7 +167,27 @@ jobs: echo "Found entitlements file: ${{ env.ENTITLEMENTS_FILE }}" fi shell: bash - + + # Save cache for next workflow run + - name: Save Build Cache + if: always() + uses: actions/cache/save@v4 + with: + path: | + DerivedDataCache + Intermediate + Saved/Autosaves + Saved/Config + .unreal + key: ${{ steps.build-cache.outputs.cache-primary-key }} + + # Create a debug log file for notarize action + - name: Create debug log directory + run: | + mkdir -p debug_logs + echo "DEBUG_LOG_PATH=$(pwd)/debug_logs/notarize_log.txt" >> $GITHUB_ENV + shell: bash + # Use the macos-notarize action to sign and notarize the app - name: Sign and Notarize macOS App uses: ./.gitea/actions/macos-notarize @@ -162,6 +205,15 @@ jobs: bundle-id: ${{ env.BUNDLE_ID }} fallback-to-adhoc: 'false' + # Upload debug logs if available + - name: Upload Debug Logs + uses: actions/upload-artifact@v3 + if: always() + with: + name: notarize-debug-logs + path: debug_logs + retention-days: 7 + # Upload only the DMG file as main distribution artifact - name: Upload Mac Distribution DMG uses: actions/upload-artifact@v3 @@ -169,7 +221,7 @@ jobs: with: name: LuckyWorld-Mac-Distribution path: ${{ steps.sign-and-notarize.outputs.package-path }} - retention-days: 30 + retention-days: 30 # Report results - name: Report Results -- 2.47.2 From 6c29eb93be09f8205b6c1ed4a8e46a95e863cfb1 Mon Sep 17 00:00:00 2001 From: Ozgur Ersoy Date: Wed, 16 Apr 2025 01:41:36 +0200 Subject: [PATCH 106/109] fix(actions): enhance macOS notarization workflow with detailed debug logging, improved variable management, and streamlined artifact handling --- .gitea/workflows/test-macos-build.yml | 525 ++++++++++++++++++++++++-- 1 file changed, 503 insertions(+), 22 deletions(-) diff --git a/.gitea/workflows/test-macos-build.yml b/.gitea/workflows/test-macos-build.yml index 4c44d1fe..65466571 100644 --- a/.gitea/workflows/test-macos-build.yml +++ b/.gitea/workflows/test-macos-build.yml @@ -188,22 +188,503 @@ jobs: echo "DEBUG_LOG_PATH=$(pwd)/debug_logs/notarize_log.txt" >> $GITHUB_ENV shell: bash - # Use the macos-notarize action to sign and notarize the app - - name: Sign and Notarize macOS App - uses: ./.gitea/actions/macos-notarize - id: sign-and-notarize - with: - app-path: ${{ env.APP_PATH }} - entitlements-file: ${{ env.ENTITLEMENTS_FILE }} - team-id: ${{ secrets.APPLE_TEAM_ID }} - certificate-base64: ${{ secrets.MACOS_CERTIFICATE }} - certificate-password: ${{ secrets.MACOS_CERTIFICATE_PWD }} - notarization-method: 'api-key' - notary-api-key-id: ${{ secrets.NOTARY_API_KEY_ID }} - notary-api-key-issuer-id: ${{ secrets.NOTARY_API_KEY_ISSUER_ID }} - notary-api-key-path: ${{ secrets.NOTARY_API_KEY_PATH }} - bundle-id: ${{ env.BUNDLE_ID }} - fallback-to-adhoc: 'false' + # Beginning of macos-notarize steps + - name: Setup debug environment + id: setup-debug-env + run: | + # Create debug directory if env variable is set + if [[ -n "$DEBUG_LOG_PATH" ]]; then + mkdir -p "$(dirname "$DEBUG_LOG_PATH")" + touch "$DEBUG_LOG_PATH" + echo "Debug logging enabled to: $DEBUG_LOG_PATH" | tee -a "$DEBUG_LOG_PATH" + fi + + # Define a debug function + debug_log() { + echo "DEBUG: $1" + if [[ -n "$DEBUG_LOG_PATH" ]]; then + echo "$(date '+%Y-%m-%d %H:%M:%S') - $1" >> "$DEBUG_LOG_PATH" + fi + } + # Export the function for use in subsequent steps + export -f debug_log + + debug_log "Starting macOS notarize action" + debug_log "App path: ${{ env.APP_PATH }}" + debug_log "Team ID: ${{ secrets.APPLE_TEAM_ID }}" + debug_log "Notarization method: api-key" + debug_log "Bundle ID: ${{ env.BUNDLE_ID }}" + shell: bash + + - name: Set up variables + id: setup + run: | + # Debugging info + debug_log "Setting up variables" + + # Generate unique name for keychain + KEYCHAIN_NAME="build-keychain-$(uuidgen)" + KEYCHAIN_PASSWORD="$(uuidgen)" + echo "KEYCHAIN_NAME=$KEYCHAIN_NAME" >> $GITHUB_ENV + echo "KEYCHAIN_PASSWORD=$KEYCHAIN_PASSWORD" >> $GITHUB_ENV + + # Set paths + echo "APP_PATH=${{ env.APP_PATH }}" >> $GITHUB_ENV + + # Generate working directory for temp files + WORK_DIR="$(mktemp -d)" + echo "WORK_DIR=$WORK_DIR" >> $GITHUB_ENV + + # Set bundle id (from input or extract from app) + if [[ -n "${{ env.BUNDLE_ID }}" ]]; then + BUNDLE_ID="${{ env.BUNDLE_ID }}" + else + BUNDLE_ID=$(/usr/libexec/PlistBuddy -c "Print :CFBundleIdentifier" "${{ env.APP_PATH }}/Contents/Info.plist") + fi + echo "BUNDLE_ID=$BUNDLE_ID" >> $GITHUB_ENV + + # Get app name from bundle path + APP_NAME=$(basename "${{ env.APP_PATH }}" .app) + echo "APP_NAME=$APP_NAME" >> $GITHUB_ENV + + # Set output directory + OUTPUT_DIR="$(pwd)/PackagedReleases" + mkdir -p "$OUTPUT_DIR" + echo "OUTPUT_DIR=$OUTPUT_DIR" >> $GITHUB_ENV + + # Set package paths + ZIP_PATH="$OUTPUT_DIR/${APP_NAME}.zip" + DMG_PATH="$OUTPUT_DIR/${APP_NAME}.dmg" + echo "ZIP_PATH=$ZIP_PATH" >> $GITHUB_ENV + echo "DMG_PATH=$DMG_PATH" >> $GITHUB_ENV + + # Set notarization variables based on method + echo "Using API key method for notarization" + + # Create API key file + API_KEY_FILE="$WORK_DIR/api_key.p8" + echo "${{ secrets.NOTARY_API_KEY_PATH }}" | base64 --decode > "$API_KEY_FILE" + echo "API_KEY_FILE=$API_KEY_FILE" >> $GITHUB_ENV + + # Verify API key file exists + if [[ ! -f "$API_KEY_FILE" ]]; then + debug_log "ERROR: API key file could not be created" + exit 1 + fi + + debug_log "API key file created at: $API_KEY_FILE" + debug_log "API key ID: ${{ secrets.NOTARY_API_KEY_ID }}" + debug_log "API key issuer ID: ${{ secrets.NOTARY_API_KEY_ISSUER_ID }}" + shell: bash + + - name: Setup keychain + id: setup-keychain + run: | + debug_log "Setting up keychain" + + # Create temporary keychain + security create-keychain -p "$KEYCHAIN_PASSWORD" "$KEYCHAIN_NAME" + security default-keychain -s "$KEYCHAIN_NAME" + security unlock-keychain -p "$KEYCHAIN_PASSWORD" "$KEYCHAIN_NAME" + security set-keychain-settings -t 3600 -u "$KEYCHAIN_NAME" + + # Create certificate file + CERTIFICATE_PATH="$WORK_DIR/certificate.p12" + echo "${{ secrets.MACOS_CERTIFICATE }}" | base64 --decode > "$CERTIFICATE_PATH" + + # Add to keychain + debug_log "Importing certificate into keychain" + security import "$CERTIFICATE_PATH" -k "$KEYCHAIN_NAME" -P "${{ secrets.MACOS_CERTIFICATE_PWD }}" -T /usr/bin/codesign + + # Allow codesign to access keychain items + security set-key-partition-list -S apple-tool:,apple:,codesign: -s -k "$KEYCHAIN_PASSWORD" "$KEYCHAIN_NAME" + + # Verify certificate was imported + security find-identity -v "$KEYCHAIN_NAME" | grep "Developer ID Application" + IDENTITY_RESULT=$? + + if [ $IDENTITY_RESULT -eq 0 ]; then + debug_log "Certificate imported successfully" + SIGNING_IDENTITY="Developer ID Application: ${{ secrets.APPLE_TEAM_ID }}" + echo "SIGNING_IDENTITY=$SIGNING_IDENTITY" >> $GITHUB_ENV + echo "CERTIFICATE_AVAILABLE=true" >> $GITHUB_ENV + else + debug_log "WARNING: No Developer ID Application certificate found" + if [[ "false" == "true" ]]; then + debug_log "Falling back to ad-hoc signing" + echo "CERTIFICATE_AVAILABLE=adhoc" >> $GITHUB_ENV + else + debug_log "Not falling back to ad-hoc signing as specified" + echo "CERTIFICATE_AVAILABLE=false" >> $GITHUB_ENV + fi + fi + shell: bash + + - name: Sign application + id: sign-app + run: | + debug_log "Starting application signing process" + + # Check if certificate is available + if [[ "$CERTIFICATE_AVAILABLE" == "false" ]]; then + debug_log "No certificate available and fallback disabled. Skipping signing." + echo "SIGNING_RESULT=none" >> $GITHUB_ENV + exit 0 + fi + + # Make sure entitlements file is defined and reset variable name + ENTITLEMENTS_PATH="${{ env.ENTITLEMENTS_FILE }}" + + # Sign the app + if [[ "$CERTIFICATE_AVAILABLE" == "true" ]]; then + debug_log "Signing with Developer ID certificate" + + # First remove existing signatures + debug_log "Removing existing signatures..." + codesign --remove-signature "$APP_PATH" || true + + # Sign all dynamic libraries and frameworks + debug_log "Signing embedded binaries and frameworks..." + find "$APP_PATH/Contents/MacOS" -type f -name "*.dylib" -exec codesign --force --timestamp --options runtime --entitlements "$ENTITLEMENTS_PATH" --sign "$SIGNING_IDENTITY" {} \; + find "$APP_PATH/Contents/Frameworks" -type f -depth 1 -exec codesign --force --timestamp --options runtime --entitlements "$ENTITLEMENTS_PATH" --sign "$SIGNING_IDENTITY" {} \; + find "$APP_PATH/Contents/Frameworks" -name "*.framework" -exec codesign --force --timestamp --options runtime --entitlements "$ENTITLEMENTS_PATH" --sign "$SIGNING_IDENTITY" {} \; + + # Sign all executables + debug_log "Signing executables..." + find "$APP_PATH/Contents/MacOS" -type f -exec codesign --force --timestamp --options runtime --entitlements "$ENTITLEMENTS_PATH" --sign "$SIGNING_IDENTITY" {} \; + + # Sign app bundle + debug_log "Signing main app bundle..." + codesign --force --timestamp --options runtime --entitlements "$ENTITLEMENTS_PATH" --sign "$SIGNING_IDENTITY" "$APP_PATH" + + SIGN_RESULT=$? + if [ $SIGN_RESULT -eq 0 ]; then + debug_log "App signed successfully with Developer ID" + echo "SIGNING_RESULT=true" >> $GITHUB_ENV + else + debug_log "App signing failed with Developer ID" + echo "SIGNING_RESULT=false" >> $GITHUB_ENV + exit 1 + fi + + elif [[ "$CERTIFICATE_AVAILABLE" == "adhoc" ]]; then + debug_log "Signing with ad-hoc identity (not suitable for distribution)" + + # Remove existing signatures + codesign --remove-signature "$APP_PATH" || true + + # Sign with ad-hoc identity + codesign --force --timestamp --options runtime --entitlements "$ENTITLEMENTS_PATH" --sign - "$APP_PATH" + + SIGN_RESULT=$? + if [ $SIGN_RESULT -eq 0 ]; then + debug_log "App signed successfully with ad-hoc identity" + echo "SIGNING_RESULT=ad-hoc" >> $GITHUB_ENV + else + debug_log "App signing failed with ad-hoc identity" + echo "SIGNING_RESULT=false" >> $GITHUB_ENV + exit 1 + fi + else + debug_log "Unexpected certificate state. Skipping signing." + echo "SIGNING_RESULT=none" >> $GITHUB_ENV + fi + + # Verify signing + debug_log "Verifying app signature..." + codesign -dvv "$APP_PATH" + shell: bash + + - name: Verify notarization and stapling + id: verify-notarization + if: env.SIGNING_RESULT == 'true' + run: | + debug_log "Verifying app signature and code requirements before notarization" + + # Verify code signature + codesign --verify --verbose "$APP_PATH" + if [ $? -ne 0 ]; then + debug_log "Error: App signature verification failed" + # Don't exit, just log the error + else + debug_log "App signature verification passed" + fi + + # Check app for code requirements + codesign --display --requirements "$APP_PATH" + if [ $? -ne 0 ]; then + debug_log "Error: App doesn't meet requirements" + # Don't exit, just log the error + else + debug_log "App meets code requirements" + fi + shell: bash + + - name: Notarize application + id: notarize-app + if: env.SIGNING_RESULT == 'true' + run: | + debug_log "Starting notarization process" + + # Create ZIP for notarization + debug_log "Creating ZIP archive for notarization" + ditto -c -k --keepParent "$APP_PATH" "$ZIP_PATH" + if [ $? -ne 0 ]; then + debug_log "Error creating ZIP archive" + echo "NOTARIZATION_RESULT=false" >> $GITHUB_ENV + exit 1 + fi + + # Notarize the app using API key method + debug_log "Notarizing with API key method" + + # Submit for notarization + debug_log "Submitting app for notarization..." + xcrun notarytool submit "$ZIP_PATH" \ + --key "$API_KEY_FILE" \ + --key-id "${{ secrets.NOTARY_API_KEY_ID }}" \ + --issuer "${{ secrets.NOTARY_API_KEY_ISSUER_ID }}" \ + --wait > "$WORK_DIR/notarization_output.txt" 2>&1 + + cat "$WORK_DIR/notarization_output.txt" | tee -a "$DEBUG_LOG_PATH" + + REQUEST_STATUS=$(grep -o "status: .*" "$WORK_DIR/notarization_output.txt" | cut -d ' ' -f2) + + if [[ "$REQUEST_STATUS" == "Accepted" ]]; then + debug_log "Notarization successful" + echo "NOTARIZATION_RESULT=true" >> $GITHUB_ENV + else + debug_log "Notarization failed or timed out" + cat "$WORK_DIR/notarization_output.txt" + echo "NOTARIZATION_RESULT=false" >> $GITHUB_ENV + fi + shell: bash + + - name: Staple notarization ticket + id: staple-ticket + if: env.SIGNING_RESULT == 'true' && env.NOTARIZATION_RESULT == 'true' + run: | + debug_log "Stapling notarization ticket to app" + + # Staple the ticket + xcrun stapler staple "$APP_PATH" + STAPLE_RESULT=$? + + if [ $STAPLE_RESULT -eq 0 ]; then + debug_log "Notarization ticket stapled successfully" + echo "STAPLING_RESULT=true" >> $GITHUB_ENV + + # Verify stapling + debug_log "Verifying notarization stapling" + xcrun stapler validate "$APP_PATH" + if [ $? -eq 0 ]; then + debug_log "Stapling validation successful" + else + debug_log "Stapling validation failed, but continuing" + fi + else + debug_log "Stapling failed" + echo "STAPLING_RESULT=false" >> $GITHUB_ENV + fi + shell: bash + + - name: Remove quarantine attribute + id: remove-quarantine + if: env.SIGNING_RESULT != 'none' + run: | + debug_log "Removing quarantine attribute from app" + + # Create helper script + QUARANTINE_SCRIPT="$WORK_DIR/remove_quarantine.sh" + cat > "$QUARANTINE_SCRIPT" << 'EOF' +#!/bin/bash +# Removes the quarantine attribute from app and all its contents +echo "Removing quarantine attribute from all files..." +find "$1" -exec xattr -d com.apple.quarantine {} \; 2>/dev/null || true +echo "Quarantine attributes removed" +EOF + chmod +x "$QUARANTINE_SCRIPT" + + # Remove quarantine attribute + "$QUARANTINE_SCRIPT" "$APP_PATH" + + debug_log "Quarantine attribute removal completed" + shell: bash + + - name: Package signed app + id: package-app + run: | + debug_log "Packaging the signed app" + + # Check if we should use create-dmg if available + if command -v create-dmg &> /dev/null; then + debug_log "Using create-dmg for DMG creation" + + # Create a temporary directory for DMG contents + DMG_TEMP_DIR="$WORK_DIR/dmg-contents" + mkdir -p "$DMG_TEMP_DIR" + + # Copy the app to the temporary directory + cp -R "$APP_PATH" "$DMG_TEMP_DIR/" + + # Create instructions text file + echo "Drag the application to the Applications folder to install it." > "$DMG_TEMP_DIR/README.txt" + + # Create symlink to Applications folder + ln -s /Applications "$DMG_TEMP_DIR/Applications" + + # Use create-dmg to create a more beautiful DMG + create-dmg \ + --volname "$APP_NAME" \ + --window-pos 200 120 \ + --window-size 800 400 \ + --icon-size 100 \ + --app-drop-link 600 185 \ + --icon "$APP_NAME.app" 200 185 \ + --hide-extension "$APP_NAME.app" \ + --add-file "README.txt" 400 185 \ + --no-internet-enable \ + "$DMG_PATH" \ + "$DMG_TEMP_DIR" + + DMG_CREATE_RESULT=$? + + elif command -v hdiutil &> /dev/null; then + debug_log "Using hdiutil for DMG creation" + + # Create DMG using hdiutil + hdiutil create -volname "$APP_NAME" -srcfolder "$APP_PATH" -ov -format UDZO "$DMG_PATH" + DMG_CREATE_RESULT=$? + + else + debug_log "Neither create-dmg nor hdiutil available. Cannot create DMG." + DMG_CREATE_RESULT=1 + fi + + # Check DMG creation result + if [ $DMG_CREATE_RESULT -eq 0 ]; then + debug_log "DMG package created successfully at: $DMG_PATH" + echo "DMG_CREATED=true" >> $GITHUB_ENV + else + debug_log "DMG creation failed" + echo "DMG_CREATED=false" >> $GITHUB_ENV + fi + + # If we have a properly signed app, sign the DMG as well + if [[ "$SIGNING_RESULT" == "true" && "$DMG_CREATED" == "true" ]]; then + debug_log "Signing DMG with Developer ID certificate" + codesign --force --timestamp --sign "$SIGNING_IDENTITY" "$DMG_PATH" + + if [ $? -eq 0 ]; then + debug_log "DMG signed successfully" + else + debug_log "DMG signing failed" + fi + + # If app was notarized, also notarize the DMG + if [[ "$NOTARIZATION_RESULT" == "true" ]]; then + debug_log "Notarizing DMG..." + + # Notarize the DMG using API key method + debug_log "Notarizing DMG with API key method" + + xcrun notarytool submit "$DMG_PATH" \ + --key "$API_KEY_FILE" \ + --key-id "${{ secrets.NOTARY_API_KEY_ID }}" \ + --issuer "${{ secrets.NOTARY_API_KEY_ISSUER_ID }}" \ + --wait > "$WORK_DIR/dmg_notarization_output.txt" 2>&1 + + cat "$WORK_DIR/dmg_notarization_output.txt" | tee -a "$DEBUG_LOG_PATH" + + DMG_REQUEST_STATUS=$(grep -o "status: .*" "$WORK_DIR/dmg_notarization_output.txt" | cut -d ' ' -f2) + + if [[ "$DMG_REQUEST_STATUS" == "Accepted" ]]; then + debug_log "DMG notarization successful" + + # Staple DMG + debug_log "Stapling notarization ticket to DMG" + xcrun stapler staple "$DMG_PATH" + if [ $? -eq 0 ]; then + debug_log "DMG stapling successful" + else + debug_log "DMG stapling failed" + fi + else + debug_log "DMG notarization failed or timed out" + cat "$WORK_DIR/dmg_notarization_output.txt" + fi + fi + fi + + # Final verification of all distribution artifacts + debug_log "Verifying final distribution artifacts" + + # Check ZIP file + if [[ -f "$ZIP_PATH" ]]; then + ZIP_SIZE=$(du -h "$ZIP_PATH" | cut -f1) + debug_log "ZIP package size: $ZIP_SIZE" + + # Verify ZIP integrity + unzip -t "$ZIP_PATH" > /dev/null + if [ $? -eq 0 ]; then + debug_log "ZIP package integrity verified" + else + debug_log "ZIP package may be corrupted" + fi + fi + + # Check DMG file + if [[ -f "$DMG_PATH" ]]; then + DMG_SIZE=$(du -h "$DMG_PATH" | cut -f1) + debug_log "DMG package size: $DMG_SIZE" + + # Verify DMG signature if signed + if [[ "$SIGNING_RESULT" == "true" ]]; then + codesign -vvv "$DMG_PATH" 2>&1 | tee -a "$DEBUG_LOG_PATH" || debug_log "DMG signature verification failed" + fi + fi + + # Set output variables + if [[ "$SIGNING_RESULT" == "true" ]]; then + echo "SIGNED_STATUS=true" >> $GITHUB_ENV + elif [[ "$SIGNING_RESULT" == "ad-hoc" ]]; then + echo "SIGNED_STATUS=ad-hoc" >> $GITHUB_ENV + else + echo "SIGNED_STATUS=none" >> $GITHUB_ENV + fi + + if [[ "$NOTARIZATION_RESULT" == "true" ]]; then + echo "NOTARIZED_STATUS=true" >> $GITHUB_ENV + else + echo "NOTARIZED_STATUS=false" >> $GITHUB_ENV + fi + + if [[ "$DMG_CREATED" == "true" ]]; then + echo "PACKAGE_PATH=$DMG_PATH" >> $GITHUB_ENV + else + echo "PACKAGE_PATH=$ZIP_PATH" >> $GITHUB_ENV + fi + shell: bash + + - name: Clean up + if: always() + run: | + debug_log "Cleaning up" + + # Clean up keychain + if [[ -n "$KEYCHAIN_NAME" ]]; then + security delete-keychain "$KEYCHAIN_NAME" || true + debug_log "Keychain deleted" + fi + + # Clean up temporary files + if [[ -d "$WORK_DIR" ]]; then + rm -rf "$WORK_DIR" || true + debug_log "Temporary files deleted" + fi + + debug_log "Cleanup completed" + shell: bash # Upload debug logs if available - name: Upload Debug Logs @@ -217,21 +698,21 @@ jobs: # Upload only the DMG file as main distribution artifact - name: Upload Mac Distribution DMG uses: actions/upload-artifact@v3 - if: steps.sign-and-notarize.outputs.notarized == 'true' && steps.sign-and-notarize.outputs.signed != 'none' + if: env.NOTARIZED_STATUS == 'true' && env.SIGNED_STATUS != 'none' with: name: LuckyWorld-Mac-Distribution - path: ${{ steps.sign-and-notarize.outputs.package-path }} + path: ${{ env.PACKAGE_PATH }} retention-days: 30 # Report results - name: Report Results run: | - echo "๐Ÿ” App signing: ${{ steps.sign-and-notarize.outputs.signed }}" - echo "๐Ÿ” App notarization: ${{ steps.sign-and-notarize.outputs.notarized }}" + echo "๐Ÿ” App signing: ${{ env.SIGNED_STATUS }}" + echo "๐Ÿ” App notarization: ${{ env.NOTARIZED_STATUS }}" - if [ "${{ steps.sign-and-notarize.outputs.signed }}" != "none" ]; then + if [ "${{ env.SIGNED_STATUS }}" != "none" ]; then echo "โœ… Packaging completed successfully!" - echo "Final package: ${{ steps.sign-and-notarize.outputs.package-path }}" + echo "Final package: ${{ env.PACKAGE_PATH }}" else echo "โš ๏ธ App was not signed - check the logs for details" fi -- 2.47.2 From 84f950685208eac1bfd8bdb812edf28e693db825 Mon Sep 17 00:00:00 2001 From: Ozgur Ersoy Date: Wed, 16 Apr 2025 01:46:11 +0200 Subject: [PATCH 107/109] fix(actions): update macOS build workflow to use actions/cache@v3 for improved caching performance --- .gitea/workflows/test-macos-build.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.gitea/workflows/test-macos-build.yml b/.gitea/workflows/test-macos-build.yml index 65466571..f8f3e803 100644 --- a/.gitea/workflows/test-macos-build.yml +++ b/.gitea/workflows/test-macos-build.yml @@ -44,7 +44,7 @@ jobs: # Restore cache for build dependencies - name: Restore Build Cache id: build-cache - uses: actions/cache@v4 + uses: actions/cache@v3 with: path: | DerivedDataCache @@ -171,7 +171,7 @@ jobs: # Save cache for next workflow run - name: Save Build Cache if: always() - uses: actions/cache/save@v4 + uses: actions/cache/save@v3 with: path: | DerivedDataCache -- 2.47.2 From 85dd25cbc0c8c2dda138e1054efe8f0612def843 Mon Sep 17 00:00:00 2001 From: Ozgur Ersoy Date: Wed, 16 Apr 2025 01:50:12 +0200 Subject: [PATCH 108/109] fix(actions): add missing newline in macOS build workflow for improved script readability --- .gitea/workflows/test-macos-build.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitea/workflows/test-macos-build.yml b/.gitea/workflows/test-macos-build.yml index f8f3e803..b5ac05b6 100644 --- a/.gitea/workflows/test-macos-build.yml +++ b/.gitea/workflows/test-macos-build.yml @@ -503,6 +503,7 @@ echo "Removing quarantine attribute from all files..." find "$1" -exec xattr -d com.apple.quarantine {} \; 2>/dev/null || true echo "Quarantine attributes removed" EOF + chmod +x "$QUARANTINE_SCRIPT" # Remove quarantine attribute -- 2.47.2 From f251e847f3e069fa3513a58d10c34677a9725ded Mon Sep 17 00:00:00 2001 From: Ozgur Ersoy Date: Wed, 16 Apr 2025 01:52:41 +0200 Subject: [PATCH 109/109] fix(actions): simplify macOS build workflow by directly executing quarantine attribute removal command --- .gitea/workflows/test-macos-build.yml | 20 ++++---------------- 1 file changed, 4 insertions(+), 16 deletions(-) diff --git a/.gitea/workflows/test-macos-build.yml b/.gitea/workflows/test-macos-build.yml index b5ac05b6..6380acd3 100644 --- a/.gitea/workflows/test-macos-build.yml +++ b/.gitea/workflows/test-macos-build.yml @@ -494,22 +494,10 @@ jobs: run: | debug_log "Removing quarantine attribute from app" - # Create helper script - QUARANTINE_SCRIPT="$WORK_DIR/remove_quarantine.sh" - cat > "$QUARANTINE_SCRIPT" << 'EOF' -#!/bin/bash -# Removes the quarantine attribute from app and all its contents -echo "Removing quarantine attribute from all files..." -find "$1" -exec xattr -d com.apple.quarantine {} \; 2>/dev/null || true -echo "Quarantine attributes removed" -EOF - - chmod +x "$QUARANTINE_SCRIPT" - - # Remove quarantine attribute - "$QUARANTINE_SCRIPT" "$APP_PATH" - - debug_log "Quarantine attribute removal completed" + # Directly run the command without creating a script file + debug_log "Removing quarantine attribute from all files..." + find "$APP_PATH" -exec xattr -d com.apple.quarantine {} \; 2>/dev/null || true + debug_log "Quarantine attributes removed" shell: bash - name: Package signed app -- 2.47.2