dependabot-cargo 0.382.0 → 0.383.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: 51d4f61feae4b16e9007ba3a114ca34893d7232eb3786c88b9333917f064db35
4
- data.tar.gz: 3ce4da7afe9eb34a9adf4db1a1a6e4f8d9cfe7f77e2ea116eae2c05aedca4341
3
+ metadata.gz: 831d75a3d5aca6586046341e260170112f8a7fed6251ac1ce576aecef8fad47e
4
+ data.tar.gz: 7c8249256489d87075843aac3019f7087212e6d85c0e61fe4427ba0770c1e344
5
5
  SHA512:
6
- metadata.gz: 9c2eec9ce3b6ccea662a43c7576ba823ebde9156e36bcb0a5dc36e06b3da125e2caa7961b329e6bed364675249f8b084127c4b1c53b2a1e00a1b6a163cb9c604
7
- data.tar.gz: 642f355d2a781ef02157dc33fabde13f5fbedca6ff7ec198a6d7b7575d320796b41c837b245f1d448bc0ea9117b1088fb5a4a38f1b7bde42e31d08e3f25da2f1
6
+ metadata.gz: 79460ed1999684cebd656f087c5108a5df3babf70ee7b1a2b69b0fb9b95d599195a4fac2a1c5e61be58c1502573f98e56298fec1dbb4dbd7c4393774c11633c6
7
+ data.tar.gz: aa3392bcabac9f0ff8771a4cf24021165b5234e08654b4929c6afe303363e4a7cdf9f4a393722b7ed4d13d2bd3e69643b623741ade2a7eebd8f46801b22b99c0
@@ -88,7 +88,7 @@ module Dependabot
88
88
  sig { returns(T::Array[Dependabot::DependencyFile]) }
89
89
  attr_reader :dependency_files
90
90
 
91
- sig { returns(T::Array[T.untyped]) }
91
+ sig { returns(T::Array[Dependabot::Credential]) }
92
92
  attr_reader :credentials
93
93
 
94
94
  # Currently, there will only be a single updated dependency
@@ -217,10 +217,7 @@ module Dependabot
217
217
  def run_cargo_command(command, fingerprint:)
218
218
  start = Time.now
219
219
  command = SharedHelpers.escape_command(command)
220
- Helpers.bypass_cargo_credential_providers
221
- # Pass through any cargo registry configuration via environment variables
222
- # (e.g. CARGO_REGISTRIES_CRATES_IO_PROTOCOL, CARGO_REGISTRY_GLOBAL_CREDENTIAL_PROVIDERS).
223
- env = ENV.select { |key, _value| key.match(/^CARGO_REGISTR(Y|IES)_/) }
220
+ env = Helpers.cargo_command_env(dependency_files, credentials)
224
221
  stdout, process = Open3.capture2e(env, command)
225
222
  time_taken = Time.now - start
226
223
 
@@ -1,27 +1,15 @@
1
1
  # typed: strict
2
2
  # frozen_string_literal: true
3
3
 
4
+ require "uri"
4
5
  require "toml-rb"
6
+ require "dependabot/experiments"
5
7
 
6
8
  module Dependabot
7
9
  module Cargo
8
10
  module Helpers
9
11
  extend T::Sig
10
12
 
11
- # Disable Cargo's *global* credential providers so that Cargo does not attempt to look up registry tokens
12
- # on its own. The dependabot proxy (https://github.com/dependabot/proxy/) handles all registry authentication
13
- # transparently by intercepting HTTP requests and injecting the appropriate credentials.
14
- #
15
- # Note: this only affects the global/default credential provider. Per-registry `credential-provider` settings
16
- # in .cargo/config.toml override this env var, so those are stripped separately by `sanitize_cargo_config`.
17
- #
18
- # Uses ||= so developers can override by setting CARGO_REGISTRY_GLOBAL_CREDENTIAL_PROVIDERS=cargo:token in their
19
- # shell (along with the appropriate CARGO_REGISTRIES_{NAME}_TOKEN vars) for local development without the proxy.
20
- sig { void }
21
- def self.bypass_cargo_credential_providers
22
- ENV["CARGO_REGISTRY_GLOBAL_CREDENTIAL_PROVIDERS"] ||= ""
23
- end
24
-
25
13
  # Strip per-registry `credential-provider` settings from .cargo/config.toml.
26
14
  #
27
15
  # Users may have entries like:
@@ -56,6 +44,98 @@ module Dependabot
56
44
  "Failed to parse Cargo config file: #{e.message}"
57
45
  )
58
46
  end
