File/Folder access/scoping for background only apps

We create plug-ins for Adobe Creative Cloud and have run into an issue with respect to file/folder permissions. First, all of our libraries, code is code-signed and notarized as per Apple requirements but distribute outside of the Mac App store.

We install a Photoshop plug-in and its mainly a UI which then executes a background app containing the business logic to read/write files. The background app runs as a separate process and is not in the Photoshop sandbox space so it doesn't inherit Photoshop permissions/scoping rules. Our plug-in communicates with the background process via ports etc.

When a user chooses a file to process from lets say the Desktop, generally macOS first pops up a message that says ABCD background app is trying to access files from the Desktop do you grant it permission etc...This is also true for network mounted volumes or downloads folder. This message generally appears properly when everything is under an account with admin rights.

However, when our tool is installed from a Standard Account, the macOS messages asking for confirmation to access the Desktop or Documents or Downloads folder doesn't appear and access to the file/folders is denied. Thus our background only process errors out. Looking at the Security and Privacy->Files and Folders the button to enable access is in the Off position. If we turn these on Manually, everything works.

But this is a really poor user experience and sometimes our users think our software is not working.

Does anybody have any idea how to allow for the file/folder permissions to be registered/granted in such a case? Should we try to register these as Full Disk Access? Any ideas and/or solutions are welcome.

There, that's better...

I'm unaware of any difference between admin and standard users with respect to these kinds of permissions. Your description of the behaviour when installed in a standard account is how I would expect these apps to function normally. I think the most likely explanation is that most users (and developers and testers) use admin accounts and they haven't made a habit of resetting these permissions to test onboarding and initial setup. Full Disk Access is sometimes a solution. But that isn't a meaningful improvement over the default process. The user still has to manually go into System Settings. And in some cases, when people try to run these tasks as root, it can make these problems even more difficult. The root cause is attempting to use separate backgrounds tools. Why not just put all of the logic into the UI? Or take that further and make your app more stand-alone, with the plug-in being less important? I'm afraid there aren't any ways to technically work around the problem. The user has control. So rather than fight the system, look for different ways to engage with the user. Since your app isn't distributed via the Mac App Store, you have lots of options.

First off, ruling an issue out here:

However, when our tool is installed from a Standard Account, the macOS messages asking for confirmation to access the Desktop or Documents or Downloads folder don’t appear and access to the file/folders is denied.

Does your app include all of the relevant tcc strings (NSDesktopFolderUsageDescription, etc.)? Also, one thing to be careful of here is that there are a bunch of heuristics in this system that control how/when these are presented, which can make knowing "why" something is working a particular way difficult to determine. When you're looking closely at an issue like this, I'd always suggest working on a totally "clean" machine*, not your normal development machine.

*VMs are handy for this, as you can get the system to a fully configured state, then duplicate the VM image so you can always start over from the same exact starting point.

We install a Photoshop plug-in and it’s mainly a UI which then executes a background app containing the business logic to read/write files. The background app runs as a separate process and is not in the Photoshop sandbox space so it doesn't inherit Photoshop permissions/scoping rules.

Full disclosure, I have no idea how Photoshop's plugin system works these days. Is your Photoshop plugin written as a library that Photoshop loads and executes or is it an independent process/app that Photoshop runs?

Getting into details:

executes a background app containing the business logic to read/write files.

How are you doing this? Is the background app a launch agent or something else? Also, what exactly "is" your background app? Is it a true (presumably faceless) "app" that runs NSApplication, has a bundle ID, etc.?

Our plug-in communicates with the background process via ports etc.

How are you actually communicating? XPC or something else? The "official" way to transfer file access is what's described in "Share file access between processes with URL bookmarks”. However, while I know that will work over XPC, I'm not sure it will work through other communication pipes. Note that if you use this approach, make sure you read it carefully and don't pass anything into the options parameter. Somewhat confusingly, you DON'T want to create a "security-scoped bookmark", because that would actually restrict access (details depending on the bookmark type). What you're creating has implicit scope attached, which means the access of the creating process is extended to the receiving process.

There are other options for transferring access, but I want to understand what you're actually doing in more depth before we get into that.

Finally, on this point:

Should we try to register these as Full Disk Access?

