dependabot-composer 0.311.0 → 0.312.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 1b7f9286dece3b3c0c35b5be85a580078a6467edb4dd43b9817601f541b5c2cf
4
- data.tar.gz: 4d31a01b968c789451178cee2855a6e507fad696663bac7e01cc89103b6a5c0c
3
+ metadata.gz: 8c49eb03ec5cdf799b6e907a757ba5e332dfcea06312b82cb21d38e94da364f6
4
+ data.tar.gz: c49110cee8257749ed2d7f03c2f868d088d4219e9cd42cd39835aa8c80b3c48a
5
5
  SHA512:
6
- metadata.gz: fb35c79db05afba4a18eceb83722484488031b68503975dd13df219b3eaba3d98d931bb0850dd74f2c5a3023689441e436083f01e81a188bd1db897840496a86
7
- data.tar.gz: d963a5ccdc05bc63e3ee72b6d59bd8e9e8eedd3ac71d3a7da457d803ccd9ff618cf2d68c5da1e6e6707606cbbc1d094664dbc2d386fe3ca22ace4116eaa3a5cd
6
+ metadata.gz: d792223dd012bd103ed61ddb50f4dcdd5d0ba86657939c8cdb70f52655e74e9b59535e983a8929bb533fe1ce9bffd00977fa66deb2ecc467fadb472d23cb5d53
7
+ data.tar.gz: 8618aa8c287c4eee25fedf9a551d5c682fc92464e0e5d3fd7a0018ed5752fdcbe96fe9512032fe86aa32c268c1abbe60dcaceaba2e6ccdc707b228d0e9c26e7f
@@ -174,7 +174,7 @@ module Dependabot
174
174
 
175
175
  sig { params(dependency_url: String).returns(String) }
176
176
  def self.clean_dependency_url(dependency_url)
177
- return dependency_url unless URI::DEFAULT_PARSER.regexp[:ABS_URI].match?(dependency_url)
177
+ return dependency_url unless URI::RFC2396_PARSER.regexp[:ABS_URI].match?(dependency_url)
178
178
 
179
179
  url = URI.parse(dependency_url)
180
180
  url.user = nil
@@ -1,8 +1,9 @@
1
- # typed: true
1
+ # typed: strict
2
2
  # frozen_string_literal: true
3
3
 
4
4
  require "excon"
5
5
  require "json"
6
+ require "sorbet-runtime"
6
7
 
7
8
  require "dependabot/composer/update_checker"
8
9
  require "dependabot/update_checkers/version_filters"
@@ -13,9 +14,20 @@ module Dependabot
13
14
  module Composer
14
15
  class UpdateChecker
15
16
  class LatestVersionFinder
16
- def initialize(dependency:, dependency_files:, credentials:,
17
- ignored_versions:, raise_on_ignored: false,
18
- security_advisories:)
17
+ extend T::Sig
18
+
19
+ sig do
20
+ params(
21
+ dependency: Dependabot::Dependency,
22
+ dependency_files: T::Array[Dependabot::DependencyFile],
23
+ credentials: T::Array[Dependabot::Credential],
24
+ ignored_versions: T::Array[String],
25
+ security_advisories: T::Array[Dependabot::SecurityAdvisory],
26
+ raise_on_ignored: T::Boolean
27
+ ).void
28
+ end
29
+ def initialize(dependency:, dependency_files:, credentials:, ignored_versions:, security_advisories:,
30
+ raise_on_ignored: false)
19
31
  @dependency = dependency
20
32
  @dependency_files = dependency_files
21
33
  @credentials = credentials
@@ -24,22 +36,40 @@ module Dependabot
24
36
  @security_advisories = security_advisories
25
37
  end
26
38
 
39
+ sig { returns(T.nilable(Dependabot::Version)) }
27
40
  def latest_version
28
- @latest_version ||= fetch_latest_version
41
+ @latest_version ||= T.let(
42
+ fetch_latest_version,
43
+ T.nilable(Dependabot::Version)
44
+ )
29
45
  end
30
46
 
47
+ sig { returns(T.nilable(Dependabot::Version)) }
31
48
  def lowest_security_fix_version
32
- @lowest_security_fix_version ||= fetch_lowest_security_fix_version
49
+ @lowest_security_fix_version ||= T.let(
50
+ fetch_lowest_security_fix_version,
51
+ T.nilable(Dependabot::Version)
52
+ )
33
53
  end
34
54
 
35
55
  private
36
56
 
57
+ sig { returns(Dependabot::Dependency) }
37
58
  attr_reader :dependency
59
+
60
+ sig { returns(T::Array[Dependabot::DependencyFile]) }
38
61
  attr_reader :dependency_files
62
+
63
+ sig { returns(T::Array[Dependabot::Credential]) }
39
64
  attr_reader :credentials
65
+
66
+ sig { returns(T::Array[String]) }
40
67
  attr_reader :ignored_versions
68
+
69
+ sig { returns(T::Array[Dependabot::SecurityAdvisory]) }
41
70
  attr_reader :security_advisories
42
71
 
72
+ sig { returns(T.nilable(Dependabot::Version)) }
43
73
  def fetch_latest_version
44
74
  versions = available_versions
45
75
  versions = filter_prerelease_versions(versions)
@@ -47,6 +77,7 @@ module Dependabot
47
77
  versions.max
48
78
  end
49
79
 
80
+ sig { returns(T.nilable(Dependabot::Version)) }
50
81
  def fetch_lowest_security_fix_version
51
82
  versions = available_versions
52
83
  versions = filter_prerelease_versions(versions)
@@ -58,12 +89,14 @@ module Dependabot
58
89
  versions.min
59
90
  end
60
91
 
92
+ sig { params(versions_array: T::Array[Dependabot::Version]).returns(T::Array[Dependabot::Version]) }
61
93
  def filter_prerelease_versions(versions_array)
62
94
  return versions_array if wants_prerelease?
63
95
 
64
96
  versions_array.reject(&:prerelease?)
65
97
  end
66
98
 
99
+ sig { params(versions_array: T::Array[Dependabot::Version]).returns(T::Array[Dependabot::Version]) }
67
100
  def filter_ignored_versions(versions_array)
68
101
  filtered =
69
102
  versions_array
@@ -76,6 +109,7 @@ module Dependabot
76
109
  filtered
77
110
  end
78
111
 
112
+ sig { params(versions_array: T::Array[Dependabot::Version]).returns(T::Array[Dependabot::Version]) }
79
113
  def filter_lower_versions(versions_array)
80
114
  return versions_array unless dependency.numeric_version
81
115
 
@@ -83,6 +117,7 @@ module Dependabot
83
117
  .select { |version| version > dependency.numeric_version }
84
118
  end
85
119
 
120
+ sig { returns(T::Boolean) }
86
121
  def wants_prerelease?
87
122
  current_version = dependency.numeric_version
88
123
  return true if current_version&.prerelease?
@@ -92,17 +127,19 @@ module Dependabot
92
127
  end
93
128
  end
94
129
 
130
+ sig { returns(T::Array[Dependabot::Version]) }
95
131
  def available_versions
96
132
  registry_version_details
97
133
  .select { |version| version_class.correct?(version.gsub(/^v/, "")) }
98
134
  .map { |version| version_class.new(version.gsub(/^v/, "")) }
99
135
  end
100
136
 
137
+ sig { returns(T::Array[String]) }
101
138
  def registry_version_details
102
139
  return @registry_version_details unless @registry_version_details.nil?
103
140
 
104
141
  repositories =
