Skip to content

fix(macos): let terminal programs ask for microphone, camera and Apple Events (fixes #1483) - #1487

Merged
xiaolai merged 3 commits into
mainfrom
fix/issue-1483-terminal-tcc
Sep 30, 2026
Merged

xiaolai merged 3 commits into
mainfrom
fix/issue-1483-terminal-tcc

Conversation

@xiaolai

@xiaolai xiaolai commented Sep 30, 2026

Copy link
Copy Markdown
Owner

Summary

Programs run in VMark's integrated terminal couldn't use the microphone, the camera or Apple Events on macOS. macOS attributes them to VMark, and under the Hardened Runtime VMark declared none of these, so every request was denied without a prompt. FFmpeg recorded all-zero audio (#1483), and osascript and camera capture failed the same way.

This lands @mao13811364454's fix from #1485 (their commit is cherry-picked with authorship kept) and extends it:

  • Three resources, not one: microphone, camera and Apple Events, the part of iTerm2's and Ghostty's declared set that terminal programs realistically use.
  • The MCP sidecar gets none of them. The Tauri bundler re-signs every externalBin with the app's entitlements (crates/tauri-bundler macos/app.rs, sign.rs, CLI 2.11.5) but copies bundle.macOS.files unsigned and signs the app without --deep. So the macOS release places the sidecar through src-tauri/tauri.macos-release.conf.json, keeping the signature release.yml already gives it with sidecar-entitlements.plist (JIT exceptions only). Dev builds, Windows and Linux are unchanged.
  • The shipped artifact is checked, not just the plists: scripts/verify-macos-bundle-entitlements.sh runs in release.yml after the build (it blocks publishing) and in release-smoke.yml on the published DMG from v0.9.89.
  • The permission prompts are localized for all ten app locales (macos-l10n/<lang>.lproj/InfoPlist.strings).
  • Old tags still build: the layout is read from the checked-out tree, so a manual release of an older tag builds as before, and half a layout fails.

Fixes #1483
Closes #1485

Validation

  • Guard test: scripts/check-macos-tcc-entitlements.test.mjs passes 22/22. It failed first (4/5, then 11/22) before each change, and mutations are caught: commenting out the verifier, or dropping the overlay from the build args.

  • Release-style local build: run with the exact release args, from the repo root, ad-hoc signed (--config src-tauri/tauri.macos-release.conf.json --target aarch64-apple-darwin).

    • The app carries all 6 entitlements and the sidecar only its 3 runtime exceptions.
    • Assets.car is kept, and all 10 .lproj folders are present.
    • codesign --verify --deep --strict passes, and the bundled sidecar's --health-check passes.
  • Verify script, checked both ways:

    Bundle Result
    Correct layout passes
    Sidecar re-signed with the app's entitlements fails
    Sidecar without hardened runtime fails
    Missing bundle fails
  • Layout step: all three cases were run using the shell code taken from the workflow.

  • Gates: pnpm check:predelta passed all 46, and pnpm check:all exited 0 (41,462 app tests, servers, build and size limits). The website build and plutil -lint on every plist and .strings file pass.

  • Codex review: round 1 had one Medium and three Low findings, all fixed. Round 2 returned NO FINDINGS.

Not verified here

  • Notarization of the new layout. It happens only in the release. Nested code signed with Developer ID, hardened runtime and a timestamp meets Apple's rules. If Apple rejects it anyway, the release stops at notarization and nothing ships.
  • Real prompts. The microphone was tested by the contributor on an ad-hoc build. I haven't triggered the camera or Apple Events prompts by hand.

mao13811364454 and others added 3 commits September 30, 2026 11:47
Add the audio-input entitlement and microphone usage description for
recording tools launched from the integrated terminal. Document user
consent, virtual-input routing, and short-recording verification.

(cherry picked from commit 42c210f)
…e Events

macOS attributes programs run in VMark's integrated terminal to VMark, so
under the Hardened Runtime they can only ask for a protected resource the app
declares. VMark declared none: FFmpeg recorded all-zero audio with no prompt
(#1483), and the camera and osascript failed the same way.

- src-tauri/app-entitlements.plist: the app bundle's own entitlements, adding
  audio-input, camera and automation.apple-events to the existing runtime
  exceptions. Info.plist gains the three usage descriptions, translated for
  the ten app locales in macos-l10n/<lang>.lproj/InfoPlist.strings.
- The Tauri bundler re-signs every externalBin with the app's entitlements but
  copies bundle.macOS.files unsigned. The macOS release therefore places the
  MCP sidecar through tauri.macos-release.conf.json, keeping the signature
  release.yml gives it with sidecar-entitlements.plist (JIT exceptions only).
  The layout is read from the checked-out tree, so a manual release of an
  older tag still builds as before.
- scripts/verify-macos-bundle-entitlements.sh checks the signed .app: in
  release.yml before publishing, and in release-smoke.yml on the published
  DMG from v0.9.89.
- scripts/check-macos-tcc-entitlements.test.mjs pins the plists, the
  translations and the release wiring.

Builds on the entitlement change from #1485.
…n macOS

Replaces the audio-only section from #1485 with one covering all three
resources, where to change the permission, and what a silent denial looks
like, in English and the nine translated guides.
@xiaolai
xiaolai merged commit 81180fa into main Sep 30, 2026
18 checks passed
@xiaolai
xiaolai deleted the fix/issue-1483-terminal-tcc branch September 30, 2026 05:01
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug] macOS integrated terminal audio capture is denied because the app lacks audio-input entitlement

2 participants