From 5e18344296ab25849d9912dcf82e58a30a98b882 Mon Sep 17 00:00:00 2001 From: Dan Rosser Date: Mon, 14 Sep 2026 15:55:25 +1000 Subject: [PATCH 1/2] Fix macOS notarization to use the current signing identity's team CERTIFICATE_OSX_APPLICATION was rotated to a new Developer ID Application certificate (the previous one expired, see #646), but ci_build_pg.sh still hardcoded the old certificate holder's Team ID and Apple ID for xcrun notarytool. Since notarization requires --team-id to match the team that issued the signing certificate, this would have submitted a build signed under one identity's team while authenticating as a different one, and notarization would fail. Reads TEAM_ID from a new CERTIFCATE_TEAM_ID secret and APPLE_ID from the already-updated GA_APPLE_USERNAME secret instead, in both the active package_app() path and the unreachable-but-should-stay- consistent sign_and_upload() path. --- .github/workflows/build-macos.yml | 1 + scripts/osx/ci_build_pg.sh | 6 +++--- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/.github/workflows/build-macos.yml b/.github/workflows/build-macos.yml index b7b6d971..1622ef2e 100644 --- a/.github/workflows/build-macos.yml +++ b/.github/workflows/build-macos.yml @@ -111,6 +111,7 @@ jobs: GA_CI_SECRET: ${{ secrets.CI_SECRET }} CERTIFICATE_OSX_APPLICATION: ${{ secrets.CERTIFICATE_OSX_APPLICATION }} CERTIFICATE_PASSWORD: ${{ secrets.CERTIFICATE_PASSWORD }} + CERTIFCATE_TEAM_ID: ${{ secrets.CERTIFCATE_TEAM_ID }} GA_APPLE_USERNAME: ${{ secrets.GA_APPLE_USERNAME }} GA_APPLE_PASS: ${{ secrets.GA_APPLE_PASS }} GA_NOTARIZE_PROVIDER: ${{ secrets.GA_NOTARIZE_PROVIDER }} diff --git a/scripts/osx/ci_build_pg.sh b/scripts/osx/ci_build_pg.sh index 522ab54f..30b24a12 100755 --- a/scripts/osx/ci_build_pg.sh +++ b/scripts/osx/ci_build_pg.sh @@ -116,8 +116,8 @@ package_app(){ echo "cd to ${PG_DIR}" cd ${PG_DIR} - TEAM_ID="HC25N2E7UT" - APPLE_ID="theo@theowatson.com" + TEAM_ID="${CERTIFCATE_TEAM_ID}" + APPLE_ID="${GA_APPLE_USERNAME}" # echo "--identity=3rd Party Mac Developer Application: ${APPLE_ID} (${TEAM_ID})" if [[ ("${TRAVIS_REPO_SLUG}/${TRAVIS_BRANCH}" == "openframeworks/projectGenerator/master" || "${TRAVIS_REPO_SLUG}/${TRAVIS_BRANCH}" == "openframeworks/projectGenerator/bleeding") && "$TRAVIS_PULL_REQUEST" == "false" ]] || [[ ("${GITHUB_REF##*/}" == "master" || "${GITHUB_REF##*/}" == "bleeding") && -z "${GITHUB_HEAD_REF}" ]] ; then @@ -169,7 +169,7 @@ sign_and_upload(){ # need to upload zip of just app to apple for notarizing zip --symlinks -r -q projectGenerator-$PLATFORM/projectGenerator.app.zip projectGenerator-$PLATFORM/projectGenerator.app # xcrun altool --notarize-app --primary-bundle-id "com.electron.projectgenerator" --username "${GA_APPLE_USERNAME}" -p "${GA_APPLE_PASS}" --asc-provider "${GA_NOTARIZE_PROVIDER}" --file projectGenerator-$PLATFORM/projectGenerator.app.zip - TEAM_ID="HC25N2E7UT" + TEAM_ID="${CERTIFCATE_TEAM_ID}" xcrun notarytool submit "projectGenerator-${PLATFORM}/projectGenerator-${PLATFORM}.app.zip" --apple-id "${GA_APPLE_USERNAME}" --team-id "${TEAM_ID}" --password "${GA_APPLE_PASS}" # Upload to OF CI server From ba547da65d4507c37502675d8527172073bb011b Mon Sep 17 00:00:00 2001 From: Dan Rosser Date: Mon, 14 Sep 2026 16:11:11 +1000 Subject: [PATCH 2/2] Switch macOS notarization to an App Store Connect API key Apple ID + app-specific password ties CI notarization to a personal account's credentials, which need re-issuing every time the account holder changes (as just happened rotating away from the expired Theo Watson certificate). An App Store Connect API key is decoupled from any individual Apple ID, scoped to just the Developer role, and revocable independently of anyone's personal account. Adds setup_notarization_key(), which writes the raw .p8 key contents (APPLE_API_KEY_P8 - GitHub secrets preserve multi-line values as-is, so no base64 step is needed) to a file for notarytool's --key flag, and switches both notarytool submit call sites from --apple-id/--team-id/--password to --key/--key-id/--issuer. GA_APPLE_USERNAME/GA_APPLE_PASS/CERTIFCATE_TEAM_ID are no longer read by any active code path after this - left as-is in the workflow env block rather than removed, since deleting secrets/wiring wasn't the point of this change. --- .github/workflows/build-macos.yml | 3 +++ scripts/osx/ci_build_pg.sh | 31 +++++++++++++++++++++++++------ 2 files changed, 28 insertions(+), 6 deletions(-) diff --git a/.github/workflows/build-macos.yml b/.github/workflows/build-macos.yml index 1622ef2e..4b48c4bb 100644 --- a/.github/workflows/build-macos.yml +++ b/.github/workflows/build-macos.yml @@ -112,6 +112,9 @@ jobs: CERTIFICATE_OSX_APPLICATION: ${{ secrets.CERTIFICATE_OSX_APPLICATION }} CERTIFICATE_PASSWORD: ${{ secrets.CERTIFICATE_PASSWORD }} CERTIFCATE_TEAM_ID: ${{ secrets.CERTIFCATE_TEAM_ID }} + APPLE_API_KEY_P8: ${{ secrets.APPLE_API_KEY_P8 }} + APPLE_API_KEY_ID: ${{ secrets.APPLE_API_KEY_ID }} + APPLE_API_ISSUER_ID: ${{ secrets.APPLE_API_ISSUER_ID }} GA_APPLE_USERNAME: ${{ secrets.GA_APPLE_USERNAME }} GA_APPLE_PASS: ${{ secrets.GA_APPLE_PASS }} GA_NOTARIZE_PROVIDER: ${{ secrets.GA_NOTARIZE_PROVIDER }} diff --git a/scripts/osx/ci_build_pg.sh b/scripts/osx/ci_build_pg.sh index 30b24a12..1e9f920b 100755 --- a/scripts/osx/ci_build_pg.sh +++ b/scripts/osx/ci_build_pg.sh @@ -116,9 +116,6 @@ package_app(){ echo "cd to ${PG_DIR}" cd ${PG_DIR} - TEAM_ID="${CERTIFCATE_TEAM_ID}" - APPLE_ID="${GA_APPLE_USERNAME}" - # echo "--identity=3rd Party Mac Developer Application: ${APPLE_ID} (${TEAM_ID})" if [[ ("${TRAVIS_REPO_SLUG}/${TRAVIS_BRANCH}" == "openframeworks/projectGenerator/master" || "${TRAVIS_REPO_SLUG}/${TRAVIS_BRANCH}" == "openframeworks/projectGenerator/bleeding") && "$TRAVIS_PULL_REQUEST" == "false" ]] || [[ ("${GITHUB_REF##*/}" == "master" || "${GITHUB_REF##*/}" == "bleeding") && -z "${GITHUB_HEAD_REF}" ]] ; then electron-osx-sign projectGenerator-$PLATFORM/projectGenerator.app --platform=darwin --type=distribution --no-gatekeeper-assess --hardened-runtime --entitlements=scripts/osx/PG.entitlements --entitlements-inherit=scripts/osx/PG.entitlements @@ -129,7 +126,10 @@ package_app(){ zip --symlinks -r -q projectGenerator-$PLATFORM/projectGenerator-$PLATFORM.zip projectGenerator-$PLATFORM/projectGenerator.app if [[ ("${TRAVIS_REPO_SLUG}/${TRAVIS_BRANCH}" == "openframeworks/projectGenerator/master" || "${TRAVIS_REPO_SLUG}/${TRAVIS_BRANCH}" == "openframeworks/projectGenerator/bleeding") && "$TRAVIS_PULL_REQUEST" == "false" ]] || [[ ("${GITHUB_REF##*/}" == "master" || "${GITHUB_REF##*/}" == "bleeding") && -z "${GITHUB_HEAD_REF}" ]] ; then - xcrun notarytool submit "projectGenerator-${PLATFORM}/projectGenerator-${PLATFORM}.zip" --apple-id "${APPLE_ID}" --team-id "${TEAM_ID}" --password "${GA_APPLE_PASS}" + # App Store Connect API key auth (--key/--key-id/--issuer) instead of + # --apple-id/--team-id/--password - not tied to a personal Apple ID's + # password, and revocable independently (see setup_notarization_key) + xcrun notarytool submit "projectGenerator-${PLATFORM}/projectGenerator-${PLATFORM}.zip" --key "${APPLE_API_KEY_PATH}" --key-id "${APPLE_API_KEY_ID}" --issuer "${APPLE_API_ISSUER_ID}" fi mv projectGenerator-$PLATFORM/projectGenerator-$PLATFORM.zip ${PG_DIR}/../../../projectGenerator/projectGenerator-$PLATFORM.zip @@ -169,8 +169,7 @@ sign_and_upload(){ # need to upload zip of just app to apple for notarizing zip --symlinks -r -q projectGenerator-$PLATFORM/projectGenerator.app.zip projectGenerator-$PLATFORM/projectGenerator.app # xcrun altool --notarize-app --primary-bundle-id "com.electron.projectgenerator" --username "${GA_APPLE_USERNAME}" -p "${GA_APPLE_PASS}" --asc-provider "${GA_NOTARIZE_PROVIDER}" --file projectGenerator-$PLATFORM/projectGenerator.app.zip - TEAM_ID="${CERTIFCATE_TEAM_ID}" - xcrun notarytool submit "projectGenerator-${PLATFORM}/projectGenerator-${PLATFORM}.app.zip" --apple-id "${GA_APPLE_USERNAME}" --team-id "${TEAM_ID}" --password "${GA_APPLE_PASS}" + xcrun notarytool submit "projectGenerator-${PLATFORM}/projectGenerator-${PLATFORM}.app.zip" --key "${APPLE_API_KEY_PATH}" --key-id "${APPLE_API_KEY_ID}" --issuer "${APPLE_API_ISSUER_ID}" # Upload to OF CI server echo "Uploading $PLATFORM PG to CI servers" @@ -193,6 +192,22 @@ sign_and_upload(){ fi } +setup_notarization_key(){ + echo " setup_notarization_key" + + # APPLE_API_KEY_P8 holds the raw .p8 contents (the -----BEGIN PRIVATE KEY----- + # block) directly - GitHub secrets preserve multi-line values as-is, so no + # base64 round-trip is needed. notarytool still requires a file path (no + # inline-content option), so it's written out here for the CLI call to use. + if [[ -n "${APPLE_API_KEY_P8}" ]]; then + echo "Writing App Store Connect API key" + APPLE_API_KEY_PATH="${PG_DIR}/AuthKey_${APPLE_API_KEY_ID}.p8" + printf '%s\n' "${APPLE_API_KEY_P8}" > "${APPLE_API_KEY_PATH}" + chmod 600 "${APPLE_API_KEY_PATH}" + export APPLE_API_KEY_PATH + fi +} + import_certificate(){ echo " import_certificate" @@ -244,6 +259,10 @@ import_certificate # Generate electron app echo "##[endgroup]" +echo "##[group]setup_notarization_key" +setup_notarization_key +echo "##[endgroup]" + echo "##[group]build_frontend" ${CURRENT_DIR}/build_frontend.sh echo "##[endgroup]"