# typed: strict# frozen_string_literal: truerequire"cgi"require"excon"require"nokogiri"require"sorbet-runtime"require"dependabot/security_advisory"require"dependabot/dependency"require"dependabot/update_checkers/version_filters"require"dependabot/registry_client"require"dependabot/package/package_details"require"dependabot/package/release_cooldown_options"moduleDependabotmodulePackageclassPackageLatestVersionFinderextendT::SigextendT::HelpersDAY_IN_SECONDS=T.let(24*60*60,Integer)abstract!sig{returns(Dependabot::Dependency)}attr_reader:dependencysig{returns(T::Array[Dependabot::DependencyFile])}attr_reader:dependency_filessig{returns(T::Array[Dependabot::Credential])}attr_reader:credentialssig{returns(T::Array[String])}attr_reader:ignored_versionssig{returns(T::Array[SecurityAdvisory])}attr_reader:security_advisoriessig{returns(T.nilable(ReleaseCooldownOptions))}attr_reader:cooldown_optionssig{returns(T::Hash[Symbol,T.untyped])}attr_reader:optionssigdoparams(dependency: Dependabot::Dependency,dependency_files: T::Array[Dependabot::DependencyFile],credentials: T::Array[Dependabot::Credential],ignored_versions: T::Array[String],security_advisories: T::Array[Dependabot::SecurityAdvisory],cooldown_options: T.nilable(ReleaseCooldownOptions),raise_on_ignored: T::Boolean,options: T::Hash[Symbol,T.untyped]).voidenddefinitialize(dependency:,dependency_files:,credentials:,ignored_versions:,security_advisories:,cooldown_options: nil,raise_on_ignored: false,options: {})@dependency=dependency@dependency_files=dependency_files@credentials=credentials@ignored_versions=ignored_versions@security_advisories=security_advisories@cooldown_options=cooldown_options@raise_on_ignored=raise_on_ignored# It can be used by sub classes to pass options to the registry client@options=options@latest_version=T.let(nil,T.nilable(Dependabot::Version))@latest_version_with_no_unlock=T.let(nil,T.nilable(Dependabot::Version))@lowest_security_fix_version=T.let(nil,T.nilable(Dependabot::Version))@package_details=T.let(nil,T.nilable(Dependabot::Package::PackageDetails))endsigdoparams(language_version: T.nilable(T.any(String,Dependabot::Version))).returns(T.nilable(Dependabot::Version))enddeflatest_version(language_version: nil)@latest_version||=fetch_latest_version(language_version: language_version)endsigdoparams(language_version: T.nilable(T.any(String,Dependabot::Version))).returns(T.nilable(Dependabot::Version))enddeflatest_version_with_no_unlock(language_version: nil)@latest_version_with_no_unlock||=fetch_latest_version_with_no_unlock(language_version: language_version)endsigdoparams(language_version: T.nilable(T.any(String,Dependabot::Version))).returns(T.nilable(Dependabot::Version))enddeflowest_security_fix_version(language_version: nil)@lowest_security_fix_version||=fetch_lowest_security_fix_version(language_version: language_version)endsig{abstract.returns(T.nilable(Dependabot::Package::PackageDetails))}defpackage_details;endsigdoreturns(T.nilable(T::Array[Dependabot::Package::PackageRelease]))enddefavailable_versionspackage_details&.releasesendprotectedsigdoparams(language_version: T.nilable(T.any(String,Dependabot::Version))).returns(T.nilable(Dependabot::Version))enddeffetch_latest_version(language_version: nil)releases=available_versionsreturnunlessreleasesreleases=filter_yanked_versions(releases)releases=filter_by_cooldown(releases)releases=filter_unsupported_versions(releases,language_version)releases=filter_prerelease_versions(releases)releases=filter_ignored_versions(releases)releases=apply_post_fetch_latest_versions_filter(releases)releases.max_by(&:version)&.versionendsigdoparams(language_version: T.nilable(T.any(String,Dependabot::Version))).returns(T.nilable(Dependabot::Version))enddeffetch_latest_version_with_no_unlock(language_version:)releases=available_versionsreturnunlessreleasesreleases=filter_yanked_versions(releases)releases=filter_by_cooldown(releases)releases=filter_unsupported_versions(releases,language_version)releases=filter_prerelease_versions(releases)releases=filter_ignored_versions(releases)releases=filter_out_of_range_versions(releases)releases=apply_post_fetch_latest_versions_filter(releases)releases.max_by(&:version)&.versionendsigdoparams(language_version: T.nilable(T.any(String,Dependabot::Version))).returns(T.nilable(Dependabot::Version))enddeffetch_lowest_security_fix_version(language_version: nil)releases=available_versionsreturnunlessreleasesreleases=filter_yanked_versions(releases)releases=filter_unsupported_versions(releases,language_version)# versions = filter_prerelease_versions(versions)releases=Dependabot::UpdateCheckers::VersionFilters.filter_vulnerable_versions(releases,security_advisories)releases=filter_ignored_versions(releases)releases=filter_lower_versions(releases)releases=apply_post_fetch_lowest_security_fix_versions_filter(releases)releases.min_by(&:version)&.versionendsigdoparams(releases: T::Array[Dependabot::Package::PackageRelease]).returns(T::Array[Dependabot::Package::PackageRelease])enddefapply_post_fetch_latest_versions_filter(releases)releasesendsigdoparams(releases: T::Array[Dependabot::Package::PackageRelease]).returns(T::Array[Dependabot::Package::PackageRelease])enddefapply_post_fetch_lowest_security_fix_versions_filter(releases)releasesendsigdoparams(releases: T::Array[Dependabot::Package::PackageRelease]).returns(T::Array[Dependabot::Package::PackageRelease])enddeffilter_yanked_versions(releases)filtered=releases.reject(&:yanked?)ifreleases.count>filtered.countDependabot.logger.info("Filtered out #{releases.count-filtered.count} yanked versions")endfilteredendsigdoparams(releases: T::Array[Dependabot::Package::PackageRelease]).returns(T::Array[Dependabot::Package::PackageRelease])enddeffilter_by_cooldown(releases)returnreleasesunlesscooldown_enabled?returnreleasesunlesscooldown_optionsfiltered=releases.reject{|release|in_cooldown_period?(release)}ifreleases.count>filtered.countDependabot.logger.info("Filtered out #{releases.count-filtered.count} versions due to cooldown")endfilteredendsig{params(release: Dependabot::Package::PackageRelease).returns(T::Boolean)}defin_cooldown_period?(release)returnfalseunlessrelease.released_atcurrent_version=version_class.correct?(dependency.version)?version_class.new(dependency.version):nildays=cooldown_days_for(current_version,release.version)# Calculate the number of seconds passed since the releasepassed_seconds=Time.now.to_i-release.released_at.to_i# Check if the release is within the cooldown periodpassed_seconds<days*DAY_IN_SECONDSendsigdoparams(releases: T::Array[Dependabot::Package::PackageRelease],language_version: T.nilable(T.any(String,Dependabot::Version))).returns(T::Array[Dependabot::Package::PackageRelease])enddeffilter_unsupported_versions(releases,language_version)filtered=releases.filter_mapdo|release|language_requirement=release.language&.requirementnextreleaseunlesslanguage_versionnextreleaseunlesslanguage_requirementnextunlesslanguage_requirement.satisfied_by?(language_version)releaseendifreleases.count>filtered.countdelta=releases.count-filtered.countDependabot.logger.info("Filtered out #{delta} unsupported Language #{language_version} versions")endfilteredendsigdoparams(releases: T::Array[Dependabot::Package::PackageRelease]).returns(T::Array[Dependabot::Package::PackageRelease])enddeffilter_prerelease_versions(releases)returnreleasesifwants_prerelease?filtered=releases.reject{|release|release.version.prerelease?}ifreleases.count>filtered.countDependabot.logger.info("Filtered out #{releases.count-filtered.count} pre-release versions")endfilteredendsigdoparams(releases: T::Array[Dependabot::Package::PackageRelease]).returns(T::Array[Dependabot::Package::PackageRelease])enddeffilter_ignored_versions(releases)filtered=releases.rejectdo|release|ignore_requirements.any?do|r|r.satisfied_by?(release.version)endendif@raise_on_ignored&&filter_lower_versions(filtered).empty?&&filter_lower_versions(releases).any?raiseDependabot::AllVersionsIgnoredendifreleases.count>filtered.countDependabot.logger.info("Filtered out #{releases.count-filtered.count} ignored versions")endfilteredendsigdoparams(releases: T::Array[Dependabot::Package::PackageRelease]).returns(T::Array[Dependabot::Package::PackageRelease])enddeffilter_lower_versions(releases)returnreleasesunlessdependency.numeric_versionreleases.select{|release|release.version>dependency.numeric_version}endsigdoparams(releases: T::Array[Dependabot::Package::PackageRelease]).returns(T::Array[Dependabot::Package::PackageRelease])enddeffilter_out_of_range_versions(releases)reqs=dependency.requirements.filter_mapdo|r|nextifr.fetch(:requirement).nil?requirement_class.requirements_array(r.fetch(:requirement))endreleases.selectdo|release|reqs.all?do|r|r.any?{|o|o.satisfied_by?(release.version)}endendendsig{returns(T::Boolean)}defcooldown_enabled?falseendsigdoparams(current_version: T.nilable(Dependabot::Version),new_version: Dependabot::Version).returns(Integer)enddefcooldown_days_for(current_version,new_version)cooldown=@cooldown_optionsreturn0ifcooldown.nil?return0unlesscooldown_enabled?return0unlesscooldown.included?(dependency.name)returncooldown.default_daysifcurrent_version.nil?current_version_semver=current_version.semver_partsnew_version_semver=new_version.semver_parts# If semver_parts is nil for either, return default cooldownreturncooldown.default_daysifcurrent_version_semver.nil?||new_version_semver.nil?# Ensure values are always integerscurrent_major,current_minor,current_patch=current_version_semvernew_major,new_minor,new_patch=new_version_semver# Determine cooldown based on version differencereturncooldown.semver_major_daysifnew_major>current_majorreturncooldown.semver_minor_daysifnew_minor>current_minorreturncooldown.semver_patch_daysifnew_patch>current_patchcooldown.default_daysendsig{returns(T::Boolean)}defwants_prerelease?returnversion_class.new(dependency.version).prerelease?ifdependency.versiondependency.requirements.any?do|req|reqs=(req.fetch(:requirement)||"").split(",").map(&:strip)reqs.any?{|r|r.match?(/[A-Za-z]/)}endendsig{returns(T::Array[T.untyped])}defignore_requirementsignored_versions.flat_map{|req|requirement_class.requirements_array(req)}endsig{returns(T.class_of(Dependabot::Version))}defversion_classdependency.version_classendsig{returns(T.class_of(Dependabot::Requirement))}defrequirement_classdependency.requirement_classendendendend