Skip to content

Instantly share code, notes, and snippets.

@leogdion
Created February 25, 2026 23:51
Show Gist options
  • Select an option

  • Save leogdion/30298f56b6bc9a52feb02775e1e21e11 to your computer and use it in GitHub Desktop.

Select an option

Save leogdion/30298f56b6bc9a52feb02775e1e21e11 to your computer and use it in GitHub Desktop.
CI Codesign Debugging: errSecInternalComponent on macOS 26 with Fastlane Match

CI Codesign Debugging Log

Branch: 321-bushelxpc-provisioning-profile Issue: BushelXPC.xpc codesign fails with errSecInternalComponent during CI archive builds


Summary of Changes Made

Commit 1 — 5544dd0 — "Fix CI codesign errSecInternalComponent by setting keychain partition list"

What we did: After match imports certs and unlock_keychain unlocks the login keychain, explicitly call security set-key-partition-list on login.keychain-db.

Result: Still failed with errSecInternalComponent. The command ran for 0 seconds in the fastlane summary — likely a no-op because the certificate private keys may not actually be in login.keychain-db in the CI environment (macOS 26).


Commit 2 — 58657330 — "Fix codesign errSecInternalComponent with dedicated keychain and archive build logs"

What we did (Fastfile): Replaced the login.keychain approach with a dedicated build_keychain:

  1. delete_keychain(name: "build_keychain") — clean up from previous runs
  2. create_keychain(name: "build_keychain", timeout: 0, lock_when_sleeps: false, ...) — fresh keychain that never auto-locks
  3. match(..., keychain_name: "build_keychain", ...) — import certs into this known keychain
  4. sh("security set-key-partition-list ... ~/Library/Keychains/build_keychain.keychain-db") — set ACL

What we did (main.yml): Added Upload Build Logs step (if: always()) to upload ~/Library/Logs/gym/ as an artifact named build-logs-{run_id} after every Deploy step, pass or fail.

Result (run 22396779557): ❌ Still failed, but with a different and new error.


Current Failure — Run 22396779557

Job: Archive/Deploy App Artifact: build-logs-22396779557 (uploaded, 814KB, 5 files) Artifact URL: https://github.com/brightdigit/Bushel/actions/runs/22396779557/artifacts/5654422882

What happened

The build now crashes in update_certificates before xcodebuild even runs, at Fastfile:104 — our explicit sh("security set-key-partition-list") call.

Root cause: keychain path mismatch.

When fastlane create_keychain(name: "build_keychain") runs on this version of macOS, the keychain file is created at:

~/Library/Keychains/build_keychain-db

But our set-key-partition-list call targets:

~/Library/Keychains/build_keychain.keychain-db   ← WRONG

These are different files. The command fails with nonzero exit code because the path doesn't exist.

Additionally: match already runs set-key-partition-list internally for each certificate it imports (visible in the log: skip_set_partition_list: false). Our explicit call at the end is redundant.

From the log:

INFO: $ security import .../certs/distribution/KY2WP5Y4S7.p12
      -k '/Users/services/Library/Keychains/build_keychain-db' ...
INFO: Setting key partition list...
INFO: $ security set-key-partition-list -S apple-tool:,apple:,codesign: -s -k ***
      /Users/services/Library/Keychains/build_keychain-db 1> /dev/null

Match correctly uses build_keychain-db. Then our lane runs:

INFO: $ security set-key-partition-list -S apple-tool:,apple:,codesign: -s -k ***
      /Users/services/Library/Keychains/build_keychain.keychain-db

→ crashes because build_keychain.keychain-db does not exist.


How to Pull the Build Log from the Artifact

The gym log contains the full raw xcodebuild output — much more detail than the GitHub Actions inline log.

Option A — GitHub CLI (fastest)

# List artifacts for the run
gh run view <run_id> --json artifacts

# Download the artifact
gh run download <run_id> -n build-logs-<run_id>

# The log will be at:
# build-logs-<run_id>/Bushel-Bushel.log

For the current failing run:

gh run download 22396779557 -n build-logs-22396779557
open build-logs-22396779557/Bushel-Bushel.log

Option B — GitHub UI

  1. Go to https://github.com/brightdigit/Bushel/actions/runs/22396779557
  2. Scroll to the bottom → Artifacts section
  3. Click build-logs-22396779557 to download the zip
  4. Unzip → open Bushel-Bushel.log

Searching the log for codesign errors

