From d0ffa0beb52679ddfc90ccc03e27572337db79dc Mon Sep 17 00:00:00 2001 From: Leo Kettmeir Date: Wed, 10 Aug 2022 21:13:53 +0200 Subject: [PATCH] fix(permissions): ignore empty values (#15447) --- cli/file_watcher.rs | 4 +- cli/lsp/testing/execution.rs | 2 +- cli/main.rs | 16 +-- cli/standalone.rs | 2 +- cli/tools/bench.rs | 4 +- cli/tools/test.rs | 4 +- runtime/permissions.rs | 271 +++++++++++++++++++++-------------- 7 files changed, 180 insertions(+), 123 deletions(-) diff --git a/cli/file_watcher.rs b/cli/file_watcher.rs index 0f9f7d1ff0..c5a92e5bfa 100644 --- a/cli/file_watcher.rs +++ b/cli/file_watcher.rs @@ -261,7 +261,7 @@ pub async fn watch_func2( print_config: PrintConfig, ) -> Result<(), AnyError> where - O: FnMut(T) -> F, + O: FnMut(T) -> Result, F: Future>, { let (watcher_sender, mut watcher_receiver) = @@ -306,7 +306,7 @@ where add_paths_to_watcher(&mut watcher, &maybe_paths.unwrap()); } }; - let operation_future = error_handler(operation(operation_args.clone())); + let operation_future = error_handler(operation(operation_args.clone())?); select! { _ = receiver_future => {}, diff --git a/cli/lsp/testing/execution.rs b/cli/lsp/testing/execution.rs index 8d789b20e3..de74de40ed 100644 --- a/cli/lsp/testing/execution.rs +++ b/cli/lsp/testing/execution.rs @@ -282,7 +282,7 @@ impl TestRun { let flags = flags_from_vec(args.into_iter().map(String::from).collect())?; let ps = proc_state::ProcState::build(flags).await?; let permissions = - Permissions::from_options(&ps.options.permissions_options()); + Permissions::from_options(&ps.options.permissions_options())?; test::check_specifiers( &ps, permissions.clone(), diff --git a/cli/main.rs b/cli/main.rs index adc719c839..b8a8c17b30 100644 --- a/cli/main.rs +++ b/cli/main.rs @@ -472,7 +472,7 @@ async fn install_command( preload_flags.inspect = None; preload_flags.inspect_brk = None; let permissions = - Permissions::from_options(&preload_flags.permissions_options()); + Permissions::from_options(&preload_flags.permissions_options())?; let ps = ProcState::build(preload_flags).await?; let main_module = resolve_url_or_path(&install_flags.module_url)?; let mut worker = create_main_worker( @@ -562,7 +562,7 @@ async fn eval_command( // type, and so our "fake" specifier needs to have the proper extension. let main_module = resolve_url_or_path(&format!("./$deno$eval.{}", eval_flags.ext))?; - let permissions = Permissions::from_options(&flags.permissions_options()); + let permissions = Permissions::from_options(&flags.permissions_options())?; let ps = ProcState::build(flags).await?; let mut worker = create_main_worker( &ps, @@ -862,7 +862,7 @@ async fn repl_command( let mut worker = create_main_worker( &ps, main_module.clone(), - Permissions::from_options(&ps.options.permissions_options()), + Permissions::from_options(&ps.options.permissions_options())?, vec![], Default::default(), ); @@ -883,7 +883,7 @@ async fn run_from_stdin(flags: Flags) -> Result { let mut worker = create_main_worker( &ps.clone(), main_module.clone(), - Permissions::from_options(&ps.options.permissions_options()), + Permissions::from_options(&ps.options.permissions_options())?, vec![], Default::default(), ); @@ -994,8 +994,8 @@ async fn run_with_watch(flags: Flags, script: String) -> Result { ModuleSpecifier, )| { let flags = flags.clone(); - let permissions = Permissions::from_options(&flags.permissions_options()); - async move { + let permissions = Permissions::from_options(&flags.permissions_options())?; + Ok(async move { let ps = ProcState::build_for_file_watcher((*flags).clone(), sender.clone()) .await?; @@ -1015,7 +1015,7 @@ async fn run_with_watch(flags: Flags, script: String) -> Result { executor.execute(&main_module).await?; Ok(()) - } + }) }; file_watcher::watch_func2( @@ -1053,7 +1053,7 @@ async fn run_command( let main_module = resolve_url_or_path(&run_flags.script)?; let ps = ProcState::build(flags).await?; let permissions = - Permissions::from_options(&ps.options.permissions_options()); + Permissions::from_options(&ps.options.permissions_options())?; let mut worker = create_main_worker( &ps, main_module.clone(), diff --git a/cli/standalone.rs b/cli/standalone.rs index 72b9b5ef73..9a64854999 100644 --- a/cli/standalone.rs +++ b/cli/standalone.rs @@ -224,7 +224,7 @@ pub async fn run( let flags = metadata_to_flags(&metadata); let main_module = &metadata.entrypoint; let ps = ProcState::build(flags).await?; - let permissions = Permissions::from_options(&metadata.permissions); + let permissions = Permissions::from_options(&metadata.permissions)?; let blob_store = BlobStore::default(); let broadcast_channel = InMemoryBroadcastChannel::default(); let module_loader = Rc::new(EmbeddedModuleLoader { diff --git a/cli/tools/bench.rs b/cli/tools/bench.rs index e859ef7866..60bdd62809 100644 --- a/cli/tools/bench.rs +++ b/cli/tools/bench.rs @@ -524,7 +524,7 @@ pub async fn run_benchmarks( ) -> Result<(), AnyError> { let ps = ProcState::build(flags).await?; let permissions = - Permissions::from_options(&ps.options.permissions_options()); + Permissions::from_options(&ps.options.permissions_options())?; let specifiers = collect_specifiers( bench_flags.include.unwrap_or_else(|| vec![".".to_string()]), &bench_flags.ignore.clone(), @@ -559,7 +559,7 @@ pub async fn run_benchmarks_with_watch( ) -> Result<(), AnyError> { let ps = ProcState::build(flags).await?; let permissions = - Permissions::from_options(&ps.options.permissions_options()); + Permissions::from_options(&ps.options.permissions_options())?; let include = bench_flags.include.unwrap_or_else(|| vec![".".to_string()]); let ignore = bench_flags.ignore.clone(); diff --git a/cli/tools/test.rs b/cli/tools/test.rs index e4b9ad3980..7df7e560dc 100644 --- a/cli/tools/test.rs +++ b/cli/tools/test.rs @@ -1385,7 +1385,7 @@ pub async fn run_tests( ) -> Result<(), AnyError> { let ps = ProcState::build(flags).await?; let permissions = - Permissions::from_options(&ps.options.permissions_options()); + Permissions::from_options(&ps.options.permissions_options())?; let specifiers_with_mode = fetch_specifiers_with_test_mode( &ps, test_flags.include, @@ -1430,7 +1430,7 @@ pub async fn run_tests_with_watch( ) -> Result<(), AnyError> { let ps = ProcState::build(flags).await?; let permissions = - Permissions::from_options(&ps.options.permissions_options()); + Permissions::from_options(&ps.options.permissions_options())?; let include = test_flags.include; let ignore = test_flags.ignore.clone(); diff --git a/runtime/permissions.rs b/runtime/permissions.rs index de44989eb1..9602b94d51 100644 --- a/runtime/permissions.rs +++ b/runtime/permissions.rs @@ -215,12 +215,16 @@ impl NetDescriptor { fn new>(host: &&(T, Option)) -> Self { NetDescriptor(host.0.as_ref().to_string(), host.1) } +} - pub fn from_string(host: String) -> Self { - let url = url::Url::parse(&format!("http://{}", host)).unwrap(); +impl FromStr for NetDescriptor { + type Err = AnyError; + + fn from_str(s: &str) -> Result { + let url = url::Url::parse(&format!("http://{s}"))?; let hostname = url.host_str().unwrap().to_string(); - NetDescriptor(hostname, url.port()) + Ok(NetDescriptor(hostname, url.port())) } } @@ -1126,12 +1130,12 @@ pub struct Permissions { impl Default for Permissions { fn default() -> Self { Self { - read: Permissions::new_read(&None, false), - write: Permissions::new_write(&None, false), - net: Permissions::new_net(&None, false), - env: Permissions::new_env(&None, false), - run: Permissions::new_run(&None, false), - ffi: Permissions::new_ffi(&None, false), + read: Permissions::new_read(&None, false).unwrap(), + write: Permissions::new_write(&None, false).unwrap(), + net: Permissions::new_net(&None, false).unwrap(), + env: Permissions::new_env(&None, false).unwrap(), + run: Permissions::new_run(&None, false).unwrap(), + ffi: Permissions::new_ffi(&None, false).unwrap(), hrtime: Permissions::new_hrtime(false), } } @@ -1153,90 +1157,106 @@ impl Permissions { pub fn new_read( state: &Option>, prompt: bool, - ) -> UnaryPermission { - UnaryPermission:: { + ) -> Result, AnyError> { + Ok(UnaryPermission:: { global_state: global_state_from_option(state), - granted_list: resolve_read_allowlist(state), + granted_list: resolve_read_allowlist(state)?, prompt, ..Default::default() - } + }) } pub fn new_write( state: &Option>, prompt: bool, - ) -> UnaryPermission { - UnaryPermission:: { + ) -> Result, AnyError> { + Ok(UnaryPermission:: { global_state: global_state_from_option(state), - granted_list: resolve_write_allowlist(state), + granted_list: resolve_write_allowlist(state)?, prompt, ..Default::default() - } + }) } pub fn new_net( state: &Option>, prompt: bool, - ) -> UnaryPermission { - UnaryPermission:: { + ) -> Result, AnyError> { + Ok(UnaryPermission:: { global_state: global_state_from_option(state), - granted_list: state - .as_ref() - .map(|v| { + granted_list: state.as_ref().map_or_else( + || Ok(HashSet::new()), + |v| { v.iter() - .map(|x| NetDescriptor::from_string(x.clone())) - .collect() - }) - .unwrap_or_else(HashSet::new), + .map(|x| NetDescriptor::from_str(x)) + .collect::, AnyError>>() + }, + )?, prompt, ..Default::default() - } + }) } pub fn new_env( state: &Option>, prompt: bool, - ) -> UnaryPermission { - UnaryPermission:: { + ) -> Result, AnyError> { + Ok(UnaryPermission:: { global_state: global_state_from_option(state), - granted_list: state - .as_ref() - .map(|v| v.iter().map(EnvDescriptor::new).collect()) - .unwrap_or_else(HashSet::new), + granted_list: state.as_ref().map_or_else( + || Ok(HashSet::new()), + |v| { + v.iter() + .map(|x| { + if x.is_empty() { + Err(AnyError::msg("Empty path is not allowed")) + } else { + Ok(EnvDescriptor::new(x)) + } + }) + .collect() + }, + )?, prompt, ..Default::default() - } + }) } pub fn new_run( state: &Option>, prompt: bool, - ) -> UnaryPermission { - UnaryPermission:: { + ) -> Result, AnyError> { + Ok(UnaryPermission:: { global_state: global_state_from_option(state), - granted_list: state - .as_ref() - .map(|v| { + granted_list: state.as_ref().map_or_else( + || Ok(HashSet::new()), + |v| { v.iter() - .map(|x| RunDescriptor::from_str(x).unwrap()) + .map(|x| { + if x.is_empty() { + Err(AnyError::msg("Empty path is not allowed")) + } else { + Ok(RunDescriptor::from_str(x).unwrap()) + } + }) .collect() - }) - .unwrap_or_else(HashSet::new), + }, + )?, prompt, ..Default::default() - } + }) } pub fn new_ffi( state: &Option>, prompt: bool, - ) -> UnaryPermission { - UnaryPermission:: { + ) -> Result, AnyError> { + Ok(UnaryPermission:: { global_state: global_state_from_option(state), - granted_list: resolve_ffi_allowlist(state), + granted_list: resolve_ffi_allowlist(state)?, prompt, ..Default::default() - } + }) } pub fn new_hrtime(state: bool) -> UnitPermission { @@ -1248,26 +1268,26 @@ impl Permissions { ) } - pub fn from_options(opts: &PermissionsOptions) -> Self { - Self { - read: Permissions::new_read(&opts.allow_read, opts.prompt), - write: Permissions::new_write(&opts.allow_write, opts.prompt), - net: Permissions::new_net(&opts.allow_net, opts.prompt), - env: Permissions::new_env(&opts.allow_env, opts.prompt), - run: Permissions::new_run(&opts.allow_run, opts.prompt), - ffi: Permissions::new_ffi(&opts.allow_ffi, opts.prompt), + pub fn from_options(opts: &PermissionsOptions) -> Result { + Ok(Self { + read: Permissions::new_read(&opts.allow_read, opts.prompt)?, + write: Permissions::new_write(&opts.allow_write, opts.prompt)?, + net: Permissions::new_net(&opts.allow_net, opts.prompt)?, + env: Permissions::new_env(&opts.allow_env, opts.prompt)?, + run: Permissions::new_run(&opts.allow_run, opts.prompt)?, + ffi: Permissions::new_ffi(&opts.allow_ffi, opts.prompt)?, hrtime: Permissions::new_hrtime(opts.allow_hrtime), - } + }) } pub fn allow_all() -> Self { Self { - read: Permissions::new_read(&Some(vec![]), false), - write: Permissions::new_write(&Some(vec![]), false), - net: Permissions::new_net(&Some(vec![]), false), - env: Permissions::new_env(&Some(vec![]), false), - run: Permissions::new_run(&Some(vec![]), false), - ffi: Permissions::new_ffi(&Some(vec![]), false), + read: Permissions::new_read(&Some(vec![]), false).unwrap(), + write: Permissions::new_write(&Some(vec![]), false).unwrap(), + net: Permissions::new_net(&Some(vec![]), false).unwrap(), + env: Permissions::new_env(&Some(vec![]), false).unwrap(), + run: Permissions::new_run(&Some(vec![]), false).unwrap(), + ffi: Permissions::new_ffi(&Some(vec![]), false).unwrap(), hrtime: Permissions::new_hrtime(true), } } @@ -1370,43 +1390,55 @@ fn global_state_from_option(flag: &Option>) -> PermissionState { pub fn resolve_read_allowlist( allow: &Option>, -) -> HashSet { +) -> Result, AnyError> { if let Some(v) = allow { v.iter() .map(|raw_path| { - ReadDescriptor(resolve_from_cwd(Path::new(&raw_path)).unwrap()) + if raw_path.as_os_str().is_empty() { + Err(AnyError::msg("Empty path is not allowed")) + } else { + resolve_from_cwd(Path::new(&raw_path)).map(ReadDescriptor) + } }) .collect() } else { - HashSet::new() + Ok(HashSet::new()) } } pub fn resolve_write_allowlist( allow: &Option>, -) -> HashSet { +) -> Result, AnyError> { if let Some(v) = allow { v.iter() .map(|raw_path| { - WriteDescriptor(resolve_from_cwd(Path::new(&raw_path)).unwrap()) + if raw_path.as_os_str().is_empty() { + Err(AnyError::msg("Empty path is not allowed")) + } else { + resolve_from_cwd(Path::new(&raw_path)).map(WriteDescriptor) + } }) .collect() } else { - HashSet::new() + Ok(HashSet::new()) } } pub fn resolve_ffi_allowlist( allow: &Option>, -) -> HashSet { +) -> Result, AnyError> { if let Some(v) = allow { v.iter() .map(|raw_path| { - FfiDescriptor(resolve_from_cwd(Path::new(&raw_path)).unwrap()) + if raw_path.as_os_str().is_empty() { + Err(AnyError::msg("Empty path is not allowed")) + } else { + resolve_from_cwd(Path::new(&raw_path)).map(FfiDescriptor) + } }) .collect() } else { - HashSet::new() + Ok(HashSet::new()) } } @@ -1687,7 +1719,7 @@ pub fn create_child_permissions( ChildUnaryPermissionArg::NotGranted => {} ChildUnaryPermissionArg::GrantedList(granted_list) => { worker_perms.env.granted_list = - Permissions::new_env(&Some(granted_list), false).granted_list; + Permissions::new_env(&Some(granted_list), false)?.granted_list; if !worker_perms .env .granted_list @@ -1732,7 +1764,7 @@ pub fn create_child_permissions( ChildUnaryPermissionArg::NotGranted => {} ChildUnaryPermissionArg::GrantedList(granted_list) => { worker_perms.net.granted_list = - Permissions::new_net(&Some(granted_list), false).granted_list; + Permissions::new_net(&Some(granted_list), false)?.granted_list; if !worker_perms .net .granted_list @@ -1763,7 +1795,7 @@ pub fn create_child_permissions( worker_perms.ffi.granted_list = Permissions::new_ffi( &Some(granted_list.iter().map(PathBuf::from).collect()), false, - ) + )? .granted_list; if !worker_perms .ffi @@ -1795,7 +1827,7 @@ pub fn create_child_permissions( worker_perms.read.granted_list = Permissions::new_read( &Some(granted_list.iter().map(PathBuf::from).collect()), false, - ) + )? .granted_list; if !worker_perms .read @@ -1825,7 +1857,7 @@ pub fn create_child_permissions( ChildUnaryPermissionArg::NotGranted => {} ChildUnaryPermissionArg::GrantedList(granted_list) => { worker_perms.run.granted_list = - Permissions::new_run(&Some(granted_list), false).granted_list; + Permissions::new_run(&Some(granted_list), false)?.granted_list; if !worker_perms .run .granted_list @@ -1856,7 +1888,7 @@ pub fn create_child_permissions( worker_perms.write.granted_list = Permissions::new_write( &Some(granted_list.iter().map(PathBuf::from).collect()), false, - ) + )? .granted_list; if !worker_perms .write @@ -2080,7 +2112,8 @@ mod tests { allow_read: Some(allowlist.clone()), allow_write: Some(allowlist), ..Default::default() - }); + }) + .unwrap(); // Inside of /a/specific and /a/specific/dir/name assert!(perms.read.check(Path::new("/a/specific/dir/name")).is_ok()); @@ -2146,7 +2179,8 @@ mod tests { "www.github.com:443" ]), ..Default::default() - }); + }) + .unwrap(); let domain_tests = vec![ ("localhost", 1234, true), @@ -2181,7 +2215,8 @@ mod tests { let mut perms = Permissions::from_options(&PermissionsOptions { allow_net: Some(svec![]), // this means `--allow-net` is present without values following `=` sign ..Default::default() - }); + }) + .unwrap(); let domain_tests = vec![ ("localhost", 1234), @@ -2215,7 +2250,8 @@ mod tests { let mut perms = Permissions::from_options(&PermissionsOptions { allow_net: None, ..Default::default() - }); + }) + .unwrap(); let domain_tests = vec![ ("localhost", 1234), @@ -2256,7 +2292,8 @@ mod tests { "www.github.com:443" ]), ..Default::default() - }); + }) + .unwrap(); let url_tests = vec![ // Any protocol + port for localhost should be ok, since we don't specify @@ -2314,7 +2351,8 @@ mod tests { allow_read: Some(read_allowlist), allow_net: Some(svec!["localhost"]), ..Default::default() - }); + }) + .unwrap(); let mut fixtures = vec![ ( @@ -2373,26 +2411,29 @@ mod tests { read: UnaryPermission { global_state: PermissionState::Prompt, ..Permissions::new_read(&Some(vec![PathBuf::from("/foo")]), false) + .unwrap() }, write: UnaryPermission { global_state: PermissionState::Prompt, ..Permissions::new_write(&Some(vec![PathBuf::from("/foo")]), false) + .unwrap() }, net: UnaryPermission { global_state: PermissionState::Prompt, - ..Permissions::new_net(&Some(svec!["127.0.0.1:8000"]), false) + ..Permissions::new_net(&Some(svec!["127.0.0.1:8000"]), false).unwrap() }, env: UnaryPermission { global_state: PermissionState::Prompt, - ..Permissions::new_env(&Some(svec!["HOME"]), false) + ..Permissions::new_env(&Some(svec!["HOME"]), false).unwrap() }, run: UnaryPermission { global_state: PermissionState::Prompt, - ..Permissions::new_run(&Some(svec!["deno"]), false) + ..Permissions::new_run(&Some(svec!["deno"]), false).unwrap() }, ffi: UnaryPermission { global_state: PermissionState::Prompt, ..Permissions::new_ffi(&Some(vec![PathBuf::from("deno")]), false) + .unwrap() }, hrtime: UnitPermission { state: PermissionState::Prompt, @@ -2483,6 +2524,7 @@ mod tests { &Some(vec![PathBuf::from("/foo"), PathBuf::from("/foo/baz")]), false, ) + .unwrap() }, write: UnaryPermission { global_state: PermissionState::Prompt, @@ -2490,6 +2532,7 @@ mod tests { &Some(vec![PathBuf::from("/foo"), PathBuf::from("/foo/baz")]), false, ) + .unwrap() }, net: UnaryPermission { global_state: PermissionState::Prompt, @@ -2497,18 +2540,20 @@ mod tests { &Some(svec!["127.0.0.1", "127.0.0.1:8000"]), false, ) + .unwrap() }, env: UnaryPermission { global_state: PermissionState::Prompt, - ..Permissions::new_env(&Some(svec!["HOME"]), false) + ..Permissions::new_env(&Some(svec!["HOME"]), false).unwrap() }, run: UnaryPermission { global_state: PermissionState::Prompt, - ..Permissions::new_run(&Some(svec!["deno"]), false) + ..Permissions::new_run(&Some(svec!["deno"]), false).unwrap() }, ffi: UnaryPermission { global_state: PermissionState::Prompt, ..Permissions::new_ffi(&Some(vec![PathBuf::from("deno")]), false) + .unwrap() }, hrtime: UnitPermission { state: PermissionState::Denied, @@ -2536,12 +2581,12 @@ mod tests { #[test] fn test_check() { let mut perms = Permissions { - read: Permissions::new_read(&None, true), - write: Permissions::new_write(&None, true), - net: Permissions::new_net(&None, true), - env: Permissions::new_env(&None, true), - run: Permissions::new_run(&None, true), - ffi: Permissions::new_ffi(&None, true), + read: Permissions::new_read(&None, true).unwrap(), + write: Permissions::new_write(&None, true).unwrap(), + net: Permissions::new_net(&None, true).unwrap(), + env: Permissions::new_env(&None, true).unwrap(), + run: Permissions::new_run(&None, true).unwrap(), + ffi: Permissions::new_ffi(&None, true).unwrap(), hrtime: Permissions::new_hrtime(false), }; @@ -2586,12 +2631,12 @@ mod tests { #[test] fn test_check_fail() { let mut perms = Permissions { - read: Permissions::new_read(&None, true), - write: Permissions::new_write(&None, true), - net: Permissions::new_net(&None, true), - env: Permissions::new_env(&None, true), - run: Permissions::new_run(&None, true), - ffi: Permissions::new_ffi(&None, true), + read: Permissions::new_read(&None, true).unwrap(), + write: Permissions::new_write(&None, true).unwrap(), + net: Permissions::new_net(&None, true).unwrap(), + env: Permissions::new_env(&None, true).unwrap(), + run: Permissions::new_run(&None, true).unwrap(), + ffi: Permissions::new_ffi(&None, true).unwrap(), hrtime: Permissions::new_hrtime(false), }; @@ -2652,7 +2697,7 @@ mod tests { let mut perms = Permissions::allow_all(); perms.env = UnaryPermission { global_state: PermissionState::Prompt, - ..Permissions::new_env(&Some(svec!["HOME"]), false) + ..Permissions::new_env(&Some(svec!["HOME"]), false).unwrap() }; prompt_value.set(true); @@ -2810,9 +2855,9 @@ mod tests { #[test] fn test_create_child_permissions() { let mut main_perms = Permissions { - env: Permissions::new_env(&Some(vec![]), false), + env: Permissions::new_env(&Some(vec![]), false).unwrap(), hrtime: Permissions::new_hrtime(true), - net: Permissions::new_net(&Some(svec!["foo", "bar"]), false), + net: Permissions::new_net(&Some(svec!["foo", "bar"]), false).unwrap(), ..Default::default() }; assert_eq!( @@ -2828,8 +2873,8 @@ mod tests { ) .unwrap(), Permissions { - env: Permissions::new_env(&Some(vec![]), false), - net: Permissions::new_net(&Some(svec!["foo"]), false), + env: Permissions::new_env(&Some(vec![]), false).unwrap(), + net: Permissions::new_net(&Some(svec!["foo"]), false).unwrap(), ..Default::default() } ); @@ -2865,7 +2910,8 @@ mod tests { let mut main_perms = Permissions::from_options(&PermissionsOptions { prompt: true, ..Default::default() - }); + }) + .unwrap(); prompt_value.set(true); let worker_perms = create_child_permissions( &mut main_perms, @@ -2885,7 +2931,8 @@ mod tests { let mut main_perms = Permissions::from_options(&PermissionsOptions { prompt: true, ..Default::default() - }); + }) + .unwrap(); prompt_value.set(false); assert!(main_perms.write.check(&PathBuf::from("foo")).is_err()); let worker_perms = create_child_permissions( @@ -2895,4 +2942,14 @@ mod tests { .unwrap(); assert_eq!(worker_perms.write.denied_list, main_perms.write.denied_list); } + + #[test] + fn test_handle_empty_value() { + assert!(Permissions::new_read(&Some(vec![PathBuf::new()]), false).is_err()); + assert!(Permissions::new_env(&Some(vec![String::new()]), false).is_err()); + assert!(Permissions::new_run(&Some(vec![String::new()]), false).is_err()); + assert!(Permissions::new_ffi(&Some(vec![PathBuf::new()]), false).is_err()); + assert!(Permissions::new_net(&Some(svec![String::new()]), false).is_err()); + assert!(Permissions::new_write(&Some(vec![PathBuf::new()]), false).is_err()); + } }