Skip to content

Commit 2464e66

Browse files
committed
Introduce logic for cvss_v4 severity
1 parent da0eff0 commit 2464e66

File tree

7 files changed

+242
-19
lines changed

7 files changed

+242
-19
lines changed

ChangeLog.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
### 0.10.0 / [TBD]
2+
3+
* Added {Bundler::Audit::Advisory#cvss_v4} (@onshi).
4+
15
### 0.9.2 / 2024-08-22
26

37
* Officially support Ruby 3.2 and 3.3.

lib/bundler/audit/advisory.rb

Lines changed: 39 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ class Advisory < Struct.new(:path,
3131
:description,
3232
:cvss_v2,
3333
:cvss_v3,
34+
:cvss_v4,
3435
:cve,
3536
:osvdb,
3637
:ghsa,
@@ -77,6 +78,7 @@ def self.load(path)
7778
data['description'],
7879
data['cvss_v2'],
7980
data['cvss_v3'],
81+
data['cvss_v4'],
8082
data['cve'],
8183
data['osvdb'],
8284
data['ghsa'],
@@ -136,20 +138,43 @@ def identifiers
136138
# The criticality of the vulnerability based on the CVSS score.
137139
#
138140
def criticality
139-
if cvss_v3
140-
case cvss_v3
141-
when 0.0 then :none
142-
when 0.1..3.9 then :low
143-
when 4.0..6.9 then :medium
144-
when 7.0..8.9 then :high
145-
when 9.0..10.0 then :critical
146-
end
147-
elsif cvss_v2
148-
case cvss_v2
149-
when 0.0..3.9 then :low
150-
when 4.0..6.9 then :medium
151-
when 7.0..10.0 then :high
152-
end
141+
return estimate_criticality(cvss_v4) if cvss_v4
142+
return estimate_criticality(cvss_v3) if cvss_v3
143+
144+
estimate_criticality_cvss_v2(cvss_v2) if cvss_v2
145+
end
146+
147+
#
148+
# Estimates criticality score based on CVSS v3 or CVSS v4 standard and criticality value.
149+
#
150+
# @param [Float] criticality_value
151+
# The criticality score calculated using given standard.
152+
# @return [:none, :low, :medium, :high, :critical, nil]
153+
# The criticality of the vulnerability based on the CVSS score.
154+
#
155+
def estimate_criticality(criticality_value)
156+
case criticality_value
157+
when 0.0 then :none
158+
when 0.1..3.9 then :low
159+
when 4.0..6.9 then :medium
160+
when 7.0..8.9 then :high
161+
when 9.0..10.0 then :critical
162+
end
163+
end
164+
165+
#
166+
# Estimates criticality score based on CVSS v2 standard and criticality value.
167+
#
168+
# @param [Float] criticality_value
169+
# The criticality score calculated using given standard.
170+
# @return [:none, :low, :medium, :high, :critical, nil]
171+
# The criticality of the vulnerability based on the CVSS score.
172+
#
173+
def estimate_criticality_cvss_v2(criticality_value)
174+
case criticality_value
175+
when 0.0..3.9 then :low
176+
when 4.0..6.9 then :medium
177+
when 7.0..10.0 then :high
153178
end
154179
end
155180

lib/bundler/audit/version.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,6 @@
1818
module Bundler
1919
module Audit
2020
# bundler-audit version
21-
VERSION = '0.9.2'
21+
VERSION = "0.10.0"
2222
end
2323
end

spec/advisory_spec.rb

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,11 @@
8686
it { is_expected.to eq(data['cvss_v3']) }
8787
end
8888

89+
describe '#cvss_v4' do
90+
subject { super().cvss_v4 }
91+
it { is_expected.to eq(data['cvss_v4']) }
92+
end
93+
8994
describe '#description' do
9095
subject { super().description }
9196
it { is_expected.to eq(data['description']) }
@@ -289,6 +294,56 @@
289294

290295
it { expect(subject.criticality).to eq(:critical) }
291296
end
297+
298+
context "when cvss_v4 is 0.0" do
299+
subject do
300+
described_class.new.tap do |advisory|
301+
advisory.cvss_v4 = 0.0
302+
end
303+
end
304+
305+
it { expect(subject.criticality).to eq(:none) }
306+
end
307+
308+
context "when cvss_v4 is between 0.1 and 3.9" do
309+
subject do
310+
described_class.new.tap do |advisory|
311+
advisory.cvss_v4 = 3.9
312+
end
313+
end
314+
315+
it { expect(subject.criticality).to eq(:low) }
316+
end
317+
318+
context "when cvss_v4 is between 4.0 and 6.9" do
319+
subject do
320+
described_class.new.tap do |advisory|
321+
advisory.cvss_v4 = 6.9
322+
end
323+
end
324+
325+
it { expect(subject.criticality).to eq(:medium) }
326+
end
327+
328+
context "when cvss_v4 is between 7.0 and 8.9" do
329+
subject do
330+
described_class.new.tap do |advisory|
331+
advisory.cvss_v4 = 8.9
332+
end
333+
end
334+
335+
it { expect(subject.criticality).to eq(:high) }
336+
end
337+
338+
context "when cvss_v4 is between 9.0 and 10.0" do
339+
subject do
340+
described_class.new.tap do |advisory|
341+
advisory.cvss_v4 = 10.0
342+
end
343+
end
344+
345+
it { expect(subject.criticality).to eq(:critical) }
346+
end
292347
end
293348

294349
describe "#unaffected?" do

spec/cli/formats/junit_spec.rb

Lines changed: 71 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -111,8 +111,76 @@
111111
end
112112
end
113113

114+
context "when CVSS v4 is present" do
115+
context "when Advisory#criticality is :none" do
116+
let(:advisory) do
117+
super().tap do |advisory|
118+
advisory.cvss_v4 = 0.0
119+
end
120+
end
121+
122+
it "must print 'Criticality: None'" do
123+
expect(output).to include("Criticality: None")
124+
end
125+
end
126+
127+
context "when Advisory#criticality is :low" do
128+
let(:advisory) do
129+
super().tap do |advisory|
130+
advisory.cvss_v4 = 0.1
131+
end
132+
end
133+
134+
it "must print 'Criticality: Low'" do
135+
expect(output).to include("Criticality: Low")
136+
end
137+
end
138+
139+
context "when Advisory#criticality is :medium" do
140+
let(:advisory) do
141+
super().tap do |advisory|
142+
advisory.cvss_v4 = 4.0
143+
end
144+
end
145+
146+
it "must print 'Criticality: Medium'" do
147+
expect(output).to include("Criticality: Medium")
148+
end
149+
end
150+
151+
context "when Advisory#criticality is :high" do
152+
let(:advisory) do
153+
super().tap do |advisory|
154+
advisory.cvss_v4 = 7.0
155+
end
156+
end
157+
158+
it "must print 'Criticality: High'" do
159+
expect(output).to include("Criticality: High")
160+
end
161+
end
162+
163+
context "when Advisory#criticality is :critical" do
164+
let(:advisory) do
165+
super().tap do |advisory|
166+
advisory.cvss_v4 = 9.0
167+
end
168+
end
169+
170+
it "must print 'Criticality: High'" do
171+
expect(output).to include("Criticality: Critical")
172+
end
173+
end
174+
end
175+
114176
context "when CVSS v3 is present" do
115-
context "when Advisory#criticality is :none (cvss_v3 only)" do
177+
let(:advisory) do
178+
super().tap do |advisory|
179+
advisory.cvss_v4 = nil
180+
end
181+
end
182+
183+
context "when Advisory#criticality is :none" do
116184
let(:advisory) do
117185
super().tap do |advisory|
118186
advisory.cvss_v3 = 0.0
@@ -160,7 +228,7 @@
160228
end
161229
end
162230

163-
context "when Advisory#criticality is :critical (cvss_v3 only)" do
231+
context "when Advisory#criticality is :critical" do
164232
let(:advisory) do
165233
super().tap do |advisory|
166234
advisory.cvss_v3 = 9.0
@@ -177,6 +245,7 @@
177245
let(:advisory) do
178246
super().tap do |advisory|
179247
advisory.cvss_v3 = nil
248+
advisory.cvss_v4 = nil
180249
end
181250
end
182251

spec/cli/formats/text_spec.rb

Lines changed: 71 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -104,8 +104,76 @@
104104
end
105105
end
106106

107+
context "when CVSS v4 is present" do
108+
context "when Advisory#criticality is :none" do
109+
let(:advisory) do
110+
super().tap do |advisory|
111+
advisory.cvss_v4 = 0.0
112+
end
113+
end
114+
115+
it "must print 'Criticality: None'" do
116+
expect(output_lines).to include("Criticality: None")
117+
end
118+
end
119+
120+
context "when Advisory#criticality is :low" do
121+
let(:advisory) do
122+
super().tap do |advisory|
123+
advisory.cvss_v4 = 0.1
124+
end
125+
end
126+
127+
it "must print 'Criticality: Low'" do
128+
expect(output_lines).to include("Criticality: Low")
129+
end
130+
end
131+
132+
context "when Advisory#criticality is :medium" do
133+
let(:advisory) do
134+
super().tap do |advisory|
135+
advisory.cvss_v4 = 4.0
136+
end
137+
end
138+
139+
it "must print 'Criticality: Medium'" do
140+
expect(output_lines).to include("Criticality: Medium")
141+
end
142+
end
143+
144+
context "when Advisory#criticality is :high" do
145+
let(:advisory) do
146+
super().tap do |advisory|
147+
advisory.cvss_v4 = 7.0
148+
end
149+
end
150+
151+
it "must print 'Criticality: High'" do
152+
expect(output_lines).to include("Criticality: High")
153+
end
154+
end
155+
156+
context "when Advisory#criticality is :critical" do
157+
let(:advisory) do
158+
super().tap do |advisory|
159+
advisory.cvss_v4 = 9.0
160+
end
161+
end
162+
163+
it "must print 'Criticality: High'" do
164+
expect(output_lines).to include("Criticality: Critical")
165+
end
166+
end
167+
end
168+
107169
context "when CVSS v3 is present" do
108-
context "when Advisory#criticality is :none (cvss_v3 only)" do
170+
let(:advisory) do
171+
super().tap do |advisory|
172+
advisory.cvss_v4 = nil
173+
end
174+
end
175+
176+
context "when Advisory#criticality is :none" do
109177
let(:advisory) do
110178
super().tap do |advisory|
111179
advisory.cvss_v3 = 0.0
@@ -153,7 +221,7 @@
153221
end
154222
end
155223

156-
context "when Advisory#criticality is :critical (cvss_v3 only)" do
224+
context "when Advisory#criticality is :critical" do
157225
let(:advisory) do
158226
super().tap do |advisory|
159227
advisory.cvss_v3 = 9.0
@@ -170,6 +238,7 @@
170238
let(:advisory) do
171239
super().tap do |advisory|
172240
advisory.cvss_v3 = nil
241+
advisory.cvss_v4 = nil
173242
end
174243
end
175244

spec/fixtures/advisory/CVE-2020-1234.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ description: |
1111
1212
cvss_v2: 10.0
1313
cvss_v3: 9.8
14+
cvss_v4: 9.9
1415

1516
unaffected_versions:
1617
- "< 0.1.0"

0 commit comments

Comments
 (0)