From 4c610c89e12d42d1f52999a2687c7daf78f28b0e Mon Sep 17 00:00:00 2001 From: James Magahern Date: Thu, 25 Jun 2026 21:44:42 -0700 Subject: [PATCH] ios: install ci profiles for xcode signing --- .gitea/workflows/testflight-release.yml | 70 +++++++++++++++++-------- ios/.env.example | 1 + ios/Apps/Sybil/project.yml | 6 +++ ios/fastlane/CI.md | 17 ++++-- ios/fastlane/Fastfile | 10 ++-- 5 files changed, 72 insertions(+), 32 deletions(-) diff --git a/.gitea/workflows/testflight-release.yml b/.gitea/workflows/testflight-release.yml index e367825..c73af48 100644 --- a/.gitea/workflows/testflight-release.yml +++ b/.gitea/workflows/testflight-release.yml @@ -84,39 +84,58 @@ jobs: : "${APPSTORE_PROVISIONING_PROFILE_BASE64:?APPSTORE_PROVISIONING_PROFILE_BASE64 secret is required}" keychain_password="$(uuidgen)" - keychain_path="${HOME}/Library/Keychains/${SIGNING_KEYCHAIN}.keychain-db" + keychain_name="${SIGNING_KEYCHAIN}.keychain" previous_default_keychain="$(security default-keychain -d user | sed 's/[ "]//g' || true)" developer_dir="$(xcode-select -p)" - mkdir -p "${HOME}/Library/Keychains" "${HOME}/Library/MobileDevice/Provisioning Profiles" ios/build/secrets + signing_dir="$(mktemp -d "${RUNNER_TEMP:-${TMPDIR:-/tmp}}/sybil-signing.XXXXXX")" + certificate_path="${signing_dir}/appstore-signing.p12" + profile_path="${signing_dir}/Sybil_AppStore_CI.mobileprovision" + profile_plist="${signing_dir}/profile.plist" + old_profile_dir="${HOME}/Library/MobileDevice/Provisioning Profiles" + xcode_profile_dir="${HOME}/Library/Developer/Xcode/UserData/Provisioning Profiles" + mkdir -p "${old_profile_dir}" "${xcode_profile_dir}" - printf '%s' "${APPSTORE_CERTIFICATES_FILE_BASE64}" | base64 --decode > ios/build/secrets/appstore-signing.p12 - printf '%s' "${APPSTORE_PROVISIONING_PROFILE_BASE64}" | base64 --decode > "${HOME}/Library/MobileDevice/Provisioning Profiles/Sybil_AppStore_CI.mobileprovision" - curl -fsSL https://www.apple.com/certificateauthority/AppleWWDRCAG3.cer -o ios/build/secrets/AppleWWDRCAG3.cer + printf '%s' "${APPSTORE_CERTIFICATES_FILE_BASE64}" | base64 --decode > "${certificate_path}" + printf '%s' "${APPSTORE_PROVISIONING_PROFILE_BASE64}" | base64 --decode > "${profile_path}" + security cms -D -i "${profile_path}" > "${profile_plist}" + profile_uuid="$(/usr/libexec/PlistBuddy -c 'Print UUID' "${profile_plist}")" + profile_name="$(/usr/libexec/PlistBuddy -c 'Print Name' "${profile_plist}")" + old_profile_path="${old_profile_dir}/${profile_uuid}.mobileprovision" + xcode_profile_path="${xcode_profile_dir}/${profile_uuid}.mobileprovision" + old_named_profile_path="${old_profile_dir}/Sybil_AppStore_CI.mobileprovision" + xcode_named_profile_path="${xcode_profile_dir}/Sybil_AppStore_CI.mobileprovision" + cp "${profile_path}" "${old_profile_path}" + cp "${profile_path}" "${xcode_profile_path}" + cp "${profile_path}" "${old_named_profile_path}" + cp "${profile_path}" "${xcode_named_profile_path}" - 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 list-keychains -d user -s "${keychain_path}" $(security list-keychains -d user | sed 's/[ "]//g') - security default-keychain -d user -s "${keychain_path}" - security import ios/build/secrets/AppleWWDRCAG3.cer \ - -k "${keychain_path}" \ - -T /usr/bin/codesign \ - -T /usr/bin/security \ - -T /usr/bin/xcodebuild - security import ios/build/secrets/appstore-signing.p12 \ - -k "${keychain_path}" \ + security create-keychain -p "${keychain_password}" "${keychain_name}" + security set-keychain-settings -lut 21600 "${keychain_name}" + security unlock-keychain -p "${keychain_password}" "${keychain_name}" + security import "${certificate_path}" \ + -k "${keychain_name}" \ + -f pkcs12 \ -P "${APPSTORE_CERTIFICATES_PASSWORD}" \ - -A \ -T /usr/bin/codesign \ -T /usr/bin/security \ -T /usr/bin/xcodebuild \ -T "${developer_dir}/usr/bin/xcodebuild" - security set-key-partition-list -S apple-tool:,apple:,codesign: -s -k "${keychain_password}" "${keychain_path}" - security find-identity -v -p codesigning "${keychain_path}" + security set-key-partition-list -S apple-tool:,apple:,codesign: -s -k "${keychain_password}" "${keychain_name}" + security list-keychains -d user -s "${keychain_name}" $(security list-keychains -d user | sed 's/[ "]//g') + security default-keychain -d user -s "${keychain_name}" + security find-identity -v -p codesigning "${keychain_name}" + security find-identity -v -p codesigning + echo "Installed ${profile_name} (${profile_uuid}) provisioning profile" { - echo "SYBIL_SIGNING_KEYCHAIN_PATH=${keychain_path}" + echo "SYBIL_SIGNING_KEYCHAIN_PATH=${keychain_name}" echo "SYBIL_SIGNING_KEYCHAIN_PASSWORD=${keychain_password}" echo "SYBIL_PREVIOUS_DEFAULT_KEYCHAIN=${previous_default_keychain}" + echo "SYBIL_PROVISIONING_PROFILE_UUID=${profile_uuid}" + echo "SYBIL_SIGNING_DIR=${signing_dir}" + echo "SYBIL_OLD_PROFILE_PATH=${old_profile_path}" + echo "SYBIL_XCODE_PROFILE_PATH=${xcode_profile_path}" + echo "SYBIL_OLD_NAMED_PROFILE_PATH=${old_named_profile_path}" + echo "SYBIL_XCODE_NAMED_PROFILE_PATH=${xcode_named_profile_path}" } >> "${GITHUB_ENV}" - name: Build and upload to TestFlight @@ -137,6 +156,7 @@ jobs: security list-keychains -d user -s "${SYBIL_SIGNING_KEYCHAIN_PATH}" $(security list-keychains -d user | sed 's/[ "]//g') security default-keychain -d user -s "${SYBIL_SIGNING_KEYCHAIN_PATH}" security find-identity -v -p codesigning "${SYBIL_SIGNING_KEYCHAIN_PATH}" + security find-identity -v -p codesigning SYBIL_VERSION_TAG="${TAG_NAME}" bundle exec fastlane ios beta @@ -230,4 +250,10 @@ jobs: if [[ -n "${SYBIL_PREVIOUS_DEFAULT_KEYCHAIN:-}" ]]; then security default-keychain -d user -s "${SYBIL_PREVIOUS_DEFAULT_KEYCHAIN}" || true fi - security delete-keychain "${HOME}/Library/Keychains/${SIGNING_KEYCHAIN}.keychain-db" || true + rm -f \ + "${SYBIL_OLD_PROFILE_PATH:-}" \ + "${SYBIL_XCODE_PROFILE_PATH:-}" \ + "${SYBIL_OLD_NAMED_PROFILE_PATH:-}" \ + "${SYBIL_XCODE_NAMED_PROFILE_PATH:-}" + rm -rf "${SYBIL_SIGNING_DIR:-}" + security delete-keychain "${SIGNING_KEYCHAIN}.keychain" || true diff --git a/ios/.env.example b/ios/.env.example index 2e3113f..7997bdf 100644 --- a/ios/.env.example +++ b/ios/.env.example @@ -5,6 +5,7 @@ FASTLANE_HIDE_CHANGELOG=1 SYBIL_APP_STORE_APPLE_ID=6759442828 SYBIL_PROVIDER_PUBLIC_ID=c043d167-ad88-4036-84ea-76c223f1b1b2 SYBIL_PROVISIONING_PROFILE_SPECIFIER=Sybil AppStore CI +SYBIL_PROVISIONING_PROFILE_UUID= SYBIL_CODE_SIGN_IDENTITY=Apple Distribution: James Magahern (DQQH5H6GBD) SYBIL_XCODE_CODE_SIGN_IDENTITY=Apple Distribution SYBIL_SIGNING_CERTIFICATE_ID= diff --git a/ios/Apps/Sybil/project.yml b/ios/Apps/Sybil/project.yml index 4bfc36b..9c19df9 100644 --- a/ios/Apps/Sybil/project.yml +++ b/ios/Apps/Sybil/project.yml @@ -32,6 +32,12 @@ targets: INFOPLIST_KEY_UILaunchScreen_Generation: YES INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone: UIInterfaceOrientationPortrait INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad: UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight + configs: + Release: + CODE_SIGN_STYLE: Manual + CODE_SIGN_IDENTITY: Apple Distribution + "CODE_SIGN_IDENTITY[sdk=iphoneos*]": Apple Distribution + PROVISIONING_PROFILE_SPECIFIER: Sybil AppStore CI schemes: Sybil: diff --git a/ios/fastlane/CI.md b/ios/fastlane/CI.md index d2b7dbb..4ea4015 100644 --- a/ios/fastlane/CI.md +++ b/ios/fastlane/CI.md @@ -15,11 +15,12 @@ git push origin release/v1.10.0 The release job runs on the `xcode` runner label, imports the signing p12 into a temporary per-user keychain, makes that keychain the user default for the -duration of the job, installs the App Store provisioning profile, builds and -uploads the app with fastlane, then creates or updates the matching Gitea -release with the generated IPA as an asset. The job restores the previous user -default keychain and deletes the temporary signing keychain in an `always()` -cleanup step. +duration of the job, installs the App Store provisioning profile in both the +legacy MobileDevice directory and the Xcode UserData directory used by newer +Xcode releases, builds and uploads the app with fastlane, then creates or +updates the matching Gitea release with the generated IPA as an asset. The job +restores the previous user default keychain and deletes the temporary signing +keychain and installed profiles in an `always()` cleanup step. Required repository secrets: @@ -49,6 +50,12 @@ exact certificate common name used when exporting a local p12 for secrets, while `SYBIL_XCODE_CODE_SIGN_IDENTITY` defaults to the generic `Apple Distribution` selector that Xcode uses during archive/export. +The Release signing settings are also present in `Apps/Sybil/project.yml` so +XcodeGen emits a manually signed App Store archive configuration. CI passes the +installed provisioning profile UUID to Fastlane as +`SYBIL_PROVISIONING_PROFILE_UUID`; Fastlane writes that UUID into the generated +project before archiving. + If the Apple team has reached the Distribution certificate limit, set `SYBIL_SIGNING_CERTIFICATE_ID` to the portal id for a certificate whose private key exists in the local login keychain before running `create_ci_signing`. The diff --git a/ios/fastlane/Fastfile b/ios/fastlane/Fastfile index 8659df6..931b3e7 100644 --- a/ios/fastlane/Fastfile +++ b/ios/fastlane/Fastfile @@ -71,6 +71,10 @@ def apply_release_signing_settings settings["PROVISIONING_PROFILE_SPECIFIER"] = PROFILE_SPECIFIER settings["CODE_SIGN_IDENTITY"] = XCODE_CODE_SIGN_IDENTITY settings["CODE_SIGN_IDENTITY[sdk=iphoneos*]"] = XCODE_CODE_SIGN_IDENTITY + if present?(ENV["SYBIL_PROVISIONING_PROFILE_UUID"]) + settings["PROVISIONING_PROFILE"] = ENV["SYBIL_PROVISIONING_PROFILE_UUID"] + settings["PROVISIONING_PROFILE[sdk=iphoneos*]"] = ENV["SYBIL_PROVISIONING_PROFILE_UUID"] + end end project.save end @@ -428,11 +432,7 @@ platform :ios do xcode_args = [ xcode_build_setting("MARKETING_VERSION", version), - xcode_build_setting("CURRENT_PROJECT_VERSION", build_number), - xcode_build_setting("CODE_SIGN_STYLE", "Manual"), - xcode_build_setting("DEVELOPMENT_TEAM", TEAM_ID), - xcode_build_setting("PROVISIONING_PROFILE_SPECIFIER", PROFILE_SPECIFIER), - xcode_build_setting("CODE_SIGN_IDENTITY", XCODE_CODE_SIGN_IDENTITY) + xcode_build_setting("CURRENT_PROJECT_VERSION", build_number) ] if present?(ENV["SYBIL_SIGNING_KEYCHAIN_PATH"]) xcode_args << xcode_build_setting("OTHER_CODE_SIGN_FLAGS", "--keychain #{ENV.fetch("SYBIL_SIGNING_KEYCHAIN_PATH")}")