Compare commits

..

57 Commits

Author SHA1 Message Date
730d609f81 Relax Xcode signing identity matching
Some checks failed
TestFlight / testflight (push) Failing after 26s
2026-06-25 23:57:17 -07:00
137fce8558 Use passworded CI keychain
Some checks failed
TestFlight / testflight (push) Failing after 25s
2026-06-25 23:53:24 -07:00
3e6d3c6817 Use user keychain domain in CI
Some checks failed
TestFlight / testflight (push) Failing after 23s
2026-06-25 23:51:33 -07:00
100b51de12 Use explicit CI signing keychain
Some checks failed
TestFlight / testflight (push) Failing after 18s
2026-06-25 23:48:26 -07:00
23ee30a53a Simplify TestFlight CI signing
Some checks failed
TestFlight / testflight (push) Failing after 22s
2026-06-25 23:44:13 -07:00
0be2442ad0 Pass signing keychain to Xcode resolver
Some checks failed
TestFlight / testflight (push) Failing after 28s
2026-06-25 23:37:24 -07:00
c84ef8c242 Refresh CI key partition access before build
Some checks failed
TestFlight / testflight (push) Failing after 27s
2026-06-25 23:35:00 -07:00
98f96eda45 Let Xcode select Apple Distribution identity
Some checks failed
TestFlight / testflight (push) Failing after 25s
2026-06-25 23:32:38 -07:00
3904457c21 Use runner home for CI keychain preferences
Some checks failed
TestFlight / testflight (push) Failing after 24s
2026-06-25 23:30:46 -07:00
0fc2117a11 Set CI keychain as default for Xcode
Some checks failed
TestFlight / testflight (push) Failing after 18s
2026-06-25 23:28:58 -07:00
60469f05b5 Tolerate login keychain preference failure
Some checks failed
TestFlight / testflight (push) Failing after 23s
2026-06-25 23:27:13 -07:00
d834ed7931 Create CI login keychain when missing
Some checks failed
TestFlight / testflight (push) Failing after 19s
2026-06-25 23:25:42 -07:00
f98a002f52 Use explicit runner login keychain
Some checks failed
TestFlight / testflight (push) Failing after 17s
2026-06-25 23:23:13 -07:00
b0c0a2d55e Reset CI keychain search list
Some checks failed
TestFlight / testflight (push) Failing after 19s
2026-06-25 23:21:42 -07:00
3262f4ff80 Detect runner login keychain path
Some checks failed
TestFlight / testflight (push) Failing after 19s
2026-06-25 23:20:06 -07:00
585be09eb7 Target login keychain path for CI signing
Some checks failed
TestFlight / testflight (push) Failing after 19s
2026-06-25 23:18:01 -07:00
387896741c Use runner login keychain for CI signing
Some checks failed
TestFlight / testflight (push) Failing after 21s
2026-06-25 23:16:22 -07:00
f6a10af7a9 Use signing certificate identity hash
Some checks failed
TestFlight / testflight (push) Failing after 24s
2026-06-25 23:13:08 -07:00
8aab86e2a6 Avoid changing default keychain in CI
Some checks failed
TestFlight / testflight (push) Failing after 25s
2026-06-25 23:10:35 -07:00
eb4b233e33 Resolve CI signing keychain path
Some checks failed
TestFlight / testflight (push) Failing after 18s
2026-06-25 23:08:35 -07:00
cbd7a68e57 Make CI signing keychain visible to Xcode
Some checks failed
TestFlight / testflight (push) Failing after 21s
2026-06-25 23:06:00 -07:00
04c15e8f12 Use absolute iOS paths in Fastlane
Some checks failed
TestFlight / testflight (push) Failing after 25s
2026-06-25 22:50:30 -07:00
ca28ebc0a0 Use disposable match keychain in CI
Some checks failed
TestFlight / testflight (push) Failing after 16s
2026-06-25 22:48:59 -07:00
87787642b5 Preserve Ruby path for TestFlight workflow
Some checks failed
TestFlight / testflight (push) Failing after 22s
2026-06-25 22:46:14 -07:00
4124a31a34 Use Ruby 3.1 for TestFlight workflow
Some checks failed
TestFlight / testflight (push) Failing after 21s
2026-06-25 22:43:27 -07:00
a68f1e50ca Reset iOS TestFlight deployment
Some checks failed
TestFlight / testflight (push) Failing after 14s
2026-06-25 22:41:00 -07:00
272ad0bbf0 ios: pass signing settings to archive
Some checks failed
TestFlight Release / testflight (push) Failing after 17s
2026-06-25 22:19:25 -07:00
de7b448bc5 ios: avoid system default keychain writes
Some checks failed
TestFlight Release / testflight (push) Failing after 16s
2026-06-25 22:16:24 -07:00
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
f977f9943c ios: patch generated release signing settings
Some checks failed
TestFlight Release / testflight (push) Failing after 16s
2026-06-25 21:31:51 -07:00
f445730a41 ios: override iphoneos signing identity
Some checks failed
TestFlight Release / testflight (push) Failing after 16s
2026-06-25 21:29:35 -07:00
76cb808c33 ios: use disposable keychain as ci default
Some checks failed
TestFlight Release / testflight (push) Failing after 15s
2026-06-25 21:27:19 -07:00
e167bd983f ios: use generic xcode signing selector
Some checks failed
TestFlight Release / testflight (push) Failing after 19s
2026-06-25 21:25:13 -07:00
e4dd91564f ios: unlock signing keychain before build
Some checks failed
TestFlight Release / testflight (push) Failing after 17s
2026-06-25 21:20:31 -07:00
3bfde476a6 ios: use single identity signing p12
Some checks failed
TestFlight Release / testflight (push) Failing after 16s
2026-06-25 21:18:54 -07:00
b8676027db ios: trust Apple root in CI signing keychain
Some checks failed
TestFlight Release / testflight (push) Failing after 8s
2026-06-25 21:12:53 -07:00
d36d2c60a3 ios: install Apple WWDR intermediate in CI
Some checks failed
TestFlight Release / testflight (push) Failing after 18s
2026-06-25 21:11:01 -07:00
3d7031bb40 ios: avoid default keychain mutation in ci
Some checks failed
TestFlight Release / testflight (push) Failing after 17s
2026-06-25 21:08:32 -07:00
fa9b725c77 ios: expose signing keychain to xcodebuild
Some checks failed
TestFlight Release / testflight (push) Failing after 9s
2026-06-25 21:07:38 -07:00
a88987d08d ios: pin distribution signing identity
Some checks failed
TestFlight Release / testflight (push) Failing after 15s
2026-06-25 21:05:26 -07:00
e137ea1077 ios: bootstrap signing with existing certificate
Some checks failed
TestFlight Release / testflight (push) Failing after 17s
2026-06-25 21:03:43 -07:00
fad25d7f2b ios: configure api-key TestFlight signing 2026-06-25 20:51:01 -07:00
fb28508764 ios: ci: keychain cleanup 2026-06-25 20:35:39 -07:00
4365798f5e workflow: fix
Some checks failed
TestFlight Release / testflight (push) Failing after 16s
2026-06-25 20:21:39 -07:00
2 changed files with 107 additions and 41 deletions

