Compare commits

...

14 Commits

Author SHA1 Message Date
3c7fc51fdb ios: set ci keychain in default domain
Some checks failed
TestFlight Release / testflight (push) Failing after 10s
2026-06-25 22:14:25 -07:00
0062f37b9f ios: sign with disposable login keychain
Some checks failed
TestFlight Release / testflight (push) Failing after 17s
2026-06-25 22:12:17 -07:00
0ae551615f ios: use signing identity fingerprint in ci
Some checks failed
TestFlight Release / testflight (push) Failing after 16s
2026-06-25 22:10:06 -07:00
88bef50ae7 ios: create named ci keychain in home
Some checks failed
TestFlight Release / testflight (push) Failing after 15s
2026-06-25 22:07:12 -07:00
0d069b4233 ios: create ci keychain by name
Some checks failed
TestFlight Release / testflight (push) Failing after 11s
2026-06-25 22:05:47 -07:00
60bbe077e8 ios: pass signing keychain to xcode
Some checks failed
TestFlight Release / testflight (push) Failing after 18s
2026-06-25 22:02:19 -07:00
0b09d5425b ios: handle empty ci keychain list
Some checks failed
TestFlight Release / testflight (push) Failing after 15s
2026-06-25 21:58:01 -07:00
c9a3015e35 ios: parse ci profile without keychain
Some checks failed
TestFlight Release / testflight (push) Failing after 9s
2026-06-25 21:56:19 -07:00
abd8a80daa ios: isolate ci signing keychains
Some checks failed
TestFlight Release / testflight (push) Failing after 8s
2026-06-25 21:52:17 -07:00
0f76ef91a9 ios: restore working ci p12 import
Some checks failed
TestFlight Release / testflight (push) Failing after 9s
2026-06-25 21:48:19 -07:00
72e2ffd898 ios: use temporary keychain path in ci
Some checks failed
TestFlight Release / testflight (push) Failing after 9s
2026-06-25 21:46:48 -07:00
4c610c89e1 ios: install ci profiles for xcode signing
Some checks failed
TestFlight Release / testflight (push) Failing after 9s
2026-06-25 21:44:42 -07:00
477921563f ios: remove invalid ci codesign path
Some checks failed
TestFlight Release / testflight (push) Failing after 18s
2026-06-25 21:36:37 -07:00
0fca0e93ec ios: grant ci key access to xcode tools
Some checks failed
TestFlight Release / testflight (push) Failing after 10s
2026-06-25 21:35:11 -07:00
5 changed files with 117 additions and 34 deletions

View File

@@ -84,36 +84,87 @@ jobs:
: "${APPSTORE_PROVISIONING_PROFILE_BASE64:?APPSTORE_PROVISIONING_PROFILE_BASE64 secret is required}"
keychain_password="$(uuidgen)"
keychain_path="${HOME}/Library/Keychains/${SIGNING_KEYCHAIN}.keychain-db"
previous_default_keychain="$(security default-keychain -d user | sed 's/[ "]//g' || true)"
mkdir -p "${HOME}/Library/Keychains" "${HOME}/Library/MobileDevice/Provisioning Profiles" ios/build/secrets
if [[ "${previous_default_keychain}" == *"/${SIGNING_KEYCHAIN}"* || ! -e "${previous_default_keychain}" ]]; then
previous_default_keychain=""
fi
developer_dir="$(xcode-select -p)"
signing_dir="$(mktemp -d "${RUNNER_TEMP:-${TMPDIR:-/tmp}}/sybil-signing.XXXXXX")"
mkdir -p "${HOME}/Library/Keychains"
keychain_name="${HOME}/Library/Keychains/login.keychain"
certificate_path="${signing_dir}/appstore-signing.p12"
wwdr_certificate_path="${signing_dir}/AppleWWDRCAG3.cer"
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}"
curl -fsSL https://www.apple.com/certificateauthority/AppleWWDRCAG3.cer -o "${wwdr_certificate_path}"
openssl smime -inform DER -verify -noverify -in "${profile_path}" -out "${profile_plist}" >/dev/null
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}" \
base_keychains=()
while IFS= read -r existing_keychain; do
[[ -z "${existing_keychain}" ]] && continue
[[ "${existing_keychain}" == *"/${SIGNING_KEYCHAIN}"* ]] && continue
[[ ! -e "${existing_keychain}" ]] && continue
base_keychains+=("${existing_keychain}")
done < <(security list-keychains -d user | sed 's/[ "]//g')
security delete-keychain "${keychain_name}" >/dev/null 2>&1 || true
rm -f "${HOME}/Library/Keychains/${keychain_name}-db"
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 "${wwdr_certificate_path}" \
-k "${keychain_name}" \
-T /usr/bin/codesign \
-T /usr/bin/security \
-T /usr/bin/xcodebuild
security import ios/build/secrets/appstore-signing.p12 \
-k "${keychain_path}" \
security import "${certificate_path}" \
-k "${keychain_name}" \
-P "${APPSTORE_CERTIFICATES_PASSWORD}" \
-T /usr/bin/codesign \
-T /usr/bin/security \
-T /usr/bin/xcodebuild
security set-key-partition-list -S apple-tool:,apple:,codesign: -s -k "${keychain_password}" "${keychain_path}"
-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_name}"
if [[ "${#base_keychains[@]}" -gt 0 ]]; then
security list-keychains -d user -s "${keychain_name}" "${base_keychains[@]}"
security list-keychains -s "${keychain_name}" "${base_keychains[@]}"
else
security list-keychains -d user -s "${keychain_name}"
security list-keychains -s "${keychain_name}"
fi
security default-keychain -d user -s "${keychain_name}"
security default-keychain -s "${keychain_name}"
keychain_path="$(security list-keychains -d user | sed 's/[ "]//g' | head -n 1)"
security find-identity -v -p codesigning "${keychain_path}"
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_NAME=${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
@@ -133,7 +184,10 @@ jobs:
security unlock-keychain -p "${SYBIL_SIGNING_KEYCHAIN_PASSWORD}" "${SYBIL_SIGNING_KEYCHAIN_PATH}"
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 list-keychains -s "${SYBIL_SIGNING_KEYCHAIN_PATH}" $(security list-keychains | sed 's/[ "]//g')
security default-keychain -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
@@ -227,4 +281,11 @@ 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:-}"
security delete-keychain "${SYBIL_SIGNING_KEYCHAIN_PATH:-${HOME}/Library/Keychains/${SIGNING_KEYCHAIN}.keychain-db}" || true
rm -f "${HOME}/Library/Keychains/${SIGNING_KEYCHAIN}-"*.keychain-db
rm -rf "${SYBIL_SIGNING_DIR:-}"