105
- JSON.parse(composer_file.content)
142
+ JSON.parse(T.must(composer_file.content))
106
143
  .fetch("repositories", [])
107
144
  .select { |r| r.is_a?(Hash) }
108
145
 
@@ -115,16 +152,19 @@ module Dependabot
115
152
  urls << "https://repo.packagist.org/p2/#{dependency.name.downcase}.json"
116
153
  end
117
154
 
118
- @registry_version_details = []
155
+ @registry_version_details ||= T.let([], T.nilable(T::Array[String]))
119
156
  urls.each do |url|
120
157
  @registry_version_details += fetch_registry_versions_from_url(url)
121
158
  end
122
159
  @registry_version_details.uniq
123
160
  end
124
161
 
162
+ sig { params(url: String).returns(T::Array[String]) }
125
163
  def fetch_registry_versions_from_url(url)
126
164
  url_host = URI(url).host
127
- cred = registry_credentials.find { |c| url_host == c["registry"] || url_host == URI(c["registry"]).host }
165
+ cred = registry_credentials.find do |c|
166
+ url_host == c["registry"] || url_host == URI(T.must(c["registry"])).host
167
+ end
128
168
 
129
169
  response = Dependabot::RegistryClient.get(
130
170
  url: url,
@@ -139,6 +179,7 @@ module Dependabot
139
179
  []
140
180
  end
141
181
 
182
+ sig { params(response: T.untyped, url: String).returns(T::Array[String]) }
142
183
  def parse_registry_response(response, url)
143
184
  return [] unless response.status == 200
144
185
 
@@ -154,6 +195,7 @@ module Dependabot
154
195
  raise DependencyFileNotResolvable, msg
155
196
  end
156
197
 
198
+ sig { params(listing: T::Hash[String, T.untyped]).returns(T::Array[String]) }
157
199
  def extract_versions(listing)
158
200
  # Packagist's Metadata API format:
159
201
  # v1: "packages": {<package name>: {<version_number>: {hash of metadata for a particular release version}}}
@@ -174,26 +216,32 @@ module Dependabot
174
216
  end
175
217
  end
176
218
 
219
+ sig { returns(T::Array[Dependabot::Credential]) }
177
220
  def registry_credentials
178
221
  credentials.select { |cred| cred["type"] == PackageManager::REPOSITORY_KEY } +
179
222
  auth_json_credentials
180
223
  end
181
224
 
225
+ sig { returns(T::Array[Dependabot::Credential]) }
182
226
  def auth_json_credentials
183
- return [] unless auth_json
227
+ json = auth_json
228
+ return [] unless json
184
229
 
185
- parsed_auth_json = JSON.parse(auth_json.content)
230
+ parsed_auth_json = JSON.parse(T.must(json.content))
186
231
  parsed_auth_json.fetch("http-basic", {}).map do |reg, details|
187
- {
232
+ Dependabot::Credential.new({
188
233
  "registry" => reg,
189
234
  "username" => details["username"],
190
235
  "password" => details["password"]
191
- }
236
+ })
192
237
  end
193
238
  rescue JSON::ParserError
194
- raise Dependabot::DependencyFileNotParseable, auth_json.path
239
+ raise Dependabot::DependencyFileNotParseable, json.path if json
240
+
241
+ raise Dependabot::DependencyFileNotParseable, "Unknown path"
195
242
  end
196
243
 
244
+ sig { returns(Dependabot::DependencyFile) }
197
245
  def composer_file
198
246
  composer_file =
199
247
  dependency_files.find do |f|
@@ -204,18 +252,22 @@ module Dependabot
204
252
  composer_file
205
253
  end
206
254
 
255
+ sig { returns(T.nilable(Dependabot::DependencyFile)) }
207
256
  def auth_json
208
257
  dependency_files.find { |f| f.name == PackageManager::AUTH_FILENAME }
209
258
  end
210
259
 
260
+ sig { returns(T::Array[Dependabot::Requirement]) }
211
261
  def ignore_requirements
212
262
  ignored_versions.map { |req| requirement_class.new(req.split(",")) }
213
263
  end
214
264
 
265
+ sig { returns(T.class_of(Dependabot::Version)) }
215
266
  def version_class
216
267
  dependency.version_class
217
268
  end
218
269
 
270
+ sig { returns(T.class_of(Dependabot::Requirement)) }
219
271
  def requirement_class
220
272
  dependency.requirement_class
221
273
  end
@@ -1,4 +1,4 @@
1
- # typed: true
1
+ # typed: strict
2
2
  # frozen_string_literal: true
3
3
 
4
4
  ################################################################################
@@ -34,6 +34,13 @@ module Dependabot
34
34
  T::Array[Dependabot::RequirementsUpdateStrategy]
35
35
  )
36
36
 
37
+ sig do
38
+ params(
39
+ requirements: T::Array[T::Hash[Symbol, String]],
40
+ update_strategy: Dependabot::RequirementsUpdateStrategy,
41
+ latest_resolvable_version: T.nilable(T.any(String, Composer::Version))
42
+ ).void
43
+ end
37
44
  def initialize(requirements:, update_strategy:,
38
45
  latest_resolvable_version:)
39
46
  @requirements = requirements
@@ -43,10 +50,13 @@ module Dependabot
43
50
 
44
51
  return unless latest_resolvable_version
45
52
 
46
- @latest_resolvable_version =
47
- version_class.new(latest_resolvable_version)
53
+ @latest_resolvable_version = T.let(
54
+ version_class.new(latest_resolvable_version),
55
+ Dependabot::Version
56
+ )
48
57
  end
49
58
 
59
+ sig { returns(T::Array[T::Hash[Symbol, String]]) }
50
60
  def updated_requirements
51
61
  return requirements if update_strategy.lockfile_only?
52
62
  return requirements unless latest_resolvable_version
@@ -56,10 +66,16 @@ module Dependabot
56
66
 
57
67
  private
58
68
 
69
+ sig { returns(T::Array[T::Hash[Symbol, String]]) }
59
70
  attr_reader :requirements
71
+
72
+ sig { returns(Dependabot::RequirementsUpdateStrategy) }
60
73
  attr_reader :update_strategy
74
+
75
+ sig { returns(T.nilable(Dependabot::Version)) }
61
76
  attr_reader :latest_resolvable_version
62
77
 
78
+ sig { void }
63
79
  def check_update_strategy
64
80
  return if ALLOWED_UPDATE_STRATEGIES.include?(update_strategy)
65
81
 
@@ -67,8 +83,9 @@ module Dependabot
67
83
  end
68
84
 
69
85
  # rubocop:disable Metrics/PerceivedComplexity
86
+ sig { params(req: T::Hash[Symbol, String]).returns(T::Hash[Symbol, String]) }
70
87
  def updated_requirement(req)
71
- req_string = req[:requirement].strip
88
+ req_string = T.must(req[:requirement]).strip
72
89
  or_string_reqs = req_string.split(OR_SEPARATOR)
73
90
  or_separator = req_string.match(OR_SEPARATOR)&.to_s || " || "
74
91
  numeric_or_string_reqs = or_string_reqs
@@ -90,28 +107,33 @@ module Dependabot
90
107
  update_requirement_version(req, or_separator)
91
108
  end
92
109
 
110
+ # Add a T.must for new_req as it's defined in the case statement with multiple options
111
+ new_req = T.must(new_req)
93
112
  new_req_string =
94
113
  [new_req[:requirement], *branch_or_string_reqs].join(or_separator)
95
114
  new_req.merge(requirement: new_req_string)
