Class: Homebrew::Vulns::AdvisoryDatabase Private
- Inherits:
-
CachedFeed
- Object
- CachedFeed
- Homebrew::Vulns::AdvisoryDatabase
- Defined in:
- vulns/advisory_database.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.
Reader for the concatenated BREW-* OSV corpus published by
Homebrew/advisory-database at data/advisories.json (built by that
repository's AdvisoryIndex via rake advisories:concat).
Consumed by brew generate-formula-api to attach a vulnerabilities
field to each formula's API JSON, and by brew vulns (Phase 4) as the
local ecosystem: Homebrew range source until osv.dev ingests the feed.
Defined Under Namespace
Classes: Entry
Constant Summary collapse
- DATA_URL =
This constant is part of a private API. This constant may only be used in the Homebrew/brew repository. Third parties should avoid using this constant if possible, as it may be removed or changed without warning.
"https://raw.githubusercontent.com/Homebrew/advisory-database/" \ "main/data/advisories.json"
Instance Attribute Summary collapse
- #meta ⇒ Hash{String => T.untyped} readonly private
Class Method Summary collapse
- .cache_filename ⇒ String private
- .data_url ⇒ String private
Instance Method Summary collapse
- #formulae ⇒ Array<String> private
- #initialize(data) ⇒ void constructor private
-
#records_for(formula_name) ⇒ Array<Vulnerability>
private
Vulnerability wrappers for every
BREW-*record whoseaffected[0].package.nameisformula_name. -
#status_for(formula_name, pkg_version) ⇒ Hash{String => T.untyped}?
private
Evaluate every record for
formula_nameagainstpkg_versionand return the{open:, patched:}shape used by the formula API JSON andbrew info.
Methods inherited from CachedFeed
#as_hash, default_max_age, from_file, load, refresh
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.
27 28 29 30 31 32 33 34 35 36 37 |
# File 'vulns/advisory_database.rb', line 27 def initialize(data) super raise Error, "advisory index is not a JSON object" unless (top = as_hash(data)) raise Error, "advisory index has no 'advisories' key" unless top.key?("advisories") unless (advisories = as_hash(top["advisories"])) raise Error, "advisory index 'advisories' is not a JSON object" end @advisories = T.let(advisories, T::Hash[String, T.untyped]) @meta = T.let(as_hash(top["meta"]) || {}, T::Hash[String, T.untyped]) end |
Instance Attribute Details
#meta ⇒ 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.
40 41 42 |
# File 'vulns/advisory_database.rb', line 40 def @meta end |
Class Method Details
.cache_filename ⇒ 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.
24 |
# File 'vulns/advisory_database.rb', line 24 def self.cache_filename = "advisories.json" |
.data_url ⇒ 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.
21 |
# File 'vulns/advisory_database.rb', line 21 def self.data_url = DATA_URL |
Instance Method Details
#formulae ⇒ Array<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.
43 44 45 |
# File 'vulns/advisory_database.rb', line 43 def formulae @advisories.keys end |
#records_for(formula_name) ⇒ 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.
Vulnerability wrappers for every BREW-* record whose
affected[0].package.name is formula_name.
50 51 52 53 54 |
# File 'vulns/advisory_database.rb', line 50 def records_for(formula_name) Array(@advisories[formula_name]).filter_map do |record| Vulnerability.new(record) if record.is_a?(Hash) end end |
#status_for(formula_name, pkg_version) ⇒ Hash{String => T.untyped}?
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.
Evaluate every record for formula_name against pkg_version and
return the {open:, patched:} shape used by the formula API JSON and
brew info. open are records whose ECOSYSTEM range still contains
pkg_version; patched are records where ecosystem_specific.fix is
"patch" (Homebrew ships a resolves-annotated patch); fixed_count
counts bump-fixed records that no longer apply. Returns nil when the
corpus has no records for the formula so callers can distinguish
"checked, clean" from "not covered".
75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 |
# File 'vulns/advisory_database.rb', line 75 def status_for(formula_name, pkg_version) records = records_for(formula_name) return if records.empty? version = pkg_version.to_s open = T.let([], T::Array[Entry]) patched = T.let([], T::Array[Entry]) fixed_count = 0 records.each do |vuln| eco = vuln.affected.first&.dig("ecosystem_specific") || {} status = vuln.range_status("Homebrew", formula_name, version) entry = Entry.new( id: vuln.id, upstream: vuln.upstream.presence || vuln.aliases.presence, summary: vuln.summary, severity: vuln.severity&.to_s, fix: eco["fix"], fixed_in: status&.fixed_in, ).freeze case status&.state when nil, :affected then open << entry when :fixed if eco["fix"] == "patch" patched << entry else fixed_count += 1 end when :not_applicable then next end end { "open" => open.sort_by(&:id).map(&:to_api_hash), "patched" => patched.sort_by(&:id).map(&:to_api_hash), "fixed_count" => fixed_count, } end |