Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
136 changes: 70 additions & 66 deletions .github/workflows/bundle-desktop-intel.yml
Original file line number Diff line number Diff line change
Expand Up @@ -26,20 +26,7 @@ on:
required: false
default: ''
secrets:
CERTIFICATE_OSX_APPLICATION:
description: 'Certificate for macOS application signing'
required: false
CERTIFICATE_PASSWORD:
description: 'Password for the macOS certificate'
required: false
APPLE_ID:
description: 'Apple ID for notarization'
required: false
APPLE_ID_PASSWORD:
description: 'Password for the Apple ID'
required: false
APPLE_TEAM_ID:
description: 'Apple Team ID'
OSX_CODESIGN_ROLE:
required: false

name: Reusable workflow to bundle desktop app for Intel Mac
Expand All @@ -48,37 +35,14 @@ jobs:
bundle-desktop-intel:
runs-on: macos-latest
name: Bundle Desktop App on Intel macOS
permissions:
id-token: write
contents: read
steps:
# Check initial disk space
- name: Check initial disk space
run: df -h

# Validate Signing Secrets if signing is enabled
- name: Validate Signing Secrets
if: ${{ inputs.signing }}
run: |
if [[ -z "${{ secrets.CERTIFICATE_OSX_APPLICATION }}" ]]; then
echo "Error: CERTIFICATE_OSX_APPLICATION secret is required for signing."
exit 1
fi
if [[ -z "${{ secrets.CERTIFICATE_PASSWORD }}" ]]; then
echo "Error: CERTIFICATE_PASSWORD secret is required for signing."
exit 1
fi
if [[ -z "${{ secrets.APPLE_ID }}" ]]; then
echo "Error: APPLE_ID secret is required for signing."
exit 1
fi
if [[ -z "${{ secrets.APPLE_ID_PASSWORD }}" ]]; then
echo "Error: APPLE_ID_PASSWORD secret is required for signing."
exit 1
fi
if [[ -z "${{ secrets.APPLE_TEAM_ID }}" ]]; then
echo "Error: APPLE_TEAM_ID secret is required for signing."
exit 1
fi
echo "All required signing secrets are present."

- name: Checkout code
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683
with:
Expand Down Expand Up @@ -186,14 +150,6 @@ jobs:
cp temporal-service/temporal-service ui/desktop/src/bin/temporal-service
cp bin/temporal ui/desktop/src/bin/temporal

- name: Add MacOS certs for signing and notarization
if: ${{ inputs.signing }}
run: ./scripts/add-macos-cert.sh
working-directory: ui/desktop
env:
CERTIFICATE_OSX_APPLICATION: ${{ secrets.CERTIFICATE_OSX_APPLICATION }}
CERTIFICATE_PASSWORD: ${{ secrets.CERTIFICATE_PASSWORD }}

- name: Install dependencies
run: source ../../bin/activate-hermit && npm ci
working-directory: ui/desktop
Expand All @@ -209,8 +165,7 @@ jobs:
- name: Check disk space before bundling
run: df -h

- name: Make Unsigned App
if: ${{ !inputs.signing }}
- name: Build App
run: |
source ../../bin/activate-hermit
attempt=0
Expand All @@ -227,27 +182,76 @@ jobs:
fi
working-directory: ui/desktop

- name: Make Signed App
- name: Configure AWS credentials
if: ${{ inputs.signing }}
uses: aws-actions/configure-aws-credentials@e3dd6a429d7300a6a4c196c26e071d42e0343502 # v4
with:
role-to-assume: "${{ secrets.OSX_CODESIGN_ROLE }}"
aws-region: us-west-2

- name: Codesigning and Notarization
if: ${{ inputs.signing }}
run: |
source ../../bin/activate-hermit
attempt=0
max_attempts=2
until [ $attempt -ge $max_attempts ]; do
npm run bundle:intel && break
attempt=$((attempt + 1))
echo "Attempt $attempt failed. Retrying..."
sleep 5
done
if [ $attempt -ge $max_attempts ]; then
echo "Action failed after $max_attempts attempts."
set -e

echo "⬆️ uploading unsigned app"
source_job_url="https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}"
unsigned_url="s3://block-goose-artifacts-bucket-production/unsigned/goose-${GITHUB_SHA}-${{ github.run_id }}-intel.zip"

zip -q -u -r out/Goose-darwin-x64/Goose_intel_mac.zip entitlements.plist

# upload unsigned goose to transfer bucket so it can be passed to lambda
aws s3 cp --quiet out/Goose-darwin-x64/Goose_intel_mac.zip "${unsigned_url}"

# begin signing
echo "🚀 launching signing process"
aws lambda invoke \
--function-name codesign_helper \
--cli-binary-format raw-in-base64-out \
--payload "{\"source_s3_url\": \"${unsigned_url}\", \"source_job_url\": \"${source_job_url}\"}" \
response.json > /dev/null

if [ "$(jq -r .statusCode response.json)" != "200" ]; then
echo "⚠️ lambda function did not return expected status code"
exit 1
fi

build_number="$(jq -r .body.build_number response.json)"

