cyclonedx-cli
cyclonedx-cli copied to clipboard
`metadata.tools` not merged correctly when one SBOM uses legacy format and the other uses the newer format
I have 2 SBOM files. One created with cyclonedx-maven-plugin
{
"bomFormat" : "CycloneDX",
"specVersion" : "1.6",
"metadata" : {
"tools" : {
"components" : [
{
"type" : "library",
"author" : "OWASP Foundation",
"group" : "org.cyclonedx",
"name" : "cyclonedx-maven-plugin",
"version" : "2.9.0",
"description" : "CycloneDX Maven plugin",
"hashes" : [
{
"alg" : "MD5",
"content" : "dfaeab7ec837ce07874e2ee66fdc57d3"
},
{
"alg" : "SHA-1",
"content" : "8bab47bafc8183d0a5f37790ff55ed05ead1ae2d"
},
{
"alg" : "SHA-256",
"content" : "67117e03eae4a03ca8bab3add044995f4899aa21798a2510b8265ef8101e90ac"
},
{
"alg" : "SHA-512",
"content" : "ae6b706516bb76da806b7854aef9e348fa593f5159ae9d693ad38942165c0ebc0846d977a477f6029612d43468fd2cd73a5aa253c228a94fb8d184e0acefc3d2"
},
{
"alg" : "SHA-384",
"content" : "ee872354d8b0dcd6f9835a913b3aaba70d9365a46043be78020183282a1e9fca812e969246cbe31d642541591b46648b"
},
{
"alg" : "SHA3-384",
"content" : "e5167f9e7ceba3b7b4d1900c404543907868745334bedc69cdf79c271727148413033a3b1426b733b7549e612e44adee"
},
{
"alg" : "SHA3-256",
"content" : "41fc0bc2275f354e2c7da01041ce73ce677364799cba53920a180aa5d4571c63"
},
{
"alg" : "SHA3-512",
"content" : "ed7f97900b09b818dbc0b8a23c00a2843e1bc34e2e8eb5b6df52533af0a15b721de6f7d5c2fd9352b8d4fde768e080053b40a16f0f9f04c336fe9b44abe83fc0"
}
]
}
]
}
}
}
and one created with @cyclonedx/cyclonedx-npm
{
"$schema": "http://cyclonedx.org/schema/bom-1.6.schema.json",
"bomFormat": "CycloneDX",
"specVersion": "1.6",
"metadata": {
"tools": [
{
"name": "npm",
"version": "10.8.2"
},
{
"vendor": "@cyclonedx",
"name": "cyclonedx-npm",
"version": "1.19.3",
"externalReferences": [
{
"url": "git+https://github.com/CycloneDX/cyclonedx-node-npm.git",
"type": "vcs",
"comment": "as detected from PackageJson property \"repository.url\""
},
{
"url": "https://github.com/CycloneDX/cyclonedx-node-npm#readme",
"type": "website",
"comment": "as detected from PackageJson property \"homepage\""
},
{
"url": "https://github.com/CycloneDX/cyclonedx-node-npm/issues",
"type": "issue-tracker",
"comment": "as detected from PackageJson property \"bugs.url\""
}
]
},
{
"vendor": "@cyclonedx",
"name": "cyclonedx-library",
"version": "6.11.0",
"externalReferences": [
{
"url": "git+https://github.com/CycloneDX/cyclonedx-javascript-library.git",
"type": "vcs",
"comment": "as detected from PackageJson property \"repository.url\""
},
{
"url": "https://github.com/CycloneDX/cyclonedx-javascript-library#readme",
"type": "website",
"comment": "as detected from PackageJson property \"homepage\""
},
{
"url": "https://github.com/CycloneDX/cyclonedx-javascript-library/issues",
"type": "issue-tracker",
"comment": "as detected from PackageJson property \"bugs.url\""
}
]
}
]
}
}
(I removed irrelevant parts for readability).
cyclonedx-maven-plugin creates an SBOM that uses the newer format for the metadata.tools field, @cyclonedx/cyclonedx-npm creates one that uses the legacy format.
If I try to merge these two SBOMs, only the tools in the legacy format are included in the result:
cyclonedx-cli merge --input-files maven-sbom.json npm-sbom.json --output-format json > merged-sbom.json
{
"bomFormat": "CycloneDX",
"specVersion": "1.6",
"metadata": {
"tools": [
{
"name": "npm",
"version": "10.8.2"
},
{
"vendor": "@cyclonedx",
"name": "cyclonedx-npm",
"version": "1.19.3",
"externalReferences": [
{
"url": "git\u002Bhttps://github.com/CycloneDX/cyclonedx-node-npm.git",
"type": "vcs",
"comment": "as detected from PackageJson property \u0022repository.url\u0022"
},
{
"url": "https://github.com/CycloneDX/cyclonedx-node-npm#readme",
"type": "website",
"comment": "as detected from PackageJson property \u0022homepage\u0022"
},
{
"url": "https://github.com/CycloneDX/cyclonedx-node-npm/issues",
"type": "issue-tracker",
"comment": "as detected from PackageJson property \u0022bugs.url\u0022"
}
]
},
{
"vendor": "@cyclonedx",
"name": "cyclonedx-library",
"version": "6.11.0",
"externalReferences": [
{
"url": "git\u002Bhttps://github.com/CycloneDX/cyclonedx-javascript-library.git",
"type": "vcs",
"comment": "as detected from PackageJson property \u0022repository.url\u0022"
},
{
"url": "https://github.com/CycloneDX/cyclonedx-javascript-library#readme",
"type": "website",
"comment": "as detected from PackageJson property \u0022homepage\u0022"
},
{
"url": "https://github.com/CycloneDX/cyclonedx-javascript-library/issues",
"type": "issue-tracker",
"comment": "as detected from PackageJson property \u0022bugs.url\u0022"
}
]
}
]
}
}
The order of the input files did not matter
@WIStudent I can see why this is happening, but I'm not sure what is the best way is to resolve it.
Here is the rough summary:
- The data-model (ToolChoices) is capable of holding both legacy tools as well as tool components/services. https://github.com/CycloneDX/cyclonedx-dotnet-library/blob/main/src/CycloneDX.Core/Models/ToolChoices.cs
- When writing out the data, we can't write out both of them in order to not violate the specification. https://github.com/CycloneDX/cyclonedx-dotnet-library/blob/main/src/CycloneDX.Core/Json/Converters/ToolChoicesConverter.cs
- There is no explicit migration logic (on deserialization). Instead the library always works with the latest specification, and only before writing out in a particular format, it performs some adjustments (like dropping some unsupported members). https://github.com/CycloneDX/cyclonedx-dotnet-library/blob/main/src/CycloneDX.Core/BomUtils.cs#L49
As a side-note, I think the xml serialization will write out both variants (and thus violate the specs).
It is a tricky problem because an automatic conversion between the legacy format and the new format would require making some assumptions. One solution could be to let the user choose a tools-merging-strategy:
error: This throws an error when the input SBOMs contain different tool formats. It is up to the user to ensure that the input SBOMs all use the same tool format. This should be the default in my opinion.drop-new-format: If multiple formats are present, only export the legacy format tools and print a warning that some tools were dropped. This is the behavior we currently see in the JSON export.drop-legacy-format: If multiple formats are present, only export the tools using the new format and print a warning that some legacy tools were droppedautomatic-conversion: Use some assumptions to convert all tools to the new or legacy format (depending on the output spec version).
Another solution would be to only implement the error strategy without giving the user a choice. This would at least ensure that the merged SBOM is not incomplete or invalid.
In my case I have a Java Spring application that uses npm dependencies for parts of its frontend. I am using cyclonedx-maven-plugin and @cyclonedx/cyclonedx-npm to collect the maven and npm dependencies. @cyclonedx/cyclonedx-npm can handle v1.6 but currently only produces SBOMs using the legacy tool format. cyclonedx-maven-plugin on the other hand uses the new format if the output spec version supports it. Instead of using cyclonedx-cli merge I ended up writing my own custom maven plugin for my specific merging needs using cyclonedx-core-java. For now It merges the tools by requiring that all input SBOMs use the legacy tool format.