class Dependabot::Composer::UpdateChecker::LatestVersionFinder

Attributes

credentials[R]
dependency[R]
dependency_files[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/composer/update_checker/latest_version_finder.rb, line 15
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
end

Public Instance Methods

latest_version() click to toggle source
# File lib/dependabot/composer/update_checker/latest_version_finder.rb, line 26
def latest_version
  @latest_version ||= fetch_latest_version
end
lowest_security_fix_version() click to toggle source
# File lib/dependabot/composer/update_checker/latest_version_finder.rb, line 30
def lowest_security_fix_version
  @lowest_security_fix_version ||= fetch_lowest_security_fix_version
end

Private Instance Methods

auth_json() click to toggle source
# File lib/dependabot/composer/update_checker/latest_version_finder.rb, line 179
def auth_json
  dependency_files.find { |f| f.name == "auth.json" }
end
auth_json_credentials() click to toggle source
# File lib/dependabot/composer/update_checker/latest_version_finder.rb, line 156
def auth_json_credentials
  return [] unless auth_json

  parsed_auth_json = JSON.parse(auth_json.content)
  parsed_auth_json.fetch("http-basic", {}).map do |reg, details|
    {
      "registry" => reg,
      "username" => details["username"],
      "password" => details["password"]
    }
  end
rescue JSON::ParserError
  raise Dependabot::DependencyFileNotParseable, auth_json.path
end
available_versions() click to toggle source
# File lib/dependabot/composer/update_checker/latest_version_finder.rb, line 91
def available_versions
  registry_version_details.
    select { |version| version_class.correct?(version.gsub(/^v/, "")) }.
    map { |version| version_class.new(version.gsub(/^v/, "")) }
end
composer_file() click to toggle source
# File lib/dependabot/composer/update_checker/latest_version_finder.rb, line 171
def composer_file
  composer_file =
    dependency_files.find { |f| f.name == "composer.json" }
  raise "No composer.json!" unless composer_file

  composer_file
end
fetch_latest_version() click to toggle source
# File lib/dependabot/composer/update_checker/latest_version_finder.rb, line 39
def fetch_latest_version
  versions = available_versions
  versions = filter_prerelease_versions(versions)
  versions = filter_ignored_versions(versions)
  versions.max
end
fetch_lowest_security_fix_version() click to toggle source
# File lib/dependabot/composer/update_checker/latest_version_finder.rb, line 46
def fetch_lowest_security_fix_version
  versions = available_versions
  versions = filter_prerelease_versions(versions)
  versions = Dependabot::UpdateCheckers::VersionFilters.filter_vulnerable_versions(versions,
                                                                                   security_advisories)
  versions = filter_ignored_versions(versions)
  versions = filter_lower_versions(versions)

  versions.min
end
fetch_registry_versions_from_url(url) click to toggle source
# File lib/dependabot/composer/update_checker/latest_version_finder.rb, line 121
def fetch_registry_versions_from_url(url)
  cred = registry_credentials.find { |c| url.include?(c["registry"]) }

  response = Excon.get(
    url,
    idempotent: true,
    user: cred&.fetch("username", nil),
    password: cred&.fetch("password", nil),
    **SharedHelpers.excon_defaults
  )

  parse_registry_response(response, url)
rescue Excon::Error::Socket, Excon::Error::Timeout
  []
end
filter_ignored_versions(versions_array) click to toggle source
# File lib/dependabot/composer/update_checker/latest_version_finder.rb, line 63
def filter_ignored_versions(versions_array)
  filtered =
    versions_array.
    reject { |v| ignore_requirements.any? { |r| r.satisfied_by?(v) } }

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

  filtered
end
filter_lower_versions(versions_array) click to toggle source
# File lib/dependabot/composer/update_checker/latest_version_finder.rb, line 75
def filter_lower_versions(versions_array)
  return versions_array unless dependency.version && version_class.correct?(dependency.version)

  versions_array.
    select { |version| version > version_class.new(dependency.version) }
end
filter_prerelease_versions(versions_array) click to toggle source
# File lib/dependabot/composer/update_checker/latest_version_finder.rb, line 57
def filter_prerelease_versions(versions_array)
  return versions_array if wants_prerelease?

  versions_array.reject(&:prerelease?)
end
ignore_requirements() click to toggle source
# File lib/dependabot/composer/update_checker/latest_version_finder.rb, line 183
def ignore_requirements
  ignored_versions.map { |req| requirement_class.new(req.split(",")) }
end
parse_registry_response(response, url) click to toggle source
# File lib/dependabot/composer/update_checker/latest_version_finder.rb, line 137
def parse_registry_response(response, url)
  return [] unless response.status == 200

  listing = JSON.parse(response.body)
  return [] if listing.nil?
  return [] if listing.fetch("packages", []) == []
  return [] unless listing.dig("packages", dependency.name.downcase)

  listing.dig("packages", dependency.name.downcase).keys
rescue JSON::ParserError
  msg = "'#{url}' does not contain valid JSON"
  raise DependencyFileNotResolvable, msg
end
registry_credentials() click to toggle source
# File lib/dependabot/composer/update_checker/latest_version_finder.rb, line 151
def registry_credentials
  credentials.select { |cred| cred["type"] == "composer_repository" } +
    auth_json_credentials
end
registry_version_details() click to toggle source
# File lib/dependabot/composer/update_checker/latest_version_finder.rb, line 97
def registry_version_details
  return @registry_version_details unless @registry_version_details.nil?

  repositories =
    JSON.parse(composer_file.content).
    fetch("repositories", []).
    select { |r| r.is_a?(Hash) }

  urls = repositories.
         select { |h| h["type"] == "composer" }.
         map { |h| h["url"] }.compact.
         map { |url| url.gsub(%r{\/$}, "") + "/packages.json" }

  unless repositories.any? { |rep| rep["packagist.org"] == false }
    urls << "https://packagist.org/p/#{dependency.name.downcase}.json"
  end

  @registry_version_details = []
  urls.each do |url|
    @registry_version_details += fetch_registry_versions_from_url(url)
  end
  @registry_version_details.uniq
end
requirement_class() click to toggle source
# File lib/dependabot/composer/update_checker/latest_version_finder.rb, line 191
def requirement_class
  Utils.requirement_class_for_package_manager(
    dependency.package_manager
  )
end
version_class() click to toggle source
# File lib/dependabot/composer/update_checker/latest_version_finder.rb, line 187
def version_class
  Utils.version_class_for_package_manager(dependency.package_manager)
end
wants_prerelease?() click to toggle source
# File lib/dependabot/composer/update_checker/latest_version_finder.rb, line 82
def wants_prerelease?
  current_version = dependency.version
  return true if current_version && version_class.new(current_version).prerelease?

  dependency.requirements.any? do |req|
    req[:requirement].match?(/\d-[A-Za-z]/)
  end
end