96
115
  end
97
116
  # rubocop:enable Metrics/PerceivedComplexity
98
117
 
118
+ sig { params(req: T::Hash[Symbol, String]).returns(T::Hash[Symbol, String]) }
99
119
  def updated_alias(req)
100
- req_string = req[:requirement]
101
- real_version = req_string.split(/\sas\s/).first.strip
120
+ req_string = T.must(req[:requirement])
121
+ parts = req_string.split(/\sas\s/)
122
+ real_version = T.must(parts.first).strip
102
123
 
103
124
  # If the version we're aliasing isn't a version then we don't know
104
125
  # how to update it, so we just return the existing requirement.
105
126
  return req unless version_class.correct?(real_version)
106
127
 
107
- new_version_string = latest_resolvable_version.to_s
128
+ new_version_string = T.must(latest_resolvable_version).to_s
108
129
  new_req = req_string.sub(real_version, new_version_string)
109
130
  req.merge(requirement: new_req)
110
131
  end
111
132
 
112
133
  # rubocop:disable Metrics/PerceivedComplexity
134
+ sig { params(req: T::Hash[Symbol, String], or_separator: String).returns(T::Hash[Symbol, String]) }
113
135
  def widen_requirement(req, or_separator)
114
- current_requirement = req[:requirement]
136
+ current_requirement = T.must(req[:requirement])
115
137
  reqs = current_requirement.strip.split(SEPARATOR).map(&:strip)
116
138
 
117
139
  updated_requirement =
@@ -131,13 +153,14 @@ module Dependabot
131
153
  end
132
154
  # rubocop:enable Metrics/PerceivedComplexity
133
155
 
156
+ sig { params(req: T::Hash[Symbol, String], or_separator: String).returns(T::Hash[Symbol, String]) }
134
157
  def update_requirement_version(req, or_separator)
135
- current_requirement = req[:requirement]
158
+ current_requirement = T.must(req[:requirement])
136
159
  reqs = current_requirement.strip.split(SEPARATOR).map(&:strip)
137
160
 
138
161
  updated_requirement =
139
162
  if reqs.count > 1
140
- "^#{latest_resolvable_version}"
163
+ "^#{T.must(latest_resolvable_version)}"
141
164
  elsif reqs.any? { |r| r.match?(/<|(\s+-\s+)/) }
142
165
  update_range_requirement(current_requirement, or_separator)
143
166
  elsif reqs.any? { |r| r.match?(/>[^=]/) }
@@ -149,38 +172,42 @@ module Dependabot
149
172
  req.merge(requirement: updated_requirement)
150
173
  end
151
174
 
175
+ sig { params(requirement_string: String).returns(T::Boolean) }
152
176
  def req_satisfied_by_latest_resolvable?(requirement_string)
153
177
  ruby_requirements(requirement_string)
154
- .any? { |r| r.satisfied_by?(latest_resolvable_version) }
178
+ .any? { |r| r.satisfied_by?(T.must(latest_resolvable_version)) }
155
179
  end
156
180
 
181
+ sig { params(req_string: String).returns(String) }
157
182
  def update_version_string(req_string)
158
183
  req_string
159
184
  .sub(VERSION_REGEX) do |old_version|
160
- next latest_resolvable_version.to_s unless req_string.match?(/[~*\^]/)
185
+ next T.must(latest_resolvable_version).to_s unless req_string.match?(/[~*\^]/)
161
186
 
162
187
  old_parts = old_version.split(".")
163
- new_parts = latest_resolvable_version.to_s.split(".")
164
- .first(old_parts.count)
188
+ new_parts = T.must(latest_resolvable_version).to_s.split(".")
189
+ .first(old_parts.count)
165
190
  new_parts.map.with_index do |part, i|
166
191
  old_parts[i] == "*" ? "*" : part
167
192
  end.join(".")
168
193
  end
169
194
  end
170
195
 
196
+ sig { params(requirement_string: String).returns(T::Array[Composer::Requirement]) }
171
197
  def ruby_requirements(requirement_string)
172
198
  Composer::Requirement.requirements_array(requirement_string)
173
199
  end
174
200
 
201
+ sig { params(req_string: String, or_separator: String).returns(String) }
175
202
  def update_caret_requirement(req_string, or_separator)
176
203
  caret_requirements =
177
204
  req_string.split(SEPARATOR).select { |r| r.strip.start_with?("^") }
178
- version_parts = latest_resolvable_version.segments
205
+ version_parts = T.must(latest_resolvable_version).segments
179
206
 
180
207
  min_existing_precision =
181
- caret_requirements.map { |r| r.split(".").count }.min
208
+ caret_requirements.map { |r| r.split(".").count }.min || 0
182
209
  first_non_zero_index =
183
- version_parts.count.times.find { |i| version_parts[i] != 0 }
210
+ version_parts.count.times.find { |i| version_parts[i] != 0 } || 0
184
211
 
185
212
  precision = [min_existing_precision, first_non_zero_index + 1].max
186
213
  version = version_parts.first(precision).map.with_index do |part, i|
@@ -190,71 +217,78 @@ module Dependabot
190
217
  req_string + "#{or_separator}^#{version}"
191
218
  end
192
219
 
220
+ sig { params(req_string: String, or_separator: String).returns(String) }
193
221
  def update_tilda_requirement(req_string, or_separator)
194
222
  tilda_requirements =
195
223
  req_string.split(SEPARATOR).select { |r| r.strip.start_with?("~") }
196
- precision = tilda_requirements.map { |r| r.split(".").count }.min
224
+ precision = tilda_requirements.map { |r| r.split(".").count }.min || 0
197
225
 
198
- version_parts = latest_resolvable_version.segments.first(precision)
199
- version_parts[-1] = 0
226
+ version_parts = T.must(latest_resolvable_version).segments.first(precision)
227
+ version_parts[-1] = 0 if version_parts.any?
200
228
  version = version_parts.join(".")
201
229
 
202
230
  req_string + "#{or_separator}~#{version}"
203
231
  end
204
232
 
233
+ sig { params(req_string: String, or_separator: String).returns(String) }
205
234
  def update_wildcard_requirement(req_string, or_separator)
206
235
  wildcard_requirements =
207
236
  req_string.split(SEPARATOR).select { |r| r.include?("*") }
208
237
  precision = wildcard_requirements.map do |r|
209
238
  r.split(".").reject { |s| s == "*" }.count
210
- end.min
239
+ end.min || 0
211
240
  wildcard_count = wildcard_requirements.map do |r|
212
241
  r.split(".").select { |s| s == "*" }.count
213
- end.min
242
+ end.min || 0
214
243
 
215
- version_parts = latest_resolvable_version.segments.first(precision)
244
+ version_parts = T.must(latest_resolvable_version).segments.first(precision)
216
245
  version = version_parts.join(".")
217
246
 
218
247
  req_string + "#{or_separator}#{version}#{'.*' * wildcard_count}"
219
248
  end
220
249
 
250
+ sig { params(req_string: String, or_separator: String).returns(String) }
221
251
  def update_range_requirement(req_string, or_separator)
222
252
  range_requirements =
223
253
  req_string.split(SEPARATOR).select { |r| r.match?(/<|(\s+-\s+)/) }
224
254
 
225
255
  if range_requirements.count == 1
226
- range_requirement = range_requirements.first
256
+ range_requirement = T.must(range_requirements.first)
227
257
  versions = range_requirement.scan(VERSION_REGEX)