47
+
48
+ # Parses cargo config content and returns the names of custom registries
49
+ # whose index URL matches a credential host or url.
50
+ sig { params(config_content: String, credentials: T::Array[Dependabot::Credential]).returns(T::Array[String]) }
51
+ def self.custom_registry_names(config_content, credentials)
52
+ parsed = TomlRB.parse(config_content)
53
+ registries = parsed["registries"]
54
+ return [] unless registries.is_a?(Hash)
55
+
56
+ credential_hosts = credentials.filter_map { |cred| cred["host"] }.to_set
57
+ credential_urls = credentials.filter_map { |cred| cred["url"]&.delete_suffix("/") }.to_set
58
+
59
+ registries.select do |_name, config|
60
+ config.is_a?(Hash) && registry_index_matches?(config, credential_hosts, credential_urls)
61
+ end.keys
62
+ rescue TomlRB::Error, URI::InvalidURIError => e
63
+ Dependabot.logger.warn("Failed to parse cargo config for registry names: #{e.message}")
64
+ []
65
+ end
66
+
67
+ sig do
68
+ params(
69
+ config: T::Hash[String, String],
70
+ credential_hosts: T::Set[String],
71
+ credential_urls: T::Set[String]
72
+ ).returns(T::Boolean)
73
+ end
74
+ def self.registry_index_matches?(config, credential_hosts, credential_urls)
75
+ index = config["index"]
76
+ return false unless index.is_a?(String)
77
+
78
+ # Index URLs may have a scheme prefix like "sparse+" before the actual URL
79
+ url = index.sub(/^[a-z]+\+/, "")
80
+ host = URI.parse(url).host
81
+
82
+ (host && credential_hosts.include?(host)) ||
83
+ credential_urls.include?(url.delete_suffix("/"))
84
+ end
85
+
86
+ # Builds a hash of environment variables for Cargo registry token auth.
87
+ # Returns env vars like CARGO_REGISTRIES_<NAME>_TOKEN=garbage_token for each
88
+ # matched registry, plus CARGO_REGISTRY_GLOBAL_CREDENTIAL_PROVIDERS=cargo:token.
89
+ sig do
90
+ params(config_content: String, credentials: T::Array[Dependabot::Credential])
91
+ .returns(T::Hash[String, String])
92
+ end
93
+ def self.registry_token_env(config_content, credentials)
94
+ registry_names = custom_registry_names(config_content, credentials)
95
+ return {} if registry_names.empty?
96
+
97
+ registry_names.each_with_object({}) do |name, hash|
98
+ key = "CARGO_REGISTRIES_#{name.upcase.tr('-', '_')}_TOKEN"
99
+ hash[key] = "garbage_token"
100
+ end
101
+ end
102
+
103
+ # Convenience method: extracts .cargo/config.toml from dependency files and
104
+ # builds registry token env vars. Returns an empty hash if no config file exists.
105
+ sig do
106
+ params(
107
+ dependency_files: T::Array[Dependabot::DependencyFile],
108
+ credentials: T::Array[Dependabot::Credential]
109
+ ).returns(T::Hash[String, String])
110
+ end
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)
116
+ end
117
+
118
+ # Builds the complete environment variable hash for running cargo commands:
119
+ # 1. Sets CARGO_REGISTRIES_<NAME>_TOKEN for each matched custom registry
120
+ # 2. Merges real CARGO_REGISTR(Y|IES)_* vars from the process environment
121
+ # 3. Sets CARGO_REGISTRY_GLOBAL_CREDENTIAL_PROVIDERS=cargo:token
122
+ sig do
123
+ params(
124
+ dependency_files: T::Array[Dependabot::DependencyFile],
125
+ credentials: T::Array[Dependabot::Credential]
126
+ ).returns(T::Hash[String, String])
127
+ end
128
+ def self.cargo_command_env(dependency_files, credentials)
129
+ ENV["CARGO_REGISTRY_GLOBAL_CREDENTIAL_PROVIDERS"] ||= ""
130
+ return {} unless ENV.fetch("DEPENDABOT", nil) == "true"
131
+ return {} unless Dependabot::Experiments.enabled?(:cargo_set_registry_token_auth)
132
+
133
+ env = registry_token_env_from_files(dependency_files, credentials)
134
+ Dependabot.logger.info("Setting registry token env vars: #{env.keys.join(', ')}") unless env.empty?
135
+ env.merge!(ENV.select { |key, _value| key.match(/^CARGO_REGISTR(Y|IES)_/) })
136
+ env["CARGO_REGISTRY_GLOBAL_CREDENTIAL_PROVIDERS"] = "cargo:token"
137
+ env
138
+ end
59
139
  end
60
140
  end
61
141
  end
@@ -12,6 +12,7 @@ require "sorbet-runtime"
12
12
  require "dependabot/cargo/update_checker"
13
13
  require "dependabot/cargo/requirement"
14
14
  require "dependabot/cargo/version"
15
+ require "dependabot/dependency_requirement"
15
16
  require "dependabot/requirements_update_strategy"
16
17
 
17
18
  module Dependabot
@@ -34,7 +35,7 @@ module Dependabot
34
35
 
35
36
  sig do
36
37
  params(
37
- requirements: T::Array[T::Hash[Symbol, T.untyped]],
38
+ requirements: T::Array[Dependabot::DependencyRequirement],
38
39
  updated_source: T.nilable(T::Hash[T.any(String, Symbol), T.untyped]),
39
40
  update_strategy: Dependabot::RequirementsUpdateStrategy,
40
41
  target_version: T.nilable(T.any(String, Gem::Version))
@@ -46,7 +47,10 @@ module Dependabot
46
47
  update_strategy:,
47
48
  target_version:
48
49
  )
