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

use configured global registry for library lookup #5840

Merged
Merged
Show file tree
Hide file tree
Changes from 3 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
Original file line number Diff line number Diff line change
Expand Up @@ -375,7 +375,11 @@ def library?
return true if dependency_files.any? { |f| f.name == "lerna.json" }

@library =
LibraryDetector.new(package_json_file: package_json).library?
LibraryDetector.new(
package_json_file: package_json,
credentials: credentials,
dependency_files: dependency_files
).library?
end

def dependency_source_details
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,10 @@ module Dependabot
module NpmAndYarn
class UpdateChecker
class LibraryDetector
def initialize(package_json_file:)
def initialize(package_json_file:, credentials:, dependency_files:)
@package_json_file = package_json_file
@credentials = credentials
@dependency_files = dependency_files
end

def library?
Expand All @@ -20,7 +22,7 @@ def library?

private

attr_reader :package_json_file
attr_reader :package_json_file, :credentials, :dependency_files

def package_json_may_be_for_library?
return false unless project_name
Expand All @@ -36,7 +38,8 @@ def npm_response_matches_package_json?
return false unless project_description

# Check if the project is listed on npm. If it is, it's a library
@project_npm_response ||= Dependabot::RegistryClient.get(url: "https://registry.npmjs.org/#{escaped_project_name}")
url = "#{registry.chomp('/')}/#{escaped_project_name}"
@project_npm_response ||= Dependabot::RegistryClient.get(url: url)
return false unless @project_npm_response.status == 200

@project_npm_response.body.force_encoding("UTF-8").encode.
Expand All @@ -56,6 +59,15 @@ def escaped_project_name
def parsed_package_json
@parsed_package_json ||= JSON.parse(package_json_file.content)
end

