diff --git a/lib/bundler/audit/advisory.rb b/lib/bundler/audit/advisory.rb index 2e840474..6d65b80e 100644 --- a/lib/bundler/audit/advisory.rb +++ b/lib/bundler/audit/advisory.rb @@ -31,6 +31,7 @@ class Advisory < Struct.new(:path, :description, :cvss_v2, :cvss_v3, + :cvss_v4, :cve, :osvdb, :ghsa, @@ -77,6 +78,7 @@ def self.load(path) data['description'], data['cvss_v2'], data['cvss_v3'], + data['cvss_v4'], data['cve'], data['osvdb'], data['ghsa'], @@ -136,8 +138,8 @@ def identifiers # The criticality of the vulnerability based on the CVSS score. # def criticality - if cvss_v3 - case cvss_v3 + if cvss_v4 || cvss_v3 + case cvss_v4 || cvss_v3 when 0.0 then :none when 0.1..3.9 then :low when 4.0..6.9 then :medium diff --git a/spec/advisory_spec.rb b/spec/advisory_spec.rb index 0395d093..6edd7281 100644 --- a/spec/advisory_spec.rb +++ b/spec/advisory_spec.rb @@ -86,6 +86,11 @@ it { is_expected.to eq(data['cvss_v3']) } end + describe '#cvss_v4' do + subject { super().cvss_v4 } + it { is_expected.to eq(data['cvss_v4']) } + end + describe '#description' do subject { super().description } it { is_expected.to eq(data['description']) } @@ -289,6 +294,56 @@ it { expect(subject.criticality).to eq(:critical) } end + + context "when cvss_v4 is 0.0" do + subject do + described_class.new.tap do |advisory| + advisory.cvss_v4 = 0.0 + end + end + + it { expect(subject.criticality).to eq(:none) } + end + + context "when cvss_v4 is between 0.1 and 3.9" do + subject do + described_class.new.tap do |advisory| + advisory.cvss_v4 = 3.9 + end + end + + it { expect(subject.criticality).to eq(:low) } + end + + context "when cvss_v4 is between 4.0 and 6.9" do + subject do + described_class.new.tap do |advisory| + advisory.cvss_v4 = 6.9 + end + end + + it { expect(subject.criticality).to eq(:medium) } + end + + context "when cvss_v4 is between 7.0 and 8.9" do + subject do + described_class.new.tap do |advisory| + advisory.cvss_v4 = 8.9 + end + end + + it { expect(subject.criticality).to eq(:high) } + end + + context "when cvss_v4 is between 9.0 and 10.0" do + subject do + described_class.new.tap do |advisory| + advisory.cvss_v4 = 10.0 + end + end + + it { expect(subject.criticality).to eq(:critical) } + end end describe "#unaffected?" do diff --git a/spec/cli/formats/junit_spec.rb b/spec/cli/formats/junit_spec.rb index 0d0a2d3a..8f6f52f3 100644 --- a/spec/cli/formats/junit_spec.rb +++ b/spec/cli/formats/junit_spec.rb @@ -111,8 +111,76 @@ end end + context "when CVSS v4 is present" do + context "when Advisory#criticality is :none" do + let(:advisory) do + super().tap do |advisory| + advisory.cvss_v4 = 0.0 + end + end + + it "must print 'Criticality: None'" do + expect(output).to include("Criticality: None") + end + end + + context "when Advisory#criticality is :low" do + let(:advisory) do + super().tap do |advisory| + advisory.cvss_v4 = 0.1 + end + end + + it "must print 'Criticality: Low'" do + expect(output).to include("Criticality: Low") + end + end + + context "when Advisory#criticality is :medium" do + let(:advisory) do + super().tap do |advisory| + advisory.cvss_v4 = 4.0 + end + end + + it "must print 'Criticality: Medium'" do + expect(output).to include("Criticality: Medium") + end + end + + context "when Advisory#criticality is :high" do + let(:advisory) do + super().tap do |advisory| + advisory.cvss_v4 = 7.0 + end + end + + it "must print 'Criticality: High'" do + expect(output).to include("Criticality: High") + end + end + + context "when Advisory#criticality is :critical" do + let(:advisory) do + super().tap do |advisory| + advisory.cvss_v4 = 9.0 + end + end + + it "must print 'Criticality: High'" do + expect(output).to include("Criticality: Critical") + end + end + end + context "when CVSS v3 is present" do - context "when Advisory#criticality is :none (cvss_v3 only)" do + let(:advisory) do + super().tap do |advisory| + advisory.cvss_v4 = nil + end + end + + context "when Advisory#criticality is :none" do let(:advisory) do super().tap do |advisory| advisory.cvss_v3 = 0.0 @@ -160,7 +228,7 @@ end end - context "when Advisory#criticality is :critical (cvss_v3 only)" do + context "when Advisory#criticality is :critical" do let(:advisory) do super().tap do |advisory| advisory.cvss_v3 = 9.0 @@ -177,6 +245,7 @@ let(:advisory) do super().tap do |advisory| advisory.cvss_v3 = nil + advisory.cvss_v4 = nil end end diff --git a/spec/cli/formats/text_spec.rb b/spec/cli/formats/text_spec.rb index 987f291b..f774e8ed 100644 --- a/spec/cli/formats/text_spec.rb +++ b/spec/cli/formats/text_spec.rb @@ -104,8 +104,76 @@ end end + context "when CVSS v4 is present" do + context "when Advisory#criticality is :none" do + let(:advisory) do + super().tap do |advisory| + advisory.cvss_v4 = 0.0 + end + end + + it "must print 'Criticality: None'" do + expect(output_lines).to include("Criticality: None") + end + end + + context "when Advisory#criticality is :low" do + let(:advisory) do + super().tap do |advisory| + advisory.cvss_v4 = 0.1 + end + end + + it "must print 'Criticality: Low'" do + expect(output_lines).to include("Criticality: Low") + end + end + + context "when Advisory#criticality is :medium" do + let(:advisory) do + super().tap do |advisory| + advisory.cvss_v4 = 4.0 + end + end + + it "must print 'Criticality: Medium'" do + expect(output_lines).to include("Criticality: Medium") + end + end + + context "when Advisory#criticality is :high" do + let(:advisory) do + super().tap do |advisory| + advisory.cvss_v4 = 7.0 + end + end + + it "must print 'Criticality: High'" do + expect(output_lines).to include("Criticality: High") + end + end + + context "when Advisory#criticality is :critical" do + let(:advisory) do + super().tap do |advisory| + advisory.cvss_v4 = 9.0 + end + end + + it "must print 'Criticality: High'" do + expect(output_lines).to include("Criticality: Critical") + end + end + end + context "when CVSS v3 is present" do - context "when Advisory#criticality is :none (cvss_v3 only)" do + let(:advisory) do + super().tap do |advisory| + advisory.cvss_v4 = nil + end + end + + context "when Advisory#criticality is :none" do let(:advisory) do super().tap do |advisory| advisory.cvss_v3 = 0.0 @@ -153,7 +221,7 @@ end end - context "when Advisory#criticality is :critical (cvss_v3 only)" do + context "when Advisory#criticality is :critical" do let(:advisory) do super().tap do |advisory| advisory.cvss_v3 = 9.0 @@ -170,6 +238,7 @@ let(:advisory) do super().tap do |advisory| advisory.cvss_v3 = nil + advisory.cvss_v4 = nil end end diff --git a/spec/fixtures/advisory/CVE-2020-1234.yml b/spec/fixtures/advisory/CVE-2020-1234.yml index d01278e3..10996783 100644 --- a/spec/fixtures/advisory/CVE-2020-1234.yml +++ b/spec/fixtures/advisory/CVE-2020-1234.yml @@ -11,6 +11,7 @@ description: | cvss_v2: 10.0 cvss_v3: 9.8 +cvss_v4: 9.9 unaffected_versions: - "< 0.1.0"