class Dependabot::Gradle::UpdateChecker::VersionFinder

Constants

GOOGLE_MAVEN_REPO
GRADLE_PLUGINS_REPO
KOTLIN_PLUGIN_REPO_PREFIX
TYPE_SUFFICES

Attributes

credentials[R]
dependency[R]
dependency_files[R]
forbidden_urls[R]
ignored_versions[R]
security_advisories[R]

Public Class Methods

new(dependency:, dependency_files:, credentials:, ignored_versions:, raise_on_ignored: false, security_advisories:) click to toggle source
# File lib/dependabot/gradle/update_checker/version_finder.rb, line 21
def initialize(dependency:, dependency_files:, credentials:,
               ignored_versions:, raise_on_ignored: false,
               security_advisories:)
  @dependency          = dependency
  @dependency_files    = dependency_files
  @credentials         = credentials
  @ignored_versions    = ignored_versions
  @raise_on_ignored    = raise_on_ignored
  @security_advisories = security_advisories
  @forbidden_urls      = []
end

Public Instance Methods

latest_version_details() click to toggle source
# File lib/dependabot/gradle/update_checker/version_finder.rb, line 33
def latest_version_details
  possible_versions = versions

  possible_versions = filter_prereleases(possible_versions)
  possible_versions = filter_date_based_versions(possible_versions)
  possible_versions = filter_version_types(possible_versions)
  possible_versions = filter_ignored_versions(possible_versions)

  possible_versions.last
end
lowest_security_fix_version_details() click to toggle source
# File lib/dependabot/gradle/update_checker/version_finder.rb, line 44
def lowest_security_fix_version_details
  possible_versions = versions

  possible_versions = filter_prereleases(possible_versions)
  possible_versions = filter_date_based_versions(possible_versions)
  possible_versions = filter_version_types(possible_versions)
  possible_versions = Dependabot::UpdateCheckers::VersionFilters.filter_vulnerable_versions(possible_versions,
                                                                                            security_advisories)
  possible_versions = filter_ignored_versions(possible_versions)
  possible_versions = filter_lower_versions(possible_versions)

  possible_versions.first
end
versions() click to toggle source
# File lib/dependabot/gradle/update_checker/version_finder.rb, line 58
def versions
  version_details =
    repositories.map do |repository_details|
      url = repository_details.fetch("url")
      next google_version_details if url == GOOGLE_MAVEN_REPO

      dependency_metadata(repository_details).css("versions > version").
        select { |node| version_class.correct?(node.content) }.
        map { |node| version_class.new(node.content) }.
        map { |version| { version: version, source_url: url } }
    end.flatten.compact

  raise PrivateSourceAuthenticationFailure, forbidden_urls.first if version_details.none? && forbidden_urls.any?

  version_details.sort_by { |details| details.fetch(:version) }
end

Private Instance Methods

auth_headers(maven_repo_url) click to toggle source
# File lib/dependabot/gradle/update_checker/version_finder.rb, line 327
def auth_headers(maven_repo_url)
  auth_headers_finder.auth_headers(maven_repo_url)
end
auth_headers_finder() click to toggle source
# File lib/dependabot/gradle/update_checker/version_finder.rb, line 323
def auth_headers_finder
  @auth_headers_finder ||= Dependabot::Maven::Utils::AuthHeadersFinder.new(credentials)
