diff --git a/cli/args/mod.rs b/cli/args/mod.rs index d8f5531015..927f43e85a 100644 --- a/cli/args/mod.rs +++ b/cli/args/mod.rs @@ -578,6 +578,7 @@ fn discover_npmrc( let resolved = npmrc .as_resolved(npm_registry_url()) .context("Failed to resolve .npmrc options")?; + log::debug!(".npmrc found at: '{}'", path.display()); Ok(Arc::new(resolved)) } diff --git a/cli/cache/mod.rs b/cli/cache/mod.rs index ded163b4e4..bf8f1b1f0b 100644 --- a/cli/cache/mod.rs +++ b/cli/cache/mod.rs @@ -378,6 +378,7 @@ impl Loader for FetchCacher { } else { FetchPermissionsOptionRef::DynamicContainer(&permissions) }, + maybe_auth: None, maybe_accept: None, maybe_cache_setting: maybe_cache_setting.as_ref(), }, diff --git a/cli/file_fetcher.rs b/cli/file_fetcher.rs index e92aca5420..95d778f0bb 100644 --- a/cli/file_fetcher.rs +++ b/cli/file_fetcher.rs @@ -24,6 +24,7 @@ use deno_graph::source::LoaderChecksum; use deno_path_util::url_to_file_path; use deno_runtime::deno_permissions::PermissionsContainer; use deno_runtime::deno_web::BlobStore; +use http::header; use log::debug; use std::borrow::Cow; use std::collections::HashMap; @@ -181,6 +182,7 @@ pub enum FetchPermissionsOptionRef<'a> { pub struct FetchOptions<'a> { pub specifier: &'a ModuleSpecifier, pub permissions: FetchPermissionsOptionRef<'a>, + pub maybe_auth: Option<(header::HeaderName, header::HeaderValue)>, pub maybe_accept: Option<&'a str>, pub maybe_cache_setting: Option<&'a CacheSetting>, } @@ -350,6 +352,7 @@ impl FileFetcher { maybe_accept: Option<&str>, cache_setting: &CacheSetting, maybe_checksum: Option<&LoaderChecksum>, + maybe_auth: Option<(header::HeaderName, header::HeaderValue)>, ) -> Result { debug!( "FileFetcher::fetch_remote_no_follow - specifier: {}", @@ -442,6 +445,7 @@ impl FileFetcher { .as_ref() .map(|(_, etag)| etag.clone()), maybe_auth_token: maybe_auth_token.clone(), + maybe_auth: maybe_auth.clone(), maybe_progress_guard: maybe_progress_guard.as_ref(), }) .await? @@ -538,7 +542,18 @@ impl FileFetcher { specifier: &ModuleSpecifier, ) -> Result { self - .fetch_inner(specifier, FetchPermissionsOptionRef::AllowAll) + .fetch_inner(specifier, None, FetchPermissionsOptionRef::AllowAll) + .await + } + + #[inline(always)] + pub async fn fetch_bypass_permissions_with_maybe_auth( + &self, + specifier: &ModuleSpecifier, + maybe_auth: Option<(header::HeaderName, header::HeaderValue)>, + ) -> Result { + self + .fetch_inner(specifier, maybe_auth, FetchPermissionsOptionRef::AllowAll) .await } @@ -552,6 +567,7 @@ impl FileFetcher { self .fetch_inner( specifier, + None, FetchPermissionsOptionRef::StaticContainer(permissions), ) .await @@ -560,12 +576,14 @@ impl FileFetcher { async fn fetch_inner( &self, specifier: &ModuleSpecifier, + maybe_auth: Option<(header::HeaderName, header::HeaderValue)>, permissions: FetchPermissionsOptionRef<'_>, ) -> Result { self .fetch_with_options(FetchOptions { specifier, permissions, + maybe_auth, maybe_accept: None, maybe_cache_setting: None, }) @@ -585,12 +603,14 @@ impl FileFetcher { max_redirect: usize, ) -> Result { let mut specifier = Cow::Borrowed(options.specifier); + let mut maybe_auth = options.maybe_auth.clone(); for _ in 0..=max_redirect { match self .fetch_no_follow_with_options(FetchNoFollowOptions { fetch_options: FetchOptions { specifier: &specifier, permissions: options.permissions, + maybe_auth: maybe_auth.clone(), maybe_accept: options.maybe_accept, maybe_cache_setting: options.maybe_cache_setting, }, @@ -602,6 +622,10 @@ impl FileFetcher { return Ok(file); } FileOrRedirect::Redirect(redirect_specifier) => { + // If we were redirected to another origin, don't send the auth header anymore. + if redirect_specifier.origin() != specifier.origin() { + maybe_auth = None; + } specifier = Cow::Owned(redirect_specifier); } } @@ -666,6 +690,7 @@ impl FileFetcher { options.maybe_accept, options.maybe_cache_setting.unwrap_or(&self.cache_setting), maybe_checksum, + options.maybe_auth, ) .await } @@ -756,6 +781,7 @@ mod tests { FetchOptions { specifier, permissions: FetchPermissionsOptionRef::AllowAll, + maybe_auth: None, maybe_accept: None, maybe_cache_setting: Some(&file_fetcher.cache_setting), }, @@ -1255,6 +1281,7 @@ mod tests { FetchOptions { specifier: &specifier, permissions: FetchPermissionsOptionRef::AllowAll, + maybe_auth: None, maybe_accept: None, maybe_cache_setting: Some(&file_fetcher.cache_setting), }, @@ -1268,6 +1295,7 @@ mod tests { FetchOptions { specifier: &specifier, permissions: FetchPermissionsOptionRef::AllowAll, + maybe_auth: None, maybe_accept: None, maybe_cache_setting: Some(&file_fetcher.cache_setting), }, diff --git a/cli/http_util.rs b/cli/http_util.rs index 9c9ae9e413..4b17936d68 100644 --- a/cli/http_util.rs +++ b/cli/http_util.rs @@ -19,6 +19,7 @@ use deno_runtime::deno_fetch; use deno_runtime::deno_fetch::create_http_client; use deno_runtime::deno_fetch::CreateHttpClientOptions; use deno_runtime::deno_tls::RootCertStoreProvider; +use http::header; use http::header::HeaderName; use http::header::HeaderValue; use http::header::ACCEPT; @@ -204,6 +205,7 @@ pub struct FetchOnceArgs<'a> { pub maybe_accept: Option, pub maybe_etag: Option, pub maybe_auth_token: Option, + pub maybe_auth: Option<(header::HeaderName, header::HeaderValue)>, pub maybe_progress_guard: Option<&'a UpdateGuard>, } @@ -382,6 +384,8 @@ impl HttpClient { request .headers_mut() .insert(AUTHORIZATION, authorization_val); + } else if let Some((header, value)) = args.maybe_auth { + request.headers_mut().insert(header, value); } if let Some(accept) = args.maybe_accept { let accepts_val = HeaderValue::from_str(&accept)?; @@ -792,6 +796,7 @@ mod test { maybe_etag: None, maybe_auth_token: None, maybe_progress_guard: None, + maybe_auth: None, }) .await; if let Ok(FetchOnceResult::Code(body, headers)) = result { @@ -818,6 +823,7 @@ mod test { maybe_etag: None, maybe_auth_token: None, maybe_progress_guard: None, + maybe_auth: None, }) .await; if let Ok(FetchOnceResult::Code(body, headers)) = result { @@ -845,6 +851,7 @@ mod test { maybe_etag: None, maybe_auth_token: None, maybe_progress_guard: None, + maybe_auth: None, }) .await; if let Ok(FetchOnceResult::Code(body, headers)) = result { @@ -866,6 +873,7 @@ mod test { maybe_etag: Some("33a64df551425fcc55e".to_string()), maybe_auth_token: None, maybe_progress_guard: None, + maybe_auth: None, }) .await; assert_eq!(res.unwrap(), FetchOnceResult::NotModified); @@ -885,6 +893,7 @@ mod test { maybe_etag: None, maybe_auth_token: None, maybe_progress_guard: None, + maybe_auth: None, }) .await; if let Ok(FetchOnceResult::Code(body, headers)) = result { @@ -914,6 +923,7 @@ mod test { maybe_etag: None, maybe_auth_token: None, maybe_progress_guard: None, + maybe_auth: None, }) .await; if let Ok(FetchOnceResult::Code(body, _)) = result { @@ -939,6 +949,7 @@ mod test { maybe_etag: None, maybe_auth_token: None, maybe_progress_guard: None, + maybe_auth: None, }) .await; if let Ok(FetchOnceResult::Redirect(url, _)) = result { @@ -974,6 +985,7 @@ mod test { maybe_etag: None, maybe_auth_token: None, maybe_progress_guard: None, + maybe_auth: None, }) .await; if let Ok(FetchOnceResult::Code(body, headers)) = result { @@ -1021,6 +1033,7 @@ mod test { maybe_etag: None, maybe_auth_token: None, maybe_progress_guard: None, + maybe_auth: None, }) .await; @@ -1083,6 +1096,7 @@ mod test { maybe_etag: None, maybe_auth_token: None, maybe_progress_guard: None, + maybe_auth: None, }) .await; @@ -1136,6 +1150,7 @@ mod test { maybe_etag: None, maybe_auth_token: None, maybe_progress_guard: None, + maybe_auth: None, }) .await; if let Ok(FetchOnceResult::Code(body, headers)) = result { @@ -1177,6 +1192,7 @@ mod test { maybe_etag: None, maybe_auth_token: None, maybe_progress_guard: None, + maybe_auth: None, }) .await; if let Ok(FetchOnceResult::Code(body, headers)) = result { @@ -1199,6 +1215,7 @@ mod test { maybe_etag: Some("33a64df551425fcc55e".to_string()), maybe_auth_token: None, maybe_progress_guard: None, + maybe_auth: None, }) .await; assert_eq!(res.unwrap(), FetchOnceResult::NotModified); @@ -1233,6 +1250,7 @@ mod test { maybe_etag: None, maybe_auth_token: None, maybe_progress_guard: None, + maybe_auth: None, }) .await; if let Ok(FetchOnceResult::Code(body, headers)) = result { @@ -1262,6 +1280,7 @@ mod test { maybe_etag: None, maybe_auth_token: None, maybe_progress_guard: None, + maybe_auth: None, }) .await; assert!(result.is_err()); @@ -1283,6 +1302,7 @@ mod test { maybe_etag: None, maybe_auth_token: None, maybe_progress_guard: None, + maybe_auth: None, }) .await; @@ -1306,6 +1326,7 @@ mod test { maybe_etag: None, maybe_auth_token: None, maybe_progress_guard: None, + maybe_auth: None, }) .await; diff --git a/cli/lsp/npm.rs b/cli/lsp/npm.rs index 8bdeb7e7d8..2decfc3429 100644 --- a/cli/lsp/npm.rs +++ b/cli/lsp/npm.rs @@ -4,6 +4,7 @@ use dashmap::DashMap; use deno_core::anyhow::anyhow; use deno_core::error::AnyError; use deno_core::serde_json; +use deno_npm::npm_rc::NpmRc; use deno_semver::package::PackageNv; use deno_semver::Version; use serde::Deserialize; @@ -25,7 +26,10 @@ pub struct CliNpmSearchApi { impl CliNpmSearchApi { pub fn new(file_fetcher: Arc) -> Self { - let resolver = NpmFetchResolver::new(file_fetcher.clone()); + let resolver = NpmFetchResolver::new( + file_fetcher.clone(), + Arc::new(NpmRc::default().as_resolved(npm_registry_url()).unwrap()), + ); Self { file_fetcher, resolver, diff --git a/cli/lsp/registries.rs b/cli/lsp/registries.rs index 5f7ce00823..ade353e683 100644 --- a/cli/lsp/registries.rs +++ b/cli/lsp/registries.rs @@ -482,6 +482,7 @@ impl ModuleRegistry { .fetch_with_options(FetchOptions { specifier: &specifier, permissions: FetchPermissionsOptionRef::AllowAll, + maybe_auth: None, maybe_accept: Some("application/vnd.deno.reg.v2+json, application/vnd.deno.reg.v1+json;q=0.9, application/json;q=0.8"), maybe_cache_setting: None, }) diff --git a/cli/npm/managed/cache/mod.rs b/cli/npm/managed/cache/mod.rs index fa0e8c8a59..aaec486681 100644 --- a/cli/npm/managed/cache/mod.rs +++ b/cli/npm/managed/cache/mod.rs @@ -26,7 +26,7 @@ use crate::cache::CACHE_PERM; use crate::util::fs::atomic_write_file_with_retries; use crate::util::fs::hard_link_dir_recursive; -mod registry_info; +pub mod registry_info; mod tarball; mod tarball_extract; diff --git a/cli/npm/managed/cache/registry_info.rs b/cli/npm/managed/cache/registry_info.rs index 6c4a7503b5..6d39d3c13f 100644 --- a/cli/npm/managed/cache/registry_info.rs +++ b/cli/npm/managed/cache/registry_info.rs @@ -84,7 +84,7 @@ impl RegistryInfoDownloader { self.load_package_info_inner(name).await.with_context(|| { format!( "Error getting response at {} for package \"{}\"", - self.get_package_url(name), + get_package_url(&self.npmrc, name), name ) }) @@ -190,7 +190,7 @@ impl RegistryInfoDownloader { fn create_load_future(self: &Arc, name: &str) -> LoadFuture { let downloader = self.clone(); - let package_url = self.get_package_url(name); + let package_url = get_package_url(&self.npmrc, name); let registry_config = self.npmrc.get_registry_config(name); let maybe_auth_header = match maybe_auth_header_for_npm_registry(registry_config) { @@ -239,36 +239,36 @@ impl RegistryInfoDownloader { .map(|r| r.map_err(Arc::new)) .boxed_local() } - - fn get_package_url(&self, name: &str) -> Url { - let registry_url = self.npmrc.get_registry_url(name); - // The '/' character in scoped package names "@scope/name" must be - // encoded for older third party registries. Newer registries and - // npm itself support both ways - // - encoded: https://registry.npmjs.org/@rollup%2fplugin-json - // - non-ecoded: https://registry.npmjs.org/@rollup/plugin-json - // To support as many third party registries as possible we'll - // always encode the '/' character. - - // list of all characters used in npm packages: - // !, ', (, ), *, -, ., /, [0-9], @, [A-Za-z], _, ~ - const ASCII_SET: percent_encoding::AsciiSet = - percent_encoding::NON_ALPHANUMERIC - .remove(b'!') - .remove(b'\'') - .remove(b'(') - .remove(b')') - .remove(b'*') - .remove(b'-') - .remove(b'.') - .remove(b'@') - .remove(b'_') - .remove(b'~'); - let name = percent_encoding::utf8_percent_encode(name, &ASCII_SET); - registry_url - // Ensure that scoped package name percent encoding is lower cased - // to match npm. - .join(&name.to_string().replace("%2F", "%2f")) - .unwrap() - } +} + +pub fn get_package_url(npmrc: &ResolvedNpmRc, name: &str) -> Url { + let registry_url = npmrc.get_registry_url(name); + // The '/' character in scoped package names "@scope/name" must be + // encoded for older third party registries. Newer registries and + // npm itself support both ways + // - encoded: https://registry.npmjs.org/@rollup%2fplugin-json + // - non-ecoded: https://registry.npmjs.org/@rollup/plugin-json + // To support as many third party registries as possible we'll + // always encode the '/' character. + + // list of all characters used in npm packages: + // !, ', (, ), *, -, ., /, [0-9], @, [A-Za-z], _, ~ + const ASCII_SET: percent_encoding::AsciiSet = + percent_encoding::NON_ALPHANUMERIC + .remove(b'!') + .remove(b'\'') + .remove(b'(') + .remove(b')') + .remove(b'*') + .remove(b'-') + .remove(b'.') + .remove(b'@') + .remove(b'_') + .remove(b'~'); + let name = percent_encoding::utf8_percent_encode(name, &ASCII_SET); + registry_url + // Ensure that scoped package name percent encoding is lower cased + // to match npm. + .join(&name.to_string().replace("%2F", "%2f")) + .unwrap() } diff --git a/cli/npm/managed/mod.rs b/cli/npm/managed/mod.rs index ec50a9c65a..d0880557fe 100644 --- a/cli/npm/managed/mod.rs +++ b/cli/npm/managed/mod.rs @@ -55,7 +55,7 @@ use super::CliNpmResolver; use super::InnerCliNpmResolverRef; use super::ResolvePkgFolderFromDenoReqError; -mod cache; +pub mod cache; mod registry; mod resolution; mod resolvers; diff --git a/cli/npm/mod.rs b/cli/npm/mod.rs index 53baaf77b4..f48f7a7405 100644 --- a/cli/npm/mod.rs +++ b/cli/npm/mod.rs @@ -8,10 +8,12 @@ use std::path::Path; use std::path::PathBuf; use std::sync::Arc; +use common::maybe_auth_header_for_npm_registry; use dashmap::DashMap; use deno_ast::ModuleSpecifier; use deno_core::error::AnyError; use deno_core::serde_json; +use deno_npm::npm_rc::ResolvedNpmRc; use deno_npm::registry::NpmPackageInfo; use deno_resolver::npm::ByonmNpmResolver; use deno_resolver::npm::ByonmResolvePkgFolderFromDenoReqError; @@ -19,10 +21,10 @@ use deno_runtime::deno_node::NodeRequireResolver; use deno_runtime::ops::process::NpmProcessStateProvider; use deno_semver::package::PackageNv; use deno_semver::package::PackageReq; +use managed::cache::registry_info::get_package_url; use node_resolver::NpmResolver; use thiserror::Error; -use crate::args::npm_registry_url; use crate::file_fetcher::FileFetcher; pub use self::byonm::CliByonmNpmResolver; @@ -115,14 +117,19 @@ pub struct NpmFetchResolver { nv_by_req: DashMap>, info_by_name: DashMap>>, file_fetcher: Arc, + npmrc: Arc, } impl NpmFetchResolver { - pub fn new(file_fetcher: Arc) -> Self { + pub fn new( + file_fetcher: Arc, + npmrc: Arc, + ) -> Self { Self { nv_by_req: Default::default(), info_by_name: Default::default(), file_fetcher, + npmrc, } } @@ -157,11 +164,21 @@ impl NpmFetchResolver { return info.value().clone(); } let fetch_package_info = || async { - let info_url = npm_registry_url().join(name).ok()?; + let info_url = get_package_url(&self.npmrc, name); let file_fetcher = self.file_fetcher.clone(); + let registry_config = self.npmrc.get_registry_config(name); + // TODO(bartlomieju): this should error out, not use `.ok()`. + let maybe_auth_header = + maybe_auth_header_for_npm_registry(registry_config).ok()?; // spawn due to the lsp's `Send` requirement let file = deno_core::unsync::spawn(async move { - file_fetcher.fetch_bypass_permissions(&info_url).await.ok() + file_fetcher + .fetch_bypass_permissions_with_maybe_auth( + &info_url, + maybe_auth_header, + ) + .await + .ok() }) .await .ok()??; diff --git a/cli/tools/registry/pm.rs b/cli/tools/registry/pm.rs index 2060b9a13f..d1be901d67 100644 --- a/cli/tools/registry/pm.rs +++ b/cli/tools/registry/pm.rs @@ -367,10 +367,14 @@ pub async fn add( Default::default(), None, ); + + let npmrc = cli_factory.cli_options().unwrap().npmrc(); + deps_file_fetcher.set_download_log_level(log::Level::Trace); let deps_file_fetcher = Arc::new(deps_file_fetcher); let jsr_resolver = Arc::new(JsrFetchResolver::new(deps_file_fetcher.clone())); - let npm_resolver = Arc::new(NpmFetchResolver::new(deps_file_fetcher)); + let npm_resolver = + Arc::new(NpmFetchResolver::new(deps_file_fetcher, npmrc.clone())); let mut selected_packages = Vec::with_capacity(add_flags.packages.len()); let mut package_reqs = Vec::with_capacity(add_flags.packages.len()); diff --git a/tests/registry/npm-private3/@denotest3/basic/1.0.0/main.d.mts b/tests/registry/npm-private3/@denotest3/basic/1.0.0/main.d.mts new file mode 100644 index 0000000000..29da1e6d7b --- /dev/null +++ b/tests/registry/npm-private3/@denotest3/basic/1.0.0/main.d.mts @@ -0,0 +1,3 @@ +export declare function setValue(val: number): void; +export declare function getValue(): number; +export declare const url: string; diff --git a/tests/registry/npm-private3/@denotest3/basic/1.0.0/main.mjs b/tests/registry/npm-private3/@denotest3/basic/1.0.0/main.mjs new file mode 100644 index 0000000000..0a44f75859 --- /dev/null +++ b/tests/registry/npm-private3/@denotest3/basic/1.0.0/main.mjs @@ -0,0 +1,11 @@ +let value = 0; + +export function setValue(newValue) { + value = newValue; +} + +export function getValue() { + return value; +} + +export const url = import.meta.url; diff --git a/tests/registry/npm-private3/@denotest3/basic/1.0.0/other.mjs b/tests/registry/npm-private3/@denotest3/basic/1.0.0/other.mjs new file mode 100644 index 0000000000..00ed99da45 --- /dev/null +++ b/tests/registry/npm-private3/@denotest3/basic/1.0.0/other.mjs @@ -0,0 +1,3 @@ +export function hello() { + return "hello, world!"; +} \ No newline at end of file diff --git a/tests/registry/npm-private3/@denotest3/basic/1.0.0/package.json b/tests/registry/npm-private3/@denotest3/basic/1.0.0/package.json new file mode 100644 index 0000000000..ce6ea33830 --- /dev/null +++ b/tests/registry/npm-private3/@denotest3/basic/1.0.0/package.json @@ -0,0 +1,7 @@ +{ + "name": "@denotest3/basic", + "version": "1.0.0", + "type": "module", + "main": "main.mjs", + "types": "main.d.mts" +} diff --git a/tests/specs/npm/npmrc_install_arg/.npmrc b/tests/specs/npm/npmrc_install_arg/.npmrc new file mode 100644 index 0000000000..de3704b924 --- /dev/null +++ b/tests/specs/npm/npmrc_install_arg/.npmrc @@ -0,0 +1,2 @@ +@denotest:registry=http://localhost:4261/ +//localhost:4261/:_authToken=private-reg-token diff --git a/tests/specs/npm/npmrc_install_arg/__test__.jsonc b/tests/specs/npm/npmrc_install_arg/__test__.jsonc new file mode 100644 index 0000000000..f34cfe116a --- /dev/null +++ b/tests/specs/npm/npmrc_install_arg/__test__.jsonc @@ -0,0 +1,23 @@ +{ + "tempDir": true, + "tests": { + "deno_install_add": { + "steps": [{ + "args": "install npm:@denotest/basic", + "output": "install.out" + }, { + "args": "run -A main.js", + "output": "main.out" + }] + }, + "deno_add": { + "steps": [{ + "args": "add npm:@denotest/basic", + "output": "add.out" + }, { + "args": "run -A main.js", + "output": "main.out" + }] + } + } +} diff --git a/tests/specs/npm/npmrc_install_arg/add.out b/tests/specs/npm/npmrc_install_arg/add.out new file mode 100644 index 0000000000..11948e54d5 --- /dev/null +++ b/tests/specs/npm/npmrc_install_arg/add.out @@ -0,0 +1,4 @@ +Add npm:@denotest/basic@1.0.0 +Download http://localhost:4261/@denotest%2fbasic +Download http://localhost:4261/@denotest/basic/1.0.0.tgz +Initialize @denotest/basic@1.0.0 diff --git a/tests/specs/npm/npmrc_install_arg/install.out b/tests/specs/npm/npmrc_install_arg/install.out new file mode 100644 index 0000000000..11948e54d5 --- /dev/null +++ b/tests/specs/npm/npmrc_install_arg/install.out @@ -0,0 +1,4 @@ +Add npm:@denotest/basic@1.0.0 +Download http://localhost:4261/@denotest%2fbasic +Download http://localhost:4261/@denotest/basic/1.0.0.tgz +Initialize @denotest/basic@1.0.0 diff --git a/tests/specs/npm/npmrc_install_arg/main.js b/tests/specs/npm/npmrc_install_arg/main.js new file mode 100644 index 0000000000..e8ccf7611c --- /dev/null +++ b/tests/specs/npm/npmrc_install_arg/main.js @@ -0,0 +1,5 @@ +import { getValue, setValue } from "@denotest/basic"; + +console.log(getValue()); +setValue(42); +console.log(getValue()); diff --git a/tests/specs/npm/npmrc_install_arg/main.out b/tests/specs/npm/npmrc_install_arg/main.out new file mode 100644 index 0000000000..dcd912c89f --- /dev/null +++ b/tests/specs/npm/npmrc_install_arg/main.out @@ -0,0 +1,2 @@ +0 +42 diff --git a/tests/specs/npm/npmrc_install_arg/package.json b/tests/specs/npm/npmrc_install_arg/package.json new file mode 100644 index 0000000000..c1318b361a --- /dev/null +++ b/tests/specs/npm/npmrc_install_arg/package.json @@ -0,0 +1,5 @@ +{ + "name": "npmrc_test", + "version": "0.0.1", + "dependencies": {} +} diff --git a/tests/specs/npm/npmrc_no_auth/.npmrc b/tests/specs/npm/npmrc_no_auth/.npmrc new file mode 100644 index 0000000000..860a7c3d9a --- /dev/null +++ b/tests/specs/npm/npmrc_no_auth/.npmrc @@ -0,0 +1 @@ +@denotest3:registry=http://localhost:4263/ diff --git a/tests/specs/npm/npmrc_no_auth/__test__.jsonc b/tests/specs/npm/npmrc_no_auth/__test__.jsonc new file mode 100644 index 0000000000..efd04f0e46 --- /dev/null +++ b/tests/specs/npm/npmrc_no_auth/__test__.jsonc @@ -0,0 +1,23 @@ +{ + "tempDir": true, + "tests": { + "deno_install_arg": { + "steps": [{ + "args": "install npm:@denotest3/basic", + "output": "install.out" + }, { + "args": "run -A main.js", + "output": "main.out" + }] + }, + "deno_add_arg": { + "steps": [{ + "args": "add npm:@denotest3/basic", + "output": "add.out" + }, { + "args": "run -A main.js", + "output": "main.out" + }] + } + } +} diff --git a/tests/specs/npm/npmrc_no_auth/add.out b/tests/specs/npm/npmrc_no_auth/add.out new file mode 100644 index 0000000000..31b34da13f --- /dev/null +++ b/tests/specs/npm/npmrc_no_auth/add.out @@ -0,0 +1,4 @@ +Add npm:@denotest3/basic@1.0.0 +Download http://localhost:4263/@denotest3%2fbasic +Download http://localhost:4263/@denotest3/basic/1.0.0.tgz +Initialize @denotest3/basic@1.0.0 diff --git a/tests/specs/npm/npmrc_no_auth/install.out b/tests/specs/npm/npmrc_no_auth/install.out new file mode 100644 index 0000000000..31b34da13f --- /dev/null +++ b/tests/specs/npm/npmrc_no_auth/install.out @@ -0,0 +1,4 @@ +Add npm:@denotest3/basic@1.0.0 +Download http://localhost:4263/@denotest3%2fbasic +Download http://localhost:4263/@denotest3/basic/1.0.0.tgz +Initialize @denotest3/basic@1.0.0 diff --git a/tests/specs/npm/npmrc_no_auth/main.js b/tests/specs/npm/npmrc_no_auth/main.js new file mode 100644 index 0000000000..22713bb0da --- /dev/null +++ b/tests/specs/npm/npmrc_no_auth/main.js @@ -0,0 +1,5 @@ +import { getValue, setValue } from "@denotest3/basic"; + +console.log(getValue()); +setValue(42); +console.log(getValue()); diff --git a/tests/specs/npm/npmrc_no_auth/main.out b/tests/specs/npm/npmrc_no_auth/main.out new file mode 100644 index 0000000000..dcd912c89f --- /dev/null +++ b/tests/specs/npm/npmrc_no_auth/main.out @@ -0,0 +1,2 @@ +0 +42 diff --git a/tests/specs/npm/npmrc_no_auth/package.json b/tests/specs/npm/npmrc_no_auth/package.json new file mode 100644 index 0000000000..dddaaac464 --- /dev/null +++ b/tests/specs/npm/npmrc_no_auth/package.json @@ -0,0 +1,6 @@ +{ + "name": "npmrc_test", + "version": "0.0.1", + "dependencies": { + } +} diff --git a/tests/specs/npm/npmrc_no_auth_install/.npmrc b/tests/specs/npm/npmrc_no_auth_install/.npmrc new file mode 100644 index 0000000000..860a7c3d9a --- /dev/null +++ b/tests/specs/npm/npmrc_no_auth_install/.npmrc @@ -0,0 +1 @@ +@denotest3:registry=http://localhost:4263/ diff --git a/tests/specs/npm/npmrc_no_auth_install/__test__.jsonc b/tests/specs/npm/npmrc_no_auth_install/__test__.jsonc new file mode 100644 index 0000000000..56a598e3b9 --- /dev/null +++ b/tests/specs/npm/npmrc_no_auth_install/__test__.jsonc @@ -0,0 +1,14 @@ +{ + "tempDir": true, + "tests": { + "deno_install_arg": { + "steps": [{ + "args": "install", + "output": "install.out" + }, { + "args": "run -A main.js", + "output": "main.out" + }] + } + } +} diff --git a/tests/specs/npm/npmrc_no_auth_install/install.out b/tests/specs/npm/npmrc_no_auth_install/install.out new file mode 100644 index 0000000000..b82747af79 --- /dev/null +++ b/tests/specs/npm/npmrc_no_auth_install/install.out @@ -0,0 +1,3 @@ +Download http://localhost:4263/@denotest3%2fbasic +Download http://localhost:4263/@denotest3/basic/1.0.0.tgz +Initialize @denotest3/basic@1.0.0 diff --git a/tests/specs/npm/npmrc_no_auth_install/main.js b/tests/specs/npm/npmrc_no_auth_install/main.js new file mode 100644 index 0000000000..22713bb0da --- /dev/null +++ b/tests/specs/npm/npmrc_no_auth_install/main.js @@ -0,0 +1,5 @@ +import { getValue, setValue } from "@denotest3/basic"; + +console.log(getValue()); +setValue(42); +console.log(getValue()); diff --git a/tests/specs/npm/npmrc_no_auth_install/main.out b/tests/specs/npm/npmrc_no_auth_install/main.out new file mode 100644 index 0000000000..dcd912c89f --- /dev/null +++ b/tests/specs/npm/npmrc_no_auth_install/main.out @@ -0,0 +1,2 @@ +0 +42 diff --git a/tests/specs/npm/npmrc_no_auth_install/package.json b/tests/specs/npm/npmrc_no_auth_install/package.json new file mode 100644 index 0000000000..2d4fb15bae --- /dev/null +++ b/tests/specs/npm/npmrc_no_auth_install/package.json @@ -0,0 +1,7 @@ +{ + "name": "npmrc_test", + "version": "0.0.1", + "dependencies": { + "@denotest3/basic": "1.0.0" + } +} diff --git a/tests/util/server/src/lib.rs b/tests/util/server/src/lib.rs index 88e8287e08..e4a2cc02e3 100644 --- a/tests/util/server/src/lib.rs +++ b/tests/util/server/src/lib.rs @@ -307,7 +307,7 @@ async fn get_tcp_listener_stream( futures::stream::select_all(listeners) } -pub const TEST_SERVERS_COUNT: usize = 30; +pub const TEST_SERVERS_COUNT: usize = 32; #[derive(Default)] struct HttpServerCount { @@ -360,6 +360,7 @@ impl Default for HttpServerStarter { let mut ready_count = 0; for maybe_line in lines { if let Ok(line) = maybe_line { + eprintln!("LINE: {}", line); if line.starts_with("ready:") { ready_count += 1; } diff --git a/tests/util/server/src/npm.rs b/tests/util/server/src/npm.rs index f1c341738a..4b17b95f72 100644 --- a/tests/util/server/src/npm.rs +++ b/tests/util/server/src/npm.rs @@ -18,6 +18,7 @@ use crate::PathRef; pub const DENOTEST_SCOPE_NAME: &str = "@denotest"; pub const DENOTEST2_SCOPE_NAME: &str = "@denotest2"; +pub const DENOTEST3_SCOPE_NAME: &str = "@denotest3"; pub static PUBLIC_TEST_NPM_REGISTRY: Lazy = Lazy::new(|| { TestNpmRegistry::new( @@ -54,6 +55,18 @@ pub static PRIVATE_TEST_NPM_REGISTRY_2: Lazy = ) }); +pub static PRIVATE_TEST_NPM_REGISTRY_3: Lazy = + Lazy::new(|| { + TestNpmRegistry::new( + NpmRegistryKind::Private, + &format!( + "http://localhost:{}", + crate::servers::PRIVATE_NPM_REGISTRY_3_PORT + ), + "npm-private3", + ) + }); + pub enum NpmRegistryKind { Public, Private, @@ -90,6 +103,7 @@ impl TestNpmRegistry { } pub fn root_dir(&self) -> PathRef { + eprintln!("root {}", self.local_path); tests_path().join("registry").join(&self.local_path) } @@ -106,6 +120,7 @@ impl TestNpmRegistry { } pub fn registry_file(&self, name: &str) -> Result>> { + eprintln!("registry file {}", name); self.get_package_property(name, |p| p.registry_file.as_bytes().to_vec()) } @@ -123,6 +138,7 @@ impl TestNpmRegistry { package_name: &str, func: impl FnOnce(&CustomNpmPackage) -> TResult, ) -> Result> { + eprintln!("get package property {}", package_name); // it's ok if multiple threads race here as they will do the same work twice if !self.cache.lock().contains_key(package_name) { match get_npm_package(&self.hostname, &self.local_path, package_name)? { @@ -139,6 +155,7 @@ impl TestNpmRegistry { &self, uri_path: &'s str, ) -> Option<(&'s str, &'s str)> { + eprintln!("GEETT {}", uri_path); let prefix1 = format!("/{}/", DENOTEST_SCOPE_NAME); let prefix2 = format!("/{}%2f", DENOTEST_SCOPE_NAME); @@ -161,6 +178,17 @@ impl TestNpmRegistry { return Some((DENOTEST2_SCOPE_NAME, package_name_with_path)); } + let prefix1 = format!("/{}/", DENOTEST3_SCOPE_NAME); + let prefix2 = format!("/{}%2f", DENOTEST3_SCOPE_NAME); + + let maybe_package_name_with_path = uri_path + .strip_prefix(&prefix1) + .or_else(|| uri_path.strip_prefix(&prefix2)); + + if let Some(package_name_with_path) = maybe_package_name_with_path { + return Some((DENOTEST3_SCOPE_NAME, package_name_with_path)); + } + None } } @@ -170,6 +198,10 @@ fn get_npm_package( local_path: &str, package_name: &str, ) -> Result> { + eprintln!( + "get npm package {} {} {}", + registry_hostname, local_path, package_name + ); let registry_hostname = if package_name == "@denotest/tarballs-privateserver2" { "http://localhost:4262" diff --git a/tests/util/server/src/servers/mod.rs b/tests/util/server/src/servers/mod.rs index 3e18aafce4..3a9c440104 100644 --- a/tests/util/server/src/servers/mod.rs +++ b/tests/util/server/src/servers/mod.rs @@ -91,6 +91,7 @@ const PROVENANCE_MOCK_SERVER_PORT: u16 = 4251; pub(crate) const PUBLIC_NPM_REGISTRY_PORT: u16 = 4260; pub(crate) const PRIVATE_NPM_REGISTRY_1_PORT: u16 = 4261; pub(crate) const PRIVATE_NPM_REGISTRY_2_PORT: u16 = 4262; +pub(crate) const PRIVATE_NPM_REGISTRY_3_PORT: u16 = 4263; // Use the single-threaded scheduler. The hyper server is used as a point of // comparison for the (single-threaded!) benchmarks in cli/bench. We're not @@ -143,6 +144,8 @@ pub async fn run_all_servers() { npm_registry::private_npm_registry1(PRIVATE_NPM_REGISTRY_1_PORT); let private_npm_registry_2_server_futs = npm_registry::private_npm_registry2(PRIVATE_NPM_REGISTRY_2_PORT); + let private_npm_registry_3_server_futs = + npm_registry::private_npm_registry3(PRIVATE_NPM_REGISTRY_3_PORT); let mut futures = vec![ redirect_server_fut.boxed_local(), @@ -173,6 +176,7 @@ pub async fn run_all_servers() { futures.extend(npm_registry_server_futs); futures.extend(private_npm_registry_1_server_futs); futures.extend(private_npm_registry_2_server_futs); + futures.extend(private_npm_registry_3_server_futs); assert_eq!(futures.len(), TEST_SERVERS_COUNT); diff --git a/tests/util/server/src/servers/npm_registry.rs b/tests/util/server/src/servers/npm_registry.rs index acbd9cab48..4ada468fac 100644 --- a/tests/util/server/src/servers/npm_registry.rs +++ b/tests/util/server/src/servers/npm_registry.rs @@ -56,6 +56,14 @@ pub fn private_npm_registry2(port: u16) -> Vec> { ) } +pub fn private_npm_registry3(port: u16) -> Vec> { + run_npm_server( + port, + "npm private registry server error", + private_npm_registry3_handler, + ) +} + fn run_npm_server( port: u16, error_msg: &'static str, @@ -141,6 +149,13 @@ async fn private_npm_registry2_handler( handle_req_for_registry(req, &npm::PRIVATE_TEST_NPM_REGISTRY_2).await } +async fn private_npm_registry3_handler( + req: Request, +) -> Result>, anyhow::Error> { + // No auth for this registry + handle_req_for_registry(req, &npm::PRIVATE_TEST_NPM_REGISTRY_3).await +} + async fn handle_req_for_registry( req: Request, test_npm_registry: &npm::TestNpmRegistry,