class Dependabot::Python::UpdateChecker::IndexFinder

Constants

ENVIRONMENT_VARIABLE_REGEX
PYPI_BASE_URL

Attributes

credentials[R]
dependency_files[R]

Public Class Methods

new(dependency_files:, credentials:) click to toggle source
# File lib/dependabot/python/update_checker/index_finder.rb, line 14
def initialize(dependency_files:, credentials:)
  @dependency_files = dependency_files
  @credentials      = credentials
end

Public Instance Methods

index_urls() click to toggle source
# File lib/dependabot/python/update_checker/index_finder.rb, line 19
def index_urls
  extra_index_urls =
    config_variable_index_urls[:extra] +
    pipfile_index_urls[:extra] +
    requirement_file_index_urls[:extra] +
    pip_conf_index_urls[:extra] +
    pyproject_index_urls[:extra]

  extra_index_urls = extra_index_urls.map do |url|
    clean_check_and_remove_environment_variables(url)
  end

  # URL encode any `@` characters within registry URL creds.
  # TODO: The test that fails if the `map` here is removed is likely a
  # bug in Ruby's URI parser, and should be fixed there.
  [main_index_url, *extra_index_urls].map do |url|
    url.rpartition("@").tap { |a| a.first.gsub!("@", "%40") }.join
  end.uniq
end

Private Instance Methods

authed_base_url(base_url) click to toggle source
# File lib/dependabot/python/update_checker/index_finder.rb, line 180
def authed_base_url(base_url)
  cred = credential_for(base_url)
  return base_url unless cred

  AuthedUrlBuilder.authed_url(credential: cred).gsub(%r{/*$}, "") + "/"
end
clean_check_and_remove_environment_variables(url) click to toggle source
# File lib/dependabot/python/update_checker/index_finder.rb, line 152
def clean_check_and_remove_environment_variables(url)
  url = url.strip.gsub(%r{/*$}, "") + "/"

  return authed_base_url(url) unless url.match?(ENVIRONMENT_VARIABLE_REGEX)

  config_variable_urls =
    [
      config_variable_index_urls[:main],
      *config_variable_index_urls[:extra]
    ].
    compact.
    map { |u| u.strip.gsub(%r{/*$}, "") + "/" }

  regexp = url.
           sub(%r{(?<=://).+@}, "").
           split(ENVIRONMENT_VARIABLE_REGEX).
           map { |part| Regexp.quote(part) }.
           join(".+")
  authed_url = config_variable_urls.find { |u| u.match?(regexp) }
  return authed_url if authed_url

  cleaned_url = url.gsub(%r{#{ENVIRONMENT_VARIABLE_REGEX}/?}, "")
  authed_url = authed_base_url(cleaned_url)
  return authed_url if credential_for(cleaned_url)

  raise PrivateSourceAuthenticationFailure, url
end
config_variable_index_urls() click to toggle source
# File lib/dependabot/python/update_checker/index_finder.rb, line 134
def config_variable_index_urls
  urls = { main: nil, extra: [] }

  index_url_creds = credentials.
                    select { |cred| cred["type"] == "python_index" }

  if (main_cred = index_url_creds.find { |cred| cred["replaces-base"] })
    urls[:main] = AuthedUrlBuilder.authed_url(credential: main_cred)
  end

  urls[:extra] =
    index_url_creds.
    reject { |cred| cred["replaces-base"] }.
    map { |cred| AuthedUrlBuilder.authed_url(credential: cred) }

  urls
end
credential_for(url) click to toggle source
# File lib/dependabot/python/update_checker/index_finder.rb, line 187
def credential_for(url)
  credentials.
    select { |c| c["type"] == "python_index" }.
    find do |c|
      cred_url = c.fetch("index-url").gsub(%r{/*$}, "") + "/"
      cred_url.include?(url)
    end
end
main_index_url() click to toggle source
# File lib/dependabot/python/update_checker/index_finder.rb, line 43
def main_index_url
  url =
    config_variable_index_urls[:main] ||
    pipfile_index_urls[:main] ||
    requirement_file_index_urls[:main] ||
    pip_conf_index_urls[:main] ||
    pyproject_index_urls[:main] ||
    PYPI_BASE_URL

  return unless url

  clean_check_and_remove_environment_variables(url)
end
pip_compile_files() click to toggle source
# File lib/dependabot/python/update_checker/index_finder.rb, line 212
def pip_compile_files
  dependency_files.select { |f| f.name.end_with?(".in") }
end
pip_conf() click to toggle source
# File lib/dependabot/python/update_checker/index_finder.rb, line 196
def pip_conf
  dependency_files.find { |f| f.name == "pip.conf" }
end
pip_conf_index_urls() click to toggle source
# File lib/dependabot/python/update_checker/index_finder.rb, line 76
def pip_conf_index_urls
  urls = { main: nil, extra: [] }

  return urls unless pip_conf

  content = pip_conf.content

  if content.match?(/^index-url\s*=/x)
    urls[:main] = content.match(/^index-url\s*=\s*(.+)/).
                  captures.first
  end
  urls[:extra] += content.scan(/^extra-index-url\s*=(.+)/).flatten

  urls
end
pipfile() click to toggle source
# File lib/dependabot/python/update_checker/index_finder.rb, line 200
def pipfile
  dependency_files.find { |f| f.name == "Pipfile" }
end
pipfile_index_urls() click to toggle source
# File lib/dependabot/python/update_checker/index_finder.rb, line 92
def pipfile_index_urls
  urls = { main: nil, extra: [] }

  return urls unless pipfile

  pipfile_object = TomlRB.parse(pipfile.content)

  urls[:main] = pipfile_object["source"]&.first&.fetch("url", nil)

  pipfile_object["source"]&.each do |source|
    urls[:extra] << source.fetch("url") if source["url"]
  end
  urls[:extra] = urls[:extra].uniq

  urls
rescue TomlRB::ParseError, TomlRB::ValueOverwriteError
  urls
end
pyproject() click to toggle source
# File lib/dependabot/python/update_checker/index_finder.rb, line 204
def pyproject
  dependency_files.find { |f| f.name == "pyproject.toml" }
end
pyproject_index_urls() click to toggle source
# File lib/dependabot/python/update_checker/index_finder.rb, line 111
def pyproject_index_urls
  urls = { main: nil, extra: [] }

  return urls unless pyproject

  sources =
    TomlRB.parse(pyproject.content).dig("tool", "poetry", "source") ||
    []

  sources.each do |source|
    if source["default"]
      urls[:main] = source["url"]
    else
      urls[:extra] << source["url"]
    end
  end
  urls[:extra] = urls[:extra].uniq

  urls
rescue TomlRB::ParseError, TomlRB::ValueOverwriteError
  urls
end
requirement_file_index_urls() click to toggle source
# File lib/dependabot/python/update_checker/index_finder.rb, line 57
def requirement_file_index_urls
  urls = { main: nil, extra: [] }

  requirements_files.each do |file|
    if file.content.match?(/^--index-url\s+['"]?([^\s'"]+)['"]?/)
      urls[:main] =
        file.content.match(/^--index-url\s+['"]?([^\s'"]+)['"]?/).
        captures.first&.strip
    end
    urls[:extra] +=
      file.content.
      scan(/^--extra-index-url\s+['"]?([^\s'"]+)['"]?/).
      flatten.
      map(&:strip)
  end

  urls
end
requirements_files() click to toggle source
# File lib/dependabot/python/update_checker/index_finder.rb, line 208
def requirements_files
  dependency_files.select { |f| f.name.match?(/requirements/x) }
end