Skip to content

fix: drop hardcoded team prefix to support external-contributor builds#1028

Merged
datlechin merged 3 commits intoTableProApp:mainfrom
tonghs:fix/team-prefix-portability
May 6, 2026
Merged

fix: drop hardcoded team prefix to support external-contributor builds#1028
datlechin merged 3 commits intoTableProApp:mainfrom
tonghs:fix/team-prefix-portability

Conversation

@tonghs
Copy link
Copy Markdown
Contributor

@tonghs tonghs commented May 6, 2026

Summary

Implements #1020. Makes the codebase portable across Apple Developer teams so external contributors can build and run a Debug build on a personal team without hand-patching files. Release behavior under the official D7HJ5TFYCU team is unchanged: codesign reproduces the same effective entitlements.

Three failure modes were blocking external contributors:

  1. ProvisioningTablePro.entitlements declared the iCloud capability, which free personal teams don't support, so Xcode refused to create a profile.
  2. KeychainKeychainHelper.accessGroup hardcoded D7HJ5TFYCU.com.TablePro.shared, an access group only the official team can sign for. Every keychain write returned errSecMissingEntitlement. Visible symptom: "Access denied (using password: NO)" on Test Connection because the password write silently failed.
  3. RuntimeCloudKitSyncEngine.init called CKContainer(identifier:) unconditionally, which traps with EXC_BREAKPOINT on launch when the iCloud entitlement is absent.

Approach

Three pure-source changes to support both teams from the same code, plus one new shipped file and a docs update:

  • TablePro.entitlements keychain group is now $(AppIdentifierPrefix)com.TablePro.shared. codesign substitutes the active team's prefix at sign time, so the official build still signs as D7HJ5TFYCU.com.TablePro.shared and a personal-team build signs as <their-prefix>.com.TablePro.shared. Removed the redundant application-identifier and team-identifier keys (codesign auto-injects these).
  • KeychainHelper reads keychain-access-groups from the running process via SecTaskCopyValueForEntitlement at init, prefers the entry ending in .com.TablePro.shared, and validates it matches ^[A-Z0-9]{10}\..+ (rejects unsubstituted $(...) templates from ad-hoc builds). When no valid group is declared, baseQuery simply omits kSecAttrAccessGroup, letting the keychain fall back to the default per-app group.
  • CloudKitSyncEngine adds a static func hasICloudEntitlement() and makes container / database optional. init only constructs them when the entitlement is present; otherwise it logs a warning and stays disabled. Each method guard let container/database else { throw SyncError.accountUnavailable }. SyncCoordinator.currentAccountId was reaching across into a duplicated CKContainer(identifier:) literal — it now delegates to a new engine.currentAccountId() method, removing that duplication.
  • TablePro/TablePro.Debug.entitlements is new: identical to the default minus the iCloud keys. Contributors on personal teams point Debug builds at it instead of the iCloud-enabled file. iCloud sync degrades gracefully at runtime when the entitlement is absent (existing do/catch paths surface "iCloud unavailable" through the existing UI).

Tests

TableProTests/Core/Sync/CloudKitSyncEngineTests.swift — 6 cases verifying the soft-dependency path. Each gates with try #require(!CloudKitSyncEngine.hasICloudEntitlement()) so it auto-skips when the test host happens to be signed with iCloud (otherwise the tests would hit real CloudKit). Covers checkAccountStatus, ensureZoneExists, push (non-empty + empty short-circuit), pull, and currentAccountId.

Contributor setup

CONTRIBUTING.md adds a section on the one-time Xcode UI setup for non-official teams: Team selection (with note about repeating for other targets if signing fails), Bundle Identifier change, and switching Code Signing Entitlements to the new Debug variant. Also documents that the resulting pbxproj changes shouldn't be committed (revert or use git update-index --skip-worktree).

CHANGELOG

Entry under [Unreleased]### Fixed. Fixes #1020.

Test plan

  • swiftlint lint --strict — 0 violations
  • Debug build succeeds on a personal Apple ID team after the documented Xcode UI setup
  • Saving a database connection password and reconnecting works (verifies keychain access group fallback)
  • iCloud sync UI surfaces "disabled" state instead of crashing on a build without iCloud entitlement
  • xcodebuild ... test -only-testing:TableProTests/CloudKitSyncEngineTests passes locally
  • Maintainer to verify: Release build on the official team produces a binary with the same effective entitlements (codesign -d --entitlements - should still show D7HJ5TFYCU.com.TablePro.shared as the keychain access group)

@chatgpt-codex-connector
Copy link
Copy Markdown

Codex usage limits have been reached for code reviews. Please check with the admins of this repo to increase the limits by adding credits.
Credits must be used to enable repository wide code reviews.

@datlechin datlechin merged commit 723b0a2 into TableProApp:main May 6, 2026
1 check passed
@datlechin
Copy link
Copy Markdown
Member

Thank you.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Hardcoded team prefix and bundle ID block external contributors from building locally

2 participants