From 7e092210312af337a118c70865c2eb2593c83192 Mon Sep 17 00:00:00 2001 From: andy finch Date: Wed, 13 Mar 2019 12:43:47 -0400 Subject: [PATCH] --no-prompt flag for non-interactive environments (#1913) --- src/compiler.rs | 1 + src/flags.rs | 5 +++++ src/ops.rs | 4 ++++ src/permissions.rs | 28 ++++++++++++++++++++------ tools/permission_prompt_test.py | 35 ++++++++++++++++++++++++++++++++- 5 files changed, 66 insertions(+), 7 deletions(-) diff --git a/src/compiler.rs b/src/compiler.rs index 5fe335c551..12554dcecf 100644 --- a/src/compiler.rs +++ b/src/compiler.rs @@ -58,6 +58,7 @@ fn lazy_start(parent_state: &Arc) -> Resource { allow_env: AtomicBool::new(false), allow_net: AtomicBool::new(true), allow_run: AtomicBool::new(false), + ..Default::default() }; let rid = cell.get_or_insert_with(|| { let resource = workers::spawn( diff --git a/src/flags.rs b/src/flags.rs index 471fc58ede..d6a63a9fbf 100644 --- a/src/flags.rs +++ b/src/flags.rs @@ -22,6 +22,7 @@ pub struct DenoFlags { pub allow_net: bool, pub allow_env: bool, pub allow_run: bool, + pub no_prompts: bool, pub types: bool, pub prefetch: bool, pub info: bool, @@ -108,6 +109,9 @@ fn set_recognized_flags( flags.allow_read = true; flags.allow_write = true; } + if matches.opt_present("no-prompt") { + flags.no_prompts = true; + } if matches.opt_present("types") { flags.types = true; } @@ -149,6 +153,7 @@ pub fn set_flags( opts.optflag("", "allow-env", "Allow environment access"); opts.optflag("", "allow-run", "Allow running subprocesses"); opts.optflag("A", "allow-all", "Allow all permissions"); + opts.optflag("", "no-prompt", "Do not use prompts"); opts.optflag("", "recompile", "Force recompilation of TypeScript code"); opts.optflag("h", "help", "Print this message"); opts.optflag("D", "log-debug", "Log debug output"); diff --git a/src/ops.rs b/src/ops.rs index 17cb008dbd..da4a018633 100644 --- a/src/ops.rs +++ b/src/ops.rs @@ -1899,6 +1899,7 @@ mod tests { allow_env: AtomicBool::new(true), allow_net: AtomicBool::new(true), allow_run: AtomicBool::new(true), + ..Default::default() }; let isolate = Isolate::new( IsolateInit { @@ -1944,6 +1945,7 @@ mod tests { allow_env: AtomicBool::new(true), allow_net: AtomicBool::new(true), allow_run: AtomicBool::new(true), + ..Default::default() }; let isolate = Isolate::new( IsolateInit { @@ -1989,6 +1991,7 @@ mod tests { allow_env: AtomicBool::new(true), allow_net: AtomicBool::new(false), allow_run: AtomicBool::new(true), + ..Default::default() }; let isolate = Isolate::new( IsolateInit { @@ -2034,6 +2037,7 @@ mod tests { allow_env: AtomicBool::new(false), allow_net: AtomicBool::new(true), allow_run: AtomicBool::new(false), + ..Default::default() }; let isolate = Isolate::new( IsolateInit { diff --git a/src/permissions.rs b/src/permissions.rs index 03ffd20cb5..5f9588a1eb 100644 --- a/src/permissions.rs +++ b/src/permissions.rs @@ -18,6 +18,7 @@ pub struct DenoPermissions { pub allow_net: AtomicBool, pub allow_env: AtomicBool, pub allow_run: AtomicBool, + pub no_prompts: AtomicBool, } impl DenoPermissions { @@ -28,6 +29,7 @@ impl DenoPermissions { allow_env: AtomicBool::new(flags.allow_env), allow_net: AtomicBool::new(flags.allow_net), allow_run: AtomicBool::new(flags.allow_run), + no_prompts: AtomicBool::new(flags.no_prompts), } } @@ -36,7 +38,7 @@ impl DenoPermissions { return Ok(()); }; // TODO get location (where access occurred) - let r = permission_prompt("access to run a subprocess"); + let r = self.try_permissions_prompt("access to run a subprocess"); if r.is_ok() { self.allow_run.store(true, Ordering::SeqCst); } @@ -48,7 +50,8 @@ impl DenoPermissions { return Ok(()); }; // TODO get location (where access occurred) - let r = permission_prompt(&format!("read access to \"{}\"", filename));; + let r = + self.try_permissions_prompt(&format!("read access to \"{}\"", filename));; if r.is_ok() { self.allow_read.store(true, Ordering::SeqCst); } @@ -60,7 +63,8 @@ impl DenoPermissions { return Ok(()); }; // TODO get location (where access occurred) - let r = permission_prompt(&format!("write access to \"{}\"", filename));; + let r = + self.try_permissions_prompt(&format!("write access to \"{}\"", filename));; if r.is_ok() { self.allow_write.store(true, Ordering::SeqCst); } @@ -72,8 +76,10 @@ impl DenoPermissions { return Ok(()); }; // TODO get location (where access occurred) - let r = - permission_prompt(&format!("network access to \"{}\"", domain_name)); + let r = self.try_permissions_prompt(&format!( + "network access to \"{}\"", + domain_name + )); if r.is_ok() { self.allow_net.store(true, Ordering::SeqCst); } @@ -85,13 +91,22 @@ impl DenoPermissions { return Ok(()); }; // TODO get location (where access occurred) - let r = permission_prompt(&"access to environment variables"); + let r = self.try_permissions_prompt(&"access to environment variables"); if r.is_ok() { self.allow_env.store(true, Ordering::SeqCst); } r } + /// Try to present the user with a permission prompt + /// will error with permission_denied if no_prompts is enabled + fn try_permissions_prompt(&self, message: &str) -> DenoResult<()> { + if self.no_prompts.load(Ordering::SeqCst) { + return Err(permission_denied()); + } + permission_prompt(message) + } + pub fn allows_run(&self) -> bool { return self.allow_run.load(Ordering::SeqCst); } @@ -144,6 +159,7 @@ impl DenoPermissions { allow_env: AtomicBool::new(false), allow_net: AtomicBool::new(false), allow_run: AtomicBool::new(false), + ..Default::default() } } } diff --git a/tools/permission_prompt_test.py b/tools/permission_prompt_test.py index 88fc791bf0..c5ebe4acb7 100755 --- a/tools/permission_prompt_test.py +++ b/tools/permission_prompt_test.py @@ -55,7 +55,8 @@ class Prompt(object): allow_write=False, allow_net=False, allow_env=False, - allow_run=False): + allow_run=False, + no_prompt=False): "Returns (return_code, stdout, stderr)." cmd = [self.deno_exe, PERMISSIONS_PROMPT_TEST_TS, arg] if allow_read: @@ -68,6 +69,8 @@ class Prompt(object): cmd.append("--allow-env") if allow_run: cmd.append("--allow-run") + if no_prompt: + cmd.append("--no-prompt") return tty_capture(cmd, bytes_input) def warm_up(self): @@ -92,6 +95,11 @@ class Prompt(object): assert b'PermissionDenied: permission denied' in stderr assert b'⚠️ Deno requests read access' in stderr + def test_read_no_prompt(self): + code, _stdout, stderr = self.run('needsRead', b'', no_prompt=True) + assert code == 1 + assert b'PermissionDenied: permission denied' in stderr + def test_write_yes(self): code, stdout, stderr = self.run('needsWrite', b'y\n') assert code == 0 @@ -110,6 +118,11 @@ class Prompt(object): assert b'PermissionDenied: permission denied' in stderr assert b'⚠️ Deno requests write access' in stderr + def test_write_no_prompt(self): + code, _stdout, stderr = self.run('needsWrite', b'', no_prompt=True) + assert code == 1 + assert b'PermissionDenied: permission denied' in stderr + def test_env_yes(self): code, stdout, stderr = self.run('needsEnv', b'y\n') assert code == 0 @@ -128,6 +141,11 @@ class Prompt(object): assert b'PermissionDenied: permission denied' in stderr assert b'⚠️ Deno requests access to environment' in stderr + def test_env_no_prompt(self): + code, _stdout, stderr = self.run('needsEnv', b'', no_prompt=True) + assert code == 1 + assert b'PermissionDenied: permission denied' in stderr + def test_net_yes(self): code, stdout, stderr = self.run('needsEnv', b'y\n') assert code == 0 @@ -146,6 +164,11 @@ class Prompt(object): assert b'PermissionDenied: permission denied' in stderr assert b'⚠️ Deno requests network access' in stderr + def test_net_no_prompt(self): + code, _stdout, stderr = self.run('needsNet', b'', no_prompt=True) + assert code == 1 + assert b'PermissionDenied: permission denied' in stderr + def test_run_yes(self): code, stdout, stderr = self.run('needsRun', b'y\n') assert code == 0 @@ -164,6 +187,11 @@ class Prompt(object): assert b'PermissionDenied: permission denied' in stderr assert b'⚠️ Deno requests access to run' in stderr + def test_run_no_prompt(self): + code, _stdout, stderr = self.run('needsRun', b'', no_prompt=True) + assert code == 1 + assert b'PermissionDenied: permission denied' in stderr + def permission_prompt_test(deno_exe): p = Prompt(deno_exe) @@ -171,18 +199,23 @@ def permission_prompt_test(deno_exe): p.test_read_yes() p.test_read_arg() p.test_read_no() + p.test_read_no_prompt() p.test_write_yes() p.test_write_arg() p.test_write_no() + p.test_write_no_prompt() p.test_env_yes() p.test_env_arg() p.test_env_no() + p.test_env_no_prompt() p.test_net_yes() p.test_net_arg() p.test_net_no() + p.test_net_no_prompt() p.test_run_yes() p.test_run_arg() p.test_run_no() + p.test_run_no_prompt() def main():