ITMS-90885 “${executable}” in bundle “${bundle}” is missing a provisioning profile

I'm struggling to get past the following error from Transporter. I've tried everything I can think of and I'm not sure what else to do.

WARNING ITMS-90885: ""Cannot be used with TestFlight because the executable “${executable}” in bundle “${bundle}” is missing a provisioning profile but has an application identifier in its signature. Nested executables are expected to have provisioning profiles with application identifiers matching the identifier in the signature in order to be eligible for TestFlight.""

Setup

  • I'm using electron with a main.app and nested helper apps (e.g. Main.app/Contents/Frameworks/Main Helper (Renderer).app)
  • I'm trying to upload to the Mac App Store
  • I'm codesign-ing the contents with Apple Distribution: ... and signing the pkg installer with 3rd Party Mac Developer Installer: ...
  • I'm using osx-sign to manage the code signing for me: basically it's doing a whole bunch of this:
codesign --sign {40-char-hash} --force --timestamp --options runtime --entitlements "$CHILD_PLIST" "packages/mas-universal/{APP_NAME}.app/Contents/Frameworks/{APP_NAME} Helper (Renderer).app"

Replies

Many Mac apps do not need a provisioning profile. This is only necessary if your app uses restricted entitlements [1], where you need the profile to authorise the use of those entitlements.

However, this changes with TestFlight. A TestFlight app must have a profile. If you have an existing Mac app that doesn’t have a profile, you have to tweak your build system to give it a profile if you want to distribute it using TestFlight.

How you do that depends on how your app is built. With Xcode it’s as simple as enabling a restricted entitlements on your app target. Any one will do, but I tend to use the Keychain Access Groups one. Xcode’s automatic code signing will then kick in and do the right thing.

If you’re using third-party tooling then you should consult with the support resources for that tooling.

Alternatively, if you want to do this by hand, a good starting point is:

Within that context, you’ll then need to:

  1. Use the Developer website to allocate an App ID for your app.

  2. Then create a Distribution > Mac App Store provisioning profile for that App ID, making sure to include the Apple Distribution you’re going to sign with.

  3. Embed that profile within your app, per the rules in Placing Content in a Bundle.

  4. Add the App ID and Team ID entitlements to your .entitlements file.

  5. Then sign and package your app as before.

Regarding step 4, I recommend that you use Xcode to work out exactly what entitlements to use:

  1. Create a test project that has the same bundle ID as your existing app.

  2. Add a restricted entitlement of your choosing.

  3. Do a Build > Archive.

  4. In the organiser, export that app for App Store distribution.

  5. Pull apart the installer package.

  6. Dump the app’s entitlements to see what Xcode included.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

[1] As defined in TN3125 Inside Code Signing: Provisioning Profiles.

Quinn, I just got this warning, but I don't want to use TestFlight for Mac. Is there any way to avoid getting the warning?

By the way, this sounds like a great way to get rejected by App Review: "How you do that depends on how your app is built. With Xcode it’s as simple as enabling a restricted entitlements on your app target." I've gotten rejections in the past for unused entitlements.

@eskimo, thank you for your response. (and thank you for all your comments in the developer forums, they've been really helpful!)

Unfortunately I can't build my app via xcode (or maybe just don't know how) so I can't really test the different entitlements (e.g. the keychain one) in xcode. I build a sample app and added the keychain entitlement so I could see what keys got added. I tried adding this to my entitlements file, but it didn't solve the error.

<key>keychain-access-groups
</key>
<array>
<string>$(AppIdentifierPrefix)-trigger-provisioning-profile
</string>
</array>

I ended up switching my build system from electron-builder to electron-forge and I now get a green checkmark on the "verify" action in Transporter.

I don't really know what changed. The signatures look the same, the file structure of the .app look largely the same. A few little differences I noticed:

  • the helper applications in Contents/Frameworks changed from "App Name Helper (GPU).app" to "appName Helper (GPU).app".
  • in Contents/Frameworks/App Name Helper (GPU).app/Contents/Info.plist the CFBundleName changed from "Electron Helper" to "appName"
  • the codesign entitlements are the same before and after (codesign -d --entitlements - --xml Contents/Frameworks/App Name Helper.app)

When I upload my x64 build to appstoreconnect, I'm now receiving a "Not Available for Testing" status without any details. I'm going to try a universal build and see if that works better.

jeffjohnson wrote:

Is there any way to avoid getting the warning?

No idea.

