Bundle structure and its repercussions

I recently inherited a project to port an app bundle to arm64, and some of the design decisions in the app bundle are undocumented. I'd like to structure the bundle as canonically as possible, to minimize future problems as much as possible.

In particular, there are two areas where I would like some clarification. I have read all of eskimo's guides (what a godsend!), but have not been able to find an explanation for these yet.

  1. We have some helper executables that allow us to run jobs in the background, etc... Historically, these have always been in Contents/Resources, for some reason; that seems to be a bad idea. I have seen conflicting advice suggesting to use Helpers or just MacOS. What are the advantages or disadvantages of using each folder? Would dumping all the executables in MacOS be an adequate solution and, if not, why should I use Helpers?

  2. Our app contains "compiled extensions" in Contents/SharedSupport, which consist of small intel-based apps (with their own app bundle) that our app can interact with. They are supposed to be a demo of extensions that the users could code and compile themselves, thus justifying their location. Should these be signed in any special way? Our app used to employ the --deep flag for code signing, but following eskimo's guidelines I have removed that, and it is not clear to me how these should be signed.

Thank you.

Accepted Reply

There’s definitely a gap between what you should do and what you can get away with. What you should do is documented in Placing Content in a Bundle, which I’m sure you’ve found already. However, you can typically get away with more than that.

One really toxic thing is putting resources in a location that are reserved for code. That will cause problems and I strongly recommend that you avoid it.

OTOH, putting code in a location that’s reserved for resources isn’t too bad [1]. As long as you don’t combine that with using --deep for signing, you probably won’t run into problems. And using --deep for signing is a bad idea anyway, due to the entitlements issue.

Regarding your specific questions:

1. … What are the advantages or disadvantages of using each folder?

The main advantage of Contents/MacOS is that you can locate your helping tool using the path(forAuxiliaryExecutable:) method. Beyond that, it’s pretty much a wash.

2. … it is not clear to me how these should be signed.

It depends on whether you expect the user to be able to run these. If so, you should consider them a separate code item [2] and thus sign them independently. It’s fine to leave them in Contents/SharedSupport. I mean, it’s a bit of a weird location, which is why I didn’t mention it in Placing Content in a Bundle, but it was historically meaningful and probably won’t cause problems.

Share and Enjoy

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

[1] If you’re curious, TN3126 Inside Code Signing: Hashes explains the difference you’ll see, namely, that the code signature of the parent bundle won’t reference the item as code, with cdhash and requirement properties. Historically that was relevant — the requirement property allowed you to update a code item within a bundle without breaking the bundle’s seal — but that’s not something that we rely on today.

[2] Per the usage in Creating distribution-signed code for macOS.

Replies

There’s definitely a gap between what you should do and what you can get away with. What you should do is documented in Placing Content in a Bundle, which I’m sure you’ve found already. However, you can typically get away with more than that.

One really toxic thing is putting resources in a location that are reserved for code. That will cause problems and I strongly recommend that you avoid it.

OTOH, putting code in a location that’s reserved for resources isn’t too bad [1]. As long as you don’t combine that with using --deep for signing, you probably won’t run into problems. And using --deep for signing is a bad idea anyway, due to the entitlements issue.

Regarding your specific questions:

1. … What are the advantages or disadvantages of using each folder?

The main advantage of Contents/MacOS is that you can locate your helping tool using the path(forAuxiliaryExecutable:) method. Beyond that, it’s pretty much a wash.

2. … it is not clear to me how these should be signed.

It depends on whether you expect the user to be able to run these. If so, you should consider them a separate code item [2] and thus sign them independently. It’s fine to leave them in Contents/SharedSupport. I mean, it’s a bit of a weird location, which is why I didn’t mention it in Placing Content in a Bundle, but it was historically meaningful and probably won’t cause problems.

Share and Enjoy

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

[1] If you’re curious, TN3126 Inside Code Signing: Hashes explains the difference you’ll see, namely, that the code signature of the parent bundle won’t reference the item as code, with cdhash and requirement properties. Historically that was relevant — the requirement property allowed you to update a code item within a bundle without breaking the bundle’s seal — but that’s not something that we rely on today.

[2] Per the usage in Creating distribution-signed code for macOS.