# Find codesign failures
grep -n "errSec\|CodeSign failed\|ARCHIVE FAILED\|The following build" Bushel-Bushel.log

# Find the actual codesign invocation
grep -n "^CodeSign\|^/usr/bin/codesign" Bushel-Bushel.log

# Find keychain-related output
grep -n "keychain\|partition" Bushel-Bushel.log

CI Environment Notes

  • Runner: Leos-Mac-Mini-M2 (self-hosted)
  • Runner user: services (/Users/services/)
  • Xcode: /Applications/Xcode.app (version 26.2)
  • Keychain path format on this OS: ~/Library/Keychains/{name}-db (no .keychain extension)
  • fastlane_tmp_keychain-db appears in the keychain list from previous fastlane runs

Commit 3 — 9c5f3bc1 — "Fix CI codesign by removing redundant set-key-partition-list call"

What we did: Removed the explicit sh("security set-key-partition-list") call from update_certificates lane since match already handles this internally.

Result (run 22400553728): ❌ Fixed the path error (Fastfile no longer crashes), but BushelXPC.xpc still fails with errSecInternalComponent during the actual xcodebuild codesign step.

Key finding: The error "There are no local code signing identities found" and "SecItemCopyMatching: The specified item could not be found in the keychain" appeared during certificate import, but certificates DID get imported. The codesign failure happens later when xcodebuild tries to sign BushelXPC.xpc.


Commit 4 — f7deaa1e — "Pass keychain to xcodebuild to fix errSecInternalComponent"

What we did: Added OTHER_CODE_SIGN_FLAGS="--keychain /path/to/build_keychain-db" to the build_app call via xcargs parameter, so codesign explicitly knows which keychain to use.

Result (run 22404004601): ❌ The --keychain flag IS being passed correctly to codesign (verified in build logs), but still errSecInternalComponent.

Build log shows:

/usr/bin/codesign --force --sign 0175E92BF420A8802DED6B650550D7D593AED42A --keychain /Users/services/Library/Keychains/build_keychain-db --entitlements ... BushelXPC.xpc
BushelXPC.xpc: errSecInternalComponent

Analysis: The issue is NOT that codesign doesn't know which keychain to use — it does. The problem is that it can't ACCESS the private key in that keychain.


Commit 5 — 280dbe6d — "Explicitly unlock keychain before xcodebuild"

What we did: Added explicit unlock_keychain(path: keychain_path, password: keychain_password) call before build_app, even though create_keychain already set timeout: 0 (never lock).

Result (run 22407651314): ❌ The unlock step completed successfully (visible in logs), but still errSecInternalComponent.

Summary so far: We now have:

  • ✅ Keychain created correctly
  • ✅ Certificates imported
  • ✅ Partition list set by match
  • ✅ Keychain explicitly unlocked
  • --keychain flag passed to codesign
  • ❌ Still getting errSecInternalComponent

Commit 6 — 372e2537 — "Use default keychain instead of custom keychain"

What we did: Completely removed custom keychain approach. Simplified update_certificates to just call match without any keychain creation, unlock, or xcargs parameters. Let match use the system's default login keychain.

Rationale: Custom keychains in CI can have ACL/permissions issues on newer macOS versions. The default keychain should already have proper system configuration.

Result (run 22408023891): ❌ Even with the default keychain, still errSecInternalComponent.

Critical insight: This persistent error across ALL approaches (custom keychain, default keychain, explicit unlock, explicit keychain path) suggests the problem is NOT with keychain access configuration, but with WHAT we're trying to sign.


Commit 7 (workflow) — 5044dc4e — "Temporarily disable build/lint jobs to focus on deploy"

What we did: Modified .github/workflows/main.yml to disable build-macos, build-linux, and lint jobs by adding && false to their if conditions, and removed the needs dependency from the deploy job.

Result: CI runs complete in ~8 minutes instead of 1+ hour, allowing much faster iteration on the codesign fixes.


Root Cause Investigation

Key Discovery: Branch Name and CloudKit Entitlements

Branch name: 321-bushelxpc-provisioning-profile

This branch is specifically about BushelXPC's provisioning profile configuration. The persistent errSecInternalComponent error across all keychain-related fixes suggests the issue is in the Xcode project configuration, not the Fastfile.

BushelXPC Entitlements in Project.swift

Both Bushel.app and BushelXPC.xpc have CloudKit entitlements:

