Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

CycloneDX fixes #8882

Merged
merged 6 commits into from
Jul 16, 2024
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
74 changes: 42 additions & 32 deletions plugins/reporters/cyclonedx/src/main/kotlin/CycloneDxReporter.kt
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ import java.util.Date
import java.util.SortedSet
import java.util.UUID

import org.apache.logging.log4j.kotlin.logger

import org.cyclonedx.Version
import org.cyclonedx.generators.BomGeneratorFactory
import org.cyclonedx.model.AttachmentText
Expand Down Expand Up @@ -336,8 +338,7 @@ class CycloneDxReporter : Reporter {

hashes = listOfNotNull(hash)

// TODO: Support license expressions once we have fully converted to them.
licenses = LicenseChoice().apply { licenses = licenseObjects }
if (licenseObjects.isNotEmpty()) licenses = LicenseChoice().apply { licenses = licenseObjects }

// TODO: Find a way to associate copyrights to the license they belong to, see
// https://github.com/CycloneDX/cyclonedx-core-java/issues/58
Expand Down Expand Up @@ -369,37 +370,14 @@ class CycloneDxReporter : Reporter {
outputFileExtensions.forEach { fileExtension ->
val outputFile = outputDir.resolve("$outputName.$fileExtension")

val bomGenerator = when (fileExtension) {
"xml" -> BomGeneratorFactory.createXml(schemaVersion, bom)
"json" -> {
// JSON output cannot handle extensible types (see [1]), so simply remove them. As JSON output is
// guaranteed to be the last format serialized, it is okay to modify the BOM here without doing a
// deep copy first.
//
// [1] https://github.com/CycloneDX/cyclonedx-core-java/issues/99.
val bomWithoutExtensibleTypes = bom.apply {
components.forEach { component ->
// Clear the "dependencyType".
component.extensibleTypes = null

component.licenses.licenses.forEach { license ->
// Clear the "origin".
license.extensibleTypes = null
}

// Remove duplicates that may occur due to clearing the distinguishing extensive type.
component.licenses.licenses = component.licenses.licenses.distinct()
}
}

BomGeneratorFactory.createJson(schemaVersion, bomWithoutExtensibleTypes) as Any
}

else -> throw IllegalArgumentException("Unsupported CycloneDX file extension '$fileExtension'.")
runCatching {
generateBom(bom, schemaVersion, fileExtension)
}.onSuccess { bom ->
outputFile.bufferedWriter().use { it.write(bom) }
writtenFiles += outputFile
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it really necessary to include writing to the file into runCatching ?
e.g. What kind of errors could happen there for which it would be beneficial to continue?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's probably not necessary, but I also did not see any harm in doing so as it made the code a bit simpler. But I've changed the code now to write the file only onSuccess.

}.onFailure {
logger.error("Unable to create CycloneDX report: ", it)
}

outputFile.bufferedWriter().use { it.write(bomGenerator.toString()) }
writtenFiles += outputFile
}

return writtenFiles
Expand All @@ -411,3 +389,35 @@ class CycloneDxReporter : Reporter {
*/
private fun ResolvedLicenseInfo.getLicenseNames(vararg sources: LicenseSource): SortedSet<String> =
licenses.filter { license -> sources.any { it in license.sources } }.mapTo(sortedSetOf()) { it.license.toString() }

/**
* Return the string representation for the given [bom], [schemaVersion] and [fileExtension].
*/
private fun generateBom(bom: Bom, schemaVersion: Version, fileExtension: String): String =
when (fileExtension) {
"xml" -> BomGeneratorFactory.createXml(schemaVersion, bom).toXmlString()
"json" -> {
// JSON output cannot handle extensible types (see [1]), so simply remove them. As JSON output is guaranteed
// to be the last format serialized, it is okay to modify the BOM here without doing a deep copy first.
//
// [1] https://github.com/CycloneDX/cyclonedx-core-java/issues/99.
val bomWithoutExtensibleTypes = bom.apply {
components.forEach { component ->
// Clear the "dependencyType".
component.extensibleTypes = null

component.licenses.licenses.forEach { license ->
// Clear the "origin".
license.extensibleTypes = null
}

// Remove duplicates that may occur due to clearing the distinguishing extensive type.
component.licenses.licenses = component.licenses.licenses.distinct()
}
}

BomGeneratorFactory.createJson(schemaVersion, bomWithoutExtensibleTypes).toJsonString()
}

else -> throw IllegalArgumentException("Unsupported CycloneDX file extension '$fileExtension'.")
}
Loading