I've developed SOL, an open-source macOS launcher.
Inside of SOL, I added the ability to run AppleScript commands, one of these commands allows me to lock the computer:
{
iconImage: Assets.LockIcon,
name: 'Lock',
type: ItemType.CONFIGURATION,
callback: () => {
solNative.executeAppleScript(
`tell application "System Events" to keystroke "q" using {control down, command down}`,
)
},
},
I have also added the correct entitlements for the hardened runtime (it is distributed only via DeveloperID and not via app store, so hardened runtime is the only capability needed)
<key>com.apple.security.temporary-exception.apple-events</key>
<array>
<string>com.apple.systemevents</string>
<string>com.apple.systempreferences</string>
</array>
The problem is: when I run the app via XCode it works fine, but once the app is packaged and distributed via DeveloperID signed binary, then the lock AppleScript stops working.
Looking at System Preferences I can see the app is still registered and has automation access:
Why does the script stop working? If I remove the permission and re-add it then it starts working again. Does it have to do with the binary? Or is there some permission model I am missing? I had a similar problem with folder access with a different app, so could it be something similar (a security feature I'm not aware of?)
EDIT 1:
Looking through the console.app logs there is also no error message.
EDIT 2:
I just managed to reproduce the issue while attached to XCode and log the output of calling the AppleScript:
Optional({
NSAppleScriptErrorAppName = "System Events";
NSAppleScriptErrorBriefMessage = "Sol is not allowed to send keystrokes.";
NSAppleScriptErrorMessage = "System Events got an error: Sol is not allowed to send keystrokes.";
NSAppleScriptErrorNumber = 1002;
NSAppleScriptErrorRange = "NSRange: {36, 48}";
})
But the app does have accessibility permissions but this still happens? 🥴
EDIT 3:
I just tried removing the app from the accessibility panel and re-adding it, and now the script works again. I killed the app and started it again, and it still works. So my guess right now, is that it has something to do with the binary. Maybe if I replace it with a new version then the accessibility setting doesn't work anymore?
After much gathering at hints all over the internet, I've come to the conclusion that the problem lies in having different binaries.
It makes sense that macOS does some binary check to make sure the application has not been swaped. I had therefore two binaries in my machine a "release" one, which was DeveloperID signed. And the XCode debug one, which uses a development certificate. So both are different and therefore do not pass the binary check.
The brute force solution is not to have a release version installed in my machine. Another solution would be to have the debug binary have a different bundle ID (com.ospfranco.sol), so that macOS allows both the release binary and the debug binary to have accessibility access.