From 45b09a13d3e4f23b38d39610e86210ee58e7efdb Mon Sep 17 00:00:00 2001 From: James Magahern Date: Sat, 11 Jul 2026 13:16:13 -0700 Subject: [PATCH] ci: put CI keychain first in codesign search list codesign resolves signing identities through the user keychain search list (first match wins) and ignores --keychain for the lookup. This runner hosts another project (Sybil-2) whose keychain holds the same Apple Distribution identity, so if that keychain is locked and appears earlier in the search list, codesign fails with errSecInternalComponent no matter how correctly our own keychain is set up. Prepend the fresh CI keychain to the search list for the build and always delete it afterward, which restores the original list. Co-Authored-By: Claude Sonnet 5 --- fastlane/Fastfile | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/fastlane/Fastfile b/fastlane/Fastfile index c0bd806..fa0e6fe 100644 --- a/fastlane/Fastfile +++ b/fastlane/Fastfile @@ -93,6 +93,14 @@ platform :ios do ) end + # CI signs headlessly, so match needs a fresh unlocked keychain to import + # into. codesign resolves identities through the user keychain search + # list (first match wins; the --keychain flag does not restrict the + # lookup), and other projects' keychains on this runner hold the same + # identity but are usually locked — so ours must come first. delete_keychain + # in the beta lane's ensure removes both the keychain and its search-list + # entry, which also keeps our (later locked) copy from shadowing those + # other projects. private_lane :prepare_ci_keychain do next unless ci? @@ -102,9 +110,15 @@ platform :ios do password: CI_KEYCHAIN_PASSWORD, unlock: true, timeout: 3600, - add_to_search_list: true + add_to_search_list: false ) + others = sh("security list-keychains -d user", log: false) + .scan(/"([^"]+)"/) + .flatten + .reject { |path| path.include?(CI_KEYCHAIN_NAME) } + sh("security list-keychains -d user -s #{([CI_KEYCHAIN_DB_PATH] + others).shelljoin}") + ENV["MATCH_KEYCHAIN_NAME"] = CI_KEYCHAIN_NAME ENV["MATCH_KEYCHAIN_PASSWORD"] = CI_KEYCHAIN_PASSWORD end @@ -166,5 +180,7 @@ platform :ios do api_key: api_key, skip_waiting_for_build_processing: true ) + ensure + delete_keychain(name: CI_KEYCHAIN_NAME) if ci? && File.file?(CI_KEYCHAIN_DB_PATH) end end