CycloneDX / cyclonedx-cli

CycloneDX CLI tool for SBOM analysis, merging, diffs and format conversions.
https://cyclonedx.org/
Apache License 2.0
317 stars 62 forks source link

`metadata.tools` not merged correctly when one SBOM uses legacy format and the other uses the newer format #408

Open WIStudent opened 1 month ago

WIStudent commented 1 month ago

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

andreas-hilti commented 1 month ago

@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:

As a side-note, I think the xml serialization will write out both variants (and thus violate the specs).

WIStudent commented 1 month ago

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:

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.