#659: macOS app may use the microphone for voice-over

Problem: the macOS bundle had no NSMicrophoneUsageDescription and empty
hardened-runtime entitlements, so macOS never asked for microphone access
and voice-over recording got no input.

Fix: declare NSMicrophoneUsageDescription in Info.plist.in and grant
com.apple.security.device.audio-input in entitlements.plist; an xtask test
guards both.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
vangel76
2026-10-10 19:00:52 +02:00
co-authored by Claude Opus 5.5
parent 98ba9acbce
commit 379b9b5dec
3 changed files with 30 additions and 1 deletions
+4
View File
@@ -42,6 +42,10 @@
<true/>
<key>NSRequiresAquaSystemAppearance</key>
<false/>
<!-- Voice-over recording (timeline track header ▸ Voice-over Record) reads the microphone.
Without this string macOS never asks and the app gets no input. -->
<key>NSMicrophoneUsageDescription</key>
<string>FilmCraft uses the microphone to record voice-over onto the timeline.</string>
<key>NSHumanReadableCopyright</key>
<string>Copyright © the FilmCraft authors. MIT OR Apache-2.0.</string>
+5 -1
View File
@@ -1,9 +1,13 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<!-- Hardened-runtime entitlements for Filmcraft. Deliberately empty: the app is pure Rust,
<!-- Hardened-runtime entitlements for Filmcraft. Deliberately minimal: the app is pure Rust,
loads no unsigned code, needs no JIT, and is not sandboxed (it opens files by path, from the
command line and drag-and-drop). Add exceptions here only with a reason in a comment. -->
<plist version="1.0">
<dict>
<!-- Voice-over recording reads the microphone; the hardened runtime blocks audio input without
this (Info.plist.in carries the matching NSMicrophoneUsageDescription). -->
<key>com.apple.security.device.audio-input</key>
<true/>
</dict>
</plist>
+21
View File
@@ -504,3 +504,24 @@ fn main() -> ExitCode {
}
}
}
#[cfg(test)]
mod tests {
use std::path::Path;
fn macos_packaging(file: &str) -> String {
let path = Path::new(env!("CARGO_MANIFEST_DIR")).join("../packaging/macos").join(file);
std::fs::read_to_string(&path).unwrap_or_else(|e| panic!("{}: {e}", path.display()))
}
/// Voice-over recording needs both halves on macOS: the usage string (else the permission
/// prompt never appears) and the hardened-runtime audio-input entitlement (else the input is
/// blocked). Regression test for #659.
#[test]
fn macos_bundle_may_use_the_microphone() {
let plist = macos_packaging("Info.plist.in");
assert!(plist.contains("<key>NSMicrophoneUsageDescription</key>"));
let entitlements = macos_packaging("entitlements.plist");
assert!(entitlements.contains("<key>com.apple.security.device.audio-input</key>\n <true/>"));
}
}