dependabot-common 0.391.0 → 0.393.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/lib/dependabot/clients/azure.rb +42 -22
- data/lib/dependabot/clients/bitbucket.rb +52 -26
- data/lib/dependabot/clients/bitbucket_with_retries.rb +11 -12
- data/lib/dependabot/clients/codecommit.rb +73 -53
- data/lib/dependabot/clients/github_resource_parser.rb +70 -0
- data/lib/dependabot/clients/github_with_retries.rb +63 -23
- data/lib/dependabot/clients/gitlab_with_retries.rb +19 -17
- data/lib/dependabot/clients/json_response_parser.rb +103 -0
- data/lib/dependabot/command_helpers.rb +89 -13
- data/lib/dependabot/credential.rb +12 -3
- data/lib/dependabot/dependency_requirement.rb +28 -15
- data/lib/dependabot/errors.rb +7 -0
- data/lib/dependabot/file_fetchers/base.rb +196 -140
- data/lib/dependabot/file_updaters/vendor_updater.rb +8 -2
- data/lib/dependabot/git_tag_details.rb +8 -14
- data/lib/dependabot/metadata_finders/base/changelog_finder.rb +211 -110
- data/lib/dependabot/metadata_finders/base/commit_response_parser.rb +68 -0
- data/lib/dependabot/metadata_finders/base/commits_finder.rb +44 -38
- data/lib/dependabot/pull_request_creator/azure.rb +1 -1
- data/lib/dependabot/pull_request_creator/branch_name_template.rb +1 -1
- data/lib/dependabot/pull_request_creator/codecommit.rb +10 -12
- data/lib/dependabot/pull_request_creator/github.rb +55 -35
- data/lib/dependabot/pull_request_creator/gitlab.rb +37 -11
- data/lib/dependabot/pull_request_creator/labeler.rb +65 -15
- data/lib/dependabot/pull_request_creator/message_builder/issue_linker.rb +21 -2
- data/lib/dependabot/pull_request_creator/message_builder/link_and_mention_sanitizer.rb +53 -13
- data/lib/dependabot/pull_request_creator/message_builder/metadata_presenter.rb +20 -13
- data/lib/dependabot/pull_request_creator/pr_name_prefixer.rb +179 -78
- data/lib/dependabot/pull_request_updater/azure.rb +63 -11
- data/lib/dependabot/pull_request_updater/github.rb +44 -34
- data/lib/dependabot/pull_request_updater/gitlab.rb +23 -12
- data/lib/dependabot/pull_request_updater.rb +3 -3
- data/lib/dependabot/shared_helpers.rb +107 -39
- data/lib/dependabot/update_checkers/base.rb +9 -5
- data/lib/dependabot/update_checkers/version_filters.rb +5 -0
- data/lib/dependabot/update_checkers/vulnerability_audit.rb +282 -0
- data/lib/dependabot/workspace/git.rb +36 -5
- data/lib/dependabot.rb +1 -1
- metadata +6 -2
|
@@ -1,9 +1,10 @@
|
|
|
1
|
-
# typed:
|
|
1
|
+
# typed: strong
|
|
2
2
|
# frozen_string_literal: true
|
|
3
3
|
|
|
4
4
|
require "octokit"
|
|
5
5
|
require "sorbet-runtime"
|
|
6
6
|
require "dependabot/pull_request_creator"
|
|
7
|
+
require "dependabot/errors"
|
|
7
8
|
require "dependabot/credential"
|
|
8
9
|
|
|
9
10
|
module Dependabot
|
|
@@ -313,16 +314,13 @@ module Dependabot
|
|
|
313
314
|
def fetch_github_labels
|
|
314
315
|
client = github_client_for_source
|
|
315
316
|
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
T::Array[String]
|
|
319
|
-
)
|
|
320
|
-
|
|
317
|
+
raw_labels = client.labels(source.repo, per_page: 100)
|
|
318
|
+
labels = github_label_names(raw_labels)
|
|
321
319
|
next_link = T.let(client.last_response.rels[:next], T.nilable(Sawyer::Relation))
|
|
322
320
|
|
|
323
321
|
while next_link
|
|
324
322
|
next_page = T.let(next_link.get, Sawyer::Response)
|
|
325
|
-
labels
|
|
323
|
+
labels.concat(github_labels_from_page(next_page))
|
|
326
324
|
next_link = next_page.rels[:next]
|
|
327
325
|
end
|
|
328
326
|
|
|
@@ -331,12 +329,51 @@ module Dependabot
|
|
|
331
329
|
|
|
332
330
|
sig { returns(T::Array[String]) }
|
|
333
331
|
def fetch_gitlab_labels
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
332
|
+
gitlab_client_for_source
|
|
333
|
+
.labels(source.repo, per_page: 100)
|
|
334
|
+
.auto_paginate
|
|
335
|
+
.map { |label| gitlab_label_name(label) }
|
|
336
|
+
end
|
|
337
|
+
|
|
338
|
+
sig { params(label: Sawyer::Resource).returns(String) }
|
|
339
|
+
def github_label_name(label)
|
|
340
|
+
value = T.cast(label[:name], Object)
|
|
341
|
+
return value if value.is_a?(String)
|
|
342
|
+
|
|
343
|
+
raise_bad_label_response("GitHub", "name must be a string")
|
|
344
|
+
end
|
|
345
|
+
|
|
346
|
+
sig { params(response: Sawyer::Response).returns(T::Array[String]) }
|
|
347
|
+
def github_labels_from_page(response)
|
|
348
|
+
github_label_names(T.cast(response.data, Object))
|
|
349
|
+
end
|
|
350
|
+
|
|
351
|
+
sig { params(data: Object).returns(T::Array[String]) }
|
|
352
|
+
def github_label_names(data)
|
|
353
|
+
raise_bad_label_response("GitHub", "page data must be an array") unless data.is_a?(Array)
|
|
354
|
+
|
|
355
|
+
data.map do |raw_label|
|
|
356
|
+
label = T.cast(raw_label, Object)
|
|
357
|
+
raise_bad_label_response("GitHub", "label must be an object") unless label.is_a?(Sawyer::Resource)
|
|
358
|
+
|
|
359
|
+
github_label_name(label)
|
|
360
|
+
end
|
|
361
|
+
end
|
|
362
|
+
|
|
363
|
+
sig { params(label: ::Gitlab::ObjectifiedHash).returns(String) }
|
|
364
|
+
def gitlab_label_name(label)
|
|
365
|
+
value = T.cast(label["name"], Object)
|
|
366
|
+
return value if value.is_a?(String)
|
|
367
|
+
|
|
368
|
+
raise_bad_label_response("GitLab", "name must be a string")
|
|
369
|
+
end
|
|
370
|
+
|
|
371
|
+
sig { params(provider: String, message: String).returns(T.noreturn) }
|
|
372
|
+
def raise_bad_label_response(provider, message)
|
|
373
|
+
raise Dependabot::PrivateSourceBadResponse.new(
|
|
374
|
+
source.url,
|
|
375
|
+
"Malformed #{provider} label response: #{message}"
|
|
338
376
|
)
|
|
339
|
-
.map(&:name)
|
|
340
377
|
end
|
|
341
378
|
|
|
342
379
|
sig { returns(T::Array[String]) }
|
|
@@ -394,7 +431,7 @@ module Dependabot
|
|
|
394
431
|
)
|
|
395
432
|
@labels = [*@labels, DEFAULT_DEPENDENCIES_LABEL].uniq
|
|
396
433
|
rescue Octokit::UnprocessableEntity => e
|
|
397
|
-
raise unless e
|
|
434
|
+
raise unless github_label_already_exists?(e)
|
|
398
435
|
|
|
399
436
|
@labels = [*@labels, DEFAULT_DEPENDENCIES_LABEL].uniq
|
|
400
437
|
end
|
|
@@ -421,7 +458,7 @@ module Dependabot
|
|
|
421
458
|
)
|
|
422
459
|
@labels = [*@labels, DEFAULT_SECURITY_LABEL].uniq
|
|
423
460
|
rescue Octokit::UnprocessableEntity => e
|
|
424
|
-
raise unless e
|
|
461
|
+
raise unless github_label_already_exists?(e)
|
|
425
462
|
|
|
426
463
|
@labels = [*@labels, DEFAULT_SECURITY_LABEL].uniq
|
|
427
464
|
end
|
|
@@ -450,11 +487,24 @@ module Dependabot
|
|
|
450
487
|
)
|
|
451
488
|
@labels = [*@labels, language_name].uniq
|
|
452
489
|
rescue Octokit::UnprocessableEntity => e
|
|
453
|
-
raise unless e
|
|
490
|
+
raise unless github_label_already_exists?(e)
|
|
454
491
|
|
|
455
492
|
@labels = [*@labels, language_name].uniq.compact
|
|
456
493
|
end
|
|
457
494
|
|
|
495
|
+
sig { params(error: Octokit::UnprocessableEntity).returns(T::Boolean) }
|
|
496
|
+
def github_label_already_exists?(error)
|
|
497
|
+
errors = T.cast(error.errors, Object)
|
|
498
|
+
return false unless errors.is_a?(Array)
|
|
499
|
+
|
|
500
|
+
first_error = T.cast(errors.first, Object)
|
|
501
|
+
return false unless first_error.is_a?(Hash)
|
|
502
|
+
|
|
503
|
+
typed_error = T.let(first_error, T::Hash[T.any(Symbol, String), Object])
|
|
504
|
+
code = typed_error[:code] || typed_error["code"]
|
|
505
|
+
code == "already_exists"
|
|
506
|
+
end
|
|
507
|
+
|
|
458
508
|
sig { params(language: String).returns(String) }
|
|
459
509
|
def default_description_for(language)
|
|
460
510
|
"Pull requests that update #{language.capitalize} code"
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
# frozen_string_literal: true
|
|
3
3
|
|
|
4
4
|
require "sorbet-runtime"
|
|
5
|
+
require "uri"
|
|
5
6
|
require "dependabot/pull_request_creator/message_builder"
|
|
6
7
|
|
|
7
8
|
module Dependabot
|
|
@@ -53,19 +54,37 @@ module Dependabot
|
|
|
53
54
|
&.fetch("repo", nil)
|
|
54
55
|
|
|
55
56
|
source = if repo
|
|
56
|
-
"
|
|
57
|
+
"#{qualified_reference_base_url}/#{repo}"
|
|
57
58
|
elsif source_url
|
|
58
59
|
source_url
|
|
59
60
|
end
|
|
60
61
|
|
|
61
62
|
if source
|
|
62
|
-
"[#{repo ? (repo + tag) : tag}](#{source}
|
|
63
|
+
"[#{repo ? (repo + tag) : tag}](#{source}#{issue_path(source)}/#{number})"
|
|
63
64
|
else
|
|
64
65
|
issue_link
|
|
65
66
|
end
|
|
66
67
|
end
|
|
67
68
|
end
|
|
68
69
|
end
|
|
70
|
+
|
|
71
|
+
private
|
|
72
|
+
|
|
73
|
+
sig { params(source: String).returns(String) }
|
|
74
|
+
def issue_path(source)
|
|
75
|
+
URI.parse(source).host&.downcase == "gitlab.com" ? "/-/work_items" : "/issues"
|
|
76
|
+
rescue URI::InvalidURIError
|
|
77
|
+
"/issues"
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
sig { returns(String) }
|
|
81
|
+
def qualified_reference_base_url
|
|
82
|
+
return "https://github.com" unless source_url
|
|
83
|
+
|
|
84
|
+
URI.parse(T.must(source_url)).host&.downcase == "gitlab.com" ? "https://gitlab.com" : "https://github.com"
|
|
85
|
+
rescue URI::InvalidURIError
|
|
86
|
+
"https://github.com"
|
|
87
|
+
end
|
|
69
88
|
end
|
|
70
89
|
end
|
|
71
90
|
end
|
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
require "commonmarker"
|
|
5
5
|
require "sorbet-runtime"
|
|
6
6
|
require "strscan"
|
|
7
|
+
require "uri"
|
|
7
8
|
require "dependabot/pull_request_creator/message_builder"
|
|
8
9
|
|
|
9
10
|
module Dependabot
|
|
@@ -13,6 +14,9 @@ module Dependabot
|
|
|
13
14
|
extend T::Sig
|
|
14
15
|
|
|
15
16
|
GITHUB_USERNAME = /[a-z0-9]+(-[a-z0-9]+)*/i
|
|
17
|
+
GITLAB_USERNAME = /[a-z0-9](?:[a-z0-9_.-]*[a-z0-9_-])?/i
|
|
18
|
+
GITHUB_HOST = "github.com"
|
|
19
|
+
GITLAB_HOST = "gitlab.com"
|
|
16
20
|
GITHUB_REF_REGEX = %r{
|
|
17
21
|
(?:https?://)?
|
|
18
22
|
github\.com/(?<repo>#{GITHUB_USERNAME}/[^/\s]+)/
|
|
@@ -20,9 +24,6 @@ module Dependabot
|
|
|
20
24
|
}x
|
|
21
25
|
# [^/\s#]+ means one or more characters not matching (^) the class /, whitespace (\s), or #
|
|
22
26
|
GITHUB_NWO_REGEX = %r{(?<repo>#{GITHUB_USERNAME}/[^/\s#]+)#(?<number>\d+)}
|
|
23
|
-
MENTION_REGEX = %r{(?<![A-Za-z0-9`~])@#{GITHUB_USERNAME}/?}
|
|
24
|
-
# regex to match a team mention on github
|
|
25
|
-
TEAM_MENTION_REGEX = %r{(?<![A-Za-z0-9`~])@(?<org>#{GITHUB_USERNAME})/(?<team>#{GITHUB_USERNAME})/?}
|
|
26
27
|
# End of string
|
|
27
28
|
EOS_REGEX = /\z/
|
|
28
29
|
|
|
@@ -49,9 +50,18 @@ module Dependabot
|
|
|
49
50
|
sig { returns(T.nilable(String)) }
|
|
50
51
|
attr_reader :github_redirection_service
|
|
51
52
|
|
|
52
|
-
sig {
|
|
53
|
-
|
|
53
|
+
sig { returns(T.nilable(String)) }
|
|
54
|
+
attr_reader :metadata_source_url
|
|
55
|
+
|
|
56
|
+
sig do
|
|
57
|
+
params(
|
|
58
|
+
github_redirection_service: T.nilable(String),
|
|
59
|
+
metadata_source_url: T.nilable(String)
|
|
60
|
+
).void
|
|
61
|
+
end
|
|
62
|
+
def initialize(github_redirection_service:, metadata_source_url: nil)
|
|
54
63
|
@github_redirection_service = github_redirection_service
|
|
64
|
+
@metadata_source_url = metadata_source_url
|
|
55
65
|
end
|
|
56
66
|
|
|
57
67
|
sig { params(text: String, unsafe: T::Boolean, format_html: T::Boolean).returns(String) }
|
|
@@ -90,7 +100,7 @@ module Dependabot
|
|
|
90
100
|
def sanitize_mentions(doc)
|
|
91
101
|
doc.walk do |node|
|
|
92
102
|
if node.type == :text &&
|
|
93
|
-
node.string_content.match?(
|
|
103
|
+
node.string_content.match?(mention_regex)
|
|
94
104
|
nodes = if parent_node_link?(node)
|
|
95
105
|
build_mention_link_text_nodes(node.string_content)
|
|
96
106
|
else
|
|
@@ -111,10 +121,10 @@ module Dependabot
|
|
|
111
121
|
def sanitize_team_mentions(doc)
|
|
112
122
|
doc.walk do |node|
|
|
113
123
|
if node.type == :text &&
|
|
114
|
-
node.string_content.match?(
|
|
124
|
+
node.string_content.match?(team_mention_regex)
|
|
115
125
|
if parent_node_link?(node)
|
|
116
126
|
# Preserve text node formatting while preventing notifications with zero-width space
|
|
117
|
-
node.string_content = node.string_content.gsub(
|
|
127
|
+
node.string_content = node.string_content.gsub(team_mention_regex) do |match|
|
|
118
128
|
insert_zero_width_space_in_mention(match)
|
|
119
129
|
end
|
|
120
130
|
else
|
|
@@ -189,9 +199,9 @@ module Dependabot
|
|
|
189
199
|
scan = StringScanner.new(text)
|
|
190
200
|
|
|
191
201
|
until scan.eos?
|
|
192
|
-
line = scan.scan_until(
|
|
202
|
+
line = scan.scan_until(mention_regex) ||
|
|
193
203
|
scan.scan_until(EOS_REGEX)
|
|
194
|
-
line_match = T.must(line).match(
|
|
204
|
+
line_match = T.must(line).match(mention_regex)
|
|
195
205
|
mention = line_match&.to_s
|
|
196
206
|
text_node = Commonmarker::Node.new(:text)
|
|
197
207
|
|
|
@@ -199,7 +209,7 @@ module Dependabot
|
|
|
199
209
|
text_node.string_content = line_match.pre_match
|
|
200
210
|
nodes << text_node
|
|
201
211
|
nodes << create_link_node(
|
|
202
|
-
"
|
|
212
|
+
"#{mention_profile_base_url}/#{mention.delete_prefix('@')}", mention.to_s
|
|
203
213
|
)
|
|
204
214
|
else
|
|
205
215
|
text_node.string_content = line
|
|
@@ -216,9 +226,9 @@ module Dependabot
|
|
|
216
226
|
|
|
217
227
|
scan = StringScanner.new(text)
|
|
218
228
|
until scan.eos?
|
|
219
|
-
line = scan.scan_until(
|
|
229
|
+
line = scan.scan_until(team_mention_regex) ||
|
|
220
230
|
scan.scan_until(EOS_REGEX)
|
|
221
|
-
line_match = T.must(line).match(
|
|
231
|
+
line_match = T.must(line).match(team_mention_regex)
|
|
222
232
|
mention = line_match&.to_s
|
|
223
233
|
text_node = Commonmarker::Node.new(:text)
|
|
224
234
|
|
|
@@ -235,6 +245,36 @@ module Dependabot
|
|
|
235
245
|
nodes
|
|
236
246
|
end
|
|
237
247
|
|
|
248
|
+
sig { returns(Regexp) }
|
|
249
|
+
def mention_regex
|
|
250
|
+
%r{(?<![A-Za-z0-9`~])@#{mention_username_regex}/?}
|
|
251
|
+
end
|
|
252
|
+
|
|
253
|
+
sig { returns(Regexp) }
|
|
254
|
+
def team_mention_regex
|
|
255
|
+
username_regex = mention_username_regex
|
|
256
|
+
%r{(?<![A-Za-z0-9`~])@(?<org>#{username_regex})/(?<team>#{username_regex})/?}
|
|
257
|
+
end
|
|
258
|
+
|
|
259
|
+
sig { returns(Regexp) }
|
|
260
|
+
def mention_username_regex
|
|
261
|
+
metadata_source_host == GITLAB_HOST ? GITLAB_USERNAME : GITHUB_USERNAME
|
|
262
|
+
end
|
|
263
|
+
|
|
264
|
+
sig { returns(String) }
|
|
265
|
+
def mention_profile_base_url
|
|
266
|
+
"https://#{metadata_source_host == GITLAB_HOST ? GITLAB_HOST : GITHUB_HOST}"
|
|
267
|
+
end
|
|
268
|
+
|
|
269
|
+
sig { returns(T.nilable(String)) }
|
|
270
|
+
def metadata_source_host
|
|
271
|
+
return unless metadata_source_url
|
|
272
|
+
|
|
273
|
+
URI.parse(T.must(metadata_source_url)).host&.downcase
|
|
274
|
+
rescue URI::InvalidURIError
|
|
275
|
+
nil
|
|
276
|
+
end
|
|
277
|
+
|
|
238
278
|
sig { params(text: String).returns(T::Array[Commonmarker::Node]) }
|
|
239
279
|
def build_mention_link_text_nodes(text)
|
|
240
280
|
code_node = Commonmarker::Node.new(:code)
|
|
@@ -85,13 +85,11 @@ module Dependabot
|
|
|
85
85
|
def vulnerabilities_cascade
|
|
86
86
|
return "" unless vulnerabilities_fixed&.any?
|
|
87
87
|
|
|
88
|
-
msg =
|
|
89
|
-
|
|
90
|
-
|
|
88
|
+
msg = T.must(vulnerabilities_fixed).map do |vulnerability|
|
|
89
|
+
details = sanitize_template_tags(serialized_vulnerability_details(vulnerability))
|
|
90
|
+
sanitize_links_and_mentions(details, metadata_source_url: vulnerability["source_url"])
|
|
91
91
|
end
|
|
92
|
-
|
|
93
|
-
msg = sanitize_template_tags(msg)
|
|
94
|
-
msg = sanitize_links_and_mentions(msg)
|
|
92
|
+
msg = msg.join
|
|
95
93
|
|
|
96
94
|
build_details_tag(summary: "Vulnerabilities fixed", body: msg)
|
|
97
95
|
end
|
|
@@ -109,7 +107,7 @@ module Dependabot
|
|
|
109
107
|
base_url: source_url + "/blob/HEAD/"
|
|
110
108
|
)
|
|
111
109
|
msg = sanitize_template_tags(msg)
|
|
112
|
-
msg = sanitize_links_and_mentions(msg)
|
|
110
|
+
msg = sanitize_links_and_mentions(msg, metadata_source_url: releases_url)
|
|
113
111
|
|
|
114
112
|
build_details_tag(summary: "Release notes", body: msg)
|
|
115
113
|
end
|
|
@@ -125,7 +123,7 @@ module Dependabot
|
|
|
125
123
|
msg = link_issues(text: msg)
|
|
126
124
|
msg = fix_relative_links(text: msg, base_url: changelog_url)
|
|
127
125
|
msg = sanitize_template_tags(msg)
|
|
128
|
-
msg = sanitize_links_and_mentions(msg)
|
|
126
|
+
msg = sanitize_links_and_mentions(msg, metadata_source_url: changelog_url)
|
|
129
127
|
|
|
130
128
|
build_details_tag(summary: "Changelog", body: msg)
|
|
131
129
|
end
|
|
@@ -141,7 +139,7 @@ module Dependabot
|
|
|
141
139
|
msg = link_issues(text: msg)
|
|
142
140
|
msg = fix_relative_links(text: msg, base_url: upgrade_guide_url)
|
|
143
141
|
msg = sanitize_template_tags(msg)
|
|
144
|
-
msg = sanitize_links_and_mentions(msg)
|
|
142
|
+
msg = sanitize_links_and_mentions(msg, metadata_source_url: upgrade_guide_url)
|
|
145
143
|
|
|
146
144
|
build_details_tag(summary: "Upgrade guide", body: msg)
|
|
147
145
|
end
|
|
@@ -170,7 +168,7 @@ module Dependabot
|
|
|
170
168
|
"- See full diff in [compare view](#{commits_url})\n"
|
|
171
169
|
end
|
|
172
170
|
msg = link_issues(text: msg)
|
|
173
|
-
msg = sanitize_links_and_mentions(msg)
|
|
171
|
+
msg = sanitize_links_and_mentions(msg, metadata_source_url: commits_url)
|
|
174
172
|
|
|
175
173
|
build_details_tag(summary: "Commits", body: msg)
|
|
176
174
|
end
|
|
@@ -317,10 +315,19 @@ module Dependabot
|
|
|
317
315
|
!%w(bitbucket codecommit).include?(source.provider)
|
|
318
316
|
end
|
|
319
317
|
|
|
320
|
-
sig
|
|
321
|
-
|
|
318
|
+
sig do
|
|
319
|
+
params(
|
|
320
|
+
text: String,
|
|
321
|
+
unsafe: T::Boolean,
|
|
322
|
+
metadata_source_url: T.nilable(String)
|
|
323
|
+
).returns(String)
|
|
324
|
+
end
|
|
325
|
+
def sanitize_links_and_mentions(text, unsafe: false, metadata_source_url: source_url)
|
|
322
326
|
LinkAndMentionSanitizer
|
|
323
|
-
.new(
|
|
327
|
+
.new(
|
|
328
|
+
github_redirection_service: github_redirection_service,
|
|
329
|
+
metadata_source_url: metadata_source_url
|
|
330
|
+
)
|
|
324
331
|
.sanitize_links_and_mentions(text: text, unsafe: unsafe, format_html: source_provider_supports_html?)
|
|
325
332
|
end
|
|
326
333
|
|