I've gotten rejections in the past for unused entitlements.

I don’t work for App Review and can’t make definitive statements on their behalf. However, the reports I’ve seen of things like that are typically when the entitlement enables user-level capabilities. For example, a common issue is claiming com.apple.security.network.server when your app doesn’t provide server functionality [1].

Claiming entitlements that identify your app, like com.apple.application-identifier and com.apple.developer.team-identifier, seem pretty safe (-:


I build a sample app and added the keychain entitlement so I could see what keys got added.

You have to look at the entitlement of the built app, not the entitlements configured in Xcode. For example, if I create an app from the built-in macOS > App template I see this:

% codesign -d --entitlements - Test730398.app 
…
[Dict]
    [Key] com.apple.security.app-sandbox
    [Value]
        [Bool] true
    [Key] com.apple.security.files.user-selected.read-only
    [Value]
        [Bool] true
    [Key] com.apple.security.get-task-allow
    [Value]
        [Bool] true

None of these entitlements are restricted and thus there’s no provisioning profile:

% ls -l Test730398.app/Contents/embedded.provisionprofile
ls: Test730398.app/Contents/embedded.provisionprofile: No such file or directory

If I then add the Keychain Sharing capability and rebuild, I see this:

% codesign -d --entitlements - Test730398.app
…
[Dict]
    [Key] com.apple.application-identifier
    [Value]
        [String] SKMME9E2Y8.com.example.apple-samplecode.Test730398
    [Key] com.apple.developer.team-identifier
    [Value]
        [String] SKMME9E2Y8
    [Key] com.apple.security.app-sandbox
    [Value]
        [Bool] true
    [Key] com.apple.security.files.user-selected.read-only
    [Value]
        [Bool] true
    [Key] com.apple.security.get-task-allow
    [Value]
        [Bool] true
    [Key] keychain-access-groups
    [Value]
        [Array]

There are lots of restricted entitlements here, and so Xcode added a provisioning profile to authorise their use:

% security cms -D -i Test730398.app/Contents/embedded.provisionprofile | plutil -p -  
{
  …
  "Entitlements" => {
    "com.apple.application-identifier" => "SKMME9E2Y8.com.example.apple-samplecode.*"
    "com.apple.developer.team-identifier" => "SKMME9E2Y8"
    "keychain-access-groups" => [
      0 => "SKMME9E2Y8.*"
    ]
  }
  …
}

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

This came up in some other context and NateBosscher sent me a copy of their installer package. That confirms my earlier theory about an entitlements / profile mismatch.

After unpacking the app I see multiple executables, including:

% FindMachO.sh nnnnn.app                                                                                              
nnnnn.app/Contents/MacOS/nnnnn
…
nnnnn.app/Contents/Frameworks/nnnnn Helper (Renderer).app/Contents/MacOS/nnnnn Helper (Renderer)
…

Note In these Terminal transcripts, I’m redacting the Team ID to TTTTTTTTTT, the bundle ID to com.bbbbbbbbbbbbbbbb.bbbbb, and the app name to nnnnn.

The main app claims restricted entitlements:

% codesign -d --ent - nnnnn.app 
Executable=/Users/quinn/Desktop/nnnnn.app/Contents/MacOS/nnnnn
[Dict]
    [Key] com.apple.application-identifier
    [Value]
        [String] TTTTTTTTTT.com.bbbbbbbbbbbbbbbb.bbbbb
    …

and those claims are authorised by a profile:

% security cms -D -i nnnnn.app/Contents/embedded.provisionprofile | plutil -p -
{
  …
  "Entitlements" => {
    "com.apple.application-identifier" => "TTTTTTTTTT.com.bbbbbbbbbbbbbbbb.bbbbb"
    "com.apple.developer.team-identifier" => "TTTTTTTTTT"
    "keychain-access-groups" => [
      0 => "TTTTTTTTTT.*"
    ]
  }
  …
}

The helper app also claims restricted entitlements:

% codesign -d --ent - "nnnnn.app/Contents/Frameworks/nnnnn Helper (Renderer).app/Contents/MacOS/nnnnn Helper (Renderer)"
Executable=/Users/quinn/Desktop/nnnnn.app/Contents/Frameworks/nnnnn Helper (Renderer).app/Contents/MacOS/nnnnn Helper (Renderer)
[Dict]
    [Key] com.apple.application-identifier
    [Value]
        [String] TTTTTTTTTT.com.bbbbbbbbbbbbbbbb.bbbbb
    …

but there is no profile to authorise those claims:

% security cms -D -i "nnnnn.app/Contents/Frameworks/nnnnn Helper (Renderer).app/Contents/embedded.provisionprofile"                                        
security: unable to open "nnnnn.app/Contents/Frameworks/nnnnn Helper (Renderer).app/Contents/embedded.provisionprofile" for reading: No such file or directory

So, there are two problems here:

  • If you’re going to claim restricted entitlements, you need a profile to authorise that.

  • Your main app and its helpers all use the same App ID, which is nonsense. The App ID is supposed to be a combination of the App ID prefix, typically your Team ID, and your bundle ID. The bundle IDs are different, and thus the App IDs should be different as well.

You need to look at each of helper to decide whether it needs any restricted entitlements:

  • If it doesn’t, stop claiming the ‘administrative’ ones, namely com.apple.application-identifier and com.apple.developer.team-identifier. Then you’ll no longer need a profile [1].

  • If it does, assign it a real App ID, put that App ID into the com.apple.application-identifier entitlement, and then embed a profile within that helper.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

[1] TestFlight requires a profile for the top-level app but I don’t think it requires one for nested helpers.

Thank you Quinn. I was able to get my app to build on AppStoreConnect for TestFlight by removing the com.apple.application-identifier key from my nested app entitlements, but it now crashes on-launch and I can't figure it out :/

So my nested applications now have app entitlements like this:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
    <dict>
        <key>com.apple.security.app-sandbox</key>
        <true/>
        <key>com.apple.security.application-groups</key>
        <array>
            <string>TTTTTT.com.bbbbbbbbbbbbbbb.bbbb</string>
        </array>
    </dict>
</plist>

So it builds and is able to be downloaded by TestFlight, but my app crashes on startup. I've tried playing with the nested app entitlements without any luck.

  • Attempted: com.apple.security.app-sandbox + com.apple.security.inherit (didn't work)
  • Attempted: com.apple.security.app-sandbox (didn't work)
  • Attempted: com.apple.security.app-sandbox + com.apple.security.application-groups (didn't work)

In my most recent test, com.apple.security.app-sandbox + com.apple.security.application-groups, I'm getting the following console errors

error	11:37:37.340377-0400	taskgated-helper	com.bbbbbbbbbbbbbb.bbbb: Unsatisfied entitlements: com.apple.security.application-groups
error	11:37:37.340426-0400	taskgated-helper	Disallowing: com.bbbbbbbbbbbbbb.bbbb
error	11:37:37.770554-0400	kernel	Sandbox: Bbbb(23775) deny(1) mach-lookup com.apple.CoreLocation.agent
error	11:37:37.770618-0400	kernel	Sandbox: Bbbb(23775) deny(1) mach-lookup com.apple.locationd.desktop.registration
error	11:37:37.776840-0400	kernel	Sandbox: Bbbb(23775) deny(1) mach-register com.bbbbbbbbbbbbbb.bbbb.MachPortRendezvousServer.23775
error	11:37:37.842333-0400	runningboardd	RBSStateCapture remove item called for untracked item 221-170-18294 (target:[app<application.com.bbbbbbbbbbbbbb.bbbb.nnnnnnnnnnn.nnnnnnnnnnn(501)>:23775])
error	11:37:37.842364-0400	runningboardd	RBSStateCapture remove item called for untracked item 221-139-18293 (target:[app<application.com.bbbbbbbbbbbbbb.bbbb.nnnnnnnnnnn.nnnnnnnnnnn(501)>:23775])
error	11:37:37.842438-0400	runningboardd	RBSStateCapture remove item called for untracked item 221-139-18292 (target:[app<application.com.bbbbbbbbbbbbbb.bbbb.nnnnnnnnnnn.nnnnnnnnnnn(501)>:23775])

For extra detail, my main app entitlement is as follows:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
    <dict>
        <key>com.apple.security.app-sandbox</key>
        <true/>

        <key>com.apple.security.network.client</key>
        <true/>
        <key>com.apple.security.network.server</key>
        <true/>
        <key>com.apple.security.device.usb</key>
        <true/>
        <key>com.apple.security.device.serial</key>
        <true/>
        <key>com.apple.security.files.user-selected.read-write</key>
        <true/>
        <key>com.apple.security.cs.allow-jit</key>
        <true/>
        <key>com.apple.security.cs.allow-unsigned-executable-memory</key>
        <true/>
        <key>com.apple.security.cs.allow-dyld-environment-variables</key>
        <true/>
        <key>com.apple.security.cs.disable-library-validation</key>
        <true/>

        <key>com.apple.application-identifier</key>
        <string>TTTTTTT.com.bbbbbbbbbbbbb.bbbb</string>

        <key>keychain-access-groups</key>
        <array>
            <string>TTTTTTT.*</string>
        </array>

        <key>com.apple.developer.team-identifier</key>
        <string>TTTTTTT</string>

        <key>com.apple.security.application-groups</key>
        <array>
            <string>TTTTTTT.com.bbbbbbbbbbbbb.bbbb</string>
        </array>
    </dict>
</plist>

but my app crashes on startup

How are you launching these nested app? Using NSWorkspace? Or something similar, like Launch Services? Or as a child process using Process? Or one of its underlying APIs, like NSTask, posix_spawn, or fork/exec?

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

  • Going to split this into a few comments because of the character limit :( I'm using electron so it's a bit tricky to know for sure.

Add a Comment

I'm using electron so it's a little tricky to figure out.

It looks like it's using posix_spawn, based on this chromium code - https://chromium.googlesource.com/chromium/src/+/master/base/mac/mach_port_rendezvous.cc + this electron patch. The crash seems to be happening at the MachPort connection checkpoint here 0 https://chromium.googlesource.com/chromium/src/+/master/base/mac/mach_port_rendezvous.cc#147

There are other spots in electron that have NSWorkspace, but I think that's just for shell commands. There's also a few launch services references, but I think that's for opening 3rd party apps.

I was also able to grab a dtruss output to confirm that it's using posix_spawn. I had to first make a copy of the main executable Contents/MacOS/NNNN and remove the code sign with sudo codesign --remove-signature NNNN2. It seems like child processes are able to spawn, but not open the MachPort?

Quinn, I'll email that full dtruss output to you and the full console logs from a my last post in case there's something that jumps out.

I was also able to grab a dtruss output to confirm that it's using posix_spawn.

Hey hey, that was exactly what I was going to suggest.

Given that these programs are started as child processes, you have to sign them with:

  • com.apple.security.app-sandbox, to enable the sandbox, and

  • com.apple.security.inherit, to inherit the sandbox from your parent rather than start a new one

You probably don’t need any other entitlements but that kinda depends on what those programs do.

If you apply just those entitlements, what behaviour do you see?

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

Ok, so looks like we're getting there. Thank you for coming along the journey with me.

TLDR; solved a bunch of problems, jump to last heading for current problem.

Entitlements

The correct "inherit" entitlements (for child items) are:

  • com.apple.security.app-sandbox
  • com.apple.security.inherit

Inherit Entitlement Notes

And the reason it didn't work during my previous attempt was because of a downstream issue which I'll get to in a minute.

With this updated "inherit" plist, I continued to receive Unsatisfied entitlements: com.apple.security.application-groups, but as mentioned here this is a non-fatal issue and can often be ignored. (adding a com.apple.security.application-groups to the "inherit" plist caused other errors for me).

All things ending in .framework, .app and .node need to be signed with this "inherit" entitlements.

Main Entitlements

For the record, my main app entitlements is as follows:

  • com.apple.security.app-sandbox
  • com.apple.application-identifier: TTTTTTTT.com.nnnnnnnnnnnnn.nnnnn
  • com.apple.developer.team-identifier: TTTTTT
  • com.apple.security.network.client
  • com.apple.security.network.server
  • com.apple.security.device.usb (specific to my app, others may not need this)
  • com.apple.security.device.serial (specific to my app, others may not need this)
  • com.apple.security.files.user-selected.read-write
  • com.apple.security.cs.allow-jit
  • com.apple.security.cs.allow-unsigned-executable-memory
  • com.apple.security.cs.disable-executable-page-protection
  • com.apple.security.cs.allow-dyld-environment-variables
  • com.apple.security.cs.disable-library-validation
  • keychain-access-groups: [TTTTTTTT.*]
  • com.apple.security.application-groups: [TTTTTTTT.com.nnnnnnnnnnnnn.nnnnn]

Debugging

Dtruss: I was able to capture the sys calls by unsigning the main binary (Contents/MacOS/Nnnnn), but that required sudo-ing and the application seemed to be in a different sandbox when I did that and hit issues trying to read attributes from the main .app folder. In retrospect, I think that output was misleading for what I was trying to do.

XCode: I tried to run the app via XCode's Debug > Debug Executable..., I ran into issues because my app doesn't have the com.apple.security.get-task-allow entitlement. But, just adding that entitlement to the main entitlements didn't work for me. (I think it conflicts with com.apple.security.app-sandbox?). Instead of dealing with that, I was able to just disable SIP with csrutil disable (via recovery mode reboot) and attach XCode no problem.

When running in XCode, I was able to find that the exit was because of a failed assertion on the Mach Port.

Mach/XPC Stuff

Next issue was this pesky panic: FATAL:mach_port_rendezvous.cc(142)] Check failed: kr == KERN_SUCCESS. bootstrap_check_in. You can see the source code here https://chromium.googlesource.com/chromium/src/base/+/master/mac/mach_port_rendezvous.cc. Digging through the console logs, I was able to find this error Sandbox: Nnnnn(23775) deny(1) mach-register com.nnnnnnnnnnnnn.nnnnnn.MachPortRendezvousServer.23775.

Btw, I kept SIP disabled for this part so I could attach my XCode debugger.

So that's interesting, can't register a mach port... maybe a permissions issue me thinks? Digging around, I found that XPC naming must match your app identity

A Service Management login item can only run a single XPC listener and its name must match the name of the login item. - https://developer.apple.com/forums/thread/703702?answerId=709877022#709877022

👋 thank you Quinn.

So, if the name needs to match... my error says it's trying to register without the TTTTT part of TTTTT.com.nnnnnnnnn.nnnn... So why is chromium / electron doing that...

Going back to the chromium source code from above, jump to line 143 - note: mac::BaseBundleID(). Ok, so dig backwards, where does that come from - here it is: https://source.chromium.org/chromium/chromium/src/+/HEAD:base/mac/foundation_util.mm;l=289. which relies on base_bundle_id which is set in SetBaseBundleID.

Some quick googling, that's set over here in electron. And interesting.. it looks for a ElectronTeamID Info.plist property. Quick check of our Info.plist - nada.

Updated the build process to include ElectronTeamID: TTTTTT in my Info.plist. Cool, works great!

Fun note: my app doesn't require com.apple.security.temporary-exception.mach-lookup.global-name since from what I can tell, com.apple.security.application-groups and com.apple.security.app-sandbox allow you to use any named Mach Port with a prefix of TTTTT.com.nnnnnnnnnn.nnnn.

Pink Flashing Screen

Once I tested that everything was working, I re-enabled SIP (csrutil enable) and started the app. Got a pink and white seizure-type screen. The console logs showed this error: kernel CODE SIGNING: 1036[nnnnn Helper (Re] vm_map_protect:6073(0x0,0x0,0x7) can't have both write and exec at the same time.

I tried using com.apple.security.cs.disable-executable-page-protection in my main entitlement (since it would get inherited by the Helper), but that didn't work. Back to the drawing board...

I think [the get-task-allow entitlement]] conflicts with com.apple.security.app-sandbox?

Correct. There are ways to get around this for general development but it’s a bit of a challenge if your specific goal to use the debugger to help debug entitlement issues.

com.apple.security.application-groups and com.apple.security.app-sandbox allow you to use any named Mach port with a prefix of TTTTT.com.nnnnnnnnnn.nnnn.

Correct.

Well, specifically, the Mach service name should have the app group ID as its prefix.

I tried using com.apple.security.cs.disable-executable-page-protection in my main entitlement (since it would get inherited by the Helper), but that didn't work.

Right. That’s because your helper inherits its sandbox but not its entitlements.

The right thing to do here is to add that entitlement to your helper’s entitlements. When you start an executable as a child process, and thus it inherits its sandbox, the App Sandbox runtime checks that its entitlements are allowed in that situation. This check consists of a relatively short allowlist, but I believe that this entitlement is on it.

Oh, the right right thing to do is to not use this entitlement. It’s a superset of com.apple.security.cs.allow-unsigned-executable-memory which is in turn a superset of com.apple.security.cs.allow-jit. A well-written JIT only needs the latter. Even a JIT that hasn’t been updated should be able to get away with the middle one.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

That did it! I added com.apple.security.cs.allow-unsigned-executable-memory to my child-process entitlements and everything works as expected.

All of my issues are fixed now. Thank you, thank you, thank you Quinn!

I feel like I finally understand a whole bunch of random app store stuff that I'm NEVER going to touch again. That was really painful, but thank you for helping me through it.