Class: Homebrew::Vulns::Vulnerability Private

Inherits:
Object
  • Object
show all
Includes:
Utils::Output::Mixin
Defined in:
vulns/vulnerability.rb

Overview

This class is part of a private API. This class may only be used in the Homebrew/brew repository. Third parties should avoid using this class if possible, as it may be removed or changed without warning.

Wraps a single OSV vulnerability record. See https://ossf.github.io/osv-schema/ for the field definitions.

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Methods included from Utils::Output::Mixin

#issue_reporting_message, #odebug, #odeprecated, #odie, #odisabled, #ofail, #oh1, #oh1_title, #ohai, #ohai_title, #onoe, #opoo, #opoo_outside_github_actions, #opoo_without_github_actions_annotation, #pretty_deprecated, #pretty_disabled, #pretty_duration, #pretty_install_status, #pretty_installed, #pretty_uninstalled, #pretty_unmarked, #pretty_upgradable, #pretty_warning

Constructor Details

#initialize(data) ⇒ void

This method is part of a private API. This method may only be used in the Homebrew/brew repository. Third parties should avoid using this method if possible, as it may be removed or changed without warning.

Parameters:



42
43
44
45
46
47
48
49
50
# File 'vulns/vulnerability.rb', line 42

def initialize(data)
  @id = T.let(data.fetch("id"), String)
  @summary = T.let(data["summary"], T.nilable(String))
  @details = T.let(data["details"], T.nilable(String))
  @aliases = T.let(Array(data["aliases"]), T::Array[String])
  @references = T.let(Array(data["references"]), T::Array[T::Hash[String, T.untyped]])
  @affected = T.let(Array(data["affected"]), T::Array[T::Hash[String, T.untyped]])
  @severity = T.let(extract_severity(data), T.nilable(Symbol))
end

Instance Attribute Details

#affectedArray<Hash{String => T.untyped}> (readonly)

This method is part of a private API. This method may only be used in the Homebrew/brew repository. Third parties should avoid using this method if possible, as it may be removed or changed without warning.

Returns:



39
40
41
# File 'vulns/vulnerability.rb', line 39

def affected
  @affected
end

#aliasesArray<String> (readonly)

This method is part of a private API. This method may only be used in the Homebrew/brew repository. Third parties should avoid using this method if possible, as it may be removed or changed without warning.

Returns:



36
37
38
# File 'vulns/vulnerability.rb', line 36

def aliases
  @aliases
end

#detailsString? (readonly)

This method is part of a private API. This method may only be used in the Homebrew/brew repository. Third parties should avoid using this method if possible, as it may be removed or changed without warning.

Returns:



30
31
32
# File 'vulns/vulnerability.rb', line 30

def details
  @details
end

#idString (readonly)

This method is part of a private API. This method may only be used in the Homebrew/brew repository. Third parties should avoid using this method if possible, as it may be removed or changed without warning.

Returns:



27
28
29
# File 'vulns/vulnerability.rb', line 27

def id
  @id
end

#referencesArray<Hash{String => T.untyped}> (readonly)

This method is part of a private API. This method may only be used in the Homebrew/brew repository. Third parties should avoid using this method if possible, as it may be removed or changed without warning.

Returns:



39
40
41
# File 'vulns/vulnerability.rb', line 39

def references
  @references
end

#severitySymbol? (readonly)

This method is part of a private API. This method may only be used in the Homebrew/brew repository. Third parties should avoid using this method if possible, as it may be removed or changed without warning.

Returns:



33
34
35
# File 'vulns/vulnerability.rb', line 33

def severity
  @severity
end

#summaryString? (readonly)

This method is part of a private API. This method may only be used in the Homebrew/brew repository. Third parties should avoid using this method if possible, as it may be removed or changed without warning.

Returns:



30
31
32
# File 'vulns/vulnerability.rb', line 30

def summary
  @summary
end

Class Method Details

.from_osv_list(list) ⇒ Array<Vulnerability>

