From aa6c1cf2954ba60ad5bf8a52f3ac1084d384447e Mon Sep 17 00:00:00 2001 From: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Date: Sun, 8 Feb 2026 02:49:11 +0000 Subject: [PATCH] fix: filter system daemons from mic detection to prevent false notifications Remove the fallback in resolve_via_nsrunningapp_inner that returned processes based solely on bundleIdentifier when no .app bundle was found. System daemons like avconferenced (FaceTime audio daemon) would slip through this fallback and trigger false 'Meeting in progress?' notifications. Now only processes with an actual .app bundle path are resolved to apps. Co-Authored-By: yujonglee --- crates/detect/src/list/macos.rs | 73 ++++++++++++++++++++++++--------- 1 file changed, 54 insertions(+), 19 deletions(-) diff --git a/crates/detect/src/list/macos.rs b/crates/detect/src/list/macos.rs index 75251ba8ad..3c5832b53d 100644 --- a/crates/detect/src/list/macos.rs +++ b/crates/detect/src/list/macos.rs @@ -84,25 +84,10 @@ fn resolve_via_nsrunningapp(pid: i32) -> Option { fn resolve_via_nsrunningapp_inner(pid: i32) -> Option { let app = NSRunningApplication::runningApplicationWithProcessIdentifier(pid)?; - if let Some(bundle_url) = app.bundleURL() { - if let Some(path_ns) = bundle_url.path() { - let path_str = path_ns.to_string(); - if let Some(resolved) = find_outermost_app(Path::new(&path_str)) { - return Some(resolved); - } - } - } - - let bundle_id = app.bundleIdentifier()?.to_string(); - let name = app - .localizedName() - .map(|s| s.to_string()) - .unwrap_or_else(|| bundle_id.clone()); - - Some(InstalledApp { - id: bundle_id, - name, - }) + let bundle_url = app.bundleURL()?; + let path_ns = bundle_url.path()?; + let path_str = path_ns.to_string(); + find_outermost_app(Path::new(&path_str)) } fn resolve_via_sysinfo(pid: i32) -> Option { @@ -157,4 +142,54 @@ mod tests { println!("- {} ({})", app.name, app.id); } } + + #[test] + fn test_find_outermost_app_system_daemon_path() { + let result = find_outermost_app(Path::new("/usr/libexec/avconferenced")); + assert!( + result.is_none(), + "system daemon should not resolve to an app" + ); + } + + #[test] + fn test_find_outermost_app_system_library_path() { + let result = + find_outermost_app(Path::new("/System/Library/PrivateFrameworks/SomeFramework")); + assert!( + result.is_none(), + "system framework should not resolve to an app" + ); + } + + // cargo test -p detect --features list,mic,app test_resolve_to_app_filters_system_daemons -- --ignored --nocapture + #[test] + #[ignore] + fn test_resolve_to_app_filters_system_daemons() { + let result = resolve_to_app(1); + println!("launchd (pid 1) resolved to: {:?}", result); + assert!( + result.is_none(), + "launchd (pid 1) is a system daemon and should not resolve to an app" + ); + } + + // cargo test -p detect --features list,mic,app test_mic_using_apps_no_system_daemons -- --ignored --nocapture + #[test] + #[ignore] + fn test_mic_using_apps_no_system_daemons() { + let apps = list_mic_using_apps(); + println!("Mic-using apps:"); + for app in &apps { + println!("- {} ({})", app.name, app.id); + } + for app in &apps { + assert!( + !app.name.ends_with('d') || app.name.contains('.'), + "detected app '{}' ({}) looks like a system daemon", + app.name, + app.id, + ); + } + } }