Skip to content

Commit

Permalink
feat: added adapter for osv scanner
Browse files Browse the repository at this point in the history
- osv scanner adapter generates KPIs by using the existing CveAdapter
- Additional data models for osv detail results are provided, however they are not parsed by default to keep the parsing logic as small as possible to be robust against changes
  • Loading branch information
janniclas committed Nov 13, 2024
1 parent 5f9ae19 commit 976122f
Show file tree
Hide file tree
Showing 16 changed files with 3,631 additions and 7 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,10 @@ sealed class AdapterResult {

class KpiTechLag(rawValueKpi: RawValueKpi, val techLag: TechLagResult.Success) :
Success(rawValueKpi)

override fun toString(): String {
return "[Adapter Result Success]: $rawValueKpi"
}
}

data class Error(val type: ErrorType) : AdapterResult()
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
/*
* Copyright (c) 2024 Fraunhofer IEM. All rights reserved.
*
* Licensed under the MIT license. See LICENSE file in the project root for details.
*
* SPDX-License-Identifier: MIT
* License-Filename: LICENSE
*/

package de.fraunhofer.iem.spha.adapter.tools.osv

import de.fraunhofer.iem.spha.adapter.AdapterResult
import de.fraunhofer.iem.spha.adapter.kpis.cve.CveAdapter
import de.fraunhofer.iem.spha.model.adapter.osv.OsvScannerDto
import de.fraunhofer.iem.spha.model.adapter.vulnerability.VulnerabilityDto
import java.io.InputStream
import kotlinx.serialization.ExperimentalSerializationApi
import kotlinx.serialization.json.Json
import kotlinx.serialization.json.decodeFromStream