def registry
NpmAndYarn::UpdateChecker::RegistryFinder.new(
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") }
).registry_from_rc(project_name)
end
end
end
end
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,10 @@ class RegistryFinder
/^registry\s*=\s*['"]?(?<registry>.*?)['"]?$/.freeze
YARN_GLOBAL_REGISTRY_REGEX =
/^(?:--)?registry\s+['"](?<registry>.*)['"]/.freeze
NPM_SCOPED_REGISTRY_REGEX =
/^(?<scope>@[^:]+)\s*:registry\s*=\s*['"]?(?<registry>.*?)['"]?$/.freeze
YARN_SCOPED_REGISTRY_REGEX =
/['"](?<scope>@[^:]+):registry['"]\s['"](?<registry>.*)['"]/.freeze

def initialize(dependency:, credentials:, npmrc_file: nil,
yarnrc_file: nil)
Expand Down Expand Up @@ -46,6 +50,13 @@ def self.central_registry?(registry)
end
end

def registry_from_rc(dependency_name)
return global_registry unless dependency_name.start_with?("@") && dependency_name.include?("/")

scope = dependency_name.split("/").first
scoped_registry(scope)
end

private

attr_reader :dependency, :credentials, :npmrc_file, :yarnrc_file
Expand All @@ -64,7 +75,7 @@ def first_registry_with_dependency_details
nil
end&.fetch("registry")

@first_registry_with_dependency_details ||= global_registry
@first_registry_with_dependency_details ||= global_registry.sub(%r{/+$}, "").sub(%r{^.*?//}, "")
end

def registry_url
Expand Down Expand Up @@ -194,22 +205,32 @@ def global_registry
npmrc_file&.content.to_s.scan(NPM_GLOBAL_REGISTRY_REGEX) do
next if Regexp.last_match[:registry].include?("${")

registry = Regexp.last_match[:registry].strip.
sub(%r{/+$}, "").
sub(%r{^.*?//}, "")
return registry
return Regexp.last_match[:registry].strip
end

yarnrc_file&.content.to_s.scan(YARN_GLOBAL_REGISTRY_REGEX) do
next if Regexp.last_match[:registry].include?("${")

registry = Regexp.last_match[:registry].strip.
sub(%r{/+$}, "").
sub(%r{^.*?//}, "")
return registry
return Regexp.last_match[:registry].strip
end

"https://registry.npmjs.org"
end

def scoped_registry(scope)
npmrc_file&.content.to_s.scan(NPM_SCOPED_REGISTRY_REGEX) do
next if Regexp.last_match[:registry].include?("${") || Regexp.last_match[:scope] != scope

return Regexp.last_match[:registry].strip
end

yarnrc_file&.content.to_s.scan(YARN_SCOPED_REGISTRY_REGEX) do
next if Regexp.last_match[:registry].include?("${") || Regexp.last_match[:scope] != scope

return Regexp.last_match[:registry].strip
end

"registry.npmjs.org"
global_registry
end

# npm registries expect slashes to be escaped
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,18 @@
require "dependabot/npm_and_yarn/update_checker/library_detector"

RSpec.describe Dependabot::NpmAndYarn::UpdateChecker::LibraryDetector do
subject(:finder) { described_class.new(package_json_file: package_json_file) }
subject(:finder) do
described_class.new(
package_json_file: package_json_file,
credentials: credentials,
dependency_files: dependency_files
)
end
let(:package_json_file) do
project_dependency_files(project_name).find { |f| f.name == "package.json" }
end
let(:credentials) { {} }
let(:dependency_files) { project_dependency_files(project_name) }

describe "library?" do
subject { finder.library? }
Expand Down Expand Up @@ -64,5 +72,69 @@
end
end
end

context "with a custom global registry" do
let(:project_name) { "npm8/library_with_global_registry" }

context "not listed in registry" do
before do
stub_request(:get, "http://example.com/dependabot/etag").
to_return(status: 404)
end

it { is_expected.to eq(false) }
end

context "listed on registry" do
before do
stub_request(:get, "http://example.com/dependabot/etag").
to_return(status: 200, body: body)
end

context "with a description that matches" do
let(:body) { fixture("npm_responses", "etag.json") }
it { is_expected.to eq(true) }
end

context "with a description that doesn't match" do
let(:body) do
fixture("npm_responses", "is_number.json")
end
it { is_expected.to eq(false) }
end
end
end

context "with a custom scoped registry" do
let(:project_name) { "npm8/library_with_scoped_registry" }

context "not listed in registry" do
before do
stub_request(:get, "http://example.com/dependabot/@dependabot%2Fetag").
to_return(status: 404)
end

it { is_expected.to eq(false) }
end

context "listed on registry" do
before do
stub_request(:get, "http://example.com/dependabot/@dependabot%2Fetag").
to_return(status: 200, body: body)
end

context "with a description that matches" do
let(:body) { fixture("npm_responses", "etag.json") }
it { is_expected.to eq(true) }
end

context "with a description that doesn't match" do
let(:body) do
fixture("npm_responses", "is_number.json")
end
it { is_expected.to eq(false) }
end
end
end
end
end
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,40 @@
end
let(:source) { nil }

describe "registry_from_rc" do
subject { finder.registry_from_rc(dependency_name) }

let(:dependency_name) { "some_dep" }

it { is_expected.to eq("https://registry.npmjs.org") }

context "with a global npm registry" do
let(:npmrc_file) { Dependabot::DependencyFile.new(name: ".npmrc", content: "registry=http://example.com") }

it { is_expected.to eq("http://example.com") }
end

context "with a global yarn registry" do
let(:yarnrc_file) { Dependabot::DependencyFile.new(name: ".yarnrc", content: 'registry "http://example.com"') }

it { is_expected.to eq("http://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") }

it { is_expected.to eq("http://example.com") }
end

context "with a scoped yarn registry" do
let(:dependency_name) { "@dependabot/some_dep" }
let(:yarnrc_file) { Dependabot::DependencyFile.new(name: ".yarnrc", content: '"@dependabot:registry" "http://example.com"') }

it { is_expected.to eq("http://example.com") }
end
end

describe "registry" do
subject { finder.registry }

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
registry=http://example.com/dependabot
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
{
"name": "etag",
"description": "Create simple ETags",
"version": "1.8.0",
"contributors": [
"Douglas Christopher Wilson <[email protected]>",
"David Björklund <[email protected]>"
],
"license": "MIT",
"keywords": [
"etag",
"http",
"res"
],
"repository": "jshttp/etag",
"devDependencies": {
"beautify-benchmark": "0.2.4",
"benchmark": "2.1.3",
"eslint": "3.15.0",
"eslint-config-standard": "6.2.1",
"eslint-plugin-markdown": "1.0.0-beta.3",
"eslint-plugin-promise": "3.4.2",
"eslint-plugin-standard": "2.0.1",
"istanbul": "0.4.5",
"mocha": "1.21.5",
"seedrandom": "2.4.2"
},
"files": [
"LICENSE",
"HISTORY.md",
"README.md",
"index.js"
],
"engines": {
"node": ">= 0.6"
},
"scripts": {
"bench": "node benchmark/index.js",
"lint": "eslint --plugin markdown --ext js,md .",
"test": "mocha --reporter spec --bail --check-leaks test/",
"test-cov": "istanbul cover node_modules/mocha/bin/_mocha -- --reporter dot --check-leaks test/",
"test-travis": "istanbul cover node_modules/mocha/bin/_mocha --report lcovonly -- --reporter spec --check-leaks test/"
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
@dependabot:registry=http://example.com/dependabot
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
{
"name": "@dependabot/etag",
"description": "Create simple ETags",
"version": "1.8.0",
"contributors": [
"Douglas Christopher Wilson <[email protected]>",
"David Björklund <[email protected]>"
],
"license": "MIT",
"keywords": [
"etag",
"http",
"res"
],
"repository": "jshttp/etag",
"devDependencies": {
"beautify-benchmark": "0.2.4",
"benchmark": "2.1.3",
"eslint": "3.15.0",
"eslint-config-standard": "6.2.1",
"eslint-plugin-markdown": "1.0.0-beta.3",
"eslint-plugin-promise": "3.4.2",
"eslint-plugin-standard": "2.0.1",
"istanbul": "0.4.5",
"mocha": "1.21.5",
"seedrandom": "2.4.2"
},
"files": [
"LICENSE",
"HISTORY.md",
"README.md",
"index.js"
],
"engines": {
"node": ">= 0.6"
},
"scripts": {
"bench": "node benchmark/index.js",
"lint": "eslint --plugin markdown --ext js,md .",
"test": "mocha --reporter spec --bail --check-leaks test/",
"test-cov": "istanbul cover node_modules/mocha/bin/_mocha -- --reporter dot --check-leaks test/",
"test-travis": "istanbul cover node_modules/mocha/bin/_mocha --report lcovonly -- --reporter spec --check-leaks test/"
}
}