View File

@@ -4,7 +4,7 @@ on:
workflow_dispatch:
push:
tags:
- "release/v*"
- "v*"
jobs:
testflight:
@@ -62,7 +62,6 @@ jobs:
MATCH_PASSWORD: ${{ secrets.MATCH_PASSWORD }}
MATCH_GIT_URL: ${{ secrets.MATCH_GIT_URL }}
MATCH_GIT_BASIC_AUTHORIZATION: ${{ secrets.MATCH_GIT_BASIC_AUTHORIZATION }}
SYBIL_BUILD_NUMBER: ${{ github.run_number }}
FASTLANE_SKIP_UPDATE_CHECK: "1"
FASTLANE_XCODEBUILD_SETTINGS_TIMEOUT: "120"
run: |

View File

@@ -1,3 +1,4 @@
require "fileutils"
require "shellwords"
default_platform(:ios)
@@ -6,26 +7,27 @@ APP_IDENTIFIER = "net.buzzert.sybil2"
SCHEME = "Sybil"
TEAM_ID = "DQQH5H6GBD"
PROFILE_NAME = "Sybil AppStore CI"
SIGNING_IDENTITY = "Apple Distribution: James Magahern (DQQH5H6GBD)"
CI_KEYCHAIN_NAME = "sybil_ci_keychain"
CI_KEYCHAIN_PASSWORD = "sybil-ci-keychain-password"
CI_KEYCHAIN_DB_PATH = File.expand_path("~/Library/Keychains/#{CI_KEYCHAIN_NAME}-db")
IOS_ROOT = File.expand_path("..", __dir__)
PROJECT_FILE = File.join(IOS_ROOT, "Sybil.xcodeproj")
PROJECT_SPEC = File.join(IOS_ROOT, "project.yml")
CI_KEYCHAIN_PATH = File.join(File.expand_path("~/Library/Keychains"), CI_KEYCHAIN_NAME)
CI_KEYCHAIN_DB_PATH = "#{CI_KEYCHAIN_PATH}-db"
LOGIN_KEYCHAIN_PATH = File.expand_path("~/Library/Keychains/login.keychain")
LOGIN_KEYCHAIN_DB_PATH = "#{LOGIN_KEYCHAIN_PATH}-db"
def present?(value)
!value.to_s.strip.empty?
end
def ci?
present?(ENV["CI"])
end
def release_version
tag = ENV["SYBIL_VERSION_TAG"]
tag = ENV["GITHUB_REF_NAME"] if !present?(tag)
tag = ENV["SYBIL_VERSION_TAG"].to_s
tag = ENV["GITHUB_REF_NAME"].to_s if !present?(tag)
tag = ENV["GITHUB_REF"].to_s.sub(%r{\Arefs/tags/}, "") if !present?(tag)
tag = sh("git describe --tags --abbrev=0").strip if !present?(tag)
version = tag.to_s.sub(%r{\Arelease/}, "").sub(/\Av/, "")
version = tag.sub(%r{\Arelease/}, "").sub(/\Av/, "")
unless version.match?(/\A\d+\.\d+\.\d+\z/)
UI.user_error!("Release tag must look like v1.2.3; got #{tag.inspect}")
@@ -34,18 +36,12 @@ def release_version
version
end
# App Store Connect requires CFBundleVersion to be unique and strictly
# increasing app-wide (not just per marketing version), so we derive it from
# the monotonic CI run number rather than querying TestFlight (that query can
# lag behind builds still processing and hand back a colliding value).
def build_number
value = present?(ENV["SYBIL_BUILD_NUMBER"]) ? ENV["SYBIL_BUILD_NUMBER"] : ENV["GITHUB_RUN_NUMBER"]
unless value.to_s.match?(/\A\d+\z/)
UI.user_error!("Build number must come from SYBIL_BUILD_NUMBER/GITHUB_RUN_NUMBER; got #{value.inspect}")
def ci?
present?(ENV["CI"])
end
value.to_i
def ci_keychain_path
File.file?(CI_KEYCHAIN_DB_PATH) ? CI_KEYCHAIN_DB_PATH : CI_KEYCHAIN_PATH
end
platform :ios do
@@ -58,27 +54,54 @@ platform :ios do
)
end
# CI has no login keychain, so create a dedicated throwaway one for match to
# import the distribution cert into. The runner's launchd job sets
# SessionCreate, so add_to_search_list actually makes it visible to xcodebuild.
private_lane :prepare_ci_keychain do
private_lane :setup_ci_signing do
next unless ci?
delete_keychain(name: CI_KEYCHAIN_NAME) if File.file?(CI_KEYCHAIN_DB_PATH)
FileUtils.mkdir_p(File.dirname(CI_KEYCHAIN_PATH))
sh("security delete-keychain #{CI_KEYCHAIN_PATH.shellescape} || true", log: false)
FileUtils.rm_f(CI_KEYCHAIN_PATH)
FileUtils.rm_f(CI_KEYCHAIN_DB_PATH)
create_keychain(
name: CI_KEYCHAIN_NAME,
path: CI_KEYCHAIN_PATH,
password: CI_KEYCHAIN_PASSWORD,
default_keychain: false,
unlock: true,
timeout: 3600,
add_to_search_list: true
lock_when_sleeps: true,
add_to_search_list: false
)
ENV["MATCH_KEYCHAIN_NAME"] = CI_KEYCHAIN_NAME
sh("security default-keychain -d user -s #{CI_KEYCHAIN_PATH.shellescape}", log: false)
sh("security list-keychains -d user -s #{ci_keychain_path.shellescape}", log: false)
sh("security list-keychains -d dynamic -s #{ci_keychain_path.shellescape} || true", log: false)
sh("security list-keychains -d common -s #{ci_keychain_path.shellescape} || true", log: false)
ENV["MATCH_KEYCHAIN_NAME"] = CI_KEYCHAIN_PATH
ENV["MATCH_KEYCHAIN_PASSWORD"] = CI_KEYCHAIN_PASSWORD
ENV["MATCH_READONLY"] = "true"
end
private_lane :cleanup_ci_signing do
next unless ci?
if File.file?(LOGIN_KEYCHAIN_DB_PATH) || File.file?(LOGIN_KEYCHAIN_PATH)
sh("security default-keychain -d user -s #{LOGIN_KEYCHAIN_PATH.shellescape} || true", log: false)
sh("security list-keychains -d user -s #{LOGIN_KEYCHAIN_DB_PATH.shellescape} || true", log: false)
end
sh("security delete-keychain #{ci_keychain_path.shellescape} || true", log: false)
FileUtils.rm_f(CI_KEYCHAIN_PATH)
FileUtils.rm_f(CI_KEYCHAIN_DB_PATH)
rescue => error
UI.message("Unable to delete temporary CI keychain: #{error.message}")
ensure
ENV.delete("MATCH_KEYCHAIN_NAME")
ENV.delete("MATCH_KEYCHAIN_PASSWORD")
ENV.delete("MATCH_READONLY")
end
private_lane :sync_signing do |options|
match(
match_options = {
type: "appstore",
readonly: options.fetch(:readonly),
app_identifier: APP_IDENTIFIER,
@@ -89,7 +112,28 @@ platform :ios do
git_full_name: "Sybil Release Bot",
git_user_email: "james.magahern@me.com",
api_key: options.fetch(:api_key)
)
}
match_options[:keychain_name] = ENV["MATCH_KEYCHAIN_NAME"] if present?(ENV["MATCH_KEYCHAIN_NAME"])
match_options[:keychain_password] = ENV["MATCH_KEYCHAIN_PASSWORD"] if ENV.key?("MATCH_KEYCHAIN_PASSWORD")
match(match_options)
end
private_lane :verify_ci_signing do
next unless ci?
if File.file?(ci_keychain_path)
password = ENV.fetch("MATCH_KEYCHAIN_PASSWORD", "")
sh("security unlock-keychain -p #{password.shellescape} #{ci_keychain_path.shellescape}", log: false)
sh("security set-key-partition-list -S apple-tool:,apple:,codesign: -s -k #{password.shellescape} #{ci_keychain_path.shellescape}", log: false)
end
identities = sh("security find-identity -v -p codesigning #{ci_keychain_path.shellescape}", log: false)
UI.message(identities)
unless identities.include?(SIGNING_IDENTITY)
UI.user_error!("The CI keychain search list does not contain #{SIGNING_IDENTITY}")
end
end
desc "Create or update match signing assets"
@@ -99,28 +143,49 @@ platform :ios do
desc "Build and upload to TestFlight"
lane :beta do
prepare_ci_keychain
setup_ci_signing
api_key = app_store_api_key
sh("xcodegen", "--spec", PROJECT_SPEC)
sh("xcodegen --spec #{PROJECT_SPEC.shellescape}")
increment_version_number(version_number: release_version, xcodeproj: PROJECT_FILE)
increment_build_number(build_number: build_number, xcodeproj: PROJECT_FILE)
increment_version_number(
version_number: release_version,
xcodeproj: PROJECT_FILE
)
latest_build_number = latest_testflight_build_number(
app_identifier: APP_IDENTIFIER,
api_key: api_key,
initial_build_number: 0
)
increment_build_number(
build_number: latest_build_number + 1,
xcodeproj: PROJECT_FILE
)
sync_signing(api_key: api_key, readonly: true)
verify_ci_signing
xcargs = [
"DEVELOPMENT_TEAM=#{TEAM_ID.shellescape}",
"CODE_SIGN_STYLE=Manual",
"CODE_SIGN_IDENTITY=Apple\\ Distribution",
"PROVISIONING_PROFILE_SPECIFIER=#{PROFILE_NAME.shellescape}"
]
if ci?
xcargs << "CODE_SIGN_KEYCHAIN=#{ci_keychain_path.shellescape}"
xcargs << "OTHER_CODE_SIGN_FLAGS=#{("--keychain #{ci_keychain_path}").shellescape}"
end
build_app(
project: PROJECT_FILE,
scheme: SCHEME,
export_method: "app-store",
codesigning_identity: "Apple Distribution",
xcargs: [
"DEVELOPMENT_TEAM=#{TEAM_ID.shellescape}",
"CODE_SIGN_STYLE=Manual",
"CODE_SIGN_IDENTITY=Apple\\ Distribution",
"PROVISIONING_PROFILE_SPECIFIER=#{PROFILE_NAME.shellescape}"
].join(" "),
xcargs: xcargs.join(" "),
export_options: {
signingStyle: "manual",
teamID: TEAM_ID,
@@ -134,5 +199,7 @@ platform :ios do
api_key: api_key,
skip_waiting_for_build_processing: true
)
ensure
cleanup_ci_signing
end
end