Thanks for being a part of WWDC25!

How did we do? We’d love to know your thoughts on this year’s conference. Take the survey here

Gatekeeper "bundle_id: NOT_A_BUNDLE" rejection

Context: large platform-agnostic CLI tool built as a handcrafted bundle (not via an Xcode project) that has been successfully codesigned, stapled, and zipped; macOS 14.7.5 syspolicy_check reports

App passed all pre-distribution checks and is ready for distribution.

However, running the executable in the Terminal produces a "cannot be opened because the developer cannot be verified" popup. The executable does succeed after manually clearing its quarantine attribute.

Having worked through Resolving Gatekeeper Problems, the only detail logged in the Console is

Adding Gatekeeper denial breadcrumb (direct): ... bundle_id: NOT_A_BUNDLE.

Experimental observations: a minimized trivial CLI executable with a similar bundle layout and name successfully executes without being rejected, and oddly, renaming the original bundle from "name" to "name.suffix" allows it to be successfully executed.

It's unclear why the bundle name would affect Gatekeeper only in some circumstances, and we'd greatly prefer not to rename the bundle for compatibility reasons, so it would be good if there were some way to get further diagnostic detail leading to a workaround - thank you.

Answered by DTS Engineer in 837442022
It would be very useful for Apple to add a test VM creation CLI to the developer toolkit

I tend to agree but, given that current reality, I encourage you to explore the raft of third-party options out there [1].

As to your original issue, adding an extension is the right option here.

macOS draws a clear distinction between bundled and non-bundle code. This really matters when comes to code signing. See the discussion is Creating distribution-signed code for macOS.

That Java runtime is signed as a bundle:

% codesign -d -vvv jdk-21.0.7+6-jre 
Executable=/Users/quinn/Desktop/jdk-21.0.7+6-jre/Contents/MacOS/libjli.dylib
Identifier=net.java.openjdk.jre
Format=bundle with Mach-O thin (arm64)
       ^^^^^^

However, the exact definition of what constitutes a bundle is more squishy then it should be. It seems that codesign and Gatekeeper disagree as to whether the file name extension is required, which is why the OpenJDK folks are able to sign that item as a bundle but that trips up Gatekeeper.

Now there are other problems here — Java runtimes are notorious for not following the rules in Placing Content in a Bundle — but they don’t seem to be causing you grief so I fine for us to just move on.

Share and Enjoy

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

[1] Given your background, I suspect you’d like Tart.

I’d like to start by clarifying some things.

However, running the executable in the Terminal produces a "cannot be opened because the developer cannot be verified" popup.

You’re talking about running the program from the Unix shell that’s running in Terminal, right? Because running it in Terminal by double clicking the tool is a known problem [1].

large platform-agnostic CLI tool built as a handcrafted bundle

Why is the tool bundled? There are good reasons to do this — to use restricted entitlements [2], to make TCC happy, and so on — but I’d like to get a handle on that background.

Finally, how are you testing this? My general advice is that you run each test on a fresh (virtual) machine, as explained in Testing a Notarised Product.

Share and Enjoy

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

[1] Which is explained in Tool Blocked by Gatekeeper, part of the Resolving Gatekeeper Problems post you referenced.

[2] See Signing a daemon with a restricted entitlement.

We think our compatibility issue can be handled, so this problem has probably become academic, but a simple reproducible case is listed at the end.

You’re talking about running the program from the Unix shell that’s running in Terminal, right? Why is the tool bundled?

Correct - that is its only mode of operation. It is a structured collection of nearly a thousand filesystem objects that includes a JRE.

Finally, how are you testing this? My general advice is that you run each test on a fresh (virtual) machine

Unfortunately, we don't yet have access to VMs. (It would be very useful for Apple to add a test VM creation CLI to the developer toolkit now that the core functionality is built into macOS.)

Repro case:

  • Download a JRE tgz, e.g. https://adoptium.net/temurin/releases/?os=mac&version=21&package=jre&arch=aarch64
  • Re-archive as non-suffixed zip: tar -xzf OpenJDK21U-jre_aarch64_mac_hotspot_21.0.7_6.tar.gz && mv jdk-21.0.7+6-jre jdkjre && zip -qr jdkjre.zip jdkjre
  • Quarantine the zip
  • Failure as non-suffixed bundle: unzip -q jdkjre.zip && jdkjre/Contents/Home/bin/java --version
  • Success as suffixed bundle: mv jdkjre jdk.jre && jdk.jre/Contents/Home/bin/java --version
It would be very useful for Apple to add a test VM creation CLI to the developer toolkit

I tend to agree but, given that current reality, I encourage you to explore the raft of third-party options out there [1].

As to your original issue, adding an extension is the right option here.

macOS draws a clear distinction between bundled and non-bundle code. This really matters when comes to code signing. See the discussion is Creating distribution-signed code for macOS.

That Java runtime is signed as a bundle:

% codesign -d -vvv jdk-21.0.7+6-jre 
Executable=/Users/quinn/Desktop/jdk-21.0.7+6-jre/Contents/MacOS/libjli.dylib
Identifier=net.java.openjdk.jre
Format=bundle with Mach-O thin (arm64)
       ^^^^^^

However, the exact definition of what constitutes a bundle is more squishy then it should be. It seems that codesign and Gatekeeper disagree as to whether the file name extension is required, which is why the OpenJDK folks are able to sign that item as a bundle but that trips up Gatekeeper.

Now there are other problems here — Java runtimes are notorious for not following the rules in Placing Content in a Bundle — but they don’t seem to be causing you grief so I fine for us to just move on.

Share and Enjoy

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

[1] Given your background, I suspect you’d like Tart.

Gatekeeper "bundle_id: NOT_A_BUNDLE" rejection
 
 
Q