This method is part of a private API. This method may only be used in the Homebrew/brew repository. Third parties should avoid using this method if possible, as it may be removed or changed without warning.

Parameters:

Returns:



53
54
55
# File 'vulns/vulnerability.rb', line 53

def self.from_osv_list(list)
  list.map { |data| new(data) }
end

Instance Method Details

#advisory_urlString?

This method is part of a private API. This method may only be used in the Homebrew/brew repository. Third parties should avoid using this method if possible, as it may be removed or changed without warning.

Returns:



81
82
83
# File 'vulns/vulnerability.rb', line 81

def advisory_url
  references.find { |r| r["type"] == "ADVISORY" }&.dig("url")
end

#affects_version?(version) ⇒ Boolean

This method is part of a private API. This method may only be used in the Homebrew/brew repository. Third parties should avoid using this method if possible, as it may be removed or changed without warning.

OSV has already matched this record against the queried version. This method only overrides that with false when every affected entry can be evaluated locally (explicit versions list or SEMVER range) and none of them contains the target. Any uncheckable range or comparison failure keeps the match.

Parameters:

Returns:

  • (Boolean)


105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
# File 'vulns/vulnerability.rb', line 105

def affects_version?(version)
  return true if affected.empty?

  target = normalize_version(version)
  checkable = T.let(false, T::Boolean)

  affected.each do |aff|
    versions = Array(aff["versions"])
    if versions.any?
      checkable = true
      return true if versions.any? { |v| normalize_version(v.to_s) == target }
    end

    Array(aff["ranges"]).each do |range|
      return true if range["type"] != "SEMVER"

      checkable = true
      return true if in_semver_range?(target, Array(range["events"]))
    end
  end

  !checkable
end

#cve_idsArray<String>

This method is part of a private API. This method may only be used in the Homebrew/brew repository. Third parties should avoid using this method if possible, as it may be removed or changed without warning.

Returns:



76
77
78
# File 'vulns/vulnerability.rb', line 76

def cve_ids
  identifiers.select { |i| i.start_with?("CVE-") }
end

#extract_severity(data) ⇒ Symbol?

This method is part of a private API. This method may only be used in the Homebrew/brew repository. Third parties should avoid using this method if possible, as it may be removed or changed without warning.

Parameters:

Returns:



130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
# File 'vulns/vulnerability.rb', line 130

def extract_severity(data)
  Array(data["severity"])
    .select { |s| CVSS_TYPE_PRIORITY.key?(s["type"]) }
    .sort_by { |s| -CVSS_TYPE_PRIORITY.fetch(s["type"]) }
    .each do |s|
      sev = CVSS.severity(s["score"].to_s)
      return sev if sev
    end

  top = normalize_severity(data.dig("database_specific", "severity"))
  return top if top

  affected.each do |aff|
    eco = normalize_severity(aff.dig("ecosystem_specific", "severity"))
    return eco if eco

    db = normalize_severity(aff.dig("database_specific", "severity"))
    return db if db
  end

  nil
end

#fix_urlsArray<String>

This method is part of a private API. This method may only be used in the Homebrew/brew repository. Third parties should avoid using this method if possible, as it may be removed or changed without warning.

Returns:



86
87
88
# File 'vulns/vulnerability.rb', line 86

def fix_urls
  references.select { |r| r["type"] == "FIX" }.filter_map { |r| r["url"] }
end

#fixed_versionsArray<String>

This method is part of a private API. This method may only be used in the Homebrew/brew repository. Third parties should avoid using this method if possible, as it may be removed or changed without warning.

Returns:



91
92
93
94
95
96
97
# File 'vulns/vulnerability.rb', line 91

def fixed_versions
  affected.flat_map do |aff|
    Array(aff["ranges"]).flat_map do |range|
      Array(range["events"]).filter_map { |e| e["fixed"] }
    end
  end.uniq
end

#identifiersArray<String>

This method is part of a private API. This method may only be used in the Homebrew/brew repository. Third parties should avoid using this method if possible, as it may be removed or changed without warning.

Returns:



