Skip to content

Commit

Permalink
feat(reporter): Support the CycloneDX vulnerability extension in Repo…
Browse files Browse the repository at this point in the history
…rter

Signed-off-by: George Andrinopoulos <[email protected]>
  • Loading branch information
geoandri authored and sschuberth committed Nov 1, 2023
1 parent 73e5110 commit d0efc19
Show file tree
Hide file tree
Showing 6 changed files with 115 additions and 23 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,8 @@
"url": "https://github.com/oss-review-toolkit/ort"
}
],
"type": "library"
"type": "library",
"bom-ref": "NPM:@ort:concluded-license:1.0"
},
{
"group": "@ort",
Expand Down Expand Up @@ -124,7 +125,8 @@
"url": "https://github.com/oss-review-toolkit/ort"
}
],
"type": "library"
"type": "library",
"bom-ref": "NPM:@ort:declared-license:1.0"
},
{
"group": "@ort",
Expand Down Expand Up @@ -159,7 +161,8 @@
"url": "https://github.com/oss-review-toolkit/ort"
}
],
"type": "library"
"type": "library",
"bom-ref": "NPM:@ort:license-file:1.0"
},
{
"group": "@ort",
Expand Down Expand Up @@ -204,7 +207,8 @@
"url": "https://github.com/oss-review-toolkit/ort"
}
],
"type": "library"
"type": "library",
"bom-ref": "NPM:@ort:license-file-and-additional-licenses:1.0"
},
{
"group": "@ort",
Expand Down Expand Up @@ -233,7 +237,8 @@
"url": "https://github.com/oss-review-toolkit/ort"
}
],
"type": "library"
"type": "library",
"bom-ref": "NPM:@ort:no-license-file:1.0"
}
],
"externalReferences": [
Expand All @@ -255,4 +260,4 @@
"comment": "Package-URL of the project"
}
]
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,8 @@
"url": "https://github.com/oss-review-toolkit/ort"
}
],
"type": "library"
"type": "library",
"bom-ref": "NPM:@ort:concluded-license:1.0"
},
{
"group": "@ort",
Expand Down Expand Up @@ -124,7 +125,8 @@
"url": "https://github.com/oss-review-toolkit/ort"
}
],
"type": "library"
"type": "library",
"bom-ref": "NPM:@ort:declared-license:1.0"
},
{
"group": "@ort",
Expand Down Expand Up @@ -159,7 +161,8 @@
"url": "https://github.com/oss-review-toolkit/ort"
}
],
"type": "library"
"type": "library",
"bom-ref": "NPM:@ort:license-file:1.0"
},
{
"group": "@ort",
Expand Down Expand Up @@ -204,7 +207,8 @@
"url": "https://github.com/oss-review-toolkit/ort"
}
],
"type": "library"
"type": "library",
"bom-ref": "NPM:@ort:license-file-and-additional-licenses:1.0"
},
{
"group": "@ort",
Expand Down Expand Up @@ -233,7 +237,28 @@
"url": "https://github.com/oss-review-toolkit/ort"
}
],
"type": "library"
"type": "library",
"bom-ref": "NPM:@ort:no-license-file:1.0"
}
],
"vulnerabilities": [
{
"id": "CVE-2021-1234",
"ratings": [
{
"source": {
"url": "https://cves.example.org/cve1"
},
"severity": "medium"
}
],
"description": "A vulnerability description",
"detail": "A vulnerability summary",
"affects": [
{
"ref": "NPM:@ort:declared-license:1.0"
}
]
}
]
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
</licenses>
</metadata>
<components>
<component type="library">
<component type="library" bom-ref="NPM:@ort:concluded-license:1.0">
<group>@ort</group>
<name>concluded-license</name>
<version>1.0</version>
Expand Down Expand Up @@ -49,7 +49,7 @@
<modified>false</modified>
<externalReferences><reference type="website"><url>https://github.com/oss-review-toolkit/ort</url></reference></externalReferences><ort:dependencyType xmlns:ort="http://www.w3.org/1999/xhtml">direct</ort:dependencyType>
</component>
<component type="library">
<component type="library" bom-ref="NPM:@ort:declared-license:1.0">
<group>@ort</group>
<name>declared-license</name>
<version>1.0</version>
Expand All @@ -72,7 +72,7 @@
<modified>false</modified>
<externalReferences><reference type="website"><url>https://github.com/oss-review-toolkit/ort</url></reference></externalReferences><ort:dependencyType xmlns:ort="http://www.w3.org/1999/xhtml">direct</ort:dependencyType>
</component>
<component type="library">
<component type="library" bom-ref="NPM:@ort:license-file:1.0">
<group>@ort</group>
<name>license-file</name>
<version>1.0</version>
Expand All @@ -91,7 +91,7 @@
<modified>false</modified>
<externalReferences><reference type="website"><url>https://github.com/oss-review-toolkit/ort</url></reference></externalReferences><ort:dependencyType xmlns:ort="http://www.w3.org/1999/xhtml">direct</ort:dependencyType>
</component>
<component type="library">
<component type="library" bom-ref="NPM:@ort:license-file-and-additional-licenses:1.0">
<group>@ort</group>
<name>license-file-and-additional-licenses</name>
<version>1.0</version>
Expand All @@ -114,7 +114,7 @@
<modified>false</modified>
<externalReferences><reference type="website"><url>https://github.com/oss-review-toolkit/ort</url></reference></externalReferences><ort:dependencyType xmlns:ort="http://www.w3.org/1999/xhtml">direct</ort:dependencyType>
</component>
<component type="library">
<component type="library" bom-ref="NPM:@ort:no-license-file:1.0">
<group>@ort</group>
<name>no-license-file</name>
<version>1.0</version>
Expand All @@ -131,4 +131,24 @@
<externalReferences><reference type="website"><url>https://github.com/oss-review-toolkit/ort</url></reference></externalReferences><ort:dependencyType xmlns:ort="http://www.w3.org/1999/xhtml">direct</ort:dependencyType>
</component>
</components>
<vulnerabilities>
<vulnerability>
<id>CVE-2021-1234</id>
<ratings>
<rating>
<source>
<url>https://cves.example.org/cve1</url>
</source>
<severity>medium</severity>
</rating>
</ratings>
<description>A vulnerability description</description>
<detail>A vulnerability summary</detail>
<affects>
<target>
<ref>NPM:@ort:declared-license:1.0</ref>
</target>
</affects>
</vulnerability>
</vulnerabilities>
</bom>
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ import org.cyclonedx.parsers.JsonParser
import org.cyclonedx.parsers.XmlParser

