CgEvent post works from command line, but not from app on development machine

Hi,

M1 - Mac OS 12.0.1.

I am simulating keyboard events targeted to Logic Pro by posting CgEvents.

This works when I launch my app executing the script that is set as the executable for the app within the info.plist (CFBundleExecutable) on the command line, but not when I double click on the app to open it.

I have enabled the app within Privacy & Security > Accessibility > MyApp.app. I've also deleted the accessibility setting, and the app, rebuilt and reenabled to no effect.

In contrast, as the app uses the network, if I enable the Firewall, I'll get an Allow Request. If I disable the Firewall, the Allow Request doesn't show.

I realise that to ship I need to do the code sign/notarize dance, but I'd expect to get a similar prompt as per the Firewall permissions when running on my development machine, and be able to authorise the sending of keystrokes.

Any help very much appreciated!

Thanks,

Stew

Answered by DTS Engineer in 744555022

Am I correct in thinking that this is the root cause of my problems?

I can’t promise it’s the only cause but it’s definitely something you should fix before going further.

I guess I need to create a native main executable to implement the functionality of the script. Any suggestions as to the best way to do that?

See this post for some code you can adapt to your specific needs. Just hold your nose while you program in C (-:

[Hmmm, I should link to that from my On File System Permissions post. I’m off to do that right now.]

Lemme know how you get along. I’m always interesting in learning about the experiences of folks using alternative development environments.

Share and Enjoy

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

OK, I've moved on a bit... and would appreciate confirmation of my current understanding...

The reason that terminal works is because this is enabled in Security & Privacy > Privacy > Automation > Terminal.app > System Events.app (checked). When the app is run via the terminal it inherits these rights, so all is fine and dandy.

The only way to make this work when double clicking the app is to use a temporary exception entitlement:

com.apple.security.temporary-exception.apple-events

This is largely prohibited from the app store, which doesn't concern me, as I will be "out of App store".

So I've taken my first round of the codesign, notarize dance:

After creating my App ID, the Developer Certificate, and Provisioning Profile I then created an entitlements plist. Please see below.

I then signed the app and notarized sucessfully. Note: I am not using XCode, but used the command line utilities. This did not fix the problem.

My current thinking as to what may address the issue is:

  1. Set the Capabilities within the App ID. When I set this up, I couldn't see any that related to System Events, so currently no capabilities are enabled. What one(s), if any do I need to enable on the App ID to activate the System Events?

  2. I need to use the Provisioning Profile to "whitelist" the temporary exception. Is this required? I haven't found any instructions yet as to how to use the Provisioning Profile to white list the temporary exception. How do I do this? I've seen a reference to placing it in the MacOS directory, but not sure...

  3. I need to "Harden Up"!. I suspect this may be a prerequisite for enabling the temporary exception, but again I'm not sure. I believe there's a setting within XCode, but how do I "harden" manually, and at what stage do I do this?

  4. I'm missing some other entitlements. Please see the current ones below - are these all necessary and sufficient?

I suspect that the network entitlements have worked, but how do I check that? There are no permissions within the Privacy panel. I understand that the user approved entitlements get stored in the TCC database, but the tccutil doesn't provide a way of listing these?

I'd very much appreciate some pointers as to which avenues to take.

Thanks,

Stew

<key>com.apple.security.cs.allow-unsigned-executable-memory</key><true/>
	<key>com.apple.security.cs.disable-library-validation</key><true/>

<key>com.apple.security.cs.allow-dyld-environment-variables</key><true/>
	<key>com.apple.security.files.user-selected.read-write</key><true/>	
   

Duh! It didn't like the Xml. Here are the entitlements:

com.apple.security.automation.apple-events true com.apple.security.network.client true com.apple.security.network.server true com.apple.security.temporary-exception.apple-events true com.apple.security.cs.allow-unsigned-executable-memory true com.apple.security.cs.disable-library-validation true com.apple.security.cs.allow-dyld-environment-variables true com.apple.security.files.user-selected.read-write true

Sorry, I missed something that may be relevant.

After the notarization had succeeded, as notified by email:

Your Mac software has been notarized. You can now export this software and distribute it directly to users.

I ran:

spctl -a -vv MyApp.app      

and got this:

MyApp.app: a sealed resource is missing or invalid.

Which could be another issue? What would cause this to fail, especially after the successful notification?

I also mention "exporting" - presumably this is from XCode, or is there a manual step I also need to do?

Cheers,

Stew

Code signing and notarisation does not factor into user approved privileges except insofar as your code must be signed with a stable signing identity. So it’s fine to use Apple Development signing to test this stuff. You don’t need to do the Developer ID signing / notarisation dance.

Note If you’re having problems with that, I put a bunch of links in the Notarisation Resources post, and the various other posts it links to. If those don’t help, feel free to start a new thread with the appropriate tags because I’d like to keep this focus on posting events.

Posting events with CGEvent does not require any specific entitlements. It does, however, require user approval in System Settings > Privacy & Security. CG has two APIs that can help here:

  • CGPreflightPostEventAccess

  • CGRequestPostEventAccess

You wrote:

This works when I launch my app executing the script that is set as the executable for the app within the Info.plist (CFBundleExecutable)

What sort of script?

If it’s something like a shell script, you’re going to run into problems. This is something I go into in the Scripting section of my On File System Permissions post.

Share and Enjoy

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

Hi Quinn,

Thanks for your reply and clarify my understanding regarding not needing entitlements for posting CGEvents. I think I was confusing this with AppleEvents. I do run scripts to raise windows, check if they're open, or minimised. As they work fine, can I safely assume that there are no security implications in doing this?

Back to the posting events... I came across a post of yours which is relevant:

Programmatically press "delete" or "cmd + v" in sandboxed app https://developer.apple.com/forums/thread/708652

T1Daniel presented a sample that "//Triggers system default accessibility access pop-up". I did a simple runtime test with a few keystrokes. I don't get a pop-up as expected, and also get a "Sender is prohibited from synthesizing events" in the Console for each key down/up post.

Which leads me to the second part of your reply, where you may have hit the nail on the head! Yes, I am using a .sh script as the configured executable. The script sets the current directory to the "application" directory within Resources, and then executes the executable. This is on account of using a Pharo Smalltalk VM as the executable. Please see the script below.

Reading your On File System Permissions post:

TCC and Main Executables TCC expects its bundled clients — apps, app extensions, and so on — to use a native main executable. That is, it expects the CFBundleExecutable property to be the name of a Mach-O executable. If your product uses a script as its main executable, you are likely to encounter TCC problems. To resolve these, switch to using a Mach-O executable.

Am I correct in thinking that this is the root cause of my problems? I guess I need to create a native main executable to implement the functionality of the script. Any suggestions as to the best way to do that?

With respect to codesigning and notarization, I do need to do this as I want to avoid a nasty user experience when opening my app for the first time. See "Can't you just right click?" https://lapcatsoftware.com/articles/unsigned.html. So going down this rabbit hole has proved a valuable learning experience!

Thanks for your help!

Stew

=============================

BASEDIR=$(cd $(dirname $0) && pwd)

cd ${BASEDIR}

cd ../

cd Resources/MyApp

exec ../../MacOS/Pharo -logLevel=4 MyApp.image

Accepted Answer

Am I correct in thinking that this is the root cause of my problems?

I can’t promise it’s the only cause but it’s definitely something you should fix before going further.

I guess I need to create a native main executable to implement the functionality of the script. Any suggestions as to the best way to do that?

See this post for some code you can adapt to your specific needs. Just hold your nose while you program in C (-:

[Hmmm, I should link to that from my On File System Permissions post. I’m off to do that right now.]

Lemme know how you get along. I’m always interesting in learning about the experiences of folks using alternative development environments.

Share and Enjoy

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

Ok, after holding my nose with C I adapted your code to discover that changing the directory within this was useless, as it reverted once the trampoline process had finished.

So I decided to simply invoke the Pharo VM directly. Due to some quirks/bus in its start up routines, it took many hours to get it to start and change the working directory.

The good news is that I am now triggering the expected Accessibility prompt. As this is asynchronous, on installation I probe the system with a dummy keystroke, which causes the "Open Accessibility Preferences" dialog. I unlock, check the app, and re lock, and then continue. The bad news is that this makes no difference - Logic is not responding to the keypresses and I'm still getting the "Sender is prohibited from synthesizing events" in the Console error.

Interestingly there's a whole bunch of messages in the Console when I'm configuring the accessibility. Some have red dots!.

I did get a prompt for Automation/Apple Events when I first ran a script. This no longer appears, so at least that is working.

There's a slight irony in your comment regarding "alternative development environments", since Apple software has its origins in Smalltalk. Please see https://www.mac-history.net/2010/03/22/apple-and-xerox-parc/2/ And your moniker triggered a tune that I recognised - good old Manfred Mann!

Anyway, got any ideas on this?

Cheers,

Stew

Good news!

I was about to do a reset using "sudo tccutil reset Accessibility" as described in https://www.macworld.com/article/347452/how-to-fix-macos-accessibility-permission-when-an-app-cant-be-enabled.html, and it suddenly started to work!. Not sure what I did differently, but as the article says, Accessibility is fragile.

As I'm getting some "flashing" due to focus switching I'd like to explore the possibility of sending the events without having to bring Logic into focus. The OSC command that opens the Logic dialog, causes Logic to "bounce" in the dock. Is there any way I can send keyboard events to this bouncing, non focused dialog, without first bringing Logic into focus? If so happy to open a new thread to discuss.

Thanks "Mighty Quinn"!

Please note that I've opened a new post regarding sending events without switching focus to avoid the flashing using CGEventPostToPid, which doesn't seem to work.

See https://developer.apple.com/forums/thread/724835

CgEvent post works from command line, but not from app on development machine
 
 
Q