summaryrefslogtreecommitdiff
path: root/cli/args
diff options
context:
space:
mode:
authorBartek Iwańczuk <biwanczuk@gmail.com>2024-09-26 02:50:54 +0100
committerGitHub <noreply@github.com>2024-09-26 01:50:54 +0000
commit5504acea6751480f1425c88353ad5d36257bdce7 (patch)
treefa02e6c546eae469aac894bfc71600ab4eccad28 /cli/args
parent05415bb9de475aa8646985a545f30fe93136207e (diff)
feat: add `--allow-import` flag (#25469)
This replaces `--allow-net` for import permissions and makes the security sandbox stricter by also checking permissions for statically analyzable imports. By default, this has a value of `--allow-import=deno.land:443,jsr.io:443,esm.sh:443,raw.githubusercontent.com:443,gist.githubusercontent.com:443`, but that can be overridden by providing a different set of hosts. Additionally, when no value is provided, import permissions are inferred from the CLI arguments so the following works because `fresh.deno.dev:443` will be added to the list of allowed imports: ```ts deno run -A -r https://fresh.deno.dev ``` --------- Co-authored-by: David Sherret <dsherret@gmail.com>
Diffstat (limited to 'cli/args')
-rw-r--r--cli/args/flags.rs253
-rw-r--r--cli/args/mod.rs102
2 files changed, 270 insertions, 85 deletions
diff --git a/cli/args/flags.rs b/cli/args/flags.rs
index 10fa07bed..74ccb512f 100644
--- a/cli/args/flags.rs
+++ b/cli/args/flags.rs
@@ -1,5 +1,6 @@
// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
+use std::borrow::Cow;
use std::collections::HashSet;
use std::env;
use std::ffi::OsString;
@@ -44,6 +45,7 @@ use crate::args::resolve_no_prompt;
use crate::util::fs::canonicalize_path;
use super::flags_net;
+use super::jsr_url;
#[derive(Clone, Debug, Default, Eq, PartialEq)]
pub enum ConfigFlag {
@@ -639,6 +641,7 @@ pub struct PermissionFlags {
pub allow_write: Option<Vec<String>>,
pub deny_write: Option<Vec<String>>,
pub no_prompt: bool,
+ pub allow_import: Option<Vec<String>>,
}
impl PermissionFlags {
@@ -658,9 +661,10 @@ impl PermissionFlags {
|| self.deny_sys.is_some()
|| self.allow_write.is_some()
|| self.deny_write.is_some()
+ || self.allow_import.is_some()
}
- pub fn to_options(&self) -> PermissionsOptions {
+ pub fn to_options(&self, cli_arg_urls: &[Cow<Url>]) -> PermissionsOptions {
fn handle_allow<T: Default>(
allow_all: bool,
value: Option<T>,
@@ -673,6 +677,41 @@ impl PermissionFlags {
}
}
+ fn handle_imports(
+ cli_arg_urls: &[Cow<Url>],
+ imports: Option<Vec<String>>,
+ ) -> Option<Vec<String>> {
+ if imports.is_some() {
+ return imports;
+ }
+
+ let builtin_allowed_import_hosts = [
+ "deno.land:443",
+ "esm.sh:443",
+ "jsr.io:443",
+ "raw.githubusercontent.com:443",
+ "gist.githubusercontent.com:443",
+ ];
+
+ let mut imports =
+ Vec::with_capacity(builtin_allowed_import_hosts.len() + 1);
+ imports
+ .extend(builtin_allowed_import_hosts.iter().map(|s| s.to_string()));
+
+ // also add the JSR_URL env var
+ if let Some(jsr_host) = allow_import_host_from_url(jsr_url()) {
+ imports.push(jsr_host);
+ }
+ // include the cli arg urls
+ for url in cli_arg_urls {
+ if let Some(host) = allow_import_host_from_url(url) {
+ imports.push(host);
+ }
+ }
+
+ Some(imports)
+ }
+
PermissionsOptions {
allow_all: self.allow_all,
allow_env: handle_allow(self.allow_all, self.allow_env.clone()),
@@ -689,11 +728,33 @@ impl PermissionFlags {
deny_sys: self.deny_sys.clone(),
allow_write: handle_allow(self.allow_all, self.allow_write.clone()),
deny_write: self.deny_write.clone(),
+ allow_import: handle_imports(
+ cli_arg_urls,
+ handle_allow(self.allow_all, self.allow_import.clone()),
+ ),
prompt: !resolve_no_prompt(self),
}
}
}
+/// Gets the --allow-import host from the provided url
+fn allow_import_host_from_url(url: &Url) -> Option<String> {
+ let host = url.host()?;
+ if let Some(port) = url.port() {
+ Some(format!("{}:{}", host, port))
+ } else {
+ use deno_core::url::Host::*;
+ match host {
+ Domain(domain) if domain == "jsr.io" && url.scheme() == "https" => None,
+ _ => match url.scheme() {
+ "https" => Some(format!("{}:443", host)),
+ "http" => Some(format!("{}:80", host)),
+ _ => None,
+ },
+ }
+ }
+}
+
fn join_paths(allowlist: &[String], d: &str) -> String {
allowlist
.iter()
@@ -881,6 +942,17 @@ impl Flags {
_ => {}
}
+ match &self.permissions.allow_import {
+ Some(allowlist) if allowlist.is_empty() => {
+ args.push("--allow-import".to_string());
+ }
+ Some(allowlist) => {
+ let s = format!("--allow-import={}", allowlist.join(","));
+ args.push(s);
+ }
+ _ => {}
+ }
+
args
}
@@ -991,6 +1063,7 @@ impl Flags {
self.permissions.allow_write = None;
self.permissions.allow_sys = None;
self.permissions.allow_ffi = None;
+ self.permissions.allow_import = None;
}
pub fn resolve_watch_exclude_set(
@@ -1707,6 +1780,7 @@ Future runs of this module will trigger no downloads or compilation unless --rel
)
.arg(frozen_lockfile_arg())
.arg(allow_scripts_arg())
+ .arg(allow_import_arg())
})
}
@@ -1766,6 +1840,7 @@ Unless --reload is specified, this command will not re-download already cached d
.required_unless_present("help")
.value_hint(ValueHint::FilePath),
)
+ .arg(allow_import_arg())
}
)
}
@@ -1994,6 +2069,7 @@ Show documentation for runtime built-ins:
.arg(no_lock_arg())
.arg(no_npm_arg())
.arg(no_remote_arg())
+ .arg(allow_import_arg())
.arg(
Arg::new("json")
.long("json")
@@ -2358,6 +2434,7 @@ The following information is shown:
.help("UNSTABLE: Outputs the information in JSON format")
.action(ArgAction::SetTrue),
))
+ .arg(allow_import_arg())
}
fn install_subcommand() -> Command {
@@ -3151,47 +3228,44 @@ fn permission_args(app: Command, requires: Option<&'static str>) -> Command {
.after_help(cstr!(r#"<y>Permission options:</>
<y>Docs</>: <c>https://docs.deno.com/go/permissions</>
- <g>-A, --allow-all</> Allow all permissions.
- <g>--no-prompt</> Always throw if required permission wasn't passed.
- <p(245)>Can also be set via the DENO_NO_PROMPT environment variable.</>
- <g>-R, --allow-read[=<<PATH>...]</> Allow file system read access. Optionally specify allowed paths.
- <p(245)>--allow-read | --allow-read="/etc,/var/log.txt"</>
- <g>-W, --allow-write[=<<PATH>...]</> Allow file system write access. Optionally specify allowed paths.
- <p(245)>--allow-write | --allow-write="/etc,/var/log.txt"</>
- <g>-N, --allow-net[=<<IP_OR_HOSTNAME>...]</> Allow network access. Optionally specify allowed IP addresses and host names, with ports as necessary.
- <p(245)>--allow-net | --allow-net="localhost:8080,deno.land"</>
- <g>-E, --allow-env[=<<VARIABLE_NAME>...]</> Allow access to environment variables. Optionally specify accessible environment variables.
- <p(245)>--allow-env | --allow-env="PORT,HOME,PATH"</>
- <g>-S, --allow-sys[=<<API_NAME>...]</> Allow access to OS information. Optionally allow specific APIs by function name.
- <p(245)>--allow-sys | --allow-sys="systemMemoryInfo,osRelease"</>
- <g>--allow-run[=<<PROGRAM_NAME>...]</> Allow running subprocesses. Optionally specify allowed runnable program names.
- <p(245)>--allow-run | --allow-run="whoami,ps"</>
- <g>--allow-ffi[=<<PATH>...]</> (Unstable) Allow loading dynamic libraries. Optionally specify allowed directories or files.
- <p(245)>--allow-ffi | --allow-ffi="./libfoo.so"</>
- <g> --deny-read[=<<PATH>...]</> Deny file system read access. Optionally specify denied paths.
- <p(245)>--deny-read | --deny-read="/etc,/var/log.txt"</>
- <g> --deny-write[=<<PATH>...]</> Deny file system write access. Optionally specify denied paths.
- <p(245)>--deny-write | --deny-write="/etc,/var/log.txt"</>
- <g> --deny-net[=<<IP_OR_HOSTNAME>...]</> Deny network access. Optionally specify defined IP addresses and host names, with ports as necessary.
- <p(245)>--deny-net | --deny-net="localhost:8080,deno.land"</>
- <g> --deny-env[=<<VARIABLE_NAME>...]</> Deny access to environment variables. Optionally specify inacessible environment variables.
- <p(245)>--deny-env | --deny-env="PORT,HOME,PATH"</>
- <g>-S, --deny-sys[=<<API_NAME>...]</> Deny access to OS information. Optionally deny specific APIs by function name.
- <p(245)>--deny-sys | --deny-sys="systemMemoryInfo,osRelease"</>
- <g>--deny-run[=<<PROGRAM_NAME>...]</> Deny running subprocesses. Optionally specify denied runnable program names.
- <p(245)>--deny-run | --deny-run="whoami,ps"</>
- <g>--deny-ffi[=<<PATH>...]</> (Unstable) Deny loading dynamic libraries. Optionally specify denied directories or files.
- <p(245)>--deny-ffi | --deny-ffi="./libfoo.so"</>
+ <g>-A, --allow-all</> Allow all permissions.
+ <g>--no-prompt</> Always throw if required permission wasn't passed.
+ <p(245)>Can also be set via the DENO_NO_PROMPT environment variable.</>
+ <g>-R, --allow-read[=<<PATH>...]</> Allow file system read access. Optionally specify allowed paths.
+ <p(245)>--allow-read | --allow-read="/etc,/var/log.txt"</>
+ <g>-W, --allow-write[=<<PATH>...]</> Allow file system write access. Optionally specify allowed paths.
+ <p(245)>--allow-write | --allow-write="/etc,/var/log.txt"</>
+ <g>-I, --allow-import[=<<IP_OR_HOSTNAME>...]</> Allow importing from remote hosts. Optionally specify allowed IP addresses and host names, with ports as necessary.
+ Default value: <p(245)>deno.land:443,jsr.io:443,esm.sh:443,raw.githubusercontent.com:443,user.githubusercontent.com:443</>
+ <p(245)>--allow-import | --allow-import="example.com,github.com"</>
+ <g>-N, --allow-net[=<<IP_OR_HOSTNAME>...]</> Allow network access. Optionally specify allowed IP addresses and host names, with ports as necessary.
+ <p(245)>--allow-net | --allow-net="localhost:8080,deno.land"</>
+ <g>-E, --allow-env[=<<VARIABLE_NAME>...]</> Allow access to environment variables. Optionally specify accessible environment variables.
+ <p(245)>--allow-env | --allow-env="PORT,HOME,PATH"</>
+ <g>-S, --allow-sys[=<<API_NAME>...]</> Allow access to OS information. Optionally allow specific APIs by function name.
+ <p(245)>--allow-sys | --allow-sys="systemMemoryInfo,osRelease"</>
+ <g>--allow-run[=<<PROGRAM_NAME>...]</> Allow running subprocesses. Optionally specify allowed runnable program names.
+ <p(245)>--allow-run | --allow-run="whoami,ps"</>
+ <g>--allow-ffi[=<<PATH>...]</> (Unstable) Allow loading dynamic libraries. Optionally specify allowed directories or files.
+ <p(245)>--allow-ffi | --allow-ffi="./libfoo.so"</>
+ <g> --deny-read[=<<PATH>...]</> Deny file system read access. Optionally specify denied paths.
+ <p(245)>--deny-read | --deny-read="/etc,/var/log.txt"</>
+ <g> --deny-write[=<<PATH>...]</> Deny file system write access. Optionally specify denied paths.
+ <p(245)>--deny-write | --deny-write="/etc,/var/log.txt"</>
+ <g> --deny-net[=<<IP_OR_HOSTNAME>...]</> Deny network access. Optionally specify defined IP addresses and host names, with ports as necessary.
+ <p(245)>--deny-net | --deny-net="localhost:8080,deno.land"</>
+ <g> --deny-env[=<<VARIABLE_NAME>...]</> Deny access to environment variables. Optionally specify inacessible environment variables.
+ <p(245)>--deny-env | --deny-env="PORT,HOME,PATH"</>
+ <g>-S, --deny-sys[=<<API_NAME>...]</> Deny access to OS information. Optionally deny specific APIs by function name.
+ <p(245)>--deny-sys | --deny-sys="systemMemoryInfo,osRelease"</>
+ <g>--deny-run[=<<PROGRAM_NAME>...]</> Deny running subprocesses. Optionally specify denied runnable program names.
+ <p(245)>--deny-run | --deny-run="whoami,ps"</>
+ <g>--deny-ffi[=<<PATH>...]</> (Unstable) Deny loading dynamic libraries. Optionally specify denied directories or files.
+ <p(245)>--deny-ffi | --deny-ffi="./libfoo.so"</>
"#))
.arg(
{
- let mut arg = Arg::new("allow-all")
- .short('A')
- .long("allow-all")
- .action(ArgAction::SetTrue)
- .help("Allow all permissions")
- .hide(true)
- ;
+ let mut arg = allow_all_arg().hide(true);
if let Some(requires) = requires {
arg = arg.requires(requires)
}
@@ -3200,7 +3274,7 @@ fn permission_args(app: Command, requires: Option<&'static str>) -> Command {
)
.arg(
{
- let mut arg = Arg::new("allow-read")
+ let mut arg = Arg::new("allow-read")
.long("allow-read")
.short('R')
.num_args(0..)
@@ -3218,7 +3292,7 @@ fn permission_args(app: Command, requires: Option<&'static str>) -> Command {
)
.arg(
{
- let mut arg = Arg::new("deny-read")
+ let mut arg = Arg::new("deny-read")
.long("deny-read")
.num_args(0..)
.action(ArgAction::Append)
@@ -3235,7 +3309,7 @@ fn permission_args(app: Command, requires: Option<&'static str>) -> Command {
)
.arg(
{
- let mut arg = Arg::new("allow-write")
+ let mut arg = Arg::new("allow-write")
.long("allow-write")
.short('W')
.num_args(0..)
@@ -3253,7 +3327,7 @@ fn permission_args(app: Command, requires: Option<&'static str>) -> Command {
)
.arg(
{
- let mut arg = Arg::new("deny-write")
+ let mut arg = Arg::new("deny-write")
.long("deny-write")
.num_args(0..)
.action(ArgAction::Append)
@@ -3270,7 +3344,7 @@ fn permission_args(app: Command, requires: Option<&'static str>) -> Command {
)
.arg(
{
- let mut arg = Arg::new("allow-net")
+ let mut arg = Arg::new("allow-net")
.long("allow-net")
.short('N')
.num_args(0..)
@@ -3289,7 +3363,7 @@ fn permission_args(app: Command, requires: Option<&'static str>) -> Command {
)
.arg(
{
- let mut arg = Arg::new("deny-net")
+ let mut arg = Arg::new("deny-net")
.long("deny-net")
.num_args(0..)
.use_value_delimiter(true)
@@ -3383,7 +3457,7 @@ fn permission_args(app: Command, requires: Option<&'static str>) -> Command {
)
.arg(
{
- let mut arg = Arg::new("deny-sys")
+ let mut arg = Arg::new("deny-sys")
.long("deny-sys")
.num_args(0..)
.use_value_delimiter(true)
@@ -3418,7 +3492,7 @@ fn permission_args(app: Command, requires: Option<&'static str>) -> Command {
)
.arg(
{
- let mut arg = Arg::new("deny-run")
+ let mut arg = Arg::new("deny-run")
.long("deny-run")
.num_args(0..)
.use_value_delimiter(true)
@@ -3509,6 +3583,26 @@ fn permission_args(app: Command, requires: Option<&'static str>) -> Command {
arg
}
)
+ .arg(
+ {
+ let mut arg = allow_import_arg().hide(true);
+ if let Some(requires) = requires {
+ // allow this for install --global
+ if requires != "global" {
+ arg = arg.requires(requires)
+ }
+ }
+ arg
+ }
+ )
+}
+
+fn allow_all_arg() -> Arg {
+ Arg::new("allow-all")
+ .short('A')
+ .long("allow-all")
+ .action(ArgAction::SetTrue)
+ .help("Allow all permissions")
}
fn runtime_args(
@@ -3537,6 +3631,20 @@ fn runtime_args(
.arg(strace_ops_arg())
}
+fn allow_import_arg() -> Arg {
+ Arg::new("allow-import")
+ .long("allow-import")
+ .short('I')
+ .num_args(0..)
+ .use_value_delimiter(true)
+ .require_equals(true)
+ .value_name("IP_OR_HOSTNAME")
+ .help(cstr!(
+ "Allow importing from remote hosts. Optionally specify allowed IP addresses and host names, with ports as necessary. Default value: <p(245)>deno.land:443,jsr.io:443,esm.sh:443,raw.githubusercontent.com:443,user.githubusercontent.com:443</>"
+ ))
+ .value_parser(flags_net::validator)
+}
+
fn inspect_args(app: Command) -> Command {
app
.arg(
@@ -4174,6 +4282,7 @@ fn cache_parse(
unstable_args_parse(flags, matches, UnstableArgsConfig::ResolutionOnly);
frozen_lockfile_arg_parse(flags, matches);
allow_scripts_arg_parse(flags, matches)?;
+ allow_import_parse(flags, matches);
let files = matches.remove_many::<String>("file").unwrap().collect();
flags.subcommand = DenoSubcommand::Cache(CacheFlags { files });
Ok(())
@@ -4195,6 +4304,7 @@ fn check_parse(
doc: matches.get_flag("doc"),
doc_only: matches.get_flag("doc-only"),
});
+ allow_import_parse(flags, matches);
Ok(())
}
@@ -4320,6 +4430,7 @@ fn doc_parse(
no_lock_arg_parse(flags, matches);
no_npm_arg_parse(flags, matches);
no_remote_arg_parse(flags, matches);
+ allow_import_parse(flags, matches);
let source_files_val = matches.remove_many::<String>("source_file");
let source_files = if let Some(val) = source_files_val {
@@ -4460,6 +4571,7 @@ fn info_parse(
lock_args_parse(flags, matches);
no_remote_arg_parse(flags, matches);
no_npm_arg_parse(flags, matches);
+ allow_import_parse(flags, matches);
let json = matches.get_flag("json");
flags.subcommand = DenoSubcommand::Info(InfoFlags {
file: matches.remove_one::<String>("file"),
@@ -4495,6 +4607,7 @@ fn install_parse(
force,
}),
});
+
return Ok(());
}
@@ -5175,13 +5288,22 @@ fn permission_args_parse(
}
if matches.get_flag("allow-hrtime") || matches.get_flag("deny-hrtime") {
- log::warn!("⚠️ Warning: `allow-hrtime` and `deny-hrtime` have been removed in Deno 2, as high resolution time is now always allowed.");
+ // use eprintln instead of log::warn because logging hasn't been initialized yet
+ #[allow(clippy::print_stderr)]
+ {
+ eprintln!(
+ "{} `allow-hrtime` and `deny-hrtime` have been removed in Deno 2, as high resolution time is now always allowed",
+ deno_runtime::colors::yellow("Warning")
+ );
+ }
}
if matches.get_flag("allow-all") {
flags.allow_all();
}
+ allow_import_parse(flags, matches);
+
if matches.get_flag("no-prompt") {
flags.permissions.no_prompt = true;
}
@@ -5189,6 +5311,13 @@ fn permission_args_parse(
Ok(())
}
+fn allow_import_parse(flags: &mut Flags, matches: &mut ArgMatches) {
+ if let Some(imports_wl) = matches.remove_many::<String>("allow-import") {
+ let imports_allowlist = flags_net::parse(imports_wl.collect()).unwrap();
+ flags.permissions.allow_import = Some(imports_allowlist);
+ }
+}
+
fn unsafely_ignore_certificate_errors_parse(
flags: &mut Flags,
matches: &mut ArgMatches,
@@ -6215,7 +6344,7 @@ mod tests {
#[test]
fn short_permission_flags() {
- let r = flags_from_vec(svec!["deno", "run", "-RNESW", "gist.ts"]);
+ let r = flags_from_vec(svec!["deno", "run", "-RNESWI", "gist.ts"]);
assert_eq!(
r.unwrap(),
Flags {
@@ -6226,6 +6355,7 @@ mod tests {
allow_read: Some(vec![]),
allow_write: Some(vec![]),
allow_env: Some(vec![]),
+ allow_import: Some(vec![]),
allow_net: Some(vec![]),
allow_sys: Some(vec![]),
..Default::default()
@@ -10777,7 +10907,7 @@ mod tests {
}
);
// just make sure this doesn't panic
- let _ = flags.permissions.to_options();
+ let _ = flags.permissions.to_options(&[]);
}
#[test]
@@ -10852,4 +10982,27 @@ mod tests {
Usage: deno repl [OPTIONS] [-- [ARGS]...]\n"
)
}
+
+ #[test]
+ fn test_allow_import_host_from_url() {
+ fn parse(text: &str) -> Option<String> {
+ allow_import_host_from_url(&Url::parse(text).unwrap())
+ }
+
+ assert_eq!(parse("https://jsr.io"), None);
+ assert_eq!(
+ parse("http://127.0.0.1:4250"),
+ Some("127.0.0.1:4250".to_string())
+ );
+ assert_eq!(parse("http://jsr.io"), Some("jsr.io:80".to_string()));
+ assert_eq!(
+ parse("https://example.com"),
+ Some("example.com:443".to_string())
+ );
+ assert_eq!(
+ parse("http://example.com"),
+ Some("example.com:80".to_string())
+ );
+ assert_eq!(parse("file:///example.com"), None);
+ }
}
diff --git a/cli/args/mod.rs b/cli/args/mod.rs
index 1c92777ae..80b9afb24 100644
--- a/cli/args/mod.rs
+++ b/cli/args/mod.rs
@@ -769,6 +769,7 @@ pub struct CliOptions {
// application need not concern itself with, so keep these private
flags: Arc<Flags>,
initial_cwd: PathBuf,
+ main_module_cell: std::sync::OnceLock<Result<ModuleSpecifier, AnyError>>,
maybe_node_modules_folder: Option<PathBuf>,
npmrc: Arc<ResolvedNpmRc>,
maybe_lockfile: Option<Arc<CliLockfile>>,
@@ -825,6 +826,7 @@ impl CliOptions {
npmrc,
maybe_node_modules_folder,
overrides: Default::default(),
+ main_module_cell: std::sync::OnceLock::new(),
start_dir,
deno_dir_provider,
})
@@ -1105,40 +1107,43 @@ impl CliOptions {
self.flags.env_file.as_ref()
}
- pub fn resolve_main_module(&self) -> Result<ModuleSpecifier, AnyError> {
- let main_module = match &self.flags.subcommand {
- DenoSubcommand::Compile(compile_flags) => {
- resolve_url_or_path(&compile_flags.source_file, self.initial_cwd())?
- }
- DenoSubcommand::Eval(_) => {
- resolve_url_or_path("./$deno$eval.ts", self.initial_cwd())?
- }
- DenoSubcommand::Repl(_) => {
- resolve_url_or_path("./$deno$repl.ts", self.initial_cwd())?
- }
- DenoSubcommand::Run(run_flags) => {
- if run_flags.is_stdin() {
- std::env::current_dir()
- .context("Unable to get CWD")
- .and_then(|cwd| {
- resolve_url_or_path("./$deno$stdin.ts", &cwd)
- .map_err(AnyError::from)
- })?
- } else if NpmPackageReqReference::from_str(&run_flags.script).is_ok() {
- ModuleSpecifier::parse(&run_flags.script)?
- } else {
- resolve_url_or_path(&run_flags.script, self.initial_cwd())?
- }
- }
- DenoSubcommand::Serve(run_flags) => {
- resolve_url_or_path(&run_flags.script, self.initial_cwd())?
- }
- _ => {
- bail!("No main module.")
- }
- };
+ pub fn resolve_main_module(&self) -> Result<&ModuleSpecifier, AnyError> {
+ self
+ .main_module_cell
+ .get_or_init(|| {
+ let main_module = match &self.flags.subcommand {
+ DenoSubcommand::Compile(compile_flags) => {
+ resolve_url_or_path(&compile_flags.source_file, self.initial_cwd())?
+ }
+ DenoSubcommand::Eval(_) => {
+ resolve_url_or_path("./$deno$eval.ts", self.initial_cwd())?
+ }
+ DenoSubcommand::Repl(_) => {
+ resolve_url_or_path("./$deno$repl.ts", self.initial_cwd())?
+ }
+ DenoSubcommand::Run(run_flags) => {
+ if run_flags.is_stdin() {
+ resolve_url_or_path("./$deno$stdin.ts", self.initial_cwd())?
+ } else if NpmPackageReqReference::from_str(&run_flags.script)
+ .is_ok()
+ {
+ ModuleSpecifier::parse(&run_flags.script)?
+ } else {
+ resolve_url_or_path(&run_flags.script, self.initial_cwd())?
+ }
+ }
+ DenoSubcommand::Serve(run_flags) => {
+ resolve_url_or_path(&run_flags.script, self.initial_cwd())?
+ }
+ _ => {
+ bail!("No main module.")
+ }
+ };
- Ok(main_module)
+ Ok(main_module)
+ })
+ .as_ref()
+ .map_err(|err| deno_core::anyhow::anyhow!("{}", err))
}
pub fn resolve_file_header_overrides(
@@ -1159,7 +1164,7 @@ impl CliOptions {
(maybe_main_specifier, maybe_content_type)
{
HashMap::from([(
- main_specifier,
+ main_specifier.clone(),
HashMap::from([("content-type".to_string(), content_type.to_string())]),
)])
} else {
@@ -1480,7 +1485,34 @@ impl CliOptions {
}
pub fn permissions_options(&self) -> PermissionsOptions {
- self.flags.permissions.to_options()
+ fn files_to_urls(files: &[String]) -> Vec<Cow<'_, Url>> {
+ files
+ .iter()
+ .filter_map(|f| Url::parse(f).ok().map(Cow::Owned))
+ .collect()
+ }
+
+ // get a list of urls to imply for --allow-import
+ let cli_arg_urls = self
+ .resolve_main_module()
+ .ok()
+ .map(|url| vec![Cow::Borrowed(url)])
+ .or_else(|| match &self.flags.subcommand {
+ DenoSubcommand::Cache(cache_flags) => {
+ Some(files_to_urls(&cache_flags.files))
+ }
+ DenoSubcommand::Check(check_flags) => {
+ Some(files_to_urls(&check_flags.files))
+ }
+ DenoSubcommand::Install(InstallFlags {
+ kind: InstallKind::Global(flags),
+ }) => Url::parse(&flags.module_url)
+ .ok()
+ .map(|url| vec![Cow::Owned(url)]),
+ _ => None,
+ })
+ .unwrap_or_default();
+ self.flags.permissions.to_options(&cli_arg_urls)
}
pub fn reload_flag(&self) -> bool {