import org.ossreviewtoolkit.reporter.ORT_RESULT
import org.ossreviewtoolkit.reporter.ORT_RESULT_WITH_VULNERABILITIES
import org.ossreviewtoolkit.reporter.ReporterInput
import org.ossreviewtoolkit.utils.common.normalizeLineBreaks
import org.ossreviewtoolkit.utils.test.getAssetAsString
Expand Down Expand Up @@ -67,7 +68,8 @@ class CycloneDxReporterFunTest : WordSpec({
val expectedBom = getAssetAsString("cyclonedx-reporter-expected-result.xml")
val xmlOptions = optionSingle + mapOf("output.file.formats" to "xml")

val bomFile = CycloneDxReporter().generateReport(ReporterInput(ORT_RESULT), outputDir, xmlOptions).single()
val bomFile = CycloneDxReporter()
.generateReport(ReporterInput(ORT_RESULT_WITH_VULNERABILITIES), outputDir, xmlOptions).single()
val actualBom = bomFile.readText().patchCycloneDxResult().normalizeLineBreaks()

actualBom shouldBe expectedBom
Expand All @@ -76,7 +78,8 @@ class CycloneDxReporterFunTest : WordSpec({
"be valid JSON according to schema version $defaultSchemaVersion" {
val jsonOptions = optionSingle + mapOf("output.file.formats" to "json")

val bomFile = CycloneDxReporter().generateReport(ReporterInput(ORT_RESULT), outputDir, jsonOptions).single()
val bomFile = CycloneDxReporter()
.generateReport(ReporterInput(ORT_RESULT_WITH_VULNERABILITIES), outputDir, jsonOptions).single()

bomFile shouldBe aFile()
bomFile shouldNotBe emptyFile()
Expand All @@ -87,7 +90,8 @@ class CycloneDxReporterFunTest : WordSpec({
val expectedBom = getAssetAsString("cyclonedx-reporter-expected-result.json")
val jsonOptions = optionSingle + mapOf("output.file.formats" to "json")

val bomFile = CycloneDxReporter().generateReport(ReporterInput(ORT_RESULT), outputDir, jsonOptions).single()
val bomFile = CycloneDxReporter()
.generateReport(ReporterInput(ORT_RESULT_WITH_VULNERABILITIES), outputDir, jsonOptions).single()
val actualBom = bomFile.readText().patchCycloneDxResult()

actualBom shouldEqualJson expectedBom
Expand All @@ -100,7 +104,8 @@ class CycloneDxReporterFunTest : WordSpec({
"create one file per project" {
val jsonOptions = optionMulti + mapOf("output.file.formats" to "json")

val bomFiles = CycloneDxReporter().generateReport(ReporterInput(ORT_RESULT), outputDir, jsonOptions)
val bomFiles = CycloneDxReporter()
.generateReport(ReporterInput(ORT_RESULT_WITH_VULNERABILITIES), outputDir, jsonOptions)

bomFiles shouldHaveSize 2
}
Expand All @@ -109,7 +114,7 @@ class CycloneDxReporterFunTest : WordSpec({
val xmlOptions = optionMulti + mapOf("output.file.formats" to "xml")

val (bomFileProjectWithFindings, bomFileProjectWithoutFindings) = CycloneDxReporter()
.generateReport(ReporterInput(ORT_RESULT), outputDir, xmlOptions).also {
.generateReport(ReporterInput(ORT_RESULT_WITH_VULNERABILITIES), outputDir, xmlOptions).also {
it shouldHaveSize 2
}

Expand All @@ -132,7 +137,7 @@ class CycloneDxReporterFunTest : WordSpec({
val jsonOptions = optionMulti + mapOf("output.file.formats" to "json")

val (bomFileProjectWithFindings, bomFileProjectWithoutFindings) = CycloneDxReporter()
.generateReport(ReporterInput(ORT_RESULT), outputDir, jsonOptions).also {
.generateReport(ReporterInput(ORT_RESULT_WITH_VULNERABILITIES), outputDir, jsonOptions).also {
it shouldHaveSize 2
}

Expand Down
35 changes: 35 additions & 0 deletions plugins/reporters/cyclonedx/src/main/kotlin/CycloneDxReporter.kt
Original file line number Diff line number Diff line change
Expand Up @@ -39,11 +39,13 @@ import org.cyclonedx.model.Metadata
import org.cyclonedx.model.metadata.ToolInformation

import org.ossreviewtoolkit.model.FileFormat
import org.ossreviewtoolkit.model.Identifier
import org.ossreviewtoolkit.model.LicenseSource
import org.ossreviewtoolkit.model.Package
import org.ossreviewtoolkit.model.Project
import org.ossreviewtoolkit.model.licenses.ResolvedLicenseInfo
import org.ossreviewtoolkit.model.utils.toPurl
import org.ossreviewtoolkit.model.vulnerabilities.Vulnerability
import org.ossreviewtoolkit.reporter.Reporter
import org.ossreviewtoolkit.reporter.ReporterInput
import org.ossreviewtoolkit.utils.common.isFalse
Expand Down Expand Up @@ -202,6 +204,8 @@ class CycloneDxReporter : Reporter {
addPackageToBom(input, pkg, bom, dependencyType)
}

addVulnerabilitiesToBom(input.ortResult.getVulnerabilities(), bom)

outputFiles += writeBom(bom, schemaVersion, outputDir, REPORT_BASE_FILENAME, outputFileFormats)
} else {
projects.forEach { project ->
Expand Down Expand Up @@ -244,6 +248,8 @@ class CycloneDxReporter : Reporter {
addPackageToBom(input, pkg, bom, dependencyType)
}

addVulnerabilitiesToBom(input.ortResult.getVulnerabilities(), bom)

val reportName = "$REPORT_BASE_FILENAME-${project.id.toPath("-")}"
outputFiles += writeBom(bom, schemaVersion, outputDir, reportName, outputFileFormats)
}
Expand All @@ -252,6 +258,34 @@ class CycloneDxReporter : Reporter {
return outputFiles
}

private fun addVulnerabilitiesToBom(advisorVulnerabilities: Map<Identifier, List<Vulnerability>>, bom: Bom) {
val vulnerabilities = mutableListOf<org.cyclonedx.model.vulnerability.Vulnerability>()
advisorVulnerabilities.forEach {
val vulnerabilityBomRef = it.key.toCoordinates()
it.value.forEach {
val vulnerability = org.cyclonedx.model.vulnerability.Vulnerability().apply {
id = it.id
description = it.description
detail = it.summary
ratings = it.references.map { reference ->
org.cyclonedx.model.vulnerability.Vulnerability.Rating().apply {
source = org.cyclonedx.model.vulnerability.Vulnerability.Source()
.apply { url = reference.url.toString() }
severity = org.cyclonedx.model.vulnerability.Vulnerability.Rating.Severity
.fromString(reference.severityRating.lowercase())
}
}
affects = mutableListOf(
org.cyclonedx.model.vulnerability.Vulnerability.Affect()
.apply { ref = vulnerabilityBomRef }
)
}
vulnerabilities.add(vulnerability)
}
bom.vulnerabilities = vulnerabilities
}
}

private fun addPackageToBom(input: ReporterInput, pkg: Package, bom: Bom, dependencyType: String) {
val resolvedLicenseInfo = input.licenseInfoResolver.resolveLicenseInfo(pkg.id).filterExcluded()
.applyChoices(input.ortResult.getPackageLicenseChoices(pkg.id))
Expand Down Expand Up @@ -280,6 +314,7 @@ class CycloneDxReporter : Reporter {
name = pkg.id.name
version = pkg.id.version
description = pkg.description
bomRef = pkg.id.toCoordinates()

// TODO: Map package-manager-specific OPTIONAL scopes.
scope = if (input.ortResult.isExcluded(pkg.id)) {
Expand Down
4 changes: 3 additions & 1 deletion reporter/src/testFixtures/kotlin/TestData.kt
Original file line number Diff line number Diff line change
Expand Up @@ -405,8 +405,10 @@ val ORT_RESULT = OrtResult(

val VULNERABILITY = Vulnerability(
id = "CVE-2021-1234",
summary = "A vulnerability summary",
description = "A vulnerability description",
references = listOf(
VulnerabilityReference(URI("https://cves.example.org/cve1"), "Cvss2", "MEDIUM")
VulnerabilityReference(URI("https://cves.example.org/cve1"), "Cvss2", "6.0")
)
)

Expand Down

0 comments on commit d0efc19

Please sign in to comment.