71
72
73
# File 'vulns/vulnerability.rb', line 71

def identifiers
  [id, *aliases].compact
end

#in_semver_range?(target, events) ⇒ Boolean

This method is part of a private API. This method may only be used in the Homebrew/brew repository. Third parties should avoid using this method if possible, as it may be removed or changed without warning.

Parameters:

Returns:

  • (Boolean)


173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
# File 'vulns/vulnerability.rb', line 173

def in_semver_range?(target, events)
  return false if events.empty?

  intervals(events).any? do |lower, upper, upper_inclusive|
    above = lower.nil? || semver_compare!(target, lower) >= 0
    below = if upper.nil?
      true
    elsif upper_inclusive
      semver_compare!(target, upper) <= 0
    else
      semver_compare!(target, upper).negative?
    end
    above && below
  end
rescue => e
  odebug "Failed to check #{target} against SEMVER range for #{id}: #{e}"
  true
end

#intervals(events) ⇒ Array<Array<([String, nil], [String, nil], Boolean)>>

This method is part of a private API. This method may only be used in the Homebrew/brew repository. Third parties should avoid using this method if possible, as it may be removed or changed without warning.

Parameters:

Returns:



201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
# File 'vulns/vulnerability.rb', line 201

def intervals(events)
  result = []
  lower = T.let(nil, T.nilable(String))

  events.each do |event|
    if (intro = event["introduced"])
      result << [lower, nil, false] if lower
      intro = normalize_version(intro.to_s)
      lower = (intro == "0") ? nil : intro
    elsif (fixed = event["fixed"])
      result << [lower, normalize_version(fixed.to_s), false]
      lower = nil
    elsif (last = event["last_affected"])
      result << [lower, normalize_version(last.to_s), true]
      lower = nil
    elsif (limit = event["limit"])
      limit = limit.to_s
      upper = (limit == "*") ? nil : normalize_version(limit)
      result << [lower, upper, false]
      lower = nil
    end
  end
  result << [lower, nil, false] if lower || result.empty?
  result
end

#normalize_severity(value) ⇒ Symbol?

This method is part of a private API. This method may only be used in the Homebrew/brew repository. Third parties should avoid using this method if possible, as it may be removed or changed without warning.

Parameters:

Returns:



154
155
156
157
158
159
160
161
# File 'vulns/vulnerability.rb', line 154

def normalize_severity(value)
  case value&.downcase
  when "critical" then :critical
  when "high" then :high
  when "medium", "moderate" then :medium
  when "low" then :low
  end
end

#normalize_version(version) ⇒ String

This method is part of a private API. This method may only be used in the Homebrew/brew repository. Third parties should avoid using this method if possible, as it may be removed or changed without warning.

Parameters:

Returns:



164
165
166
# File 'vulns/vulnerability.rb', line 164

def normalize_version(version)
  version.sub(/\Av/i, "")
end

#semver_compare!(left, right) ⇒ Integer

This method is part of a private API. This method may only be used in the Homebrew/brew repository. Third parties should avoid using this method if possible, as it may be removed or changed without warning.

Parameters:

Returns:



193
194
195
# File 'vulns/vulnerability.rb', line 193

def semver_compare!(left, right)
  Semver.compare(left, right) || raise(Uncomparable, "cannot compare #{left.inspect} with #{right.inspect}")
end

#severity_displayString

This method is part of a private API. This method may only be used in the Homebrew/brew repository. Third parties should avoid using this method if possible, as it may be removed or changed without warning.

Returns:



58
59
60
# File 'vulns/vulnerability.rb', line 58

def severity_display
  severity&.to_s&.upcase || "UNKNOWN"
end

#severity_levelInteger

This method is part of a private API. This method may only be used in the Homebrew/brew repository. Third parties should avoid using this method if possible, as it may be removed or changed without warning.

Returns:



63
64
65
66
67
68
# File 'vulns/vulnerability.rb', line 63

def severity_level
  sev = severity
  return 0 if sev.nil?

  SEVERITY_LEVEL.fetch(sev, 0)
end