Search code examples
python-3.xmacoscron

MacOS crontab runtime stderr: /usr/local/bin/python3: can't open file 'myscript.py': [Errno 1] Operation not permitted


When trying to run a python script via a crontab schedule:

* * * * * /Users/myUser/Documents/Code/Tools/appName/myScript.py >>/tmp/crontab.log 2>/tmp/crontab.err

Even tried a few different permutations of cd in crontab and os.chdir() in my script:

* * * * * cd Documents/Code/Tools/app-use_tracker/ && /usr/local/bin/python3 app-use_tracker.py >>/tmp/crontab.log 2>/tmp/crontab.err

I kept getting the error below on stderr:

/usr/local/bin/python3: can't open file 'app-use_tracker.py': [Errno 1] Operation not permitted

I came across this solution on SO: https://stackoverflow.com/a/59574552/10761353 but giving Python3 Full disk access doesn't sound like a great(secure) idea.

I even tried 777 permissions on the python3 script, but no change in behaviour 😶

I'm hoping for one of 2 possible solutions. (or both?):

  • alternative ideas on how to get the Python3 script to run, or
  • ways to figure out where in the filesystem, if any such place exists, Python3 can make the requisite types of file read/writes

Solution

  • Recent versions require applications to get users' permission to access the their private information. This includes things like your contacts, the camera and microphone, ... and many parts of the user's home directory, including ~/Desktop, ~/Documents, ~/Downloads, etc. This system is called Transparency Consent and Control (TCC), and you can find some more general info about it in this Apple security guide and this Ask Different Q&A.

    Command-line programs aren't considered "applications", so they don't have their own permissions in this system; they inherit permissions from whatever ran them. For interactive use, that's something like Terminal.app (you probably got prompted for permission the first time you tried to do anything in ~/Documents in Terminal). For cron jobs, that's the cron daemon itself.

    The simplest solution is to move the files someplace that TCC doesn't consider private. Unfortunately, its list of locations that it considers private sometimes expands from version to version, so a subdirectory that works fine now might suddenly run into restrictions after an OS update. But I'm pretty sure it'll only ever include "standard" subdirectories of the user home directory, so if you make one that isn't part of the standard set (e.g. ~/Code or ~/Scripts) it should be safe. ~/Public is also pretty clearly not going to be a restricted location. You could also put files entirely outside your home directory, like under /Users/Shared.

    If that doesn't work for what your script needs to do, you may need to grant access to cron, although I'd avoid this if possible for security reasons. But if you need to, you can go to System Preferences -> Security & Privacy pane -> Privacy tab -> either Files and Folders (for partial access) or Full Disk Access (for, um, full disk access) in the sidebar, then click the padlock at the bottom and authenticate, then click the "+" button, and add /usr/sbin/cron to the list. See this Ask Different Q&A.