class Dependabot::Docker::UpdateChecker
Constants
- NAME_WITH_VERSION
- VERSION_REGEX
- VERSION_WITH_PFX
- VERSION_WITH_PFX_AND_SFX
- VERSION_WITH_SFX
Public Instance Methods
latest_resolvable_version()
click to toggle source
# File lib/dependabot/docker/update_checker.rb, line 63 def latest_resolvable_version # Resolvability isn't an issue for Docker containers. latest_version end
latest_resolvable_version_with_no_unlock()
click to toggle source
# File lib/dependabot/docker/update_checker.rb, line 68 def latest_resolvable_version_with_no_unlock # No concept of "unlocking" for Docker containers dependency.version end
latest_version()
click to toggle source
# File lib/dependabot/docker/update_checker.rb, line 59 def latest_version fetch_latest_version(dependency.version) end
updated_requirements()
click to toggle source
# File lib/dependabot/docker/update_checker.rb, line 73 def updated_requirements dependency.requirements.map do |req| updated_source = req.fetch(:source).dup updated_source[:digest] = updated_digest if req[:source][:digest] updated_source[:tag] = fetch_latest_version(req[:source][:tag]) if req[:source][:tag] req.merge(source: updated_source) end end
Private Instance Methods
canonical_version?(tag)
click to toggle source
# File lib/dependabot/docker/update_checker.rb, line 212 def canonical_version?(tag) return false unless numeric_version_from(tag) return true if tag == numeric_version_from(tag) # .NET tags are suffixed with -sdk return true if tag == numeric_version_from(tag) + "-sdk" tag == "jdk-" + numeric_version_from(tag) end
commit_sha_suffix?(tag)
click to toggle source
# File lib/dependabot/docker/update_checker.rb, line 187 def commit_sha_suffix?(tag) # Some people suffix their versions with commit SHAs. Dependabot # can't order on those but will try to, so instead we should exclude # them (unless there's a `latest` version pushed to the registry, in # which case we'll use that to find the latest version) return false unless tag.match?(/(^|\-g?)[0-9a-f]{7,}$/) !tag.match?(/(^|\-)\d+$/) end
credentials_finder()
click to toggle source
# File lib/dependabot/docker/update_checker.rb, line 335 def credentials_finder @credentials_finder ||= Utils::CredentialsFinder.new(credentials) end
digest_of(tag)
click to toggle source
# File lib/dependabot/docker/update_checker.rb, line 255 def digest_of(tag) @digests ||= {} return @digests[tag] if @digests.key?(tag) @digests[tag] = begin docker_registry_client.digest(docker_repo_name, tag) rescue *transient_docker_errors => e attempt ||= 1 attempt += 1 return if attempt > 3 && e.is_a?(DockerRegistry2::NotFound) raise if attempt > 3 retry end rescue DockerRegistry2::RegistryAuthenticationException, RestClient::Forbidden raise PrivateSourceAuthenticationFailure, registry_hostname end
digest_up_to_date?()
click to toggle source
# File lib/dependabot/docker/update_checker.rb, line 128 def digest_up_to_date? dependency.requirements.all? do |req| next true unless req.fetch(:source)[:digest] next true unless (new_digest = digest_of(dependency.version)) req.fetch(:source).fetch(:digest) == new_digest end end
docker_registry_client()
click to toggle source
# File lib/dependabot/docker/update_checker.rb, line 346 def docker_registry_client @docker_registry_client ||= DockerRegistry2::Registry.new( "https://#{registry_hostname}", user: registry_credentials&.fetch("username", nil), password: registry_credentials&.fetch("password", nil) ) end
docker_repo_name()
click to toggle source
# File lib/dependabot/docker/update_checker.rb, line 339 def docker_repo_name return dependency.name unless using_dockerhub? return dependency.name unless dependency.name.split("/").count < 2 "library/#{dependency.name}" end
fetch_latest_version(version)
click to toggle source
NOTE: It's important that this always returns a version (even if it's the existing one) as it is what we later check the digest of.
# File lib/dependabot/docker/update_checker.rb, line 139 def fetch_latest_version(version) @versions ||= {} return @versions[version] if @versions.key?(version) @versions[version] = begin return version unless version.match?(NAME_WITH_VERSION) # Prune out any downgrade tags before checking for pre-releases # (which requires a call to the registry for each tag, so can be slow) candidate_tags = comparable_tags_from_registry(version) non_downgrade_tags = remove_version_downgrades(candidate_tags, version) candidate_tags = non_downgrade_tags if non_downgrade_tags.any? unless prerelease?(version) candidate_tags = candidate_tags. reject { |tag| prerelease?(tag) } end latest_tag = filter_ignored(candidate_tags). max_by do |tag| [version_class.new(numeric_version_from(tag)), tag.length] end latest_tag || version end end
filter_ignored(candidate_tags)
click to toggle source
# File lib/dependabot/docker/update_checker.rb, line 355 def filter_ignored(candidate_tags) filtered = candidate_tags. reject do |tag| version = version_class.new(numeric_version_from(tag)) ignore_requirements.any? { |r| r.satisfied_by?(version) } end if @raise_on_ignored && filter_lower_versions(filtered).empty? && filter_lower_versions(candidate_tags).any? raise AllVersionsIgnored end filtered end
filter_lower_versions(tags)
click to toggle source
# File lib/dependabot/docker/update_checker.rb, line 369 def filter_lower_versions(tags) versions_array = tags.map { |tag| version_class.new(numeric_version_from(tag)) } versions_array. select { |version| version > version_class.new(numeric_version_from(dependency.version)) } end
format_of(tag)
click to toggle source
# File lib/dependabot/docker/update_checker.rb, line 294 def format_of(tag) version = numeric_version_from(tag) return :year_month if version.match?(/^[12]\d{3}(?:[.\-]|$)/) return :year_month_day if version.match?(/^[12]\d{5}(?:[.\-]|$)/) return :build_num if version.match?(/^\d+$/) :normal end
latest_digest()
click to toggle source
# File lib/dependabot/docker/update_checker.rb, line 249 def latest_digest return unless tags_from_registry.include?("latest") digest_of("latest") end
latest_version_resolvable_with_full_unlock?()
click to toggle source
# File lib/dependabot/docker/update_checker.rb, line 85 def latest_version_resolvable_with_full_unlock? # Full unlock checks aren't relevant for Dockerfiles false end
numeric_version_from(tag)
click to toggle source
# File lib/dependabot/docker/update_checker.rb, line 316 def numeric_version_from(tag) return unless tag.match?(NAME_WITH_VERSION) tag.match(NAME_WITH_VERSION).named_captures.fetch("version").downcase end
prefix_of(tag)
click to toggle source
# File lib/dependabot/docker/update_checker.rb, line 286 def prefix_of(tag) tag.match(NAME_WITH_VERSION).named_captures.fetch("prefix") end
prerelease?(tag)
click to toggle source
# File lib/dependabot/docker/update_checker.rb, line 304 def prerelease?(tag) return true if numeric_version_from(tag).gsub(/kb/i, "").match?(/[a-zA-Z]/) # If we're dealing with a numeric version we can compare it against # the digest for the `latest` tag. return false unless numeric_version_from(tag) return false unless latest_digest return false unless version_of_latest_tag version_class.new(numeric_version_from(tag)) > version_of_latest_tag end
registry_credentials()
click to toggle source
# File lib/dependabot/docker/update_checker.rb, line 331 def registry_credentials credentials_finder.credentials_for_registry(registry_hostname) end
registry_hostname()
click to toggle source
# File lib/dependabot/docker/update_checker.rb, line 322 def registry_hostname dependency.requirements.first[:source][:registry] || "registry.hub.docker.com" end
remove_version_downgrades(candidate_tags, version)
click to toggle source
# File lib/dependabot/docker/update_checker.rb, line 180 def remove_version_downgrades(candidate_tags, version) candidate_tags.select do |tag| version_class.new(numeric_version_from(tag)) >= version_class.new(numeric_version_from(version)) end end
suffix_of(tag)
click to toggle source
# File lib/dependabot/docker/update_checker.rb, line 290 def suffix_of(tag) tag.match(NAME_WITH_VERSION).named_captures.fetch("suffix") end
transient_docker_errors()
click to toggle source
# File lib/dependabot/docker/update_checker.rb, line 275 def transient_docker_errors [ RestClient::Exceptions::Timeout, RestClient::ServerBrokeConnection, RestClient::ServiceUnavailable, RestClient::InternalServerError, RestClient::BadGateway, DockerRegistry2::NotFound ] end
updated_dependencies_after_full_unlock()
click to toggle source
# File lib/dependabot/docker/update_checker.rb, line 90 def updated_dependencies_after_full_unlock raise NotImplementedError end
updated_digest()
click to toggle source
# File lib/dependabot/docker/update_checker.rb, line 222 def updated_digest @updated_digest ||= digest_of(latest_version) end
using_dockerhub?()
click to toggle source
# File lib/dependabot/docker/update_checker.rb, line 327 def using_dockerhub? registry_hostname == "registry.hub.docker.com" end
version_can_update?(*)
click to toggle source
# File lib/dependabot/docker/update_checker.rb, line 94 def version_can_update?(*) !version_up_to_date? end
version_of_latest_tag()
click to toggle source
# File lib/dependabot/docker/update_checker.rb, line 197 def version_of_latest_tag return unless latest_digest candidate_tag = tags_from_registry. select { |tag| canonical_version?(tag) }. sort_by { |t| version_class.new(numeric_version_from(t)) }. reverse. find { |t| digest_of(t) == latest_digest } return unless candidate_tag version_class.new(numeric_version_from(candidate_tag)) end
version_tag_up_to_date?(version)
click to toggle source
# File lib/dependabot/docker/update_checker.rb, line 110 def version_tag_up_to_date?(version) return unless version&.match?(NAME_WITH_VERSION) latest_version = fetch_latest_version(version) old_v = numeric_version_from(version) latest_v = numeric_version_from(latest_version) return true if version_class.new(latest_v) <= version_class.new(old_v) # Check the precision of the potentially higher tag is the same as the # one it would replace. In the event that it's not the same, check the # digests are also unequal. Avoids 'updating' ruby-2 -> ruby-2.5.1 return false if old_v.split(".").count == latest_v.split(".").count digest_of(version) == digest_of(latest_version) end
version_up_to_date?()
click to toggle source
# File lib/dependabot/docker/update_checker.rb, line 98 def version_up_to_date? # If the tag isn't up-to-date then we can definitely update return false if version_tag_up_to_date?(dependency.version) == false return false if dependency.requirements.any? do |req| version_tag_up_to_date?(req.fetch(:source, {})[:tag]) == false end # Otherwise, if the Dockerfile specifies a digest check that that is # up-to-date digest_up_to_date? end