Skip to content

Stop a missing signing profile from shipping a dead app - #192

Merged
arzafran merged 1 commit into
mainfrom
fix/provision-profile-guard
Jul 29, 2026
Merged

Stop a missing signing profile from shipping a dead app#192
arzafran merged 1 commit into
mainfrom
fix/provision-profile-guard

Conversation

@arzafran

Copy link
Copy Markdown
Member

What this does

The app needs a provisioning profile from Apple to use iCloud. Without one it still builds, still gets signed, still passes Apple's notarization, and then refuses to open on every machine it lands on. Nothing in the pipeline noticed.

The check that exists to catch this was written when the app used no Apple services, so it said a missing profile was expected and let the build through. That stopped being true when CloudKit landed this morning, which left the one guard against a dead release asserting the release was fine.

It now reads what the app actually asks for and stops the build if the profile is missing, or if the profile it has does not cover it.

Summary

  • verify-provision-profile.sh now reads entitlements from the signature via codesign -d --entitlements, not from the source .entitlements file. The two can diverge, and the signature is what AMFI reads at launch.
  • Fails when restricted entitlements are declared and no profile is embedded (previously exit 0 with "This is expected for the current build").
  • Also fails when a profile is present but does not grant every restricted entitlement. A profile generated against the wrong App ID bricks exactly as hard as no profile, and nothing checked that before.
  • com.apple.developer.* is treated as restricted, with team-identifier excluded — codesign injects that into essentially every Developer-ID bundle, so including it failed every build.
  • Corrected the stale comments in release.yml and sign-release-app.sh that still claimed the app ships no restricted entitlements and that a missing profile is harmless.

Test plan

Verified against real signed bundles on macOS 26.5.2:

  • IINA.app (no restricted entitlements, no profile) → exit 0
  • 1Password.app (associated-domains + authentication-services, with profile) → exit 0, reports "covers all 2 restricted entitlement(s)"
  • Dato.app (usernotifications.time-sensitive, no profile) → exit 1, fail-closed
  • Programa signed with the real programa.entitlements and no profile → exit 1, naming icloud-services and icloud-container-identifiers. This is the AMFI-brick case, and it was previously exit 0.

Note on the deliberate asymmetry: aps-environment and usernotifications.* are not excluded even though Dato and Xcode demonstrably ship them without profiles. Programa uses neither, and an unnecessary failure is a loud one-line fix while a missed one ships an app that will not launch. If either is ever added and this fires, check Apple's capability docs before widening the exclusion.

A Debug build cannot exercise this: CODE_SIGN_ENTITLEMENTS is empty in the project and programa.entitlements is applied post-build by sign-release-app.sh, so only release-path bundles carry the restricted keys.

The app needs a provisioning profile from Apple to use iCloud. Without
one it still builds, still gets signed, still passes Apple's checks, and
then refuses to open on every machine it lands on.

The check meant to catch that was written back when the app used no
Apple services, so it said a missing profile was fine and passed the
build. That stopped being true this morning. It now reads what the app
actually asks for and stops the build when the profile is missing, or
when the profile it has does not cover it.
@arzafran
arzafran merged commit a4810d1 into main Jul 29, 2026
8 of 10 checks passed
@arzafran
arzafran deleted the fix/provision-profile-guard branch July 29, 2026 16:43
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.

1 participant