dependabot-npm_and_yarn 0.253.0 → 0.255.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/helpers/lib/pnpm/lockfile-parser.js +4 -0
- data/helpers/package-lock.json +1244 -482
- data/helpers/package.json +5 -5
- data/helpers/test/pnpm/fixtures/parser/empty_version/pnpm-lock.yaml +72 -0
- data/helpers/test/pnpm/fixtures/parser/no_lockfile_change/pnpm-lock.yaml +2744 -0
- data/helpers/test/pnpm/fixtures/parser/only_dev_dependencies/pnpm-lock.yaml +16 -0
- data/helpers/test/pnpm/fixtures/parser/peer_disambiguation/pnpm-lock.yaml +855 -0
- data/helpers/test/pnpm/lockfile-parser.test.js +62 -0
- data/helpers/test/yarn/fixtures/conflicting-dependency-parser/nested/yarn.lock +26 -15
- data/helpers/test/yarn/fixtures/updater/illegal_character/package.json +8 -0
- data/helpers/test/yarn/fixtures/updater/illegal_character/yarn.lock +14 -0
- data/helpers/test/yarn/updater.test.js +29 -0
- data/lib/dependabot/npm_and_yarn/file_parser.rb +1 -1
- data/lib/dependabot/npm_and_yarn/file_updater/npmrc_builder.rb +138 -60
- data/lib/dependabot/npm_and_yarn/file_updater/yarn_lockfile_updater.rb +5 -0
- data/lib/dependabot/npm_and_yarn/package_name.rb +15 -12
- data/lib/dependabot/npm_and_yarn/sub_dependency_files_filterer.rb +1 -1
- data/lib/dependabot/npm_and_yarn/update_checker/version_resolver.rb +13 -1
- metadata +37 -16
@@ -0,0 +1,62 @@
|
|
1
|
+
const {
|
2
|
+
parseLockfile,
|
3
|
+
} = require("../../lib/pnpm");
|
4
|
+
const fs = require("fs");
|
5
|
+
const os = require("os");
|
6
|
+
const path = require("path");
|
7
|
+
|
8
|
+
describe("generates an updated pnpm lock for the original file", () => {
|
9
|
+
|
10
|
+
let tempDir;
|
11
|
+
beforeEach(() => {
|
12
|
+
tempDir = fs.mkdtempSync(os.tmpdir() + path.sep);
|
13
|
+
});
|
14
|
+
afterEach(() => fs.rm(tempDir, { recursive: true }, () => {}));
|
15
|
+
|
16
|
+
function copyDependencies(sourceDir, destDir) {
|
17
|
+
const srcPnpmYaml = path.join(
|
18
|
+
__dirname,
|
19
|
+
`fixtures/parser/${sourceDir}/pnpm-lock.yaml`
|
20
|
+
);
|
21
|
+
fs.copyFileSync(srcPnpmYaml, `${destDir}/pnpm-lock.yaml`);
|
22
|
+
}
|
23
|
+
|
24
|
+
it("that contains duplicate dependencies", async () =>{
|
25
|
+
copyDependencies("no_lockfile_change", tempDir);
|
26
|
+
const result = await parseLockfile(tempDir);
|
27
|
+
|
28
|
+
expect(result.length).toEqual(398);
|
29
|
+
})
|
30
|
+
|
31
|
+
it("that contains only dev dependencies but no (prod) dependencies", async () =>{
|
32
|
+
copyDependencies("only_dev_dependencies", tempDir);
|
33
|
+
const result = await parseLockfile(tempDir);
|
34
|
+
|
35
|
+
expect(result).toEqual([
|
36
|
+
{
|
37
|
+
name: 'etag',
|
38
|
+
version: '1.8.0',
|
39
|
+
resolved: undefined,
|
40
|
+
dev: true,
|
41
|
+
specifiers: [ '^1.0.0' ],
|
42
|
+
aliased: false
|
43
|
+
}
|
44
|
+
]);
|
45
|
+
})
|
46
|
+
|
47
|
+
it("that contains dependencies which locked to versions with peer disambiguation suffix", async () =>{
|
48
|
+
copyDependencies("peer_disambiguation", tempDir);
|
49
|
+
const result = await parseLockfile(tempDir);
|
50
|
+
|
51
|
+
expect(result.length).toEqual(122);
|
52
|
+
})
|
53
|
+
|
54
|
+
// Should have the version in the lock file.
|
55
|
+
it("that contains dependencies with an empty version", async () =>{
|
56
|
+
copyDependencies("empty_version", tempDir);
|
57
|
+
const result = await parseLockfile(tempDir);
|
58
|
+
|
59
|
+
expect(result.length).toEqual(9);
|
60
|
+
})
|
61
|
+
|
62
|
+
})
|
@@ -48,16 +48,17 @@ d@1, d@^1.0.1:
|
|
48
48
|
es5-ext "^0.10.50"
|
49
49
|
type "^1.0.1"
|
50
50
|
|
51
|
-
es5-ext@^0.10.35, es5-ext@^0.10.45, es5-ext@^0.10.46, es5-ext@^0.10.50, es5-ext@~0.10.14, es5-ext@~0.10.2, es5-ext@~0.10.46:
|
52
|
-
version "0.10.
|
53
|
-
resolved "https://registry.
|
54
|
-
integrity sha512-
|
51
|
+
es5-ext@^0.10.35, es5-ext@^0.10.45, es5-ext@^0.10.46, es5-ext@^0.10.50, es5-ext@^0.10.62, es5-ext@~0.10.14, es5-ext@~0.10.2, es5-ext@~0.10.46:
|
52
|
+
version "0.10.63"
|
53
|
+
resolved "https://registry.yarnpkg.com/es5-ext/-/es5-ext-0.10.63.tgz#9c222a63b6a332ac80b1e373b426af723b895bd6"
|
54
|
+
integrity sha512-hUCZd2Byj/mNKjfP9jXrdVZ62B8KuA/VoK7X8nUh5qT+AxDmcbvZz041oDVZdbIN1qW6XY9VDNwzkvKnZvK2TQ==
|
55
55
|
dependencies:
|
56
|
-
es6-iterator "
|
57
|
-
es6-symbol "
|
58
|
-
|
56
|
+
es6-iterator "^2.0.3"
|
57
|
+
es6-symbol "^3.1.3"
|
58
|
+
esniff "^2.0.1"
|
59
|
+
next-tick "^1.1.0"
|
59
60
|
|
60
|
-
es6-iterator@^2.0.3
|
61
|
+
es6-iterator@^2.0.3:
|
61
62
|
version "2.0.3"
|
62
63
|
resolved "https://registry.npmjs.org/es6-iterator/-/es6-iterator-2.0.3.tgz#a7de889141a05a94b0854403b2d0a0fbfa98f3b7"
|
63
64
|
integrity sha1-p96IkUGgWpSwhUQDstCg+/qY87c=
|
@@ -66,7 +67,7 @@ es6-iterator@^2.0.3, es6-iterator@~2.0.3:
|
|
66
67
|
es5-ext "^0.10.35"
|
67
68
|
es6-symbol "^3.1.1"
|
68
69
|
|
69
|
-
es6-symbol@^3.1.1, es6-symbol
|
70
|
+
es6-symbol@^3.1.1, es6-symbol@^3.1.3:
|
70
71
|
version "3.1.3"
|
71
72
|
resolved "https://registry.npmjs.org/es6-symbol/-/es6-symbol-3.1.3.tgz#bad5d3c1bcdac28269f4cb331e431c78ac705d18"
|
72
73
|
integrity sha512-NJ6Yn3FuDinBaBRWl/q5X/s4koRHBrgKAu+yGI6JCBeiu3qrcbJhwT2GeR/EXVfylRk8dpQVJoLEFhK+Mu31NA==
|
@@ -84,6 +85,16 @@ es6-weak-map@^2.0.2:
|
|
84
85
|
es6-iterator "^2.0.3"
|
85
86
|
es6-symbol "^3.1.1"
|
86
87
|
|
88
|
+
esniff@^2.0.1:
|
89
|
+
version "2.0.1"
|
90
|
+
resolved "https://registry.yarnpkg.com/esniff/-/esniff-2.0.1.tgz#a4d4b43a5c71c7ec51c51098c1d8a29081f9b308"
|
91
|
+
integrity sha512-kTUIGKQ/mDPFoJ0oVfcmyJn4iBDRptjNVIzwIFR7tqWXdVI9xfA2RMwY/gbSpJG3lkdWNEjLap/NqVHZiJsdfg==
|
92
|
+
dependencies:
|
93
|
+
d "^1.0.1"
|
94
|
+
es5-ext "^0.10.62"
|
95
|
+
event-emitter "^0.3.5"
|
96
|
+
type "^2.7.2"
|
97
|
+
|
87
98
|
event-emitter@^0.3.5:
|
88
99
|
version "0.3.5"
|
89
100
|
resolved "https://registry.npmjs.org/event-emitter/-/event-emitter-0.3.5.tgz#df8c69eef1647923c7157b9ce83840610b02cc39"
|
@@ -135,16 +146,11 @@ memoizee@^0.4.14:
|
|
135
146
|
next-tick "1"
|
136
147
|
timers-ext "^0.1.5"
|
137
148
|
|
138
|
-
next-tick@1:
|
149
|
+
next-tick@1, next-tick@^1.1.0:
|
139
150
|
version "1.1.0"
|
140
151
|
resolved "https://registry.npmjs.org/next-tick/-/next-tick-1.1.0.tgz#1836ee30ad56d67ef281b22bd199f709449b35eb"
|
141
152
|
integrity sha512-CXdUiJembsNjuToQvxayPZF9Vqht7hewsvy2sOWafLvi2awflj9mOC6bHIg50orX8IJvWKY9wYQ/zB2kogPslQ==
|
142
153
|
|
143
|
-
next-tick@~1.0.0:
|
144
|
-
version "1.0.0"
|
145
|
-
resolved "https://registry.npmjs.org/next-tick/-/next-tick-1.0.0.tgz#ca86d1fe8828169b0120208e3dc8424b9db8342c"
|
146
|
-
integrity sha1-yobR/ogoFpsBICCOPchCS524NCw=
|
147
|
-
|
148
154
|
objnest@^5.0.6:
|
149
155
|
version "5.0.10"
|
150
156
|
resolved "https://registry.npmjs.org/objnest/-/objnest-5.0.10.tgz#90e43b11870502fcb445e97fcf402499f5f75c75"
|
@@ -170,3 +176,8 @@ type@^2.0.0:
|
|
170
176
|
version "2.1.0"
|
171
177
|
resolved "https://registry.npmjs.org/type/-/type-2.1.0.tgz#9bdc22c648cf8cf86dd23d32336a41cfb6475e3f"
|
172
178
|
integrity sha512-G9absDWvhAWCV2gmF1zKud3OyC61nZDwWvBL2DApaVFogI07CprggiQAOOjvp2NRjYWFzPyu7vwtDrQFq8jeSA==
|
179
|
+
|
180
|
+
type@^2.7.2:
|
181
|
+
version "2.7.2"
|
182
|
+
resolved "https://registry.yarnpkg.com/type/-/type-2.7.2.tgz#2376a15a3a28b1efa0f5350dcf72d24df6ef98d0"
|
183
|
+
integrity sha512-dzlvlNlt6AXU7EBSfpAscydQ7gXB+pPGsPnfJnZpiNJBDj7IaJzQlBZYGdEi4R9HmPdBv2XmWJ6YUtoTa7lmCw==
|
@@ -0,0 +1,14 @@
|
|
1
|
+
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
|
2
|
+
# yarn lockfile v1
|
3
|
+
|
4
|
+
"@commitlint/cli@^15.0.0":
|
5
|
+
version "15.0.0"
|
6
|
+
resolved "https://registry.yarnpkg.com/@commitlint/cli/-/cli-15.0.0.tgz#8e78e86ee2b6955c1a5d140e734a6c171ce367ee"
|
7
|
+
|
8
|
+
"is-positive@^3.1.0":
|
9
|
+
version "3.1.0"
|
10
|
+
resolved "https://registry.yarnpkg.com/is-positive/-/is-positive-3.1.0.tgz#857db584a1ba5d1cb2980527fc3b6c435d37b0fd"
|
11
|
+
|
12
|
+
"left-pad@^1.0.0":
|
13
|
+
version "1.0.0"
|
14
|
+
resolved "https://registry.yarnpkg.com/left-pad/-/left-pad-1.0.0.tgz#c84e2417581bbb8eaf2b9e3d7a122e572ab1af37"
|
@@ -85,4 +85,33 @@ describe("updater", () => {
|
|
85
85
|
expect(error).not.toBeNull();
|
86
86
|
}
|
87
87
|
});
|
88
|
+
|
89
|
+
it("with a package.json which contains illegal character '@' in the name", async () => {
|
90
|
+
copyDependencies("illegal_character", tempDir);
|
91
|
+
|
92
|
+
try {
|
93
|
+
await updateDependencyFiles(tempDir, [
|
94
|
+
{
|
95
|
+
name: "@commitlint/cli",
|
96
|
+
version: "19.3.0",
|
97
|
+
requirements: [
|
98
|
+
{
|
99
|
+
requirement: "^19.3.0",
|
100
|
+
file: "package.json",
|
101
|
+
groups: ["devDependencies"],
|
102
|
+
source:
|
103
|
+
{
|
104
|
+
type: "registry",
|
105
|
+
url: "https://registry.yarnpkg.com"
|
106
|
+
}
|
107
|
+
}
|
108
|
+
]
|
109
|
+
}
|
110
|
+
]
|
111
|
+
);
|
112
|
+
} catch (error) {
|
113
|
+
expect(error).not.toBeNull();
|
114
|
+
expect(error.message).toEqual("package.json: Name contains illegal characters")
|
115
|
+
}
|
116
|
+
});
|
88
117
|
});
|
@@ -291,7 +291,7 @@ module Dependabot
|
|
291
291
|
semver_version_for(lockfile_details&.fetch("version", ""))
|
292
292
|
end
|
293
293
|
|
294
|
-
sig { params(version: String).returns(T.nilable(T.any(String, Integer, Gem::Version))) }
|
294
|
+
sig { params(version: T.nilable(String)).returns(T.nilable(T.any(String, Integer, Gem::Version))) }
|
295
295
|
def semver_version_for(version)
|
296
296
|
version_class.semver_for(version)
|
297
297
|
end
|
@@ -1,6 +1,8 @@
|
|
1
|
-
# typed:
|
1
|
+
# typed: strict
|
2
2
|
# frozen_string_literal: true
|
3
3
|
|
4
|
+
require "sorbet-runtime"
|
5
|
+
|
4
6
|
require "dependabot/npm_and_yarn/file_updater"
|
5
7
|
|
6
8
|
module Dependabot
|
@@ -10,13 +12,25 @@ module Dependabot
|
|
10
12
|
# committed .npmrc
|
11
13
|
# We should refactor this to use UpdateChecker::RegistryFinder
|
12
14
|
class NpmrcBuilder
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
15
|
+
extend T::Sig
|
16
|
+
|
17
|
+
CENTRAL_REGISTRIES = T.let(
|
18
|
+
%w(
|
19
|
+
registry.npmjs.org
|
20
|
+
registry.yarnpkg.com
|
21
|
+
).freeze,
|
22
|
+
T::Array[String]
|
23
|
+
)
|
17
24
|
|
18
25
|
SCOPED_REGISTRY = /^\s*@(?<scope>\S+):registry\s*=\s*(?<registry>\S+)/
|
19
26
|
|
27
|
+
sig do
|
28
|
+
params(
|
29
|
+
dependency_files: T::Array[Dependabot::DependencyFile],
|
30
|
+
credentials: T::Array[Dependabot::Credential],
|
31
|
+
dependencies: T::Array[Dependabot::Dependency]
|
32
|
+
).void
|
33
|
+
end
|
20
34
|
def initialize(dependency_files:, credentials:, dependencies: [])
|
21
35
|
@dependency_files = dependency_files
|
22
36
|
@credentials = credentials
|
@@ -24,6 +38,7 @@ module Dependabot
|
|
24
38
|
end
|
25
39
|
|
26
40
|
# PROXY WORK
|
41
|
+
sig { returns(String) }
|
27
42
|
def npmrc_content
|
28
43
|
initial_content =
|
29
44
|
if npmrc_file then complete_npmrc_from_credentials
|
@@ -48,6 +63,7 @@ module Dependabot
|
|
48
63
|
# PROXY WORK
|
49
64
|
# Yarn allows registries to be defined either in an .npmrc or .yarnrc
|
50
65
|
# so we need to parse both files for registry keys
|
66
|
+
sig { returns(String) }
|
51
67
|
def yarnrc_content
|
52
68
|
initial_content =
|
53
69
|
if npmrc_file then complete_yarnrc_from_credentials
|
@@ -61,65 +77,83 @@ module Dependabot
|
|
61
77
|
|
62
78
|
private
|
63
79
|
|
80
|
+
sig { returns(T::Array[Dependabot::DependencyFile]) }
|
64
81
|
attr_reader :dependency_files
|
82
|
+
|
83
|
+
sig { returns(T::Array[Dependabot::Credential]) }
|
65
84
|
attr_reader :credentials
|
85
|
+
|
86
|
+
sig { returns(T::Array[Dependabot::Dependency]) }
|
66
87
|
attr_reader :dependencies
|
67
88
|
|
89
|
+
sig { returns(T.nilable(String)) }
|
68
90
|
def build_npmrc_content_from_lockfile
|
69
91
|
return unless yarn_lock || package_lock || shrinkwrap
|
70
92
|
return unless global_registry
|
71
93
|
|
72
|
-
registry = global_registry["registry"]
|
73
|
-
registry = "https://#{registry}" unless registry
|
94
|
+
registry = T.must(global_registry)["registry"]
|
95
|
+
registry = "https://#{registry}" unless registry&.start_with?("http")
|
74
96
|
"registry = #{registry}\n" \
|
75
97
|
"#{npmrc_global_registry_auth_line}" \
|
76
98
|
"always-auth = true"
|
77
99
|
end
|
78
100
|
|
101
|
+
sig { returns(T.nilable(String)) }
|
79
102
|
def build_yarnrc_content_from_lockfile
|
80
103
|
return unless yarn_lock || package_lock
|
81
104
|
return unless global_registry
|
82
105
|
|
83
|
-
"registry \"https://#{global_registry['registry']}\"\n" \
|
106
|
+
"registry \"https://#{T.must(global_registry)['registry']}\"\n" \
|
84
107
|
"#{yarnrc_global_registry_auth_line}" \
|
85
108
|
"npmAlwaysAuth: true"
|
86
109
|
end
|
87
110
|
|
88
|
-
|
111
|
+
# rubocop:disable Metrics/PerceivedComplexity
|
112
|
+
# rubocop:disable Metrics/CyclomaticComplexity
|
113
|
+
# rubocop:disable Metrics/AbcSize
|
114
|
+
sig { returns(T.nilable(Dependabot::Credential)) }
|
115
|
+
def global_registry
|
89
116
|
return @global_registry if defined?(@global_registry)
|
90
117
|
|
91
|
-
@global_registry =
|
118
|
+
@global_registry = T.let(
|
92
119
|
registry_credentials.find do |cred|
|
93
120
|
next false if CENTRAL_REGISTRIES.include?(cred["registry"])
|
94
121
|
|
95
122
|
# If all the URLs include this registry, it's global
|
96
|
-
next true if dependency_urls
|
97
|
-
url.include?(cred["registry"])
|
123
|
+
next true if dependency_urls&.size&.positive? && dependency_urls&.all? do |url|
|
124
|
+
url.include?(T.must(cred["registry"]))
|
98
125
|
end
|
99
126
|
|
100
127
|
# Check if this registry has already been defined in .npmrc as a scoped registry
|
101
|
-
next false if npmrc_scoped_registries
|
128
|
+
next false if npmrc_scoped_registries&.any? { |sr| sr.include?(T.must(cred["registry"])) }
|
102
129
|
|
103
|
-
next false if yarnrc_scoped_registries
|
130
|
+
next false if yarnrc_scoped_registries&.any? { |sr| sr.include?(T.must(cred["registry"])) }
|
104
131
|
|
105
132
|
# If any unscoped URLs include this registry, assume it's global
|
106
133
|
dependency_urls
|
107
|
-
|
108
|
-
|
109
|
-
end
|
134
|
+
&.reject { |u| u.include?("@") || u.include?("%40") }
|
135
|
+
&.any? { |url| url.include?(T.must(cred["registry"])) }
|
136
|
+
end,
|
137
|
+
T.nilable(Dependabot::Credential)
|
138
|
+
)
|
110
139
|
end
|
140
|
+
# rubocop:enable Metrics/PerceivedComplexity
|
141
|
+
# rubocop:enable Metrics/CyclomaticComplexity
|
142
|
+
# rubocop:enable Metrics/AbcSize
|
111
143
|
|
144
|
+
sig { returns(String) }
|
112
145
|
def npmrc_global_registry_auth_line
|
113
146
|
# This token is passed in from the Dependabot Config
|
114
147
|
# We write it to the .npmrc file so that it can be used by the VulnerabilityAuditor
|
115
|
-
token = global_registry
|
148
|
+
token = global_registry&.fetch("token", nil)
|
116
149
|
return "" unless token
|
117
150
|
|
118
|
-
auth_line(token, global_registry
|
151
|
+
auth_line(token, global_registry&.fetch("registry")) + "\n"
|
119
152
|
end
|
120
153
|
|
154
|
+
sig { returns(String) }
|
121
155
|
def yarnrc_global_registry_auth_line
|
122
|
-
token = global_registry
|
156
|
+
token = global_registry&.fetch("token", nil)
|
123
157
|
return "" unless token
|
124
158
|
|
125
159
|
if token.include?(":")
|
@@ -133,6 +167,8 @@ module Dependabot
|
|
133
167
|
end
|
134
168
|
end
|
135
169
|
|
170
|
+
# rubocop:disable Metrics/AbcSize
|
171
|
+
sig { returns(T.nilable(T::Array[String])) }
|
136
172
|
def dependency_urls
|
137
173
|
return @dependency_urls if defined?(@dependency_urls)
|
138
174
|
|
@@ -154,55 +190,62 @@ module Dependabot
|
|
154
190
|
npm_lockfile = package_lock || shrinkwrap
|
155
191
|
if npm_lockfile
|
156
192
|
@dependency_urls +=
|
157
|
-
npm_lockfile.content.scan(/"resolved"\s*:\s*"(.*)"/)
|
158
|
-
|
159
|
-
|
160
|
-
|
193
|
+
T.must(npm_lockfile.content).scan(/"resolved"\s*:\s*"(.*)"/)
|
194
|
+
.flatten
|
195
|
+
.select { |url| url.is_a?(String) }
|
196
|
+
.reject { |url| url.start_with?("git") }
|
161
197
|
end
|
162
198
|
if yarn_lock
|
163
199
|
@dependency_urls +=
|
164
|
-
yarn_lock.content.scan(/ resolved "(.*?)"/).flatten
|
200
|
+
T.must(T.must(yarn_lock).content).scan(/ resolved "(.*?)"/).flatten
|
165
201
|
end
|
166
202
|
|
167
203
|
# The registry URL for Bintray goes into the lockfile in a
|
168
204
|
# modified format, so we modify it back before checking against
|
169
205
|
# our credentials
|
170
|
-
@dependency_urls =
|
206
|
+
@dependency_urls = T.let(
|
171
207
|
@dependency_urls.map do |url|
|
172
208
|
url.gsub("dl.bintray.com//", "api.bintray.com/npm/")
|
173
|
-
end
|
209
|
+
end,
|
210
|
+
T.nilable(T::Array[String])
|
211
|
+
)
|
174
212
|
end
|
213
|
+
# rubocop:enable Metrics/AbcSize
|
175
214
|
|
215
|
+
sig { returns(String) }
|
176
216
|
def complete_npmrc_from_credentials
|
177
|
-
initial_content = npmrc_file.content
|
178
|
-
|
217
|
+
initial_content = T.must(T.must(npmrc_file).content)
|
218
|
+
.gsub(/^.*\$\{.*\}.*/, "").strip + "\n"
|
179
219
|
return initial_content unless yarn_lock || package_lock
|
180
220
|
return initial_content unless global_registry
|
181
221
|
|
182
|
-
registry = global_registry["registry"]
|
183
|
-
registry = "https://#{registry}" unless registry
|
222
|
+
registry = T.must(global_registry)["registry"]
|
223
|
+
registry = "https://#{registry}" unless registry&.start_with?("http")
|
184
224
|
initial_content +
|
185
225
|
"registry = #{registry}\n" \
|
186
226
|
"#{npmrc_global_registry_auth_line}" \
|
187
227
|
"always-auth = true\n"
|
188
228
|
end
|
189
229
|
|
230
|
+
sig { returns(String) }
|
190
231
|
def complete_yarnrc_from_credentials
|
191
|
-
initial_content = yarnrc_file.content
|
192
|
-
|
232
|
+
initial_content = T.must(T.must(yarnrc_file).content)
|
233
|
+
.gsub(/^.*\$\{.*\}.*/, "").strip + "\n"
|
193
234
|
return initial_content unless yarn_lock || package_lock
|
194
235
|
return initial_content unless global_registry
|
195
236
|
|
196
237
|
initial_content +
|
197
|
-
"registry: \"https://#{global_registry['registry']}\"\n" \
|
238
|
+
"registry: \"https://#{T.must(global_registry)['registry']}\"\n" \
|
198
239
|
"#{yarnrc_global_registry_auth_line}" \
|
199
240
|
"npmAlwaysAuth: true\n"
|
200
241
|
end
|
201
242
|
|
243
|
+
sig { returns(T.nilable(String)) }
|
202
244
|
def build_npmrc_from_yarnrc
|
203
245
|
yarnrc_global_registry =
|
204
|
-
yarnrc_file
|
205
|
-
|
246
|
+
yarnrc_file&.content
|
247
|
+
&.lines
|
248
|
+
&.find { |line| line.match?(/^\s*registry\s/) }
|
206
249
|
&.match(NpmAndYarn::UpdateChecker::RegistryFinder::YARN_GLOBAL_REGISTRY_REGEX)
|
207
250
|
&.named_captures&.fetch("registry")
|
208
251
|
|
@@ -211,10 +254,12 @@ module Dependabot
|
|
211
254
|
build_npmrc_content_from_lockfile
|
212
255
|
end
|
213
256
|
|
257
|
+
sig { returns(T.nilable(String)) }
|
214
258
|
def build_yarnrc_from_yarnrc
|
215
259
|
yarnrc_global_registry =
|
216
|
-
yarnrc_file
|
217
|
-
|
260
|
+
yarnrc_file&.content
|
261
|
+
&.lines
|
262
|
+
&.find { |line| line.match?(/^\s*registry\s/) }
|
218
263
|
&.match(/^\s*registry\s+"(?<registry>[^"]+)"/)
|
219
264
|
&.named_captures&.fetch("registry")
|
220
265
|
|
@@ -223,12 +268,13 @@ module Dependabot
|
|
223
268
|
build_yarnrc_content_from_lockfile
|
224
269
|
end
|
225
270
|
|
271
|
+
sig { returns(T::Array[String]) }
|
226
272
|
def credential_lines_for_npmrc
|
227
|
-
lines = []
|
273
|
+
lines = T.let([], T::Array[String])
|
228
274
|
registry_credentials.each do |cred|
|
229
275
|
registry = cred.fetch("registry")
|
230
276
|
|
231
|
-
lines += registry_scopes(registry) if registry_scopes(registry)
|
277
|
+
lines += T.must(registry_scopes(registry)) if registry_scopes(registry)
|
232
278
|
|
233
279
|
token = cred.fetch("token", nil)
|
234
280
|
next unless token
|
@@ -242,6 +288,7 @@ module Dependabot
|
|
242
288
|
["always-auth = true"] + lines
|
243
289
|
end
|
244
290
|
|
291
|
+
sig { params(token: String, registry: T.nilable(String)).returns(String) }
|
245
292
|
def auth_line(token, registry = nil)
|
246
293
|
auth = if token.include?(":")
|
247
294
|
encoded_token = Base64.encode64(token).delete("\n")
|
@@ -262,23 +309,30 @@ module Dependabot
|
|
262
309
|
"//#{registry_with_trailing_slash}:#{auth}"
|
263
310
|
end
|
264
311
|
|
312
|
+
sig { returns(T.nilable(T::Array[String])) }
|
265
313
|
def npmrc_scoped_registries
|
266
314
|
return [] unless npmrc_file
|
267
315
|
|
268
|
-
@npmrc_scoped_registries ||=
|
269
|
-
npmrc_file.content.lines.select { |line| line.match?(SCOPED_REGISTRY) }
|
270
|
-
.filter_map { |line| line.match(SCOPED_REGISTRY)&.named_captures&.fetch("registry") }
|
316
|
+
@npmrc_scoped_registries ||= T.let(
|
317
|
+
T.must(T.must(npmrc_file).content).lines.select { |line| line.match?(SCOPED_REGISTRY) }
|
318
|
+
.filter_map { |line| line.match(SCOPED_REGISTRY)&.named_captures&.fetch("registry") },
|
319
|
+
T.nilable(T::Array[String])
|
320
|
+
)
|
271
321
|
end
|
272
322
|
|
323
|
+
sig { returns(T.nilable(T::Array[String])) }
|
273
324
|
def yarnrc_scoped_registries
|
274
325
|
return [] unless yarnrc_file
|
275
326
|
|
276
|
-
@yarnrc_scoped_registries ||=
|
277
|
-
yarnrc_file.content.lines.select { |line| line.match?(SCOPED_REGISTRY) }
|
278
|
-
.filter_map { |line| line.match(SCOPED_REGISTRY)&.named_captures&.fetch("registry") }
|
327
|
+
@yarnrc_scoped_registries ||= T.let(
|
328
|
+
T.must(T.must(yarnrc_file).content).lines.select { |line| line.match?(SCOPED_REGISTRY) }
|
329
|
+
.filter_map { |line| line.match(SCOPED_REGISTRY)&.named_captures&.fetch("registry") },
|
330
|
+
T.nilable(T::Array[String])
|
331
|
+
)
|
279
332
|
end
|
280
333
|
|
281
334
|
# rubocop:disable Metrics/PerceivedComplexity
|
335
|
+
sig { params(registry: String).returns(T.nilable(T::Array[String])) }
|
282
336
|
def registry_scopes(registry)
|
283
337
|
# Central registries don't just apply to scopes
|
284
338
|
return if CENTRAL_REGISTRIES.include?(registry)
|
@@ -289,13 +343,13 @@ module Dependabot
|
|
289
343
|
[registry]
|
290
344
|
affected_urls =
|
291
345
|
dependency_urls
|
292
|
-
|
346
|
+
&.select do |url|
|
293
347
|
next false unless url.include?(registry)
|
294
348
|
|
295
349
|
other_regs.none? { |r| r.include?(registry) && url.include?(r) }
|
296
350
|
end
|
297
351
|
|
298
|
-
scopes = affected_urls.map do |url|
|
352
|
+
scopes = T.must(affected_urls).map do |url|
|
299
353
|
url.split(/\%40|@/)[1]&.split(%r{\%2[fF]|/})&.first
|
300
354
|
end.uniq
|
301
355
|
|
@@ -306,41 +360,65 @@ module Dependabot
|
|
306
360
|
end
|
307
361
|
# rubocop:enable Metrics/PerceivedComplexity
|
308
362
|
|
363
|
+
sig { returns(T::Array[Dependabot::Credential]) }
|
309
364
|
def registry_credentials
|
310
365
|
credentials.select { |cred| cred.fetch("type") == "npm_registry" }
|
311
366
|
end
|
312
367
|
|
368
|
+
sig { returns(T.nilable(T::Hash[String, T.untyped])) }
|
313
369
|
def parsed_package_lock
|
314
|
-
@parsed_package_lock ||=
|
370
|
+
@parsed_package_lock ||= T.let(
|
371
|
+
JSON.parse(T.must(T.must(package_lock).content)),
|
372
|
+
T.nilable(T::Hash[String, T.untyped])
|
373
|
+
)
|
315
374
|
end
|
316
375
|
|
376
|
+
sig { returns(T.nilable(Dependabot::DependencyFile)) }
|
317
377
|
def npmrc_file
|
318
|
-
@npmrc_file ||=
|
319
|
-
|
378
|
+
@npmrc_file ||= T.let(
|
379
|
+
dependency_files.find { |f| f.name.end_with?(".npmrc") },
|
380
|
+
T.nilable(Dependabot::DependencyFile)
|
381
|
+
)
|
320
382
|
end
|
321
383
|
|
384
|
+
sig { returns(T.nilable(Dependabot::DependencyFile)) }
|
322
385
|
def yarnrc_file
|
323
|
-
@yarnrc_file ||=
|
324
|
-
|
386
|
+
@yarnrc_file ||= T.let(
|
387
|
+
dependency_files.find { |f| f.name.end_with?(".yarnrc") },
|
388
|
+
T.nilable(Dependabot::DependencyFile)
|
389
|
+
)
|
325
390
|
end
|
326
391
|
|
392
|
+
sig { returns(T.nilable(Dependabot::DependencyFile)) }
|
327
393
|
def yarnrc_yml_file
|
328
|
-
@yarnrc_yml_file ||=
|
329
|
-
|
394
|
+
@yarnrc_yml_file ||= T.let(
|
395
|
+
dependency_files.find { |f| f.name.end_with?(".yarnrc.yml") },
|
396
|
+
T.nilable(Dependabot::DependencyFile)
|
397
|
+
)
|
330
398
|
end
|
331
399
|
|
400
|
+
sig { returns(T.nilable(Dependabot::DependencyFile)) }
|
332
401
|
def yarn_lock
|
333
|
-
@yarn_lock ||=
|
402
|
+
@yarn_lock ||= T.let(
|
403
|
+
dependency_files.find { |f| f.name == "yarn.lock" },
|
404
|
+
T.nilable(Dependabot::DependencyFile)
|
405
|
+
)
|
334
406
|
end
|
335
407
|
|
408
|
+
sig { returns(T.nilable(Dependabot::DependencyFile)) }
|
336
409
|
def package_lock
|
337
|
-
@package_lock ||=
|
338
|
-
dependency_files.find { |f| f.name == "package-lock.json" }
|
410
|
+
@package_lock ||= T.let(
|
411
|
+
dependency_files.find { |f| f.name == "package-lock.json" },
|
412
|
+
T.nilable(Dependabot::DependencyFile)
|
413
|
+
)
|
339
414
|
end
|
340
415
|
|
416
|
+
sig { returns(T.nilable(Dependabot::DependencyFile)) }
|
341
417
|
def shrinkwrap
|
342
|
-
@shrinkwrap ||=
|
343
|
-
dependency_files.find { |f| f.name == "npm-shrinkwrap.json" }
|
418
|
+
@shrinkwrap ||= T.let(
|
419
|
+
dependency_files.find { |f| f.name == "npm-shrinkwrap.json" },
|
420
|
+
T.nilable(Dependabot::DependencyFile)
|
421
|
+
)
|
344
422
|
end
|
345
423
|
end
|
346
424
|
end
|
@@ -128,6 +128,11 @@ module Dependabot
|
|
128
128
|
end
|
129
129
|
end
|
130
130
|
rescue SharedHelpers::HelperSubprocessFailed => e
|
131
|
+
# package.json name cannot contain characters like empty string or @.
|
132
|
+
if e.message.include?("Name contains illegal characters")
|
133
|
+
raise Dependabot::DependencyFileNotParseable, e.message
|
134
|
+
end
|
135
|
+
|
131
136
|
names = dependencies.map(&:name)
|
132
137
|
package_missing = names.any? do |name|
|
133
138
|
e.message.include?("find package \"#{name}")
|