Class: Dependabot::SecurityAdvisory

Inherits:
Object
  • Object
show all
Extended by:
T::Sig
Defined in:
lib/dependabot/security_advisory.rb

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(dependency_name:, package_manager:, vulnerable_versions: [], safe_versions: []) ⇒ SecurityAdvisory

Returns a new instance of SecurityAdvisory.



35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
# File 'lib/dependabot/security_advisory.rb', line 35

def initialize(
  dependency_name:,
  package_manager:,
  vulnerable_versions: [],
  safe_versions: []
)
  @dependency_name = dependency_name
  @package_manager = package_manager
  @vulnerable_version_strings = T.let(vulnerable_versions || [], T::Array[T.any(String, Dependabot::Requirement)])
  @vulnerable_versions = T.let([], T::Array[Dependabot::Requirement])
  @safe_versions = T.let([], T::Array[Dependabot::Requirement])

  convert_string_version_requirements(vulnerable_version_strings, safe_versions || [])
  check_version_requirements
end

Instance Attribute Details

#dependency_nameObject (readonly)

Returns the value of attribute dependency_name.



12
13
14
# File 'lib/dependabot/security_advisory.rb', line 12

def dependency_name
  @dependency_name
end

#package_managerObject (readonly)

Returns the value of attribute package_manager.



15
16
17
# File 'lib/dependabot/security_advisory.rb', line 15

def package_manager
  @package_manager
end

#safe_versionsObject (readonly)

Returns the value of attribute safe_versions.



21
22
23
# File 'lib/dependabot/security_advisory.rb', line 21

def safe_versions
  @safe_versions
end

#vulnerable_version_stringsObject (readonly)

Returns the value of attribute vulnerable_version_strings.



24
25
26
# File 'lib/dependabot/security_advisory.rb', line 24

def vulnerable_version_strings
  @vulnerable_version_strings
end

#vulnerable_versionsObject (readonly)

Returns the value of attribute vulnerable_versions.



18
19
20
# File 'lib/dependabot/security_advisory.rb', line 18

def vulnerable_versions
  @vulnerable_versions
end

Instance Method Details

#affects_version?(version) ⇒ Boolean

Returns:

  • (Boolean)


103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
# File 'lib/dependabot/security_advisory.rb', line 103

def affects_version?(version)
  return false unless version_class.correct?(version)
  return false unless [*safe_versions, *vulnerable_versions].any?

  version = version_class.new(version)

  # If version is known safe for this advisory, it's not vulnerable
  return false if safe_versions.any? { |r| r.satisfied_by?(version) }

  # If in the vulnerable range and not known safe, it's vulnerable
  return true if vulnerable_versions.any? { |r| r.satisfied_by?(version) }

  # If a vulnerable range present but not met, it's not vulnerable
  return false if vulnerable_versions.any?

  # Finally, if no vulnerable range provided, but a safe range provided,
  # and this versions isn't included (checked earlier), it's vulnerable
  safe_versions.any?
end

#fixed_by?(dependency) ⇒ Boolean

Returns:

  • (Boolean)


78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
# File 'lib/dependabot/security_advisory.rb', line 78

def fixed_by?(dependency)
  # Handle case mismatch between the security advisory and parsed name
  return false unless dependency_name.casecmp(dependency.name)&.zero?
  return false unless package_manager == dependency.package_manager
  # TODO: Support no previous version to the same level as dependency graph
  # and security alerts. We currently ignore dependency updates without a
  # previous version because we don't know if the dependency was vulnerable.
  return false unless dependency.previous_version
  return false unless version_class.correct?(dependency.previous_version)

  # Ignore deps that weren't previously vulnerable
  return false unless affects_version?(T.must(dependency.previous_version))

  # Removing a dependency is a way to fix the vulnerability
  return true if dependency.removed?

  # Select deps that are now fixed
  !affects_version?(T.must(dependency.version))
end

#vulnerable?(version) ⇒ Boolean

Returns:

  • (Boolean)


52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
# File 'lib/dependabot/security_advisory.rb', line 52

def vulnerable?(version)
  in_safe_range = safe_versions
                  .any? { |r| r.satisfied_by?(version) }

  # If version is known safe for this advisory, it's not vulnerable
  return false if in_safe_range

  in_vulnerable_range = vulnerable_versions
                        .any? { |r| r.satisfied_by?(version) }

  # If in the vulnerable range and not known safe, it's vulnerable
  return true if in_vulnerable_range

  # If a vulnerable range present but not met, it's not vulnerable
  return false if vulnerable_versions.any?

  # Finally, if no vulnerable range provided, but a safe range provided,
  # and this versions isn't included (checked earlier), it's vulnerable
  safe_versions.any?
end