From 88f5ddfc2edf215830492faba6942031de201df2 Mon Sep 17 00:00:00 2001 From: Jurre Stender Date: Mon, 10 Oct 2022 14:59:59 +0200 Subject: [PATCH] Yarn Berry: Ensure registry config is respected When a global/scoped registry is configured in the yarnrc, Dependabot should honor this for all requests, also for Yarn Berry, which prior to this change wasn't the case. This ensures we correctly parse it etc. --- .../file_updater/npm_lockfile_updater.rb | 7 +- .../file_updater/yarn_lockfile_updater.rb | 7 +- .../update_checker/latest_version_finder.rb | 7 +- .../update_checker/library_detector.rb | 3 +- .../update_checker/registry_finder.rb | 19 +++- .../update_checker/registry_finder_spec.rb | 54 +++++++++- .../.yarn/install-state.gz | Bin 0 -> 3679 bytes .../yarnrc_global_registry/.yarnrc.yml | 1 + .../yarnrc_global_registry/package.json | 22 ++++ .../yarnrc_global_registry/yarn.lock | 97 ++++++++++++++++++ 10 files changed, 207 insertions(+), 10 deletions(-) create mode 100644 npm_and_yarn/spec/fixtures/projects/yarn_berry/yarnrc_global_registry/.yarn/install-state.gz create mode 100644 npm_and_yarn/spec/fixtures/projects/yarn_berry/yarnrc_global_registry/.yarnrc.yml create mode 100644 npm_and_yarn/spec/fixtures/projects/yarn_berry/yarnrc_global_registry/package.json create mode 100644 npm_and_yarn/spec/fixtures/projects/yarn_berry/yarnrc_global_registry/yarn.lock diff --git a/npm_and_yarn/lib/dependabot/npm_and_yarn/file_updater/npm_lockfile_updater.rb b/npm_and_yarn/lib/dependabot/npm_and_yarn/file_updater/npm_lockfile_updater.rb index 462c773b1f..70755c7584 100644 --- a/npm_and_yarn/lib/dependabot/npm_and_yarn/file_updater/npm_lockfile_updater.rb +++ b/npm_and_yarn/lib/dependabot/npm_and_yarn/file_updater/npm_lockfile_updater.rb @@ -429,10 +429,9 @@ def handle_missing_package(package_name, error_message) reg = NpmAndYarn::UpdateChecker::RegistryFinder.new( dependency: missing_dep, credentials: credentials, - npmrc_file: dependency_files. - find { |f| f.name.end_with?(".npmrc") }, - yarnrc_file: dependency_files. - find { |f| f.name.end_with?(".yarnrc") } + npmrc_file: dependency_files. find { |f| f.name.end_with?(".npmrc") }, + yarnrc_file: dependency_files. find { |f| f.name.end_with?(".yarnrc") }, + yarnrc_yml_file: dependency_files.find { |f| f.name.end_with?(".yarnrc.yml") } ).registry return if UpdateChecker::RegistryFinder.central_registry?(reg) && !package_name.start_with?("@") diff --git a/npm_and_yarn/lib/dependabot/npm_and_yarn/file_updater/yarn_lockfile_updater.rb b/npm_and_yarn/lib/dependabot/npm_and_yarn/file_updater/yarn_lockfile_updater.rb index 0b7ba03f65..37347612a6 100644 --- a/npm_and_yarn/lib/dependabot/npm_and_yarn/file_updater/yarn_lockfile_updater.rb +++ b/npm_and_yarn/lib/dependabot/npm_and_yarn/file_updater/yarn_lockfile_updater.rb @@ -474,7 +474,8 @@ def handle_missing_package(package_name, error_message, yarn_lock) dependency: missing_dep, credentials: credentials, npmrc_file: npmrc_file, - yarnrc_file: yarnrc_file + yarnrc_file: yarnrc_file, + yarnrc_yml_file: yarnrc_yml_file ).registry return if UpdateChecker::RegistryFinder.central_registry?(reg) && !package_name.start_with?("@") @@ -578,6 +579,10 @@ def yarnrc_file def npmrc_file dependency_files.find { |f| f.name == ".npmrc" } end + + def yarnrc_yml_file + dependency_files.find { |f| f.name.end_with?(".yarnrc.yml") } + end end end end diff --git a/npm_and_yarn/lib/dependabot/npm_and_yarn/update_checker/latest_version_finder.rb b/npm_and_yarn/lib/dependabot/npm_and_yarn/update_checker/latest_version_finder.rb index 2f377dfc1b..6aa68418e9 100644 --- a/npm_and_yarn/lib/dependabot/npm_and_yarn/update_checker/latest_version_finder.rb +++ b/npm_and_yarn/lib/dependabot/npm_and_yarn/update_checker/latest_version_finder.rb @@ -371,7 +371,8 @@ def registry_finder dependency: dependency, credentials: credentials, npmrc_file: npmrc_file, - yarnrc_file: yarnrc_file + yarnrc_file: yarnrc_file, + yarnrc_yml_file: yarnrc_yml_file ) end @@ -395,6 +396,10 @@ def yarnrc_file dependency_files.find { |f| f.name.end_with?(".yarnrc") } end + def yarnrc_yml_file + dependency_files.find { |f| f.name.end_with?(".yarnrc.yml") } + end + # TODO: Remove need for me def git_dependency? # ignored_version/raise_on_ignored are irrelevant. diff --git a/npm_and_yarn/lib/dependabot/npm_and_yarn/update_checker/library_detector.rb b/npm_and_yarn/lib/dependabot/npm_and_yarn/update_checker/library_detector.rb index 3f39cb5668..79df070952 100644 --- a/npm_and_yarn/lib/dependabot/npm_and_yarn/update_checker/library_detector.rb +++ b/npm_and_yarn/lib/dependabot/npm_and_yarn/update_checker/library_detector.rb @@ -65,7 +65,8 @@ def registry dependency: nil, credentials: credentials, npmrc_file: dependency_files.find { |f| f.name.end_with?(".npmrc") }, - yarnrc_file: dependency_files.find { |f| f.name.end_with?(".yarnrc") } + yarnrc_file: dependency_files.find { |f| f.name.end_with?(".yarnrc") }, + yarnrc_yml_file: dependency_files.find { |f| f.name.end_with?(".yarnrc.yml") } ).registry_from_rc(project_name) end end diff --git a/npm_and_yarn/lib/dependabot/npm_and_yarn/update_checker/registry_finder.rb b/npm_and_yarn/lib/dependabot/npm_and_yarn/update_checker/registry_finder.rb index 1f0e9b58e5..4d4dfcc9c6 100644 --- a/npm_and_yarn/lib/dependabot/npm_and_yarn/update_checker/registry_finder.rb +++ b/npm_and_yarn/lib/dependabot/npm_and_yarn/update_checker/registry_finder.rb @@ -25,11 +25,12 @@ class RegistryFinder /['"](?@[^:]+):registry['"]\s((['"](?.*)['"])|(?.*))/.freeze def initialize(dependency:, credentials:, npmrc_file: nil, - yarnrc_file: nil) + yarnrc_file: nil, yarnrc_yml_file: nil) @dependency = dependency @credentials = credentials @npmrc_file = npmrc_file @yarnrc_file = yarnrc_file + @yarnrc_yml_file = yarnrc_yml_file end def registry @@ -59,7 +60,7 @@ def registry_from_rc(dependency_name) private - attr_reader :dependency, :credentials, :npmrc_file, :yarnrc_file + attr_reader :dependency, :credentials, :npmrc_file, :yarnrc_file, :yarnrc_yml_file def first_registry_with_dependency_details @first_registry_with_dependency_details ||= @@ -214,6 +215,8 @@ def global_registry return Regexp.last_match[:registry].strip end + return parsed_yarnrc_yml["npmRegistryServer"] if parsed_yarnrc_yml&.key?("npmRegistryServer") + "https://registry.npmjs.org" end @@ -230,6 +233,11 @@ def scoped_registry(scope) return Regexp.last_match[:registry].strip end + if parsed_yarnrc_yml + yarn_berry_registry = parsed_yarnrc_yml.dig("npmScopes", scope.delete_prefix("@"), "npmRegistryServer") + return yarn_berry_registry if yarn_berry_registry + end + global_registry end @@ -245,6 +253,13 @@ def registry_source_url sources.find { |s| s[:type] == "registry" }&.fetch(:url) end + + def parsed_yarnrc_yml + return unless yarnrc_yml_file + return @parsed_yarnrc_yml if defined? @parsed_yarnrc_yml + + @parsed_yarnrc_yml = YAML.safe_load(yarnrc_yml_file.content) + end end end end diff --git a/npm_and_yarn/spec/dependabot/npm_and_yarn/update_checker/registry_finder_spec.rb b/npm_and_yarn/spec/dependabot/npm_and_yarn/update_checker/registry_finder_spec.rb index 5c7d0c546b..f9b0d35fcd 100644 --- a/npm_and_yarn/spec/dependabot/npm_and_yarn/update_checker/registry_finder_spec.rb +++ b/npm_and_yarn/spec/dependabot/npm_and_yarn/update_checker/registry_finder_spec.rb @@ -9,11 +9,13 @@ dependency: dependency, credentials: credentials, npmrc_file: npmrc_file, - yarnrc_file: yarnrc_file + yarnrc_file: yarnrc_file, + yarnrc_yml_file: yarnrc_yml_file ) end let(:npmrc_file) { nil } let(:yarnrc_file) { nil } + let(:yarnrc_yml_file) { nil } let(:credentials) do [{ "type" => "git_source", @@ -62,6 +64,14 @@ it { is_expected.to eq("http://example.com") } end + context "with a global yarn berry registry" do + let(:yarnrc_yml_file) do + Dependabot::DependencyFile.new(name: ".yarnrc.yml", content: 'npmRegistryServer: "https://example.com"') + end + + it { is_expected.to eq("https://example.com") } + end + context "with a scoped npm registry" do let(:dependency_name) { "@dependabot/some_dep" } let(:npmrc_file) { Dependabot::DependencyFile.new(name: ".npmrc", content: "@dependabot:registry=http://example.com") } @@ -82,6 +92,20 @@ it { is_expected.to eq("http://example.com") } end + + context "with a scoped yarn berry registry" do + let(:dependency_name) { "@dependabot/some_dep" } + let(:yarnrc_yml_content) do + <<~YARNRC + npmScopes: + dependabot: + npmRegistryServer: "https://example.com" + YARNRC + end + let(:yarnrc_yml_file) { Dependabot::DependencyFile.new(name: ".yarnrc", content: yarnrc_yml_content) } + + it { is_expected.to eq("https://example.com") } + end end describe "registry" do @@ -221,6 +245,34 @@ end end + context "with a .yarnrc.yml file" do + let(:yarnrc_yml_file) do + project_dependency_files(project_name).find { |f| f.name == ".yarnrc.yml" } + end + let(:project_name) { "yarn_berry/yarnrc_global_registry" } + + before do + url = "https://npm-proxy.fury.io/password/dependabot/etag" + body = fixture("gemfury_responses", "gemfury_response_etag.json") + + stub_request(:get, url).to_return(status: 200, body: body) + end + + it { is_expected.to eq("npm-proxy.fury.io/password/dependabot") } + + context "that can't be reached" do + before do + url = "https://npm-proxy.fury.io/password/dependabot/etag" + stub_request(:get, url).to_return(status: 401, body: "") + end + + # Since this registry is declared at the global registry, in the absence + # of other information we should still us it (and *not* flaa back to + # registry.npmjs.org) + it { is_expected.to eq("npm-proxy.fury.io/password/dependabot") } + end + end + context "with a private registry source" do let(:source) do { type: "registry", url: "https://npm.fury.io/dependabot" } diff --git a/npm_and_yarn/spec/fixtures/projects/yarn_berry/yarnrc_global_registry/.yarn/install-state.gz b/npm_and_yarn/spec/fixtures/projects/yarn_berry/yarnrc_global_registry/.yarn/install-state.gz new file mode 100644 index 0000000000000000000000000000000000000000..78726d4c6617f01d9e01df0618fb16518971bc72 GIT binary patch literal 3679 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 literal 0 HcmV?d00001 diff --git a/npm_and_yarn/spec/fixtures/projects/yarn_berry/yarnrc_global_registry/.yarnrc.yml b/npm_and_yarn/spec/fixtures/projects/yarn_berry/yarnrc_global_registry/.yarnrc.yml new file mode 100644 index 0000000000..ff019a31cd --- /dev/null +++ b/npm_and_yarn/spec/fixtures/projects/yarn_berry/yarnrc_global_registry/.yarnrc.yml @@ -0,0 +1 @@ +npmRegistryServer: "https://npm-proxy.fury.io/password/dependabot/" diff --git a/npm_and_yarn/spec/fixtures/projects/yarn_berry/yarnrc_global_registry/package.json b/npm_and_yarn/spec/fixtures/projects/yarn_berry/yarnrc_global_registry/package.json new file mode 100644 index 0000000000..3137db2d68 --- /dev/null +++ b/npm_and_yarn/spec/fixtures/projects/yarn_berry/yarnrc_global_registry/package.json @@ -0,0 +1,22 @@ +{ + "name": "{{ name }}", + "version": "1.0.0", + "description": "", + "main": "index.js", + "repository": { + "type": "git", + "url": "git+https://github.com/waltfy/PROTO_TEST.git" + }, + "author": "", + "license": "ISC", + "bugs": { + "url": "https://github.com/waltfy/PROTO_TEST/issues" + }, + "homepage": "https://github.com/waltfy/PROTO_TEST#readme", + "dependencies": { + "fetch-factory": "^0.0.1" + }, + "devDependencies": { + "etag": "^1.0.0" + } +} diff --git a/npm_and_yarn/spec/fixtures/projects/yarn_berry/yarnrc_global_registry/yarn.lock b/npm_and_yarn/spec/fixtures/projects/yarn_berry/yarnrc_global_registry/yarn.lock new file mode 100644 index 0000000000..fa119fdb80 --- /dev/null +++ b/npm_and_yarn/spec/fixtures/projects/yarn_berry/yarnrc_global_registry/yarn.lock @@ -0,0 +1,97 @@ +# This file is generated by running "yarn install" inside your project. +# Manual changes might be lost - proceed with caution! + +__metadata: + version: 6 + cacheKey: 8 + +"encoding@npm:^0.1.11": + version: 0.1.12 + resolution: "encoding@npm:0.1.12" + dependencies: + iconv-lite: ~0.4.13 + checksum: 96df688a93821e866bea19dd689863b1f9e07ef1c15321dde1fbcb8008ed7c785c48b248c4def01367780d2637c459b8ffa988de9647afe4200b003b1ac369ef + languageName: node + linkType: hard + +"es6-promise@npm:^3.0.2": + version: 3.3.1 + resolution: "es6-promise@npm:3.3.1" + checksum: ce4044009c2b78db18b15212338eb711cd8a4d485961bc9ec18bb24e8c1e91c96d3295b0fcf63066fc0fa1b0ade36da05e6657827d4336dece382be2429b8398 + languageName: node + linkType: hard + +"etag@npm:^1.0.0": + version: 1.7.0 + resolution: "etag@npm:1.7.0" + checksum: a76e03c51881902070fa3ecd4bd5c5b9286657ea467ada24bf866c1bdd545d08b65191d085b70fdc859caea2d68ff99c4f6936d2fa2026fd2fcc796d013e1978 + languageName: node + linkType: hard + +"fetch-factory@npm:^0.0.1": + version: 0.0.1 + resolution: "fetch-factory@npm:0.0.1" + dependencies: + es6-promise: ^3.0.2 + isomorphic-fetch: ^2.1.1 + lodash: ^3.10.1 + checksum: ff7fe6fdb8dd22080ff2d10495d0701068aac2d4d2c7c00baa675d9efa0d9b472deee7de0a60a2094446ec907833fdf0322ddaa814e1c594de5796b1e08157d9 + languageName: node + linkType: hard + +"iconv-lite@npm:~0.4.13": + version: 0.4.15 + resolution: "iconv-lite@npm:0.4.15" + checksum: 858ed660b795386d1ab85c43962d34519d46511d61432f6a74c1488dce2b6023f7eaec82f35f1e94eb20f2cfb36c6ad07e3814f9551a4b7c6058a162bbab382e + languageName: node + linkType: hard + +"is-stream@npm:^1.0.1": + version: 1.1.0 + resolution: "is-stream@npm:1.1.0" + checksum: 063c6bec9d5647aa6d42108d4c59723d2bd4ae42135a2d4db6eadbd49b7ea05b750fd69d279e5c7c45cf9da753ad2c00d8978be354d65aa9f6bb434969c6a2ae + languageName: node + linkType: hard + +"isomorphic-fetch@npm:^2.1.1": + version: 2.2.1 + resolution: "isomorphic-fetch@npm:2.2.1" + dependencies: + node-fetch: ^1.0.1 + whatwg-fetch: ">=0.10.0" + checksum: bb5daa7c3785d6742f4379a81e55b549a469503f7c9bf9411b48592e86632cf5e8fe8ea878dba185c0f33eb7c510c23abdeb55aebfdf5d3c70f031ced68c5424 + languageName: node + linkType: hard + +"lodash@npm:^3.10.1": + version: 3.10.1 + resolution: "lodash@npm:3.10.1" + checksum: 53065d3712a2fd90b55690c5af19f9625a5bbb2b7876ff76d782ee1dc22618fd4dff191d44a8e165a17b5b81a851c3e884d3b5b25e314422fbe24bb299542685 + languageName: node + linkType: hard + +"node-fetch@npm:^1.0.1": + version: 1.6.3 + resolution: "node-fetch@npm:1.6.3" + dependencies: + encoding: ^0.1.11 + is-stream: ^1.0.1 + checksum: cd8e3990065538141796c4f4d67dc9a9969880d9c4b9c6ad61cd5d140d9839bb04c099d53c16910dbef77ae73f390554370e2208862754ca71e1f6e445cb52f0 + languageName: node + linkType: hard + +"whatwg-fetch@npm:>=0.10.0": + version: 2.0.2 + resolution: "whatwg-fetch@npm:2.0.2" + checksum: 686d167f497d894d9dddb7f91d042ab927775a9c877015945261406ad64248e464c7fcfddc5a41e400102e3f68934da4762b7b8fadced8fc126b0a88f5e3bd0f + languageName: node + linkType: hard + +"{{ name }}@workspace:.": + version: 0.0.0-use.local + resolution: "{{ name }}@workspace:." + dependencies: + etag: ^1.0.0 + fetch-factory: ^0.0.1 + languageName: unknown + linkType: soft