diff --git a/.github/workflows/bundle-desktop-intel.yml b/.github/workflows/bundle-desktop-intel.yml index 408784a35a..3923c6575b 100644 --- a/.github/workflows/bundle-desktop-intel.yml +++ b/.github/workflows/bundle-desktop-intel.yml @@ -34,9 +34,10 @@ on: name: Reusable workflow to bundle desktop app for Intel Mac jobs: - build-desktop-intel: + bundle-desktop-intel: runs-on: macos-latest - name: Build Desktop App on Intel macOS + name: Bundle Desktop App on Intel macOS + environment: ${{ inputs.environment || '' }} env: MACOSX_DEPLOYMENT_TARGET: "12.0" permissions: @@ -119,12 +120,22 @@ jobs: jq '.build.mac.target[0].arch = "x64"' package.json > package.json.tmp && mv package.json.tmp package.json working-directory: ui/desktop + - name: Import Apple signing certificate + if: ${{ inputs.signing }} + uses: ./.github/actions/apple-codesign + with: + certificate-base64: ${{ secrets.APPLE_CERTIFICATE_BASE64 }} + certificate-password: ${{ secrets.APPLE_CERTIFICATE_PASSWORD }} + # Check disk space before bundling - name: Check disk space before bundling run: df -h - # Build without signing — signing env vars are intentionally omitted - - name: Build App (unsigned) + - name: Build App + env: + APPLE_ID: ${{ inputs.signing && secrets.APPLE_ID || '' }} + APPLE_ID_PASSWORD: ${{ inputs.signing && secrets.APPLE_ID_PASSWORD || '' }} + APPLE_TEAM_ID: ${{ inputs.signing && secrets.APPLE_TEAM_ID || '' }} run: | source ../../bin/activate-hermit attempt=0 @@ -141,6 +152,13 @@ jobs: fi working-directory: ui/desktop + - name: Clean up signing keychain + if: always() + run: | + if [ -n "$KEYCHAIN_PATH" ] && [ -f "$KEYCHAIN_PATH" ]; then + security delete-keychain "$KEYCHAIN_PATH" || true + fi + - name: Final cleanup before artifact upload run: | echo "Performing final cleanup..." @@ -149,11 +167,11 @@ jobs: # Check disk space after cleanup df -h - - name: Upload unsigned Desktop artifact + - name: Upload Desktop artifact uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0 with: - name: Goose-darwin-x64-unsigned - path: ui/desktop/out/Goose-darwin-x64/ + name: Goose-darwin-x64 + path: ui/desktop/out/Goose-darwin-x64/Goose_intel_mac.zip - name: Quick launch test (macOS) if: ${{ inputs.quick_test }} @@ -175,127 +193,3 @@ jobs: fi # Kill the app to clean up pkill -f "Goose.app/Contents/MacOS/Goose" - - sign-desktop-intel: - needs: build-desktop-intel - if: ${{ inputs.signing }} - runs-on: macos-latest - name: Sign and Notarize Desktop App (Intel macOS) - environment: ${{ inputs.environment || '' }} - permissions: - id-token: write - contents: read - steps: - - name: Checkout code - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - with: - ref: ${{ inputs.ref != '' && inputs.ref || '' }} - sparse-checkout: | - .github/actions/apple-codesign - ui/desktop/entitlements.plist - - - name: Download unsigned artifact - uses: actions/download-artifact@37930b1c2abaa49bbe596cd826c3c89aef350131 # v7.0.0 - with: - name: Goose-darwin-x64-unsigned - path: app-bundle/ - - - name: Import Apple signing certificate - uses: ./.github/actions/apple-codesign - with: - certificate-base64: ${{ secrets.APPLE_CERTIFICATE_BASE64 }} - certificate-password: ${{ secrets.APPLE_CERTIFICATE_PASSWORD }} - - - name: Setup Node.js - uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v6.2.0 - with: - node-version: 22 - - - name: Install signing tools - run: npm install @electron/osx-sign @electron/notarize - - - name: Sign app bundle - env: - KEYCHAIN_PATH: ${{ env.KEYCHAIN_PATH }} - run: | - node -e " - const { signAsync } = require('@electron/osx-sign'); - signAsync({ - app: 'app-bundle/Goose.app', - keychain: process.env.KEYCHAIN_PATH || undefined, - identity: 'Developer ID Application', - entitlements: 'ui/desktop/entitlements.plist', - entitlementsInherit: 'ui/desktop/entitlements.plist', - }).then(() => { - console.log('Code signing complete.'); - }).catch((err) => { - console.error('Code signing failed:', err); - process.exit(1); - }); - " - - - name: Verify code signature - run: | - codesign --verify --deep --strict --verbose=2 app-bundle/Goose.app - echo "Signature verification passed." - - - name: Notarize app bundle - env: - APPLE_ID: ${{ secrets.APPLE_ID }} - APPLE_ID_PASSWORD: ${{ secrets.APPLE_ID_PASSWORD }} - APPLE_TEAM_ID: ${{ secrets.APPLE_TEAM_ID }} - run: | - node -e " - const { notarize } = require('@electron/notarize'); - notarize({ - appPath: 'app-bundle/Goose.app', - appleId: process.env.APPLE_ID, - appleIdPassword: process.env.APPLE_ID_PASSWORD, - teamId: process.env.APPLE_TEAM_ID, - }).then(() => { - console.log('Notarization complete.'); - }).catch((err) => { - console.error('Notarization failed:', err); - process.exit(1); - }); - " - - - name: Staple notarization ticket - run: xcrun stapler staple app-bundle/Goose.app - - - name: Create zip for distribution - run: | - cd app-bundle - ditto -c -k --sequesterRsrc --keepParent Goose.app Goose_intel_mac.zip - - - name: Upload signed Desktop artifact - uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0 - with: - name: Goose-darwin-x64 - path: app-bundle/Goose_intel_mac.zip - - - name: Clean up signing keychain - if: always() - run: | - if [ -n "$KEYCHAIN_PATH" ] && [ -f "$KEYCHAIN_PATH" ]; then - security delete-keychain "$KEYCHAIN_PATH" || true - fi - - # When signing is disabled, publish the unsigned build with the expected artifact name - package-desktop-intel: - needs: build-desktop-intel - if: ${{ !inputs.signing }} - runs-on: ubuntu-latest - name: Package Desktop App (Intel, unsigned) - steps: - - name: Download unsigned artifact - uses: actions/download-artifact@37930b1c2abaa49bbe596cd826c3c89aef350131 # v7.0.0 - with: - name: Goose-darwin-x64-unsigned - path: app-bundle/ - - - name: Upload Desktop artifact - uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0 - with: - name: Goose-darwin-x64 - path: app-bundle/Goose_intel_mac.zip diff --git a/.github/workflows/bundle-desktop.yml b/.github/workflows/bundle-desktop.yml index 3d29e0b204..0cb3d0b019 100644 --- a/.github/workflows/bundle-desktop.yml +++ b/.github/workflows/bundle-desktop.yml @@ -36,14 +36,17 @@ on: name: Reusable workflow to bundle desktop app jobs: - build-desktop: + bundle-desktop: runs-on: macos-latest - name: Build Desktop App on macOS + name: Bundle Desktop App on macOS + environment: ${{ inputs.environment || '' }} env: MACOSX_DEPLOYMENT_TARGET: "12.0" permissions: id-token: write contents: read + outputs: + artifact-url: ${{ steps.upload-app-bundle.outputs.artifact-url }} steps: # Debug information about the workflow and inputs - name: Debug workflow info @@ -149,12 +152,22 @@ jobs: run: source ../../bin/activate-hermit && pnpm install --frozen-lockfile working-directory: ui/desktop + - name: Import Apple signing certificate + if: ${{ inputs.signing }} + uses: ./.github/actions/apple-codesign + with: + certificate-base64: ${{ secrets.APPLE_CERTIFICATE_BASE64 }} + certificate-password: ${{ secrets.APPLE_CERTIFICATE_PASSWORD }} + # Check disk space before bundling - name: Check disk space before bundling run: df -h - # Build without signing — signing env vars are intentionally omitted - - name: Build App (unsigned) + - name: Build App + env: + APPLE_ID: ${{ inputs.signing && secrets.APPLE_ID || '' }} + APPLE_ID_PASSWORD: ${{ inputs.signing && secrets.APPLE_ID_PASSWORD || '' }} + APPLE_TEAM_ID: ${{ inputs.signing && secrets.APPLE_TEAM_ID || '' }} run: | source ../../bin/activate-hermit attempt=0 @@ -171,6 +184,13 @@ jobs: fi working-directory: ui/desktop + - name: Clean up signing keychain + if: always() + run: | + if [ -n "$KEYCHAIN_PATH" ] && [ -f "$KEYCHAIN_PATH" ]; then + security delete-keychain "$KEYCHAIN_PATH" || true + fi + - name: Final cleanup before artifact upload run: | echo "Performing final cleanup..." @@ -179,12 +199,12 @@ jobs: # Check disk space after cleanup df -h - - name: Upload unsigned Desktop artifact + - name: Upload Desktop artifact id: upload-app-bundle uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0 with: - name: Goose-darwin-arm64-unsigned - path: ui/desktop/out/Goose-darwin-arm64/ + name: Goose-darwin-arm64 + path: ui/desktop/out/Goose-darwin-arm64/Goose.zip - name: Quick launch test (macOS) if: ${{ inputs.quick_test }} @@ -206,133 +226,3 @@ jobs: fi # Kill the app to clean up pkill -f "Goose.app/Contents/MacOS/Goose" - - sign-desktop: - needs: build-desktop - if: ${{ inputs.signing }} - runs-on: macos-latest - name: Sign and Notarize Desktop App on macOS - environment: ${{ inputs.environment || '' }} - permissions: - id-token: write - contents: read - outputs: - artifact-url: ${{ steps.upload-signed-bundle.outputs.artifact-url }} - steps: - - name: Checkout code - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - with: - ref: ${{ inputs.ref != '' && inputs.ref || '' }} - sparse-checkout: | - .github/actions/apple-codesign - ui/desktop/entitlements.plist - - - name: Download unsigned artifact - uses: actions/download-artifact@37930b1c2abaa49bbe596cd826c3c89aef350131 # v7.0.0 - with: - name: Goose-darwin-arm64-unsigned - path: app-bundle/ - - - name: Import Apple signing certificate - uses: ./.github/actions/apple-codesign - with: - certificate-base64: ${{ secrets.APPLE_CERTIFICATE_BASE64 }} - certificate-password: ${{ secrets.APPLE_CERTIFICATE_PASSWORD }} - - - name: Setup Node.js - uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v6.2.0 - with: - node-version: 22 - - - name: Install signing tools - run: npm install @electron/osx-sign @electron/notarize - - - name: Sign app bundle - env: - KEYCHAIN_PATH: ${{ env.KEYCHAIN_PATH }} - run: | - node -e " - const { signAsync } = require('@electron/osx-sign'); - signAsync({ - app: 'app-bundle/Goose.app', - keychain: process.env.KEYCHAIN_PATH || undefined, - identity: 'Developer ID Application', - entitlements: 'ui/desktop/entitlements.plist', - entitlementsInherit: 'ui/desktop/entitlements.plist', - }).then(() => { - console.log('Code signing complete.'); - }).catch((err) => { - console.error('Code signing failed:', err); - process.exit(1); - }); - " - - - name: Verify code signature - run: | - codesign --verify --deep --strict --verbose=2 app-bundle/Goose.app - echo "Signature verification passed." - - - name: Notarize app bundle - env: - APPLE_ID: ${{ secrets.APPLE_ID }} - APPLE_ID_PASSWORD: ${{ secrets.APPLE_ID_PASSWORD }} - APPLE_TEAM_ID: ${{ secrets.APPLE_TEAM_ID }} - run: | - node -e " - const { notarize } = require('@electron/notarize'); - notarize({ - appPath: 'app-bundle/Goose.app', - appleId: process.env.APPLE_ID, - appleIdPassword: process.env.APPLE_ID_PASSWORD, - teamId: process.env.APPLE_TEAM_ID, - }).then(() => { - console.log('Notarization complete.'); - }).catch((err) => { - console.error('Notarization failed:', err); - process.exit(1); - }); - " - - - name: Staple notarization ticket - run: xcrun stapler staple app-bundle/Goose.app - - - name: Create zip for distribution - run: | - cd app-bundle - ditto -c -k --sequesterRsrc --keepParent Goose.app Goose.zip - - - name: Upload signed Desktop artifact - id: upload-signed-bundle - uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0 - with: - name: Goose-darwin-arm64 - path: app-bundle/Goose.zip - - - name: Clean up signing keychain - if: always() - run: | - if [ -n "$KEYCHAIN_PATH" ] && [ -f "$KEYCHAIN_PATH" ]; then - security delete-keychain "$KEYCHAIN_PATH" || true - fi - - # When signing is disabled, publish the unsigned build with the expected artifact name - package-desktop: - needs: build-desktop - if: ${{ !inputs.signing }} - runs-on: ubuntu-latest - name: Package Desktop App (unsigned) - outputs: - artifact-url: ${{ steps.upload-unsigned-bundle.outputs.artifact-url }} - steps: - - name: Download unsigned artifact - uses: actions/download-artifact@37930b1c2abaa49bbe596cd826c3c89aef350131 # v7.0.0 - with: - name: Goose-darwin-arm64-unsigned - path: app-bundle/ - - - name: Upload Desktop artifact - id: upload-unsigned-bundle - uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0 - with: - name: Goose-darwin-arm64 - path: app-bundle/Goose.zip