dependabot-nuget 0.247.0 → 0.248.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/nuget/file_fetcher.rb +12 -8
- data/lib/dependabot/nuget/file_parser.rb +10 -0
- data/lib/dependabot/nuget/nuget_config_credential_helpers.rb +10 -1
- data/lib/dependabot/nuget/requirement.rb +17 -8
- data/lib/dependabot/nuget/update_checker/nupkg_fetcher.rb +76 -8
- data/lib/dependabot/nuget/update_checker/nuspec_fetcher.rb +25 -3
- data/lib/dependabot/nuget/update_checker/requirements_updater.rb +32 -9
- data/lib/dependabot/nuget/update_checker/version_finder.rb +167 -62
- data/lib/dependabot/nuget/update_checker.rb +73 -29
- metadata +5 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 60679d8e50f3e96aa05400b03ccc9e0dd491c1a7cf340c4c7a39bcb48675c3f6
|
4
|
+
data.tar.gz: 235eb5b57423534578945568766179c2805c6c1e19b5bdb806cc4fd5a5e78dc7
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 1976d20f2b23920eb44176098e89109ee5e969f7e12eaa959e06948e543b9383dcf08c7521eeb9f69602fab37f17ffaafc937e203cce68439327d9735590e1b9
|
7
|
+
data.tar.gz: d240a0489a0ab0dc72283ea736a55965cb13a2fe375cb7eb5a98beb473f9e227bf6ec52a07fba05f2177ee228c716197f60d5fe35d3170b1687aaa07648915eb
|
@@ -25,7 +25,7 @@ module Dependabot
|
|
25
25
|
return true if filenames.any? { |f| f.match?("^src$") }
|
26
26
|
return true if filenames.any? { |f| f.end_with?(".proj") }
|
27
27
|
|
28
|
-
filenames.any? { |name| name.match?(/\.
|
28
|
+
filenames.any? { |name| name.match?(/\.(cs|vb|fs)proj$/) }
|
29
29
|
end
|
30
30
|
|
31
31
|
sig { override.returns(String) }
|
@@ -53,7 +53,7 @@ module Dependabot
|
|
53
53
|
end
|
54
54
|
|
55
55
|
sig { override.returns(T::Array[DependencyFile]) }
|
56
|
-
def fetch_files
|
56
|
+
def fetch_files
|
57
57
|
fetched_files = []
|
58
58
|
fetched_files += project_files
|
59
59
|
fetched_files += directory_build_files
|
@@ -73,10 +73,7 @@ module Dependabot
|
|
73
73
|
if project_files.none? && packages_config_files.none?
|
74
74
|
raise T.must(@missing_sln_project_file_errors.first) if @missing_sln_project_file_errors&.any?
|
75
75
|
|
76
|
-
|
77
|
-
Dependabot::DependencyFileNotFound,
|
78
|
-
File.join(directory, "<anything>.(cs|vb|fs)proj")
|
79
|
-
)
|
76
|
+
raise_dependency_file_not_found
|
80
77
|
end
|
81
78
|
|
82
79
|
fetched_files
|
@@ -102,9 +99,16 @@ module Dependabot
|
|
102
99
|
project_files
|
103
100
|
end
|
104
101
|
rescue Octokit::NotFound, Gitlab::Error::NotFound
|
102
|
+
raise_dependency_file_not_found
|
103
|
+
end
|
104
|
+
|
105
|
+
sig { returns(T.noreturn) }
|
106
|
+
def raise_dependency_file_not_found
|
105
107
|
raise(
|
106
|
-
Dependabot::DependencyFileNotFound
|
107
|
-
|
108
|
+
Dependabot::DependencyFileNotFound.new(
|
109
|
+
File.join(directory, "*.(sln|csproj|vbproj|fsproj|proj)"),
|
110
|
+
"Unable to find `*.sln`, `*.(cs|vb|fs)proj`, or `*.proj` in directory `#{directory}`"
|
111
|
+
)
|
108
112
|
)
|
109
113
|
end
|
110
114
|
|
@@ -44,6 +44,16 @@ module Dependabot
|
|
44
44
|
Dependabot.logger.warn "Dependency '#{d.name}' excluded due to unparsable version: #{d.version}"
|
45
45
|
end
|
46
46
|
|
47
|
+
dependency_info = dependencies.map do |d|
|
48
|
+
requirements_info = d.requirements.filter_map { |r| " file: #{r[:file]}, metadata: #{r[:metadata]}" }
|
49
|
+
.join("\n")
|
50
|
+
" name: #{d.name}, version: #{d.version}\n#{requirements_info}"
|
51
|
+
end.join("\n")
|
52
|
+
|
53
|
+
if dependencies.length.positive?
|
54
|
+
Dependabot.logger.info "The following dependencies were found:\n#{dependency_info}"
|
55
|
+
end
|
56
|
+
|
47
57
|
dependencies
|
48
58
|
end
|
49
59
|
|
@@ -1,18 +1,25 @@
|
|
1
|
-
# typed:
|
1
|
+
# typed: strong
|
2
2
|
# frozen_string_literal: true
|
3
3
|
|
4
|
+
require "sorbet-runtime"
|
5
|
+
|
4
6
|
module Dependabot
|
5
7
|
module Nuget
|
6
8
|
module NuGetConfigCredentialHelpers
|
9
|
+
extend T::Sig
|
10
|
+
|
11
|
+
sig { returns(String) }
|
7
12
|
def self.user_nuget_config_path
|
8
13
|
home_directory = Dir.home
|
9
14
|
File.join(home_directory, ".nuget", "NuGet", "NuGet.Config")
|
10
15
|
end
|
11
16
|
|
17
|
+
sig { returns(String) }
|
12
18
|
def self.temporary_nuget_config_path
|
13
19
|
user_nuget_config_path + "_ORIGINAL"
|
14
20
|
end
|
15
21
|
|
22
|
+
sig { params(credentials: T::Array[Dependabot::Credential]).void }
|
16
23
|
def self.add_credentials_to_nuget_config(credentials)
|
17
24
|
return unless File.exist?(user_nuget_config_path)
|
18
25
|
|
@@ -48,6 +55,7 @@ module Dependabot
|
|
48
55
|
File.write(user_nuget_config_path, nuget_config)
|
49
56
|
end
|
50
57
|
|
58
|
+
sig { void }
|
51
59
|
def self.restore_user_nuget_config
|
52
60
|
return unless File.exist?(temporary_nuget_config_path)
|
53
61
|
|
@@ -55,6 +63,7 @@ module Dependabot
|
|
55
63
|
File.rename(temporary_nuget_config_path, user_nuget_config_path)
|
56
64
|
end
|
57
65
|
|
66
|
+
sig { params(credentials: T::Array[Dependabot::Credential], _block: T.proc.void).void }
|
58
67
|
def self.patch_nuget_config_for_action(credentials, &_block)
|
59
68
|
add_credentials_to_nuget_config(credentials)
|
60
69
|
begin
|
@@ -1,4 +1,4 @@
|
|
1
|
-
# typed:
|
1
|
+
# typed: strict
|
2
2
|
# frozen_string_literal: true
|
3
3
|
|
4
4
|
require "sorbet-runtime"
|
@@ -12,6 +12,9 @@ require "dependabot/nuget/version"
|
|
12
12
|
module Dependabot
|
13
13
|
module Nuget
|
14
14
|
class Requirement < Dependabot::Requirement
|
15
|
+
extend T::Sig
|
16
|
+
|
17
|
+
sig { override.params(obj: T.any(Gem::Version, String)).returns([String, Gem::Version]) }
|
15
18
|
def self.parse(obj)
|
16
19
|
return ["=", Nuget::Version.new(obj.to_s)] if obj.is_a?(Gem::Version)
|
17
20
|
|
@@ -28,11 +31,12 @@ module Dependabot
|
|
28
31
|
# For consistency with other languages, we define a requirements array.
|
29
32
|
# Dotnet doesn't have an `OR` separator for requirements, so it always
|
30
33
|
# contains a single element.
|
31
|
-
sig { override.params(requirement_string: T.nilable(String)).returns(T::Array[Requirement]) }
|
34
|
+
sig { override.params(requirement_string: T.nilable(String)).returns(T::Array[Dependabot::Requirement]) }
|
32
35
|
def self.requirements_array(requirement_string)
|
33
36
|
[new(requirement_string)]
|
34
37
|
end
|
35
38
|
|
39
|
+
sig { params(requirements: T.any(T.nilable(String), T::Array[T.nilable(String)])).void }
|
36
40
|
def initialize(*requirements)
|
37
41
|
requirements = requirements.flatten.flat_map do |req_string|
|
38
42
|
convert_dotnet_constraint_to_ruby_constraint(req_string)
|
@@ -41,6 +45,7 @@ module Dependabot
|
|
41
45
|
super(requirements)
|
42
46
|
end
|
43
47
|
|
48
|
+
sig { override.params(version: Gem::Version).returns(T::Boolean) }
|
44
49
|
def satisfied_by?(version)
|
45
50
|
version = Nuget::Version.new(version.to_s)
|
46
51
|
super
|
@@ -48,10 +53,11 @@ module Dependabot
|
|
48
53
|
|
49
54
|
private
|
50
55
|
|
56
|
+
sig { params(req_string: T.nilable(String)).returns(T.nilable(T.any(String, T::Array[String]))) }
|
51
57
|
def convert_dotnet_constraint_to_ruby_constraint(req_string)
|
52
58
|
return unless req_string
|
53
59
|
|
54
|
-
return convert_dotnet_range_to_ruby_range(req_string) if req_string
|
60
|
+
return convert_dotnet_range_to_ruby_range(req_string) if req_string.start_with?("(", "[")
|
55
61
|
|
56
62
|
return req_string.split(",").map(&:strip) if req_string.include?(",")
|
57
63
|
|
@@ -61,6 +67,7 @@ module Dependabot
|
|
61
67
|
end
|
62
68
|
|
63
69
|
# rubocop:disable Metrics/PerceivedComplexity
|
70
|
+
sig { params(req_string: String).returns(T::Array[String]) }
|
64
71
|
def convert_dotnet_range_to_ruby_range(req_string)
|
65
72
|
lower_b, upper_b = req_string.split(",").map(&:strip).map do |bound|
|
66
73
|
next convert_range_wildcard_req(bound) if bound.include?("*")
|
@@ -70,9 +77,9 @@ module Dependabot
|
|
70
77
|
|
71
78
|
lower_b =
|
72
79
|
if ["(", "["].include?(lower_b) then nil
|
73
|
-
elsif lower_b.start_with?("(") then "> #{lower_b.sub(/\(\s*/, '')}"
|
80
|
+
elsif T.must(lower_b).start_with?("(") then "> #{T.must(lower_b).sub(/\(\s*/, '')}"
|
74
81
|
else
|
75
|
-
">= #{lower_b.sub(/\[\s*/, '').strip}"
|
82
|
+
">= #{T.must(lower_b).sub(/\[\s*/, '').strip}"
|
76
83
|
end
|
77
84
|
|
78
85
|
upper_b =
|
@@ -87,20 +94,22 @@ module Dependabot
|
|
87
94
|
end
|
88
95
|
# rubocop:enable Metrics/PerceivedComplexity
|
89
96
|
|
97
|
+
sig { params(req_string: String).returns(String) }
|
90
98
|
def convert_range_wildcard_req(req_string)
|
91
|
-
range_end = req_string[-1]
|
92
|
-
defined_part = req_string.split("*").first
|
99
|
+
range_end = T.must(req_string[-1])
|
100
|
+
defined_part = T.must(req_string.split("*").first)
|
93
101
|
version = defined_part + "0"
|
94
102
|
version += range_end if [")", "]"].include?(range_end)
|
95
103
|
version
|
96
104
|
end
|
97
105
|
|
106
|
+
sig { params(req_string: String).returns(String) }
|
98
107
|
def convert_wildcard_req(req_string)
|
99
108
|
return ">= 0-a" if req_string == "*-*"
|
100
109
|
|
101
110
|
return ">= 0" if req_string.start_with?("*")
|
102
111
|
|
103
|
-
defined_part = req_string.split("*").first
|
112
|
+
defined_part = T.must(req_string.split("*").first)
|
104
113
|
suffix = defined_part.end_with?(".") ? "0" : "a"
|
105
114
|
version = defined_part + suffix
|
106
115
|
"~> #{version}"
|
@@ -1,23 +1,43 @@
|
|
1
|
-
# typed:
|
1
|
+
# typed: strict
|
2
2
|
# frozen_string_literal: true
|
3
3
|
|
4
4
|
require "nokogiri"
|
5
|
-
require "zip"
|
6
5
|
require "stringio"
|
6
|
+
require "sorbet-runtime"
|
7
|
+
require "zip"
|
8
|
+
|
7
9
|
require "dependabot/nuget/http_response_helpers"
|
8
10
|
|
9
11
|
module Dependabot
|
10
12
|
module Nuget
|
11
13
|
class NupkgFetcher
|
14
|
+
extend T::Sig
|
15
|
+
|
12
16
|
require_relative "repository_finder"
|
13
17
|
|
18
|
+
sig do
|
19
|
+
params(
|
20
|
+
dependency_urls: T::Array[T::Hash[Symbol, String]],
|
21
|
+
package_id: String,
|
22
|
+
package_version: String
|
23
|
+
)
|
24
|
+
.returns(T.nilable(String))
|
25
|
+
end
|
14
26
|
def self.fetch_nupkg_buffer(dependency_urls, package_id, package_version)
|
15
27
|
# check all repositories for the first one that has the nupkg
|
16
|
-
dependency_urls.reduce(nil) do |nupkg_buffer, repository_details|
|
28
|
+
dependency_urls.reduce(T.let(nil, T.nilable(String))) do |nupkg_buffer, repository_details|
|
17
29
|
nupkg_buffer || fetch_nupkg_buffer_from_repository(repository_details, package_id, package_version)
|
18
30
|
end
|
19
31
|
end
|
20
32
|
|
33
|
+
sig do
|
34
|
+
params(
|
35
|
+
repository_details: T::Hash[Symbol, T.untyped],
|
36
|
+
package_id: T.nilable(String),
|
37
|
+
package_version: T.nilable(String)
|
38
|
+
)
|
39
|
+
.returns(T.nilable(String))
|
40
|
+
end
|
21
41
|
def self.fetch_nupkg_url_from_repository(repository_details, package_id, package_version)
|
22
42
|
return unless package_id && package_version && !package_version.empty?
|
23
43
|
|
@@ -35,6 +55,14 @@ module Dependabot
|
|
35
55
|
package_url
|
36
56
|
end
|
37
57
|
|
58
|
+
sig do
|
59
|
+
params(
|
60
|
+
repository_details: T::Hash[Symbol, T.untyped],
|
61
|
+
package_id: String,
|
62
|
+
package_version: String
|
63
|
+
)
|
64
|
+
.returns(T.nilable(String))
|
65
|
+
end
|
38
66
|
def self.fetch_nupkg_buffer_from_repository(repository_details, package_id, package_version)
|
39
67
|
package_url = fetch_nupkg_url_from_repository(repository_details, package_id, package_version)
|
40
68
|
return unless package_url
|
@@ -43,6 +71,14 @@ module Dependabot
|
|
43
71
|
fetch_stream(package_url, auth_header)
|
44
72
|
end
|
45
73
|
|
74
|
+
sig do
|
75
|
+
params(
|
76
|
+
repository_details: T::Hash[Symbol, T.untyped],
|
77
|
+
package_id: String,
|
78
|
+
package_version: String
|
79
|
+
)
|
80
|
+
.returns(T.nilable(String))
|
81
|
+
end
|
46
82
|
def self.get_nuget_v3_package_url(repository_details, package_id, package_version)
|
47
83
|
base_url = repository_details[:base_url]
|
48
84
|
unless base_url
|
@@ -57,15 +93,23 @@ module Dependabot
|
|
57
93
|
|
58
94
|
# rubocop:disable Metrics/CyclomaticComplexity
|
59
95
|
# rubocop:disable Metrics/PerceivedComplexity
|
96
|
+
sig do
|
97
|
+
params(
|
98
|
+
repository_details: T::Hash[Symbol, T.untyped],
|
99
|
+
package_id: String,
|
100
|
+
package_version: String
|
101
|
+
)
|
102
|
+
.returns(T.nilable(String))
|
103
|
+
end
|
60
104
|
def self.get_nuget_v3_package_url_from_search(repository_details, package_id, package_version)
|
61
105
|
search_url = repository_details[:search_url]
|
62
106
|
return nil unless search_url
|
63
107
|
|
64
108
|
# get search result
|
65
109
|
search_result_response = fetch_url(search_url, repository_details)
|
66
|
-
return nil unless search_result_response
|
110
|
+
return nil unless search_result_response&.status == 200
|
67
111
|
|
68
|
-
search_response_body = HttpResponseHelpers.remove_wrapping_zero_width_chars(search_result_response.body)
|
112
|
+
search_response_body = HttpResponseHelpers.remove_wrapping_zero_width_chars(T.must(search_result_response).body)
|
69
113
|
search_results = JSON.parse(search_response_body)
|
70
114
|
|
71
115
|
# find matching package and version
|
@@ -90,15 +134,23 @@ module Dependabot
|
|
90
134
|
# rubocop:enable Metrics/PerceivedComplexity
|
91
135
|
# rubocop:enable Metrics/CyclomaticComplexity
|
92
136
|
|
137
|
+
sig do
|
138
|
+
params(
|
139
|
+
repository_details: T::Hash[Symbol, T.untyped],
|
140
|
+
package_id: String,
|
141
|
+
package_version: String
|
142
|
+
)
|
143
|
+
.returns(T.nilable(String))
|
144
|
+
end
|
93
145
|
def self.get_nuget_v2_package_url(repository_details, package_id, package_version)
|
94
146
|
# get package XML
|
95
147
|
base_url = repository_details[:base_url].delete_suffix("/")
|
96
148
|
package_url = "#{base_url}/Packages(Id='#{package_id}',Version='#{package_version}')"
|
97
149
|
response = fetch_url(package_url, repository_details)
|
98
|
-
return nil unless response
|
150
|
+
return nil unless response&.status == 200
|
99
151
|
|
100
152
|
# find relevant element
|
101
|
-
doc = Nokogiri::XML(response.body)
|
153
|
+
doc = Nokogiri::XML(T.must(response).body)
|
102
154
|
doc.remove_namespaces!
|
103
155
|
|
104
156
|
content_element = doc.xpath("/entry/content")
|
@@ -106,6 +158,14 @@ module Dependabot
|
|
106
158
|
nupkg_url
|
107
159
|
end
|
108
160
|
|
161
|
+
sig do
|
162
|
+
params(
|
163
|
+
stream_url: String,
|
164
|
+
auth_header: T::Hash[String, String],
|
165
|
+
max_redirects: Integer
|
166
|
+
)
|
167
|
+
.returns(T.nilable(String))
|
168
|
+
end
|
109
169
|
def self.fetch_stream(stream_url, auth_header, max_redirects = 5)
|
110
170
|
current_url = stream_url
|
111
171
|
current_redirects = 0
|
@@ -128,17 +188,25 @@ module Dependabot
|
|
128
188
|
current_redirects += 1
|
129
189
|
return nil if current_redirects > max_redirects
|
130
190
|
|
131
|
-
current_url = response.headers["Location"]
|
191
|
+
current_url = T.must(response.headers["Location"])
|
132
192
|
else
|
133
193
|
return nil
|
134
194
|
end
|
135
195
|
end
|
136
196
|
end
|
137
197
|
|
198
|
+
sig do
|
199
|
+
params(
|
200
|
+
url: String,
|
201
|
+
repository_details: T::Hash[Symbol, T.untyped]
|
202
|
+
)
|
203
|
+
.returns(T.nilable(Excon::Response))
|
204
|
+
end
|
138
205
|
def self.fetch_url(url, repository_details)
|
139
206
|
fetch_url_with_auth(url, repository_details.fetch(:auth_header))
|
140
207
|
end
|
141
208
|
|
209
|
+
sig { params(url: String, auth_header: T::Hash[T.any(String, Symbol), T.untyped]).returns(Excon::Response) }
|
142
210
|
def self.fetch_url_with_auth(url, auth_header)
|
143
211
|
cache = CacheManager.cache("nupkg_fetcher_cache")
|
144
212
|
cache[url] ||= Dependabot::RegistryClient.get(
|
@@ -1,23 +1,42 @@
|
|
1
|
-
# typed:
|
1
|
+
# typed: strict
|
2
2
|
# frozen_string_literal: true
|
3
3
|
|
4
4
|
require "nokogiri"
|
5
|
-
require "zip"
|
6
5
|
require "stringio"
|
6
|
+
require "sorbet-runtime"
|
7
|
+
require "zip"
|
7
8
|
|
8
9
|
module Dependabot
|
9
10
|
module Nuget
|
10
11
|
class NuspecFetcher
|
12
|
+
extend T::Sig
|
13
|
+
|
11
14
|
require_relative "nupkg_fetcher"
|
12
15
|
require_relative "repository_finder"
|
13
16
|
|
17
|
+
sig do
|
18
|
+
params(
|
19
|
+
dependency_urls: T::Array[T::Hash[Symbol, String]],
|
20
|
+
package_id: String,
|
21
|
+
package_version: String
|
22
|
+
)
|
23
|
+
.returns(T.nilable(Nokogiri::XML::Document))
|
24
|
+
end
|
14
25
|
def self.fetch_nuspec(dependency_urls, package_id, package_version)
|
15
26
|
# check all repositories for the first one that has the nuspec
|
16
|
-
dependency_urls.reduce(nil) do |nuspec_xml, repository_details|
|
27
|
+
dependency_urls.reduce(T.let(nil, T.nilable(Nokogiri::XML::Document))) do |nuspec_xml, repository_details|
|
17
28
|
nuspec_xml || fetch_nuspec_from_repository(repository_details, package_id, package_version)
|
18
29
|
end
|
19
30
|
end
|
20
31
|
|
32
|
+
sig do
|
33
|
+
params(
|
34
|
+
repository_details: T::Hash[Symbol, T.untyped],
|
35
|
+
package_id: T.nilable(String),
|
36
|
+
package_version: T.nilable(String)
|
37
|
+
)
|
38
|
+
.returns(T.nilable(Nokogiri::XML::Document))
|
39
|
+
end
|
21
40
|
def self.fetch_nuspec_from_repository(repository_details, package_id, package_version)
|
22
41
|
return unless package_id && package_version && !package_version.empty?
|
23
42
|
|
@@ -55,6 +74,7 @@ module Dependabot
|
|
55
74
|
nuspec_xml
|
56
75
|
end
|
57
76
|
|
77
|
+
sig { params(feed_url: String).returns(T::Boolean) }
|
58
78
|
def self.feed_supports_nuspec_download?(feed_url)
|
59
79
|
feed_regexs = [
|
60
80
|
# nuget
|
@@ -67,6 +87,7 @@ module Dependabot
|
|
67
87
|
feed_regexs.any? { |reg| reg.match(feed_url) }
|
68
88
|
end
|
69
89
|
|
90
|
+
sig { params(zip_stream: String, package_id: String).returns(T.nilable(String)) }
|
70
91
|
def self.extract_nuspec(zip_stream, package_id)
|
71
92
|
Zip::File.open_buffer(zip_stream) do |zip|
|
72
93
|
nuspec_entry = zip.find { |entry| entry.name == "#{package_id}.nuspec" }
|
@@ -75,6 +96,7 @@ module Dependabot
|
|
75
96
|
nil
|
76
97
|
end
|
77
98
|
|
99
|
+
sig { params(string: String).returns(String) }
|
78
100
|
def self.remove_invalid_characters(string)
|
79
101
|
string.dup
|
80
102
|
.force_encoding(Encoding::UTF_8)
|
@@ -1,4 +1,4 @@
|
|
1
|
-
# typed:
|
1
|
+
# typed: strict
|
2
2
|
# frozen_string_literal: true
|
3
3
|
|
4
4
|
#######################################################################
|
@@ -6,6 +6,8 @@
|
|
6
6
|
# https://docs.microsoft.com/en-us/nuget/reference/package-versioning #
|
7
7
|
#######################################################################
|
8
8
|
|
9
|
+
require "sorbet-runtime"
|
10
|
+
|
9
11
|
require "dependabot/update_checkers/base"
|
10
12
|
require "dependabot/nuget/version"
|
11
13
|
|
@@ -13,14 +15,25 @@ module Dependabot
|
|
13
15
|
module Nuget
|
14
16
|
class UpdateChecker < Dependabot::UpdateCheckers::Base
|
15
17
|
class RequirementsUpdater
|
18
|
+
extend T::Sig
|
19
|
+
|
20
|
+
sig do
|
21
|
+
params(
|
22
|
+
requirements: T::Array[T::Hash[Symbol, T.untyped]],
|
23
|
+
latest_version: T.nilable(T.any(String, Dependabot::Nuget::Version)),
|
24
|
+
source_details: T.nilable(T::Hash[Symbol, T.untyped])
|
25
|
+
)
|
26
|
+
.void
|
27
|
+
end
|
16
28
|
def initialize(requirements:, latest_version:, source_details:)
|
17
29
|
@requirements = requirements
|
18
30
|
@source_details = source_details
|
19
31
|
return unless latest_version
|
20
32
|
|
21
|
-
@latest_version = version_class.new(latest_version)
|
33
|
+
@latest_version = T.let(version_class.new(latest_version), Dependabot::Nuget::Version)
|
22
34
|
end
|
23
35
|
|
36
|
+
sig { returns(T::Array[T::Hash[Symbol, T.untyped]]) }
|
24
37
|
def updated_requirements
|
25
38
|
return requirements unless latest_version
|
26
39
|
|
@@ -52,32 +65,42 @@ module Dependabot
|
|
52
65
|
|
53
66
|
private
|
54
67
|
|
55
|
-
|
68
|
+
sig { returns(T::Array[T::Hash[Symbol, T.untyped]]) }
|
69
|
+
attr_reader :requirements
|
70
|
+
|
71
|
+
sig { returns(T.nilable(Dependabot::Nuget::Version)) }
|
72
|
+
attr_reader :latest_version
|
73
|
+
|
74
|
+
sig { returns(T.nilable(T::Hash[Symbol, T.untyped])) }
|
75
|
+
attr_reader :source_details
|
56
76
|
|
77
|
+
sig { returns(T.class_of(Dependabot::Nuget::Version)) }
|
57
78
|
def version_class
|
58
|
-
Nuget::Version
|
79
|
+
Dependabot::Nuget::Version
|
59
80
|
end
|
60
81
|
|
82
|
+
sig { params(req_string: String).returns(String) }
|
61
83
|
def update_wildcard_requirement(req_string)
|
62
84
|
return req_string if req_string == "*-*"
|
63
85
|
|
64
86
|
return req_string if req_string == "*"
|
65
87
|
|
66
|
-
precision = req_string.split("*").first.split(/\.|\-/).count
|
88
|
+
precision = T.must(req_string.split("*").first).split(/\.|\-/).count
|
67
89
|
wildcard_section = req_string.partition(/(?=[.\-]\*)/).last
|
68
90
|
|
69
|
-
version_parts = latest_version.segments.first(precision)
|
91
|
+
version_parts = T.must(latest_version).segments.first(precision)
|
70
92
|
version = version_parts.join(".")
|
71
93
|
|
72
94
|
version + wildcard_section
|
73
95
|
end
|
74
96
|
|
97
|
+
sig { returns(T::Hash[Symbol, T.untyped]) }
|
75
98
|
def updated_source
|
76
99
|
{
|
77
100
|
type: "nuget_repo",
|
78
|
-
url: source_details
|
79
|
-
nuspec_url: source_details
|
80
|
-
source_url: source_details
|
101
|
+
url: source_details&.fetch(:repo_url),
|
102
|
+
nuspec_url: source_details&.fetch(:nuspec_url),
|
103
|
+
source_url: source_details&.fetch(:source_url)
|
81
104
|
}
|
82
105
|
end
|
83
106
|
end
|
@@ -1,16 +1,18 @@
|
|
1
|
-
# typed:
|
1
|
+
# typed: strict
|
2
2
|
# frozen_string_literal: true
|
3
3
|
|
4
|
+
require "sorbet-runtime"
|
5
|
+
|
4
6
|
require "dependabot/nuget/version"
|
5
7
|
require "dependabot/nuget/requirement"
|
6
8
|
require "dependabot/update_checkers/base"
|
7
9
|
require "dependabot/update_checkers/version_filters"
|
8
10
|
require "dependabot/nuget/nuget_client"
|
9
|
-
require "sorbet-runtime"
|
10
11
|
|
11
12
|
module Dependabot
|
12
13
|
module Nuget
|
13
14
|
class UpdateChecker < Dependabot::UpdateCheckers::Base
|
15
|
+
# rubocop:disable Metrics/ClassLength
|
14
16
|
class VersionFinder
|
15
17
|
extend T::Sig
|
16
18
|
|
@@ -19,10 +21,24 @@ module Dependabot
|
|
19
21
|
|
20
22
|
NUGET_RANGE_REGEX = /[\(\[].*,.*[\)\]]/
|
21
23
|
|
22
|
-
|
23
|
-
|
24
|
+
sig do
|
25
|
+
params(
|
26
|
+
dependency: Dependabot::Dependency,
|
27
|
+
dependency_files: T::Array[Dependabot::DependencyFile],
|
28
|
+
credentials: T::Array[Dependabot::Credential],
|
29
|
+
ignored_versions: T::Array[String],
|
30
|
+
security_advisories: T::Array[Dependabot::SecurityAdvisory],
|
31
|
+
repo_contents_path: T.nilable(String),
|
32
|
+
raise_on_ignored: T::Boolean
|
33
|
+
).void
|
34
|
+
end
|
35
|
+
def initialize(dependency:,
|
36
|
+
dependency_files:,
|
37
|
+
credentials:,
|
38
|
+
ignored_versions:,
|
24
39
|
security_advisories:,
|
25
|
-
repo_contents_path
|
40
|
+
repo_contents_path:,
|
41
|
+
raise_on_ignored: false)
|
26
42
|
@dependency = dependency
|
27
43
|
@dependency_files = dependency_files
|
28
44
|
@credentials = credentials
|
@@ -32,53 +48,89 @@ module Dependabot
|
|
32
48
|
@repo_contents_path = repo_contents_path
|
33
49
|
end
|
34
50
|
|
51
|
+
sig { returns(T.nilable(T::Hash[Symbol, T.untyped])) }
|
35
52
|
def latest_version_details
|
36
53
|
@latest_version_details ||=
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
54
|
+
T.let(
|
55
|
+
begin
|
56
|
+
possible_versions = versions
|
57
|
+
possible_versions = filter_prereleases(possible_versions)
|
58
|
+
possible_versions = filter_ignored_versions(possible_versions)
|
59
|
+
|
60
|
+
find_highest_compatible_version(possible_versions)
|
61
|
+
end,
|
62
|
+
T.nilable(T::Hash[Symbol, T.untyped])
|
63
|
+
)
|
44
64
|
end
|
45
65
|
|
66
|
+
sig { returns(T.nilable(T::Hash[Symbol, T.untyped])) }
|
46
67
|
def lowest_security_fix_version_details
|
47
68
|
@lowest_security_fix_version_details ||=
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
possible_versions
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
69
|
+
T.let(
|
70
|
+
begin
|
71
|
+
possible_versions = versions
|
72
|
+
possible_versions = filter_prereleases(possible_versions)
|
73
|
+
possible_versions = Dependabot::UpdateCheckers::VersionFilters.filter_vulnerable_versions(
|
74
|
+
possible_versions, security_advisories
|
75
|
+
)
|
76
|
+
possible_versions = filter_ignored_versions(possible_versions)
|
77
|
+
possible_versions = filter_lower_versions(possible_versions)
|
78
|
+
|
79
|
+
find_lowest_compatible_version(possible_versions)
|
80
|
+
end,
|
81
|
+
T.nilable(T::Hash[Symbol, T.untyped])
|
82
|
+
)
|
59
83
|
end
|
60
84
|
|
85
|
+
sig { returns(T::Array[T::Hash[Symbol, T.nilable(T.any(Dependabot::Version, String))]]) }
|
61
86
|
def versions
|
62
87
|
available_v3_versions + available_v2_versions
|
63
88
|
end
|
64
89
|
|
65
|
-
|
66
|
-
|
90
|
+
sig { returns(Dependabot::Dependency) }
|
91
|
+
attr_reader :dependency
|
92
|
+
|
93
|
+
sig { returns(T::Array[Dependabot::DependencyFile]) }
|
94
|
+
attr_reader :dependency_files
|
95
|
+
|
96
|
+
sig { returns(T::Array[Dependabot::Credential]) }
|
97
|
+
attr_reader :credentials
|
98
|
+
|
99
|
+
sig { returns(T::Array[String]) }
|
100
|
+
attr_reader :ignored_versions
|
101
|
+
|
102
|
+
sig { returns(T::Array[Dependabot::SecurityAdvisory]) }
|
103
|
+
attr_reader :security_advisories
|
104
|
+
|
105
|
+
sig { returns(T.nilable(String)) }
|
106
|
+
attr_reader :repo_contents_path
|
67
107
|
|
68
108
|
private
|
69
109
|
|
110
|
+
sig do
|
111
|
+
params(possible_versions: T::Array[T::Hash[Symbol, T.untyped]])
|
112
|
+
.returns(T.nilable(T::Hash[Symbol, T.untyped]))
|
113
|
+
end
|
70
114
|
def find_highest_compatible_version(possible_versions)
|
71
115
|
# sorted versions descending
|
72
116
|
sorted_versions = possible_versions.sort_by { |v| v.fetch(:version) }.reverse
|
73
117
|
find_compatible_version(sorted_versions)
|
74
118
|
end
|
75
119
|
|
120
|
+
sig do
|
121
|
+
params(possible_versions: T::Array[T::Hash[Symbol, T.untyped]])
|
122
|
+
.returns(T.nilable(T::Hash[Symbol, T.untyped]))
|
123
|
+
end
|
76
124
|
def find_lowest_compatible_version(possible_versions)
|
77
125
|
# sorted versions ascending
|
78
126
|
sorted_versions = possible_versions.sort_by { |v| v.fetch(:version) }
|
79
127
|
find_compatible_version(sorted_versions)
|
80
128
|
end
|
81
129
|
|
130
|
+
sig do
|
131
|
+
params(sorted_versions: T::Array[T::Hash[Symbol, T.untyped]])
|
132
|
+
.returns(T.nilable(T::Hash[Symbol, T.untyped]))
|
133
|
+
end
|
82
134
|
def find_compatible_version(sorted_versions)
|
83
135
|
# By checking the first version separately, we can avoid additional network requests
|
84
136
|
first_version = sorted_versions.first
|
@@ -92,27 +144,37 @@ module Dependabot
|
|
92
144
|
sorted_versions.find { |v| version_compatible?(v.fetch(:version)) }
|
93
145
|
end
|
94
146
|
|
147
|
+
sig { params(version: T.nilable(T.any(Dependabot::Version, String))).returns(T::Boolean) }
|
95
148
|
def version_compatible?(version)
|
96
149
|
str_version_compatible?(version.to_s)
|
97
150
|
end
|
98
151
|
|
152
|
+
sig { params(version: String).returns(T::Boolean) }
|
99
153
|
def str_version_compatible?(version)
|
100
154
|
compatibility_checker.compatible?(version)
|
101
155
|
end
|
102
156
|
|
157
|
+
sig { returns(Dependabot::Nuget::CompatibilityChecker) }
|
103
158
|
def compatibility_checker
|
104
|
-
@compatibility_checker ||=
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
159
|
+
@compatibility_checker ||=
|
160
|
+
T.let(
|
161
|
+
CompatibilityChecker.new(
|
162
|
+
dependency_urls: dependency_urls,
|
163
|
+
dependency: dependency,
|
164
|
+
tfm_finder: TfmFinder.new(
|
165
|
+
dependency_files: dependency_files,
|
166
|
+
credentials: credentials,
|
167
|
+
repo_contents_path: repo_contents_path
|
168
|
+
)
|
169
|
+
),
|
170
|
+
T.nilable(Dependabot::Nuget::CompatibilityChecker)
|
111
171
|
)
|
112
|
-
)
|
113
172
|
end
|
114
173
|
|
115
|
-
sig
|
174
|
+
sig do
|
175
|
+
params(possible_versions: T::Array[T::Hash[Symbol, T.untyped]])
|
176
|
+
.returns(T::Array[T::Hash[Symbol, T.untyped]])
|
177
|
+
end
|
116
178
|
def filter_prereleases(possible_versions)
|
117
179
|
filtered = possible_versions.reject do |d|
|
118
180
|
version = d.fetch(:version)
|
@@ -124,7 +186,10 @@ module Dependabot
|
|
124
186
|
filtered
|
125
187
|
end
|
126
188
|
|
127
|
-
sig
|
189
|
+
sig do
|
190
|
+
params(possible_versions: T::Array[T::Hash[Symbol, T.untyped]])
|
191
|
+
.returns(T::Array[T::Hash[Symbol, T.untyped]])
|
192
|
+
end
|
128
193
|
def filter_ignored_versions(possible_versions)
|
129
194
|
filtered = possible_versions
|
130
195
|
|
@@ -147,6 +212,10 @@ module Dependabot
|
|
147
212
|
filtered
|
148
213
|
end
|
149
214
|
|
215
|
+
sig do
|
216
|
+
params(possible_versions: T::Array[T::Hash[Symbol, T.untyped]])
|
217
|
+
.returns(T::Array[T::Hash[Symbol, T.untyped]])
|
218
|
+
end
|
150
219
|
def filter_lower_versions(possible_versions)
|
151
220
|
return possible_versions unless dependency.numeric_version
|
152
221
|
|
@@ -155,12 +224,14 @@ module Dependabot
|
|
155
224
|
end
|
156
225
|
end
|
157
226
|
|
227
|
+
sig { params(string: String).returns(T::Array[String]) }
|
158
228
|
def parse_requirement_string(string)
|
159
229
|
return [string] if string.match?(NUGET_RANGE_REGEX)
|
160
230
|
|
161
231
|
string.split(",").map(&:strip)
|
162
232
|
end
|
163
233
|
|
234
|
+
sig { returns(T::Array[T::Hash[Symbol, T.any(Dependabot::Version, String, NilClass)]]) }
|
164
235
|
def available_v3_versions
|
165
236
|
v3_nuget_listings.flat_map do |listing|
|
166
237
|
listing
|
@@ -181,6 +252,7 @@ module Dependabot
|
|
181
252
|
end
|
182
253
|
end
|
183
254
|
|
255
|
+
sig { returns(T::Array[T::Hash[Symbol, T.any(Dependabot::Version, String, NilClass)]]) }
|
184
256
|
def available_v2_versions
|
185
257
|
v2_nuget_listings.flat_map do |listing|
|
186
258
|
body = listing.fetch("xml_body", [])
|
@@ -200,6 +272,10 @@ module Dependabot
|
|
200
272
|
end
|
201
273
|
end
|
202
274
|
|
275
|
+
sig do
|
276
|
+
params(entry: Nokogiri::XML::Element)
|
277
|
+
.returns(T::Hash[Symbol, T.any(Dependabot::Version, String, NilClass)])
|
278
|
+
end
|
203
279
|
def dependency_details_from_v2_entry(entry)
|
204
280
|
version = entry.at_xpath("./properties/Version").content.strip
|
205
281
|
source_urls = []
|
@@ -221,10 +297,11 @@ module Dependabot
|
|
221
297
|
end
|
222
298
|
|
223
299
|
# rubocop:disable Metrics/PerceivedComplexity
|
300
|
+
sig { params(version: Dependabot::Version).returns(T::Boolean) }
|
224
301
|
def related_to_current_pre?(version)
|
225
302
|
current_version = dependency.numeric_version
|
226
303
|
if current_version&.prerelease? &&
|
227
|
-
current_version
|
304
|
+
current_version.release == version.release
|
228
305
|
return true
|
229
306
|
end
|
230
307
|
|
@@ -242,36 +319,50 @@ module Dependabot
|
|
242
319
|
false
|
243
320
|
end
|
244
321
|
end
|
245
|
-
|
246
322
|
# rubocop:enable Metrics/PerceivedComplexity
|
247
323
|
|
324
|
+
sig { returns(T::Array[T::Hash[String, T.untyped]]) }
|
248
325
|
def v3_nuget_listings
|
249
326
|
@v3_nuget_listings ||=
|
250
|
-
|
251
|
-
|
252
|
-
|
253
|
-
|
254
|
-
|
255
|
-
|
256
|
-
|
257
|
-
|
327
|
+
T.let(
|
328
|
+
dependency_urls
|
329
|
+
.select { |details| details.fetch(:repository_type) == "v3" }
|
330
|
+
.filter_map do |url_details|
|
331
|
+
versions = NugetClient.get_package_versions(dependency.name, url_details)
|
332
|
+
next unless versions
|
333
|
+
|
334
|
+
{ "versions" => versions, "listing_details" => url_details }
|
335
|
+
end,
|
336
|
+
T.nilable(T::Array[T::Hash[String, T.untyped]])
|
337
|
+
)
|
258
338
|
end
|
259
339
|
|
340
|
+
sig { returns(T::Array[T::Hash[String, T.untyped]]) }
|
260
341
|
def v2_nuget_listings
|
261
342
|
@v2_nuget_listings ||=
|
262
|
-
|
263
|
-
|
264
|
-
|
265
|
-
|
266
|
-
|
267
|
-
|
268
|
-
|
269
|
-
|
270
|
-
|
271
|
-
|
272
|
-
|
343
|
+
T.let(
|
344
|
+
dependency_urls
|
345
|
+
.select { |details| details.fetch(:repository_type) == "v2" }
|
346
|
+
.flat_map { |url_details| fetch_paginated_v2_nuget_listings(url_details) }
|
347
|
+
.filter_map do |url_details, response|
|
348
|
+
next unless response.status == 200
|
349
|
+
|
350
|
+
{
|
351
|
+
"xml_body" => response.body,
|
352
|
+
"listing_details" => url_details
|
353
|
+
}
|
354
|
+
end,
|
355
|
+
T.nilable(T::Array[T::Hash[String, T.untyped]])
|
356
|
+
)
|
273
357
|
end
|
274
358
|
|
359
|
+
sig do
|
360
|
+
params(
|
361
|
+
url_details: T::Hash[Symbol, T.untyped],
|
362
|
+
results: T::Hash[T::Hash[Symbol, T.untyped], Excon::Response]
|
363
|
+
)
|
364
|
+
.returns(T::Array[T::Array[T.untyped]])
|
365
|
+
end
|
275
366
|
def fetch_paginated_v2_nuget_listings(url_details, results = {})
|
276
367
|
response = Dependabot::RegistryClient.get(
|
277
368
|
url: url_details[:versions_url],
|
@@ -295,6 +386,7 @@ module Dependabot
|
|
295
386
|
results.to_a
|
296
387
|
end
|
297
388
|
|
389
|
+
sig { params(xml_body: String).returns(T.nilable(String)) }
|
298
390
|
def fetch_v2_next_link_href(xml_body)
|
299
391
|
doc = Nokogiri::XML(xml_body)
|
300
392
|
doc.remove_namespaces!
|
@@ -307,32 +399,44 @@ module Dependabot
|
|
307
399
|
nil
|
308
400
|
end
|
309
401
|
|
402
|
+
sig { returns(T::Array[T::Hash[Symbol, T.untyped]]) }
|
310
403
|
def dependency_urls
|
311
404
|
@dependency_urls ||=
|
312
|
-
|
313
|
-
|
314
|
-
|
315
|
-
|
316
|
-
|
405
|
+
T.let(
|
406
|
+
RepositoryFinder.new(
|
407
|
+
dependency: dependency,
|
408
|
+
credentials: credentials,
|
409
|
+
config_files: nuget_configs
|
410
|
+
).dependency_urls,
|
411
|
+
T.nilable(T::Array[T::Hash[Symbol, T.untyped]])
|
412
|
+
)
|
317
413
|
end
|
318
414
|
|
415
|
+
sig { returns(T::Array[Dependabot::DependencyFile]) }
|
319
416
|
def nuget_configs
|
320
417
|
@nuget_configs ||=
|
321
|
-
|
418
|
+
T.let(
|
419
|
+
dependency_files.select { |f| f.name.match?(/nuget\.config$/i) },
|
420
|
+
T.nilable(T::Array[Dependabot::DependencyFile])
|
421
|
+
)
|
322
422
|
end
|
323
423
|
|
424
|
+
sig { returns(String) }
|
324
425
|
def sanitized_name
|
325
426
|
dependency.name.downcase
|
326
427
|
end
|
327
428
|
|
429
|
+
sig { returns(T.class_of(Gem::Version)) }
|
328
430
|
def version_class
|
329
431
|
dependency.version_class
|
330
432
|
end
|
331
433
|
|
434
|
+
sig { returns(T.class_of(Dependabot::Requirement)) }
|
332
435
|
def requirement_class
|
333
436
|
dependency.requirement_class
|
334
437
|
end
|
335
438
|
|
439
|
+
sig { returns(T::Hash[Symbol, Integer]) }
|
336
440
|
def excon_options
|
337
441
|
# For large JSON files we sometimes need a little longer than for
|
338
442
|
# other languages. For example, see:
|
@@ -345,6 +449,7 @@ module Dependabot
|
|
345
449
|
}
|
346
450
|
end
|
347
451
|
end
|
452
|
+
# rubocop:enable Metrics/ClassLength
|
348
453
|
end
|
349
454
|
end
|
350
455
|
end
|
@@ -1,47 +1,59 @@
|
|
1
|
-
# typed:
|
1
|
+
# typed: strict
|
2
2
|
# frozen_string_literal: true
|
3
3
|
|
4
4
|
require "dependabot/nuget/file_parser"
|
5
5
|
require "dependabot/update_checkers"
|
6
6
|
require "dependabot/update_checkers/base"
|
7
|
+
require "sorbet-runtime"
|
7
8
|
|
8
9
|
module Dependabot
|
9
10
|
module Nuget
|
10
11
|
class UpdateChecker < Dependabot::UpdateCheckers::Base
|
12
|
+
extend T::Sig
|
13
|
+
|
11
14
|
require_relative "update_checker/version_finder"
|
12
15
|
require_relative "update_checker/property_updater"
|
13
16
|
require_relative "update_checker/requirements_updater"
|
14
17
|
require_relative "update_checker/dependency_finder"
|
15
18
|
|
19
|
+
sig { override.returns(T.nilable(String)) }
|
16
20
|
def latest_version
|
17
21
|
# No need to find latest version for transitive dependencies unless they have a vulnerability.
|
18
22
|
return dependency.version if !dependency.top_level? && !vulnerable?
|
19
23
|
|
20
24
|
# if no update sources have the requisite package, then we can only assume that the current version is correct
|
21
|
-
@latest_version =
|
25
|
+
@latest_version = T.let(
|
26
|
+
latest_version_details&.fetch(:version)&.to_s || dependency.version,
|
27
|
+
T.nilable(String)
|
28
|
+
)
|
22
29
|
end
|
23
30
|
|
31
|
+
sig { override.returns(T.nilable(T.any(String, Gem::Version))) }
|
24
32
|
def latest_resolvable_version
|
25
33
|
# We always want a full unlock since any package update could update peer dependencies as well.
|
26
34
|
# To force a full unlock instead of an own unlock, we return nil.
|
27
35
|
nil
|
28
36
|
end
|
29
37
|
|
38
|
+
sig { override.returns(Dependabot::Nuget::Version) }
|
30
39
|
def lowest_security_fix_version
|
31
40
|
lowest_security_fix_version_details&.fetch(:version)
|
32
41
|
end
|
33
42
|
|
43
|
+
sig { override.returns(T.nilable(Dependabot::Version)) }
|
34
44
|
def lowest_resolvable_security_fix_version
|
35
45
|
return nil if version_comes_from_multi_dependency_property?
|
36
46
|
|
37
47
|
lowest_security_fix_version
|
38
48
|
end
|
39
49
|
|
50
|
+
sig { override.returns(NilClass) }
|
40
51
|
def latest_resolvable_version_with_no_unlock
|
41
52
|
# Irrelevant, since Nuget has a single dependency file
|
42
53
|
nil
|
43
54
|
end
|
44
55
|
|
56
|
+
sig { override.returns(T::Array[T::Hash[Symbol, T.untyped]]) }
|
45
57
|
def updated_requirements
|
46
58
|
RequirementsUpdater.new(
|
47
59
|
requirements: dependency.requirements,
|
@@ -50,6 +62,7 @@ module Dependabot
|
|
50
62
|
).updated_requirements
|
51
63
|
end
|
52
64
|
|
65
|
+
sig { returns(T::Boolean) }
|
53
66
|
def up_to_date?
|
54
67
|
# No need to update transitive dependencies unless they have a vulnerability.
|
55
68
|
return true if !dependency.top_level? && !vulnerable?
|
@@ -62,6 +75,7 @@ module Dependabot
|
|
62
75
|
super
|
63
76
|
end
|
64
77
|
|
78
|
+
sig { returns(T::Boolean) }
|
65
79
|
def requirements_unlocked_or_can_be?
|
66
80
|
# If any requirements have an uninterpolated property in them then
|
67
81
|
# that property couldn't be found, and the requirement therefore
|
@@ -73,6 +87,7 @@ module Dependabot
|
|
73
87
|
|
74
88
|
private
|
75
89
|
|
90
|
+
sig { returns(T.nilable(T::Hash[Symbol, T.untyped])) }
|
76
91
|
def preferred_resolvable_version_details
|
77
92
|
# If this dependency is vulnerable, prefer trying to update to the
|
78
93
|
# lowest_resolvable_security_fix_version. Otherwise update all the way
|
@@ -82,6 +97,7 @@ module Dependabot
|
|
82
97
|
latest_version_details
|
83
98
|
end
|
84
99
|
|
100
|
+
sig { override.returns(T::Boolean) }
|
85
101
|
def latest_version_resolvable_with_full_unlock?
|
86
102
|
# We always want a full unlock since any package update could update peer dependencies as well.
|
87
103
|
return true unless version_comes_from_multi_dependency_property?
|
@@ -89,6 +105,7 @@ module Dependabot
|
|
89
105
|
property_updater.update_possible?
|
90
106
|
end
|
91
107
|
|
108
|
+
sig { override.returns(T::Array[Dependabot::Dependency]) }
|
92
109
|
def updated_dependencies_after_full_unlock
|
93
110
|
return property_updater.updated_dependencies if version_comes_from_multi_dependency_property?
|
94
111
|
|
@@ -96,7 +113,7 @@ module Dependabot
|
|
96
113
|
|
97
114
|
updated_dependency = Dependency.new(
|
98
115
|
name: dependency.name,
|
99
|
-
version: latest_version
|
116
|
+
version: latest_version,
|
100
117
|
requirements: updated_requirements,
|
101
118
|
previous_version: dependency.version,
|
102
119
|
previous_requirements: dependency.requirements,
|
@@ -112,47 +129,66 @@ module Dependabot
|
|
112
129
|
updated_dependencies
|
113
130
|
end
|
114
131
|
|
132
|
+
sig { returns(T.nilable(T::Hash[Symbol, T.untyped])) }
|
115
133
|
def preferred_version_details
|
116
134
|
return lowest_security_fix_version_details if vulnerable?
|
117
135
|
|
118
136
|
latest_version_details
|
119
137
|
end
|
120
138
|
|
139
|
+
sig { returns(T.nilable(T::Hash[Symbol, T.untyped])) }
|
121
140
|
def latest_version_details
|
122
|
-
@latest_version_details ||=
|
141
|
+
@latest_version_details ||=
|
142
|
+
T.let(
|
143
|
+
version_finder.latest_version_details,
|
144
|
+
T.nilable(T::Hash[Symbol, T.untyped])
|
145
|
+
)
|
123
146
|
end
|
124
147
|
|
148
|
+
sig { returns(T.nilable(T::Hash[Symbol, T.untyped])) }
|
125
149
|
def lowest_security_fix_version_details
|
126
150
|
@lowest_security_fix_version_details ||=
|
127
|
-
|
151
|
+
T.let(
|
152
|
+
version_finder.lowest_security_fix_version_details,
|
153
|
+
T.nilable(T::Hash[Symbol, T.untyped])
|
154
|
+
)
|
128
155
|
end
|
129
156
|
|
157
|
+
sig { returns(Dependabot::Nuget::UpdateChecker::VersionFinder) }
|
130
158
|
def version_finder
|
131
159
|
@version_finder ||=
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
160
|
+
T.let(
|
161
|
+
VersionFinder.new(
|
162
|
+
dependency: dependency,
|
163
|
+
dependency_files: dependency_files,
|
164
|
+
credentials: credentials,
|
165
|
+
ignored_versions: ignored_versions,
|
166
|
+
raise_on_ignored: @raise_on_ignored,
|
167
|
+
security_advisories: security_advisories,
|
168
|
+
repo_contents_path: @repo_contents_path
|
169
|
+
),
|
170
|
+
T.nilable(Dependabot::Nuget::UpdateChecker::VersionFinder)
|
140
171
|
)
|
141
172
|
end
|
142
173
|
|
174
|
+
sig { returns(Dependabot::Nuget::UpdateChecker::PropertyUpdater) }
|
143
175
|
def property_updater
|
144
176
|
@property_updater ||=
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
177
|
+
T.let(
|
178
|
+
PropertyUpdater.new(
|
179
|
+
dependency: dependency,
|
180
|
+
dependency_files: dependency_files,
|
181
|
+
target_version_details: latest_version_details,
|
182
|
+
credentials: credentials,
|
183
|
+
ignored_versions: ignored_versions,
|
184
|
+
raise_on_ignored: @raise_on_ignored,
|
185
|
+
repo_contents_path: @repo_contents_path
|
186
|
+
),
|
187
|
+
T.nilable(Dependabot::Nuget::UpdateChecker::PropertyUpdater)
|
153
188
|
)
|
154
189
|
end
|
155
190
|
|
191
|
+
sig { returns(T::Boolean) }
|
156
192
|
def version_comes_from_multi_dependency_property?
|
157
193
|
declarations_using_a_property.any? do |requirement|
|
158
194
|
property_name = requirement.fetch(:metadata).fetch(:property_name)
|
@@ -167,20 +203,28 @@ module Dependabot
|
|
167
203
|
end
|
168
204
|
end
|
169
205
|
|
206
|
+
sig { returns(T::Array[T::Hash[Symbol, T.untyped]]) }
|
170
207
|
def declarations_using_a_property
|
171
208
|
@declarations_using_a_property ||=
|
172
|
-
|
173
|
-
|
209
|
+
T.let(
|
210
|
+
dependency.requirements
|
211
|
+
.select { |req| req.dig(:metadata, :property_name) },
|
212
|
+
T.nilable(T::Array[T::Hash[Symbol, T.untyped]])
|
213
|
+
)
|
174
214
|
end
|
175
215
|
|
216
|
+
sig { returns(T::Array[Dependabot::Dependency]) }
|
176
217
|
def all_property_based_dependencies
|
177
218
|
@all_property_based_dependencies ||=
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
219
|
+
T.let(
|
220
|
+
Nuget::FileParser.new(
|
221
|
+
dependency_files: dependency_files,
|
222
|
+
source: nil
|
223
|
+
).parse.select do |dep|
|
224
|
+
dep.requirements.any? { |req| req.dig(:metadata, :property_name) }
|
225
|
+
end,
|
226
|
+
T.nilable(T::Array[Dependabot::Dependency])
|
227
|
+
)
|
184
228
|
end
|
185
229
|
end
|
186
230
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: dependabot-nuget
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.248.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Dependabot
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2024-03-
|
11
|
+
date: 2024-03-21 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: dependabot-common
|
@@ -16,14 +16,14 @@ dependencies:
|
|
16
16
|
requirements:
|
17
17
|
- - '='
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version: 0.
|
19
|
+
version: 0.248.0
|
20
20
|
type: :runtime
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
24
|
- - '='
|
25
25
|
- !ruby/object:Gem::Version
|
26
|
-
version: 0.
|
26
|
+
version: 0.248.0
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: rubyzip
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
@@ -385,7 +385,7 @@ licenses:
|
|
385
385
|
- Nonstandard
|
386
386
|
metadata:
|
387
387
|
bug_tracker_uri: https://github.com/dependabot/dependabot-core/issues
|
388
|
-
changelog_uri: https://github.com/dependabot/dependabot-core/releases/tag/v0.
|
388
|
+
changelog_uri: https://github.com/dependabot/dependabot-core/releases/tag/v0.248.0
|
389
389
|
post_install_message:
|
390
390
|
rdoc_options: []
|
391
391
|
require_paths:
|