Class: Dependabot::NpmAndYarn::UpdateChecker

Inherits:
UpdateCheckers::Base
  • Object
show all
Extended by:
T::Sig
Defined in:
lib/dependabot/npm_and_yarn/update_checker.rb,
lib/dependabot/npm_and_yarn/update_checker/library_detector.rb,
lib/dependabot/npm_and_yarn/update_checker/version_resolver.rb,
lib/dependabot/npm_and_yarn/update_checker/requirements_updater.rb,
lib/dependabot/npm_and_yarn/update_checker/latest_version_finder.rb,
lib/dependabot/npm_and_yarn/update_checker/vulnerability_auditor.rb,
lib/dependabot/npm_and_yarn/update_checker/dependency_files_builder.rb,
lib/dependabot/npm_and_yarn/update_checker/subdependency_version_resolver.rb,
lib/dependabot/npm_and_yarn/update_checker/conflicting_dependency_resolver.rb

Overview

rubocop:disable Metrics/ClassLength

Defined Under Namespace

Classes: ConflictingDependencyResolver, DependencyFilesBuilder, LibraryDetector, PackageLatestVersionFinder, RequirementsUpdater, SubdependencyVersionResolver, VersionResolver, VulnerabilityAuditor

Instance Method Summary collapse

Constructor Details

#initialize(dependency:, dependency_files:, credentials:, repo_contents_path: nil, ignored_versions: [], raise_on_ignored: false, security_advisories: [], requirements_update_strategy: nil, dependency_group: nil, update_cooldown: nil, options: {}) ⇒ UpdateChecker

rubocop:disable Metrics/AbcSize



39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
# File 'lib/dependabot/npm_and_yarn/update_checker.rb', line 39

def initialize( # rubocop:disable Metrics/AbcSize
  dependency:,
  dependency_files:,
  credentials:,
  repo_contents_path: nil,
  ignored_versions: [],
  raise_on_ignored: false,
  security_advisories: [],
  requirements_update_strategy: nil,
  dependency_group: nil,
  update_cooldown: nil,
  options: {}
)
  @latest_version = T.let(nil, T.nilable(T.any(String, Gem::Version)))
  @latest_resolvable_version = T.let(nil, T.nilable(T.any(String, Dependabot::Version)))
  @updated_requirements = T.let(nil, T.nilable(T::Array[T::Hash[Symbol, T.untyped]]))
  @vulnerability_audit = T.let(nil, T.nilable(T::Hash[String, T.untyped]))
  @vulnerable_versions = T.let(nil, T.nilable(T::Array[T.any(String, Gem::Version)]))

  @latest_version_for_git_dependency = T.let(nil, T.nilable(T.any(String, Gem::Version)))
  @latest_released_version = T.let(nil, T.nilable(Gem::Version))
  @latest_version_details = T.let(nil, T.nilable(T::Hash[Symbol, T.untyped]))
  @latest_version_finder = T.let(nil, T.nilable(PackageLatestVersionFinder))
  @version_resolver = T.let(nil, T.nilable(VersionResolver))
  @subdependency_version_resolver = T.let(nil, T.nilable(SubdependencyVersionResolver))
  @library = T.let(nil, T.nilable(T::Boolean))
  @package_json = T.let(nil, T.nilable(Dependabot::DependencyFile))
  @git_commit_checker = T.let(nil, T.nilable(Dependabot::GitCommitChecker))
  super
end

Instance Method Details

#conflicting_dependenciesObject



202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
# File 'lib/dependabot/npm_and_yarn/update_checker.rb', line 202

def conflicting_dependencies
  conflicts = ConflictingDependencyResolver.new(
    dependency_files: dependency_files,
    credentials: credentials
  ).conflicting_dependencies(
    dependency: dependency,
    target_version: lowest_security_fix_version
  )
  return conflicts unless vulnerability_audit_performed?

  vulnerable = [vulnerability_audit].select do |hash|
    !hash["fix_available"] && hash["explanation"]
  end

  conflicts + vulnerable
end

#latest_resolvable_previous_version(updated_version) ⇒ Object



160
161
162
# File 'lib/dependabot/npm_and_yarn/update_checker.rb', line 160

def latest_resolvable_previous_version(updated_version)
  T.unsafe(version_resolver.latest_resolvable_previous_version(updated_version))
end

#latest_resolvable_versionObject



97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
# File 'lib/dependabot/npm_and_yarn/update_checker.rb', line 97

