Module: Dependabot::Cargo::Helpers

Extended by:
T::Sig
Defined in:
lib/dependabot/cargo/helpers.rb

Class Method Summary collapse

Class Method Details

.cargo_command_env(dependency_files, credentials) ⇒ Object



128
129
130
131
132
133
134
135
136
137
138
# File 'lib/dependabot/cargo/helpers.rb', line 128

def self.cargo_command_env(dependency_files, credentials)
  ENV["CARGO_REGISTRY_GLOBAL_CREDENTIAL_PROVIDERS"] ||= ""
  return {} unless ENV.fetch("DEPENDABOT", nil) == "true"
  return {} unless Dependabot::Experiments.enabled?(:cargo_set_registry_token_auth)

  env = registry_token_env_from_files(dependency_files, credentials)
  Dependabot.logger.info("Setting registry token env vars: #{env.keys.join(', ')}") unless env.empty?
  env.merge!(ENV.select { |key, _value| key.match(/^CARGO_REGISTR(Y|IES)_/) })
  env["CARGO_REGISTRY_GLOBAL_CREDENTIAL_PROVIDERS"] = "cargo:token"
  env
end

.custom_registry_names(config_content, credentials) ⇒ Object



51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
# File 'lib/dependabot/cargo/helpers.rb', line 51

def self.custom_registry_names(config_content, credentials)
  parsed = TomlRB.parse(config_content)
  registries = parsed["registries"]
  return [] unless registries.is_a?(Hash)

  credential_hosts = credentials.filter_map { |cred| cred["host"] }.to_set
  credential_urls = credentials.filter_map { |cred| cred["url"]&.delete_suffix("/") }.to_set

  registries.select do |_name, config|
    config.is_a?(Hash) && registry_index_matches?(config, credential_hosts, credential_urls)
  end.keys
rescue TomlRB::Error, URI::InvalidURIError => e
  Dependabot.logger.warn("Failed to parse cargo config for registry names: #{e.message}")
  []
end

.registry_index_matches?(config, credential_hosts, credential_urls) ⇒ Boolean

Returns:

  • (Boolean)


74
75
76
77
78
79
80
81
82
83
84
# File 'lib/dependabot/cargo/helpers.rb', line 74

def self.registry_index_matches?(config, credential_hosts, credential_urls)
  index = config["index"]
  return false unless index.is_a?(String)

  # Index URLs may have a scheme prefix like "sparse+" before the actual URL
  url = index.sub(/^[a-z]+\+/, "")
  host = URI.parse(url).host

  (host && credential_hosts.include?(host)) ||
    credential_urls.include?(url.delete_suffix("/"))
end

.registry_token_env(config_content, credentials) ⇒ Object



93
94
95
96
97
98
99
100
101
# File 'lib/dependabot/cargo/helpers.rb', line 93

def self.registry_token_env(config_content, credentials)
  registry_names = custom_registry_names(config_content, credentials)
  return {} if registry_names.empty?

  registry_names.each_with_object({}) do |name, hash|
    key = "CARGO_REGISTRIES_#{name.upcase.tr('-', '_')}_TOKEN"
    hash[key] = "garbage_token"
  end
end

.registry_token_env_from_files(dependency_files, credentials) ⇒ Object



111
112
113
114
115
116
# File 'lib/dependabot/cargo/helpers.rb', line 111

def self.registry_token_env_from_files(dependency_files, credentials)
  config_file = dependency_files.find { |f| f.name == ".cargo/config.toml" }
  return {} unless config_file

  registry_token_env(T.must(config_file.content), credentials)
end

.sanitize_cargo_config(config_content) ⇒ Object



23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
# File 'lib/dependabot/cargo/helpers.rb', line 23

def self.sanitize_cargo_config(config_content)
  parsed = TomlRB.parse(config_content)
  return config_content unless parsed.is_a?(Hash)

  registries = parsed["registries"]
  if registries.is_a?(Hash)
    registries.each_value do |registry_config|
      registry_config.delete("credential-provider") if registry_config.is_a?(Hash)
    end
  end

  # Also strip credential-provider from [registry] (crates.io default registry). Users who `cargo publish`
  # from CI may have this set. It's a per-registry override that takes precedence over the global env var,
  # so we need to remove it to prevent Cargo from trying to look up a token.
  registry = parsed["registry"]
  registry.delete("credential-provider") if registry.is_a?(Hash)

  TomlRB.dump(parsed)
rescue TomlRB::Error => e
  raise Dependabot::DependencyFileNotParseable.new(
    ".cargo/config.toml",
    "Failed to parse Cargo config file: #{e.message}"
  )
end