View File

@@ -5,8 +5,10 @@ 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_XCODE_CODE_SIGN_IDENTITY=6B74B268C4761720FB2051D01D8BB3E47B55D9F5
SYBIL_EXPORT_SIGNING_CERTIFICATE=Apple Distribution
SYBIL_SIGNING_CERTIFICATE_ID=
SYBIL_SIGNING_KEYCHAIN=

View File

@@ -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:

View File

@@ -13,13 +13,15 @@ git tag release/v1.10.0
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.
The release job runs on the `xcode` runner label, creates the runner user's
login keychain from Gitea secrets, makes that keychain the user default for the
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 user login keychain
and installed profiles in an `always()` cleanup step. No signing material is
installed into the system keychain.
Required repository secrets:
@@ -46,8 +48,17 @@ default.
Fastlane keeps two signing names separate. `SYBIL_CODE_SIGN_IDENTITY` is the
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.
`SYBIL_XCODE_CODE_SIGN_IDENTITY` defaults to the certificate SHA-1 fingerprint
that Xcode uses during archive. `SYBIL_EXPORT_SIGNING_CERTIFICATE` defaults to
the generic `Apple Distribution` selector used in the export options.
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. CI also passes the temporary keychain path as
`CODE_SIGN_KEYCHAIN` so Xcode searches the disposable keychain for the imported
Distribution identity.
If the Apple team has reached the Distribution certificate limit, set
`SYBIL_SIGNING_CERTIFICATE_ID` to the portal id for a certificate whose private

View File

@@ -20,7 +20,8 @@ APP_STORE_APPLE_ID = ENV.fetch("SYBIL_APP_STORE_APPLE_ID", "6759442828")
PROVIDER_PUBLIC_ID = ENV.fetch("SYBIL_PROVIDER_PUBLIC_ID", "c043d167-ad88-4036-84ea-76c223f1b1b2")
PROFILE_SPECIFIER = ENV["SYBIL_PROVISIONING_PROFILE_SPECIFIER"].to_s.strip.empty? ? "Sybil AppStore CI" : ENV["SYBIL_PROVISIONING_PROFILE_SPECIFIER"]
SIGNING_CERTIFICATE_NAME = ENV["SYBIL_CODE_SIGN_IDENTITY"].to_s.strip.empty? ? "Apple Distribution: James Magahern (DQQH5H6GBD)" : ENV["SYBIL_CODE_SIGN_IDENTITY"]
XCODE_CODE_SIGN_IDENTITY = ENV["SYBIL_XCODE_CODE_SIGN_IDENTITY"].to_s.strip.empty? ? "Apple Distribution" : ENV["SYBIL_XCODE_CODE_SIGN_IDENTITY"]
XCODE_CODE_SIGN_IDENTITY = ENV["SYBIL_XCODE_CODE_SIGN_IDENTITY"].to_s.strip.empty? ? "6B74B268C4761720FB2051D01D8BB3E47B55D9F5" : ENV["SYBIL_XCODE_CODE_SIGN_IDENTITY"]
EXPORT_SIGNING_CERTIFICATE = ENV["SYBIL_EXPORT_SIGNING_CERTIFICATE"].to_s.strip.empty? ? "Apple Distribution" : ENV["SYBIL_EXPORT_SIGNING_CERTIFICATE"]
IOS_ROOT = File.expand_path("..", __dir__)
PROJECT_FILE = File.join(IOS_ROOT, "Sybil.xcodeproj")
PROJECT_SPEC = File.join(IOS_ROOT, "project.yml")
@@ -71,6 +72,11 @@ 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
settings["CODE_SIGN_KEYCHAIN"] = ENV["SYBIL_SIGNING_KEYCHAIN_PATH"] if present?(ENV["SYBIL_SIGNING_KEYCHAIN_PATH"])
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,13 +434,10 @@ 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("CODE_SIGN_KEYCHAIN", ENV.fetch("SYBIL_SIGNING_KEYCHAIN_PATH"))
xcode_args << xcode_build_setting("OTHER_CODE_SIGN_FLAGS", "--keychain #{ENV.fetch("SYBIL_SIGNING_KEYCHAIN_PATH")}")
end
xcode_args = xcode_args.join(" ")
@@ -455,7 +458,7 @@ platform :ios do
provisioningProfiles: {
APP_IDENTIFIER => PROFILE_SPECIFIER
},
signingCertificate: XCODE_CODE_SIGN_IDENTITY,
signingCertificate: EXPORT_SIGNING_CERTIFICATE,
teamID: TEAM_ID,
manageAppVersionAndBuildNumber: false,
uploadSymbols: true,