object OsvAdapter {
private val jsonParser = Json {
ignoreUnknownKeys = true
explicitNulls = false
}

@OptIn(ExperimentalSerializationApi::class)
fun dtoFromJson(jsonData: InputStream): OsvScannerDto {
return jsonParser.decodeFromStream<OsvScannerDto>(jsonData)
}

fun transformDataToKpi(data: OsvScannerDto): Collection<AdapterResult> {
return transformDataToKpi(listOf(data))
}

fun transformDataToKpi(data: Collection<OsvScannerDto>): Collection<AdapterResult> {
return CveAdapter.transformCodeVulnerabilityToKpi(
data.flatMap { results ->
results.results.flatMap { result ->
result.packages.flatMap { pkg ->
pkg.groups.mapNotNull { group ->
val severity = group.maxSeverity.toDoubleOrNull()
if (severity == null) {
null
} else {
VulnerabilityDto(
cveIdentifier = group.ids.first(),
packageName = pkg.osvPackage.name,
severity = severity,
version = pkg.osvPackage.version,
)
}
}
}
}
}
)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -91,9 +91,13 @@ object TrivyAdapter {
val cvssData = it.cvss!!.values.map { jsonParser.decodeFromJsonElement<CVSSData>(it) }

val score = getHighestCvssScore(cvssData)
val packageID = "${it.pkgName}@${it.installedVersion}"
logger.trace { "Selected CVSS score $score for vulnerability '${it.vulnerabilityID}'" }
VulnerabilityDto(it.vulnerabilityID, packageID, score)
VulnerabilityDto(
cveIdentifier = it.vulnerabilityID,
packageName = it.pkgName,
version = it.installedVersion,
severity = score,
)
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ class CveAdapterTest {
cveIdentifier = "not blank",
packageName = "not blank",
severity = 0.1,
version = "0.0.1",
)
)
)
Expand All @@ -44,17 +45,29 @@ class CveAdapterTest {
val invalidKpis =
CveAdapter.transformCodeVulnerabilityToKpi(
listOf(
VulnerabilityDto(cveIdentifier = "not blank", packageName = "", severity = 0.1),
VulnerabilityDto(cveIdentifier = "", packageName = "not blank", severity = 0.1),
VulnerabilityDto(
cveIdentifier = "not blank",
packageName = "",
severity = 0.1,
version = "0.0.1",
),
VulnerabilityDto(
cveIdentifier = "",
packageName = "not blank",
severity = 0.1,
version = "0.0.1",
),
VulnerabilityDto(
cveIdentifier = "not blank",
packageName = "not blank",
severity = -0.1,
version = "0.0.1",
),
VulnerabilityDto(
cveIdentifier = "not blank",
packageName = "not blank",
severity = 10.1,
version = "0.0.1",
),
)
)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
/*
* Copyright (c) 2024 Fraunhofer IEM. All rights reserved.
*
* Licensed under the MIT license. See LICENSE file in the project root for details.
*
* SPDX-License-Identifier: MIT
* License-Filename: LICENSE
*/

package de.fraunhofer.iem.spha.adapter.tools.osv

import de.fraunhofer.iem.spha.adapter.AdapterResult
import java.nio.file.Files
import kotlin.io.path.Path
import kotlin.test.Test
import kotlin.test.assertEquals
import org.junit.jupiter.api.assertDoesNotThrow
import org.junit.jupiter.api.assertThrows
import org.junit.jupiter.params.ParameterizedTest
import org.junit.jupiter.params.provider.ValueSource

class OsvAdapterTest {
@ParameterizedTest
@ValueSource(
strings =
[
"{}", // No schema
"{\"SchemaVersion\": 3}", // Not supported schema
]
)
fun testInvalidJson(input: String) {
input.byteInputStream().use {
assertThrows<UnsupportedOperationException> { OsvAdapter.dtoFromJson(it) }
}
}

@ParameterizedTest
@ValueSource(strings = ["{\"results\": []}"])
fun testEmptyDto(input: String) {
input.byteInputStream().use {
val dto = OsvAdapter.dtoFromJson(it)
assertEquals(0, dto.results.count())
}
}

@Test
fun testResultDto() {
Files.newInputStream(Path("src/test/resources/osv-scanner.json")).use {
val dto = assertDoesNotThrow { OsvAdapter.dtoFromJson(it) }

val kpis = assertDoesNotThrow { OsvAdapter.transformDataToKpi(dto) }

assertEquals(8, kpis.size)

kpis.forEach { assert(it is AdapterResult.Success) }

val smallest = kpis.minByOrNull { (it as AdapterResult.Success).rawValueKpi.score }!!
assertEquals(0, (smallest as AdapterResult.Success).rawValueKpi.score)
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -79,9 +79,9 @@ class TrivyAdapterTest {
mockkObject(CveAdapter)
val vulns =
listOf(
VulnerabilityDto("CVE-1", "A", 1.0),
VulnerabilityDto("CVE-2", "B", 2.0),
VulnerabilityDto("CVE-3", "C", 1.3),
VulnerabilityDto("CVE-1", "A", "1.0", severity = 1.0),
VulnerabilityDto("CVE-2", "B", "2.0", severity = 2.0),
VulnerabilityDto("CVE-3", "C", "1.3", severity = 1.3),
)

TrivyAdapter.transformDataToKpi(TrivyDto(vulns))
Expand Down
37 changes: 37 additions & 0 deletions adapter/src/test/resources/osv-debian.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
{
"id": "DSA-3029-1",
"summary": "nginx - security update",
"affected": [
{
"package": {
"ecosystem": "Debian:7",
"name": "nginx"
},
"ranges": [
{
"type": "ECOSYSTEM",
"events": [
{
"introduced": "0"
},
{
"fixed": "1.2.1-2.2+wheezy3"
}
]
}
]
}
],
"aliases": [
"CVE-2014-3616"
],
"published": "2014-09-20T00:00:00Z",
"modified": "2014-09-20T08:18:07Z",
"details": "\nAntoine Delignat-Lavaud and Karthikeyan Bhargavan discovered that it was\npossible to reuse cached SSL sessions in unrelated contexts, allowing\nvirtual host confusion attacks in some configurations by an attacker in\na privileged network position.\n\n\nFor the stable distribution (wheezy), this problem has been fixed in\nversion 1.2.1-2.2+wheezy3.\n\n\nFor the testing distribution (jessie), this problem has been fixed in\nversion 1.6.2-1.\n\n\nFor the unstable distribution (sid), this problem has been fixed in\nversion 1.6.2-1.\n\n\nWe recommend that you upgrade your nginx packages.\n\n\n",
"references": [
{
"type": "ADVISORY",
"url": "https://www.debian.org/security/2014/dsa-3029"
}
]
}
75 changes: 75 additions & 0 deletions adapter/src/test/resources/osv-npm.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
{
"schema_version": "1.2.0",
"id": "GHSA-r9p9-mrjm-926w",
"modified": "2021-03-08T16:02:43Z",
"published": "2021-03-08T16:06:50Z",
"aliases": [
"CVE-2020-28498"
],
"summary": "Use of a Broken or Risky Cryptographic Algorithm",
"details": "The npm package `elliptic` before version 6.5.4 are vulnerable to Cryptographic Issues via the secp256k1 implementation in elliptic/ec/key.js. There is no check to confirm that the public key point passed into the derive function actually exists on the secp256k1 curve. This results in the potential for the private key used in this implementation to be revealed after a number of ECDH operations are performed.",
"severity": [
{
"type": "CVSS_V3",
"score": "CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:C/C:H/I:N/A:N"
}
],
"affected": [
{
"package": {
"ecosystem": "npm",
"name": "elliptic"
},
"ranges": [
{
"type": "ECOSYSTEM",
"events": [
{
"introduced": "0"
},
{
"fixed": "6.5.4"
}
]
}
]
}
],
"references": [
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2020-28498"
},
{
"type": "WEB",
"url": "https://github.com/indutny/elliptic/pull/244/commits"
},
{
"type": "WEB",
"url": "https://github.com/indutny/elliptic/commit/441b7428b0e8f6636c42118ad2aaa186d3c34c3f"
},
{
"type": "WEB",
"url": "https://github.com/christianlundkvist/blog/blob/master/2020_05_26_secp256k1_twist_attacks/secp256k1_twist_attacks.md"
},
{
"type": "WEB",
"url": "https://snyk.io/vuln/SNYK-JAVA-ORGWEBJARSNPM-1069836"
},
{
"type": "WEB",
"url": "https://snyk.io/vuln/SNYK-JS-ELLIPTIC-1064899"
},
{
"type": "WEB",
"url": "https://www.npmjs.com/package/elliptic"
}
],
"database_specific": {
"cwe_ids": [
"CWE-327"
],
"severity": "MODERATE",
"github_reviewed": true
}
}
36 changes: 36 additions & 0 deletions adapter/src/test/resources/osv-osv.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
{
"schema_version": "1.2.0",
"id": "OSV-2020-584",
"published": "2020-07-01T00:00:18.401815Z",
"modified": "2021-03-09T04:49:05.965964Z",
"summary": "Heap-buffer-overflow in collator_compare_fuzzer.cpp",
"details": "OSS-Fuzz report: https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=15499\nCrash type: Heap-buffer-overflow WRITE 3\nCrash state:\ncollator_compare_fuzzer.cpp\n",
"references": [
{
"type": "REPORT",
"url": "https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=15499"
}
],
"affected": [
{
"package": {
"ecosystem": "OSS-Fuzz",
"name": "icu"
},
"ranges": [
{
"type": "GIT",
"repo": "https://github.com/unicode-org/icu.git",
"events": [
{
"introduced": "6e5755a2a833bc64852eae12967d0a54d7adf629"
},
{
"fixed": "c43455749b914feef56b178b256f29b3016146eb"
}
]
}
]
}
]
}
Loading

0 comments on commit 976122f

Please sign in to comment.