0
0
Fork 0
mirror of https://github.com/denoland/deno.git synced 2024-10-29 08:58:01 -04:00

feat(repl): run "deno repl" with no permissions (#16795)

This commit changes "deno repl" command to run with no permissions by
default and accept "--allow-*" flags. 

This change is dictated by the fact that currently there is no way to
run REPL with limited permissions. Technically it's a breaking 
change in the CLI command, but there's agreement in the team 
that it has merit and it's a good solution.

Running just "deno" command still starts the REPL with full permissions
allowed, but now a banner is printed to inform users about that:
This commit is contained in:
Bartek Iwańczuk 2022-12-07 20:21:18 +01:00 committed by GitHub
parent 192f07bb7e
commit 1a472ad06b
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 48 additions and 63 deletions

View file

@ -163,6 +163,7 @@ pub struct LintFlags {
pub struct ReplFlags {
pub eval_files: Option<Vec<String>>,
pub eval: Option<String>,
pub is_default_command: bool,
}
#[derive(Clone, Debug, Eq, PartialEq, Deserialize, Serialize)]
@ -245,6 +246,7 @@ impl Default for DenoSubcommand {
DenoSubcommand::Repl(ReplFlags {
eval_files: None,
eval: None,
is_default_command: true,
})
}
}
@ -624,6 +626,7 @@ pub fn flags_from_vec(args: Vec<String>) -> clap::Result<Flags> {
ReplFlags {
eval_files: None,
eval: None,
is_default_command: true,
},
),
}
@ -632,15 +635,18 @@ pub fn flags_from_vec(args: Vec<String>) -> clap::Result<Flags> {
}
fn handle_repl_flags(flags: &mut Flags, repl_flags: ReplFlags) {
// If user runs just `deno` binary we enter REPL and allow all permissions.
if repl_flags.is_default_command {
flags.allow_net = Some(vec![]);
flags.allow_env = Some(vec![]);
flags.allow_run = Some(vec![]);
flags.allow_read = Some(vec![]);
flags.allow_sys = Some(vec![]);
flags.allow_write = Some(vec![]);
flags.allow_ffi = Some(vec![]);
flags.allow_hrtime = true;
}
flags.subcommand = DenoSubcommand::Repl(repl_flags);
flags.allow_net = Some(vec![]);
flags.allow_env = Some(vec![]);
flags.allow_run = Some(vec![]);
flags.allow_read = Some(vec![]);
flags.allow_sys = Some(vec![]);
flags.allow_write = Some(vec![]);
flags.allow_ffi = Some(vec![]);
flags.allow_hrtime = true;
}
fn clap_root(version: &str) -> Command {
@ -1464,7 +1470,7 @@ Ignore linting a file by adding an ignore comment at the top of the file:
}
fn repl_subcommand<'a>() -> Command<'a> {
runtime_args(Command::new("repl"), false, true)
runtime_args(Command::new("repl"), true, true)
.about("Read Eval Print Loop")
.arg(
Arg::new("eval-file")
@ -1483,7 +1489,6 @@ fn repl_subcommand<'a>() -> Command<'a> {
.takes_value(true)
.value_name("code"),
)
.arg(unsafely_ignore_certificate_errors_arg())
}
fn run_subcommand<'a>() -> Command<'a> {
@ -2654,7 +2659,7 @@ fn lint_parse(flags: &mut Flags, matches: &clap::ArgMatches) {
}
fn repl_parse(flags: &mut Flags, matches: &clap::ArgMatches) {
runtime_args_parse(flags, matches, false, true);
runtime_args_parse(flags, matches, true, true);
unsafely_ignore_certificate_errors_parse(flags, matches);
let eval_files: Option<Vec<String>> = matches
@ -2666,6 +2671,7 @@ fn repl_parse(flags: &mut Flags, matches: &clap::ArgMatches) {
ReplFlags {
eval_files,
eval: matches.value_of("eval").map(ToOwned::to_owned),
is_default_command: false,
},
);
}
@ -4276,7 +4282,8 @@ mod tests {
Flags {
subcommand: DenoSubcommand::Repl(ReplFlags {
eval_files: None,
eval: None
eval: None,
is_default_command: true,
}),
allow_net: Some(vec![]),
unsafely_ignore_certificate_errors: None,
@ -4295,13 +4302,14 @@ mod tests {
#[test]
fn repl_with_flags() {
#[rustfmt::skip]
let r = flags_from_vec(svec!["deno", "repl", "--import-map", "import_map.json", "--no-remote", "--config", "tsconfig.json", "--no-check", "--reload", "--lock", "lock.json", "--lock-write", "--cert", "example.crt", "--cached-only", "--location", "https:foo", "--v8-flags=--help", "--seed", "1", "--inspect=127.0.0.1:9229", "--unsafely-ignore-certificate-errors"]);
let r = flags_from_vec(svec!["deno", "repl", "-A", "--import-map", "import_map.json", "--no-remote", "--config", "tsconfig.json", "--no-check", "--reload", "--lock", "lock.json", "--lock-write", "--cert", "example.crt", "--cached-only", "--location", "https:foo", "--v8-flags=--help", "--seed", "1", "--inspect=127.0.0.1:9229", "--unsafely-ignore-certificate-errors"]);
assert_eq!(
r.unwrap(),
Flags {
subcommand: DenoSubcommand::Repl(ReplFlags {
eval_files: None,
eval: None
eval: None,
is_default_command: false,
}),
import_map_path: Some("import_map.json".to_string()),
no_remote: true,
@ -4316,6 +4324,7 @@ mod tests {
v8_flags: svec!["--help", "--random-seed=1"],
seed: Some(1),
inspect: Some("127.0.0.1:9229".parse().unwrap()),
allow_all: true,
allow_net: Some(vec![]),
allow_env: Some(vec![]),
allow_run: Some(vec![]),
@ -4333,22 +4342,16 @@ mod tests {
#[test]
fn repl_with_eval_flag() {
#[rustfmt::skip]
let r = flags_from_vec(svec!["deno", "repl", "--eval", "console.log('hello');"]);
let r = flags_from_vec(svec!["deno", "repl", "--allow-write", "--eval", "console.log('hello');"]);
assert_eq!(
r.unwrap(),
Flags {
subcommand: DenoSubcommand::Repl(ReplFlags {
eval_files: None,
eval: Some("console.log('hello');".to_string()),
is_default_command: false,
}),
allow_net: Some(vec![]),
allow_env: Some(vec![]),
allow_run: Some(vec![]),
allow_read: Some(vec![]),
allow_sys: Some(vec![]),
allow_write: Some(vec![]),
allow_ffi: Some(vec![]),
allow_hrtime: true,
type_check_mode: TypeCheckMode::None,
..Flags::default()
}
@ -4369,15 +4372,8 @@ mod tests {
"https://examples.deno.land/hello-world.ts".to_string()
]),
eval: None,
is_default_command: false,
}),
allow_net: Some(vec![]),
allow_env: Some(vec![]),
allow_run: Some(vec![]),
allow_read: Some(vec![]),
allow_sys: Some(vec![]),
allow_write: Some(vec![]),
allow_ffi: Some(vec![]),
allow_hrtime: true,
type_check_mode: TypeCheckMode::None,
..Flags::default()
}
@ -5172,16 +5168,9 @@ mod tests {
subcommand: DenoSubcommand::Repl(ReplFlags {
eval_files: None,
eval: Some("console.log('hello');".to_string()),
is_default_command: false,
}),
unsafely_ignore_certificate_errors: Some(vec![]),
allow_net: Some(vec![]),
allow_env: Some(vec![]),
allow_run: Some(vec![]),
allow_read: Some(vec![]),
allow_sys: Some(vec![]),
allow_write: Some(vec![]),
allow_ffi: Some(vec![]),
allow_hrtime: true,
type_check_mode: TypeCheckMode::None,
..Flags::default()
}
@ -5246,7 +5235,8 @@ mod tests {
Flags {
subcommand: DenoSubcommand::Repl(ReplFlags {
eval_files: None,
eval: None
eval: None,
is_default_command: false,
}),
unsafely_ignore_certificate_errors: Some(svec![
"deno.land",
@ -5256,14 +5246,6 @@ mod tests {
"[::1]",
"1.2.3.4"
]),
allow_net: Some(vec![]),
allow_env: Some(vec![]),
allow_run: Some(vec![]),
allow_read: Some(vec![]),
allow_sys: Some(vec![]),
allow_write: Some(vec![]),
allow_ffi: Some(vec![]),
allow_hrtime: true,
type_check_mode: TypeCheckMode::None,
..Flags::default()
}

View file

@ -585,13 +585,7 @@ async fn repl_command(
)
.await?;
worker.setup_repl().await?;
tools::repl::run(
&ps,
worker.into_main_worker(),
repl_flags.eval_files,
repl_flags.eval,
)
.await
tools::repl::run(&ps, worker.into_main_worker(), repl_flags).await
}
async fn run_from_stdin(flags: Flags) -> Result<i32, AnyError> {

View file

@ -557,6 +557,7 @@ mod inspector {
async fn inspector_runtime_evaluate_does_not_crash() {
let child = util::deno_cmd()
.arg("repl")
.arg("--allow-read")
.arg(inspect_flag_with_unique_port("--inspect"))
.stdin(std::process::Stdio::piped())
.stdout(std::process::Stdio::piped())

View file

@ -460,9 +460,9 @@ mod repl {
#[test]
fn import() {
let (out, _) = util::run_and_collect_output(
let (out, _) = util::run_and_collect_output_with_args(
true,
"repl",
vec![],
Some(vec!["import('./subdir/auto_print_hello.ts')"]),
Some(vec![("NO_COLOR".to_owned(), "1".to_owned())]),
false,
@ -472,9 +472,9 @@ mod repl {
#[test]
fn import_declarations() {
let (out, _) = util::run_and_collect_output(
let (out, _) = util::run_and_collect_output_with_args(
true,
"repl",
vec!["repl", "--allow-read"],
Some(vec!["import './subdir/auto_print_hello.ts';"]),
Some(vec![("NO_COLOR".to_owned(), "1".to_owned())]),
false,
@ -796,7 +796,7 @@ mod repl {
fn eval_file_flag_multiple_files() {
let (out, err) = util::run_and_collect_output_with_args(
true,
vec!["repl", "--eval-file=http://127.0.0.1:4545/repl/import_type.ts,./tsc/d.ts,http://127.0.0.1:4545/type_definitions/foo.js"],
vec!["repl", "--allow-read", "--eval-file=http://127.0.0.1:4545/repl/import_type.ts,./tsc/d.ts,http://127.0.0.1:4545/type_definitions/foo.js"],
Some(vec!["b.method1=v4", "b.method1()+foo.toUpperCase()"]),
None,
true,

View file

@ -1,5 +1,7 @@
// Copyright 2018-2022 the Deno authors. All rights reserved. MIT license.
use crate::args::ReplFlags;
use crate::colors;
use crate::proc_state::ProcState;
use deno_core::error::AnyError;
use deno_runtime::permissions::Permissions;
@ -77,8 +79,7 @@ async fn read_eval_file(
pub async fn run(
ps: &ProcState,
worker: MainWorker,
maybe_eval_files: Option<Vec<String>>,
maybe_eval: Option<String>,
repl_flags: ReplFlags,
) -> Result<i32, AnyError> {
let mut repl_session = ReplSession::initialize(worker).await?;
let mut rustyline_channel = rustyline_channel();
@ -92,7 +93,7 @@ pub async fn run(
let history_file_path = ps.dir.repl_history_file_path();
let editor = ReplEditor::new(helper, history_file_path)?;
if let Some(eval_files) = maybe_eval_files {
if let Some(eval_files) = repl_flags.eval_files {
for eval_file in eval_files {
match read_eval_file(ps, &eval_file).await {
Ok(eval_source) => {
@ -114,7 +115,7 @@ pub async fn run(
}
}
if let Some(eval) = maybe_eval {
if let Some(eval) = repl_flags.eval {
let output = repl_session.evaluate_line_and_get_output(&eval).await?;
// only output errors
if let EvaluationOutput::Error(error_text) = output {
@ -127,6 +128,13 @@ pub async fn run(
if !ps.options.is_quiet() {
println!("Deno {}", crate::version::deno());
println!("exit using ctrl+d, ctrl+c, or close()");
if repl_flags.is_default_command {
println!(
"{}",
colors::yellow("REPL is running with all permissions allowed.")
);
println!("To specify permissions, run `deno repl` with allow flags.")
}
}
loop {