end
central_repo_urls() click to toggle source
# File lib/dependabot/gradle/update_checker/version_finder.rb, line 311
def central_repo_urls
  central_url_without_protocol =
    Gradle::FileParser::RepositoriesFinder::CENTRAL_REPO_URL.
    gsub(%r{^.*://}, "")

  %w(http:// https://).map { |p| p + central_url_without_protocol }
end
check_response(response, repository_url) click to toggle source
# File lib/dependabot/gradle/update_checker/version_finder.rb, line 194
def check_response(response, repository_url)
  return unless [401, 403].include?(response.status)
  return if @forbidden_urls.include?(repository_url)
  return if central_repo_urls.include?(repository_url)

  @forbidden_urls << repository_url
end
credentials_repository_details() click to toggle source
# File lib/dependabot/gradle/update_checker/version_finder.rb, line 222
def credentials_repository_details
  credentials.
    select { |cred| cred["type"] == "maven_repository" }.
    map do |cred|
    {
      "url" => cred.fetch("url").gsub(%r{/+$}, ""),
      "auth_headers" => auth_headers(cred.fetch("url").gsub(%r{/+$}, ""))
    }
  end
end
dependency_metadata(repository_details) click to toggle source
# File lib/dependabot/gradle/update_checker/version_finder.rb, line 169
def dependency_metadata(repository_details)
  @dependency_metadata ||= {}
  @dependency_metadata[repository_details.hash] ||=
    begin
      response = Excon.get(
        dependency_metadata_url(repository_details.fetch("url")),
        idempotent: true,
        **Dependabot::SharedHelpers.excon_defaults(headers: repository_details.fetch("auth_headers"))
      )
      check_response(response, repository_details.fetch("url"))
      Nokogiri::XML(response.body)
    rescue URI::InvalidURIError
      Nokogiri::XML("")
    rescue Excon::Error::Socket, Excon::Error::Timeout,
           Excon::Error::TooManyRedirects
      raise if central_repo_urls.include?(repository_details["url"])

      Nokogiri::XML("")
    end
end
dependency_metadata_url(repository_url) click to toggle source
# File lib/dependabot/gradle/update_checker/version_finder.rb, line 283
def dependency_metadata_url(repository_url)
  group_id, artifact_id = group_and_artifact_ids
  group_id = "#{KOTLIN_PLUGIN_REPO_PREFIX}.#{group_id}" if kotlin_plugin?

  "#{repository_url}/"\
  "#{group_id.tr('.', '/')}/"\
  "#{artifact_id}/"\
  "maven-metadata.xml"
end
dependency_repository_details() click to toggle source
# File lib/dependabot/gradle/update_checker/version_finder.rb, line 233
def dependency_repository_details
  requirement_files =
    dependency.requirements.
    map { |r| r.fetch(:file) }.
    map { |nm| dependency_files.find { |f| f.name == nm } }

  @dependency_repository_details ||=
    requirement_files.flat_map do |target_file|
      Gradle::FileParser::RepositoriesFinder.new(
        dependency_files: dependency_files,
        target_dependency_file: target_file
      ).repository_urls.
        map do |url|
          { "url" => url, "auth_headers" => {} }
        end
    end.uniq
end
filter_date_based_versions(possible_versions) click to toggle source
# File lib/dependabot/gradle/update_checker/version_finder.rb, line 86
def filter_date_based_versions(possible_versions)
  return possible_versions if wants_date_based_version?

  possible_versions.
    reject { |v| v.fetch(:version) > version_class.new(1900) }
end
filter_ignored_versions(possible_versions) click to toggle source
# File lib/dependabot/gradle/update_checker/version_finder.rb, line 98
def filter_ignored_versions(possible_versions)
  filtered = possible_versions

  ignored_versions.each do |req|
    ignore_requirements = Gradle::Requirement.requirements_array(req)
    filtered =
      filtered.
      reject { |v| ignore_requirements.any? { |r| r.satisfied_by?(v.fetch(:version)) } }
  end

  if @raise_on_ignored && filter_lower_versions(filtered).empty? &&
     filter_lower_versions(possible_versions).any?
    raise AllVersionsIgnored
  end

  filtered
end
filter_lower_versions(possible_versions) click to toggle source
# File lib/dependabot/gradle/update_checker/version_finder.rb, line 116
def filter_lower_versions(possible_versions)
  return possible_versions unless dependency.version && version_class.correct?(dependency.version)

  possible_versions.select do |v|
    v.fetch(:version) > version_class.new(dependency.version)
  end
end
filter_prereleases(possible_versions) click to toggle source
# File lib/dependabot/gradle/update_checker/version_finder.rb, line 80
def filter_prereleases(possible_versions)
  return possible_versions if wants_prerelease?

  possible_versions.reject { |v| v.fetch(:version).prerelease? }
end
filter_version_types(possible_versions) click to toggle source
# File lib/dependabot/gradle/update_checker/version_finder.rb, line 93
def filter_version_types(possible_versions)
  possible_versions.
    select { |v| matches_dependency_version_type?(v.fetch(:version)) }
end
google_version_details() click to toggle source
# File lib/dependabot/gradle/update_checker/version_finder.rb, line 138
def google_version_details
  url = GOOGLE_MAVEN_REPO
  group_id, artifact_id = group_and_artifact_ids

  dependency_metadata_url = "#{GOOGLE_MAVEN_REPO}/"\
                            "#{group_id.tr('.', '/')}/"\
                            "group-index.xml"

  @google_version_details ||=
    begin
      response = Excon.get(
        dependency_metadata_url,
        idempotent: true,
        **SharedHelpers.excon_defaults
      )
      Nokogiri::XML(response.body)
    end

  xpath = "/#{group_id}/#{artifact_id}"
  return unless @google_version_details.at_xpath(xpath)

  @google_version_details.at_xpath(xpath).
    attributes.fetch("versions").
    value.split(",").
    select { |v| version_class.correct?(v) }.
    map { |v| version_class.new(v) }.
    map { |version| { version: version, source_url: url } }
rescue Nokogiri::XML::XPath::SyntaxError
  nil
end
group_and_artifact_ids() click to toggle source
# File lib/dependabot/gradle/update_checker/version_finder.rb, line 293
def group_and_artifact_ids
  if kotlin_plugin?
    [dependency.name, "#{KOTLIN_PLUGIN_REPO_PREFIX}.#{dependency.name}.gradle.plugin"]
  elsif plugin?
    [dependency.name, "#{dependency.name}.gradle.plugin"]
  else
    dependency.name.split(":")
  end
end
kotlin_plugin?() click to toggle source
# File lib/dependabot/gradle/update_checker/version_finder.rb, line 307
def kotlin_plugin?
  plugin? && dependency.requirements.any? { |r| r.fetch(:groups).include? "kotlin" }
end
matches_dependency_version_type?(comparison_version) click to toggle source
# File lib/dependabot/gradle/update_checker/version_finder.rb, line 258
def matches_dependency_version_type?(comparison_version)
  return true unless dependency.version

  current_type = dependency.version.
                 gsub("native-mt", "native_mt").
                 split(/[.\-]/).
                 find do |type|
                   TYPE_SUFFICES.find { |s| type.include?(s) }
                 end

  version_type = comparison_version.to_s.
                 gsub("native-mt", "native_mt").
                 split(/[.\-]/).
                 find do |type|
                   TYPE_SUFFICES.find { |s| type.include?(s) }
                 end

  current_type == version_type
end
plugin?() click to toggle source
# File lib/dependabot/gradle/update_checker/version_finder.rb, line 303
def plugin?
  dependency.requirements.any? { |r| r.fetch(:groups).include? "plugins" }
end
plugin_repository_details() click to toggle source
# File lib/dependabot/gradle/update_checker/version_finder.rb, line 251
def plugin_repository_details
  [{
    "url" => GRADLE_PLUGINS_REPO,
    "auth_headers" => {}
  }] + dependency_repository_details
end
pom() click to toggle source
# File lib/dependabot/gradle/update_checker/version_finder.rb, line 278
def pom
  filename = dependency.requirements.first.fetch(:file)
  dependency_files.find { |f| f.name == filename }
end
repositories() click to toggle source
# File lib/dependabot/gradle/update_checker/version_finder.rb, line 202
def repositories
  return @repositories if @repositories

  details = if plugin?
              plugin_repository_details +
                credentials_repository_details
            else
              dependency_repository_details +
                credentials_repository_details
            end

  @repositories =
    details.reject do |repo|
      next if repo["auth_headers"]

      # Reject this entry if an identical one with non-empty auth_headers exists
      details.any? { |r| r["url"] == repo["url"] && r["auth_headers"] != {} }
    end
end
repository_urls() click to toggle source
# File lib/dependabot/gradle/update_checker/version_finder.rb, line 190
def repository_urls
  plugin? ? plugin_repository_details : dependency_repository_details
end
version_class() click to toggle source
# File lib/dependabot/gradle/update_checker/version_finder.rb, line 319
def version_class
  Gradle::Version
end
wants_date_based_version?() click to toggle source
# File lib/dependabot/gradle/update_checker/version_finder.rb, line 131
def wants_date_based_version?
  return false unless dependency.version
  return false unless version_class.correct?(dependency.version)

  version_class.new(dependency.version) >= version_class.new(100)
end
wants_prerelease?() click to toggle source
# File lib/dependabot/gradle/update_checker/version_finder.rb, line 124
def wants_prerelease?
  return false unless dependency.version
  return false unless version_class.correct?(dependency.version)

  version_class.new(dependency.version).prerelease?
end