I've got a macOS app (.app) bundle where I am trying to embed a pre-compiled ahead-of-time binary (cli application) into my app bundle but cannot get it to execute when hardened runtime is enabled.
I've got a run-script in Builds Phases in xcode (14.1) that looks like this
LOCATION="${BUILT_PRODUCTS_DIR}"/"MyApp.app/Contents/MacOS"
IDENTITY=${EXPANDED_CODE_SIGN_IDENTITY_NAME}
codesign --verbose --force -o runtime --sign "$IDENTITY" "$LOCATION/my_cli"
The binary is succesfully copied and placed as MyApp/Contents/MacOS/my_cli right along side the main executable binary for the app.
The main application is written in Dart with Flutter, while the binary (my_cli) is compiled through a combination of Rust and Dart to a single file executable.
I can successfully run my_cli when I omit the -o runtime from my main application using Dart:io Process.run (think of it as a means to execute a program, similar to Swift's Process.run), but this will fail Apple's Notary Service saying that my_cli needs to have been signed with hardened runtime.
I have tried putting the binary in multiple locations, including MyApp.App/Contents/Helpers and MyApp.App/Contents/Resources but still no luck.
The binary, my_cli, simply generates a .dylib within the Users/<user_name>/Library/Application Support/<bundle_id>/ for architecture specific optimizations, hence why it must be AOT.
The only hint I get comes from console.app which spits out something like this
Error reading receipt: Error Domain=NSCocoaErrorDomain Code=256 "The file “receipt” couldn’t be opened." UserInfo={NSFilePath=/Users/<user_name>/MyApp/build/macos/Build/Products/Debug/MyApp.app/Contents/MacOS/my_cli/Contents/_MASReceipt/receipt, NSUnderlyingError=0x7fc04960a7c0 {Error Domain=NSPOSIXErrorDomain Code=20 "Not a directory"}}
I find it strange that macOS thinks that my_cli is an app bundle or something. I still get this error even when I don't code-sign with the -o runtime flag so I am not necessarily sure it is relevant to the problem.
For some context, I have already created a cli application written in pure Dart and have embedded it within the app and code-signed with the -o runtime flag and it works great, but I have noticed that it only works successfully when I build it on my own machine rather when it gets built through a CI/CD service like Github actions. I will have to confirm this for my_cli but the source is currently broken and I am not involved in it. I will update this post if I get it to work when built on my machine. Regardless, I still want to know why it fails to execute when I pull it from our CI/CD runners.
I am aware of the quarantine flag that macOS will put on executables when downloaded from a browser, but I have already removed them and circumvented that problem by pulling through wget or curl (running xattr my_cli will come back with nothing listed).
MyApp is currently not sandboxed, but I have tried to add entitlements like
<key>com.apple.security.cs.disable-executable-page-protection</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.disable-library-validation</key>
<true/>
which I am pretty sure don't matter hence being un-sandboxed. The same boxes are checked in Xcode when you click on the "Signing and Capabilities` tab under the Hardened Runtime capability
I am running out of ideas here. If anyone has any information or a solution, it would be much appreciated.
Thanks in Advance!