From 807e2cd64a193086924e5cf058a1486bc45954db Mon Sep 17 00:00:00 2001 From: Yeikel Date: Mon, 10 Apr 2023 04:31:26 +0000 Subject: [PATCH] fix(npm): registry inferring should include the full registry path --- .gitignore | 1 + .../dependabot/npm_and_yarn/file_fetcher.rb | 23 +++--- .../npm_and_yarn/file_fetcher_spec.rb | 32 +++++++- .../package-lock.json | 75 +++++++++++++++++++ .../package.json | 25 +++++++ 5 files changed, 144 insertions(+), 12 deletions(-) create mode 100644 npm_and_yarn/spec/fixtures/projects/npm6/private_artifactory_repository/package-lock.json create mode 100644 npm_and_yarn/spec/fixtures/projects/npm6/private_artifactory_repository/package.json diff --git a/.gitignore b/.gitignore index 4a2eeedb4c12..c463950e5dc9 100644 --- a/.gitignore +++ b/.gitignore @@ -30,3 +30,4 @@ coverage/ .tool-versions .rspec_status .rdbg_history +.idea/ diff --git a/npm_and_yarn/lib/dependabot/npm_and_yarn/file_fetcher.rb b/npm_and_yarn/lib/dependabot/npm_and_yarn/file_fetcher.rb index 4ef88467c835..e025f14555df 100644 --- a/npm_and_yarn/lib/dependabot/npm_and_yarn/file_fetcher.rb +++ b/npm_and_yarn/lib/dependabot/npm_and_yarn/file_fetcher.rb @@ -22,6 +22,7 @@ class FileFetcher < Dependabot::FileFetchers::Base # "yarn link", e.g. "link:react" PATH_DEPENDENCY_STARTS = %w(file: link:. link:/ link:~/ / ./ ../ ~/).freeze PATH_DEPENDENCY_CLEAN_REGEX = /^file:|^link:/ + DEFAULT_NPM_REGISTRY = "https://registry.npmjs.org" def self.required_files_in?(filenames) filenames.include?("package.json") @@ -85,25 +86,25 @@ def fetch_files # If every entry in the lockfile uses the same registry, we can infer # that there is a global .npmrc file, so add it here as if it were in the repo. + def inferred_npmrc return @inferred_npmrc if defined?(@inferred_npmrc) return @inferred_npmrc = nil unless npmrc.nil? && package_lock known_registries = [] - JSON.parse(package_lock.content).fetch("dependencies", {}).each do |_name, details| - resolved = details.fetch("resolved", "https://registry.npmjs.org") - begin - uri = URI.parse(resolved) - rescue URI::InvalidURIError - # Ignoring non-URIs since they're not registries. - # This can happen if resolved is false, for instance. - next + JSON.parse(package_lock.content).fetch("dependencies", {}).each do |dependency_name, details| + resolved = details.fetch("resolved", DEFAULT_NPM_REGISTRY) + + next if !resolved.is_a?(String) || resolved.start_with?(DEFAULT_NPM_REGISTRY) + + index = resolved.index(dependency_name) + unless index.nil? + registry_base_url = resolved[0...index] + known_registries << registry_base_url end - # Check for scheme since path dependencies will not have one - known_registries << "#{uri.scheme}://#{uri.host}" if uri.scheme && uri.host end - if known_registries.uniq.length == 1 && known_registries.first != "https://registry.npmjs.org" + if known_registries.uniq.length == 1 && known_registries.first != DEFAULT_NPM_REGISTRY Dependabot.logger.info("Inferred global NPM registry is: #{known_registries.first}") return @inferred_npmrc = Dependabot::DependencyFile.new( name: ".npmrc", diff --git a/npm_and_yarn/spec/dependabot/npm_and_yarn/file_fetcher_spec.rb b/npm_and_yarn/spec/dependabot/npm_and_yarn/file_fetcher_spec.rb index 92dcc8abe150..56e37a6c2ad3 100644 --- a/npm_and_yarn/spec/dependabot/npm_and_yarn/file_fetcher_spec.rb +++ b/npm_and_yarn/spec/dependabot/npm_and_yarn/file_fetcher_spec.rb @@ -1787,7 +1787,37 @@ expect(file_fetcher_instance.files.map(&:name)). to eq(%w(package.json package-lock.json .npmrc)) expect(file_fetcher_instance.files.find { |f| f.name == ".npmrc" }.content). - to eq("registry=https://npm.fury.io") + to eq("registry=https://npm.fury.io/dependabot/") + end + end + + context "with no .npmrc but package-lock.json contains a artifactory repository" do + before do + allow(file_fetcher_instance).to receive(:commit).and_return("sha") + + stub_request(:get, File.join(url, "package.json?ref=sha")). + with(headers: { "Authorization" => "token token" }). + to_return( + status: 200, + body: fixture_to_response("projects/npm6/private_artifactory_repository", "package.json"), + headers: json_header + ) + + stub_request(:get, File.join(url, "package-lock.json?ref=sha")). + with(headers: { "Authorization" => "token token" }). + to_return( + status: 200, + body: fixture_to_response("projects/npm6/private_artifactory_repository", "package-lock.json"), + headers: json_header + ) + end + + it "infers an npmrc file" do + expect(file_fetcher_instance.files.count).to eq(3) + expect(file_fetcher_instance.files.map(&:name)). + to eq(%w(package.json package-lock.json .npmrc)) + expect(file_fetcher_instance.files.find { |f| f.name == ".npmrc" }.content). + to eq("registry=https://myRegistry/api/npm/npm/") end end end diff --git a/npm_and_yarn/spec/fixtures/projects/npm6/private_artifactory_repository/package-lock.json b/npm_and_yarn/spec/fixtures/projects/npm6/private_artifactory_repository/package-lock.json new file mode 100644 index 000000000000..1b45bfdeae01 --- /dev/null +++ b/npm_and_yarn/spec/fixtures/projects/npm6/private_artifactory_repository/package-lock.json @@ -0,0 +1,75 @@ +{ + "name": "test", + "version": "1.0.0", + "lockfileVersion": 1, + "requires": true, + "dependencies": { + "encoding": { + "version": "0.1.12", + "resolved": "https://myRegistry/api/npm/npm/cors/-/cors-2.8.5.tgz", + "integrity": "sha1-U4tm8+5izRq1HsMjgp0flIDHS+s=", + "requires": { + "iconv-lite": "0.4.19" + } + }, + "es6-promise": { + "version": "3.3.1", + "resolved": "https://myRegistry/api/npm/npm/es6-promise/-/es6-promise-3.3.1.tgz", + "integrity": "sha1-oIzd6EzNvzTQJ6FFG8kdS80ophM=" + }, + "etag": { + "version": "1.8.1", + "resolved": "https://myRegistry/api/npm/npm/etag/-/etag-1.8.1.tgz", + "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=", + "dev": true + }, + "fetch-factory": { + "version": "0.0.1", + "resolved": "https://myRegistry/api/npm/npm/fetch-factory/-/fetch-factory-0.0.1.tgz", + "integrity": "sha1-4AdgWb2zHjFHx1s7jAQTO6jH4HE=", + "requires": { + "es6-promise": "3.3.1", + "isomorphic-fetch": "2.2.1", + "lodash": "3.10.1" + } + }, + "iconv-lite": { + "version": "0.4.19", + "resolved": false, + "integrity": "sha512-oTZqweIP51xaGPI4uPa56/Pri/480R+mo7SeU+YETByQNhDG55ycFyNLIgta9vXhILrxXDmF7ZGhqZIcuN0gJQ==" + }, + "is-stream": { + "version": "1.1.0", + "resolved": "https://myRegistry/api/npm/npm/is-stream/-/is-stream-1.1.0.tgz", + "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=" + }, + "isomorphic-fetch": { + "version": "2.2.1", + "resolved": "https://myRegistry/api/npm/npm/isomorphic-fetch/-/isomorphic-fetch-2.2.1.tgz", + "integrity": "sha1-YRrhrPFPXoH3KVB0coGf6XM1WKk=", + "requires": { + "node-fetch": "1.7.3", + "whatwg-fetch": "2.0.3" + } + }, + "lodash": { + "version": "3.10.1", + "resolved": "https://myRegistry/api/npm/npm/lodash/-/lodash-3.10.1.tgz", + "integrity": "sha1-W/Rejkm6QYnhfUgnid/RW9FAt7Y=" + }, + "node-fetch": { + "version": "1.7.3", + "resolved": "https://myRegistry/api/npm/npm/node-fetch/-/node-fetch-1.7.3.tgz", + "integrity": "sha512-NhZ4CsKx7cYm2vSrBAr2PvFOe6sWDf0UYLRqA6svUYg7+/TSfVAu49jYC4BvQ4Sms9SZgdqGBgroqfDhJdTyKQ==", + "requires": { + "encoding": "0.1.12", + "is-stream": "1.1.0" + } + }, + "whatwg-fetch": { + "version": "2.0.3", + "resolved": "https://myRegistry/api/npm/npm/whatwg-fetch/-/whatwg-fetch-2.0.3.tgz", + "integrity": "sha1-nITsLc9oGH/wC8ZOEnS0QhduHIQ=" + } + } +} diff --git a/npm_and_yarn/spec/fixtures/projects/npm6/private_artifactory_repository/package.json b/npm_and_yarn/spec/fixtures/projects/npm6/private_artifactory_repository/package.json new file mode 100644 index 000000000000..88a3adff6e24 --- /dev/null +++ b/npm_and_yarn/spec/fixtures/projects/npm6/private_artifactory_repository/package.json @@ -0,0 +1,25 @@ +{ + "name": "{{ name }}", + "version": "1.0.0", + "description": "", + "main": "index.js", + "scripts": { + "test": "echo \"Error: no\\ test\ specified\" && exit 1", + "prettify": "prettier --write \"{{packages/*/src,examples,cypress,scripts}/**/,}*.{js,jsx,ts,tsx,css,md}\"" + }, + "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" + }}