start_time=$(date +%s)

while sleep 30; do
aws lambda invoke \
--function-name codesign_helper \
--cli-binary-format raw-in-base64-out \
--payload "{\"source_s3_url\": \"${unsigned_url}\", \"build_number\": \"${build_number}\"}" \
response.json > /dev/null

if [ "$(jq -r .statusCode response.json)" != "200" ]; then
echo "⚠️ signing request returned unexpected response code $(jq -r .statusCode response.json):"
jq . response.json
exit 1
fi

if [ "$(jq -r .body.state response.json)" == "completed" ]; then
echo "✅ signing complete ($(($(date +%s) - start_time))s)"
break
fi

if [ $(($(date +%s) - start_time)) -ge 900 ]; then
echo "⚠️ timed out ($(($(date +%s) - start_time))s)"
exit 1
fi
echo "⏲️ waiting for signing to complete ($(($(date +%s) - start_time))s)"
done

# parse lambda response
signed_url=$(jq -r .body.destination_url response.json)

# download the signed app from S3
echo "⬇️ downloading signed app"
aws s3 cp --quiet "${signed_url}" out/Goose-darwin-x64/Goose_intel_mac.zip
working-directory: ui/desktop
env:
APPLE_ID: ${{ secrets.APPLE_ID }}
APPLE_ID_PASSWORD: ${{ secrets.APPLE_ID_PASSWORD }}
APPLE_TEAM_ID: ${{ secrets.APPLE_TEAM_ID }}

- name: Final cleanup before artifact upload
run: |
Expand Down
133 changes: 69 additions & 64 deletions .github/workflows/bundle-desktop.yml
Original file line number Diff line number Diff line change
Expand Up @@ -27,20 +27,7 @@ on:
type: string
default: ''
secrets:
CERTIFICATE_OSX_APPLICATION:
description: 'Certificate for macOS application signing'
required: false
CERTIFICATE_PASSWORD:
description: 'Password for the macOS certificate'
required: false
APPLE_ID:
description: 'Apple ID for notarization'
required: false
APPLE_ID_PASSWORD:
description: 'Password for the Apple ID'
required: false
APPLE_TEAM_ID:
description: 'Apple Team ID'
OSX_CODESIGN_ROLE:
required: false

name: Reusable workflow to bundle desktop app
Expand All @@ -49,6 +36,9 @@ jobs:
bundle-desktop:
runs-on: macos-latest
name: Bundle Desktop App on macOS
permissions:
id-token: write
contents: read
steps:
# Debug information about the workflow and inputs
- name: Debug workflow info
Expand Down Expand Up @@ -78,31 +68,6 @@ jobs:
- name: Check initial disk space
run: df -h

# Validate Signing Secrets if signing is enabled
- name: Validate Signing Secrets
if: ${{ inputs.signing }}
env:
HAS_CERT: ${{ secrets.CERTIFICATE_OSX_APPLICATION != '' }}
HAS_CERT_PASS: ${{ secrets.CERTIFICATE_PASSWORD != '' }}
HAS_APPLE_ID: ${{ secrets.APPLE_ID != '' }}
HAS_APPLE_PASS: ${{ secrets.APPLE_ID_PASSWORD != '' }}
HAS_TEAM_ID: ${{ secrets.APPLE_TEAM_ID != '' }}
run: |
missing=()
[[ "${HAS_CERT}" != "true" ]] && missing+=("CERTIFICATE_OSX_APPLICATION")
[[ "${HAS_CERT_PASS}" != "true" ]] && missing+=("CERTIFICATE_PASSWORD")
[[ "${HAS_APPLE_ID}" != "true" ]] && missing+=("APPLE_ID")
[[ "${HAS_APPLE_PASS}" != "true" ]] && missing+=("APPLE_ID_PASSWORD")
[[ "${HAS_TEAM_ID}" != "true" ]] && missing+=("APPLE_TEAM_ID")