entitlements: .dictionary([
    "com.apple.security.app-sandbox": true,
    "com.apple.security.application-groups": ["group.com.brightdigit.Bushel"],
    // ... other entitlements ...
    "com.apple.security.virtualization": true,
    "com.apple.vm.networking": true,
    "com.apple.developer.icloud-container-identifiers": ["iCloud.com.brightdigit.Bushel"],
    "com.apple.developer.icloud-services": ["CloudKit"]
])

Hypothesis: If the com.brightdigit.BushelXPC App ID in the Apple Developer portal does NOT have CloudKit capability enabled, then the provisioning profile won't include these entitlements. When xcodebuild tries to sign with CloudKit entitlements specified in code but not in the profile, it fails with errSecInternalComponent due to entitlement mismatch.

Provisioning profile verification: The profile IS being installed correctly (visible in match logs):

Profile UUID: 7047e6ed-9faa-497c-b1ff-34fd31e655ed
Profile Name: match AppStore com.brightdigit.BushelXPC macos
Profile Path: /Users/services/Library/Developer/Xcode/UserData/Provisioning Profiles/7047e6ed-9faa-497c-b1ff-34fd31e655ed.provisionprofile

Commit 8 — 8cdbbc6a — "Test: Remove CloudKit entitlements from BushelXPC"

What we did: Temporarily removed CloudKit entitlements from BushelXPC in Project.swift:

entitlements: .dictionary([
    "com.apple.security.app-sandbox": true,
    "com.apple.security.application-groups": ["group.com.brightdigit.Bushel"],
    "com.apple.security.files.bookmarks.app-scope": true,
    "com.apple.security.network.server": true,
    "com.apple.security.virtualization": true,
    "com.apple.vm.networking": true
    // TEMPORARILY REMOVED CloudKit to test if provisioning profile mismatch is causing errSecInternalComponent
    // "com.apple.developer.icloud-container-identifiers": ["iCloud.com.brightdigit.Bushel"],
    // "com.apple.developer.icloud-services": ["CloudKit"]
])

Test hypothesis: If codesigning succeeds without CloudKit entitlements, it confirms the provisioning profile doesn't have CloudKit enabled.

Result (run 22408664563): ❌ Still fails with errSecInternalComponent — CloudKit was not the cause.

Key insight from decoding provisioning profiles: Both the Bushel.app profile and BushelXPC profile were decoded locally. The com.apple.security.virtualization absence is normal — it's missing from BOTH profiles, and there is no "Virtualization" capability in the Apple Developer Portal for either App ID. All com.apple.security.* sandbox entitlements work this way (not validated against the profile).

Initial root cause diagnosis (Virtualization missing from profile) was WRONG. See corrected analysis below.


Root Cause Investigation — Corrected Analysis

Profile comparison (decoded locally)

BushelXPC profile (7047e6ed) entitlements:

com.apple.application-identifier: MLT7M394S7.com.brightdigit.BushelXPC
com.apple.developer.aps-environment: production
com.apple.developer.group-session: True
com.apple.developer.icloud-container-identifiers: [iCloud.com.brightdigit.Bushel]
com.apple.developer.icloud-services: *
com.apple.developer.shared-with-you: True
com.apple.developer.team-identifier: MLT7M394S7
com.apple.developer.ubiquity-*
com.apple.security.application-groups: [group.com.brightdigit.Bushel, MLT7M394S7.*]
com.apple.vm.networking: True
keychain-access-groups: [MLT7M394S7.*]

Bushel.app profile (db0018dd) — same as above PLUS:

com.apple.developer.game-center: True
com.apple.developer.networking.vmnet: True

Both profiles are missing com.apple.security.virtualization, app-sandbox, etc. — this is the same for both targets and is normal (sandbox entitlements don't need to be in profiles).

Additional finding: CloudKit IS enabled for BushelXPC in the portal

Verified in Apple Developer Portal screenshot: com.brightdigit.BushelXPC App ID does have iCloud/CloudKit capability enabled, with iCloud.com.brightdigit.Bushel as the container. This is consistent with the decoded profile (7047e6ed) which contains:

com.apple.developer.icloud-container-identifiers: [iCloud.com.brightdigit.Bushel]
com.apple.developer.icloud-services: *

So both the portal AND the profile have CloudKit for BushelXPC. Removing it from the entitlements in Commit 8 was unnecessary — or the Commit 8 failure was a transient runner issue unrelated to CloudKit.

Commit 9 result — find-identity diagnostic (run 22411357598): ✅ ARCHIVE SUCCEEDED

find-identity output:

1) 0175E92BF420A8802DED6B650550D7D593AED42A "Apple Distribution: BRIGHT DIGIT LLC (MLT7M394S7)"
2) 0175E92BF420A8802DED6B650550D7D593AED42A "Apple Distribution: BRIGHT DIGIT LLC (MLT7M394S7)"
...
10 valid identities found

