dependabot-cargo 0.385.0 → 0.386.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: fe49d45601f5fe58da2ee6fad020f1edb4db50a2d9f2f2d47d1b0348cde16ff8
4
- data.tar.gz: b01be9ba87a3a0a452e5e24fc8c8809c29342b119ba1de6477de77cedf6de58b
3
+ metadata.gz: 342398b3a35a615f1b23ae103f2a61e3c11ab24fb92b2eb3f6227b68cdae6600
4
+ data.tar.gz: a087cc721a765e9b8fd424a6972e1f110895947e36048906832a6f7acc59baed
5
5
  SHA512:
6
- metadata.gz: d14c302e2b6ac9b4b209dd5bc21d14f2062bf04220369c7f79a56c4affc6d5fdb2fd48042045c06a354c7c7c4a418db1130fc9e77eeb90adb8745d39eb94d896
7
- data.tar.gz: 1f64b3f3937048eda866e9f9bb0b137803dc9174cf86574ea6556479e9e24779e3066c7fbf348e8d8b616f403974db53f13b9d0124ee0b814e10a921b63a652f
6
+ metadata.gz: 236e947dcc2a2a2674432ac934826740dd42591dd0568211059e11bc79d5f3875c70f63aedab2f03f5351170e3d2a9dd7537385e2c3fd240f5c02621a4624973
7
+ data.tar.gz: affa0255ca4605212a1a233cc636893532aa5b5743d94fd4a1fb1d75e70bc52ce36fb245c92cd19e5c13787906702137be32492cbc5b08327bb19875ff7ecfe0
@@ -28,7 +28,7 @@ module Dependabot
28
28
  "Repo must contain a Cargo.toml."
29
29
  end
30
30
 
31
- sig { override.returns(T.nilable(T::Hash[Symbol, T.untyped])) }
31
+ sig { override.returns(T.nilable(T::Hash[Symbol, T.anything])) }
32
32
  def ecosystem_versions
33
33
  channel = if rust_toolchain
34
34
  TomlRB.parse(T.must(rust_toolchain).content).dig("toolchain", "channel")
@@ -180,12 +180,14 @@ module Dependabot
180
180
  find_workspace_root(file)
181
181
  end
182
182
 
183
- sig { params(dependencies: T::Hash[T.untyped, T.untyped]).returns(T::Array[String]) }
183
+ sig { params(dependencies: T::Hash[String, T.anything]).returns(T::Array[String]) }
184
184
  def collect_path_dependencies_paths(dependencies)
185
185
  dependencies.filter_map do |_, details|
186
- next unless details.is_a?(Hash) && details["path"]
186
+ details = toml_table(details)
187
+ path = T.cast(details&.fetch("path", nil), T.nilable(String))
188
+ next unless path
187
189
 
188
- File.join(details["path"], "Cargo.toml").delete_prefix("/")
190
+ File.join(path, "Cargo.toml").delete_prefix("/")
189
191
  end
190
192
  end
191
193
 
@@ -194,18 +196,19 @@ module Dependabot
194
196
  def path_dependency_paths_from_file(file)
195
197
  paths = T.let([], T::Array[String])
196
198
 
197
- workspace = parsed_file(file).fetch("workspace", {})
199
+ workspace = toml_table_or_empty(parsed_file(file).fetch("workspace", {}))
198
200
  Cargo::FileParser::DEPENDENCY_TYPES.each do |type|
199
201
  # Paths specified in dependency declaration
200
- paths += collect_path_dependencies_paths(parsed_file(file).fetch(type, {}))
202
+ paths += collect_path_dependencies_paths(toml_table_or_empty(parsed_file(file).fetch(type, {})))
201
203
  # Paths specified as workspace dependencies in workspace root
202
- paths += collect_path_dependencies_paths(workspace.fetch(type, {}))
204
+ paths += collect_path_dependencies_paths(toml_table_or_empty(workspace.fetch(type, {})))
203
205
  end
204
206
 
205
207
  # Paths specified for target-specific dependencies
206
- parsed_file(file).fetch("target", {}).each do |_, t_details|
208
+ toml_table_or_empty(parsed_file(file).fetch("target", {})).each do |_, t_details|
209
+ t_details = toml_table_or_empty(t_details)
207
210
  Cargo::FileParser::DEPENDENCY_TYPES.each do |type|
208
- paths += collect_path_dependencies_paths(t_details.fetch(type, {}))
211
+ paths += collect_path_dependencies_paths(toml_table_or_empty(t_details.fetch(type, {})))
209
212
  end
210
213
  end
211
214
 
@@ -217,20 +220,25 @@ module Dependabot
217
220
  paths = []
218
221
 
219
222
  # Paths specified as replacements
220
- parsed_file(file).fetch("replace", {}).each do |_, details|
221
- next unless details.is_a?(Hash) && details["path"]
223
+ toml_table_or_empty(parsed_file(file).fetch("replace", {})).each do |_, details|
224
+ details = toml_table(details)
225
+ path = T.cast(details&.fetch("path", nil), T.nilable(String))
226
+ next unless path
222
227
 
223
- paths << File.join(details["path"], "Cargo.toml")
228
+ paths << File.join(path, "Cargo.toml")
224
229
  end
225
230
 
226
231
  # Paths specified as patches
227
- parsed_file(file).fetch("patch", {}).each do |_, details|
228
- next unless details.is_a?(Hash)
232
+ toml_table_or_empty(parsed_file(file).fetch("patch", {})).each do |_, details|
233
+ details = toml_table(details)
234
+ next unless details
229
235
 
230
236
  details.each do |_, dep_details|
231
- next unless dep_details.is_a?(Hash) && dep_details["path"]
237
+ dep_details = toml_table(dep_details)
238
+ path = T.cast(dep_details&.fetch("path", nil), T.nilable(String))
239
+ next unless path
232
240
 
233
- paths << File.join(dep_details["path"], "Cargo.toml")
241
+ paths << File.join(path, "Cargo.toml")
234
242
  end
235
243
  end
236
244
 
@@ -239,28 +247,31 @@ module Dependabot
239
247
 
240
248
  # Check if this Cargo manifest uses workspace dependencies
241
249
  # (e.g. dependency = { workspace = true }).
242
- sig { params(parsed_manifest: T::Hash[T.untyped, T.untyped]).returns(T::Boolean) }
250
+ sig { params(parsed_manifest: T::Hash[String, T.anything]).returns(T::Boolean) }
243
251
  def uses_workspace_dependencies?(parsed_manifest)
244
252
  # Check regular dependencies
245
253
  workspace_deps = Cargo::FileParser::DEPENDENCY_TYPES.any? do |type|
246
- deps = parsed_manifest.fetch(type, {})
254
+ deps = toml_table_or_empty(parsed_manifest.fetch(type, {}))
247
255
  deps.any? do |_, details|
248
- next false unless details.is_a?(Hash)
256
+ details = toml_table(details)
257
+ next false unless details
249
258
 
250
- details["workspace"] == true
259
+ T.cast(details["workspace"], T.nilable(Object)) == true
251
260
  end
252
261
  end
253
262
 
254
263
  return true if workspace_deps
255
264
 
256
265
  # Check target-specific dependencies
257
- parsed_manifest.fetch("target", {}).any? do |_, target_details|
266
+ toml_table_or_empty(parsed_manifest.fetch("target", {})).any? do |_, target_details|
267
+ target_details = toml_table_or_empty(target_details)
258
268
  Cargo::FileParser::DEPENDENCY_TYPES.any? do |type|
259
- deps = target_details.fetch(type, {})
269
+ deps = toml_table_or_empty(target_details.fetch(type, {}))
260
270
  deps.any? do |_, details|
261
- next false unless details.is_a?(Hash)
271
+ details = toml_table(details)
272
+ next false unless details
262
273
 
263
- details["workspace"] == true
274
+ T.cast(details["workspace"], T.nilable(Object)) == true
264
275
  end
265
276
  end
266
277
  end
@@ -268,13 +279,14 @@ module Dependabot
268
279
 
269
280
  # See if this Cargo manifest inherits any property from a workspace
270
281
  # (e.g. edition = { workspace = true }).
271
- sig { params(hash: T::Hash[T.untyped, T.untyped]).returns(T::Boolean) }
282
+ sig { params(hash: T::Hash[String, T.anything]).returns(T::Boolean) }
272
283
  def workspace_member?(hash)
273
284
  hash.each do |key, value|
285
+ value = T.cast(value, T.nilable(Object))
274
286
  if key == "workspace" && value == true
275
287
  return true
276
288
  elsif value.is_a?(Hash)
277
- return workspace_member?(value)
289
+ return workspace_member?(toml_table_or_empty(value))
278
290
  end
279
291
  end
280
292
  false
@@ -289,7 +301,8 @@ module Dependabot
289
301
  def find_workspace_root(workspace_member)
290
302
  current_dir = workspace_member.name.rpartition("/").first
291
303
 
292
- workspace_root_dir = parsed_file(workspace_member).dig("package", "workspace")
304
+ package = toml_table_or_empty(parsed_file(workspace_member)["package"])
305
+ workspace_root_dir = T.cast(package["workspace"], T.nilable(String))
293
306
  unless workspace_root_dir.nil?
