Extensions not opening if they are signed using the command line tools

Hello there We have recently discovered an issue where extensions in an app bundle would not open if they are signed (using codesign, in our case). We are assuming that this is because they can either not be run by the main app (because of some signing/security issue) or that the system immediately kills them because they are incorrectly signed.

The setup

  1. Simply create a main app containing any app extension (we have tried FinderSync and Share)
  2. Archive and export the app using the xcodebuild command (though exporting it through Xcode works aswell)
  3. Sign the app container (.app) and the extension (.appex file in Contents/PlugIns).
  4. Open the app
  5. The Extension won't be visible in the Preferences and is not running

The problem

If we do not sign the app extension, the main app and app extension start as expected (this not an option though, because notarization will fail when the app extension is not signed). If we sign the app extension, the app extension will not start (when running the main app). We assume that this is because macOSs Gatekeeper immediately kills them when started. But we are not sure why.

Demo Project

You can find a very simple demo project in the Github Repository linked below. This demo project only contains an almost empty main app, a completely default App Extension (everything is left as when generated, except the myFolderURL which was changed to / for testing purposes).

The demo project also contains two scripts, one which builds app and signs it completely (with app extension) and one which builds the app and signs everything but the App Extension. Both scripts export a .app file, and a zip file.

Make sure to insert the name of your Developer ID Application Certificate into the script (simply replace the XXXXXXX with the name of your certificate)

To reproduce our issue:

  1. Run the unsigned app and open the preferences with the button to confirm that the app extension have been added.
  2. delete the app (to make sure the app extension is not still in the preferences when testing the signed app)
  3. Open the app with the signed extension and you'll see that upon opening the app and viewing the preferences that the app extension is not present in the list (and therefore not open). This can be tested using the Activity Monitor or 'top' command as well.

You can find the link to the github repository containing the demo project here (I could not directly insert the github link because of the question guidelines): StackOverflow Question

Conclusion

To summarise: When signing an app extension (Finder Sync in the Demo), the extension does not open/gets killed when the extension is signed. If the extension is not signed everything works as intended. As said, we believe that either signing, notarising, or the gatekeeper might be the cause of this issue, probably this is some issue with our build/sign automation (the demo contains the scripts with our automation code). Can that be the case or are extensions handled differently and we are missing a step?

Accepted Reply

For anyone else experiencing this issue, we finally figured it out:

In the end, this is the command we were using to sign our extensions with (incorrect command):

codesign -s "Developer ID Application: XXXXXXXXX (XXXXXXX)" -f --timestamp -o runtime "OurApp.app/Contents/PlugIns/OurExtension.app"

After some digging in the Console, we found that the extensions were being closed by the gatekeeper with the following message:

[/Applications/Extension_With_Signing_Demo.app/Contents/PlugIns/findersynctest.appex]: plug-ins must be sandboxed

After discovering this message, the cause of the error was pretty clear for us: Because we hadn't deemed it necessary to actually pass entitlements while signing the extension (because we thought that they didn't require any) and we didn't know that extensions require sandbox to run.

To solve the issue, all we did was add an entitlements plist file containing some of the basic entitlements:

<?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.files.user-selected.read-only</key>
	<true/>
</dict>
</plist>

and included them in our command

codesign -s "Developer ID Application: XXXXXXXXX (XXXXXXX)" -f --timestamp -o runtime --entitlements EntitlementsFile.entitlements "OurApp.app/Contents/PlugIns/OurExtension.app"

After that, the extensions started as intended.

Summary

The solution to our problem was the fact that we didn't pass any entitlements when signing the extensions, even though extensions require the sandbox entitlement.

A very helpful resource on how to add entitlements when signing an app or app extension (and code signing in general): Creating Distribution-Signed Code for Mac

Replies

AFAICT this is the command you’re using for signing:

codesign -s "Developer ID Application: XXXXXXXXX (XXXXXXX)" -f --timestamp -o runtime --display --entitlements :- "$i"

I see two oddities here:

  • The -s tells it to sign code, but the --display tells it to display the code signature. I’m not sure what codesign does in that case, but it’s unlikely to be good. Remove the --display

  • Your app and appex use entitlements, but --entitlements :- is telling codesign to display the entitlements, not apply them. You need to either:

    • Apply the entitlements, using --entitlements /path/to/your.entitlements.

    • Or preserve the entitlements, using --preserve-metadata=entitlements

Share and Enjoy

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

Hi there, Thanks for your quick reply!

Unfortunately the file I provided to you was incorrect (we were testing some things with the signature before and left it in the script by accident). I have updated the file in the repository with the correct command (its essentially the same command as in the export_without_extension_signing.sh file)

 I’m not sure what codesign does in that case, but it’s unlikely to be good.

With this codesign would not have run at all and therefore not sign anything. The problem mentioned in the original post still occurs even when the signing commands are all executed correctly.

For anyone else experiencing this issue, we finally figured it out:

In the end, this is the command we were using to sign our extensions with (incorrect command):

codesign -s "Developer ID Application: XXXXXXXXX (XXXXXXX)" -f --timestamp -o runtime "OurApp.app/Contents/PlugIns/OurExtension.app"

After some digging in the Console, we found that the extensions were being closed by the gatekeeper with the following message:

[/Applications/Extension_With_Signing_Demo.app/Contents/PlugIns/findersynctest.appex]: plug-ins must be sandboxed

After discovering this message, the cause of the error was pretty clear for us: Because we hadn't deemed it necessary to actually pass entitlements while signing the extension (because we thought that they didn't require any) and we didn't know that extensions require sandbox to run.

To solve the issue, all we did was add an entitlements plist file containing some of the basic entitlements:

<?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.files.user-selected.read-only</key>
	<true/>
</dict>
</plist>

and included them in our command

codesign -s "Developer ID Application: XXXXXXXXX (XXXXXXX)" -f --timestamp -o runtime --entitlements EntitlementsFile.entitlements "OurApp.app/Contents/PlugIns/OurExtension.app"

After that, the extensions started as intended.

Summary

The solution to our problem was the fact that we didn't pass any entitlements when signing the extensions, even though extensions require the sandbox entitlement.

A very helpful resource on how to add entitlements when signing an app or app extension (and code signing in general): Creating Distribution-Signed Code for Mac