diff --git a/Library/Homebrew/test/vulns/advisory_database_spec.rb b/Library/Homebrew/test/vulns/advisory_database_spec.rb index 4ff6558656..a52a24a1bb 100644 --- a/Library/Homebrew/test/vulns/advisory_database_spec.rb +++ b/Library/Homebrew/test/vulns/advisory_database_spec.rb @@ -31,7 +31,12 @@ RSpec.describe Homebrew::Vulns::AdvisoryDatabase do it "raises Error when the advisories key is missing" do expect { described_class.new({ "meta" => {} }) } - .to raise_error(Homebrew::Vulns::CachedFeed::Error, /missing 'advisories' key/) + .to raise_error(Homebrew::Vulns::CachedFeed::Error, /no 'advisories' key/) + end + + it "distinguishes a wrong-type advisories value from a missing key" do + expect { described_class.new({ "advisories" => [] }) } + .to raise_error(Homebrew::Vulns::CachedFeed::Error, /'advisories' is not a JSON object/) end end @@ -89,6 +94,19 @@ RSpec.describe Homebrew::Vulns::AdvisoryDatabase do expect(corpus.status_for("nope", "1.0")).to be_nil end + it "ignores :not_applicable records rather than counting them as fixed or patched" do + d = db({ "foo" => [ + record("BREW-foo-CVE-1", "foo", + events: [{ "introduced" => "2.0" }, { "fixed" => "3.0" }], fix: "bump"), + record("BREW-foo-CVE-2", "foo", + events: [{ "introduced" => "2.0" }, { "fixed" => "3.0" }], fix: "patch"), + ] }) + status = d.status_for("foo", "1.0") + expect(status["open"]).to eq [] + expect(status["patched"]).to eq [] + expect(status["fixed_count"]).to eq 0 + end + it "compacts nil fields out of each entry hash" do status = corpus.status_for("unzip", "6.0_29") expect(status["open"].first.keys).to eq %w[id upstream] diff --git a/Library/Homebrew/vulns/advisory_database.rb b/Library/Homebrew/vulns/advisory_database.rb index b4fe35736f..d284c4a6c3 100644 --- a/Library/Homebrew/vulns/advisory_database.rb +++ b/Library/Homebrew/vulns/advisory_database.rb @@ -27,7 +27,10 @@ module Homebrew def initialize(data) super raise Error, "advisory index is not a JSON object" unless (top = as_hash(data)) - raise Error, "advisory index missing 'advisories' key" unless (advisories = as_hash(top["advisories"])) + 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]) @@ -89,12 +92,15 @@ module Homebrew fix: eco["fix"], fixed_in: status&.fixed_in, ).freeze - if status.nil? || status.affected? - open << entry - elsif eco["fix"] == "patch" - patched << entry - else - fixed_count += 1 + 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