def latest_resolvable_version
  return unless latest_version

  @latest_resolvable_version ||=
    if dependency.top_level?
      T.cast(
        version_resolver.latest_resolvable_version,
        T.nilable(T.any(String, Dependabot::Version))
      )
    else
      # If the dependency is indirect its version is constrained  by the
      # requirements placed on it by dependencies lower down the tree
      T.cast(
        subdependency_version_resolver.latest_resolvable_version,
        T.nilable(T.any(String, Dependabot::Version))
      )
    end
end

#latest_resolvable_version_with_no_unlockObject



146
147
148
149
150
151
152
153
154
# File 'lib/dependabot/npm_and_yarn/update_checker.rb', line 146

def latest_resolvable_version_with_no_unlock
  unless dependency.top_level?
    return T.cast(latest_resolvable_version, T.nilable(T.any(String, Dependabot::Version)))
  end

  return latest_resolvable_version_with_no_unlock_for_git_dependency if git_dependency?

  latest_version_finder.latest_version_with_no_unlock
end

#latest_versionObject



87
88
89
90
91
92
93
94
# File 'lib/dependabot/npm_and_yarn/update_checker.rb', line 87

def latest_version
  @latest_version ||=
    if git_dependency?
      latest_version_for_git_dependency
    else
      latest_version_details&.fetch(:version)
    end
end

#lowest_resolvable_security_fix_versionObject



125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
# File 'lib/dependabot/npm_and_yarn/update_checker.rb', line 125

def lowest_resolvable_security_fix_version
  raise "Dependency not vulnerable!" unless vulnerable?

  # NOTE: Currently, we don't resolve transitive/sub-dependencies as
  # npm/yarn don't provide any control over updating to a specific
  # sub-dependency version.

  # Return nil for vulnerable transitive dependencies if there are conflicting dependencies.
  # This helps catch errors in such cases.
  return nil if !dependency.top_level? && conflicting_dependencies.any?

  # For transitive dependencies without conflicts, return the latest resolvable transitive
  # security fix version that does not require unlocking other dependencies.
  return latest_resolvable_transitive_security_fix_version_with_no_unlock unless dependency.top_level?

  # For top-level dependencies, return the lowest security fix version.
  # TODO: Consider checking resolvability here in the future.
  lowest_security_fix_version
end

#lowest_security_fix_versionObject



117
118
119
120
121
122
# File 'lib/dependabot/npm_and_yarn/update_checker.rb', line 117

def lowest_security_fix_version
  # This will require a full unlock to update multiple top level ancestors.
  return if vulnerability_audit["fix_available"] && vulnerability_audit["top_level_ancestors"].count > 1

  T.unsafe(latest_version_finder.lowest_security_fix_version)
end

#requirements_unlocked_or_can_be?Boolean

Returns:

  • (Boolean)


188
189
190
# File 'lib/dependabot/npm_and_yarn/update_checker.rb', line 188

def requirements_unlocked_or_can_be?
  !requirements_update_strategy&.lockfile_only?
end

#requirements_update_strategyObject



193
194
195
196
197
198
199
# File 'lib/dependabot/npm_and_yarn/update_checker.rb', line 193

def requirements_update_strategy
  # If passed in as an option (in the base class) honour that option
  return @requirements_update_strategy if @requirements_update_strategy

  # Otherwise, widen ranges for libraries and bump versions for apps
  library? ? RequirementsUpdateStrategy::WidenRanges : RequirementsUpdateStrategy::BumpVersions
end

#up_to_date?Boolean

Returns:

  • (Boolean)


71
72
73
74
75
76
77
78
79
# File 'lib/dependabot/npm_and_yarn/update_checker.rb', line 71

def up_to_date?
  return false if security_update? &&
                  dependency.version &&
                  version_class.correct?(dependency.version) &&
                  vulnerable_versions.any? &&
                  !vulnerable_versions.include?(current_version)

  super
end

#updated_requirementsObject



165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
# File 'lib/dependabot/npm_and_yarn/update_checker.rb', line 165

def updated_requirements
  resolvable_version =
    if preferred_resolvable_version.is_a?(version_class)
      preferred_resolvable_version.to_s
    elsif preferred_resolvable_version.nil?
      nil
    else
      # If the preferred_resolvable_version came back as anything other
      # than a version class or `nil` it must be because this is a git
      # dependency, for which we don't check resolvability.
      latest_version_details&.fetch(:version, nil)&.to_s
    end

  @updated_requirements ||=
    RequirementsUpdater.new(
      requirements: dependency.requirements,
      updated_source: updated_source,
      latest_resolvable_version: resolvable_version,
      update_strategy: T.must(requirements_update_strategy)
    ).updated_requirements
end

#vulnerable?Boolean

Returns:

  • (Boolean)


82
83
84
# File 'lib/dependabot/npm_and_yarn/update_checker.rb', line 82

def vulnerable?
  super || vulnerable_versions.any?
end