mirror of
https://github.com/denoland/deno.git
synced 2024-11-21 15:04:11 -05:00
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>
This commit is contained in:
parent
05415bb9de
commit
5504acea67
507 changed files with 1116 additions and 483 deletions
8
Cargo.lock
generated
8
Cargo.lock
generated
|
@ -1584,9 +1584,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "deno_graph"
|
||||
version = "0.82.2"
|
||||
version = "0.82.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9328b62ffc7e806f1c92fd7a22e4ff3046fcb53f2d46e3e1297482b2c4c2bb9d"
|
||||
checksum = "938ed2efa1dd9fdcceeebc169b2b7910506b8dacc992cfdcffd84aa6a3eb8db0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"async-trait",
|
||||
|
@ -8119,9 +8119,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "webpki-root-certs"
|
||||
version = "0.26.5"
|
||||
version = "0.26.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e6d93b773107ba49bc84dd3b241e019c702d886fd5c457defe2ea8b1123a5dcd"
|
||||
checksum = "e8c6dfa3ac045bc517de14c7b1384298de1dbd229d38e08e169d9ae8c170937c"
|
||||
dependencies = [
|
||||
"rustls-pki-types",
|
||||
]
|
||||
|
|
|
@ -68,7 +68,7 @@ deno_cache_dir = { workspace = true }
|
|||
deno_config = { version = "=0.35.0", features = ["workspace", "sync"] }
|
||||
deno_core = { workspace = true, features = ["include_js_files_for_snapshotting"] }
|
||||
deno_doc = { version = "0.148.0", features = ["html", "syntect"] }
|
||||
deno_graph = { version = "=0.82.2" }
|
||||
deno_graph = { version = "=0.82.3" }
|
||||
deno_lint = { version = "=0.67.0", features = ["docs"] }
|
||||
deno_lockfile.workspace = true
|
||||
deno_npm = "=0.25.2"
|
||||
|
|
|
@ -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 {
|
||||
|
@ -3158,6 +3235,9 @@ fn permission_args(app: Command, requires: Option<&'static str>) -> Command {
|
|||
<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.
|
||||
|
@ -3185,13 +3265,7 @@ fn permission_args(app: Command, requires: Option<&'static str>) -> Command {
|
|||
"#))
|
||||
.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)
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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,7 +1107,10 @@ impl CliOptions {
|
|||
self.flags.env_file.as_ref()
|
||||
}
|
||||
|
||||
pub fn resolve_main_module(&self) -> Result<ModuleSpecifier, AnyError> {
|
||||
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())?
|
||||
|
@ -1118,13 +1123,10 @@ impl CliOptions {
|
|||
}
|
||||
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() {
|
||||
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())?
|
||||
|
@ -1139,6 +1141,9 @@ impl CliOptions {
|
|||
};
|
||||
|
||||
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 {
|
||||
|
|
42
cli/cache/mod.rs
vendored
42
cli/cache/mod.rs
vendored
|
@ -1,10 +1,11 @@
|
|||
// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
|
||||
|
||||
use crate::args::jsr_url;
|
||||
use crate::args::CacheSetting;
|
||||
use crate::errors::get_error_class_name;
|
||||
use crate::file_fetcher::FetchNoFollowOptions;
|
||||
use crate::file_fetcher::FetchOptions;
|
||||
use crate::file_fetcher::FetchPermissionsOption;
|
||||
use crate::file_fetcher::FetchPermissionsOptionRef;
|
||||
use crate::file_fetcher::FileFetcher;
|
||||
use crate::file_fetcher::FileOrRedirect;
|
||||
use crate::npm::CliNpmResolver;
|
||||
|
@ -19,6 +20,7 @@ use deno_graph::source::CacheInfo;
|
|||
use deno_graph::source::LoadFuture;
|
||||
use deno_graph::source::LoadResponse;
|
||||
use deno_graph::source::Loader;
|
||||
use deno_runtime::deno_permissions::PermissionsContainer;
|
||||
use std::collections::HashMap;
|
||||
use std::path::Path;
|
||||
use std::path::PathBuf;
|
||||
|
@ -104,6 +106,13 @@ pub type LocalLspHttpCache =
|
|||
deno_cache_dir::LocalLspHttpCache<RealDenoCacheEnv>;
|
||||
pub use deno_cache_dir::HttpCache;
|
||||
|
||||
pub struct FetchCacherOptions {
|
||||
pub file_header_overrides: HashMap<ModuleSpecifier, HashMap<String, String>>,
|
||||
pub permissions: PermissionsContainer,
|
||||
/// If we're publishing for `deno publish`.
|
||||
pub is_deno_publish: bool,
|
||||
}
|
||||
|
||||
/// A "wrapper" for the FileFetcher and DiskCache for the Deno CLI that provides
|
||||
/// a concise interface to the DENO_DIR when building module graphs.
|
||||
pub struct FetchCacher {
|
||||
|
@ -112,26 +121,27 @@ pub struct FetchCacher {
|
|||
global_http_cache: Arc<GlobalHttpCache>,
|
||||
npm_resolver: Arc<dyn CliNpmResolver>,
|
||||
module_info_cache: Arc<ModuleInfoCache>,
|
||||
permissions: FetchPermissionsOption,
|
||||
permissions: PermissionsContainer,
|
||||
cache_info_enabled: bool,
|
||||
is_deno_publish: bool,
|
||||
}
|
||||
|
||||
impl FetchCacher {
|
||||
pub fn new(
|
||||
file_fetcher: Arc<FileFetcher>,
|
||||
file_header_overrides: HashMap<ModuleSpecifier, HashMap<String, String>>,
|
||||
global_http_cache: Arc<GlobalHttpCache>,
|
||||
npm_resolver: Arc<dyn CliNpmResolver>,
|
||||
module_info_cache: Arc<ModuleInfoCache>,
|
||||
permissions: FetchPermissionsOption,
|
||||
options: FetchCacherOptions,
|
||||
) -> Self {
|
||||
Self {
|
||||
file_fetcher,
|
||||
file_header_overrides,
|
||||
global_http_cache,
|
||||
npm_resolver,
|
||||
module_info_cache,
|
||||
permissions,
|
||||
file_header_overrides: options.file_header_overrides,
|
||||
permissions: options.permissions,
|
||||
is_deno_publish: options.is_deno_publish,
|
||||
cache_info_enabled: false,
|
||||
}
|
||||
}
|
||||
|
@ -208,10 +218,24 @@ impl Loader for FetchCacher {
|
|||
}
|
||||
}
|
||||
|
||||
if self.is_deno_publish
|
||||
&& matches!(specifier.scheme(), "http" | "https")
|
||||
&& !specifier.as_str().starts_with(jsr_url().as_str())
|
||||
{
|
||||
// mark non-JSR remote modules as external so we don't need --allow-import
|
||||
// permissions as these will error out later when publishing
|
||||
return Box::pin(futures::future::ready(Ok(Some(
|
||||
LoadResponse::External {
|
||||
specifier: specifier.clone(),
|
||||
},
|
||||
))));
|
||||
}
|
||||
|
||||
let file_fetcher = self.file_fetcher.clone();
|
||||
let file_header_overrides = self.file_header_overrides.clone();
|
||||
let permissions = self.permissions.clone();
|
||||
let specifier = specifier.clone();
|
||||
let is_statically_analyzable = !options.was_dynamic_root;
|
||||
|
||||
async move {
|
||||
let maybe_cache_setting = match options.cache_setting {
|
||||
|
@ -230,7 +254,11 @@ impl Loader for FetchCacher {
|
|||
.fetch_no_follow_with_options(FetchNoFollowOptions {
|
||||
fetch_options: FetchOptions {
|
||||
specifier: &specifier,
|
||||
permissions: permissions.as_ref(),
|
||||
permissions: if is_statically_analyzable {
|
||||
FetchPermissionsOptionRef::StaticContainer(&permissions)
|
||||
} else {
|
||||
FetchPermissionsOptionRef::DynamicContainer(&permissions)
|
||||
},
|
||||
maybe_accept: None,
|
||||
maybe_cache_setting: maybe_cache_setting.as_ref(),
|
||||
},
|
||||
|
|
|
@ -185,6 +185,7 @@ struct CliFactoryServices {
|
|||
node_resolver: Deferred<Arc<NodeResolver>>,
|
||||
npm_resolver: Deferred<Arc<dyn CliNpmResolver>>,
|
||||
permission_desc_parser: Deferred<Arc<RuntimePermissionDescriptorParser>>,
|
||||
root_permissions_container: Deferred<PermissionsContainer>,
|
||||
sloppy_imports_resolver: Deferred<Option<Arc<SloppyImportsResolver>>>,
|
||||
text_only_progress_bar: Deferred<ProgressBar>,
|
||||
type_checker: Deferred<Arc<TypeChecker>>,
|
||||
|
@ -626,6 +627,7 @@ impl CliFactory {
|
|||
self.maybe_file_watcher_reporter().clone(),
|
||||
self.file_fetcher()?.clone(),
|
||||
self.global_http_cache()?.clone(),
|
||||
self.root_permissions_container()?.clone(),
|
||||
)))
|
||||
})
|
||||
.await
|
||||
|
@ -659,6 +661,7 @@ impl CliFactory {
|
|||
Ok(Arc::new(MainModuleGraphContainer::new(
|
||||
self.cli_options()?.clone(),
|
||||
self.module_load_preparer().await?.clone(),
|
||||
self.root_permissions_container()?.clone(),
|
||||
)))
|
||||
})
|
||||
.await
|
||||
|
@ -755,15 +758,20 @@ impl CliFactory {
|
|||
))
|
||||
}
|
||||
|
||||
pub fn create_permissions_container(
|
||||
pub fn root_permissions_container(
|
||||
&self,
|
||||
) -> Result<PermissionsContainer, AnyError> {
|
||||
) -> Result<&PermissionsContainer, AnyError> {
|
||||
self
|
||||
.services
|
||||
.root_permissions_container
|
||||
.get_or_try_init(|| {
|
||||
let desc_parser = self.permission_desc_parser()?.clone();
|
||||
let permissions = Permissions::from_options(
|
||||
desc_parser.as_ref(),
|
||||
&self.cli_options()?.permissions_options(),
|
||||
)?;
|
||||
Ok(PermissionsContainer::new(desc_parser, permissions))
|
||||
})
|
||||
}
|
||||
|
||||
pub async fn create_cli_main_worker_factory(
|
||||
|
@ -816,6 +824,7 @@ impl CliFactory {
|
|||
npm_resolver.clone(),
|
||||
self.permission_desc_parser()?.clone(),
|
||||
self.root_cert_store_provider().clone(),
|
||||
self.root_permissions_container()?.clone(),
|
||||
StorageKeyResolver::from_options(cli_options),
|
||||
cli_options.sub_command().clone(),
|
||||
self.create_cli_main_worker_options()?,
|
||||
|
|
|
@ -23,6 +23,7 @@ use deno_graph::source::LoaderChecksum;
|
|||
|
||||
use deno_runtime::deno_permissions::PermissionsContainer;
|
||||
use deno_runtime::deno_web::BlobStore;
|
||||
use deno_runtime::fs_util::specifier_to_file_path;
|
||||
use log::debug;
|
||||
use std::borrow::Cow;
|
||||
use std::collections::HashMap;
|
||||
|
@ -135,7 +136,7 @@ impl MemoryFiles {
|
|||
|
||||
/// Fetch a source file from the local file system.
|
||||
fn fetch_local(specifier: &ModuleSpecifier) -> Result<File, AnyError> {
|
||||
let local = specifier.to_file_path().map_err(|_| {
|
||||
let local = specifier_to_file_path(specifier).map_err(|_| {
|
||||
uri_error(format!("Invalid file path.\n Specifier: {specifier}"))
|
||||
})?;
|
||||
// If it doesnt have a extension, we want to treat it as typescript by default
|
||||
|
@ -173,30 +174,8 @@ fn get_validated_scheme(
|
|||
#[derive(Debug, Copy, Clone)]
|
||||
pub enum FetchPermissionsOptionRef<'a> {
|
||||
AllowAll,
|
||||
Container(&'a PermissionsContainer),
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum FetchPermissionsOption {
|
||||
AllowAll,
|
||||
Container(PermissionsContainer),
|
||||
}
|
||||
|
||||
impl FetchPermissionsOption {
|
||||
pub fn as_ref(&self) -> FetchPermissionsOptionRef {
|
||||
match self {
|
||||
FetchPermissionsOption::AllowAll => FetchPermissionsOptionRef::AllowAll,
|
||||
FetchPermissionsOption::Container(container) => {
|
||||
FetchPermissionsOptionRef::Container(container)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<PermissionsContainer> for FetchPermissionsOption {
|
||||
fn from(value: PermissionsContainer) -> Self {
|
||||
Self::Container(value)
|
||||
}
|
||||
DynamicContainer(&'a PermissionsContainer),
|
||||
StaticContainer(&'a PermissionsContainer),
|
||||
}
|
||||
|
||||
pub struct FetchOptions<'a> {
|
||||
|
@ -564,7 +543,6 @@ impl FileFetcher {
|
|||
}
|
||||
|
||||
/// Fetch a source file and asynchronously return it.
|
||||
#[allow(dead_code)] // todo(25469): undo when merging
|
||||
#[inline(always)]
|
||||
pub async fn fetch(
|
||||
&self,
|
||||
|
@ -572,7 +550,10 @@ impl FileFetcher {
|
|||
permissions: &PermissionsContainer,
|
||||
) -> Result<File, AnyError> {
|
||||
self
|
||||
.fetch_inner(specifier, FetchPermissionsOptionRef::Container(permissions))
|
||||
.fetch_inner(
|
||||
specifier,
|
||||
FetchPermissionsOptionRef::StaticContainer(permissions),
|
||||
)
|
||||
.await
|
||||
}
|
||||
|
||||
|
@ -647,8 +628,17 @@ impl FileFetcher {
|
|||
FetchPermissionsOptionRef::AllowAll => {
|
||||
// allow
|
||||
}
|
||||
FetchPermissionsOptionRef::Container(permissions) => {
|
||||
permissions.check_specifier(specifier)?;
|
||||
FetchPermissionsOptionRef::StaticContainer(permissions) => {
|
||||
permissions.check_specifier(
|
||||
specifier,
|
||||
deno_runtime::deno_permissions::CheckSpecifierKind::Static,
|
||||
)?;
|
||||
}
|
||||
FetchPermissionsOptionRef::DynamicContainer(permissions) => {
|
||||
permissions.check_specifier(
|
||||
specifier,
|
||||
deno_runtime::deno_permissions::CheckSpecifierKind::Dynamic,
|
||||
)?;
|
||||
}
|
||||
}
|
||||
if let Some(file) = self.memory_files.get(specifier) {
|
||||
|
|
|
@ -9,9 +9,9 @@ use deno_core::error::AnyError;
|
|||
use deno_core::parking_lot::RwLock;
|
||||
use deno_graph::ModuleGraph;
|
||||
use deno_runtime::colors;
|
||||
use deno_runtime::deno_permissions::PermissionsContainer;
|
||||
|
||||
use crate::args::CliOptions;
|
||||
use crate::file_fetcher::FetchPermissionsOption;
|
||||
use crate::module_loader::ModuleLoadPreparer;
|
||||
use crate::util::fs::collect_specifiers;
|
||||
use crate::util::path::is_script_ext;
|
||||
|
@ -45,12 +45,14 @@ pub struct MainModuleGraphContainer {
|
|||
inner: Arc<RwLock<Arc<ModuleGraph>>>,
|
||||
cli_options: Arc<CliOptions>,
|
||||
module_load_preparer: Arc<ModuleLoadPreparer>,
|
||||
root_permissions: PermissionsContainer,
|
||||
}
|
||||
|
||||
impl MainModuleGraphContainer {
|
||||
pub fn new(
|
||||
cli_options: Arc<CliOptions>,
|
||||
module_load_preparer: Arc<ModuleLoadPreparer>,
|
||||
root_permissions: PermissionsContainer,
|
||||
) -> Self {
|
||||
Self {
|
||||
update_queue: Default::default(),
|
||||
|
@ -59,6 +61,7 @@ impl MainModuleGraphContainer {
|
|||
)))),
|
||||
cli_options,
|
||||
module_load_preparer,
|
||||
root_permissions,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -76,7 +79,7 @@ impl MainModuleGraphContainer {
|
|||
specifiers,
|
||||
false,
|
||||
self.cli_options.ts_type_lib_window(),
|
||||
FetchPermissionsOption::AllowAll,
|
||||
self.root_permissions.clone(),
|
||||
ext_overwrite,
|
||||
)
|
||||
.await?;
|
||||
|
|
|
@ -11,7 +11,6 @@ use crate::cache::ModuleInfoCache;
|
|||
use crate::cache::ParsedSourceCache;
|
||||
use crate::colors;
|
||||
use crate::errors::get_error_class_name;
|
||||
use crate::file_fetcher::FetchPermissionsOption;
|
||||
use crate::file_fetcher::FileFetcher;
|
||||
use crate::npm::CliNpmResolver;
|
||||
use crate::resolver::CliGraphResolver;
|
||||
|
@ -41,6 +40,7 @@ use deno_graph::ResolutionError;
|
|||
use deno_graph::SpecifierError;
|
||||
use deno_runtime::deno_fs::FileSystem;
|
||||
use deno_runtime::deno_node;
|
||||
use deno_runtime::deno_permissions::PermissionsContainer;
|
||||
use deno_runtime::fs_util::specifier_to_file_path;
|
||||
use deno_semver::jsr::JsrDepPackageReq;
|
||||
use deno_semver::package::PackageNv;
|
||||
|
@ -249,6 +249,19 @@ impl ModuleGraphCreator {
|
|||
package_configs: &[JsrPackageConfig],
|
||||
build_fast_check_graph: bool,
|
||||
) -> Result<ModuleGraph, AnyError> {
|
||||
fn graph_has_external_remote(graph: &ModuleGraph) -> bool {
|
||||
// Earlier on, we marked external non-JSR modules as external.
|
||||
// If the graph contains any of those, it would cause type checking
|
||||
// to crash, so since publishing is going to fail anyway, skip type
|
||||
// checking.
|
||||
graph.modules().any(|module| match module {
|
||||
deno_graph::Module::External(external_module) => {
|
||||
matches!(external_module.specifier.scheme(), "http" | "https")
|
||||
}
|
||||
_ => false,
|
||||
})
|
||||
}
|
||||
|
||||
let mut roots = Vec::new();
|
||||
for package_config in package_configs {
|
||||
roots.extend(package_config.config_file.resolve_export_value_urls()?);
|
||||
|
@ -262,9 +275,12 @@ impl ModuleGraphCreator {
|
|||
})
|
||||
.await?;
|
||||
self.graph_valid(&graph)?;
|
||||
if self.options.type_check_mode().is_true() {
|
||||
if self.options.type_check_mode().is_true()
|
||||
&& !graph_has_external_remote(&graph)
|
||||
{
|
||||
self.type_check_graph(graph.clone()).await?;
|
||||
}
|
||||
|
||||
if build_fast_check_graph {
|
||||
let fast_check_workspace_members = package_configs
|
||||
.iter()
|
||||
|
@ -279,6 +295,7 @@ impl ModuleGraphCreator {
|
|||
},
|
||||
)?;
|
||||
}
|
||||
|
||||
Ok(graph)
|
||||
}
|
||||
|
||||
|
@ -370,6 +387,7 @@ pub struct ModuleGraphBuilder {
|
|||
maybe_file_watcher_reporter: Option<FileWatcherReporter>,
|
||||
file_fetcher: Arc<FileFetcher>,
|
||||
global_http_cache: Arc<GlobalHttpCache>,
|
||||
root_permissions_container: PermissionsContainer,
|
||||
}
|
||||
|
||||
impl ModuleGraphBuilder {
|
||||
|
@ -386,6 +404,7 @@ impl ModuleGraphBuilder {
|
|||
maybe_file_watcher_reporter: Option<FileWatcherReporter>,
|
||||
file_fetcher: Arc<FileFetcher>,
|
||||
global_http_cache: Arc<GlobalHttpCache>,
|
||||
root_permissions_container: PermissionsContainer,
|
||||
) -> Self {
|
||||
Self {
|
||||
options,
|
||||
|
@ -399,6 +418,7 @@ impl ModuleGraphBuilder {
|
|||
maybe_file_watcher_reporter,
|
||||
file_fetcher,
|
||||
global_http_cache,
|
||||
root_permissions_container,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -670,20 +690,26 @@ impl ModuleGraphBuilder {
|
|||
|
||||
/// Creates the default loader used for creating a graph.
|
||||
pub fn create_graph_loader(&self) -> cache::FetchCacher {
|
||||
self.create_fetch_cacher(FetchPermissionsOption::AllowAll)
|
||||
self.create_fetch_cacher(self.root_permissions_container.clone())
|
||||
}
|
||||
|
||||
pub fn create_fetch_cacher(
|
||||
&self,
|
||||
permissions: FetchPermissionsOption,
|
||||
permissions: PermissionsContainer,
|
||||
) -> cache::FetchCacher {
|
||||
cache::FetchCacher::new(
|
||||
self.file_fetcher.clone(),
|
||||
self.options.resolve_file_header_overrides(),
|
||||
self.global_http_cache.clone(),
|
||||
self.npm_resolver.clone(),
|
||||
self.module_info_cache.clone(),
|
||||
cache::FetchCacherOptions {
|
||||
file_header_overrides: self.options.resolve_file_header_overrides(),
|
||||
permissions,
|
||||
is_deno_publish: matches!(
|
||||
self.options.sub_command(),
|
||||
crate::args::DenoSubcommand::Publish { .. }
|
||||
),
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
@ -3614,6 +3614,11 @@ impl Inner {
|
|||
}),
|
||||
// bit of a hack to force the lsp to cache the @types/node package
|
||||
type_check_mode: crate::args::TypeCheckMode::Local,
|
||||
permissions: crate::args::PermissionFlags {
|
||||
// allow remote import permissions in the lsp for now
|
||||
allow_import: Some(vec![]),
|
||||
..Default::default()
|
||||
},
|
||||
..Default::default()
|
||||
}),
|
||||
initial_cwd,
|
||||
|
|
|
@ -104,7 +104,7 @@ impl ModuleLoadPreparer {
|
|||
roots: &[ModuleSpecifier],
|
||||
is_dynamic: bool,
|
||||
lib: TsTypeLib,
|
||||
permissions: crate::file_fetcher::FetchPermissionsOption,
|
||||
permissions: PermissionsContainer,
|
||||
ext_overwrite: Option<&String>,
|
||||
) -> Result<(), AnyError> {
|
||||
log::debug!("Preparing module load.");
|
||||
|
@ -252,13 +252,15 @@ impl CliModuleLoaderFactory {
|
|||
&self,
|
||||
graph_container: TGraphContainer,
|
||||
lib: TsTypeLib,
|
||||
root_permissions: PermissionsContainer,
|
||||
dynamic_permissions: PermissionsContainer,
|
||||
is_worker: bool,
|
||||
parent_permissions: PermissionsContainer,
|
||||
permissions: PermissionsContainer,
|
||||
) -> ModuleLoaderAndSourceMapGetter {
|
||||
let loader = Rc::new(CliModuleLoader(Rc::new(CliModuleLoaderInner {
|
||||
lib,
|
||||
root_permissions,
|
||||
dynamic_permissions,
|
||||
is_worker,
|
||||
parent_permissions,
|
||||
permissions,
|
||||
graph_container,
|
||||
emitter: self.shared.emitter.clone(),
|
||||
parsed_source_cache: self.shared.parsed_source_cache.clone(),
|
||||
|
@ -274,20 +276,20 @@ impl ModuleLoaderFactory for CliModuleLoaderFactory {
|
|||
fn create_for_main(
|
||||
&self,
|
||||
root_permissions: PermissionsContainer,
|
||||
dynamic_permissions: PermissionsContainer,
|
||||
) -> ModuleLoaderAndSourceMapGetter {
|
||||
self.create_with_lib(
|
||||
(*self.shared.main_module_graph_container).clone(),
|
||||
self.shared.lib_window,
|
||||
/* is worker */ false,
|
||||
root_permissions.clone(),
|
||||
root_permissions,
|
||||
dynamic_permissions,
|
||||
)
|
||||
}
|
||||
|
||||
fn create_for_worker(
|
||||
&self,
|
||||
root_permissions: PermissionsContainer,
|
||||
dynamic_permissions: PermissionsContainer,
|
||||
parent_permissions: PermissionsContainer,
|
||||
permissions: PermissionsContainer,
|
||||
) -> ModuleLoaderAndSourceMapGetter {
|
||||
self.create_with_lib(
|
||||
// create a fresh module graph for the worker
|
||||
|
@ -295,21 +297,21 @@ impl ModuleLoaderFactory for CliModuleLoaderFactory {
|
|||
self.shared.graph_kind,
|
||||
))),
|
||||
self.shared.lib_worker,
|
||||
root_permissions,
|
||||
dynamic_permissions,
|
||||
/* is worker */ true,
|
||||
parent_permissions,
|
||||
permissions,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
struct CliModuleLoaderInner<TGraphContainer: ModuleGraphContainer> {
|
||||
lib: TsTypeLib,
|
||||
is_worker: bool,
|
||||
/// The initial set of permissions used to resolve the static imports in the
|
||||
/// worker. These are "allow all" for main worker, and parent thread
|
||||
/// permissions for Web Worker.
|
||||
root_permissions: PermissionsContainer,
|
||||
/// Permissions used to resolve dynamic imports, these get passed as
|
||||
/// "root permissions" for Web Worker.
|
||||
dynamic_permissions: PermissionsContainer,
|
||||
parent_permissions: PermissionsContainer,
|
||||
permissions: PermissionsContainer,
|
||||
shared: Arc<SharedCliModuleLoaderState>,
|
||||
emitter: Arc<Emitter>,
|
||||
parsed_source_cache: Arc<ParsedSourceCache>,
|
||||
|
@ -769,11 +771,12 @@ impl<TGraphContainer: ModuleGraphContainer> ModuleLoader
|
|||
}
|
||||
}
|
||||
|
||||
let root_permissions = if is_dynamic {
|
||||
inner.dynamic_permissions.clone()
|
||||
let permissions = if is_dynamic {
|
||||
inner.permissions.clone()
|
||||
} else {
|
||||
inner.root_permissions.clone()
|
||||
inner.parent_permissions.clone()
|
||||
};
|
||||
let is_dynamic = is_dynamic || inner.is_worker; // consider workers as dynamic for permissions
|
||||
let lib = inner.lib;
|
||||
let mut update_permit = graph_container.acquire_update_permit().await;
|
||||
let graph = update_permit.graph_mut();
|
||||
|
@ -783,7 +786,7 @@ impl<TGraphContainer: ModuleGraphContainer> ModuleLoader
|
|||
&[specifier],
|
||||
is_dynamic,
|
||||
lib,
|
||||
root_permissions.into(),
|
||||
permissions,
|
||||
None,
|
||||
)
|
||||
.await?;
|
||||
|
|
|
@ -130,8 +130,6 @@ struct SharedModuleLoaderState {
|
|||
#[derive(Clone)]
|
||||
struct EmbeddedModuleLoader {
|
||||
shared: Arc<SharedModuleLoaderState>,
|
||||
root_permissions: PermissionsContainer,
|
||||
dynamic_permissions: PermissionsContainer,
|
||||
}
|
||||
|
||||
pub const MODULE_NOT_FOUND: &str = "Module not found";
|
||||
|
@ -402,28 +400,23 @@ struct StandaloneModuleLoaderFactory {
|
|||
impl ModuleLoaderFactory for StandaloneModuleLoaderFactory {
|
||||
fn create_for_main(
|
||||
&self,
|
||||
root_permissions: PermissionsContainer,
|
||||
dynamic_permissions: PermissionsContainer,
|
||||
_root_permissions: PermissionsContainer,
|
||||
) -> ModuleLoaderAndSourceMapGetter {
|
||||
ModuleLoaderAndSourceMapGetter {
|
||||
module_loader: Rc::new(EmbeddedModuleLoader {
|
||||
shared: self.shared.clone(),
|
||||
root_permissions,
|
||||
dynamic_permissions,
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
fn create_for_worker(
|
||||
&self,
|
||||
root_permissions: PermissionsContainer,
|
||||
dynamic_permissions: PermissionsContainer,
|
||||
_parent_permissions: PermissionsContainer,
|
||||
_permissions: PermissionsContainer,
|
||||
) -> ModuleLoaderAndSourceMapGetter {
|
||||
ModuleLoaderAndSourceMapGetter {
|
||||
module_loader: Rc::new(EmbeddedModuleLoader {
|
||||
shared: self.shared.clone(),
|
||||
root_permissions,
|
||||
dynamic_permissions,
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
@ -664,7 +657,8 @@ pub async fn run(
|
|||
};
|
||||
|
||||
let permissions = {
|
||||
let mut permissions = metadata.permissions.to_options();
|
||||
let mut permissions =
|
||||
metadata.permissions.to_options(/* cli_arg_urls */ &[]);
|
||||
// if running with an npm vfs, grant read access to it
|
||||
if let Some(vfs_root) = maybe_vfs_root {
|
||||
match &mut permissions.allow_read {
|
||||
|
@ -713,6 +707,7 @@ pub async fn run(
|
|||
npm_resolver,
|
||||
permission_desc_parser,
|
||||
root_cert_store_provider,
|
||||
permissions,
|
||||
StorageKeyResolver::empty(),
|
||||
crate::args::DenoSubcommand::Run(Default::default()),
|
||||
CliMainWorkerOptions {
|
||||
|
@ -752,7 +747,7 @@ pub async fn run(
|
|||
deno_core::JsRuntime::init_platform(None, true);
|
||||
|
||||
let mut worker = worker_factory
|
||||
.create_main_worker(WorkerExecutionMode::Run, main_module, permissions)
|
||||
.create_main_worker(WorkerExecutionMode::Run, main_module)
|
||||
.await?;
|
||||
|
||||
let exit_code = worker.run().await?;
|
||||
|
|
|
@ -51,6 +51,7 @@ pub async fn check(
|
|||
|
||||
let specifiers_for_typecheck = if check_flags.doc || check_flags.doc_only {
|
||||
let file_fetcher = factory.file_fetcher()?;
|
||||
let root_permissions = factory.root_permissions_container()?;
|
||||
|
||||
let mut specifiers_for_typecheck = if check_flags.doc {
|
||||
specifiers.clone()
|
||||
|
@ -59,7 +60,7 @@ pub async fn check(
|
|||
};
|
||||
|
||||
for s in specifiers {
|
||||
let file = file_fetcher.fetch_bypass_permissions(&s).await?;
|
||||
let file = file_fetcher.fetch(&s, root_permissions).await?;
|
||||
let snippet_files = extract::extract_snippet_files(file)?;
|
||||
for snippet_file in snippet_files {
|
||||
specifiers_for_typecheck.push(snippet_file.specifier.clone());
|
||||
|
|
|
@ -135,7 +135,7 @@ pub async fn compile(
|
|||
file,
|
||||
eszip,
|
||||
root_dir_url,
|
||||
&module_specifier,
|
||||
module_specifier,
|
||||
&compile_flags,
|
||||
cli_options,
|
||||
)
|
||||
|
|
|
@ -644,8 +644,21 @@ impl<'a> GraphDisplayContext<'a> {
|
|||
ModuleError::InvalidTypeAssertion { .. } => {
|
||||
self.build_error_msg(specifier, "(invalid import attribute)")
|
||||
}
|
||||
ModuleError::LoadingErr(_, _, _) => {
|
||||
self.build_error_msg(specifier, "(loading error)")
|
||||
ModuleError::LoadingErr(_, _, err) => {
|
||||
use deno_graph::ModuleLoadError::*;
|
||||
let message = match err {
|
||||
HttpsChecksumIntegrity(_) => "(checksum integrity error)",
|
||||
Decode(_) => "(loading decode error)",
|
||||
Loader(err) => match deno_core::error::get_custom_error_class(err) {
|
||||
Some("NotCapable") => "(not capable, requires --allow-import)",
|
||||
_ => "(loading error)",
|
||||
},
|
||||
Jsr(_) => "(loading error)",
|
||||
NodeUnknownBuiltinModule(_) => "(unknown node built-in error)",
|
||||
Npm(_) => "(npm loading error)",
|
||||
TooManyRedirects => "(too many redirects error)",
|
||||
};
|
||||
self.build_error_msg(specifier, message.as_ref())
|
||||
}
|
||||
ModuleError::ParseErr(_, _) => {
|
||||
self.build_error_msg(specifier, "(parsing error)")
|
||||
|
|
|
@ -3,7 +3,6 @@
|
|||
use std::borrow::Cow;
|
||||
use std::path::PathBuf;
|
||||
use std::sync::Arc;
|
||||
use std::sync::Mutex;
|
||||
|
||||
use deno_ast::diagnostics::Diagnostic;
|
||||
use deno_ast::diagnostics::DiagnosticLevel;
|
||||
|
@ -21,6 +20,7 @@ use deno_ast::SourceRanged;
|
|||
use deno_ast::SourceTextInfo;
|
||||
use deno_core::anyhow::anyhow;
|
||||
use deno_core::error::AnyError;
|
||||
use deno_core::parking_lot::Mutex;
|
||||
use deno_core::url::Url;
|
||||
use deno_graph::FastCheckDiagnostic;
|
||||
use deno_semver::Version;
|
||||
|
@ -36,7 +36,7 @@ impl PublishDiagnosticsCollector {
|
|||
pub fn print_and_error(&self) -> Result<(), AnyError> {
|
||||
let mut errors = 0;
|
||||
let mut has_slow_types_errors = false;
|
||||
let mut diagnostics = self.diagnostics.lock().unwrap().take();
|
||||
let mut diagnostics = self.diagnostics.lock().take();
|
||||
|
||||
diagnostics.sort_by_cached_key(|d| d.sorting_key());
|
||||
|
||||
|
@ -75,8 +75,16 @@ impl PublishDiagnosticsCollector {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn has_error(&self) -> bool {
|
||||
self
|
||||
.diagnostics
|
||||
.lock()
|
||||
.iter()
|
||||
.any(|d| matches!(d.level(), DiagnosticLevel::Error))
|
||||
}
|
||||
|
||||
pub fn push(&self, diagnostic: PublishDiagnostic) {
|
||||
self.diagnostics.lock().unwrap().push(diagnostic);
|
||||
self.diagnostics.lock().push(diagnostic);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -341,13 +341,11 @@ impl PublishPreparer {
|
|||
bail!("Exiting due to DENO_INTERNAL_FAST_CHECK_OVERWRITE")
|
||||
} else {
|
||||
log::info!("Checking for slow types in the public API...");
|
||||
let mut any_pkg_had_diagnostics = false;
|
||||
for package in package_configs {
|
||||
let export_urls = package.config_file.resolve_export_value_urls()?;
|
||||
let diagnostics =
|
||||
collect_no_slow_type_diagnostics(&graph, &export_urls);
|
||||
if !diagnostics.is_empty() {
|
||||
any_pkg_had_diagnostics = true;
|
||||
for diagnostic in diagnostics {
|
||||
diagnostics_collector
|
||||
.push(PublishDiagnostic::FastCheck(diagnostic));
|
||||
|
@ -355,7 +353,9 @@ impl PublishPreparer {
|
|||
}
|
||||
}
|
||||
|
||||
if any_pkg_had_diagnostics {
|
||||
// skip type checking the slow type graph if there are any errors because
|
||||
// errors like remote modules existing will cause type checking to crash
|
||||
if diagnostics_collector.has_error() {
|
||||
Ok(Arc::new(graph))
|
||||
} else {
|
||||
// fast check passed, type check the output as a temporary measure
|
||||
|
|
|
@ -16,6 +16,7 @@ pub async fn cache_top_level_deps(
|
|||
) -> Result<(), AnyError> {
|
||||
let npm_resolver = factory.npm_resolver().await?;
|
||||
let cli_options = factory.cli_options()?;
|
||||
let root_permissions = factory.root_permissions_container()?;
|
||||
if let Some(npm_resolver) = npm_resolver.as_managed() {
|
||||
if !npm_resolver.ensure_top_level_package_json_install().await? {
|
||||
if let Some(lockfile) = cli_options.maybe_lockfile() {
|
||||
|
@ -106,7 +107,7 @@ pub async fn cache_top_level_deps(
|
|||
&roots,
|
||||
false,
|
||||
deno_config::deno_json::TsTypeLib::DenoWorker,
|
||||
crate::file_fetcher::FetchPermissionsOption::AllowAll,
|
||||
root_permissions.clone(),
|
||||
None,
|
||||
)
|
||||
.await?;
|
||||
|
|
|
@ -162,7 +162,7 @@ pub async fn run(
|
|||
let factory = CliFactory::from_flags(flags);
|
||||
let cli_options = factory.cli_options()?;
|
||||
let main_module = cli_options.resolve_main_module()?;
|
||||
let permissions = factory.create_permissions_container()?;
|
||||
let permissions = factory.root_permissions_container()?;
|
||||
let npm_resolver = factory.npm_resolver().await?.clone();
|
||||
let resolver = factory.resolver().await?.clone();
|
||||
let file_fetcher = factory.file_fetcher()?;
|
||||
|
@ -177,7 +177,7 @@ pub async fn run(
|
|||
.create_custom_worker(
|
||||
WorkerExecutionMode::Repl,
|
||||
main_module.clone(),
|
||||
permissions,
|
||||
permissions.clone(),
|
||||
vec![crate::ops::testing::deno_test::init_ops(test_event_sender)],
|
||||
Default::default(),
|
||||
)
|
||||
|
@ -189,7 +189,7 @@ pub async fn run(
|
|||
npm_resolver,
|
||||
resolver,
|
||||
worker,
|
||||
main_module,
|
||||
main_module.clone(),
|
||||
test_event_receiver,
|
||||
)
|
||||
.await?;
|
||||
|
|
|
@ -60,10 +60,9 @@ pub async fn run_script(
|
|||
|
||||
maybe_npm_install(&factory).await?;
|
||||
|
||||
let permissions = factory.create_permissions_container()?;
|
||||
let worker_factory = factory.create_cli_main_worker_factory().await?;
|
||||
let mut worker = worker_factory
|
||||
.create_main_worker(mode, main_module, permissions)
|
||||
.create_main_worker(mode, main_module.clone())
|
||||
.await?;
|
||||
|
||||
let exit_code = worker.run().await?;
|
||||
|
@ -79,7 +78,6 @@ pub async fn run_from_stdin(flags: Arc<Flags>) -> Result<i32, AnyError> {
|
|||
|
||||
let file_fetcher = factory.file_fetcher()?;
|
||||
let worker_factory = factory.create_cli_main_worker_factory().await?;
|
||||
let permissions = factory.create_permissions_container()?;
|
||||
let mut source = Vec::new();
|
||||
std::io::stdin().read_to_end(&mut source)?;
|
||||
// Save a fake file into file fetcher cache
|
||||
|
@ -91,7 +89,7 @@ pub async fn run_from_stdin(flags: Arc<Flags>) -> Result<i32, AnyError> {
|
|||
});
|
||||
|
||||
let mut worker = worker_factory
|
||||
.create_main_worker(WorkerExecutionMode::Run, main_module, permissions)
|
||||
.create_main_worker(WorkerExecutionMode::Run, main_module.clone())
|
||||
.await?;
|
||||
let exit_code = worker.run().await?;
|
||||
Ok(exit_code)
|
||||
|
@ -125,11 +123,10 @@ async fn run_with_watch(
|
|||
|
||||
let _ = watcher_communicator.watch_paths(cli_options.watch_paths());
|
||||
|
||||
let permissions = factory.create_permissions_container()?;
|
||||
let mut worker = factory
|
||||
.create_cli_main_worker_factory()
|
||||
.await?
|
||||
.create_main_worker(mode, main_module, permissions)
|
||||
.create_main_worker(mode, main_module.clone())
|
||||
.await?;
|
||||
|
||||
if watch_flags.hmr {
|
||||
|
@ -173,10 +170,9 @@ pub async fn eval_command(
|
|||
source: source_code.into_bytes().into(),
|
||||
});
|
||||
|
||||
let permissions = factory.create_permissions_container()?;
|
||||
let worker_factory = factory.create_cli_main_worker_factory().await?;
|
||||
let mut worker = worker_factory
|
||||
.create_main_worker(WorkerExecutionMode::Eval, main_module, permissions)
|
||||
.create_main_worker(WorkerExecutionMode::Eval, main_module.clone())
|
||||
.await?;
|
||||
let exit_code = worker.run().await?;
|
||||
Ok(exit_code)
|
||||
|
|
|
@ -5,7 +5,6 @@ use std::sync::Arc;
|
|||
use deno_core::error::AnyError;
|
||||
use deno_core::futures::TryFutureExt;
|
||||
use deno_core::ModuleSpecifier;
|
||||
use deno_runtime::deno_permissions::PermissionsContainer;
|
||||
|
||||
use super::run::check_permission_before_script;
|
||||
use super::run::maybe_npm_install;
|
||||
|
@ -44,13 +43,11 @@ pub async fn serve(
|
|||
|
||||
maybe_npm_install(&factory).await?;
|
||||
|
||||
let permissions = factory.create_permissions_container()?;
|
||||
let worker_factory = factory.create_cli_main_worker_factory().await?;
|
||||
|
||||
do_serve(
|
||||
worker_factory,
|
||||
main_module,
|
||||
permissions,
|
||||
main_module.clone(),
|
||||
serve_flags.worker_count,
|
||||
false,
|
||||
)
|
||||
|
@ -60,7 +57,6 @@ pub async fn serve(
|
|||
async fn do_serve(
|
||||
worker_factory: CliMainWorkerFactory,
|
||||
main_module: ModuleSpecifier,
|
||||
permissions: PermissionsContainer,
|
||||
worker_count: Option<usize>,
|
||||
hmr: bool,
|
||||
) -> Result<i32, AnyError> {
|
||||
|
@ -71,7 +67,6 @@ async fn do_serve(
|
|||
worker_count,
|
||||
},
|
||||
main_module.clone(),
|
||||
permissions.clone(),
|
||||
)
|
||||
.await?;
|
||||
let worker_count = match worker_count {
|
||||
|
@ -87,15 +82,13 @@ async fn do_serve(
|
|||
for i in 0..extra_workers {
|
||||
let worker_factory = worker_factory.clone();
|
||||
let main_module = main_module.clone();
|
||||
let permissions = permissions.clone();
|
||||
let (tx, rx) = tokio::sync::oneshot::channel();
|
||||
channels.push(rx);
|
||||
std::thread::Builder::new()
|
||||
.name(format!("serve-worker-{i}"))
|
||||
.spawn(move || {
|
||||
deno_runtime::tokio_util::create_and_run_current_thread(async move {
|
||||
let result =
|
||||
run_worker(i, worker_factory, main_module, permissions, hmr).await;
|
||||
let result = run_worker(i, worker_factory, main_module, hmr).await;
|
||||
let _ = tx.send(result);
|
||||
});
|
||||
})?;
|
||||
|
@ -124,7 +117,6 @@ async fn run_worker(
|
|||
worker_count: usize,
|
||||
worker_factory: CliMainWorkerFactory,
|
||||
main_module: ModuleSpecifier,
|
||||
permissions: PermissionsContainer,
|
||||
hmr: bool,
|
||||
) -> Result<i32, AnyError> {
|
||||
let mut worker = worker_factory
|
||||
|
@ -134,7 +126,6 @@ async fn run_worker(
|
|||
worker_count: Some(worker_count),
|
||||
},
|
||||
main_module,
|
||||
permissions,
|
||||
)
|
||||
.await?;
|
||||
if hmr {
|
||||
|
@ -171,11 +162,9 @@ async fn serve_with_watch(
|
|||
maybe_npm_install(&factory).await?;
|
||||
|
||||
let _ = watcher_communicator.watch_paths(cli_options.watch_paths());
|
||||
|
||||
let permissions = factory.create_permissions_container()?;
|
||||
let worker_factory = factory.create_cli_main_worker_factory().await?;
|
||||
|
||||
do_serve(worker_factory, main_module, permissions, worker_count, hmr)
|
||||
do_serve(worker_factory, main_module.clone(), worker_count, hmr)
|
||||
.await?;
|
||||
|
||||
Ok(())
|
||||
|
|
|
@ -62,13 +62,12 @@ pub trait ModuleLoaderFactory: Send + Sync {
|
|||
fn create_for_main(
|
||||
&self,
|
||||
root_permissions: PermissionsContainer,
|
||||
dynamic_permissions: PermissionsContainer,
|
||||
) -> ModuleLoaderAndSourceMapGetter;
|
||||
|
||||
fn create_for_worker(
|
||||
&self,
|
||||
root_permissions: PermissionsContainer,
|
||||
dynamic_permissions: PermissionsContainer,
|
||||
parent_permissions: PermissionsContainer,
|
||||
permissions: PermissionsContainer,
|
||||
) -> ModuleLoaderAndSourceMapGetter;
|
||||
}
|
||||
|
||||
|
@ -136,6 +135,7 @@ struct SharedWorkerState {
|
|||
npm_resolver: Arc<dyn CliNpmResolver>,
|
||||
permission_desc_parser: Arc<RuntimePermissionDescriptorParser>,
|
||||
root_cert_store_provider: Arc<dyn RootCertStoreProvider>,
|
||||
root_permissions: PermissionsContainer,
|
||||
shared_array_buffer_store: SharedArrayBufferStore,
|
||||
storage_key_resolver: StorageKeyResolver,
|
||||
options: CliMainWorkerOptions,
|
||||
|
@ -432,6 +432,7 @@ impl CliMainWorkerFactory {
|
|||
npm_resolver: Arc<dyn CliNpmResolver>,
|
||||
permission_parser: Arc<RuntimePermissionDescriptorParser>,
|
||||
root_cert_store_provider: Arc<dyn RootCertStoreProvider>,
|
||||
root_permissions: PermissionsContainer,
|
||||
storage_key_resolver: StorageKeyResolver,
|
||||
subcommand: DenoSubcommand,
|
||||
options: CliMainWorkerOptions,
|
||||
|
@ -452,6 +453,7 @@ impl CliMainWorkerFactory {
|
|||
npm_resolver,
|
||||
permission_desc_parser: permission_parser,
|
||||
root_cert_store_provider,
|
||||
root_permissions,
|
||||
shared_array_buffer_store: Default::default(),
|
||||
storage_key_resolver,
|
||||
options,
|
||||
|
@ -464,13 +466,12 @@ impl CliMainWorkerFactory {
|
|||
&self,
|
||||
mode: WorkerExecutionMode,
|
||||
main_module: ModuleSpecifier,
|
||||
permissions: PermissionsContainer,
|
||||
) -> Result<CliMainWorker, AnyError> {
|
||||
self
|
||||
.create_custom_worker(
|
||||
mode,
|
||||
main_module,
|
||||
permissions,
|
||||
self.shared.root_permissions.clone(),
|
||||
vec![],
|
||||
Default::default(),
|
||||
)
|
||||
|
@ -530,13 +531,9 @@ impl CliMainWorkerFactory {
|
|||
(main_module, is_cjs)
|
||||
};
|
||||
|
||||
let ModuleLoaderAndSourceMapGetter { module_loader } =
|
||||
shared.module_loader_factory.create_for_main(
|
||||
PermissionsContainer::allow_all(
|
||||
self.shared.permission_desc_parser.clone(),
|
||||
),
|
||||
permissions.clone(),
|
||||
);
|
||||
let ModuleLoaderAndSourceMapGetter { module_loader } = shared
|
||||
.module_loader_factory
|
||||
.create_for_main(permissions.clone());
|
||||
let maybe_inspector_server = shared.maybe_inspector_server.clone();
|
||||
|
||||
let create_web_worker_cb =
|
||||
|
|
|
@ -12,6 +12,7 @@ use deno_permissions::AllowRunDescriptorParseResult;
|
|||
use deno_permissions::DenyRunDescriptor;
|
||||
use deno_permissions::EnvDescriptor;
|
||||
use deno_permissions::FfiDescriptor;
|
||||
use deno_permissions::ImportDescriptor;
|
||||
use deno_permissions::NetDescriptor;
|
||||
use deno_permissions::PathQueryDescriptor;
|
||||
use deno_permissions::ReadDescriptor;
|
||||
|
@ -75,6 +76,13 @@ impl deno_permissions::PermissionDescriptorParser
|
|||
NetDescriptor::parse(text)
|
||||
}
|
||||
|
||||
fn parse_import_descriptor(
|
||||
&self,
|
||||
text: &str,
|
||||
) -> Result<ImportDescriptor, AnyError> {
|
||||
ImportDescriptor::parse(text)
|
||||
}
|
||||
|
||||
fn parse_env_descriptor(
|
||||
&self,
|
||||
text: &str,
|
||||
|
|
|
@ -14,7 +14,6 @@ use deno_core::serde::Deserializer;
|
|||
use deno_core::serde::Serialize;
|
||||
use deno_core::serde_json;
|
||||
use deno_core::unsync::sync::AtomicFlag;
|
||||
use deno_core::url;
|
||||
use deno_core::url::Url;
|
||||
use deno_core::ModuleSpecifier;
|
||||
use deno_terminal::colors;
|
||||
|
@ -950,6 +949,15 @@ impl NetDescriptor {
|
|||
|
||||
Ok(NetDescriptor(host, port))
|
||||
}
|
||||
|
||||
pub fn from_url(url: &Url) -> Result<Self, AnyError> {
|
||||
let host = url
|
||||
.host_str()
|
||||
.ok_or_else(|| type_error(format!("Missing host in url: '{}'", url)))?;
|
||||
let host = Host::parse(host)?;
|
||||
let port = url.port_or_known_default();
|
||||
Ok(NetDescriptor(host, port))
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for NetDescriptor {
|
||||
|
@ -966,6 +974,73 @@ impl fmt::Display for NetDescriptor {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Eq, PartialEq, Hash, Debug)]
|
||||
pub struct ImportDescriptor(NetDescriptor);
|
||||
|
||||
impl QueryDescriptor for ImportDescriptor {
|
||||
type AllowDesc = ImportDescriptor;
|
||||
type DenyDesc = ImportDescriptor;
|
||||
|
||||
fn flag_name() -> &'static str {
|
||||
"import"
|
||||
}
|
||||
|
||||
fn display_name(&self) -> Cow<str> {
|
||||
self.0.display_name()
|
||||
}
|
||||
|
||||
fn from_allow(allow: &Self::AllowDesc) -> Self {
|
||||
Self(NetDescriptor::from_allow(&allow.0))
|
||||
}
|
||||
|
||||
fn as_allow(&self) -> Option<Self::AllowDesc> {
|
||||
self.0.as_allow().map(ImportDescriptor)
|
||||
}
|
||||
|
||||
fn as_deny(&self) -> Self::DenyDesc {
|
||||
Self(self.0.as_deny())
|
||||
}
|
||||
|
||||
fn check_in_permission(
|
||||
&self,
|
||||
perm: &mut UnaryPermission<Self>,
|
||||
api_name: Option<&str>,
|
||||
) -> Result<(), AnyError> {
|
||||
skip_check_if_is_permission_fully_granted!(perm);
|
||||
perm.check_desc(Some(self), false, api_name)
|
||||
}
|
||||
|
||||
fn matches_allow(&self, other: &Self::AllowDesc) -> bool {
|
||||
self.0.matches_allow(&other.0)
|
||||
}
|
||||
|
||||
fn matches_deny(&self, other: &Self::DenyDesc) -> bool {
|
||||
self.0.matches_deny(&other.0)
|
||||
}
|
||||
|
||||
fn revokes(&self, other: &Self::AllowDesc) -> bool {
|
||||
self.0.revokes(&other.0)
|
||||
}
|
||||
|
||||
fn stronger_than_deny(&self, other: &Self::DenyDesc) -> bool {
|
||||
self.0.stronger_than_deny(&other.0)
|
||||
}
|
||||
|
||||
fn overlaps_deny(&self, other: &Self::DenyDesc) -> bool {
|
||||
self.0.overlaps_deny(&other.0)
|
||||
}
|
||||
}
|
||||
|
||||
impl ImportDescriptor {
|
||||
pub fn parse(specifier: &str) -> Result<Self, AnyError> {
|
||||
Ok(ImportDescriptor(NetDescriptor::parse(specifier)?))
|
||||
}
|
||||
|
||||
pub fn from_url(url: &Url) -> Result<Self, AnyError> {
|
||||
Ok(ImportDescriptor(NetDescriptor::from_url(url)?))
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Eq, PartialEq, Hash, Debug)]
|
||||
pub struct EnvDescriptor(EnvVarName);
|
||||
|
||||
|
@ -1519,19 +1594,35 @@ impl UnaryPermission<NetDescriptor> {
|
|||
self.check_desc(Some(host), false, api_name)
|
||||
}
|
||||
|
||||
pub fn check_url(
|
||||
pub fn check_all(&mut self) -> Result<(), AnyError> {
|
||||
skip_check_if_is_permission_fully_granted!(self);
|
||||
self.check_desc(None, false, None)
|
||||
}
|
||||
}
|
||||
|
||||
impl UnaryPermission<ImportDescriptor> {
|
||||
pub fn query(&self, host: Option<&ImportDescriptor>) -> PermissionState {
|
||||
self.query_desc(host, AllowPartial::TreatAsPartialGranted)
|
||||
}
|
||||
|
||||
pub fn request(
|
||||
&mut self,
|
||||
url: &url::Url,
|
||||
host: Option<&ImportDescriptor>,
|
||||
) -> PermissionState {
|
||||
self.request_desc(host)
|
||||
}
|
||||
|
||||
pub fn revoke(&mut self, host: Option<&ImportDescriptor>) -> PermissionState {
|
||||
self.revoke_desc(host)
|
||||
}
|
||||
|
||||
pub fn check(
|
||||
&mut self,
|
||||
host: &ImportDescriptor,
|
||||
api_name: Option<&str>,
|
||||
) -> Result<(), AnyError> {
|
||||
skip_check_if_is_permission_fully_granted!(self);
|
||||
let host = url
|
||||
.host_str()
|
||||
.ok_or_else(|| type_error(format!("Missing host in url: '{}'", url)))?;
|
||||
let host = Host::parse(host)?;
|
||||
let port = url.port_or_known_default();
|
||||
let descriptor = NetDescriptor(host, port);
|
||||
self.check_desc(Some(&descriptor), false, api_name)
|
||||
self.check_desc(Some(host), false, api_name)
|
||||
}
|
||||
|
||||
pub fn check_all(&mut self) -> Result<(), AnyError> {
|
||||
|
@ -1700,6 +1791,7 @@ pub struct Permissions {
|
|||
pub sys: UnaryPermission<SysDescriptor>,
|
||||
pub run: UnaryPermission<RunQueryDescriptor>,
|
||||
pub ffi: UnaryPermission<FfiQueryDescriptor>,
|
||||
pub import: UnaryPermission<ImportDescriptor>,
|
||||
pub all: UnitPermission,
|
||||
}
|
||||
|
||||
|
@ -1720,6 +1812,7 @@ pub struct PermissionsOptions {
|
|||
pub deny_sys: Option<Vec<String>>,
|
||||
pub allow_write: Option<Vec<String>>,
|
||||
pub deny_write: Option<Vec<String>>,
|
||||
pub allow_import: Option<Vec<String>>,
|
||||
pub prompt: bool,
|
||||
}
|
||||
|
||||
|
@ -1888,6 +1981,13 @@ impl Permissions {
|
|||
})?,
|
||||
opts.prompt,
|
||||
)?,
|
||||
import: Permissions::new_unary(
|
||||
parse_maybe_vec(opts.allow_import.as_deref(), |item| {
|
||||
parser.parse_import_descriptor(item)
|
||||
})?,
|
||||
None,
|
||||
opts.prompt,
|
||||
)?,
|
||||
all: Permissions::new_all(opts.allow_all),
|
||||
})
|
||||
}
|
||||
|
@ -1902,6 +2002,7 @@ impl Permissions {
|
|||
sys: UnaryPermission::allow_all(),
|
||||
run: UnaryPermission::allow_all(),
|
||||
ffi: UnaryPermission::allow_all(),
|
||||
import: UnaryPermission::allow_all(),
|
||||
all: Permissions::new_all(true),
|
||||
}
|
||||
}
|
||||
|
@ -1925,35 +2026,10 @@ impl Permissions {
|
|||
sys: Permissions::new_unary(None, None, prompt).unwrap(),
|
||||
run: Permissions::new_unary(None, None, prompt).unwrap(),
|
||||
ffi: Permissions::new_unary(None, None, prompt).unwrap(),
|
||||
import: Permissions::new_unary(None, None, prompt).unwrap(),
|
||||
all: Permissions::new_all(false),
|
||||
}
|
||||
}
|
||||
|
||||
/// A helper function that determines if the module specifier is a local or
|
||||
/// remote, and performs a read or net check for the specifier.
|
||||
pub fn check_specifier(
|
||||
&mut self,
|
||||
specifier: &ModuleSpecifier,
|
||||
) -> Result<(), AnyError> {
|
||||
match specifier.scheme() {
|
||||
"file" => match specifier_to_file_path(specifier) {
|
||||
Ok(path) => self.read.check(
|
||||
&PathQueryDescriptor {
|
||||
requested: path.to_string_lossy().into_owned(),
|
||||
resolved: path,
|
||||
}
|
||||
.into_read(),
|
||||
Some("import()"),
|
||||
),
|
||||
Err(_) => Err(uri_error(format!(
|
||||
"Invalid file path.\n Specifier: {specifier}"
|
||||
))),
|
||||
},
|
||||
"data" => Ok(()),
|
||||
"blob" => Ok(()),
|
||||
_ => self.net.check_url(specifier, Some("import()")),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Attempts to convert a specifier to a file path. By default, uses the Url
|
||||
|
@ -2002,6 +2078,12 @@ pub fn specifier_to_file_path(
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, Eq, PartialEq)]
|
||||
pub enum CheckSpecifierKind {
|
||||
Static,
|
||||
Dynamic,
|
||||
}
|
||||
|
||||
/// Wrapper struct for `Permissions` that can be shared across threads.
|
||||
///
|
||||
/// We need a way to have internal mutability for permissions as they might get
|
||||
|
@ -2039,8 +2121,43 @@ impl PermissionsContainer {
|
|||
pub fn check_specifier(
|
||||
&self,
|
||||
specifier: &ModuleSpecifier,
|
||||
kind: CheckSpecifierKind,
|
||||
) -> Result<(), AnyError> {
|
||||
self.inner.lock().check_specifier(specifier)
|
||||
let mut inner = self.inner.lock();
|
||||
match specifier.scheme() {
|
||||
"file" => {
|
||||
if inner.read.is_allow_all() || kind == CheckSpecifierKind::Static {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
match specifier_to_file_path(specifier) {
|
||||
Ok(path) => inner.read.check(
|
||||
&PathQueryDescriptor {
|
||||
requested: path.to_string_lossy().into_owned(),
|
||||
resolved: path,
|
||||
}
|
||||
.into_read(),
|
||||
Some("import()"),
|
||||
),
|
||||
Err(_) => Err(uri_error(format!(
|
||||
"Invalid file path.\n Specifier: {specifier}"
|
||||
))),
|
||||
}
|
||||
}
|
||||
"data" => Ok(()),
|
||||
"blob" => Ok(()),
|
||||
_ => {
|
||||
if inner.import.is_allow_all() {
|
||||
return Ok(()); // avoid allocation below
|
||||
}
|
||||
|
||||
let desc = self
|
||||
.descriptor_parser
|
||||
.parse_import_descriptor_from_url(specifier)?;
|
||||
inner.import.check(&desc, Some("import()"))?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[must_use = "the resolved return value to mitigate time-of-check to time-of-use issues"]
|
||||
|
@ -2375,7 +2492,12 @@ impl PermissionsContainer {
|
|||
url: &Url,
|
||||
api_name: &str,
|
||||
) -> Result<(), AnyError> {
|
||||
self.inner.lock().net.check_url(url, Some(api_name))
|
||||
let mut inner = self.inner.lock();
|
||||
if inner.net.is_allow_all() {
|
||||
return Ok(());
|
||||
}
|
||||
let desc = self.descriptor_parser.parse_net_descriptor_from_url(url)?;
|
||||
inner.net.check(&desc, Some(api_name))
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
|
@ -2589,6 +2711,7 @@ pub struct ChildPermissionsArg {
|
|||
env: ChildUnaryPermissionArg,
|
||||
net: ChildUnaryPermissionArg,
|
||||
ffi: ChildUnaryPermissionArg,
|
||||
import: ChildUnaryPermissionArg,
|
||||
read: ChildUnaryPermissionArg,
|
||||
run: ChildUnaryPermissionArg,
|
||||
sys: ChildUnaryPermissionArg,
|
||||
|
@ -2601,6 +2724,7 @@ impl ChildPermissionsArg {
|
|||
env: ChildUnaryPermissionArg::Inherit,
|
||||
net: ChildUnaryPermissionArg::Inherit,
|
||||
ffi: ChildUnaryPermissionArg::Inherit,
|
||||
import: ChildUnaryPermissionArg::Inherit,
|
||||
read: ChildUnaryPermissionArg::Inherit,
|
||||
run: ChildUnaryPermissionArg::Inherit,
|
||||
sys: ChildUnaryPermissionArg::Inherit,
|
||||
|
@ -2613,6 +2737,7 @@ impl ChildPermissionsArg {
|
|||
env: ChildUnaryPermissionArg::NotGranted,
|
||||
net: ChildUnaryPermissionArg::NotGranted,
|
||||
ffi: ChildUnaryPermissionArg::NotGranted,
|
||||
import: ChildUnaryPermissionArg::NotGranted,
|
||||
read: ChildUnaryPermissionArg::NotGranted,
|
||||
run: ChildUnaryPermissionArg::NotGranted,
|
||||
sys: ChildUnaryPermissionArg::NotGranted,
|
||||
|
@ -2677,6 +2802,11 @@ impl<'de> Deserialize<'de> for ChildPermissionsArg {
|
|||
child_permissions_arg.ffi = arg.map_err(|e| {
|
||||
de::Error::custom(format!("(deno.permissions.ffi) {e}"))
|
||||
})?;
|
||||
} else if key == "import" {
|
||||
let arg = serde_json::from_value::<ChildUnaryPermissionArg>(value);
|
||||
child_permissions_arg.import = arg.map_err(|e| {
|
||||
de::Error::custom(format!("(deno.permissions.import) {e}"))
|
||||
})?;
|
||||
} else if key == "read" {
|
||||
let arg = serde_json::from_value::<ChildUnaryPermissionArg>(value);
|
||||
child_permissions_arg.read = arg.map_err(|e| {
|
||||
|
@ -2726,6 +2856,25 @@ pub trait PermissionDescriptorParser: Debug + Send + Sync {
|
|||
fn parse_net_descriptor(&self, text: &str)
|
||||
-> Result<NetDescriptor, AnyError>;
|
||||
|
||||
fn parse_net_descriptor_from_url(
|
||||
&self,
|
||||
url: &Url,
|
||||
) -> Result<NetDescriptor, AnyError> {
|
||||
NetDescriptor::from_url(url)
|
||||
}
|
||||
|
||||
fn parse_import_descriptor(
|
||||
&self,
|
||||
text: &str,
|
||||
) -> Result<ImportDescriptor, AnyError>;
|
||||
|
||||
fn parse_import_descriptor_from_url(
|
||||
&self,
|
||||
url: &Url,
|
||||
) -> Result<ImportDescriptor, AnyError> {
|
||||
ImportDescriptor::from_url(url)
|
||||
}
|
||||
|
||||
fn parse_env_descriptor(&self, text: &str)
|
||||
-> Result<EnvDescriptor, AnyError>;
|
||||
|
||||
|
@ -2785,6 +2934,7 @@ pub fn create_child_permissions(
|
|||
&child_permissions_arg.read,
|
||||
&child_permissions_arg.write,
|
||||
&child_permissions_arg.net,
|
||||
&child_permissions_arg.import,
|
||||
&child_permissions_arg.env,
|
||||
&child_permissions_arg.sys,
|
||||
&child_permissions_arg.run,
|
||||
|
@ -2808,6 +2958,11 @@ pub fn create_child_permissions(
|
|||
.create_child_permissions(child_permissions_arg.write, |text| {
|
||||
Ok(Some(parser.parse_write_descriptor(text)?))
|
||||
})?;
|
||||
worker_perms.import = main_perms
|
||||
.import
|
||||
.create_child_permissions(child_permissions_arg.import, |text| {
|
||||
Ok(Some(parser.parse_import_descriptor(text)?))
|
||||
})?;
|
||||
worker_perms.net = main_perms
|
||||
.net
|
||||
.create_child_permissions(child_permissions_arg.net, |text| {
|
||||
|
@ -2897,6 +3052,13 @@ mod tests {
|
|||
NetDescriptor::parse(text)
|
||||
}
|
||||
|
||||
fn parse_import_descriptor(
|
||||
&self,
|
||||
text: &str,
|
||||
) -> Result<ImportDescriptor, AnyError> {
|
||||
ImportDescriptor::parse(text)
|
||||
}
|
||||
|
||||
fn parse_env_descriptor(
|
||||
&self,
|
||||
text: &str,
|
||||
|
@ -3153,8 +3315,9 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn test_check_net_url() {
|
||||
let mut perms = Permissions::from_options(
|
||||
&TestPermissionDescriptorParser,
|
||||
let parser = TestPermissionDescriptorParser;
|
||||
let perms = Permissions::from_options(
|
||||
&parser,
|
||||
&PermissionsOptions {
|
||||
allow_net: Some(svec![
|
||||
"localhost",
|
||||
|
@ -3168,6 +3331,7 @@ mod tests {
|
|||
},
|
||||
)
|
||||
.unwrap();
|
||||
let mut perms = PermissionsContainer::new(Arc::new(parser), perms);
|
||||
|
||||
let url_tests = vec![
|
||||
// Any protocol + port for localhost should be ok, since we don't specify
|
||||
|
@ -3209,8 +3373,8 @@ mod tests {
|
|||
];
|
||||
|
||||
for (url_str, is_ok) in url_tests {
|
||||
let u = url::Url::parse(url_str).unwrap();
|
||||
assert_eq!(is_ok, perms.net.check_url(&u, None).is_ok(), "{}", u);
|
||||
let u = Url::parse(url_str).unwrap();
|
||||
assert_eq!(is_ok, perms.check_net_url(&u, "api()").is_ok(), "{}", u);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3222,48 +3386,78 @@ mod tests {
|
|||
} else {
|
||||
svec!["/a"]
|
||||
};
|
||||
let mut perms = Permissions::from_options(
|
||||
&TestPermissionDescriptorParser,
|
||||
let parser = TestPermissionDescriptorParser;
|
||||
let perms = Permissions::from_options(
|
||||
&parser,
|
||||
&PermissionsOptions {
|
||||
allow_read: Some(read_allowlist),
|
||||
allow_net: Some(svec!["localhost"]),
|
||||
allow_import: Some(svec!["localhost"]),
|
||||
..Default::default()
|
||||
},
|
||||
)
|
||||
.unwrap();
|
||||
let perms = PermissionsContainer::new(Arc::new(parser), perms);
|
||||
|
||||
let mut fixtures = vec![
|
||||
(
|
||||
ModuleSpecifier::parse("http://localhost:4545/mod.ts").unwrap(),
|
||||
CheckSpecifierKind::Static,
|
||||
true,
|
||||
),
|
||||
(
|
||||
ModuleSpecifier::parse("http://localhost:4545/mod.ts").unwrap(),
|
||||
CheckSpecifierKind::Dynamic,
|
||||
true,
|
||||
),
|
||||
(
|
||||
ModuleSpecifier::parse("http://deno.land/x/mod.ts").unwrap(),
|
||||
CheckSpecifierKind::Dynamic,
|
||||
false,
|
||||
),
|
||||
(
|
||||
ModuleSpecifier::parse("data:text/plain,Hello%2C%20Deno!").unwrap(),
|
||||
CheckSpecifierKind::Dynamic,
|
||||
true,
|
||||
),
|
||||
];
|
||||
|
||||
if cfg!(target_os = "windows") {
|
||||
fixtures
|
||||
.push((ModuleSpecifier::parse("file:///C:/a/mod.ts").unwrap(), true));
|
||||
fixtures.push((
|
||||
ModuleSpecifier::parse("file:///C:/a/mod.ts").unwrap(),
|
||||
CheckSpecifierKind::Dynamic,
|
||||
true,
|
||||
));
|
||||
fixtures.push((
|
||||
ModuleSpecifier::parse("file:///C:/b/mod.ts").unwrap(),
|
||||
CheckSpecifierKind::Static,
|
||||
true,
|
||||
));
|
||||
fixtures.push((
|
||||
ModuleSpecifier::parse("file:///C:/b/mod.ts").unwrap(),
|
||||
CheckSpecifierKind::Dynamic,
|
||||
false,
|
||||
));
|
||||
} else {
|
||||
fixtures
|
||||
.push((ModuleSpecifier::parse("file:///a/mod.ts").unwrap(), true));
|
||||
fixtures
|
||||
.push((ModuleSpecifier::parse("file:///b/mod.ts").unwrap(), false));
|
||||
fixtures.push((
|
||||
ModuleSpecifier::parse("file:///a/mod.ts").unwrap(),
|
||||
CheckSpecifierKind::Dynamic,
|
||||
true,
|
||||
));
|
||||
fixtures.push((
|
||||
ModuleSpecifier::parse("file:///b/mod.ts").unwrap(),
|
||||
CheckSpecifierKind::Static,
|
||||
true,
|
||||
));
|
||||
fixtures.push((
|
||||
ModuleSpecifier::parse("file:///b/mod.ts").unwrap(),
|
||||
CheckSpecifierKind::Dynamic,
|
||||
false,
|
||||
));
|
||||
}
|
||||
|
||||
for (specifier, expected) in fixtures {
|
||||
for (specifier, kind, expected) in fixtures {
|
||||
assert_eq!(
|
||||
perms.check_specifier(&specifier).is_ok(),
|
||||
perms.check_specifier(&specifier, kind).is_ok(),
|
||||
expected,
|
||||
"{}",
|
||||
specifier,
|
||||
|
@ -3271,24 +3465,6 @@ mod tests {
|
|||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn check_invalid_specifiers() {
|
||||
set_prompter(Box::new(TestPrompter));
|
||||
let mut perms = Permissions::allow_all();
|
||||
|
||||
let mut test_cases = vec![];
|
||||
|
||||
test_cases.push("file://dir");
|
||||
test_cases.push("file://asdf/");
|
||||
test_cases.push("file://remotehost/");
|
||||
|
||||
for url in test_cases {
|
||||
assert!(perms
|
||||
.check_specifier(&ModuleSpecifier::parse(url).unwrap())
|
||||
.is_err());
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_query() {
|
||||
set_prompter(Box::new(TestPrompter));
|
||||
|
@ -3885,6 +4061,7 @@ mod tests {
|
|||
env: ChildUnaryPermissionArg::Inherit,
|
||||
net: ChildUnaryPermissionArg::Inherit,
|
||||
ffi: ChildUnaryPermissionArg::Inherit,
|
||||
import: ChildUnaryPermissionArg::Inherit,
|
||||
read: ChildUnaryPermissionArg::Inherit,
|
||||
run: ChildUnaryPermissionArg::Inherit,
|
||||
sys: ChildUnaryPermissionArg::Inherit,
|
||||
|
@ -3897,6 +4074,7 @@ mod tests {
|
|||
env: ChildUnaryPermissionArg::NotGranted,
|
||||
net: ChildUnaryPermissionArg::NotGranted,
|
||||
ffi: ChildUnaryPermissionArg::NotGranted,
|
||||
import: ChildUnaryPermissionArg::NotGranted,
|
||||
read: ChildUnaryPermissionArg::NotGranted,
|
||||
run: ChildUnaryPermissionArg::NotGranted,
|
||||
sys: ChildUnaryPermissionArg::NotGranted,
|
||||
|
@ -3930,6 +4108,7 @@ mod tests {
|
|||
"env": true,
|
||||
"net": true,
|
||||
"ffi": true,
|
||||
"import": true,
|
||||
"read": true,
|
||||
"run": true,
|
||||
"sys": true,
|
||||
|
@ -3940,6 +4119,7 @@ mod tests {
|
|||
env: ChildUnaryPermissionArg::Granted,
|
||||
net: ChildUnaryPermissionArg::Granted,
|
||||
ffi: ChildUnaryPermissionArg::Granted,
|
||||
import: ChildUnaryPermissionArg::Granted,
|
||||
read: ChildUnaryPermissionArg::Granted,
|
||||
run: ChildUnaryPermissionArg::Granted,
|
||||
sys: ChildUnaryPermissionArg::Granted,
|
||||
|
@ -3951,6 +4131,7 @@ mod tests {
|
|||
"env": false,
|
||||
"net": false,
|
||||
"ffi": false,
|
||||
"import": false,
|
||||
"read": false,
|
||||
"run": false,
|
||||
"sys": false,
|
||||
|
@ -3961,6 +4142,7 @@ mod tests {
|
|||
env: ChildUnaryPermissionArg::NotGranted,
|
||||
net: ChildUnaryPermissionArg::NotGranted,
|
||||
ffi: ChildUnaryPermissionArg::NotGranted,
|
||||
import: ChildUnaryPermissionArg::NotGranted,
|
||||
read: ChildUnaryPermissionArg::NotGranted,
|
||||
run: ChildUnaryPermissionArg::NotGranted,
|
||||
sys: ChildUnaryPermissionArg::NotGranted,
|
||||
|
@ -3972,6 +4154,7 @@ mod tests {
|
|||
"env": ["foo", "bar"],
|
||||
"net": ["foo", "bar:8000"],
|
||||
"ffi": ["foo", "file:///bar/baz"],
|
||||
"import": ["example.com"],
|
||||
"read": ["foo", "file:///bar/baz"],
|
||||
"run": ["foo", "file:///bar/baz", "./qux"],
|
||||
"sys": ["hostname", "osRelease"],
|
||||
|
@ -3985,6 +4168,7 @@ mod tests {
|
|||
"foo",
|
||||
"file:///bar/baz"
|
||||
]),
|
||||
import: ChildUnaryPermissionArg::GrantedList(svec!["example.com"]),
|
||||
read: ChildUnaryPermissionArg::GrantedList(svec![
|
||||
"foo",
|
||||
"file:///bar/baz"
|
||||
|
|
|
@ -18,7 +18,7 @@ fn xdg_cache_home_dir() {
|
|||
.env_clear()
|
||||
.env("XDG_CACHE_HOME", &xdg_cache_home)
|
||||
.args(
|
||||
"cache --reload --no-check http://localhost:4548/subdir/redirects/a.ts",
|
||||
"cache --allow-import --reload --no-check http://localhost:4548/subdir/redirects/a.ts",
|
||||
)
|
||||
.run()
|
||||
.skip_output_check()
|
||||
|
|
|
@ -9,14 +9,14 @@ use util::TestContext;
|
|||
use util::TestContextBuilder;
|
||||
|
||||
itest!(check_all {
|
||||
args: "check --quiet --all check/all/check_all.ts",
|
||||
args: "check --allow-import --quiet --all check/all/check_all.ts",
|
||||
output: "check/all/check_all.out",
|
||||
http_server: true,
|
||||
exit_code: 1,
|
||||
});
|
||||
|
||||
itest!(check_all_local {
|
||||
args: "check --quiet check/all/check_all.ts",
|
||||
args: "check --allow-import --quiet check/all/check_all.ts",
|
||||
output_str: Some(""),
|
||||
http_server: true,
|
||||
});
|
||||
|
@ -227,6 +227,7 @@ fn ts_no_recheck_on_redirect() {
|
|||
let test_context = TestContext::default();
|
||||
let check_command = test_context.new_command().args_vec([
|
||||
"run",
|
||||
"--allow-import",
|
||||
"--check",
|
||||
"run/017_import_redirect.ts",
|
||||
]);
|
||||
|
|
|
@ -539,6 +539,7 @@ fn check_local_by_default() {
|
|||
.new_command()
|
||||
.args_vec([
|
||||
"compile",
|
||||
"--allow-import",
|
||||
"--output",
|
||||
&exe.to_string_lossy(),
|
||||
"./compile/check_local_by_default.ts",
|
||||
|
@ -561,6 +562,7 @@ fn check_local_by_default2() {
|
|||
.new_command()
|
||||
.args_vec([
|
||||
"compile",
|
||||
"--allow-import",
|
||||
"--output",
|
||||
&exe.to_string_lossy(),
|
||||
"./compile/check_local_by_default2.ts"
|
||||
|
|
|
@ -456,6 +456,7 @@ fn no_http_coverage_data() {
|
|||
.new_command()
|
||||
.args_vec(vec![
|
||||
"test".to_string(),
|
||||
"--allow-import".to_string(),
|
||||
"--quiet".to_string(),
|
||||
"--no-check".to_string(),
|
||||
format!("--coverage={}", tempdir),
|
||||
|
|
|
@ -294,7 +294,7 @@ fn check_local_by_default() {
|
|||
let script_path_str = script_path.to_string_lossy().to_string();
|
||||
context
|
||||
.new_command()
|
||||
.args_vec(["install", "-g", script_path_str.as_str()])
|
||||
.args_vec(["install", "-g", "--allow-import", script_path_str.as_str()])
|
||||
.envs([
|
||||
("HOME", temp_dir_str.as_str()),
|
||||
("USERPROFILE", temp_dir_str.as_str()),
|
||||
|
@ -318,7 +318,7 @@ fn check_local_by_default2() {
|
|||
let script_path_str = script_path.to_string_lossy().to_string();
|
||||
context
|
||||
.new_command()
|
||||
.args_vec(["install", "-g", script_path_str.as_str()])
|
||||
.args_vec(["install", "-g", "--allow-import", script_path_str.as_str()])
|
||||
.envs([
|
||||
("HOME", temp_dir_str.as_str()),
|
||||
("NO_COLOR", "1"),
|
||||
|
|
|
@ -890,7 +890,7 @@ fn lsp_format_vendor_path() {
|
|||
// put this dependency in the global cache
|
||||
context
|
||||
.new_command()
|
||||
.args("cache http://localhost:4545/run/002_hello.ts")
|
||||
.args("cache --allow-import http://localhost:4545/run/002_hello.ts")
|
||||
.run()
|
||||
.skip_output_check();
|
||||
|
||||
|
|
|
@ -73,7 +73,7 @@ itest!(_005_more_imports {
|
|||
});
|
||||
|
||||
itest!(_006_url_imports {
|
||||
args: "run --quiet --reload run/006_url_imports.ts",
|
||||
args: "run --quiet --reload --allow-import run/006_url_imports.ts",
|
||||
output: "run/006_url_imports.ts.out",
|
||||
http_server: true,
|
||||
});
|
||||
|
@ -105,24 +105,25 @@ itest!(_016_double_await {
|
|||
});
|
||||
|
||||
itest!(_017_import_redirect {
|
||||
args: "run --quiet --reload run/017_import_redirect.ts",
|
||||
args: "run --quiet --allow-import --reload run/017_import_redirect.ts",
|
||||
output: "run/017_import_redirect.ts.out",
|
||||
});
|
||||
|
||||
itest!(_017_import_redirect_check {
|
||||
args: "run --quiet --reload --check run/017_import_redirect.ts",
|
||||
args:
|
||||
"run --quiet --allow-import --reload --check run/017_import_redirect.ts",
|
||||
output: "run/017_import_redirect.ts.out",
|
||||
});
|
||||
|
||||
itest!(_017_import_redirect_vendor_dir {
|
||||
args:
|
||||
"run --quiet --reload --vendor --check $TESTDATA/run/017_import_redirect.ts",
|
||||
"run --quiet --allow-import --reload --vendor --check $TESTDATA/run/017_import_redirect.ts",
|
||||
output: "run/017_import_redirect.ts.out",
|
||||
temp_cwd: true,
|
||||
});
|
||||
|
||||
itest!(_017_import_redirect_info {
|
||||
args: "info --quiet --reload run/017_import_redirect.ts",
|
||||
args: "info --quiet --allow-import --reload run/017_import_redirect.ts",
|
||||
output: "run/017_import_redirect_info.out",
|
||||
});
|
||||
|
||||
|
@ -132,7 +133,7 @@ itest!(_018_async_catch {
|
|||
});
|
||||
|
||||
itest!(_019_media_types {
|
||||
args: "run --reload run/019_media_types.ts",
|
||||
args: "run --reload --allow-import run/019_media_types.ts",
|
||||
output: "run/019_media_types.ts.out",
|
||||
http_server: true,
|
||||
});
|
||||
|
@ -154,14 +155,14 @@ itest!(_025_reload_js_type_error {
|
|||
});
|
||||
|
||||
itest!(_027_redirect_typescript {
|
||||
args: "run --quiet --reload run/027_redirect_typescript.ts",
|
||||
args: "run --quiet --reload --allow-import run/027_redirect_typescript.ts",
|
||||
output: "run/027_redirect_typescript.ts.out",
|
||||
http_server: true,
|
||||
});
|
||||
|
||||
itest!(_027_redirect_typescript_vendor_dir {
|
||||
args:
|
||||
"run --quiet --reload --vendor $TESTDATA/run/027_redirect_typescript.ts",
|
||||
"run --quiet --reload --vendor --allow-import $TESTDATA/run/027_redirect_typescript.ts",
|
||||
output: "run/027_redirect_typescript.ts.out",
|
||||
http_server: true,
|
||||
temp_cwd: true,
|
||||
|
@ -175,14 +176,14 @@ itest!(_028_args {
|
|||
|
||||
itest!(_033_import_map_remote {
|
||||
args:
|
||||
"run --quiet --reload --import-map=http://127.0.0.1:4545/import_maps/import_map_remote.json import_maps/test_remote.ts",
|
||||
"run --quiet --reload --allow-import --import-map=http://127.0.0.1:4545/import_maps/import_map_remote.json import_maps/test_remote.ts",
|
||||
output: "run/033_import_map_remote.out",
|
||||
http_server: true,
|
||||
});
|
||||
|
||||
itest!(_033_import_map_vendor_dir_remote {
|
||||
args:
|
||||
"run --quiet --reload --import-map=http://127.0.0.1:4545/import_maps/import_map_remote.json --vendor $TESTDATA/import_maps/test_remote.ts",
|
||||
"run --quiet --reload --allow-import --import-map=http://127.0.0.1:4545/import_maps/import_map_remote.json --vendor $TESTDATA/import_maps/test_remote.ts",
|
||||
output: "run/033_import_map_remote.out",
|
||||
http_server: true,
|
||||
temp_cwd: true,
|
||||
|
@ -190,7 +191,7 @@ itest!(_033_import_map_vendor_dir_remote {
|
|||
|
||||
itest!(_033_import_map_data_uri {
|
||||
args:
|
||||
"run --quiet --reload --import-map=data:application/json;charset=utf-8;base64,ewogICJpbXBvcnRzIjogewogICAgInRlc3Rfc2VydmVyLyI6ICJodHRwOi8vbG9jYWxob3N0OjQ1NDUvIgogIH0KfQ== run/import_maps/test_data.ts",
|
||||
"run --quiet --reload --allow-import --import-map=data:application/json;charset=utf-8;base64,ewogICJpbXBvcnRzIjogewogICAgInRlc3Rfc2VydmVyLyI6ICJodHRwOi8vbG9jYWxob3N0OjQ1NDUvIgogIH0KfQ== run/import_maps/test_data.ts",
|
||||
output: "run/import_maps/test_data.ts.out",
|
||||
http_server: true,
|
||||
});
|
||||
|
@ -201,7 +202,7 @@ itest!(onload {
|
|||
});
|
||||
|
||||
itest!(_035_cached_only_flag {
|
||||
args: "run --reload --check --cached-only http://127.0.0.1:4545/run/019_media_types.ts",
|
||||
args: "run --reload --check --allow-import --cached-only http://127.0.0.1:4545/run/019_media_types.ts",
|
||||
output: "run/035_cached_only_flag.out",
|
||||
exit_code: 1,
|
||||
http_server: true,
|
||||
|
@ -237,14 +238,14 @@ itest!(_047_jsx {
|
|||
});
|
||||
|
||||
itest!(_048_media_types_jsx {
|
||||
args: "run --reload run/048_media_types_jsx.ts",
|
||||
args: "run --reload --allow-import run/048_media_types_jsx.ts",
|
||||
output: "run/048_media_types_jsx.ts.out",
|
||||
http_server: true,
|
||||
});
|
||||
|
||||
itest!(_052_no_remote_flag {
|
||||
args:
|
||||
"run --reload --check --no-remote http://127.0.0.1:4545/run/019_media_types.ts",
|
||||
"run --reload --check --allow-import --no-remote http://127.0.0.1:4545/run/019_media_types.ts",
|
||||
output: "run/052_no_remote_flag.out",
|
||||
exit_code: 1,
|
||||
http_server: true,
|
||||
|
@ -467,7 +468,7 @@ itest!(dynamic_import_already_rejected {
|
|||
});
|
||||
|
||||
itest!(dynamic_import_concurrent_non_statically_analyzable {
|
||||
args: "run --allow-read --allow-net --quiet run/dynamic_import_concurrent_non_statically_analyzable/main.ts",
|
||||
args: "run --allow-import --allow-read --allow-net --quiet run/dynamic_import_concurrent_non_statically_analyzable/main.ts",
|
||||
output: "run/dynamic_import_concurrent_non_statically_analyzable/main.out",
|
||||
http_server: true,
|
||||
});
|
||||
|
@ -802,7 +803,7 @@ itest!(private_field_presence_no_check {
|
|||
|
||||
itest!(lock_write_fetch {
|
||||
args:
|
||||
"run --quiet --allow-read --allow-write --allow-env --allow-run run/lock_write_fetch/main.ts",
|
||||
"run --quiet --allow-import --allow-read --allow-write --allow-env --allow-run run/lock_write_fetch/main.ts",
|
||||
output: "run/lock_write_fetch/main.out",
|
||||
http_server: true,
|
||||
exit_code: 0,
|
||||
|
@ -810,26 +811,27 @@ itest!(lock_write_fetch {
|
|||
|
||||
itest!(lock_check_ok {
|
||||
args:
|
||||
"run --quiet --lock=run/lock_check_ok.json http://127.0.0.1:4545/run/003_relative_import.ts",
|
||||
"run --quiet --allow-import --lock=run/lock_check_ok.json http://127.0.0.1:4545/run/003_relative_import.ts",
|
||||
output: "run/003_relative_import.ts.out",
|
||||
http_server: true,
|
||||
});
|
||||
|
||||
itest!(lock_check_ok2 {
|
||||
args: "run --lock=run/lock_check_ok2.json run/019_media_types.ts",
|
||||
args:
|
||||
"run --allow-import --lock=run/lock_check_ok2.json run/019_media_types.ts",
|
||||
output: "run/019_media_types.ts.out",
|
||||
http_server: true,
|
||||
});
|
||||
|
||||
itest!(lock_v2_check_ok {
|
||||
args:
|
||||
"run --quiet --lock=run/lock_v2_check_ok.json http://127.0.0.1:4545/run/003_relative_import.ts",
|
||||
"run --allow-import --quiet --lock=run/lock_v2_check_ok.json http://127.0.0.1:4545/run/003_relative_import.ts",
|
||||
output: "run/003_relative_import.ts.out",
|
||||
http_server: true,
|
||||
});
|
||||
|
||||
itest!(lock_v2_check_ok2 {
|
||||
args: "run --lock=run/lock_v2_check_ok2.json run/019_media_types.ts",
|
||||
args: "run --allow-import --lock=run/lock_v2_check_ok2.json run/019_media_types.ts",
|
||||
output: "run/019_media_types.ts.out",
|
||||
http_server: true,
|
||||
});
|
||||
|
@ -849,7 +851,7 @@ fn lock_redirects() {
|
|||
);
|
||||
context
|
||||
.new_command()
|
||||
.args("run main.ts")
|
||||
.args("run --allow-import main.ts")
|
||||
.run()
|
||||
.skip_output_check();
|
||||
let initial_lockfile_text = r#"{
|
||||
|
@ -865,7 +867,7 @@ fn lock_redirects() {
|
|||
assert_eq!(temp_dir.read_to_string("deno.lock"), initial_lockfile_text);
|
||||
context
|
||||
.new_command()
|
||||
.args("run main.ts")
|
||||
.args("run --allow-import main.ts")
|
||||
.run()
|
||||
.assert_matches_text("Hello World\n");
|
||||
assert_eq!(temp_dir.read_to_string("deno.lock"), initial_lockfile_text);
|
||||
|
@ -892,7 +894,7 @@ fn lock_redirects() {
|
|||
// it should use the echo script instead
|
||||
context
|
||||
.new_command()
|
||||
.args("run main.ts Hi there")
|
||||
.args("run --allow-import main.ts Hi there")
|
||||
.run()
|
||||
.assert_matches_text(concat!(
|
||||
"Download http://localhost:4545/echo.ts\n",
|
||||
|
@ -1260,7 +1262,7 @@ itest!(config_types {
|
|||
|
||||
itest!(config_types_remote {
|
||||
http_server: true,
|
||||
args: "run --reload --quiet --check=all --config run/config_types/remote.tsconfig.json run/config_types/main.ts",
|
||||
args: "run --allow-import --reload --quiet --check=all --config run/config_types/remote.tsconfig.json run/config_types/main.ts",
|
||||
output: "run/config_types/main.out",
|
||||
});
|
||||
|
||||
|
@ -1365,9 +1367,10 @@ itest!(error_015_dynamic_import_permissions {
|
|||
http_server: true,
|
||||
});
|
||||
|
||||
// We have an allow-net flag but not allow-read, it should still result in error.
|
||||
// We have an allow-import flag but not allow-read, it should still result in error.
|
||||
itest!(error_016_dynamic_import_permissions2 {
|
||||
args: "run --reload --allow-net run/error_016_dynamic_import_permissions2.js",
|
||||
args:
|
||||
"run --reload --allow-import run/error_016_dynamic_import_permissions2.js",
|
||||
output: "run/error_016_dynamic_import_permissions2.out",
|
||||
exit_code: 1,
|
||||
http_server: true,
|
||||
|
@ -1428,7 +1431,7 @@ itest!(error_025_tab_indent {
|
|||
});
|
||||
|
||||
itest!(error_026_remote_import_error {
|
||||
args: "run run/error_026_remote_import_error.ts",
|
||||
args: "run --allow-import run/error_026_remote_import_error.ts",
|
||||
output: "run/error_026_remote_import_error.ts.out",
|
||||
exit_code: 1,
|
||||
http_server: true,
|
||||
|
@ -1471,18 +1474,18 @@ itest!(error_type_definitions {
|
|||
});
|
||||
|
||||
itest!(error_local_static_import_from_remote_ts {
|
||||
args: "run --reload http://localhost:4545/run/error_local_static_import_from_remote.ts",
|
||||
args: "run --allow-import --reload http://localhost:4545/run/error_local_static_import_from_remote.ts",
|
||||
exit_code: 1,
|
||||
http_server: true,
|
||||
output: "run/error_local_static_import_from_remote.ts.out",
|
||||
});
|
||||
});
|
||||
|
||||
itest!(error_local_static_import_from_remote_js {
|
||||
args: "run --reload http://localhost:4545/run/error_local_static_import_from_remote.js",
|
||||
args: "run --allow-import --reload http://localhost:4545/run/error_local_static_import_from_remote.js",
|
||||
exit_code: 1,
|
||||
http_server: true,
|
||||
output: "run/error_local_static_import_from_remote.js.out",
|
||||
});
|
||||
});
|
||||
|
||||
itest!(exit_error42 {
|
||||
exit_code: 42,
|
||||
|
@ -1531,7 +1534,7 @@ itest!(finalization_registry {
|
|||
});
|
||||
|
||||
itest!(https_import {
|
||||
args: "run --quiet --reload --cert tls/RootCA.pem run/https_import.ts",
|
||||
args: "run --allow-import --quiet --reload --cert tls/RootCA.pem run/https_import.ts",
|
||||
output: "run/https_import.ts.out",
|
||||
http_server: true,
|
||||
});
|
||||
|
@ -1542,7 +1545,7 @@ itest!(if_main {
|
|||
});
|
||||
|
||||
itest!(import_meta {
|
||||
args: "run --quiet --reload --import-map=run/import_meta/importmap.json run/import_meta/main.ts",
|
||||
args: "run --allow-import --quiet --reload --import-map=run/import_meta/importmap.json run/import_meta/main.ts",
|
||||
output: "run/import_meta/main.out",
|
||||
http_server: true,
|
||||
});
|
||||
|
@ -1553,7 +1556,7 @@ itest!(main_module {
|
|||
});
|
||||
|
||||
itest!(no_check {
|
||||
args: "run --quiet --reload --no-check run/006_url_imports.ts",
|
||||
args: "run --allow-import --quiet --reload --no-check run/006_url_imports.ts",
|
||||
output: "run/006_url_imports.ts.out",
|
||||
http_server: true,
|
||||
});
|
||||
|
@ -1569,14 +1572,15 @@ itest!(decorators_tc39_proposal {
|
|||
});
|
||||
|
||||
itest!(check_remote {
|
||||
args: "run --quiet --reload --check=all run/no_check_remote.ts",
|
||||
args:
|
||||
"run --quiet --allow-import --reload --check=all run/no_check_remote.ts",
|
||||
output: "run/no_check_remote.ts.disabled.out",
|
||||
exit_code: 1,
|
||||
http_server: true,
|
||||
});
|
||||
|
||||
itest!(no_check_remote {
|
||||
args: "run --quiet --reload --no-check=remote run/no_check_remote.ts",
|
||||
args: "run --allow-import --quiet --reload --no-check=remote run/no_check_remote.ts",
|
||||
output: "run/no_check_remote.ts.enabled.out",
|
||||
http_server: true,
|
||||
});
|
||||
|
@ -1603,13 +1607,15 @@ itest!(type_definitions_for_export {
|
|||
});
|
||||
|
||||
itest!(type_directives_01 {
|
||||
args: "run --reload --check=all -L debug run/type_directives_01.ts",
|
||||
args:
|
||||
"run --allow-import --reload --check=all -L debug run/type_directives_01.ts",
|
||||
output: "run/type_directives_01.ts.out",
|
||||
http_server: true,
|
||||
});
|
||||
|
||||
itest!(type_directives_02 {
|
||||
args: "run --reload --check=all -L debug run/type_directives_02.ts",
|
||||
args:
|
||||
"run --allow-import --reload --check=all -L debug run/type_directives_02.ts",
|
||||
output: "run/type_directives_02.ts.out",
|
||||
});
|
||||
|
||||
|
@ -1629,13 +1635,13 @@ fn type_directives_js_main() {
|
|||
}
|
||||
|
||||
itest!(type_directives_redirect {
|
||||
args: "run --reload --check run/type_directives_redirect.ts",
|
||||
args: "run --allow-import --reload --check run/type_directives_redirect.ts",
|
||||
output: "run/type_directives_redirect.ts.out",
|
||||
http_server: true,
|
||||
});
|
||||
|
||||
itest!(type_headers_deno_types {
|
||||
args: "run --reload --check run/type_headers_deno_types.ts",
|
||||
args: "run --allow-import --reload --check run/type_headers_deno_types.ts",
|
||||
output: "run/type_headers_deno_types.ts.out",
|
||||
http_server: true,
|
||||
});
|
||||
|
@ -1839,20 +1845,20 @@ itest!(unstable_kv_enabled {
|
|||
});
|
||||
|
||||
itest!(import_compression {
|
||||
args: "run --quiet --reload --allow-net run/import_compression/main.ts",
|
||||
args: "run --allow-import --quiet --reload --allow-net run/import_compression/main.ts",
|
||||
output: "run/import_compression/main.out",
|
||||
http_server: true,
|
||||
});
|
||||
|
||||
itest!(disallow_http_from_https_js {
|
||||
args: "run --quiet --reload --cert tls/RootCA.pem https://localhost:5545/run/disallow_http_from_https.js",
|
||||
args: "run --allow-import --quiet --reload --cert tls/RootCA.pem https://localhost:5545/run/disallow_http_from_https.js",
|
||||
output: "run/disallow_http_from_https_js.out",
|
||||
http_server: true,
|
||||
exit_code: 1,
|
||||
});
|
||||
|
||||
itest!(disallow_http_from_https_ts {
|
||||
args: "run --quiet --reload --cert tls/RootCA.pem https://localhost:5545/run/disallow_http_from_https.ts",
|
||||
args: "run --allow-import --quiet --reload --cert tls/RootCA.pem https://localhost:5545/run/disallow_http_from_https.ts",
|
||||
output: "run/disallow_http_from_https_ts.out",
|
||||
http_server: true,
|
||||
exit_code: 1,
|
||||
|
@ -1904,7 +1910,7 @@ itest!(es_private_fields {
|
|||
});
|
||||
|
||||
itest!(ts_import_from_js {
|
||||
args: "run --quiet --reload run/ts_import_from_js/main.js",
|
||||
args: "run --allow-import --quiet --reload run/ts_import_from_js/main.js",
|
||||
output: "run/ts_import_from_js/main.out",
|
||||
http_server: true,
|
||||
});
|
||||
|
@ -1915,100 +1921,101 @@ itest!(jsx_import_from_ts {
|
|||
});
|
||||
|
||||
itest!(jsx_import_source_pragma {
|
||||
args: "run --reload run/jsx_import_source_pragma.tsx",
|
||||
args: "run --reload --allow-import run/jsx_import_source_pragma.tsx",
|
||||
output: "run/jsx_import_source.out",
|
||||
http_server: true,
|
||||
});
|
||||
|
||||
itest!(jsx_import_source_pragma_with_config {
|
||||
args:
|
||||
"run --reload --config jsx/deno-jsx.jsonc --no-lock run/jsx_import_source_pragma.tsx",
|
||||
"run --reload --allow-import --config jsx/deno-jsx.jsonc --no-lock run/jsx_import_source_pragma.tsx",
|
||||
output: "run/jsx_import_source.out",
|
||||
http_server: true,
|
||||
});
|
||||
|
||||
itest!(jsx_import_source_pragma_with_dev_config {
|
||||
args:
|
||||
"run --reload --config jsx/deno-jsxdev.jsonc --no-lock run/jsx_import_source_pragma.tsx",
|
||||
"run --reload --allow-import --config jsx/deno-jsxdev.jsonc --no-lock run/jsx_import_source_pragma.tsx",
|
||||
output: "run/jsx_import_source_dev.out",
|
||||
http_server: true,
|
||||
});
|
||||
|
||||
itest!(jsx_import_source_no_pragma {
|
||||
args:
|
||||
"run --reload --config jsx/deno-jsx.jsonc --no-lock run/jsx_import_source_no_pragma.tsx",
|
||||
"run --allow-import --reload --config jsx/deno-jsx.jsonc --no-lock run/jsx_import_source_no_pragma.tsx",
|
||||
output: "run/jsx_import_source.out",
|
||||
http_server: true,
|
||||
});
|
||||
|
||||
itest!(jsx_import_source_no_pragma_dev {
|
||||
args: "run --reload --config jsx/deno-jsxdev.jsonc --no-lock run/jsx_import_source_no_pragma.tsx",
|
||||
args: "run --allow-import --reload --config jsx/deno-jsxdev.jsonc --no-lock run/jsx_import_source_no_pragma.tsx",
|
||||
output: "run/jsx_import_source_dev.out",
|
||||
http_server: true,
|
||||
});
|
||||
|
||||
itest!(jsx_import_source_pragma_import_map {
|
||||
args: "run --reload --import-map jsx/import-map.json run/jsx_import_source_pragma_import_map.tsx",
|
||||
args: "run --allow-import --reload --import-map jsx/import-map.json run/jsx_import_source_pragma_import_map.tsx",
|
||||
output: "run/jsx_import_source_import_map.out",
|
||||
http_server: true,
|
||||
});
|
||||
|
||||
itest!(jsx_import_source_pragma_import_map_dev {
|
||||
args: "run --reload --import-map jsx/import-map.json --config jsx/deno-jsxdev-import-map.jsonc run/jsx_import_source_pragma_import_map.tsx",
|
||||
args: "run --allow-import --reload --import-map jsx/import-map.json --config jsx/deno-jsxdev-import-map.jsonc run/jsx_import_source_pragma_import_map.tsx",
|
||||
output: "run/jsx_import_source_import_map_dev.out",
|
||||
http_server: true,
|
||||
});
|
||||
|
||||
itest!(jsx_import_source_precompile_import_map {
|
||||
args: "run --reload --check --import-map jsx/import-map.json --no-lock --config jsx/deno-jsx-precompile.jsonc run/jsx_precompile/no_pragma.tsx",
|
||||
args: "run --allow-import --reload --check --import-map jsx/import-map.json --no-lock --config jsx/deno-jsx-precompile.jsonc run/jsx_precompile/no_pragma.tsx",
|
||||
output: "run/jsx_precompile/no_pragma.out",
|
||||
http_server: true,
|
||||
});
|
||||
|
||||
itest!(jsx_import_source_precompile_import_map_skip_element {
|
||||
args: "run --reload --check --import-map jsx/import-map.json --no-lock --config jsx/deno-jsx-precompile-skip.jsonc run/jsx_precompile/skip.tsx",
|
||||
args: "run --allow-import --reload --check --import-map jsx/import-map.json --no-lock --config jsx/deno-jsx-precompile-skip.jsonc run/jsx_precompile/skip.tsx",
|
||||
output: "run/jsx_precompile/skip.out",
|
||||
http_server: true,
|
||||
});
|
||||
|
||||
itest!(jsx_import_source_import_map {
|
||||
args: "run --reload --import-map jsx/import-map.json --no-lock --config jsx/deno-jsx-import-map.jsonc run/jsx_import_source_no_pragma.tsx",
|
||||
args: "run --allow-import --reload --import-map jsx/import-map.json --no-lock --config jsx/deno-jsx-import-map.jsonc run/jsx_import_source_no_pragma.tsx",
|
||||
output: "run/jsx_import_source_import_map.out",
|
||||
http_server: true,
|
||||
});
|
||||
|
||||
itest!(jsx_import_source_import_map_dev {
|
||||
args: "run --reload --import-map jsx/import-map.json --no-lock --config jsx/deno-jsxdev-import-map.jsonc run/jsx_import_source_no_pragma.tsx",
|
||||
args: "run --allow-import --reload --import-map jsx/import-map.json --no-lock --config jsx/deno-jsxdev-import-map.jsonc run/jsx_import_source_no_pragma.tsx",
|
||||
output: "run/jsx_import_source_import_map_dev.out",
|
||||
http_server: true,
|
||||
});
|
||||
|
||||
itest!(jsx_import_source_import_map_scoped {
|
||||
args: "run --reload --import-map jsx/import-map-scoped.json --no-lock --config jsx/deno-jsx-import-map.jsonc subdir/jsx_import_source_no_pragma.tsx",
|
||||
args: "run --allow-import --reload --import-map jsx/import-map-scoped.json --no-lock --config jsx/deno-jsx-import-map.jsonc subdir/jsx_import_source_no_pragma.tsx",
|
||||
output: "run/jsx_import_source_import_map.out",
|
||||
http_server: true,
|
||||
});
|
||||
|
||||
itest!(jsx_import_source_import_map_scoped_dev {
|
||||
args: "run --reload --import-map jsx/import-map-scoped.json --no-lock --config jsx/deno-jsxdev-import-map.jsonc subdir/jsx_import_source_no_pragma.tsx",
|
||||
args: "run --allow-import --reload --import-map jsx/import-map-scoped.json --no-lock --config jsx/deno-jsxdev-import-map.jsonc subdir/jsx_import_source_no_pragma.tsx",
|
||||
output: "run/jsx_import_source_import_map_dev.out",
|
||||
http_server: true,
|
||||
});
|
||||
|
||||
itest!(jsx_import_source_pragma_no_check {
|
||||
args: "run --reload --no-check run/jsx_import_source_pragma.tsx",
|
||||
args:
|
||||
"run --allow-import --reload --no-check run/jsx_import_source_pragma.tsx",
|
||||
output: "run/jsx_import_source.out",
|
||||
http_server: true,
|
||||
});
|
||||
|
||||
itest!(jsx_import_source_pragma_with_config_no_check {
|
||||
args: "run --reload --config jsx/deno-jsx.jsonc --no-lock --no-check run/jsx_import_source_pragma.tsx",
|
||||
args: "run --allow-import --reload --config jsx/deno-jsx.jsonc --no-lock --no-check run/jsx_import_source_pragma.tsx",
|
||||
output: "run/jsx_import_source.out",
|
||||
http_server: true,
|
||||
});
|
||||
|
||||
itest!(jsx_import_source_pragma_with_config_vendor_dir {
|
||||
args: "run --reload --config jsx/deno-jsx.jsonc --no-lock --vendor $TESTDATA/run/jsx_import_source_pragma.tsx",
|
||||
args: "run --allow-import --reload --config jsx/deno-jsx.jsonc --no-lock --vendor $TESTDATA/run/jsx_import_source_pragma.tsx",
|
||||
output: "run/jsx_import_source.out",
|
||||
http_server: true,
|
||||
temp_cwd: true,
|
||||
|
@ -2017,19 +2024,19 @@ itest!(jsx_import_source_pragma_with_config_vendor_dir {
|
|||
|
||||
itest!(jsx_import_source_no_pragma_no_check {
|
||||
args:
|
||||
"run --reload --config jsx/deno-jsx.jsonc --no-lock --no-check run/jsx_import_source_no_pragma.tsx",
|
||||
"run --allow-import --reload --config jsx/deno-jsx.jsonc --no-lock --no-check run/jsx_import_source_no_pragma.tsx",
|
||||
output: "run/jsx_import_source.out",
|
||||
http_server: true,
|
||||
});
|
||||
|
||||
itest!(jsx_import_source_pragma_import_map_no_check {
|
||||
args: "run --reload --import-map jsx/import-map.json --no-check run/jsx_import_source_pragma_import_map.tsx",
|
||||
args: "run --allow-import --reload --import-map jsx/import-map.json --no-check run/jsx_import_source_pragma_import_map.tsx",
|
||||
output: "run/jsx_import_source_import_map.out",
|
||||
http_server: true,
|
||||
});
|
||||
|
||||
itest!(jsx_import_source_import_map_no_check {
|
||||
args: "run --reload --import-map jsx/import-map.json --no-lock --config jsx/deno-jsx-import-map.jsonc --no-check run/jsx_import_source_no_pragma.tsx",
|
||||
args: "run --allow-import --reload --import-map jsx/import-map.json --no-lock --config jsx/deno-jsx-import-map.jsonc --no-check run/jsx_import_source_no_pragma.tsx",
|
||||
output: "run/jsx_import_source_import_map.out",
|
||||
http_server: true,
|
||||
});
|
||||
|
@ -2093,7 +2100,7 @@ itest!(import_data_url_import_relative {
|
|||
});
|
||||
|
||||
itest!(import_data_url_imports {
|
||||
args: "run --quiet --reload run/import_data_url_imports.ts",
|
||||
args: "run --allow-import --quiet --reload run/import_data_url_imports.ts",
|
||||
output: "run/import_data_url_imports.ts.out",
|
||||
http_server: true,
|
||||
});
|
||||
|
@ -2127,7 +2134,7 @@ itest!(import_blob_url_import_relative {
|
|||
|
||||
itest!(import_blob_url_imports {
|
||||
args:
|
||||
"run --quiet --reload --allow-net=localhost:4545 run/import_blob_url_imports.ts",
|
||||
"run --allow-import --quiet --reload --allow-net=localhost:4545 run/import_blob_url_imports.ts",
|
||||
output: "run/import_blob_url_imports.ts.out",
|
||||
http_server: true,
|
||||
});
|
||||
|
@ -2143,13 +2150,13 @@ itest!(import_blob_url {
|
|||
});
|
||||
|
||||
itest!(import_file_with_colon {
|
||||
args: "run --quiet --reload run/import_file_with_colon.ts",
|
||||
args: "run --allow-import --quiet --reload run/import_file_with_colon.ts",
|
||||
output: "run/import_file_with_colon.ts.out",
|
||||
http_server: true,
|
||||
});
|
||||
|
||||
itest!(import_extensionless {
|
||||
args: "run --quiet --reload run/import_extensionless.ts",
|
||||
args: "run --allow-import --quiet --reload run/import_extensionless.ts",
|
||||
output: "run/import_extensionless.ts.out",
|
||||
http_server: true,
|
||||
});
|
||||
|
@ -2195,7 +2202,7 @@ itest!(inline_js_source_map_2_with_inline_contents {
|
|||
// was not commented out. The source line is remapped using source contents that
|
||||
// from the module graph.
|
||||
itest!(inline_js_source_map_with_contents_from_graph {
|
||||
args: "run --quiet run/inline_js_source_map_with_contents_from_graph.js",
|
||||
args: "run --allow-import --quiet run/inline_js_source_map_with_contents_from_graph.js",
|
||||
output: "run/inline_js_source_map_with_contents_from_graph.js.out",
|
||||
exit_code: 1,
|
||||
http_server: true,
|
||||
|
@ -3031,14 +3038,14 @@ mod permissions {
|
|||
});
|
||||
|
||||
itest!(dynamic_import_permissions_remote_remote {
|
||||
args: "run --quiet --reload --allow-net=localhost:4545 dynamic_import/permissions_remote_remote.ts",
|
||||
args: "run --quiet --reload --allow-import=localhost:4545 dynamic_import/permissions_remote_remote.ts",
|
||||
output: "dynamic_import/permissions_remote_remote.ts.out",
|
||||
http_server: true,
|
||||
exit_code: 1,
|
||||
});
|
||||
|
||||
itest!(dynamic_import_permissions_data_remote {
|
||||
args: "run --quiet --reload --allow-net=localhost:4545 dynamic_import/permissions_data_remote.ts",
|
||||
args: "run --quiet --reload --allow-import=localhost:4545 dynamic_import/permissions_data_remote.ts",
|
||||
output: "dynamic_import/permissions_data_remote.ts.out",
|
||||
http_server: true,
|
||||
exit_code: 1,
|
||||
|
@ -3329,7 +3336,7 @@ itest!(no_config_auto_discovery_for_local_script {
|
|||
});
|
||||
|
||||
itest!(config_not_auto_discovered_for_remote_script {
|
||||
args: "run --quiet http://127.0.0.1:4545/run/with_config/server_side_work.ts",
|
||||
args: "run --allow-import --quiet http://127.0.0.1:4545/run/with_config/server_side_work.ts",
|
||||
output_str: Some("ok\n"),
|
||||
http_server: true,
|
||||
});
|
||||
|
@ -3468,6 +3475,7 @@ fn check_local_then_remote() {
|
|||
let output = util::deno_cmd_with_deno_dir(&deno_dir)
|
||||
.current_dir(util::testdata_path())
|
||||
.arg("run")
|
||||
.arg("--allow-import")
|
||||
.arg("--check")
|
||||
.arg("run/remote_type_error/main.ts")
|
||||
.spawn()
|
||||
|
@ -3478,6 +3486,7 @@ fn check_local_then_remote() {
|
|||
let output = util::deno_cmd_with_deno_dir(&deno_dir)
|
||||
.current_dir(util::testdata_path())
|
||||
.arg("run")
|
||||
.arg("--allow-import")
|
||||
.arg("--check=all")
|
||||
.arg("run/remote_type_error/main.ts")
|
||||
.env("NO_COLOR", "1")
|
||||
|
@ -3655,6 +3664,7 @@ fn cache_test() {
|
|||
.env("DENO_DIR", deno_dir.path())
|
||||
.current_dir(util::testdata_path())
|
||||
.arg("cache")
|
||||
.arg("--allow-import=localhost:4545")
|
||||
.arg("--check=all")
|
||||
.arg("-L")
|
||||
.arg("debug")
|
||||
|
@ -3670,6 +3680,7 @@ fn cache_test() {
|
|||
.env("NO_COLOR", "1")
|
||||
.current_dir(util::testdata_path())
|
||||
.arg("run")
|
||||
.arg("--allow-import=localhost:4545")
|
||||
.arg(module_url.to_string())
|
||||
.output()
|
||||
.expect("Failed to spawn script");
|
||||
|
@ -3819,6 +3830,7 @@ fn basic_auth_tokens() {
|
|||
let output = util::deno_cmd()
|
||||
.current_dir(util::root_path())
|
||||
.arg("run")
|
||||
.arg("--allow-import")
|
||||
.arg("http://127.0.0.1:4554/run/001_hello.js")
|
||||
.piped_output()
|
||||
.spawn()
|
||||
|
@ -3840,6 +3852,7 @@ fn basic_auth_tokens() {
|
|||
let output = util::deno_cmd()
|
||||
.current_dir(util::root_path())
|
||||
.arg("run")
|
||||
.arg("--allow-import")
|
||||
.arg("http://127.0.0.1:4554/run/001_hello.js")
|
||||
.env("DENO_AUTH_TOKENS", "testuser123:testpassabc@127.0.0.1:4554")
|
||||
.piped_output()
|
||||
|
@ -4404,7 +4417,7 @@ async fn websocket_server_idletimeout() {
|
|||
}
|
||||
|
||||
itest!(no_lock_flag {
|
||||
args: "run --no-lock run/no_lock_flag/main.ts",
|
||||
args: "run --allow-import --no-lock run/no_lock_flag/main.ts",
|
||||
output: "run/no_lock_flag/main.out",
|
||||
http_server: true,
|
||||
exit_code: 0,
|
||||
|
@ -4563,7 +4576,9 @@ pub fn vendor_dir_config_file() {
|
|||
console.log(returnsHi());"#,
|
||||
);
|
||||
|
||||
let deno_run_cmd = test_context.new_command().args("run --quiet main.ts");
|
||||
let deno_run_cmd = test_context
|
||||
.new_command()
|
||||
.args("run --allow-import --quiet main.ts");
|
||||
deno_run_cmd.run().assert_matches_text("Hi\n");
|
||||
|
||||
assert!(vendor_dir.exists());
|
||||
|
@ -4574,13 +4589,15 @@ console.log(returnsHi());"#,
|
|||
assert!(!vendor_dir.exists());
|
||||
test_context
|
||||
.new_command()
|
||||
.args("cache --quiet --vendor main.ts")
|
||||
.args("cache --allow-import --quiet --vendor main.ts")
|
||||
.run();
|
||||
assert!(vendor_dir.exists());
|
||||
rm_vendor_dir();
|
||||
|
||||
temp_dir.write("deno.json", r#"{ "vendor": true }"#);
|
||||
let cache_command = test_context.new_command().args("cache --quiet main.ts");
|
||||
let cache_command = test_context
|
||||
.new_command()
|
||||
.args("cache --allow-import --quiet main.ts");
|
||||
cache_command.run();
|
||||
|
||||
assert!(vendor_dir.exists());
|
||||
|
@ -4608,7 +4625,7 @@ console.log(returnsHi());"#,
|
|||
test_context
|
||||
.new_command()
|
||||
// http_localhost_4545/subdir/#capitals_c75d7/main.js
|
||||
.args("cache http://localhost:4545/subdir/CAPITALS/main.js")
|
||||
.args("cache --allow-import http://localhost:4545/subdir/CAPITALS/main.js")
|
||||
.run()
|
||||
.skip_output_check();
|
||||
assert_eq!(
|
||||
|
@ -4625,7 +4642,7 @@ console.log(returnsHi());"#,
|
|||
test_context
|
||||
.new_command()
|
||||
// todo(dsherret): seems wrong that we don't auto-discover the config file to get the vendor directory for this
|
||||
.args("run --vendor http://localhost:4545/subdir/CAPITALS/hello_there.ts")
|
||||
.args("run --allow-import --vendor http://localhost:4545/subdir/CAPITALS/hello_there.ts")
|
||||
.run()
|
||||
.assert_matches_text("hello there\n");
|
||||
|
||||
|
@ -5120,21 +5137,23 @@ fn emit_failed_readonly_file_system() {
|
|||
fn handle_invalid_path_error() {
|
||||
let deno_cmd = util::deno_cmd_with_deno_dir(&util::new_deno_dir());
|
||||
let output = deno_cmd.arg("run").arg("file://asdf").output().unwrap();
|
||||
assert!(
|
||||
String::from_utf8_lossy(&output.stderr).contains("Invalid file path.")
|
||||
assert_contains!(
|
||||
String::from_utf8_lossy(&output.stderr),
|
||||
"Invalid file path."
|
||||
);
|
||||
|
||||
let deno_cmd = util::deno_cmd_with_deno_dir(&util::new_deno_dir());
|
||||
let output = deno_cmd.arg("run").arg("/a/b").output().unwrap();
|
||||
assert!(String::from_utf8_lossy(&output.stderr).contains("Module not found"));
|
||||
assert_contains!(String::from_utf8_lossy(&output.stderr), "Module not found");
|
||||
|
||||
let deno_cmd = util::deno_cmd_with_deno_dir(&util::new_deno_dir());
|
||||
let output = deno_cmd.arg("run").arg("//a/b").output().unwrap();
|
||||
assert!(
|
||||
String::from_utf8_lossy(&output.stderr).contains("Invalid file path.")
|
||||
assert_contains!(
|
||||
String::from_utf8_lossy(&output.stderr),
|
||||
"Invalid file path."
|
||||
);
|
||||
|
||||
let deno_cmd = util::deno_cmd_with_deno_dir(&util::new_deno_dir());
|
||||
let output = deno_cmd.arg("run").arg("///a/b").output().unwrap();
|
||||
assert!(String::from_utf8_lossy(&output.stderr).contains("Module not found"));
|
||||
assert_contains!(String::from_utf8_lossy(&output.stderr), "Module not found");
|
||||
}
|
||||
|
|
|
@ -1399,6 +1399,7 @@ async fn run_watch_reload_once() {
|
|||
let mut child = util::deno_cmd()
|
||||
.current_dir(t.path())
|
||||
.arg("run")
|
||||
.arg("--allow-import")
|
||||
.arg("--watch")
|
||||
.arg("--reload")
|
||||
.arg(&file_to_watch)
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
{
|
||||
"args": "bench --quiet check_local_by_default.ts",
|
||||
"args": "bench --allow-import --quiet check_local_by_default.ts",
|
||||
"output": "check_local_by_default.out"
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
{
|
||||
"args": "bench --quiet check_local_by_default2.ts",
|
||||
"args": "bench --allow-import --quiet check_local_by_default2.ts",
|
||||
"output": "check_local_by_default2.out",
|
||||
"exitCode": 1
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
{
|
||||
"args": "cache --quiet check_local_by_default.ts",
|
||||
"args": "cache --quiet --allow-import check_local_by_default.ts",
|
||||
"output": "check_local_by_default.out"
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
{
|
||||
"args": "cache --quiet check_local_by_default2.ts",
|
||||
"args": "cache --quiet --allow-import check_local_by_default2.ts",
|
||||
"output": "check_local_by_default2.out"
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
{
|
||||
"args": "cache --reload --check=all test.ts other.ts",
|
||||
"args": "cache --reload --allow-import --check=all test.ts other.ts",
|
||||
"output": "fetch_multiple.out"
|
||||
}
|
||||
|
|
2
tests/specs/cache/globbing/__test__.jsonc
vendored
2
tests/specs/cache/globbing/__test__.jsonc
vendored
|
@ -1,5 +1,5 @@
|
|||
{
|
||||
"args": "cache *.ts",
|
||||
"args": "cache --allow-import *.ts",
|
||||
"output": "Download http://localhost:4545/echo.ts\n",
|
||||
"exitCode": 0
|
||||
}
|
||||
|
|
2
tests/specs/cache/redirect/__test__.jsonc
vendored
2
tests/specs/cache/redirect/__test__.jsonc
vendored
|
@ -1,4 +1,4 @@
|
|||
{
|
||||
"args": "cache --reload --check=all http://localhost:4548/subdir/redirects/a.ts",
|
||||
"args": "cache --reload --allow-import --check=all http://localhost:4548/subdir/redirects/a.ts",
|
||||
"output": "redirect_cache.out"
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"steps": [{
|
||||
"args": "run --quiet --reload --allow-net --cert RootCA.pem cafile_ts_fetch.ts",
|
||||
"args": "run --quiet --reload --allow-net --allow-import --cert RootCA.pem cafile_ts_fetch.ts",
|
||||
"flaky": true,
|
||||
"output": "cafile_ts_fetch.ts.out"
|
||||
}, {
|
||||
|
@ -8,11 +8,11 @@
|
|||
"flaky": true,
|
||||
"output": "cafile_ts_fetch.ts.out"
|
||||
}, {
|
||||
"args": "info --quiet --cert RootCA.pem https://localhost:5545/cert/cafile_info.ts",
|
||||
"args": "info --quiet --allow-import --cert RootCA.pem https://localhost:5545/cert/cafile_info.ts",
|
||||
"flaky": true,
|
||||
"output": "cafile_info.ts.out"
|
||||
}, {
|
||||
"args": "cache --quiet --cert RootCA.pem http://localhost:4545/cert/cafile_url_imports.ts",
|
||||
"args": "cache --quiet --allow-import --cert RootCA.pem http://localhost:4545/cert/cafile_url_imports.ts",
|
||||
"flaky": true,
|
||||
"output": ""
|
||||
}]
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
{
|
||||
"args": "run --quiet --reload --cert RootCA.pem cafile_url_imports.ts",
|
||||
"args": "run --quiet --reload --allow-import --cert RootCA.pem cafile_url_imports.ts",
|
||||
"flaky": true,
|
||||
"output": "cafile_url_imports.ts.out"
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
{
|
||||
"args": "run --quiet --reload --unsafely-ignore-certificate-errors=localhost cafile_url_imports.ts",
|
||||
"args": "run --quiet --allow-import --reload --unsafely-ignore-certificate-errors=localhost cafile_url_imports.ts",
|
||||
"flaky": true,
|
||||
"output": "cafile_url_imports_unsafe_ssl.ts.out"
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
{
|
||||
"args": "run --quiet --reload --allow-net --unsafely-ignore-certificate-errors=deno.land cafile_url_imports.ts",
|
||||
"args": "run --quiet --reload --allow-import --allow-net --unsafely-ignore-certificate-errors=deno.land cafile_url_imports.ts",
|
||||
"output": "localhost_unsafe_ssl.ts.out",
|
||||
"exitCode": 1
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
{
|
||||
"args": "check --all main.tsx",
|
||||
"args": "check --allow-import --all main.tsx",
|
||||
"output": "main.out"
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
{
|
||||
"args": "check --all main.tsx",
|
||||
"args": "check --allow-import --all main.tsx",
|
||||
"output": "main.out"
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
{
|
||||
"args": "check --all main.ts",
|
||||
"args": "check --allow-import --all main.ts",
|
||||
"output": "Download [WILDLINE]\nCheck [WILDLINE]\n"
|
||||
}
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
{
|
||||
"tempDir": true,
|
||||
"steps": [
|
||||
{
|
||||
"args": "compile --unstable-kv -A --output out main.ts",
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
{
|
||||
"args": "doc --reload types_header.ts",
|
||||
"args": "doc --allow-import --reload types_header.ts",
|
||||
"output": "types_header.out"
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
{
|
||||
"args": "doc --reload http://127.0.0.1:4545/xTypeScriptTypes.js",
|
||||
"args": "doc --allow-import --reload http://127.0.0.1:4545/xTypeScriptTypes.js",
|
||||
"output": "types_header.out"
|
||||
}
|
||||
|
|
4
tests/specs/info/flag_script_jsx/__test__.jsonc
Normal file
4
tests/specs/info/flag_script_jsx/__test__.jsonc
Normal file
|
@ -0,0 +1,4 @@
|
|||
{
|
||||
"args": "info --allow-import http://127.0.0.1:4545/run/048_media_types_jsx.ts",
|
||||
"output": "049_info_flag_script_jsx.out"
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue