dependabot-cargo 0.384.0 → 0.385.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: ce6cbf95fb2a0787ae301e7c335ee65cc944996b5219eaba62874cdff315ffe4
4
- data.tar.gz: 7b359e82973b40e2fc92e2c53e8c7eb9928ba1bded71a1e283849b4d91f7ffc5
3
+ metadata.gz: fe49d45601f5fe58da2ee6fad020f1edb4db50a2d9f2f2d47d1b0348cde16ff8
4
+ data.tar.gz: b01be9ba87a3a0a452e5e24fc8c8809c29342b119ba1de6477de77cedf6de58b
5
5
  SHA512:
6
- metadata.gz: cee18fdefcd2ec3d06a882b08ab5f19da946e83eb38133e3a94273078baf2a460514a8e7e65281ae4d193a3643920e44f23eca9b3b4cddfef6a66ca174b730d1
7
- data.tar.gz: 1dbadf2bbad402e5862d30e81e89e4add62dce33e7e59661d9330d55b49a8b390db34a96b26c205a346e7a56e3ff643c1ed2095714033904c5dde157a176ab54
6
+ metadata.gz: d14c302e2b6ac9b4b209dd5bc21d14f2062bf04220369c7f79a56c4affc6d5fdb2fd48042045c06a354c7c7c4a418db1130fc9e77eeb90adb8745d39eb94d896
7
+ data.tar.gz: 1f64b3f3937048eda866e9f9bb0b137803dc9174cf86574ea6556479e9e24779e3066c7fbf348e8d8b616f403974db53f13b9d0124ee0b814e10a921b63a652f
@@ -47,7 +47,7 @@ module Dependabot
47
47
  def fetch_files
48
48
  fetched_files = T.let([cargo_toml], T::Array[DependencyFile])
49
49
  fetched_files << T.must(cargo_lock) if cargo_lock
50
- fetched_files << T.must(cargo_config) if cargo_config
50
+ fetched_files.concat(cargo_configs)
51
51
  fetched_files << T.must(rust_toolchain) if rust_toolchain
52
52
  fetched_files += fetch_path_dependency_and_workspace_files
53
53
  parsed_manifest = parsed_file(cargo_toml)
@@ -428,19 +428,53 @@ module Dependabot
428
428
  @cargo_lock ||= T.let(fetch_file_if_present("Cargo.lock"), T.nilable(Dependabot::DependencyFile))
429
429
  end
430
430
 
431
+ # Cargo merges configuration hierarchically: it reads `.cargo/config.toml`
432
+ # from the package directory *and* every ancestor directory up to the repo
433
+ # root, combining them. We therefore collect all of them so that registries
434
+ # (and other settings) defined higher up the tree are not dropped.
435
+ #
436
+ # The package-directory config keeps the canonical name `.cargo/config.toml`
437
+ # (single-config consumers rely on this). Ancestor configs keep their
438
+ # relative `../` paths so they are written to the correct location and can
439
+ # be merged by Cargo. When the package directory has no config of its own,
440
+ # the nearest ancestor is promoted to the canonical name to preserve the
441
+ # historical behaviour that downstream consumers depend on.
442
+ sig { returns(T::Array[Dependabot::DependencyFile]) }
443
+ def cargo_configs
444
+ return T.must(@cargo_configs) if defined?(@cargo_configs)
445
+
446
+ configs = T.let([], T::Array[Dependabot::DependencyFile])
447
+ local = local_cargo_config
448
+ parents = parent_dir_cargo_configs
449
+
450
+ if local
451
+ configs << local
452
+ configs.concat(parents)
453
+ elsif parents.any?
454
+ effective = T.must(parents.first)
455
+ effective.name = ".cargo/config.toml"
456
+ configs << effective
457
+ configs.concat(parents.drop(1))
458
+ end
459
+
460
+ @cargo_configs = T.let(configs, T.nilable(T::Array[Dependabot::DependencyFile]))
461
+ configs
462
+ end
463
+
431
464
  sig { returns(T.nilable(Dependabot::DependencyFile)) }
432
465
  def cargo_config
433
- return @cargo_config if defined?(@cargo_config)
466
+ cargo_configs.find { |f| f.name == ".cargo/config.toml" }
467
+ end
468
+
469
+ sig { returns(T.nilable(Dependabot::DependencyFile)) }
470
+ def local_cargo_config
471
+ return @local_cargo_config if defined?(@local_cargo_config)
434
472
 
435
- @cargo_config = fetch_support_file(".cargo/config.toml")
436
- @cargo_config ||= T.let(
473
+ @local_cargo_config = fetch_support_file(".cargo/config.toml")
474
+ @local_cargo_config ||= T.let(
437
475
  fetch_support_file(".cargo/config")&.tap { |f| f.name = ".cargo/config.toml" },
438
476
  T.nilable(Dependabot::DependencyFile)
439
477
  )
440
- @cargo_config ||= T.let(
441
- fetch_cargo_config_from_parent_dirs,
442
- T.nilable(Dependabot::DependencyFile)
443
- )
444
478
  end
445
479
 
446
480
  sig { returns(T.nilable(Dependabot::DependencyFile)) }
@@ -470,22 +504,26 @@ module Dependabot
470
504
  super.tap { |f| f.name = Pathname.new(f.name).cleanpath.to_s.gsub(%r{^/+}, "") }
471
505
  end
472
506
 
473
- sig { returns(T.nilable(Dependabot::DependencyFile)) }
474
- def fetch_cargo_config_from_parent_dirs
475
- return nil if directory.empty?
507
+ sig { returns(T::Array[Dependabot::DependencyFile]) }
508
+ def parent_dir_cargo_configs
509
+ return T.must(@parent_dir_cargo_configs) if defined?(@parent_dir_cargo_configs)
510
+
511
+ configs = T.let([], T::Array[Dependabot::DependencyFile])
512
+ @parent_dir_cargo_configs = T.let(configs, T.nilable(T::Array[Dependabot::DependencyFile]))
513
+ return configs if directory.empty?
476
514
 
477
515
  # Count directory depth to determine how many levels to search up
478
516
  depth = directory.split("/").count { |s| !s.empty? }
479
- return nil if depth.zero?
517
+ return configs if depth.zero?
480
518
 
481
- # Try each parent directory level
519
+ # Collect a config from every ancestor directory that has one, nearest first
482
520
  depth.times do |i|
483
521
  parent_path = ([".."] * (i + 1)).join("/")
484
522
  config = try_fetch_config_at_path(parent_path)
485
- return config if config
523
+ configs << config if config
486
524
  end
487
525
 
488
- nil
526
+ configs
489
527
  end
490
528
 
491
529
  sig { params(parent_path: String).returns(T.nilable(Dependabot::DependencyFile)) }
@@ -499,7 +537,9 @@ module Dependabot
499
537
  )
500
538
  Dependabot.logger.debug("Successfully fetched config from: #{full_path}")
501
539
  config.support_file = true
502
- config.name = ".cargo/config.toml"
540
+ # Normalise `.cargo/config` to `.cargo/config.toml` while preserving the
541
+ # relative `../` path so the file is written to the right location.
542
+ config.name = Pathname.new(File.join(parent_path, ".cargo/config.toml")).cleanpath.to_s
503
543
  return config
504
544
  rescue Dependabot::DependencyFileNotFound
505
545
  Dependabot.logger.debug("No config found at: #{full_path}")
@@ -332,10 +332,15 @@ module Dependabot
332
332
 
333
333
  sig { params(key_name: String).returns(T.nilable(String)) }
334
334
  def cargo_config_from_file(key_name)
335
- config_file = cargo_config
336
- return nil unless config_file
335
+ # Cargo merges `.cargo/config.toml` hierarchically, with nearer configs
336
+ # taking precedence over ancestors. Search the package-directory config
337
+ # first, then each ancestor config, returning the first match.
338
+ cargo_config_files.each do |config_file|
339
+ value = parsed_file(config_file).dig(*key_name.split("."))
340
+ return value if value
341
+ end
337
342
 
338
- parsed_file(config_file).dig(*key_name.split("."))
343
+ nil
339
344
  end
340
345
 
341
346
  sig { params(name: String, declaration: T.any(String, T::Hash[String, String])).returns(T.nilable(String)) }
@@ -422,9 +427,18 @@ module Dependabot
422
427
  @lockfile ||= T.let(get_original_file("Cargo.lock"), T.nilable(Dependabot::DependencyFile))
423
428
  end
424
429
 
425
- sig { returns(T.nilable(Dependabot::DependencyFile)) }
426
- def cargo_config
427
- @cargo_config ||= T.let(get_original_file(".cargo/config.toml"), T.nilable(Dependabot::DependencyFile))
430
+ # All `.cargo/config.toml` files in the fetched set, ordered nearest-first
431
+ # (package directory config, then successive ancestors). Ancestor configs
432
+ # carry relative `../` names, so we order by `../` depth to reflect Cargo's
433
+ # nearest-wins precedence.
434
+ sig { returns(T::Array[Dependabot::DependencyFile]) }
435
+ def cargo_config_files
436
+ @cargo_config_files ||= T.let(
437
+ dependency_files
438
+ .select { |f| f.name.end_with?(".cargo/config.toml") }
439
+ .sort_by { |f| f.name.scan("../").count },
440
+ T.nilable(T::Array[Dependabot::DependencyFile])
441
+ )
428
442
  end
429
443
 
430
444
  sig { returns(T.class_of(Dependabot::Version)) }
@@ -41,7 +41,7 @@ module Dependabot
41
41
  @path_dependency_files = T.let(nil, T.nilable(T::Array[Dependabot::DependencyFile]))
42
42
  @lockfile = T.let(nil, T.nilable(Dependabot::DependencyFile))
43
43
  @toolchain = T.let(nil, T.nilable(Dependabot::DependencyFile))
44
- @config = T.let(nil, T.nilable(Dependabot::DependencyFile))
44
+ @config_files = T.let(nil, T.nilable(T::Array[Dependabot::DependencyFile]))
45
45
  end
46
46
 
47
47
  sig { returns(T.any(String, T.noreturn)) }
@@ -305,11 +305,13 @@ module Dependabot
305
305
 
306
306
  File.write(lockfile.name, replace_ssh_urls(T.must(lockfile.content)))
307
307
  File.write(T.must(toolchain).name, T.must(toolchain).content) if toolchain
308
- config_file = config
309
- return unless config_file
310
-
311
- FileUtils.mkdir_p(File.dirname(config_file.name))
312
- File.write(config_file.name, Helpers.sanitize_cargo_config(T.must(config_file.content)))
308
+ config_files.each do |config_file|
309
+ FileUtils.mkdir_p(File.dirname(config_file.name))
310
+ File.write(
311
+ config_file.name,
312
+ Helpers.sanitize_cargo_config(T.must(config_file.content), file_name: config_file.name)
313
+ )
314
+ end
313
315
  end
314
316
 
315
317
  sig { void }
@@ -537,9 +539,12 @@ module Dependabot
537
539
  dependency_files.find { |f| f.name == "rust-toolchain" }
538
540
  end
539
541
 
540
- sig { returns(T.nilable(Dependabot::DependencyFile)) }
541
- def config
542
- @config ||= dependency_files.find { |f| f.name == ".cargo/config.toml" }
542
+ # Cargo merges `.cargo/config.toml` hierarchically (package directory plus
543
+ # every ancestor up to the repo root), so we materialise all of them and
544
+ # let Cargo perform the merge with its own precedence rules.
545
+ sig { returns(T::Array[Dependabot::DependencyFile]) }
546
+ def config_files
547
+ @config_files ||= dependency_files.select { |f| f.name.end_with?(".cargo/config.toml") }
543
548
  end
544
549
 
545
550
  sig { params(file: Dependabot::DependencyFile).returns(T::Boolean) }
@@ -19,8 +19,8 @@ module Dependabot
19
19
  # These per-registry settings override the global CARGO_REGISTRY_GLOBAL_CREDENTIAL_PROVIDERS env var,
20
20
  # causing Cargo to look up tokens locally. Since the dependabot proxy handles all registry authentication
21
21
  # transparently, we remove these so Cargo makes plain unauthenticated requests that the proxy can intercept.
22
- sig { params(config_content: String).returns(String) }
23
- def self.sanitize_cargo_config(config_content)
22
+ sig { params(config_content: String, file_name: String).returns(String) }
23
+ def self.sanitize_cargo_config(config_content, file_name: ".cargo/config.toml")
24
24
  parsed = TomlRB.parse(config_content)
25
25
  return config_content unless parsed.is_a?(Hash)
26
26
 
@@ -40,7 +40,7 @@ module Dependabot
40
40
  TomlRB.dump(parsed)
41
41
  rescue TomlRB::Error => e
42
42
  raise Dependabot::DependencyFileNotParseable.new(
43
- ".cargo/config.toml",
43
+ file_name,
44
44
  "Failed to parse Cargo config file: #{e.message}"
45
45
  )
46
46
  end
@@ -109,10 +109,17 @@ module Dependabot
109
109
  ).returns(T::Hash[String, String])
110
110
  end
111
111
  def self.registry_token_env_from_files(dependency_files, credentials)
112
- config_file = dependency_files.find { |f| f.name == ".cargo/config.toml" }
113
- return {} unless config_file
114
-
115
- registry_token_env(T.must(config_file.content), credentials)
112
+ config_files = dependency_files.select { |f| f.name.end_with?(".cargo/config.toml") }
113
+ return {} if config_files.empty?
114
+
115
+ # Cargo gives nearer configs precedence over ancestors on key collisions.
116
+ # A config's `../` depth (how many parent hops appear in its name)
117
+ # indicates how far up the tree it lives, so merge farthest-first and let
118
+ # the nearest config (fewest `../`) win.
119
+ ordered = config_files.sort_by { |f| -f.name.scan("../").count }
120
+ ordered.each_with_object({}) do |config_file, env|
121
+ env.merge!(registry_token_env(T.must(config_file.content), credentials))
122
+ end
116
123
  end
117
124
 
118
125
  # Builds the complete environment variable hash for running cargo commands:
@@ -207,17 +207,19 @@ module Dependabot
207
207
  )
208
208
  end
209
209
 
210
- sig { params(prepared: T::Boolean).returns(T.nilable(Integer)) }
210
+ sig { params(prepared: T::Boolean).void }
211
211
  def write_temporary_dependency_files(prepared: true)
212
212
  write_manifest_files(prepared: prepared)
213
213
 
214
214
  File.write(T.must(lockfile).name, T.must(lockfile).content) if lockfile
215
215
  File.write(T.must(toolchain).name, T.must(toolchain).content) if toolchain
216
- config_file = config
217
- return unless config_file
218
-
219
- FileUtils.mkdir_p(File.dirname(config_file.name))
220
- File.write(config_file.name, Helpers.sanitize_cargo_config(T.must(config_file.content)))
216
+ config_files.each do |config_file|
217
+ FileUtils.mkdir_p(File.dirname(config_file.name))
218
+ File.write(
219
+ config_file.name,
220
+ Helpers.sanitize_cargo_config(T.must(config_file.content), file_name: config_file.name)
221
+ )
222
+ end
221
223
  end
222
224
 
223
225
  sig { void }
@@ -554,13 +556,18 @@ module Dependabot
554
556
  )
555
557
  end
556
558
 
557
- sig { returns(T.nilable(DependencyFile)) }
558
- def config
559
- @config ||= T.let(
560
- original_dependency_files.find do |f|
561
- f.name == ".cargo/config.toml"
559
+ # Cargo merges `.cargo/config.toml` hierarchically (package directory plus
560
+ # every ancestor up to the repo root), so we materialise all of them and
561
+ # let Cargo perform the merge with its own precedence rules. Ancestor
562
+ # configs carry relative `../` names and are written to the matching
563
+ # location within the temporary tree.
564
+ sig { returns(T::Array[Dependabot::DependencyFile]) }
565
+ def config_files
566
+ @config_files ||= T.let(
567
+ original_dependency_files.select do |f|
568
+ f.name.end_with?(".cargo/config.toml")
562
569
  end,
563
- T.nilable(Dependabot::DependencyFile)
570
+ T.nilable(T::Array[Dependabot::DependencyFile])
564
571
  )
565
572
  end
566
573
 
@@ -178,7 +178,7 @@ module Dependabot
178
178
  # we want to update that tag. The latest version will then be the SHA
179
179
  # of the latest tag that looks like a version.
180
180
  if git_commit_checker.pinned_ref_looks_like_version?
181
- latest_tag = git_commit_checker.local_tag_for_latest_version
181
+ latest_tag = git_commit_checker.local_tag_for_latest_version(update_cooldown)
182
182
  return latest_tag&.fetch(:commit_sha) || dependency.version
183
183
  end
184
184
 
@@ -198,7 +198,7 @@ module Dependabot
198
198
  # of the latest tag that looks like a version.
199
199
  if git_commit_checker.pinned_ref_looks_like_version? &&
200
200
  latest_git_tag_is_resolvable?
201
- new_tag = git_commit_checker.local_tag_for_latest_version
201
+ new_tag = git_commit_checker.local_tag_for_latest_version(update_cooldown)
202
202
  return T.must(new_tag).fetch(:commit_sha)
203
203
  end
204
204
 
@@ -220,9 +220,9 @@ module Dependabot
220
220
 
221
221
  @latest_git_tag_is_resolvable_checked = true
222
222
 
223
- return false if git_commit_checker.local_tag_for_latest_version.nil?
223
+ return false if git_commit_checker.local_tag_for_latest_version(update_cooldown).nil?
224
224
 
225
- replacement_tag = T.must(git_commit_checker.local_tag_for_latest_version)
225
+ replacement_tag = T.must(git_commit_checker.local_tag_for_latest_version(update_cooldown))
226
226
 
227
227
  prepared_files = FilePreparer.new(
228
228
  dependency_files: dependency_files,
@@ -319,7 +319,7 @@ module Dependabot
319
319
  # Update the git tag if updating a pinned version
320
320
  if git_commit_checker.pinned_ref_looks_like_version? &&
321
321
  latest_git_tag_is_resolvable?
322
- new_tag = T.must(git_commit_checker.local_tag_for_latest_version)
322
+ new_tag = T.must(git_commit_checker.local_tag_for_latest_version(update_cooldown))
323
323
  return T.must(dependency_source_details).merge(ref: new_tag.fetch(:tag))
324
324
  end
325
325
 
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.384.0
4
+ version: 0.385.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.384.0
18
+ version: 0.385.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.384.0
25
+ version: 0.385.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.384.0
269
+ changelog_uri: https://github.com/dependabot/dependabot-core/releases/tag/v0.385.0
270
270
  rdoc_options: []
271
271
  require_paths:
272
272
  - lib