294
307
  workspace_root = fetch_file_from_host(
295
308
  File.join(current_dir, workspace_root_dir, "Cargo.toml"),
@@ -322,11 +335,10 @@ module Dependabot
322
335
 
323
336
  sig { params(file: Dependabot::DependencyFile).returns(T::Array[String]) }
324
337
  def workspace_dependency_paths_from_file(file)
325
- if parsed_file(file)["workspace"] && !parsed_file(file)["workspace"].key?("members")
326
- return path_dependency_paths_from_file(file)
327
- end
338
+ workspace = toml_table(parsed_file(file)["workspace"])
339
+ return path_dependency_paths_from_file(file) if workspace && !workspace.key?("members")
328
340
 
329
- workspace_paths = parsed_file(file).dig("workspace", "members")
341
+ workspace_paths = T.cast(workspace&.fetch("members", nil), T.nilable(T::Array[String]))
330
342
  return [] unless workspace_paths&.any?
331
343
 
332
344
  # Expand any workspace paths that specify a `*`
@@ -335,9 +347,7 @@ module Dependabot
335
347
  end
336
348
 
337
349
  # Excluded paths, to be subtracted for the workspaces array
338
- excluded_paths =
339
- (parsed_file(file).dig("workspace", "excluded_paths") || []) +
340
- (parsed_file(file).dig("workspace", "exclude") || [])
350
+ excluded_paths = workspace_excluded_paths(workspace)
341
351
 
342
352
  (workspace_paths - excluded_paths).map do |path|
343
353
  File.join(path, "Cargo.toml")
@@ -346,59 +356,40 @@ module Dependabot
346
356
 
347
357
  # Check whether a path is required or not. It will not be required if
348
358
  # an alternative source (i.e., a git source) is also specified
349
- # rubocop:disable Metrics/CyclomaticComplexity
350
359
  # rubocop:disable Metrics/PerceivedComplexity
351
- # rubocop:disable Metrics/AbcSize
352
360
  sig { params(file: Dependabot::DependencyFile, path: String).returns(T::Boolean) }
353
361
  def required_path?(file, path)
354
362
  # Paths specified in dependency declaration
355
363
  Cargo::FileParser::DEPENDENCY_TYPES.each do |type|
356
- parsed_file(file).fetch(type, {}).each do |_, details|
357
- next unless details.is_a?(Hash)
358
- next unless details["path"]
359
- next unless path == File.join(details["path"], "Cargo.toml")
360
-
361
- return true if details["git"].nil?
364
+ toml_table_or_empty(parsed_file(file).fetch(type, {})).each do |_, details|
365
+ return true if required_dependency_details?(details, path)
362
366
  end
363
367
  end
364
368
 
365
369
  # Paths specified for target-specific dependencies
366
- parsed_file(file).fetch("target", {}).each do |_, t_details|
370
+ toml_table_or_empty(parsed_file(file).fetch("target", {})).each do |_, t_details|
371
+ t_details = toml_table_or_empty(t_details)
367
372
  Cargo::FileParser::DEPENDENCY_TYPES.each do |type|
368
- t_details.fetch(type, {}).each do |_, details|
369
- next unless details.is_a?(Hash)
370
- next unless details["path"]
371
- next unless path == File.join(details["path"], "Cargo.toml")
372
-
373
- return true if details["git"].nil?
373
+ toml_table_or_empty(t_details.fetch(type, {})).each do |_, details|
374
+ return true if required_dependency_details?(details, path)
374
375
  end
375
376
  end
376
377
  end
377
378
 
378
379
  # Paths specified for workspace-wide dependencies
379
- workspace = parsed_file(file).fetch("workspace", {})
380
- workspace.fetch("dependencies", {}).each do |_, details|
381
- next unless details.is_a?(Hash)
382
- next unless details["path"]
383
- next unless path == File.join(details["path"], "Cargo.toml")
384
-
385
- return true if details["git"].nil?
380
+ workspace = toml_table_or_empty(parsed_file(file).fetch("workspace", {}))
381
+ toml_table_or_empty(workspace.fetch("dependencies", {})).each do |_, details|
382
+ return true if required_dependency_details?(details, path)
386
383
  end
387
384
 
388
385
  # Paths specified as replacements
389
- parsed_file(file).fetch("replace", {}).each do |_, details|
390
- next unless details.is_a?(Hash)
391
- next unless details["path"]
392
- next unless path == File.join(details["path"], "Cargo.toml")
393
-
394
- return true if details["git"].nil?
386
+ toml_table_or_empty(parsed_file(file).fetch("replace", {})).each do |_, details|
387
+ return true if required_dependency_details?(details, path)
395
388
  end
396
389
 
397
390
  false
398
391
  end
399
- # rubocop:enable Metrics/AbcSize
400
392
  # rubocop:enable Metrics/PerceivedComplexity
401
- # rubocop:enable Metrics/CyclomaticComplexity
402
393
 
403
394
  sig { params(path: String).returns(T::Array[String]) }
404
395
  def expand_workspaces(path)
@@ -411,13 +402,44 @@ module Dependabot
411
402
  .select { |filename| File.fnmatch?(path, filename) }
412
403
  end
413
404
 
414
- sig { params(file: Dependabot::DependencyFile).returns(T::Hash[T.untyped, T.untyped]) }
405
+ sig { params(file: Dependabot::DependencyFile).returns(T::Hash[String, T.anything]) }
415
406
  def parsed_file(file)
416
407
  TomlRB.parse(file.content)
417
408
  rescue TomlRB::ParseError, TomlRB::ValueOverwriteError
418
409
  raise Dependabot::DependencyFileNotParseable, file.path
419
410
  end
420
411
 
412
+ sig { params(workspace: T.nilable(T::Hash[String, T.anything])).returns(T::Array[String]) }
413
+ def workspace_excluded_paths(workspace)
414
+ (T.cast(workspace&.fetch("excluded_paths", nil), T.nilable(T::Array[String])) || []) +
415
+ (T.cast(workspace&.fetch("exclude", nil), T.nilable(T::Array[String])) || [])
416
+ end
417
+
418
+ sig { params(details: T.anything, path: String).returns(T::Boolean) }
419
+ def required_dependency_details?(details, path)
420
+ details = toml_table(details)
421
+ dependency_path = T.cast(details&.fetch("path", nil), T.nilable(String))
422
+ return false unless details && dependency_path
423
+ return false unless path == File.join(dependency_path, "Cargo.toml")
424
+
425
+ T.cast(details["git"], T.nilable(Object)).nil?
426
+ end
427
+
428
+ # Returns the value as a TOML table (Hash) when it is one, otherwise nil.
429
+ # TOML dependency values are polymorphic (e.g. `foo = "1.0"` is a String
430
+ # while `foo = { version = "1.0" }` is a table), so callers must narrow at
431
+ # runtime rather than assert a type with T.cast (which would raise).
432
+ sig { params(value: T.anything).returns(T.nilable(T::Hash[String, T.anything])) }
433
+ def toml_table(value)
434
+ obj = T.cast(value, T.nilable(Object))
435
+ obj.is_a?(Hash) ? obj : nil
436
+ end
437
+
438
+ sig { params(value: T.anything).returns(T::Hash[String, T.anything]) }
439
+ def toml_table_or_empty(value)
440
+ toml_table(value) || {}
441
+ end
442
+
421
443
  sig { returns(Dependabot::DependencyFile) }
422
444
  def cargo_toml
423
445
  @cargo_toml ||= T.let(fetch_file_from_host("Cargo.toml"), T.nilable(Dependabot::DependencyFile))
@@ -105,9 +105,8 @@ module Dependabot
105
105
  def check_rust_workspace_root
106
106
  cargo_toml = dependency_files.find { |f| f.name == "Cargo.toml" }
107
107
  workspace_root = parsed_file(T.must(cargo_toml))
108
- return unless workspace_root.is_a?(Hash)
109
108
 
110
- workspace_config = workspace_root.dig("package", "workspace")
109
+ workspace_config = T.cast(toml_table_or_empty(workspace_root["package"])["workspace"], T.nilable(String))
111
110
  return unless workspace_config
112
111
 
113
112
  msg = "This project is part of a Rust workspace but is not the " \
@@ -129,10 +128,10 @@ module Dependabot
129
128
 
130
129
  manifest_files.each do |file|
131
130
  parsed_content = parsed_file(file)
132
- next unless parsed_content.is_a?(Hash)
133
131
 
134
132
  DEPENDENCY_TYPES.each do |type|
135
- parsed_content.fetch(type, {}).each do |name, requirement|
133
+ toml_table_or_empty(parsed_content.fetch(type, {})).each do |name, requirement|
134
+ requirement = dependency_declaration(requirement)
136
135
  # Skip workspace-inherited dependencies (similar to pnpm catalog)
137
136
  # Only skip if workspace is exactly boolean true
138
137
  next if requirement.is_a?(Hash) && requirement["workspace"] == true
@@ -143,8 +142,10 @@ module Dependabot
143
142
  dependency_set << build_dependency(name, requirement, type, file)
144
143
  end
145
144
 
146
- parsed_content.fetch("target", {}).each do |_, t_details|
147
- t_details.fetch(type, {}).each do |name, requirement|
145
+ toml_table_or_empty(parsed_content.fetch("target", {})).each do |_, t_details|
146
+ t_details = toml_table_or_empty(t_details)
147
+ toml_table_or_empty(t_details.fetch(type, {})).each do |name, requirement|
148
+ requirement = dependency_declaration(requirement)
148
149
  # Skip workspace-inherited dependencies
149
150
  # Only skip if workspace is exactly boolean true
150
151
  next if requirement.is_a?(Hash) && requirement["workspace"] == true
@@ -158,8 +159,9 @@ module Dependabot
158
159
  end
159
160
  end
160
161
 
161
- workspace = parsed_content.fetch("workspace", {})
162
- workspace.fetch("dependencies", {}).each do |name, requirement|
162
+ workspace = toml_table_or_empty(parsed_content.fetch("workspace", {}))
163
+ toml_table_or_empty(workspace.fetch("dependencies", {})).each do |name, requirement|
164
+ requirement = dependency_declaration(requirement)
163
165
  next unless name == name_from_declaration(name, requirement)
164
166
  next if lockfile && !version_from_lockfile(name, requirement)
165
167
 
@@ -202,15 +204,14 @@ module Dependabot
202
204
  return dependency_set unless lockfile
203
205
 
204
206
  lockfile_content = parsed_file(T.must(lockfile))
205
- return dependency_set unless lockfile_content.is_a?(Hash)
206
207
 
207
- lockfile_content.fetch("package", []).each do |package_details|
208
- next unless package_details["source"]
208
+ T.cast(lockfile_content.fetch("package", []), T::Array[T::Hash[String, T.anything]]).each do |package_details|
209
+ next unless T.cast(package_details["source"], T.nilable(String))
209
210
 
210
211
  # TODO: This isn't quite right, as it will only give us one
211
212
  # version of each dependency (when in fact there are many)
212
213
  dependency_set << Dependency.new(
213
- name: package_details["name"],
214
+ name: T.cast(package_details["name"], String),
214
215
  version: version_from_lockfile_details(package_details),
215
216
  package_manager: "cargo",
216
217
  requirements: []
@@ -224,10 +225,9 @@ module Dependabot
224
225
  def patched_dependencies
225
226
  root_manifest = manifest_files.find { |f| f.name == "Cargo.toml" }
226
227
  parsed_content = parsed_file(T.must(root_manifest))
227
- return [] unless parsed_content.is_a?(Hash)
228
228
  return [] unless parsed_content["patch"]
229
229
 
230
- parsed_content["patch"].values.flat_map(&:keys)
230
+ toml_table_or_empty(parsed_content["patch"]).values.flat_map { |patch| toml_table_or_empty(patch).keys }
231
231
  end
232
232
 
233
233
  sig { params(declaration: T.any(String, T::Hash[String, String])).returns(T.nilable(String)) }
@@ -336,7 +336,10 @@ module Dependabot
336
336
  # taking precedence over ancestors. Search the package-directory config
337
337
  # first, then each ancestor config, returning the first match.
338
338
  cargo_config_files.each do |config_file|
339
- value = parsed_file(config_file).dig(*key_name.split("."))
339
+ value = key_name.split(".").reduce(parsed_file(config_file)) do |current, key|
340
+ toml_table_or_empty(current)[key]
341
+ end
342
+ value = T.cast(value, T.nilable(String))
340
343
  return value if value
341
344
  end
342
345
 
@@ -348,29 +351,28 @@ module Dependabot
348
351
  return unless lockfile
349
352
 
350
353
  lockfile_content = parsed_file(T.must(lockfile))
351
- return unless lockfile_content.is_a?(Hash)
352
354
 
353
355
  candidate_packages =
354
- lockfile_content.fetch("package", [])
355
- .select { |p| p["name"] == name }
356
+ lockfile_packages(lockfile_content)
357
+ .select { |p| package_field(p, "name") == name }
356
358
 
357
359
  if (req = requirement_from_declaration(declaration))
358
360
  req = Cargo::Requirement.new(req)
359
361
 
360
362
  candidate_packages =
361
363
  candidate_packages
362
- .select { |p| req.satisfied_by?(version_class.new(p["version"])) }
364
+ .select { |p| req.satisfied_by?(version_class.new(T.must(package_field(p, "version")))) }
363
365
  end
364
366
 
365
367
  candidate_packages =
366
368
  candidate_packages
367
369
  .select do |p|
368
- git_req?(declaration) ^ !p["source"]&.start_with?("git+")
370
+ git_req?(declaration) ^ !package_field(p, "source")&.start_with?("git+")
369
371
  end
370
372
 
371
373
  package =
372
374
  candidate_packages
373
- .max_by { |p| version_class.new(p["version"]) }
375
+ .max_by { |p| version_class.new(T.must(package_field(p, "version"))) }
374
376
 
375
377
  return unless package
376
378
 
@@ -392,11 +394,13 @@ module Dependabot
392
394
  }
393
395
  end
394
396
 
395
- sig { params(package_details: T::Hash[String, String]).returns(String) }
397
+ sig { params(package_details: T::Hash[String, T.anything]).returns(String) }
396
398
  def version_from_lockfile_details(package_details)
397
- return T.must(package_details["version"]) unless package_details["source"]&.start_with?("git+")
399
+ source = T.cast(package_details["source"], T.nilable(String))
400
+ version = T.cast(package_details["version"], String)
401
+ return version unless source&.start_with?("git+")
398
402
 
399
- T.must(T.must(package_details["source"]).split("#").last)
403
+ T.must(source.split("#").last)
400
404
  end
401
405
 
402
406
  sig { override.void }
@@ -404,14 +408,36 @@ module Dependabot
404
408
  raise "No Cargo.toml!" unless get_original_file("Cargo.toml")
405
409
  end
406
410
 
407
- sig { params(file: DependencyFile).returns(T.untyped) }
411
+ sig { params(file: DependencyFile).returns(T::Hash[String, T.anything]) }
408
412
  def parsed_file(file)
409
- @parsed_file ||= T.let({}, T.nilable(T::Hash[String, T.untyped]))
413
+ @parsed_file ||= T.let({}, T.nilable(T::Hash[String, T::Hash[String, T.anything]]))
410
414
  @parsed_file[file.name] ||= TomlRB.parse(file.content)
411
415
  rescue TomlRB::ParseError, TomlRB::ValueOverwriteError
412
416
  raise Dependabot::DependencyFileNotParseable, file.path
413
417
  end
414
418
 
419
+ sig { params(lockfile_content: T::Hash[String, T.anything]).returns(T::Array[T::Hash[String, T.anything]]) }
420
+ def lockfile_packages(lockfile_content)
421
+ T.cast(lockfile_content.fetch("package", []), T::Array[T::Hash[String, T.anything]])
422
+ end
423
+
424
+ sig { params(package_details: T::Hash[String, T.anything], field: String).returns(T.nilable(String)) }
425
+ def package_field(package_details, field)
426
+ T.cast(package_details[field], T.nilable(String))
427
+ end
428
+
429
+ sig { params(value: T.anything).returns(T::Hash[String, T.anything]) }
430
+ def toml_table_or_empty(value)
431
+ (obj = T.cast(value, T.nilable(Object))).is_a?(Hash) ? obj : {}
432
+ end
433
+
434
+ sig { params(value: T.anything).returns(T.any(String, T::Hash[String, String])) }
435
+ def dependency_declaration(value)
436
+ return T.cast(value, String) if T.cast(value, T.nilable(Object)).is_a?(String)
437
+
438
+ T.cast(value, T::Hash[String, String])
439
+ end
440
+
415
441
  sig { returns(T::Array[Dependabot::DependencyFile]) }
416
442
  def manifest_files
417
443
  @manifest_files ||= T.let(
@@ -392,20 +392,31 @@ module Dependabot
392
392
  TomlRB.dump(parsed_manifest)
393
393
  end
394
394
 
395
- sig { params(parsed_manifest: T::Hash[String, T.untyped]).void }
395
+ sig { params(parsed_manifest: T::Hash[String, T.anything]).void }
396
396
  def pin_target_specific_dependencies!(parsed_manifest)
397
- parsed_manifest.fetch("target", {}).each do |target, t_details|
397
+ toml_table_or_empty(parsed_manifest.fetch("target", {})).each do |target, t_details|
398
+ t_details = toml_table_or_empty(t_details)
398
399
  Cargo::FileParser::DEPENDENCY_TYPES.each do |type|
399
- t_details.fetch(type, {}).each do |name, requirement|
400
+ toml_table_or_empty(t_details.fetch(type, {})).each do |name, requirement|
400
401
  next unless name == dependency.name
401
402
 
402
403
  updated_req = "=#{dependency.version}"
403
404
 
404
- if requirement.is_a?(Hash)
405
- parsed_manifest["target"][target][type][name]["version"] =
405
+ if T.cast(requirement, T.nilable(Object)).is_a?(Hash)
406
+ toml_table_or_empty(
407
+ toml_table_or_empty(
408
+ toml_table_or_empty(
409
+ toml_table_or_empty(parsed_manifest["target"])[target]
410
+ )[type]
411
+ )[name]
412
+ )["version"] =
406
413
  updated_req
407
414
  else
408
- parsed_manifest["target"][target][type][name] = updated_req
415
+ toml_table_or_empty(
416
+ toml_table_or_empty(
417
+ toml_table_or_empty(parsed_manifest["target"])[target]
418
+ )[type]
419
+ )[name] = updated_req
409
420
  end
410
421
  end
411
422
  end
@@ -498,6 +509,12 @@ module Dependabot
498
509
  lockfile_content
499
510
  end
500
511
 
512
+ sig { params(value: T.anything).returns(T::Hash[String, T.anything]) }
513
+ def toml_table_or_empty(value)
514
+ obj = T.cast(value, T.nilable(Object))
515
+ obj.is_a?(Hash) ? obj : {}
516
+ end
517
+
501
518
  sig { returns(String) }
502
519
  def dummy_app_content
503
520
  %{fn main() {\nprintln!("Hello, world!");\n}}
@@ -19,7 +19,7 @@ module Dependabot
19
19
  sig { params(dependency: Dependabot::Dependency, credentials: T::Array[Dependabot::Credential]).void }
20
20
  def initialize(dependency:, credentials:)
21
21
  super
22
- @crates_listing = T.let(nil, T.nilable(T::Hash[String, T.untyped]))
22
+ @crates_listing = T.let(nil, T.nilable(T::Hash[String, T.anything]))
23
23
  end
24
24
 
25
25
  private
@@ -43,7 +43,10 @@ module Dependabot
43
43
  def find_source_from_crates_listing
44
44
  potential_source_urls =
45
45
  SOURCE_KEYS
46
- .filter_map { |key| T.must(crates_listing).dig("crate", key) }
46
+ .filter_map do |key|
47
+ crate = T.cast(T.must(crates_listing)["crate"], T.nilable(T::Hash[String, T.anything]))
48
+ T.cast(crate&.fetch(key, nil), T.nilable(String))
49
+ end
47
50
 
48
51
  source_url = potential_source_urls.find { |url| Source.from_url(url) }
49
52
  Source.from_url(source_url)
@@ -51,18 +54,25 @@ module Dependabot
51
54
 
52
55
  sig { returns(T.nilable(Dependabot::Source)) }
53
56
  def find_source_from_git_url
54
- info = dependency.requirements.filter_map { |r| r[:source] }.first
57
+ info = T.cast(
58
+ dependency.requirements.filter_map { |r| r[:source] }.first,
59
+ T.nilable(T::Hash[T.any(String, Symbol), T.anything])
60
+ )
61
+ return unless info
55
62
 
56
- url = info[:url] || info.fetch("url")
57
- Source.from_url(url)
63
+ url = info[:url] || info["url"]
64
+ Source.from_url(T.cast(url, T.nilable(String)))
58
65
  end
59
66
 
60
- sig { returns(T.nilable(T::Hash[String, T.untyped])) }
67
+ sig { returns(T.nilable(T::Hash[String, T.anything])) }
61
68
  def crates_listing
62
69
  return @crates_listing unless @crates_listing.nil?
63
70
 
64
- info = dependency.requirements.filter_map { |r| r[:source] }.first
65
- index = (info && info[:index]) || CRATES_IO_API
71
+ info = T.cast(
72
+ dependency.requirements.filter_map { |r| r[:source] }.first,
73
+ T.nilable(T::Hash[T.any(String, Symbol), T.anything])
74
+ )
75
+ index = T.cast((info && (info[:index] || info["index"])) || CRATES_IO_API, String)
66
76
  hdrs = build_headers(index, info)
67
77
 
68
78
  url = metadata_fetch_url(dependency, index)
@@ -71,14 +81,18 @@ module Dependabot
71
81
  @crates_listing = parse_response(response, index)
72
82
  end
73
83
 
74
- sig { params(index: String, info: T.nilable(T::Hash[String, T.untyped])).returns(T::Hash[String, String]) }
84
+ sig do
85
+ params(index: String, info: T.nilable(T::Hash[T.any(String, Symbol), T.anything]))
86
+ .returns(T::Hash[String, String])
87
+ end
75
88
  def build_headers(index, info)
76
89
  hdrs = { "User-Agent" => "Dependabot (dependabot.com)" }
77
90
  return hdrs if index == CRATES_IO_API
78
91
 
79
92
  return hdrs if info.nil?
80
93
 
81
- credentials.find { |cred| cred["type"] == "cargo_registry" && cred["registry"] == info["name"] }&.tap do |cred|
94
+ registry_name = T.cast(info["name"] || info[:name], T.nilable(String))
95
+ credentials.find { |cred| cred["type"] == "cargo_registry" && cred["registry"] == registry_name }&.tap do |cred|
82
96
  hdrs["Authorization"] = "Token #{cred['token']}"
83
97
  end
84
98
 
@@ -94,7 +108,7 @@ module Dependabot
94
108
  )
95
109
  end
96
110
 
97
- sig { params(response: Excon::Response, index: String).returns(T::Hash[String, T.untyped]) }
111
+ sig { params(response: Excon::Response, index: String).returns(T::Hash[String, T.anything]) }
98
112
  def parse_response(response, index)
99
113
  if index.start_with?("sparse+")
100
114
  parsed_response = response.body.lines.map { |line| JSON.parse(line) }
@@ -42,23 +42,25 @@ module Dependabot
42
42
  sig { returns(Dependabot::Dependency) }
43
43
  attr_reader :dependency
44
44
 
45
- sig { returns(T::Array[T.untyped]) }
45
+ sig { returns(T::Array[Dependabot::DependencyFile]) }
46
46
  attr_reader :dependency_files
47
47
 
48
- sig { returns(T::Array[T.untyped]) }
48
+ sig { returns(T::Array[Dependabot::Credential]) }
49
49
  attr_reader :credentials
50
50
 
51
51
  sig do
52
52
  returns(T.nilable(Dependabot::Package::PackageDetails))
53
53
  end
54
54
  def fetch
55
- package_releases = crates_listing.fetch("versions", []).reject { |v| v["yanked"] }.map do |release|
55
+ releases = T.cast(crates_listing.fetch("versions", []), T::Array[T::Hash[String, T.anything]])
56
+ package_releases = releases.reject { |v| v["yanked"] }.map do |release|
57
+ created_at = T.cast(release["created_at"], T.nilable(String))
56
58
  package_release(
57
- version: release["num"] || release["vers"],
58
- released_at: release["created_at"] ? Time.parse(release["created_at"]) : nil,
59
- downloads: release["downloads"],
60
- url: "#{CRATES_IO_API}/#{release['dl_path']}",
61
- rust_version: release["rust"]
59
+ version: T.cast(release["num"], T.nilable(String)) || T.cast(release["vers"], String),
60
+ released_at: created_at ? Time.parse(created_at) : nil,
61
+ downloads: T.cast(release["downloads"], T.nilable(Integer)),
62
+ url: "#{CRATES_IO_API}/#{T.cast(release['dl_path'], T.nilable(String))}",
63
+ rust_version: T.cast(release["rust"], T.nilable(String))
62
64
  )
63
65
  end
64
66
 
@@ -68,7 +70,7 @@ module Dependabot
68
70
  private
69
71
 
70
72
  sig do
71
- returns(T.untyped)
73
+ returns(T::Hash[String, T.anything])
72
74
  end
73
75
  def crates_listing
74
76
  return @crates_listing unless @crates_listing.nil?
@@ -86,41 +88,45 @@ module Dependabot
86
88
  response = fetch_response(url, hdrs)
87
89
  return {} if response.status == 404
88
90
 
89
- @crates_listing = T.let(parse_response(response, index), T.nilable(T::Hash[T.untyped, T.untyped]))
91
+ @crates_listing = T.let(parse_response(response, index), T.nilable(T::Hash[String, T.anything]))
90
92
 
91
93
  Dependabot.logger.info("Fetched metadata for #{dependency.name} from #{index} successfully")
92
94
 
93
- @crates_listing
95
+ T.must(@crates_listing)
94
96
  end
95
97
 
96
- sig { returns(T.nilable(T::Hash[T.untyped, T.untyped])) }
98
+ sig { returns(T.nilable(T::Hash[T.any(String, Symbol), T.anything])) }
97
99
  def fetch_dependency_info
98
- dependency.requirements.filter_map { |r| r[:source] }.first
100
+ T.cast(
101
+ dependency.requirements.filter_map { |r| r[:source] }.first,
102
+ T.nilable(T::Hash[T.any(String, Symbol), T.anything])
103
+ )
99
104
  end
100
105
 
101
- sig { params(info: T.untyped).returns(String) }
106
+ sig { params(info: T.nilable(T::Hash[T.any(String, Symbol), T.anything])).returns(String) }
102
107
  def fetch_index(info)
103
- (info && info[:index]) || CRATES_IO_API
108
+ T.cast((info && (info[:index] || info["index"])) || CRATES_IO_API, String)
104
109
  end
105
110
 
106
- sig { returns(T::Hash[T.untyped, T.untyped]) }
111
+ sig { returns(T::Hash[String, String]) }
107
112
  def default_headers
108
113
  { "User-Agent" => "Dependabot (dependabot.com)" }
109
114
  end
110
115
 
111
- sig { params(info: T.untyped).returns(T::Hash[T.untyped, T.untyped]) }
116
+ sig { params(info: T.nilable(T::Hash[T.any(String, Symbol), T.anything])).returns(T::Hash[String, String]) }
112
117
  def auth_headers(info)
118
+ registry_name = T.cast(info && (info[:name] || info["name"]), T.nilable(String))
113
119
  registry_creds = credentials.find do |cred|
114
- cred["type"] == "cargo_registry" && cred["registry"] == info[:name]
120
+ cred["type"] == "cargo_registry" && cred["registry"] == registry_name
115
121
  end
116
122
 
117
- return {} if registry_creds.nil?
123
+ return {} unless registry_creds
118
124
 
119
125
  token = registry_creds["token"] || "placeholder_token"
120
126
  { "Authorization" => token }
121
127
  end
122
128
 
123
- sig { params(url: String, headers: T.untyped).returns(Excon::Response) }
129
+ sig { params(url: String, headers: T::Hash[String, String]).returns(Excon::Response) }
124
130
  def fetch_response(url, headers)
125
131
  Excon.get(
126
132
  url,
@@ -129,7 +135,7 @@ module Dependabot
129
135
  )
130
136
  end
131
137
 
132
- sig { params(response: Excon::Response, index: T.untyped).returns(T::Hash[T.untyped, T.untyped]) }
138
+ sig { params(response: Excon::Response, index: String).returns(T::Hash[String, T.anything]) }
133
139
  def parse_response(response, index)
134
140
  if index.start_with?("sparse+")
135
141
  parsed_response = response.body.lines
@@ -148,7 +154,7 @@ module Dependabot
148
154
  end
149
155
  end
150
156
 
151
- sig { params(dependency: T.untyped, index: T.untyped).returns(String) }
157
+ sig { params(dependency: Dependabot::Dependency, index: String).returns(String) }
152
158
  def metadata_fetch_url(dependency, index)
153
159
  return "#{index}/#{dependency.name}" if index == CRATES_IO_API
154
160
 
@@ -123,9 +123,9 @@ module Dependabot
123
123
  TomlRB.dump(parsed_manifest)
124
124
  end
125
125
 
126
- sig { params(parsed_manifest: T::Hash[String, T.untyped], filename: String).void }
126
+ sig { params(parsed_manifest: T::Hash[String, T.anything], filename: String).void }
127
127
  def replace_req_on_target_specific_deps!(parsed_manifest, filename)
128
- parsed_manifest.fetch("target", {}).each do |target, _|
128
+ toml_table_or_empty(parsed_manifest.fetch("target", {})).each do |target, _|
129
129
  Cargo::FileParser::DEPENDENCY_TYPES.each do |type|
130
130
  dependency_names = dependency_names_for_type_and_target(
131
131
  parsed_manifest,
@@ -134,35 +134,39 @@ module Dependabot
134
134
  )
135
135
 
136
136
  dependency_names.each do |name|
137
- req = parsed_manifest.dig("target", target, type, name)
137
+ req = target_dependency_declaration(parsed_manifest, target, type, name)
138
138
 
139
139
  updated_req = temporary_requirement_for_resolution(filename)
140
140
 
141
141
  if req.is_a?(Hash)
142
- parsed_manifest["target"][target][type][name]["version"] =
143
- updated_req
142
+ target_dependency_table(parsed_manifest, target, type, name)["version"] = updated_req
144
143
  else
145
- parsed_manifest["target"][target][type][name] = updated_req
144
+ target_dependency_type_table(parsed_manifest, target, type)[name] = updated_req
146
145
  end
147
146
  end
148
147
  end
149
148
  end
150
149
  end
151
150
 
152
- sig { params(parsed_manifest: T::Hash[String, T.untyped], filename: String).void }
151
+ sig { params(parsed_manifest: T::Hash[String, T.anything], filename: String).void }
153
152
  def replace_req_on_workspace_deps!(parsed_manifest, filename)
154
- workspace = parsed_manifest.fetch("workspace", {})
155
- workspace_deps = workspace.fetch("dependencies", {})
153
+ workspace = toml_table_or_empty(parsed_manifest.fetch("workspace", {}))
154
+ workspace_deps = toml_table_or_empty(workspace.fetch("dependencies", {}))
156
155
 
157
156
  workspace_deps.each do |name, req|
157
+ req = dependency_declaration(req)
158
158
  next unless dependency.name == name_from_declaration(name, req)
159
159
 
160
160
  updated_req = temporary_requirement_for_resolution(filename)
161
161
 
162
162
  if req.is_a?(Hash)
163
- parsed_manifest["workspace"]["dependencies"][name]["version"] = updated_req
163
+ toml_table_or_empty(
164
+ toml_table_or_empty(
165
+ toml_table_or_empty(parsed_manifest["workspace"])["dependencies"]
166
+ )[name]
167
+ )["version"] = updated_req
164
168
  else
165
- parsed_manifest["workspace"]["dependencies"][name] = updated_req
169
+ toml_table_or_empty(toml_table_or_empty(parsed_manifest["workspace"])["dependencies"])[name] = updated_req
166
170
  end
167
171
  end
168
172
  end
@@ -173,13 +177,14 @@ module Dependabot
173
177
 
174
178
  Cargo::FileParser::DEPENDENCY_TYPES.each do |type|
175
179
  dependency_names_for_type(parsed_manifest, type).each do |name|
176
- req = parsed_manifest.dig(type, name)
180
+ req = T.cast(parsed_manifest.dig(type, name), T.any(String, T::Hash[String, T.anything]))
177
181
  next unless req.is_a?(Hash)
178
182
  next unless [req["tag"], req["rev"]].compact.uniq.one?
179
183
 
180
- parsed_manifest[type][name]["tag"] = replacement_git_pin if req["tag"]
184
+ dependency_options = toml_table_or_empty(toml_table_or_empty(parsed_manifest[type])[name])
185
+ dependency_options["tag"] = replacement_git_pin if req["tag"]
181
186
 
182
- parsed_manifest[type][name]["rev"] = replacement_git_pin if req["rev"]
187
+ dependency_options["rev"] = replacement_git_pin if req["rev"]
183
188
  end
184
189
  end
185
190
 
@@ -188,9 +193,9 @@ module Dependabot
188
193
  TomlRB.dump(parsed_manifest)
189
194
  end
190
195
 
191
- sig { params(parsed_manifest: T::Hash[String, T.untyped]).void }
196
+ sig { params(parsed_manifest: T::Hash[String, T.anything]).void }
192
197
  def replace_git_pin_on_target_specific_deps!(parsed_manifest)
193
- parsed_manifest.fetch("target", {}).each do |target, _|
198
+ toml_table_or_empty(parsed_manifest.fetch("target", {})).each do |target, _|
194
199
  Cargo::FileParser::DEPENDENCY_TYPES.each do |type|
195
200
  dependency_names = dependency_names_for_type_and_target(
196
201
  parsed_manifest,
@@ -199,19 +204,15 @@ module Dependabot
199
204
  )
200
205
 
201
206
  dependency_names.each do |name|
202
- req = parsed_manifest.dig("target", target, type, name)
207
+ req = target_dependency_declaration(parsed_manifest, target, type, name)
203
208
  next unless req.is_a?(Hash)
204
209
  next unless [req["tag"], req["rev"]].compact.uniq.one?
205
210
 
206
- if req["tag"]
207
- parsed_manifest["target"][target][type][name]["tag"] =
208
- replacement_git_pin
209
- end
211
+ target_dependency_table(parsed_manifest, target, type, name)["tag"] = replacement_git_pin if req["tag"]
210
212
 
211
- if req["rev"]
212
- parsed_manifest["target"][target][type][name]["rev"] =
213
- replacement_git_pin
214
- end
213
+ next unless req["rev"]
214
+
215
+ target_dependency_table(parsed_manifest, target, type, name)["rev"] = replacement_git_pin
215
216
  end
216
217
  end
217
218
  end
@@ -222,12 +223,12 @@ module Dependabot
222
223
  parsed_manifest = TomlRB.parse(content)
223
224
 
224
225
  Cargo::FileParser::DEPENDENCY_TYPES.each do |type|
225
- (parsed_manifest[type] || {}).each do |_, details|
226
- next unless details.is_a?(Hash)
227
- next unless details["git"]
226
+ toml_table_or_empty(parsed_manifest[type]).each do |_, details|
227
+ details = toml_table_or_empty(details)
228
+ git = T.cast(details.fetch("git", nil), T.nilable(String))
229
+ next unless git
228
230
 
229
- details["git"] = details["git"]
230
- .gsub(%r{ssh://git@(.*?)/}, 'https://\1/')
231
+ details["git"] = git.gsub(%r{ssh://git@(.*?)/}, 'https://\1/')
231
232
  end
232
233
  end
233
234
 
@@ -283,17 +284,29 @@ module Dependabot
283
284
  def git_dependency_version
284
285
  return unless lockfile
285
286
 
286
- TomlRB.parse(T.must(lockfile).content)
287
- .fetch("package", [])
288
- .select { |p| p["name"] == dependency.name }
289
- .find { |p| p["source"].end_with?(dependency.version) }
290
- .fetch("version")
287
+ version = dependency.version
288
+ return unless version
289
+
290
+ packages = T.cast(
291
+ TomlRB.parse(T.must(lockfile).content).fetch("package", []),
292
+ T::Array[T::Hash[String, T.anything]]
293
+ )
294
+ package = packages
295
+ .select { |p| T.cast(p["name"], T.nilable(String)) == dependency.name }
296
+ .find do |p|
297
+ source = T.cast(p["source"], T.nilable(String))
298
+ source&.end_with?(version)
299
+ end
300
+ return unless package
301
+
302
+ T.cast(package.fetch("version"), String)
291
303
  end
292
304
 
293
- sig { params(parsed_manifest: T::Hash[String, T.untyped], type: String).returns(T::Array[String]) }
305
+ sig { params(parsed_manifest: T::Hash[String, T.anything], type: String).returns(T::Array[String]) }
294
306
  def dependency_names_for_type(parsed_manifest, type)
295
307
  names = []
296
- parsed_manifest.fetch(type, {}).each do |nm, req|
308
+ toml_table_or_empty(parsed_manifest.fetch(type, {})).each do |nm, req|
309
+ req = dependency_declaration(req)
297
310
  next unless dependency.name == name_from_declaration(nm, req)
298
311
 
299
312
  names << nm
@@ -302,11 +315,13 @@ module Dependabot
302
315
  end
303
316
 
304
317
  sig do
305
- params(parsed_manifest: T::Hash[String, T.untyped], type: String, target: String).returns(T::Array[String])
318
+ params(parsed_manifest: T::Hash[String, T.anything], type: String, target: String).returns(T::Array[String])
306
319
  end
307
320
  def dependency_names_for_type_and_target(parsed_manifest, type, target)
308
321
  names = []
309
- (parsed_manifest.dig("target", target, type) || {}).each do |nm, req|
322
+ target_details = toml_table_or_empty(toml_table_or_empty(parsed_manifest["target"])[target])
323
+ toml_table_or_empty(target_details[type]).each do |nm, req|
324
+ req = dependency_declaration(req)
310
325
  next unless dependency.name == name_from_declaration(nm, req)
311
326
 
312
327
  names << nm
@@ -314,13 +329,63 @@ module Dependabot
314
329
  names
315
330
  end
316
331
 
317
- sig { params(name: String, declaration: T.untyped).returns(String) }
332
+ sig { params(name: String, declaration: T.any(String, T::Hash[String, T.anything])).returns(String) }
318
333
  def name_from_declaration(name, declaration)
319
334
  return name if declaration.is_a?(String)
320
335
 
321
- raise "Unexpected dependency declaration: #{declaration}" unless declaration.is_a?(Hash)
336
+ T.cast(declaration.fetch("package", name), String)
337
+ end
338
+
339
+ sig do
340
+ params(
341
+ parsed_manifest: T::Hash[String, T.anything],
342
+ target: String,
343
+ type: String
344
+ ).returns(T::Hash[String, T.anything])
345
+ end
346
+ def target_dependency_type_table(parsed_manifest, target, type)
347
+ target_details = toml_table_or_empty(toml_table_or_empty(parsed_manifest["target"])[target])
348
+ toml_table_or_empty(target_details[type])
349
+ end
350
+
351
+ sig do
352
+ params(
353
+ parsed_manifest: T::Hash[String, T.anything],
354
+ target: String,
355
+ type: String,
356
+ name: String
357
+ ).returns(T.any(String, T::Hash[String, T.anything]))
358
+ end
359
+ def target_dependency_declaration(parsed_manifest, target, type, name)
360
+ T.cast(
361
+ target_dependency_type_table(parsed_manifest, target, type)[name],
362
+ T.any(String, T::Hash[String, T.anything])
363
+ )
364
+ end
365
+
366
+ sig do
367
+ params(
368
+ parsed_manifest: T::Hash[String, T.anything],
369
+ target: String,
370
+ type: String,
371
+ name: String
372
+ ).returns(T::Hash[String, T.anything])
373
+ end
374
+ def target_dependency_table(parsed_manifest, target, type, name)
375
+ toml_table_or_empty(target_dependency_type_table(parsed_manifest, target, type)[name])
376
+ end
377
+
378
+ sig { params(value: T.anything).returns(T::Hash[String, T.anything]) }
379
+ def toml_table_or_empty(value)
380
+ obj = T.cast(value, T.nilable(Object))
381
+ obj.is_a?(Hash) ? obj : {}
382
+ end
383
+
384
+ sig { params(value: T.anything).returns(T.any(String, T::Hash[String, T.anything])) }
385
+ def dependency_declaration(value)
386
+ return T.cast(value, String) if T.cast(value, T.nilable(Object)).is_a?(String)
322
387
 
323
- declaration.fetch("package", name)
388
+ T.cast(value, T::Hash[String, T.anything])
324
389
  end
325
390
 
326
391
  sig { returns(T::Array[Dependabot::DependencyFile]) }
@@ -36,7 +36,7 @@ module Dependabot
36
36
  sig do
37
37
  params(
38
38
  requirements: T::Array[Dependabot::DependencyRequirement],
39
- updated_source: T.nilable(T::Hash[T.any(String, Symbol), T.untyped]),
39
+ updated_source: T.nilable(T::Hash[T.any(String, Symbol), T.anything]),
40
40
  update_strategy: Dependabot::RequirementsUpdateStrategy,
41
41
  target_version: T.nilable(T.any(String, Gem::Version))
42
42
  ).void
@@ -51,7 +51,7 @@ module Dependabot
51
51
  requirements.map { |req| Dependabot::DependencyRequirement.create(req) },
52
52
  T::Array[Dependabot::DependencyRequirement]
53
53
  )
54
- @updated_source = T.let(updated_source, T.nilable(T::Hash[T.any(String, Symbol), T.untyped]))
54
+ @updated_source = T.let(updated_source, T.nilable(T::Hash[T.any(String, Symbol), T.anything]))
55
55
  @update_strategy = T.let(update_strategy, Dependabot::RequirementsUpdateStrategy)
56
56
 
57
57
  check_update_strategy
@@ -87,7 +87,7 @@ module Dependabot
87
87
  sig { returns(T::Array[Dependabot::DependencyRequirement]) }
88
88
  attr_reader :requirements
89
89
 
90
- sig { returns(T.nilable(T::Hash[T.any(String, Symbol), T.untyped])) }
90
+ sig { returns(T.nilable(T::Hash[T.any(String, Symbol), T.anything])) }
91
91
  attr_reader :updated_source
92
92
 
93
93
  sig { returns(Dependabot::RequirementsUpdateStrategy) }
@@ -311,7 +311,7 @@ module Dependabot
311
311
  latest_resolvable_version
312
312
  end
313
313
 
314
- sig { returns(T.nilable(T::Hash[T.any(String, Symbol), T.untyped])) }
314
+ sig { returns(T.nilable(T::Hash[T.any(String, Symbol), T.anything])) }
315
315
  def updated_source
316
316
  # Never need to update source, unless a git_dependency
317
317
  return dependency_source_details unless git_dependency?
@@ -327,7 +327,7 @@ module Dependabot
327
327
  dependency_source_details
328
328
  end
329
329
 
330
- sig { returns(T.nilable(T::Hash[T.any(String, Symbol), T.untyped])) }
330
+ sig { returns(T.nilable(T::Hash[T.any(String, Symbol), T.anything])) }
331
331
  def dependency_source_details
332
332
  dependency.source_details
333
333
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: dependabot-cargo
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.385.0
4
+ version: 0.386.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Dependabot
@@ -15,14 +15,14 @@ dependencies:
15
15
  requirements:
16
16
  - - '='
17
17
  - !ruby/object:Gem::Version
18
- version: 0.385.0
18
+ version: 0.386.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.385.0
25
+ version: 0.386.0
26
26
  - !ruby/object:Gem::Dependency
27
27
  name: debug
28
28
  requirement: !ruby/object:Gem::Requirement
@@ -266,7 +266,7 @@ licenses:
266
266
  - MIT
267
267
  metadata:
268
268
  bug_tracker_uri: https://github.com/dependabot/dependabot-core/issues
269
- changelog_uri: https://github.com/dependabot/dependabot-core/releases/tag/v0.385.0
269
+ changelog_uri: https://github.com/dependabot/dependabot-core/releases/tag/v0.386.0
270
270
  rdoc_options: []
271
271
  require_paths:
272
272
  - lib