Branch: 321-bushelxpc-provisioning-profile
Issue: BushelXPC.xpc codesign fails with errSecInternalComponent during CI archive builds
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:
delete_keychain(name: "build_keychain")— clean up from previous runscreate_keychain(name: "build_keychain", timeout: 0, lock_when_sleeps: false, ...)— fresh keychain that never auto-locksmatch(..., keychain_name: "build_keychain", ...)— import certs into this known keychainsh("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.
Job: Archive/Deploy App
Artifact: build-logs-22396779557 (uploaded, 814KB, 5 files)
Artifact URL: https://github.com/brightdigit/Bushel/actions/runs/22396779557/artifacts/5654422882
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.
The gym log contains the full raw xcodebuild output — much more detail than the GitHub Actions inline log.
# 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.logFor the current failing run:
gh run download 22396779557 -n build-logs-22396779557
open build-logs-22396779557/Bushel-Bushel.log- Go to https://github.com/brightdigit/Bushel/actions/runs/22396779557
- Scroll to the bottom → Artifacts section
- Click build-logs-22396779557 to download the zip
- Unzip → open
Bushel-Bushel.log
# 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- 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.keychainextension) fastlane_tmp_keychain-dbappears in the keychain list from previous fastlane runs
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.
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.
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
- ✅
--keychainflag passed to codesign - ❌ Still getting
errSecInternalComponent
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.
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.
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.
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
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.
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).
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.
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.
Commit 9 made no code changes to Project.swift — only Fastfile diagnostic logging. Commit 8 still had CloudKit removed. Two possibilities:
- Removing CloudKit from BushelXPC entitlements WAS the fix — run 22408664563 failed transiently for another reason, and the code was already correct
- 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.
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.
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.
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.
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.
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.
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.
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.
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()withkeychain_name: "login.keychain"andforce_for_new_devices: true- After
match, dynamically detect the default keychain and applyset-key-partition-listto it
Cleanup done:
- Fastfile
update_certificateslane stripped of all debug diagnostic output; functional partition list logic retained apple-feedback-xpc-cloudkit-codesign.mddeleted (bug report was based on incorrect root cause)
| 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:104 — build_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 SUCCEEDED — find-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 |