LaunchAgent e permessi TCC su macOS: guida pratica
Quando un LaunchAgent fallisce con 'Operation not permitted' ma dal Terminale tutto funziona: come diagnosticare e aggiungere i permessi TCC corretti.
LaunchAgent e permessi TCC su macOS
Se hai un LaunchAgent che fallisce con 'Operation not permitted' ma dallo stesso script eseguito nel Terminale tutto funziona, la causa quasi certamente è macOS TCC (Transparency, Consent, and Control).
Cos'è TCC e perché conta
macOS gestisce l'accesso a risorse sensibili (disco, volumi rimovibili, contatti, fotocamera) tramite un database di permessi chiamato TCC. Quando esegui un comando nel Terminale, il Terminale ha già ricevuto i permessi che gli hai concesso. Quando launchd esegue lo stesso comando, lo fa in un contesto separato, senza ereditare i permessi del Terminale.
Risultato: il tuo script funziona da Terminale, ma fallisce silenziosamente (o con 'Operation not permitted') quando gira schedulato.
3 passi per diagnosticare e risolvere
- Leggi i log di launchd per capire l'errore esatto:
log show --predicate 'process == "launchd"' --last 10mSe vedi 'Operation not permitted' o 'TCC deny', è il permesso mancante.
- Vai in Impostazioni di Sistema → Privacy e Sicurezza e aggiungi il tuo script o binario:
- Full Disk Access: per accedere a file su disco senza restrizioni
- File e Cartelle: per accedere a volumi specifici o cartelle utente
- Volumi rimovibili: se il tuo job scrive su un disco esterno
Se il tuo LaunchAgent usa un interprete (python3, node, bash), aggiungi l'interprete in queste sezioni, non solo lo script.
- Verifica che il permesso sia effettivo rilanzando il job:
launchctl kickstart -k gui/$(id -u)/com.tuodominio.tuojobSe esce senza errore TCC, il permesso è stato applicato correttamente.
Il caso reale
Il backup notturno su volume esterno (EX400U) falliva da giorni con 'Operation not permitted'. Dallo stesso script nel Terminale: zero problemi. La causa era esattamente questa: launchd non eredita i permessi TCC che il Terminale aveva già. Aggiunto il permesso 'Volumi rimovibili' per lo script in Privacy & Security, il backup è tornato a girare.
Nota sul PATH e sulle variabili d'ambiente
Oltre ai permessi TCC, un LaunchAgent non eredita le variabili d'ambiente del tuo utente (PATH, HOME in certi casi, variabili custom). Se il tuo job chiama tool installati via brew o nvm, specifica i percorsi assoluti nel plist o aggiungi un EnvironmentVariables block:
<key>EnvironmentVariables</key>
<dict>
<key>PATH</key>
<string>/opt/homebrew/bin:/usr/local/bin:/usr/bin:/bin</string>
</dict>Combinare il fix TCC con i percorsi assoluti risolve il 90% dei casi in cui un job macOS funziona dal Terminale ma non da launchd.