"실패할 수 없는 검사는 검사가 아니야."
모든 권한 창 뒤에 있는 개인정보 데이터베이스
TCC(Transparency, Consent and Control)는 개인정보 보호 및 보안 설정 뒤에서 돌아가는 macOS 하위 시스템이야. 손쉬운 사용, 마이크, 카메라, 화면 기록, 입력 모니터링, 전체 디스크 접근, 캘린더, 미리 알림 같은 항목 하나하나가 따로 권한을 받는 서비스야. 가족의 캘린더 브리지는 미리 알림이 캘린더와 다른 권한이라는 걸 직접 겪고서야 알았어. 권한 하나엔 서비스, 클라이언트(번들 식별자나 경로), 그리고 그 클라이언트의 코드 requirement가 기록돼. 앞의 레슨 세 개가 중요한 이유가 이거야. requirement가 바뀌면 권한이 더는 안 맞아.
실전 규칙 두 개부터 보자. 첫째, 시스템 대화상자를 띄우는 요청에는 앱 Info.plist에 사용 설명 문구가 필요해(NSMicrophoneUsageDescription 같은 것들). Info.plist를 안 넣은 명령줄 도구는 소리 없이 거절당해. 둘째, 손쉬운 사용은 실행 중인 앱에서 AXIsProcessTrustedWithOptions로 물어봐야 해. macOS가 요청 창을 띄우길 원하면 prompt 옵션을 줘.
권한은 책임 프로세스 몫이야
TCC는 요청을 호출한 바이너리가 아니라 책임 프로세스, 즉 그 프로세스 트리를 거느린 앱의 요청으로 쳐. 터미널에서 프로브를 돌리면 터미널의 권한을 보고하고, 코딩 에이전트 셸에서 돌리면 에이전트를 띄운 앱의 권한을 보고해. 그래서 손쉬운 사용 API로 분할 뷰 구분선을 끌어 옮기는 가족 관문은 에이전트 세션에서 돌 수가 없어서, 사람이 직접 돌리는 단계가 됐어. AppleScript로 터미널에 띄운 명령도 보낸 쪽 신원을 달고 있었어. 설치된 런처 번들마다 손쉬운 사용 권한이 따로 필요한 이유도 같아. 번들 신원이 새로우면 TCC엔 새 클라이언트거든.
데이터베이스를 정직하게 읽기
함대 프로브가 메뉴 막대 유틸리티를 잘 돌던 Mac까지 포함해 모든 Mac에서 "권한 받은 적 없음"으로 보고했어. 프로브가 사용자 TCC 데이터베이스를 보고 있었던 거야. 손쉬운 사용 권한은 시스템 데이터베이스에 있고, 마이크 권한은 사용자별 데이터베이스에 있어. 찾는 행을 애초에 볼 수 없는 검사라서 "없음"을 보고할 수밖에 없었던 거지. 지금 프로브는 서비스마다 해당 권한이 저장된 데이터베이스를 보고, 상태를 둘이 아니라 셋으로 나눠. 행 없음은 물어본 적이 없다는 뜻이라 권한 창이 뜰 거야. auth_value = 0인 행은 물어봤는데 허용하지 않았다는 뜻이야. 이땐 창이 다시 안 뜨니까 시스템 설정에서 스위치를 켜야 해. auth_value = 2는 허용됨이야. 원격 셸에서 둘 중 어느 데이터베이스든 읽으려면 전체 디스크 접근 권한이 필요해. 못 읽었으면 못 읽었다고 보고해. 그걸 허용됨이나 없음으로 바꿔 보고하면 절대 안 돼.
서명은 안정적인데 권한이 없어
requirement 레슨에서 봤듯이, 안정적인 designated requirement는 앞으로 받을 권한이 살아남는다는 뜻이지 지금 권한이 있다는 증명이 아니야. 그래서 가족 런처에는 --check-accessibility 모드가 있어. 권한에 기대기 전에, LaunchServices가 띄운 바로 그 번들에서 직접 물어보는 모드야.