From e47b49dfdd115c3f64f28e2ac6d35b837bd9040c Mon Sep 17 00:00:00 2001 From: Gabi <136976886+Gabyran@users.noreply.github.com> Date: Fri, 7 Aug 2026 11:15:22 +0800 Subject: [PATCH] fix(bundle): declare macOS TCC privacy keys for child processes (#323) * fix(bundle): declare macOS TCC privacy keys for child processes tty7 currently ships no NS*UsageDescription keys and no data-access entitlements, so macOS falls back to a repeated "access other apps' data" prompt whenever a child process (shell, coding agent, mole, etc.) touches a protected folder such as ~/Library/Containers, Mail, Messages, or Calendar. kitty and Kaku both declare these privacy intents, which converts the prompt into a single, clear one-time grant. Add the folder/volume usage descriptions and the matching personal-information and device entitlements to the macOS bundle so the app behaves like its terminal peers. * fix(bundle): rework TCC usage strings per review - Correct problem statement: describe child-process-denied-without-prompt instead of the Full Disk Access framing (no NS*UsageDescription key exists for that class). - Add the full usage-string set (camera, microphone, contacts, calendars, reminders, photos, location, motion, local network, bluetooth, speech recognition, system administration, apple events), kitty-style wording. - Use macOS spellings: NSCalendarsFullAccessUsageDescription / NSRemindersFullAccessUsageDescription / NSLocationUsageDescription. - Drop every entitlement that has no matching usage string; keep only com.apple.security.automation.apple-events. - Restore trailing newline at EOF in bundle-macos.sh. - Document the Full Disk Access manual-grant requirement in docs/features.md. * docs: rewrite macOS privacy as feature notes (en + zh-CN) * fix(bundle): drop the apple-events entitlement, tidy the privacy docs The entitlement did not do what its comment claimed. Nothing in tty7 or in gpui's mac platform layer sends an Apple event, and it would not help the case this change is about either: the hardened-runtime automation check runs against the process actually sending the event, which is the pane's child carrying its own signature. What TCC reads off tty7.app is the usage string in Info.plist, which stays. Entitlements are per-executable and never inherited, so granting this one only widened what injected code could reach under an identity that already holds disable-library-validation. Docs: spell out the four Full Disk Access paths instead of running them together as one nested path, drop motion from the user-facing list (Core Motion has no macOS implementation, though the key stays for kitty parity), and place the section identically in the English and Chinese files. --------- Co-authored-by: l0ng-ai <24760907+l0ng-ai@users.noreply.github.com> --- .github/scripts/bundle-macos.sh | 46 +++++++++++++++++++++++++++++++++ docs/features.md | 19 ++++++++++++++ docs/features.zh-CN.md | 17 ++++++++++++ 3 files changed, 82 insertions(+) diff --git a/.github/scripts/bundle-macos.sh b/.github/scripts/bundle-macos.sh index 5f6aa63d..b2566676 100755 --- a/.github/scripts/bundle-macos.sh +++ b/.github/scripts/bundle-macos.sh @@ -68,6 +68,40 @@ cat > "$APP/Contents/Info.plist" <CFBundlePackageTypeAPPL NSHighResolutionCapable NSPrincipalClassNSApplication + + NSCameraUsageDescription + A program running inside tty7 would like to access the camera. + NSMicrophoneUsageDescription + A program running inside tty7 would like to access the microphone. + NSContactsUsageDescription + A program running inside tty7 would like to access your contacts. + NSCalendarsFullAccessUsageDescription + A program running inside tty7 would like to access your calendar data. + NSRemindersFullAccessUsageDescription + A program running inside tty7 would like to access your reminders. + NSPhotoLibraryUsageDescription + A program running inside tty7 would like to access your photo library. + NSLocationUsageDescription + A program running inside tty7 would like to access your location information. + NSMotionUsageDescription + A program running inside tty7 would like to access motion data. + NSLocalNetworkUsageDescription + A program running inside tty7 would like to access the local network. + NSBluetoothAlwaysUsageDescription + A program running inside tty7 would like to use Bluetooth. + NSSpeechRecognitionUsageDescription + A program running inside tty7 would like to use speech recognition. + NSSystemAdministrationUsageDescription + A program running inside tty7 requires elevated privileges. + NSAppleEventsUsageDescription + A program running inside tty7 would like to control other applications via Apple Events. PLIST @@ -109,6 +143,18 @@ if [[ -n "$SIGN_ID" && -n "${APPLE_CERTIFICATE:-}" ]]; then com.apple.security.cs.allow-jit com.apple.security.cs.allow-unsigned-executable-memory com.apple.security.cs.disable-library-validation + ENT diff --git a/docs/features.md b/docs/features.md index 215cecf6..e8ea8231 100644 --- a/docs/features.md +++ b/docs/features.md @@ -122,6 +122,25 @@ a brief pause; `prefix` + an unbound key passes straight through. - Hot paths are lock-free — a big `cat` never waits on drawing - The daemon buffers up to 16 MiB ahead of the window before backpressure applies +## macOS privacy + +Panes are forked from the bundled executable, so macOS attributes a program's +request for a protected resource to tty7.app. tty7 declares the matching TCC +usage strings (camera, microphone, contacts, calendar, reminders, photos, +location, local network, Bluetooth, speech recognition, Apple Events, system +administration) so that program gets the normal one-time prompt instead of +being denied outright with no prompt at all. + +Not covered by usage strings: + +- **Full Disk Access** — Apple defines no usage-string key for it. Reaching + `~/Library/Mail`, `~/Library/Messages`, `~/Library/Safari` or + `~/Library/Containers` needs a manual grant in System Settings. + +Declaring a usage string is not the same as holding the permission: tty7.app +itself is granted none of these resources. Every prompt you see belongs to +whatever you ran in the pane, and you can revoke it under Privacy & Security. + ## Localization The GUI ships English and Simplified Chinese strings. Pick one in Settings → diff --git a/docs/features.zh-CN.md b/docs/features.zh-CN.md index 564ae3f7..99cc7af4 100644 --- a/docs/features.zh-CN.md +++ b/docs/features.zh-CN.md @@ -118,6 +118,23 @@ Aider、Amp、OpenCode 等约 17 个)并在其外围加功能 —— 绝不包 - 热路径全程无锁 —— 再大的 `cat` 也不会阻塞在渲染上 - 触发背压前,守护进程最多可领先窗口缓冲 16 MiB +## macOS 隐私 + +窗格是从 app bundle 里的可执行文件 fork 出来的,所以程序申请受保护资源时, +macOS 会把这次请求算到 tty7.app 头上。tty7 声明了对应的 TCC usage strings +(摄像头、麦克风、通讯录、日历、提醒、照片、定位、本地网络、蓝牙、语音识别、 +Apple Events、系统管理),这样程序才能正常弹出一次性授权窗口,而不是连弹窗都 +没有就被直接拒绝。 + +不受 usage strings 覆盖的: + +- **完全磁盘访问** —— 苹果没有为它定义 usage-string 键。要读写 + `~/Library/Mail`、`~/Library/Messages`、`~/Library/Safari` 或 + `~/Library/Containers`,需要在「系统设置」中手动授权。 + +声明 usage string 不等于持有权限:tty7.app 自己一项都没有拿到。你看到的每个 +授权弹窗都属于你在窗格里运行的那个程序,也可以在「隐私与安全性」中撤销。 + ## 本地化 GUI 目前提供英文和简体中文两套文案。在「设置 → 外观 → 语言」中选择,或直接改