Hello and thanks for your support,
Don’t get me wrong, enabling the sandbox is a good thing. However, it certainly does present extra complications
App Sandbox is not specially required by the app at this moment, if it makes things less complex it can be removed. It was there probably because I tried to distribute to AppStore at the same time.
That’s going to cause problems. See Posting a Crash Report for advice on how to structure your bundle.
I followed the link but can't find any information related to bundle structure. I followed this document Placing content in a bundle
and because the interpreter is having an executable I placed it in MacOS folder.
Finally, are you building the top-level app with Xcode? Or with other tools?
Top level app is built with Xcode.
Thanks
Post
Replies
Boosts
Views
Activity
Hello, I've made a very good progress.
following the changes you indicated the app works :)
There is only a little detail, if python executable is moved to:
SampleApp.app/Contents/MacOS/python3.11
It appears a pop up asking 'Allow [APP] to find devices on local networks?'.
I tested the app placing python here:
SampleApp.app/Contents/MacOS/bin/python3.11
and the app works the same but the pop up is not appearing. This is a capability is not requested in the app...
I'm very curious to know why this happens.
Let me share the changes that were applied:
This is the new entitlements:
<key>com.apple.security.app-sandbox</key>
<false/>
I enabled Hardened Runtime in Build Settings - Signing section.
What about lib/python3.11. That’s not a single file, right? It’s a directory containing a hierarchy of Python goo, right?
Yes, it is a folder with all the libraries, etc. Is it ok when the folder stays in Resources?
Last change I made is to remove the --deep when signing python executable, now it looks like this:
codesign --force --options runtime --timestamp --sign "$DEVELOPER_ID_APPLICATION" "$BINARY_PATH"
and all libraries (*.so, *.dylib and *.a) are signed as follows:
codesign --force --preserve-metadata=identifier,entitlements,flags --timestamp=none --sign "$DEVELOPER_ID_APPLICATION" "$BINARY_PATH"
We tested the notarised dmg in different macs and works perfect, I'm so thankful :)
I'm not sure if I can ask this in this thread, but I would love to distribute the app via the App Store. I already have a version available on TestFlight, but it's encountering errors when running python. Before I open a new thread I would like to review the proper documentation. Could you recommend any link, advice, or tips?
I already visited this post and the links are appearing on it:
XPC Rendezvous, com.apple.security.inherit and LaunchAgent
Many thanks in advance!
Hello, thanks a lot for your guidance.
This is the error I am facing at the moment, tried some things but I am stuck:
Prompting policy for hardened runtime; service: kTCCServiceAppleEvents requires entitlement com.apple.security.automation.apple-events but it is missing for accessing={TCCDProcess: identifier={APP_IDENTIFIER}, pid=63455, auid=502, euid=502, binary_path=[PATH_APP]}, requesting={TCCDProcess: identifier=com.apple.appleeventsd, pid=756, auid=55, euid=55, binary_path=/System/Library/CoreServices/appleeventsd},
What I did since last conversation was to move python libraries to the app and only the python executable is located in the bundle.
Python.bundle/Contents
Python.bundle/Contents/Info.plist
Python.bundle/Contents/MacOS
Python.bundle/Contents/MacOS/python3.11
Added to bundle Info.plist:
<key>CFBundleExecutable</key>
<string>python3.11</string>
Added to Python.entitlements:
com.apple.security.inherit, with a Boolean value of true.
Python bundle entitlements now looks like this:
<key>com.apple.security.app-sandbox</key>
<true/>
<key>com.apple.security.inherit</key>
<true/>
In this documentation Embedding a command-line tool in a sandboxed app says:
"Add the App Sandbox and Hardened Runtime capabilities"
I could not select capabilities in the bundle, so from Build Settings Signing section I set to yes Sandbox and Hardened Runtime.
From the same documentation:
"Set the Other Code Signing Flags (OTHER_CODE_SIGN_FLAGS) build setting to $(inherited) -i $(PRODUCT_BUNDLE_IDENTIFIER)"
I had a conflict at this point, I had to remove it because I got a CodeSign error when archiving:
-i com.sampleApp.app.Python: No such file or directory
Command CodeSign failed with a nonzero exit code
In the same documentation, section "Embed the helper tool" says:
"Add the ToolX executable to that build phase, making sure Code Sign On Copy is checked."
I added the bundle and Code Sign On Copy is checked.
Thanks again for your help.
How is that bundle created? Did you start with a generic bundle target, created from the the macOS > Bundle template?
Yes exactly, followed as much as I could what describes Create the helper tool target section from Embedding a command-line tool in a sandboxed app document.
OK. And python3.11 executable is built by an external build system, right? That is, you are not using Xcode to build it from source.
I use Xcode Command Line tools (clang 16.1) to compile the source and generate the dSYM files.
Let me bring to the conversation this document I've been going through, although maybe is not related:
Accessing files from the macOS App Sandbox
Python executable needs a folder to save cache files, at the moment the folder is created by the app and set as environment variable to the executable.
The executable also needs access to the folder where the libraries are, etc.
We already know that this setup works fine in a non sanboxed app.
But now the executable is sandboxed, and the app with its libraries is sandboxed too.
Can a sandboxed process (python exec) access to a URL from another sandboxed process (app)?
The document mentioned earlier talks about bookmarks to share file access between processes, is that the way to go with all the urls the executable needs?
If so, I could imagine how to generate the bookmark in the main app, but I don't how to resolve it in the python bundle because I don't have a piece of source code.
Many thanks for your support.
My understanding is that you’re running this Python executable as a child process, using posix_spawn or something layered on top of that (like NSTask or Process). Please confirm.
Yes that's right, this is how it is running:
private let process = Process()
private let pipe = Pipe()
func startPython() async throws {
Task {
self.process.executableURL = URL(fileURLWithPath: try File.pathResource(.pythonBin))
self.process.environment = environment
self.process.arguments = arguments
self.process.standardOutput = self.pipe
try self.process.run()
self.process.waitUntilExit()
let data = self.pipe.fileHandleForReading.readDataToEndOfFile()
let output = String(data: data, encoding: .utf8) ?? ""
Log.debug("\(output)", category: .python)
}
}
Hello, sorry I am not able to follow it, I'm quite confused.
Please correct me when I am wrong.
From this document Embedding a command-line tool in a sandboxed app
Section 'Create the helper tool target'
I created a bundle and that bundle contains an executable that is located in the MacOS folder of the bundle.
Section 'Embed the helper tool'
I added a new Copy Files build phase in the app, the bundle goes to MacOS folder of the app.
Now starts the confusion...
Section 'Embed an externally built tool'
"With the app and Xcode-built helper tool working correctly, it’s time to repeat the process for a tool built using an external build system."
With 'Helper tool' means the bundle?
Section 'Embed the helper tool'
"Add the ToolX executable to that build phase, making sure Code Sign On Copy is checked."
Are we are talking about the bundle?
"In the Build Phases tab of the app target editor, add ToolC to the Embed Helper Tools build phase"
But already added the bundle that contains the executable.
I don't know if I have to add the bundle, the executable or both.
Many thanks for the clarification.
Hello, I still get some errors:
Process tccd
Prompting policy for hardened runtime; service: kTCCServiceAppleEvents requires entitlement com.apple.security.automation.apple-events but it is missing for accessing={TCCDProcess: identifier=com.sampleApp.app, pid=72680, auid=502, euid=502, binary_path=[PATH_TO_APP]]}, requesting={TCCDProcess: identifier=com.apple.appleeventsd, pid=831, auid=55, euid=55, binary_path=/System/Library/CoreServices/appleeventsd},
Process python3.11
flock failed to lock list file (<private>): errno = 35
Basically the changes I made are:
Used the code from 'Running a Child Process with Standard Input and Output', it works great, thanks!
Made a Run script to sign the executable:
codesign -s - -i com.sampleApp.app.Python -o runtime --entitlements "$ENTITLEMENTS_PATH" -f "$BINARY_PATH"
And then created a copy build phase to place the executable in Executables destination. Code sign on copy is selected. (Verified that it is placed in MacOS folder, and correctly signed.)
These are the Entitlements used to sign the executable:
<key>com.apple.security.app-sandbox</key>
<true/>
<key>com.apple.security.inherit</key>
<true/>
And these are the Entitlements of the app:
<key>com.apple.security.app-sandbox</key>
<true/>
<key>com.apple.security.files.user-selected.read-only</key>
<true/>
<key>com.apple.security.network.client</key>
<true/>
<key>com.apple.security.network.server</key>
<true/>
The security network entries are there because the app runs a small python local web server.
I assume they are inherited to the executable, correct me if I am wrong, in that case I will add them to the entitlements of the executable, do they need to be in both?
Thanks
First of all many many many thanks for your support, without it we could not progress the way we did.
Now python actually works.
Is your Python code actually using Apple events? If so, what for?
No, it's not using Apple events, I can see that warning or error even in the working version.
This document
Embedding nonstandard code structures in a bundle
helped us to find a bug that was allowing python to write bytecode (*.pyc) in not allowed folders.
We double checked all dynamic library linkage, seems all good, it's only linking to system libraries, like /usr/lib/libc++.1.dylib
Our final product is still not working, this error is still appearing:
flock failed to lock list file (<private>): errno = 35
All we know is that seems one component is reading from a place that must not be allowed.
We know it is not writing because we have the same app distributed via dmg (not sandboxed) and nothing is written out of the sandbox.
Now is about isolating python components until finding what causes the problem.
Thanks again, a lot of learnings.
Hello,
we found out that the problem of our product comes when running a python web server locally.
The app accesses the server via http://127.0.0.1:5000
But the server is never running.
On the console there are no errors, only kTCCServiceAppleEvents requires entitlement com.apple.security.automation.apple-events
The app have these entitlements:
<key>com.apple.security.app-sandbox</key>
<true/>
<key>com.apple.security.files.user-selected.read-only</key>
<true/>
<key>com.apple.security.network.client</key>
<true/>
<key>com.apple.security.network.server</key>
Because the app is client and server at the same time I added both entitlements, but I don't know if this could create a conflict...
I also have these lines in the app Info.plist to allow access to a non secure endpoint:
<key>NSAppTransportSecurity</key>
<dict>
<key>NSExceptionDomains</key>
<dict>
<key>127.0.0.1</key>
<dict>
<key>NSExceptionAllowsInsecureHTTPLoads</key>
<true/>
<key>NSExceptionRequiresForwardSecrecy</key>
<false/>
<key>NSIncludesSubdomains</key>
<true/>
</dict>
</dict>
</dict>
Is there anything else that maybe I need to consider?
Many thanks in advance.