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
69
# 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
  apply_npmrc_min_release_age
end

Instance Method Details

#conflicting_dependenciesObject



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

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



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

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

#latest_resolvable_versionObject



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

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



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

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



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

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



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

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



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

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)


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

def requirements_unlocked_or_can_be?
  !requirements_update_strategy&.lockfile_only?
end

#requirements_update_strategyObject



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

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)


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

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



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

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)


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

def vulnerable?
  super || vulnerable_versions.any?
end