The cert appears 9× because it has accumulated across multiple keychains (fastlane_tmp_keychain-db, login.keychain-db, build_keychain-db) from previous runs. The private key is accessible.

list-keychains output:

"/Users/services/Library/Keychains/fastlane_tmp_keychain-db"
"/Users/services/Library/Keychains/login.keychain-db"
"/Users/services/Library/Keychains/build_keychain-db"

build_keychain-db is still in the search list from previous attempts — this is leftover state but harmless.

** ARCHIVE SUCCEEDED ** — full build and codesign passed.

Open question: what actually fixed it?

Commit 9 made no code changes to Project.swift — only Fastfile diagnostic logging. Commit 8 still had CloudKit removed. Two possibilities:

  1. Removing CloudKit from BushelXPC entitlements WAS the fix — run 22408664563 failed transiently for another reason, and the code was already correct
  2. Transient runner issue — run 22408664563 had some ephemeral state problem and would have passed anyway; need to re-add CloudKit and verify

Since the portal and profile both have CloudKit for BushelXPC, and the main app uses CloudKit with BushelXPC in the same app group, CloudKit should be restored and verified to ensure it wasn't just a transient fluke.


Next Steps

Commit 10 — dbd76008 — "Test: Re-add CloudKit entitlements to BushelXPC to verify fix"

Restored original CloudKit entitlements in Project.swift to determine whether their removal was the real fix or a transient runner fluke.

Result (run 22412113540):BushelXPC.xpc: errSecInternalComponent — confirmed. CloudKit entitlements on the XPC service are the definitive trigger.

Conclusion: This is an Xcode 26.2 bug. The portal has CloudKit enabled, the provisioning profile contains the CloudKit entitlements, and the same entitlements on the parent .app sign successfully. The failure is specific to .xpc product type with iCloud entitlements. Apple Feedback submitted (see apple-feedback-xpc-cloudkit-codesign.md).

Resolution: Keep CloudKit removed from BushelXPC entitlements. XPC services do not need direct CloudKit access — the main app handles all data sync. The CloudKit capability can remain enabled in the portal and profile without being in the XPC entitlements.


Commit 11 — 4956a9c3 — "Set macOS 15.0 deployment target and clean up debug code"

What we did: Unrelated to codesign — added deploymentTargets: .macOS("15.0") to all three targets in Project.swift and removed a stray debug call from WelcomeView. CloudKit entitlements remained in BushelXPC (restored from Commit 10).

Result (run 22413650654):BushelXPC.xpc: errSecInternalComponent — CloudKit entitlements still present, codesign still failing.


Commit 12 — 21b65bea — "Fix BushelXPC codesigning: specify Xcode path and force profile refresh"

What we did: Added DEVELOPER_DIR='/Applications/Xcode.app/Contents/Developer' to build_app xcargs to ensure the correct Xcode is used on CI, and added force_for_new_devices: true to match to force provisioning profile refresh.

Result (run 22414564725): ❌ Still errSecInternalComponent.


Commit 13 — 63035c80 — "Fix keychain partition list to resolve errSecInternalComponent"

What we did: Added explicit security set-key-partition-list after match, targeting ~/Library/Keychains/login.keychain-db.

Result (run 22416785476): ❌ Still failing — partition list was targeting login.keychain-db but Match's certificates were in the temp keychain.


Commit 14 — f0f12a56 — "Add keychain debugging and reduce CI artifacts to Bushel-Bushel.log"

What we did: Added detailed diagnostic output (list-keychains, find-identity, provisioning profiles) before and after the partition list step. Reduced CI artifact upload to just Bushel-Bushel.log.

Result (run 22416838206): ❌ Still failing.


Commit 15 — bf7bb975 — "Critical fix: Force Match to use login keychain instead of temp keychain"

What we did: Added keychain_name: "login.keychain" to match() so certificates would go into the login keychain. Also hardcoded partition list target to ~/Library/Keychains/login.keychain-db.

