Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(npm): registry inferring should include the full registry path #7030

Merged
merged 1 commit into from
Apr 17, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 23 additions & 8 deletions npm_and_yarn/lib/dependabot/npm_and_yarn/file_fetcher.rb
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@

module Dependabot
module NpmAndYarn
class FileFetcher < Dependabot::FileFetchers::Base
class FileFetcher < Dependabot::FileFetchers::Base # rubocop:disable Metrics/ClassLength
require_relative "file_fetcher/path_dependency_builder"

# Npm always prefixes file paths in the lockfile "version" with "file:"
Expand All @@ -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")
Expand Down Expand Up @@ -86,25 +87,39 @@ 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

def inferred_npmrc # rubocop:disable Metrics/PerceivedComplexity
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")
JSON.parse(package_lock.content).fetch("dependencies", {}).each do |dependency_name, details|
resolved = details.fetch("resolved", DEFAULT_NPM_REGISTRY)

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
end
# Check for scheme since path dependencies will not have one
known_registries << "#{uri.scheme}://#{uri.host}" if uri.scheme && uri.host

next unless uri.scheme && uri.host

known_registry = "#{uri.scheme}://#{uri.host}"
path = uri.path

next unless path

index = path.index(dependency_name)
if index
registry_base_path = path[0...index].delete_suffix("/")
known_registry << registry_base_path
end

known_registries << known_registry
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",
Expand Down
31 changes: 30 additions & 1 deletion npm_and_yarn/spec/dependabot/npm_and_yarn/file_fetcher_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -1787,7 +1787,36 @@
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.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
Expand Down

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"version": "1.0.0",
"description": "",
"main": "index.js",
"dependencies": {
"fetch-factory": "0.0.1"
},
"devDependencies": {
"etag": "1.0.0"
}
}