49
- @requirements = T.let(requirements, T::Array[T::Hash[Symbol, T.untyped]])
50
+ @requirements = T.let(
51
+ requirements.map { |req| Dependabot::DependencyRequirement.create(req) },
52
+ T::Array[Dependabot::DependencyRequirement]
53
+ )
50
54
  @updated_source = T.let(updated_source, T.nilable(T::Hash[T.any(String, Symbol), T.untyped]))
51
55
  @update_strategy = T.let(update_strategy, Dependabot::RequirementsUpdateStrategy)
52
56
 
@@ -57,7 +61,7 @@ module Dependabot
57
61
  @target_version = T.let(version_class.new(target_version), Gem::Version)
58
62
  end
59
63
 
60
- sig { returns(T::Array[T::Hash[Symbol, T.untyped]]) }
64
+ sig { returns(T::Array[Dependabot::DependencyRequirement]) }
61
65
  def updated_requirements
62
66
  return requirements if update_strategy.lockfile_only?
63
67
 
@@ -65,7 +69,7 @@ module Dependabot
65
69
  # requirement at index `i` to correspond to the previous requirement
66
70
  # at the same index.
67
71
  requirements.map do |req|
68
- req = req.merge(source: updated_source)
72
+ req = Dependabot::DependencyRequirement.create(req.merge(source: updated_source))
69
73
  next req unless target_version
70
74
  next req if req[:requirement].nil?
71
75
 
@@ -80,7 +84,7 @@ module Dependabot
80
84
 
81
85
  private
82
86
 
83
- sig { returns(T::Array[T::Hash[Symbol, T.untyped]]) }
87
+ sig { returns(T::Array[Dependabot::DependencyRequirement]) }
84
88
  attr_reader :requirements
85
89
 
86
90
  sig { returns(T.nilable(T::Hash[T.any(String, Symbol), T.untyped])) }
@@ -99,7 +103,7 @@ module Dependabot
99
103
  raise "Unknown update strategy: #{update_strategy}"
100
104
  end
101
105
 
102
- sig { params(req: T::Hash[Symbol, T.untyped]).returns(T::Hash[Symbol, T.untyped]) }
106
+ sig { params(req: Dependabot::DependencyRequirement).returns(Dependabot::DependencyRequirement) }
103
107
  def update_version_requirement(req)
104
108
  string_reqs = req[:requirement].split(",").map(&:strip)
105
109
 
@@ -119,10 +123,10 @@ module Dependabot
119
123
  update_range_requirements(string_reqs)
120
124
  end
121
125
 
122
- req.merge(requirement: new_requirement)
126
+ Dependabot::DependencyRequirement.create(req.merge(requirement: new_requirement))
123
127
  end
124
128
 
125
- sig { params(req: T::Hash[Symbol, T.untyped]).returns(T::Hash[Symbol, T.untyped]) }
129
+ sig { params(req: Dependabot::DependencyRequirement).returns(Dependabot::DependencyRequirement) }
126
130
  def update_version_requirement_if_needed(req)
127
131
  string_reqs = req[:requirement].split(",").map(&:strip)
128
132
  ruby_reqs = string_reqs.map { |r| Dependabot::Cargo::Requirement.new(r) }
@@ -187,10 +187,7 @@ module Dependabot
187
187
  def run_cargo_command(command, fingerprint: nil)
188
188
  start = Time.now
189
189
  command = SharedHelpers.escape_command(command)
190
- Helpers.bypass_cargo_credential_providers
191
- # Pass through any cargo registry configuration via environment variables
192
- # (e.g. CARGO_REGISTRIES_CRATES_IO_PROTOCOL, CARGO_REGISTRY_GLOBAL_CREDENTIAL_PROVIDERS).
193
- env = ENV.select { |key, _value| key.match(/^CARGO_REGISTR(Y|IES)_/) }
190
+ env = Helpers.cargo_command_env(original_dependency_files, credentials)
194
191
 
195
192
  stdout, process = Open3.capture2e(env, command)
196
193
  time_taken = Time.now - start
@@ -90,14 +90,12 @@ module Dependabot
90
90
 
91
91
  sig { override.returns(T::Array[Dependabot::DependencyRequirement]) }
92
92
  def updated_requirements
93
- wrap_requirements(
94
- RequirementsUpdater.new(
95
- requirements: dependency.requirements,
96
- updated_source: updated_source,
97
- target_version: target_version,
98
- update_strategy: requirements_update_strategy
99
- ).updated_requirements
100
- )
93
+ RequirementsUpdater.new(
94
+ requirements: dependency.requirements,
95
+ updated_source: updated_source,
96
+ target_version: target_version,
97
+ update_strategy: requirements_update_strategy
98
+ ).updated_requirements
101
99
  end
102
100
 
103
101
  sig { override.returns(T::Boolean) }
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.382.0
4
+ version: 0.383.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.382.0
18
+ version: 0.383.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.382.0
25
+ version: 0.383.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.382.0
269
+ changelog_uri: https://github.com/dependabot/dependabot-core/releases/tag/v0.383.0
270
270
  rdoc_options: []
271
271
  require_paths:
272
272
  - lib