228
- upper_bound = versions.map { |v| version_class.new(v) }.max
258
+ # Convert version strings to Version objects and find the maximum
259
+ upper_bounds = versions.map { |v| version_class.new(T.cast(v, String)) }
260
+ upper_bound = T.cast(upper_bounds.max, Dependabot::Version)
229
261
  new_upper_bound = update_greatest_version(
230
262
  upper_bound,
231
- latest_resolvable_version
263
+ T.must(latest_resolvable_version)
232
264
  )
233
265
 
234
- req_string.sub(upper_bound.to_s, new_upper_bound.to_s)
266
+ req_string.sub(upper_bound.to_s, new_upper_bound)
235
267
  else
236
- req_string + "#{or_separator}^#{latest_resolvable_version}"
268
+ req_string + "#{or_separator}^#{T.must(latest_resolvable_version)}"
237
269
  end
238
270
  end
239
271
 
272
+ sig { params(old_version: Dependabot::Version, version_to_be_permitted: Dependabot::Version).returns(String) }
240
273
  def update_greatest_version(old_version, version_to_be_permitted)
241
274
  version = version_class.new(old_version)
242
275
  version = version.release if version.prerelease?
243
276
 
244
277
  index_to_update =
245
- version.segments.map.with_index { |seg, i| seg.zero? ? 0 : i }.max
278
+ version.segments.map.with_index { |seg, i| seg.to_i.zero? ? 0 : i }.max || 0
246
279
 
247
280
  version.segments.map.with_index do |_, index|
248
281
  if index < index_to_update
249
282
  version_to_be_permitted.segments[index]
250
283
  elsif index == index_to_update
251
- version_to_be_permitted.segments[index] + 1
284
+ version_to_be_permitted.segments[index].to_i + 1
252
285
  else
253
286
  0
254
287
  end
255
288
  end.join(".")
256
289
  end
257
290
 
291
+ sig { returns(T.class_of(Dependabot::Composer::Version)) }
258
292
  def version_class
259
293
  Composer::Version
260
294
  end
@@ -1,8 +1,9 @@
1
- # typed: true
1
+ # typed: strict
2
2
  # frozen_string_literal: true
3
3
 
4
4
  require "json"
5
5
  require "uri"
6
+ require "sorbet-runtime"
6
7
 
7
8
  require "dependabot/errors"
8
9
  require "dependabot/shared_helpers"
@@ -17,30 +18,49 @@ module Dependabot
17
18
  module Composer
18
19
  class UpdateChecker
19
20
  class VersionResolver # rubocop:disable Metrics/ClassLength
21
+ extend T::Sig
22
+
20
23
  class MissingExtensions < StandardError
24
+ extend T::Sig
25
+
26
+ sig { returns(T::Array[T::Hash[Symbol, T.untyped]]) }
21
27
  attr_reader :extensions
22
28
 
29
+ sig { params(extensions: T::Array[T::Hash[Symbol, T.untyped]]).void }
23
30
  def initialize(extensions)
24
- @extensions = extensions
31
+ @extensions = T.let(extensions, T::Array[T::Hash[Symbol, T.untyped]])
25
32
  super
26
33
  end
27
34
  end
28
35
 
29
- MISSING_EXPLICIT_PLATFORM_REQ_REGEX =
36
+ MISSING_EXPLICIT_PLATFORM_REQ_REGEX = T.let(
30
37
  %r{
31
38
  (?<=PHP\sextension\s)ext\-[^\s\/]+\s.*?\s(?=is|but)|
32
39
  (?<=requires\s)php(?:\-[^\s\/]+)?\s.*?\s(?=but)
33
- }x
34
- MISSING_IMPLICIT_PLATFORM_REQ_REGEX =
40
+ }x,
41
+ Regexp
42
+ )
43
+ MISSING_IMPLICIT_PLATFORM_REQ_REGEX = T.let(
35
44
  %r{
36
45
  (?<!with|for|by)\sext\-[^\s\/]+\s.*?\s(?=->)|
37
46
  (?<=require\s)php(?:\-[^\s\/]+)?\s.*?\s(?=->) # composer v2
38
- }x
39
- VERSION_REGEX = /[0-9]+(?:\.[A-Za-z0-9\-_]+)*/
47
+ }x,
48
+ Regexp
49
+ )
50
+ VERSION_REGEX = T.let(/[0-9]+(?:\.[A-Za-z0-9\-_]+)*/, Regexp)
40
51
 
41
52
  # Example Timeout error from Composer 2.7.7: "curl error 28 while downloading https://example.com:81/packages.json: Failed to connect to example.com port 81 after 9853 ms: Connection timed out" # rubocop:disable Layout/LineLength
