Skip to content

Commit

Permalink
feat(vulnerabilities): Support the CVSS 4 qualitative severity rating…
Browse files Browse the repository at this point in the history
… scale

Note that the rating scale did not actually change from CVSS 3. Still
add a separate class for cleaner semantics.

Signed-off-by: Sebastian Schuberth <[email protected]>
  • Loading branch information
sschuberth committed Nov 3, 2023
1 parent 6c25e2c commit 2416358
Show file tree
Hide file tree
Showing 4 changed files with 109 additions and 0 deletions.
53 changes: 53 additions & 0 deletions model/src/main/kotlin/vulnerabilities/Cvss4Rating.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
/*
* Copyright (C) 2021 The ORT Project Authors (see <https://github.com/oss-review-toolkit/ort/blob/main/NOTICE>)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* SPDX-License-Identifier: Apache-2.0
* License-Filename: LICENSE
*/

package org.ossreviewtoolkit.model.vulnerabilities

/**
* The rating attaches human-readable semantics to the score number according to CVSS version 4, see
* https://www.first.org/cvss/v4.0/specification-document#Qualitative-Severity-Rating-Scale.
*/
enum class Cvss4Rating(private val upperBound: Float) {
NONE(0.0f),
LOW(4.0f),
MEDIUM(7.0f),
HIGH(9.0f),
CRITICAL(10.0f);

companion object {
/**
* A set of names that refer to the CVSS version 4 scoring system.
*/
val NAMES = setOf("CVSS4", "CVSSV4", "CVSS:4.0")

/**
* Get the [Cvss4Rating] from a [score], or null if the [score] does not map to any [Cvss4Rating].
*/
fun fromScore(score: Float): Cvss4Rating? =
when {
score < 0.0f || score > CRITICAL.upperBound -> null
score == NONE.upperBound -> NONE
score < LOW.upperBound -> LOW
score < MEDIUM.upperBound -> MEDIUM
score < HIGH.upperBound -> HIGH
score <= CRITICAL.upperBound -> CRITICAL
else -> null
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ data class VulnerabilityReference(
when (scoringSystem?.uppercase()) {
in Cvss2Rating.NAMES -> severity?.toFloatOrNull()?.let { Cvss2Rating.fromScore(it) }?.toString()
in Cvss3Rating.NAMES -> severity?.toFloatOrNull()?.let { Cvss3Rating.fromScore(it) }?.toString()
in Cvss4Rating.NAMES -> severity?.toFloatOrNull()?.let { Cvss4Rating.fromScore(it) }?.toString()
else -> severity?.uppercase()?.takeIf { it in CVSS3_SEVERITIES }
} ?: "UNKNOWN"
}
Expand Down
47 changes: 47 additions & 0 deletions model/src/test/kotlin/vulnerabilities/Cvss4RatingTest.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
/*
* Copyright (C) 2021 The ORT Project Authors (see <https://github.com/oss-review-toolkit/ort/blob/main/NOTICE>)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* SPDX-License-Identifier: Apache-2.0
* License-Filename: LICENSE
*/

package org.ossreviewtoolkit.model.vulnerabilities

import io.kotest.core.spec.style.StringSpec
import io.kotest.matchers.nulls.beNull
import io.kotest.matchers.should
import io.kotest.matchers.shouldBe

class Cvss4RatingTest : StringSpec({
"The CVSS 4 rating should be correct for a given score" {
Cvss4Rating.fromScore(-0.1f) should beNull()

Cvss4Rating.fromScore(0.0f) shouldBe Cvss4Rating.NONE

Cvss4Rating.fromScore(0.1f) shouldBe Cvss4Rating.LOW
Cvss4Rating.fromScore(3.9f) shouldBe Cvss4Rating.LOW

Cvss4Rating.fromScore(4.0f) shouldBe Cvss4Rating.MEDIUM
Cvss4Rating.fromScore(6.9f) shouldBe Cvss4Rating.MEDIUM

Cvss4Rating.fromScore(7.0f) shouldBe Cvss4Rating.HIGH
Cvss4Rating.fromScore(8.9f) shouldBe Cvss4Rating.HIGH

Cvss4Rating.fromScore(9.0f) shouldBe Cvss4Rating.CRITICAL
Cvss4Rating.fromScore(10.0f) shouldBe Cvss4Rating.CRITICAL

Cvss4Rating.fromScore(10.1f) should beNull()
}
})
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,14 @@ class VulnerabilityReferenceTest : StringSpec({
VulnerabilityReference.getSeverityString("CVSS3", "9.0") shouldBe "CRITICAL"
}

"The severity string should be correct for a given CVSS 4 score" {
VulnerabilityReference.getSeverityString("CVSS4", "0.0") shouldBe "NONE"
VulnerabilityReference.getSeverityString("CVSSV4", "1.0") shouldBe "LOW"
VulnerabilityReference.getSeverityString("CVSS:4.0", "5.0") shouldBe "MEDIUM"
VulnerabilityReference.getSeverityString("CVSS4", "8.0") shouldBe "HIGH"
VulnerabilityReference.getSeverityString("CVSS4", "9.0") shouldBe "CRITICAL"
}

"The severity string should be correct for a given qualitative rating from an unknown scoring system" {
VulnerabilityReference.getSeverityString("", "NONE") shouldBe "NONE"
VulnerabilityReference.getSeverityString("", "LOW") shouldBe "LOW"
Expand Down

0 comments on commit 2416358

Please sign in to comment.