Practical traps hit while getting the Aposemati apps onto real devices. Each one presents as something other than what it is.
The WWDR G3 intermediate is missing
Symptom: zero valid identities while the certificate is plainly there
security find-identity -v -p codesigning # 0 valid identities foundand
codesignfails with:errSecInternalComponent unable to build chain to self-signed root
Cause: a freshly issued Apple Development certificate is signed by the WWDR G3 intermediate. The machine had G5 and an expired legacy 2023 one, so the chain could not be built — and the tooling reports that as “no valid identities”, not as “missing intermediate”.
Fix: download and install the intermediate.
curl -O https://www.apple.com/certificateauthority/AppleWWDRCAG3.cer
open AppleWWDRCAG3.cer # or: security import AppleWWDRCAG3.cer
security find-identity -v -p codesigning # now non-zeroThe general lesson
find-identityreporting 0 does not mean the certificate is absent. It means the chain does not validate. Check the intermediates at https://www.apple.com/certificateauthority/ before re-issuing anything.
Xcode must register a device once, by hand
CLI builds with -allowProvisioningUpdates will not provision a new device. Open the project in Xcode and let it register the device once; after that the CLI path works.
Related, from the same session: free-account provisioning profiles expire in 7 days and cap at 3 apps. The paid Apple Developer Program gives 1-year profiles — a second reason to enrol beyond the Phase 7 system-extension entitlement and notarization.
A sandboxed app needs a bookmark, not a path
A stored path does not survive relaunch
A sandboxed macOS app holding a user-chosen folder must store a security-scoped bookmark, not the path string. Entitlement:
com.apple.security.files.bookmarks.app-scope.
Two follow-on traps found by review:
- Check the return value of
startAccessingSecurityScopedResource(). SettingrootandisCustomregardless means the UI shows a folder the app cannot write to, and the user learns about it once per photo instead of once. - Restoring a bookmark for an ejected volume should not silently discard the folder and permanently delete the bookmark.
rtk strips comment lines from file dumps
A false alarm worth recognising
A
catofPackage.swiftthroughrtkshowed no// swift-tools-version:directive, which reads as a broken manifest. The directive was there —rtkstrips comment lines from file dumps.Cross-check with
swift package tools-version(reported 6.2.0) orrtk proxy cat <file>before believing a missing comment-line directive. The same investigation also chasedTarget Platform: arm64e-apple-macos14.0in test output as a platform-setting failure; it is swift-testing’s runner platform, and the built object carriedminos 26.0.
Smaller notes
- XcodeGen, and the
.xcodeprojis not committed. Both inputs (project.yml+ sources) are committed and a from-scratchxcodegen generate+ build was verified byte-identical from an out-of-tree copy. Defensible, and it keeps project-file churn out of diffs. swift test --filter <NoSuchThing>exits 0 and reports “0 tests passed”. Any automation must assert the expected test count, never just the exit code. This became a standing process rule for the whole build.Info.plistfor a Bonjour peer needsNSLocalNetworkUsageDescriptionandNSBonjourServices(here exactly[_aposemati._tcp]) on both targets.
Related
- aposemati-phase0-phase1-build — the branch these were hit on
- 7. Distribution: Developer ID + notarization, not the Mac App Store — why Developer ID
- aposemati-build-process-lessons