I would recommend against this. It's a lot more access than you really want, there isn't any way to "know" if it's on or not, and the confusion around that makes it very difficult to know why something actually failed. Ultimately, that means you end up with a narrower "I can't access these files and I don't know why" problem, which is exactly where you started.

Does anybody have any idea how to allow for the file/folder permissions to be registered/granted in such a case?

SO, my big recommendation here is that you START by doing the interface work of:

  1. Create UI that tells the user that you can't open the file/object and asks them to give you access through an open panel.

  2. (optional) Create UI that allows the user to select directories you "should" have access to, which your background app then saves access to using bookmarks.

The idea here is that this is the "final defense" that ensures your app ALWAYS works. This final defense is important because:

  • macOS is sufficiently complicated that it's difficult to cover EVERY single possible case. The UI above means that missing an edge case doesn't break your app.

  • End user configurations are EXTREMELY difficult to predict or control. This is actually what makes #2 helpful- it lets people with unexpected/odd configurations fix any issue "themselves" without you needing to be involved.

  • Even if something works today, it's very hard to guarantee it will work in the future, either because the system changes or we introduce bugs. Note that the benefit of the open panel isn't that it's immune from bugs*, it's that it's SO critical that it's a pretty safe bet that we'll make fixing it a top priority.

*Over a long enough time scale, everything breaks.

That last point is really critical here. I'm sure we can figure out and fix whatever is happening here. I'm also fairly sure that this will happen again in some other context no matter what you do. Forcing the user to manually select files they "shouldn't" have to is annoying, but that's still better than failing without any solution.

__
Kevin Elliott
DTS Engineer, CoreOS/Hardware

First of all, thank you for the answers. We went back and figured exactly what was occurring and the condition. Everything we did when I posted my original message was on a newly setup M4 Pro Mac with 15.5 as we like to test things continuously.

To investigate further we setup a VM with the same conditions Admin user/Standard user. On the VM everything was working under the Standard user account wherein the System did pop up message saying "Do you wish to grant ABCD" access to the Desktop or Downloads etc folder. We grant access and our plug-ins work as expected.

We went back to the actual M4 Pro machine and understood exactly what was occurring. The Admin user was Physically logged into the system though the GUI was not in use. But the Standard User for testing purposes was logging in via Screen Sharing to the M4 Pro Mac.

So the System was not popping up "Do you want to provide access to the Desktop etc folder" etc. in this condition to the Standard User. Where did the Message/Window to confirm access to the folder vanish to?

The moment the Admin User was physically logged off the Mac, everything started working for the Standard User even under Screen Sharing.

This makes us wonder if this is an edge case macOS bug?

So the System was not popping up "Do you want to provide access to the Desktop etc folder" etc. in this condition to the Standard User. Where did the Message/Window to confirm access to the folder vanish to?

There are more questions on this below, but I suspect what's going on here is you have two plugin instances (because Photoshop is running as a separate process in the two different login sessions) which are both talking to the same background process. I don't know how you ended up in that state, but it's impossible for the same process to "work" in different login sessions.

The moment the Admin User was physically logged off the Mac, everything started working for the Standard User even under Screen Sharing.

This makes us wonder if this is an edge case macOS bug?

No, I don't think this is a macOS bug. Questions I need answered here are these:

How are you doing this? Is the background app a launch agent or something else? Also, what exactly "is" your background app? Is it a true (presumably faceless) "app" that runs NSApplication, has a bundle ID, etc.?

Also, how do your background app and your plugin "find" each other so they can start communicating?

The reason this is important is that what you're describing is what happens when app component ends up (incorrectly) "crossing" between users’ sessions. Instead of each user having their own instance of your background app/process, both users end up talking to the same process. The first user works because the component is partially "entangled" with that user session and other users fail because the system is deeply confused by the entire state.

A few other things you can try:

  • Flip the users, so the standard user runs first, then the admin. I suspect the admin user will start failing, because what matters is the session that first launched the background app, NOT the account type.

  • Try the same thing with multiple admin users.

My guess is that you'll find that the second user always fails, but let me know if something else happens.

__
Kevin Elliott
DTS Engineer, CoreOS/Hardware

File/Folder access/scoping for background only apps
 
 
Q