42
- SOURCE_TIMED_OUT_REGEX = %r{curl error 28 while downloading (?<url>https?://.+/packages\.json): }
53
+ SOURCE_TIMED_OUT_REGEX = T.let(%r{curl error 28 while downloading (?<url>https?://.+/packages\.json): }, Regexp)
43
54
 
55
+ sig do
56
+ params(
57
+ credentials: T::Array[Dependabot::Credential],
58
+ dependency: Dependabot::Dependency,
59
+ dependency_files: T::Array[Dependabot::DependencyFile],
60
+ requirements_to_unlock: Symbol,
61
+ latest_allowable_version: T.nilable(Gem::Version)
62
+ ).void
63
+ end
44
64
  def initialize(credentials:, dependency:, dependency_files:,
45
65
  requirements_to_unlock:, latest_allowable_version:)
46
66
  @credentials = credentials
@@ -48,24 +68,43 @@ module Dependabot
48
68
  @dependency_files = dependency_files
49
69
  @requirements_to_unlock = requirements_to_unlock
50
70
  @latest_allowable_version = latest_allowable_version
51
- @composer_platform_extensions = initial_platform
52
- @error_handler = ComposerErrorHandler.new
71
+ @composer_platform_extensions = T.let(initial_platform, T::Hash[String, T::Array[String]])
72
+ @error_handler = T.let(ComposerErrorHandler.new, ComposerErrorHandler)
53
73
  end
54
74
 
75
+ sig { returns(T.nilable(Dependabot::Version)) }
55
76
  def latest_resolvable_version
56
- @latest_resolvable_version ||= fetch_latest_resolvable_version
77
+ @latest_resolvable_version ||= T.let(
78
+ fetch_latest_resolvable_version,
79
+ T.nilable(Dependabot::Version)
80
+ )
57
81
  end
58
82
 
59
83
  private
60
84
 
85
+ # Initialize instance variables with T.let for strict typing
86
+ sig { returns(T::Array[Dependabot::Credential]) }
61
87
  attr_reader :credentials
88
+
89
+ sig { returns(Dependabot::Dependency) }
62
90
  attr_reader :dependency
91
+
92
+ sig { returns(T::Array[Dependabot::DependencyFile]) }
63
93
  attr_reader :dependency_files
94
+
95
+ sig { returns(Symbol) }
64
96
  attr_reader :requirements_to_unlock
97
+
98
+ sig { returns(T.nilable(Gem::Version)) }
65
99
  attr_reader :latest_allowable_version
100
+
101
+ sig { returns(T::Hash[String, T::Array[String]]) }
66
102
  attr_reader :composer_platform_extensions
103
+
104
+ sig { returns(ComposerErrorHandler) }
67
105
  attr_reader :error_handler
68
106
 
107
+ sig { returns(T.nilable(Dependabot::Version)) }
69
108
  def fetch_latest_resolvable_version
70
109
  version = fetch_latest_resolvable_version_string
71
110
  return if version.nil?
@@ -80,8 +119,9 @@ module Dependabot
80
119
  retry
81
120
  end
82
121
 
122
+ sig { returns(T.nilable(String)) }
83
123
  def fetch_latest_resolvable_version_string
84
- base_directory = dependency_files.first.directory
124
+ base_directory = T.must(dependency_files.first).directory
85
125
  SharedHelpers.in_a_temporary_directory(base_directory) do
86
126
  write_temporary_dependency_files
87
127
  run_update_checker
@@ -93,6 +133,7 @@ module Dependabot
93
133
  handle_composer_errors(e)
94
134
  end
95
135
 
136
+ sig { params(unlock_requirement: T::Boolean).void }
96
137
  def write_temporary_dependency_files(unlock_requirement: true)
97
138
  write_dependency_file(unlock_requirement: unlock_requirement)
98
139
  write_path_dependency_files
@@ -101,6 +142,7 @@ module Dependabot
101
142
  write_auth_file
102
143
  end
103
144
 
145
+ sig { void }
104
146
  def write_zipped_path_dependency_files
105
147
  zipped_path_dependency_files.each do |file|
106
148
  FileUtils.mkdir_p(Pathname.new(file.name).dirname)
@@ -108,6 +150,7 @@ module Dependabot
108
150
  end
109
151
  end
110
152
 
153
+ sig { params(unlock_requirement: T::Boolean).void }
111
154
  def write_dependency_file(unlock_requirement:)
112
155
  File.write(
113
156
  PackageManager::MANIFEST_FILENAME,
@@ -117,6 +160,7 @@ module Dependabot
117
160
  )
118
161
  end
119
162
 
163
+ sig { void }
120
164
  def write_path_dependency_files
121
165
  path_dependency_files.each do |file|
122
166
  FileUtils.mkdir_p(Pathname.new(file.name).dirname)
@@ -124,14 +168,17 @@ module Dependabot
124
168
  end
125
169
  end
126
170
 
171
+ sig { void }
127
172
  def write_lockfile
128
- File.write(PackageManager::LOCKFILE_FILENAME, lockfile.content) if lockfile
173
+ File.write(PackageManager::LOCKFILE_FILENAME, T.must(lockfile).content) if lockfile
129
174
  end
130
175
 
176
+ sig { void }
131
177
  def write_auth_file
132
- File.write(PackageManager::AUTH_FILENAME, auth_json.content) if auth_json
178
+ File.write(PackageManager::AUTH_FILENAME, T.must(auth_json).content) if auth_json
133
179
  end
134
180
 
181
+ sig { params(error: SharedHelpers::HelperSubprocessFailed).returns(T::Boolean) }
135
182
  def transitory_failure?(error)
136
183
  return true if error.message.include?("404 Not Found")
137
184
  return true if error.message.include?("timed out")
@@ -140,6 +187,7 @@ module Dependabot
140
187
  error.message.include?("Content-Length mismatch")
141
188
  end
142
189
 
190
+ sig { returns(String) }
143
191
  def run_update_checker
144
192
  SharedHelpers.with_git_configured(credentials: credentials) do
145
193
  SharedHelpers.run_helper_subprocess(
@@ -156,14 +204,16 @@ module Dependabot
156
204
  end
157
205
  end
158
206
 
207
+ sig { params(unlock_requirement: T::Boolean).returns(String) }
159
208
  def prepared_composer_json_content(unlock_requirement: true)
160
- content = composer_file.content
209
+ content = T.must(T.must(composer_file).content)
161
210
  content = unlock_dep_being_updated(content) if unlock_requirement
162
211
  content = lock_git_dependencies(content) if lockfile
163
212
  content = add_temporary_platform_extensions(content)
164
213
  content
165
214
  end
166
215
 
216
+ sig { params(content: String).returns(String) }
167
217
  def unlock_dep_being_updated(content)
168
218
  content.gsub(
169
219
  /"#{Regexp.escape(dependency.name)}"\s*:\s*".*"/,
@@ -171,6 +221,7 @@ module Dependabot
171
221
  )
172
222
  end
173
223
 
224
+ sig { params(content: String).returns(String) }
174
225
  def add_temporary_platform_extensions(content)
175
226
  json = JSON.parse(content)
176
227
 
@@ -186,6 +237,7 @@ module Dependabot
186
237
  JSON.dump(json)
187
238
  end
188
239
 
240
+ sig { params(content: String).returns(String) }
189
241
  def lock_git_dependencies(content)
190
242
  json = JSON.parse(content)
191
243
 
@@ -197,7 +249,7 @@ module Dependabot
197
249
  next if req.include?("#")
198
250
 
199
251
  commit_sha = parsed_lockfile
200
- .fetch(keys[:lockfile], [])
252
+ .fetch(T.must(keys[:lockfile]), [])
201
253
  .find { |d| d["name"] == name }
202
254
  &.dig("source", "reference")
203
255
  updated_req_parts = req.split
@@ -211,6 +263,7 @@ module Dependabot
211
263
 
212
264
  # rubocop:disable Metrics/PerceivedComplexity
213
265
  # rubocop:disable Metrics/AbcSize
266
+ sig { returns(String) }
214
267
  def updated_version_requirement_string
215
268
  lower_bound =
216
269
  if requirements_to_unlock == :none
@@ -253,6 +306,7 @@ module Dependabot
253
306
  # rubocop:disable Metrics/AbcSize
254
307
  # rubocop:disable Metrics/CyclomaticComplexity
255
308
  # rubocop:disable Metrics/MethodLength
309
+ sig { params(error: SharedHelpers::HelperSubprocessFailed).returns(T.nilable(NilClass)) }
256
310
  def handle_composer_errors(error)
257
311
  # Special case for Laravel Nova, which will fall back to attempting
258
312
  # to close a private repo if given invalid (or no) credentials
@@ -271,7 +325,11 @@ module Dependabot
271
325
  missing_extensions =
272
326
  error.message.scan(MISSING_EXPLICIT_PLATFORM_REQ_REGEX)
273
327
  .map do |extension_string|
274
- name, requirement = extension_string.strip.split(" ", 2)
328
+ name, requirement = if extension_string.is_a?(Array)
329
+ [extension_string.first.to_s.strip, extension_string.last.to_s]
330
+ else
331
+ extension_string.to_s.strip.split(" ", 2)
332
+ end
275
333
  { name: name, requirement: requirement }
276
334
  end
277
335
  raise MissingExtensions, missing_extensions
@@ -282,7 +340,7 @@ module Dependabot
282
340
  missing_extensions =
283
341
  error.message.scan(MISSING_IMPLICIT_PLATFORM_REQ_REGEX)
284
342
  .map do |extension_string|
285
- name, requirement = extension_string.strip.split(" ", 2)
343
+ name, requirement = T.cast(extension_string, String).strip.split(" ", 2)
286
344
  { name: name, requirement: requirement }
287
345
  end
288
346
 
@@ -291,7 +349,7 @@ module Dependabot
291
349
  version_for_reqs(existing_reqs + [hash[:requirement]])
292
350
  end
293
351
 
294
- raise MissingExtensions, [missing_extension]
352
+ raise MissingExtensions, [missing_extension].compact
295
353
  elsif error.message.include?("cannot require itself") ||
296
354
  error.message.include?('packages.json" file could not be down')
297
355
  raise Dependabot::DependencyFileNotResolvable, error.message
@@ -312,14 +370,14 @@ module Dependabot
312
370
  # now, we therefore just ignore the dependency and log the error.
313
371
 
314
372
  Dependabot.logger.error(error.message)
315
- error.backtrace.each { |line| Dependabot.logger.error(line) }
373
+ error.backtrace&.each { |line| Dependabot.logger.error(line) }
316
374
  nil
317
375
  elsif error.message.include?("URL required authentication") ||
318
376
  error.message.include?("403 Forbidden")
319
- source = error.message.match(%r{https?://(?<source>[^/]+)/}).named_captures.fetch("source")
377
+ source = error.message.match(%r{https?://(?<source>[^/]+)/})&.named_captures&.fetch("source")
320
378
  raise Dependabot::PrivateSourceAuthenticationFailure, source
321
379
  elsif error.message.match?(SOURCE_TIMED_OUT_REGEX)
322
- url = error.message.match(SOURCE_TIMED_OUT_REGEX).named_captures.fetch("url")
380
+ url = T.must(error.message.match(SOURCE_TIMED_OUT_REGEX)&.named_captures&.fetch("url"))
323
381
  raise if [
324
382
  "packagist.org",
325
383
  "www.packagist.org"
@@ -357,6 +415,7 @@ module Dependabot
357
415
  # rubocop:enable Metrics/CyclomaticComplexity
358
416
  # rubocop:enable Metrics/MethodLength
359
417
 
418
+ sig { params(error: SharedHelpers::HelperSubprocessFailed).returns(T::Boolean) }
360
419
  def unresolvable_error?(error)
361
420
  error.message.start_with?("Could not parse version") ||
362
421
  error.message.include?("does not allow connections to http://") ||
@@ -364,15 +423,17 @@ module Dependabot
364
423
  error.message.start_with?("Invalid version string")
365
424
  end
366
425
 
426
+ sig { returns(T::Boolean) }
367
427
  def library?
368
428
  parsed_composer_file["type"] == "library"
369
429
  end
370
430
 
431
+ sig { params(message: String).returns(T::Boolean) }
371
432
  def implicit_platform_reqs_satisfiable?(message)
372
433
  missing_extensions =
373
434
  message.scan(MISSING_IMPLICIT_PLATFORM_REQ_REGEX)
374
435
  .map do |extension_string|
375
- name, requirement = extension_string.strip.split(" ", 2)
436
+ name, requirement = T.cast(extension_string, String).strip.split(" ", 2)
376
437
  { name: name, requirement: requirement }
377
438
  end
378
439
 
@@ -382,8 +443,9 @@ module Dependabot
382
443
  end
383
444
  end
384
445
 
446
+ sig { returns(T::Boolean) }
385
447
  def check_original_requirements_resolvable
386
- base_directory = dependency_files.first.directory
448
+ base_directory = T.must(dependency_files.first).directory
387
449
  SharedHelpers.in_a_temporary_directory(base_directory) do
388
450
  write_temporary_dependency_files(unlock_requirement: false)
389
451
 
@@ -414,6 +476,7 @@ module Dependabot
414
476
  raise Dependabot::DependencyFileNotResolvable, e.message
415
477
  end
416
478
 
479
+ sig { params(requirements: T::Array[String]).returns(T.nilable(String)) }
417
480
  def version_for_reqs(requirements)
418
481
  req_arrays =
419
482
  requirements
@@ -438,25 +501,32 @@ module Dependabot
438
501
  version.to_s
439
502
  end
440
503
 
504
+ sig { params(additional_extensions: T::Array[T::Hash[Symbol, String]]).void }
441
505
  def update_required_extensions(additional_extensions)
442
506
  additional_extensions.each do |ext|
443
507
  composer_platform_extensions[ext.fetch(:name)] ||= []
444
- composer_platform_extensions[ext.fetch(:name)] +=
445
- [ext.fetch(:requirement)]
446
508
  composer_platform_extensions[ext.fetch(:name)] =
447
- composer_platform_extensions[ext.fetch(:name)].uniq
509
+ T.must(composer_platform_extensions[ext.fetch(:name)]) + [ext.fetch(:requirement)]
510
+ composer_platform_extensions[ext.fetch(:name)] =
511
+ T.must(composer_platform_extensions[ext.fetch(:name)]).uniq
448
512
  end
449
513
  end
450
514
 
515
+ sig { returns(String) }
451
516
  def php_helper_path
452
517
  NativeHelpers.composer_helper_path(composer_version: composer_version)
453
518
  end
454
519
 
520
+ sig { returns(String) }
455
521
  def composer_version
456
522
  parsed_lockfile_or_nil = lockfile ? parsed_lockfile : nil
457
- @composer_version ||= Helpers.composer_version(parsed_composer_file, parsed_lockfile_or_nil)
523
+ @composer_version ||= T.let(
524
+ Helpers.composer_version(parsed_composer_file, parsed_lockfile_or_nil),
525
+ T.nilable(String)
526
+ )
458
527
  end
459
528
 
529
+ sig { returns(T::Hash[String, T::Array[String]]) }
460
530
  def initial_platform
461
531
  platform_php = Helpers.capture_platform_php(parsed_composer_file)
462
532
 
@@ -477,38 +547,63 @@ module Dependabot
477
547
  platform
478
548
  end
479
549
 
550
+ sig { returns(T::Hash[String, T.untyped]) }
480
551
  def parsed_composer_file
481
- @parsed_composer_file ||= JSON.parse(composer_file.content)
552
+ @parsed_composer_file ||= T.let(
553
+ JSON.parse(T.must(T.must(composer_file).content)),
554
+ T.nilable(T::Hash[String, T.untyped])
555
+ )
482
556
  end
483
557
 
558
+ sig { returns(T::Hash[String, T.untyped]) }
484
559
  def parsed_lockfile
485
- @parsed_lockfile ||= JSON.parse(lockfile.content)
560
+ @parsed_lockfile ||= T.let(
561
+ JSON.parse(T.must(lockfile&.content)),
562
+ T.nilable(T::Hash[String, T.untyped])
563
+ )
486
564
  end
487
565
 
566
+ sig { returns(T.nilable(Dependabot::DependencyFile)) }
488
567
  def composer_file
489
- @composer_file ||=
490
- dependency_files.find { |f| f.name == PackageManager::MANIFEST_FILENAME }
568
+ @composer_file ||= T.let(
569
+ dependency_files.find { |f| f.name == PackageManager::MANIFEST_FILENAME },
570
+ T.nilable(Dependabot::DependencyFile)
571
+ )
491
572
  end
492
573
 
574
+ sig { returns(T::Array[Dependabot::DependencyFile]) }
493
575
  def path_dependency_files
494
- @path_dependency_files ||=
495
- dependency_files.select { |f| f.name.end_with?("/#{PackageManager::MANIFEST_FILENAME}") }
576
+ @path_dependency_files ||= T.let(
577
+ dependency_files.select { |f| f.name.end_with?("/#{PackageManager::MANIFEST_FILENAME}") },
578
+ T.nilable(T::Array[Dependabot::DependencyFile])
579
+ )
496
580
  end
497
581
 
582
+ sig { returns(T::Array[Dependabot::DependencyFile]) }
498
583
  def zipped_path_dependency_files
499
- @zipped_path_dependency_files ||=
500
- dependency_files.select { |f| f.name.end_with?(".zip", ".gitkeep") }
584
+ @zipped_path_dependency_files ||= T.let(
585
+ dependency_files.select { |f| f.name.end_with?(".zip", ".gitkeep") },
586
+ T.nilable(T::Array[Dependabot::DependencyFile])
587
+ )
501
588
  end
502
589
 
590
+ sig { returns(T.nilable(Dependabot::DependencyFile)) }
503
591
  def lockfile
504
- @lockfile ||=
505
- dependency_files.find { |f| f.name == PackageManager::LOCKFILE_FILENAME }
592
+ @lockfile ||= T.let(
593
+ dependency_files.find { |f| f.name == PackageManager::LOCKFILE_FILENAME },
594
+ T.nilable(Dependabot::DependencyFile)
595
+ )
506
596
  end
507
597
 
598
+ sig { returns(T.nilable(Dependabot::DependencyFile)) }
508
599
  def auth_json
509
- @auth_json ||= dependency_files.find { |f| f.name == PackageManager::AUTH_FILENAME }
600
+ @auth_json ||= T.let(
601
+ dependency_files.find { |f| f.name == PackageManager::AUTH_FILENAME },
602
+ T.nilable(Dependabot::DependencyFile)
603
+ )
510
604
  end
511
605
 
606
+ sig { params(req_string: String).returns(T::Boolean) }
512
607
  def requirement_valid?(req_string)
513
608
  Composer::Requirement.requirements_array(req_string)
514
609
  true
@@ -516,12 +611,14 @@ module Dependabot
516
611
  false
517
612
  end
518
613
 
614
+ sig { returns(T::Array[Dependabot::Credential]) }
519
615
  def git_credentials
520
616
  credentials
521
617
  .select { |cred| cred["type"] == "git_source" }
522
618
  .select { |cred| cred["password"] }
523
619
  end
524
620
 
621
+ sig { returns(T::Array[Dependabot::Credential]) }
525
622
  def registry_credentials
526
623
  credentials
527
624
  .select { |cred| cred["type"] == PackageManager::REPOSITORY_KEY }
@@ -534,23 +631,24 @@ module Dependabot
534
631
  extend T::Sig
535
632
 
536
633
  # Private source errors
537
- CURL_ERROR = /curl error 52 while downloading (?<url>.*): Empty reply from server/
634
+ CURL_ERROR = T.let(/curl error 52 while downloading (?<url>.*): Empty reply from server/, Regexp)
538
635
 
539
- PRIVATE_SOURCE_AUTH_FAIL = [
636
+ PRIVATE_SOURCE_AUTH_FAIL = T.let([
540
637
  /Could not authenticate against (?<url>.*)/,
541
638
  /The '(?<url>.*)' URL could not be accessed \(HTTP 403\)/,
542
639
  /The "(?<url>.*)" file could not be downloaded/
543
- ].freeze
640
+ ].freeze, T::Array[Regexp])
544
641
 
545
- REQUIREMENT_ERROR = /^(?<req>.*) is invalid, it should not contain uppercase characters/
642
+ REQUIREMENT_ERROR = T.let(/^(?<req>.*) is invalid, it should not contain uppercase characters/, Regexp)
546
643
 
547
- NO_URL = "No URL specified"
644
+ NO_URL = T.let("No URL specified", String)
548
645
 
646
+ sig { params(url: String).returns(String) }
549
647
  def sanitize_uri(url)
550
648
  url = "http://#{url}" unless url.start_with?("http")
551
649
  uri = URI.parse(url)
552
650
  host = T.must(uri.host).downcase
553
- host.start_with?("www.") ? host[4..-1] : host
651
+ host.start_with?("www.") ? T.must(host[4..-1]) : host
554
652
  end
555
653
 
556
654
  # Handles errors with specific to composer error codes
@@ -561,7 +659,8 @@ module Dependabot
561
659
  next unless error.message.match?(regex)
562
660
 
563
661
  url = T.must(error.message.match(regex)).named_captures["url"]
564
- raise Dependabot::PrivateSourceAuthenticationFailure, sanitize_uri(url).empty? ? NO_URL : sanitize_uri(url)
662
+ sanitized_url = sanitize_uri(T.must(url))
663
+ raise Dependabot::PrivateSourceAuthenticationFailure, sanitized_url.empty? ? NO_URL : sanitized_url
565
664
  end
566
665
 
567
666
  # invalid requirement mentioned in manifest file
@@ -573,7 +672,7 @@ module Dependabot
573
672
  return unless error.message.match?(CURL_ERROR)
574
673
 
575
674
  url = T.must(error.message.match(CURL_ERROR)).named_captures["url"]
576
- raise PrivateSourceBadResponse, url
675
+ raise PrivateSourceBadResponse, T.must(url)
577
676
  end
578
677
  end
579
678
  end
@@ -28,7 +28,7 @@ module Dependabot
28
28
  latest_version_from_registry || latest_resolvable_version
29
29
  end
30
30
 
31
- sig { override.returns(T.nilable(Dependabot::Composer::Version)) }
31
+ sig { override.returns(T.nilable(Dependabot::Version)) }
32
32
  def latest_resolvable_version
33
33
  return nil if path_dependency? || git_dependency?
34
34
 
@@ -40,26 +40,26 @@ module Dependabot
40
40
  latest_allowable_version: latest_version_from_registry,
41
41
  requirements_to_unlock: :own
42
42
  ).latest_resolvable_version,
43
- T.nilable(Dependabot::Composer::Version)
43
+ T.nilable(Dependabot::Version)
44
44
  )
45
45
  end
46
46
 
47
- sig { override.returns(T.nilable(Dependabot::Composer::Version)) }
47
+ sig { override.returns(T.nilable(Dependabot::Version)) }
48
48
  def lowest_security_fix_version
49
49
  latest_version_finder.lowest_security_fix_version
50
50
  end
51
51
 
52
- sig { override.returns(T.nilable(Dependabot::Composer::Version)) }
52
+ sig { override.returns(T.nilable(Dependabot::Version)) }
53
53
  def lowest_resolvable_security_fix_version
54
54
  raise "Dependency not vulnerable!" unless vulnerable?
55
55
 
56
56
  @lowest_resolvable_security_fix_version ||= T.let(
57
57
  fetch_lowest_resolvable_security_fix_version,
58
- T.nilable(Dependabot::Composer::Version)
58
+ T.nilable(Dependabot::Version)
59
59
  )
60
60
  end
61
61
 
62
- sig { override.returns(T.nilable(Dependabot::Composer::Version)) }
62
+ sig { override.returns(T.nilable(Dependabot::Version)) }
63
63
  def latest_resolvable_version_with_no_unlock
64
64
  return nil if path_dependency? || git_dependency?
65
65
 
@@ -71,7 +71,7 @@ module Dependabot
71
71
  latest_allowable_version: latest_version_from_registry,
72
72
  requirements_to_unlock: :none
73
73
  ).latest_resolvable_version,
74
- T.nilable(Dependabot::Composer::Version)
74
+ T.nilable(Dependabot::Version)
75
75
  )
76
76
  end
77
77
 
@@ -80,7 +80,7 @@ module Dependabot
80
80
  RequirementsUpdater.new(
81
81
  requirements: dependency.requirements,
82
82
  latest_resolvable_version: preferred_resolvable_version&.to_s,
83
- update_strategy: requirements_update_strategy
83
+ update_strategy: T.must(requirements_update_strategy)
84
84
  ).updated_requirements
85
85
  end
86
86
 
@@ -111,7 +111,7 @@ module Dependabot
111
111
  raise NotImplementedError
112
112
  end
113
113
 
114
- sig { returns(T.nilable(Dependabot::Composer::Version)) }
114
+ sig { returns(T.nilable(Dependabot::Version)) }
115
115
  def latest_version_from_registry
116
116
  latest_version_finder.latest_version
117
117
  end
@@ -131,7 +131,7 @@ module Dependabot
131
131
  )
132
132
  end
133
133
 
134
- sig { returns(T.nilable(Dependabot::Composer::Version)) }
134
+ sig { returns(T.nilable(Dependabot::Version)) }
135
135
  def fetch_lowest_resolvable_security_fix_version
136
136
  return nil if path_dependency? || git_dependency?
137
137
 
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: dependabot-composer
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.311.0
4
+ version: 0.312.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Dependabot
8
8
  bindir: bin
9
9
  cert_chain: []
10
- date: 2025-05-01 00:00:00.000000000 Z
10
+ date: 2025-05-09 00:00:00.000000000 Z
11
11
  dependencies:
12
12
  - !ruby/object:Gem::Dependency
13
13
  name: dependabot-common
@@ -15,28 +15,28 @@ dependencies:
15
15
  requirements:
16
16
  - - '='
17
17
  - !ruby/object:Gem::Version
18
- version: 0.311.0
18
+ version: 0.312.0
19
19
  type: :runtime
20
20
  prerelease: false
21
21
  version_requirements: !ruby/object:Gem::Requirement
22
22
  requirements:
23
23
  - - '='
24
24
  - !ruby/object:Gem::Version
25
- version: 0.311.0
25
+ version: 0.312.0
26
26
  - !ruby/object:Gem::Dependency
27
27
  name: debug
28
28
  requirement: !ruby/object:Gem::Requirement
29
29
  requirements:
30
30
  - - "~>"
31
31
  - !ruby/object:Gem::Version
32
- version: 1.9.2
32
+ version: '1.9'
33
33
  type: :development
34
34
  prerelease: false
35
35
  version_requirements: !ruby/object:Gem::Requirement
36
36
  requirements:
37
37
  - - "~>"
38
38
  - !ruby/object:Gem::Version
39
- version: 1.9.2
39
+ version: '1.9'
40
40
  - !ruby/object:Gem::Dependency
41
41
  name: gpgme
42
42
  requirement: !ruby/object:Gem::Requirement
@@ -57,14 +57,14 @@ dependencies:
57
57
  requirements:
58
58
  - - "~>"
59
59
  - !ruby/object:Gem::Version
60
- version: '13'
60
+ version: '13.2'
61
61
  type: :development
62
62
  prerelease: false
63
63
  version_requirements: !ruby/object:Gem::Requirement
64
64
  requirements:
65
65
  - - "~>"
66
66
  - !ruby/object:Gem::Version
67
- version: '13'
67
+ version: '13.2'
68
68
  - !ruby/object:Gem::Dependency
69
69
  name: rspec
70
70
  requirement: !ruby/object:Gem::Requirement
@@ -99,98 +99,98 @@ dependencies:
99
99
  requirements:
100
100
  - - "~>"
101
101
  - !ruby/object:Gem::Version
102
- version: 1.9.2
102
+ version: '1.9'
103
103
  type: :development
104
104
  prerelease: false
105
105
  version_requirements: !ruby/object:Gem::Requirement
106
106
  requirements:
107
107
  - - "~>"
108
108
  - !ruby/object:Gem::Version
109
- version: 1.9.2
109
+ version: '1.9'
110
110
  - !ruby/object:Gem::Dependency
111
111
  name: rubocop
112
112
  requirement: !ruby/object:Gem::Requirement
113
113
  requirements:
114
114
  - - "~>"
115
115
  - !ruby/object:Gem::Version
116
- version: 1.67.0
116
+ version: '1.67'
117
117
  type: :development
118
118
  prerelease: false
119
119
  version_requirements: !ruby/object:Gem::Requirement
120
120
  requirements:
121
121
  - - "~>"
122
122
  - !ruby/object:Gem::Version
123
- version: 1.67.0
123
+ version: '1.67'
124
124
  - !ruby/object:Gem::Dependency
125
125
  name: rubocop-performance
126
126
  requirement: !ruby/object:Gem::Requirement
127
127
  requirements:
128
128
  - - "~>"
129
129
  - !ruby/object:Gem::Version
130
- version: 1.22.1
130
+ version: '1.22'
131
131
  type: :development
132
132
  prerelease: false
133
133
  version_requirements: !ruby/object:Gem::Requirement
134
134
  requirements:
135
135
  - - "~>"
136
136
  - !ruby/object:Gem::Version
137
- version: 1.22.1
137
+ version: '1.22'
138
138
  - !ruby/object:Gem::Dependency
139
139
  name: rubocop-rspec
140
140
  requirement: !ruby/object:Gem::Requirement
141
141
  requirements:
142
142
  - - "~>"
143
143
  - !ruby/object:Gem::Version
144
- version: 2.29.1
144
+ version: '2.29'
145
145
  type: :development
146
146
  prerelease: false
147
147
  version_requirements: !ruby/object:Gem::Requirement
148
148
  requirements:
149
149
  - - "~>"
150
150
  - !ruby/object:Gem::Version
151
- version: 2.29.1
151
+ version: '2.29'
152
152
  - !ruby/object:Gem::Dependency
153
153
  name: rubocop-sorbet
154
154
  requirement: !ruby/object:Gem::Requirement
155
155
  requirements:
156
156
  - - "~>"
157
157
  - !ruby/object:Gem::Version
158
- version: 0.8.7
158
+ version: '0.8'
159
159
  type: :development
160
160
  prerelease: false
161
161
  version_requirements: !ruby/object:Gem::Requirement
162
162
  requirements:
163
163
  - - "~>"
164
164
  - !ruby/object:Gem::Version
165
- version: 0.8.7
165
+ version: '0.8'
166
166
  - !ruby/object:Gem::Dependency
167
167
  name: simplecov
168
168
  requirement: !ruby/object:Gem::Requirement
169
169
  requirements:
170
170
  - - "~>"
171
171
  - !ruby/object:Gem::Version
172
- version: 0.22.0
172
+ version: '0.22'
173
173
  type: :development
174
174
  prerelease: false
175
175
  version_requirements: !ruby/object:Gem::Requirement
176
176
  requirements:
177
177
  - - "~>"
178
178
  - !ruby/object:Gem::Version
179
- version: 0.22.0
179
+ version: '0.22'
180
180
  - !ruby/object:Gem::Dependency
181
181
  name: turbo_tests
182
182
  requirement: !ruby/object:Gem::Requirement
183
183
  requirements:
184
184
  - - "~>"
185
185
  - !ruby/object:Gem::Version
186
- version: 2.2.0
186
+ version: '2.2'
187
187
  type: :development
188
188
  prerelease: false
189
189
  version_requirements: !ruby/object:Gem::Requirement
190
190
  requirements:
191
191
  - - "~>"
192
192
  - !ruby/object:Gem::Version
193
- version: 2.2.0
193
+ version: '2.2'
194
194
  - !ruby/object:Gem::Dependency
195
195
  name: vcr
196
196
  requirement: !ruby/object:Gem::Requirement
@@ -279,7 +279,7 @@ licenses:
279
279
  - MIT
280
280
  metadata:
281
281
  bug_tracker_uri: https://github.com/dependabot/dependabot-core/issues
282
- changelog_uri: https://github.com/dependabot/dependabot-core/releases/tag/v0.311.0
282
+ changelog_uri: https://github.com/dependabot/dependabot-core/releases/tag/v0.312.0
283
283
  rdoc_options: []
284
284
  require_paths:
285
285
  - lib