Result (run 22417671286): ❌ Still failing — keychain_name does not prevent Match from creating fastlane_tmp_keychain-db. The partition list was still targeting the wrong keychain.


Commit 16 — f9d7da0c — "Fix partition list by targeting Match's actual temp keychain"

What we did: Instead of hardcoding the keychain path, dynamically detect which keychain is the current default after Match runs:

default_keychain = sh("security default-keychain -d user", log: false).strip.tr('"', '')
sh("security set-key-partition-list -S apple-tool:,apple:,codesign: -s -k '#{keychain_password}' '#{default_keychain}' 2>&1 || true")

Key insight: Match sets fastlane_tmp_keychain-db as the default keychain when it creates one, regardless of keychain_name. Querying security default-keychain after match returns the temp keychain, so the partition list is now applied to the correct keychain.

Result (run 22418214893):ARCHIVE SUCCEEDED — codesign passes for both Bushel.app and BushelXPC.xpc. CloudKit entitlements are present in BushelXPC.


Final Resolution

Root cause (corrected): The errSecInternalComponent error was a keychain partition list issue, not a CloudKit/entitlement mismatch. Match always creates fastlane_tmp_keychain-db and sets it as the default keychain. The partition list fix was targeting login.keychain-db — the wrong keychain. Once the partition list was applied to the actual default keychain (the temp one), codesign could access the private key.

Conclusion: The earlier "CloudKit was the fix" finding (Commit 9 passing) was a transient runner coincidence. CloudKit entitlements are valid for BushelXPC and have been restored.

Fix summary:

  • match() with keychain_name: "login.keychain" and force_for_new_devices: true
  • After match, dynamically detect the default keychain and apply set-key-partition-list to it

Cleanup done:

  • Fastfile update_certificates lane stripped of all debug diagnostic output; functional partition list logic retained
  • apple-feedback-xpc-cloudkit-codesign.md deleted (bug report was based on incorrect root cause)

Run History

Run Commit Result Error
22385933496 5544dd0 BushelXPC.xpc: errSecInternalComponent (codesign) — set-key-partition-list targeted login.keychain but had no effect
22396779557 58657330 sh crash at Fastfile:104build_keychain.keychain-db does not exist (should be build_keychain-db)
22400553728 9c5f3bc1 BushelXPC.xpc: errSecInternalComponent — Fixed path error, but codesign still fails accessing private key
22404004601 f7deaa1e BushelXPC.xpc: errSecInternalComponent — Added OTHER_CODE_SIGN_FLAGS="--keychain ...", still fails
22407651314 280dbe6d BushelXPC.xpc: errSecInternalComponent — Added explicit unlock_keychain, still fails
22408023891 372e2537 BushelXPC.xpc: errSecInternalComponent — Switched to default keychain, still fails
22408664563 8cdbbc6a BushelXPC.xpc: errSecInternalComponent — Removed CloudKit; decoded both profiles: Virtualization missing from BOTH (normal, not the cause); root cause unknown — need find-identity diagnostic
22411357598 812a6828 ARCHIVE SUCCEEDEDfind-identity confirmed cert accessible (10 valid identities, hash matches); CloudKit still removed from BushelXPC; portal confirmed CloudKit IS enabled for BushelXPC identifier
22412113540 dbd76008 BushelXPC.xpc: errSecInternalComponent — Re-added CloudKit; previously thought to be the trigger; actually a transient runner coincidence
22413650654 4956a9c3 BushelXPC.xpc: errSecInternalComponent — macOS 15.0 deployment target + debug cleanup; CloudKit re-added; codesign still failing
22414564725 21b65bea BushelXPC.xpc: errSecInternalComponent — Added DEVELOPER_DIR to xcargs and force_for_new_devices: true to match
22416785476 63035c80 BushelXPC.xpc: errSecInternalComponent — Added set-key-partition-list but hardcoded login.keychain-db; certs were in the temp keychain
22416838206 f0f12a56 BushelXPC.xpc: errSecInternalComponent — Added diagnostic output; partition list still targeting wrong keychain
22417671286 bf7bb975 BushelXPC.xpc: errSecInternalComponent — Added keychain_name: "login.keychain"; Match still creates temp keychain regardless
22418214893 f9d7da0c ARCHIVE SUCCEEDED — Dynamically detect default keychain after match; partition list now targets fastlane_tmp_keychain-db (the actual keychain Match uses); CloudKit present in BushelXPC
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment