Skip to content

[build-tools] Fix iOS local build on macOS Tahoe — drop -v from find-identity in findIdentitiesByTeamId#3679

Open
kearnsm293-afk wants to merge 2 commits into
expo:mainfrom
kearnsm293-afk:fix/keychain-find-identity-trust-chain-tahoe
Open

[build-tools] Fix iOS local build on macOS Tahoe — drop -v from find-identity in findIdentitiesByTeamId#3679
kearnsm293-afk wants to merge 2 commits into
expo:mainfrom
kearnsm293-afk:fix/keychain-find-identity-trust-chain-tahoe

Conversation

@kearnsm293-afk
Copy link
Copy Markdown

Why

Closes #3678. On macOS 26 (Tahoe), eas build --profile development --platform ios --local fails at Prepare credentials with Distribution certificate ... hasn't been imported successfully even when the cert+key are correctly imported into the build keychain.

Keychain.findIdentitiesByTeamId runs:

security find-identity -v -s "(<teamId>)" <buildKeychainPath>

The -v ("valid identities only") flag requires the full trust chain (dist cert → Apple WWDR Intermediate → Apple Root CA) to resolve from the keychain(s) in the search list. The build keychain (created in Keychain.create()) only holds the cert + private key; Apple Root CA lives in /Library/Keychains/System.keychain and Apple WWDR G3 lives in the user's login keychain. security find-identity does not aggregate trust resolution across keychains passed as positional args — only security list-keychains -s does, and that change would be session-wide and undesirable.

On macOS 26 (Tahoe), this trust gate causes find-identity -v -s "(<teamId>)" <buildKeychainPath> to return 0 identities even when the cert+key were correctly imported, falsely tripping ensureCertificateImported.

How

Drop -v from the find-identity call. The remaining flags (-s "(<teamId>)" <buildKeychainPath>) still constrain the match to the right team and keychain, so the includes(fingerprint) check in ensureCertificateImported correctly answers "is the cert+key pair present in this keychain?" The cert appears in the output annotated (CSSMERR_TP_NOT_TRUSTED) — that's expected and ignored. Codesign performs its own trust resolution downstream via Security.framework (which does aggregate across keychains), so signing still succeeds end-to-end.

The change is one line in packages/build-tools/src/ios/credentials/keychain.ts plus a comment block explaining the reasoning so a future reader doesn't add -v back.

Test Plan

  • The existing integration test packages/build-tools/src/ios/credentials/__integration-tests__/keychain.test.ios.ts ("shouldn't throw any error if the certificate has been imported successfully") covers exactly this scenario. It currently fails on macOS 26 (Tahoe) due to this bug; the fix makes it pass.
  • Manually verified end-to-end: eas build --profile development --platform ios --local against an Expo-managed dist cert + ad-hoc provisioning profile completes successfully on macOS 26.0 (Tahoe) with the patch applied. Produces a signed .ipa that installs and runs on a registered iOS 26 device.
  • No regression risk on older macOS: dropping -v is strictly more permissive in what find-identity reports back. On systems where -v worked (older macOS, or systems where Apple Root CA happens to be visible in the build keychain's effective search list), the same cert+key pair still appears in the output without -v. The includes(fingerprint) check passes in both cases.

Checklist

  • CHANGELOG.md updated under ## main### 🐛 Bug fixes. (PR URL placeholder will be replaced with the real PR number once this is opened.)
  • Commit message follows the [package] Description format.
  • No public API change. No breaking change.

MikeK968 added 2 commits May 5, 2026 21:55
…identity in findIdentitiesByTeamId

`Keychain.findIdentitiesByTeamId` runs `security find-identity -v -s
"(<teamId>)" <buildKeychainPath>` to verify that the dist cert was
imported into the freshly-created build keychain. The `-v` ("valid
identities only") flag requires the full trust chain (dist cert ->
Apple WWDR Intermediate -> Apple Root CA) to resolve from the
keychain(s) in the search list. The build keychain only holds the
cert + private key; Apple Root CA lives in
/Library/Keychains/System.keychain. `security find-identity` does
not aggregate trust resolution across keychains passed as positional
args — only `security list-keychains -s` does, and that's
session-wide and would mutate the user's environment.

On macOS 26 (Tahoe), this caused `find-identity -v` to return 0
identities even when the cert+key were correctly imported, falsely
tripping `ensureCertificateImported` with "Distribution certificate
... hasn't been imported successfully".

Dropping `-v` fixes the presence check across macOS versions.
Codesign performs its own trust resolution downstream via
Security.framework (which does aggregate across keychains), so
signing still succeeds.

Existing integration test
`packages/build-tools/src/ios/credentials/__integration-tests__/keychain.test.ios.ts`
("shouldn't throw any error if the certificate has been imported
successfully") covers this scenario and now passes on Tahoe.

Closes expo#3678
@github-actions
Copy link
Copy Markdown

github-actions Bot commented May 6, 2026

Subscribed to pull request

File Patterns Mentions
**/* @douglowder

Generated by CodeMention

@jaketoolson
Copy link
Copy Markdown

This has happened to me.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

3 participants