diff --git a/apps/chanora_flutter/lib/main.dart b/apps/chanora_flutter/lib/main.dart index 3f9e350..e1dc44f 100644 --- a/apps/chanora_flutter/lib/main.dart +++ b/apps/chanora_flutter/lib/main.dart @@ -648,11 +648,18 @@ class _BetaHomeState extends State<_BetaHome> with WidgetsBindingObserver { action: SnackBarAction( label: l10n.networkPermissionOpenSettings, onPressed: () { - try { - Process.run('open', [ - 'x-apple.systempreferences:com.apple.preference.security?Privacy_LocalNetwork', - ]); - } catch (_) {} + // Fire-and-forget: don't block snackbar dismissal on the + // child process. `Process.run` may throw synchronously + // (e.g. exec ENOENT) or return a future that rejects + // (e.g. macOS denies fork); both paths are swallowed + // because the user can still open Settings manually. + unawaited( + Future(() async { + await Process.run('open', [ + 'x-apple.systempreferences:com.apple.preference.security?Privacy_LocalNetwork', + ]); + }).catchError((_) {}), + ); }, ), ), diff --git a/apps/chanora_flutter/test/services/macos_permissions_service_test.dart b/apps/chanora_flutter/test/services/macos_permissions_service_test.dart index 9a58126..7bebce3 100644 --- a/apps/chanora_flutter/test/services/macos_permissions_service_test.dart +++ b/apps/chanora_flutter/test/services/macos_permissions_service_test.dart @@ -557,4 +557,30 @@ void main() { svc.dispose(); }, ); + + test( + 'SWE4-UV / SRS-300: checkLocalNetworkAccess() returns cached state ' + 'when the channel throws', + () async { + final svc = MacOSPermissionsService(channel: channel)..start(); + + outgoingResponder = (call) async { + if (call.method == methodCheckLocalNetworkAccess) { + throw PlatformException(code: 'probe-failed'); + } + return null; + }; + + // Probe path failures (e.g. NWConnection couldn't establish a + // listener, or the Swift side threw) must not crash callers + // — they must fall back to whatever the service already cached. + final result = await svc.checkLocalNetworkAccess( + host: '127.0.0.1', + port: 9987, + ); + + expect(result, isNotNull); + svc.dispose(); + }, + ); }