if (( ${#missing[@]} > 0 )); then
echo "Error: Missing required signing secrets:"
printf '%s\n' "${missing[@]}"
exit 1
fi

echo "All required signing secrets are present."

- name: Checkout code
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683
with:
Expand Down Expand Up @@ -224,14 +189,6 @@ jobs:
cp temporal-service/temporal-service ui/desktop/src/bin/temporal-service
cp bin/temporal ui/desktop/src/bin/temporal

- name: Add MacOS certs for signing and notarization
if: ${{ inputs.signing }}
run: ./scripts/add-macos-cert.sh
working-directory: ui/desktop
env:
CERTIFICATE_OSX_APPLICATION: ${{ secrets.CERTIFICATE_OSX_APPLICATION }}
CERTIFICATE_PASSWORD: ${{ secrets.CERTIFICATE_PASSWORD }}

- name: Install dependencies
run: source ../../bin/activate-hermit && npm ci
working-directory: ui/desktop
Expand All @@ -240,8 +197,7 @@ jobs:
- name: Check disk space before bundling
run: df -h

- name: Make Unsigned App
if: ${{ !inputs.signing }}
- name: Build App
run: |
source ../../bin/activate-hermit
attempt=0
Expand All @@ -258,26 +214,75 @@ jobs:
fi
working-directory: ui/desktop

- name: Make Signed App
- name: Configure AWS credentials
if: ${{ inputs.signing }}
uses: aws-actions/configure-aws-credentials@e3dd6a429d7300a6a4c196c26e071d42e0343502 # v4
with:
role-to-assume: "${{ secrets.OSX_CODESIGN_ROLE }}"
aws-region: us-west-2

- name: Codesigning and Notarization
if: ${{ inputs.signing }}
env:
APPLE_ID: ${{ secrets.APPLE_ID }}
APPLE_ID_PASSWORD: ${{ secrets.APPLE_ID_PASSWORD }}
APPLE_TEAM_ID: ${{ secrets.APPLE_TEAM_ID }}
run: |
set -e

attempt=0
max_attempts=2
until [ $attempt -ge $max_attempts ]; do
npm run bundle:default && break
attempt=$((attempt + 1))
echo "Attempt $attempt failed. Retrying..."
sleep 5
done
if [ $attempt -ge $max_attempts ]; then
echo "Action failed after $max_attempts attempts."
echo "⬆️ uploading unsigned app"
source_job_url="https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}"
unsigned_url="s3://block-goose-artifacts-bucket-production/unsigned/goose-${GITHUB_SHA}-${{ github.run_id }}-arm64.zip"

zip -q -u -r out/Goose-darwin-arm64/Goose.zip entitlements.plist

# upload unsigned goose to transfer bucket so it can be passed to lambda
aws s3 cp --quiet out/Goose-darwin-arm64/Goose.zip "${unsigned_url}"

# begin signing
echo "🚀 launching signing process"
aws lambda invoke \
--function-name codesign_helper \
--cli-binary-format raw-in-base64-out \
--payload "{\"source_s3_url\": \"${unsigned_url}\", \"source_job_url\": \"${source_job_url}\"}" \
response.json > /dev/null

if [ "$(jq -r .statusCode response.json)" != "200" ]; then
echo "⚠️ lambda function did not return expected status code"
exit 1
fi

build_number="$(jq -r .body.build_number response.json)"

start_time=$(date +%s)

while sleep 30; do
aws lambda invoke \
--function-name codesign_helper \
--cli-binary-format raw-in-base64-out \
--payload "{\"source_s3_url\": \"${unsigned_url}\", \"build_number\": \"${build_number}\"}" \
response.json > /dev/null

if [ "$(jq -r .statusCode response.json)" != "200" ]; then
echo "⚠️ signing request returned unexpected response code $(jq -r .statusCode response.json):"
jq . response.json
exit 1
fi

if [ "$(jq -r .body.state response.json)" == "completed" ]; then
echo "✅ signing complete ($(($(date +%s) - start_time))s)"
break
fi

if [ $(($(date +%s) - start_time)) -ge 900 ]; then
echo "⚠️ timed out ($(($(date +%s) - start_time))s)"
exit 1
fi
echo "⏲️ waiting for signing to complete ($(($(date +%s) - start_time))s)"
done

# parse lambda response
signed_url=$(jq -r .body.destination_url response.json)

# download the signed app from S3
echo "⬇️ downloading signed app"
aws s3 cp --quiet "${signed_url}" out/Goose-darwin-arm64/Goose.zip
working-directory: ui/desktop

- name: Final cleanup before artifact upload
Expand Down
14 changes: 2 additions & 12 deletions .github/workflows/canary.yml
Original file line number Diff line number Diff line change
Expand Up @@ -67,13 +67,7 @@ jobs:
uses: ./.github/workflows/bundle-desktop.yml
with:
version: ${{ needs.prepare-version.outputs.version }}
signing: true
secrets:
CERTIFICATE_OSX_APPLICATION: ${{ secrets.CERTIFICATE_OSX_APPLICATION }}
CERTIFICATE_PASSWORD: ${{ secrets.CERTIFICATE_PASSWORD }}
APPLE_ID: ${{ secrets.APPLE_ID }}
APPLE_ID_PASSWORD: ${{ secrets.APPLE_ID_PASSWORD }}
APPLE_TEAM_ID: ${{ secrets.APPLE_TEAM_ID }}
signing: false

# ------------------------------------------------------------
# 5) Bundle Desktop App (Linux) - builds goosed and Electron app
Expand All @@ -92,11 +86,7 @@ jobs:
uses: ./.github/workflows/bundle-desktop-windows.yml
with:
version: ${{ needs.prepare-version.outputs.version }}
signing: true
secrets:
WINDOWS_CODESIGN_CERTIFICATE: ${{ secrets.WINDOWS_CODESIGN_CERTIFICATE }}
WINDOW_SIGNING_ROLE: ${{ secrets.WINDOW_SIGNING_ROLE }}
WINDOW_SIGNING_ROLE_TAG: ${{ secrets.WINDOW_SIGNING_ROLE_TAG }}
signing: false

# ------------------------------------
# 7) Create/Update GitHub Release
Expand Down
Loading
Loading