Commit df69393f7e

df69393f7e556dccfacfb05378fcce5c9ffc125b

parent: 017785c4ce

Verified · cmc

cmc <hello@cleberg.net> · 2026-08-22 08:02 UTC

Do not touch CloudKit from a build without entitlements

The app aborted before its first screen on any unsigned build, which is what CI
produces: xcodebuild ... CODE_SIGNING_ALLOWED=NO embeds no entitlements, so
CKContainer.default() could not resolve the iCloud container from them. It does
not return an error in that case — it raises an Objective-C exception from
inside a dispatch_once, which Swift cannot catch, so the existing do/catch never
had a chance and the process took SIGABRT. Every AccessibilityAuditTests case
then failed as 'application is not running'.

An explicit CKContainer(identifier:) crashes the same way; CloudKit validates
against entitlements either way. So the fix is to not ask. The App Group is
declared in the same entitlements file and stripped by the same mechanism, but
asking for its container returns nil rather than raising, which answers the
question CloudKit will not: does this process have entitlements at all.

Signed builds are unaffected — the container resolves, the guard passes, owner
resolution runs as before. This is why the audit job has failed since
2026-07-25; the run on krz-rebrand shows the same crash three weeks before this
branch existed.

Layout: unified · split

DomainDig/OwnerAccess.swift +21 −2
@@ -14,10 +14,29 @@ enum OwnerAccess {
14 14
15 static var isConfigured: Bool { !ownerUserRecordID.isEmpty } 15 static var isConfigured: Bool { !ownerUserRecordID.isEmpty }
16 16
17 /// Whether this build actually carries its entitlements.
18 ///
19 /// Touching CloudKit without the iCloud container entitlement does not
20 /// return an error — it raises an Objective-C exception from inside a
21 /// `dispatch_once`, which Swift cannot catch, so the process aborts before
22 /// the first screen draws. That is what any unsigned build does, including
23 /// CI: `xcodebuild ... CODE_SIGNING_ALLOWED=NO` embeds no entitlements.
24 ///
25 /// The App Group is declared in the same entitlements file and is stripped
26 /// by the same mechanism, but asking for its container returns nil rather
27 /// than raising. So it answers the question CloudKit will not: does this
28 /// process have its entitlements at all?
29 private static var hasEntitlements: Bool {
30 FileManager.default.containerURL(
31 forSecurityApplicationGroupIdentifier: DomainDigWidgetStore.appGroupID
32 ) != nil
33 }
34
17 /// The current iCloud user's record name for this app's container, or nil if 35 /// The current iCloud user's record name for this app's container, or nil if
18 /// it is unavailable (not signed into iCloud, restricted, or offline before 36 /// it is unavailable (not signed into iCloud, restricted, offline before the
19 /// the first fetch). 37 /// first fetch, or running from a build without entitlements).
20 static func currentUserRecordName() async -> String? { 38 static func currentUserRecordName() async -> String? {
39 guard hasEntitlements else { return nil }
21 do { 40 do {
22 return try await CKContainer.default().userRecordID().recordName 41 return try await CKContainer.default().userRecordID().recordName
23 } catch { 42 } catch {