cyclonedx-cli
                                
                                
                                
                                    cyclonedx-cli copied to clipboard
                            
                            
                            
                        Hierarchical merge misplaces <properties> nodes of toplevel components
Problem
I try to merge a SBOM created via https://github.com/CycloneDX/cyclonedx-node-npm to another SBOM.
The NPM SBOM contains extra properties for the toplevel components and subcomponents e.g. it looks like this, which is valid.:
  <components>
    <component type="library" bom-ref="@cyclonedx/[email protected]">
      <author>Jan Kowalleck</author>
      <group>@cyclonedx</group>
      <name>cyclonedx-npm</name>
      <version>1.7.2</version>
      <description>Create CycloneDX Software Bill of Materials (SBOM) from NPM projects.</description>
      <licenses>
        <license>
          <id>Apache-2.0</id>
        </license>
      </licenses>
      <purl>pkg:npm/%40cyclonedx/[email protected]?vcs_url=git+https://github.com/CycloneDX/cyclonedx-node-npm.git</purl>
      <externalReferences>
         ...
      </externalReferences>
      <properties>
        <property name="cdx:npm:package:extraneous">true</property>
        <property name="cdx:npm:package:path">node_modules/@cyclonedx\cyclonedx-npm</property>
      </properties>
      <components>
           ...
But after i do a hierarchical merge, the properties get shifted to the wrong place in the xsd:sequence, behind the "components" element, but the XSD wants them to be in front.
     <components>
        <component type="library" bom-ref="[email protected]:@cyclonedx/[email protected]">
          <author>Jan Kowalleck</author>
          <group>@cyclonedx</group>
          <name>cyclonedx-npm</name>
          <version>1.7.2</version>
          <description>Create CycloneDX Software Bill of Materials (SBOM) from NPM projects.</description>
          <licenses>
            <license>
              <id>Apache-2.0</id>
            </license>
          </licenses>
          <purl>pkg:npm/%40cyclonedx/[email protected]?vcs_url=git+https://github.com/CycloneDX/cyclonedx-node-npm.git</purl>
          <externalReferences>
            <reference type="issue-tracker">
              <url>https://github.com/CycloneDX/cyclonedx-node-npm/issues</url>
              <comment>as detected from PackageJson property "bugs.url"</comment>
            </reference>
            <reference type="vcs">
              <url>git+https://github.com/CycloneDX/cyclonedx-node-npm.git</url>
              <comment>as detected from PackageJson property "repository.url"</comment>
            </reference>
            <reference type="website">
              <url>https://github.com/CycloneDX/cyclonedx-node-npm#readme</url>
              <comment>as detected from PackageJson property "homepage"</comment>
            </reference>
          </externalReferences>
          <components>
          ...
          </components>
          <properties>
            <property name="cdx:npm:package:extraneous">true</property>
            <property name="cdx:npm:package:path">node_modules/@cyclonedx\cyclonedx-npm</property>
          </properties>
        </component>
This leads to a validation error later:
 Validating XML BOM...
Validation failed at line number 4304 and position 12: The element 'component' in namespace 'http://cyclonedx.org/schema/bom/1.4' has invalid child element 'properties' in namespace 'http://cyclonedx.org/schema/bom/1.4'. List of possible elements expected: 'evidence, releaseNotes' in namespace 'http://cyclonedx.org/schema/bom/1.4' as well as any element in namespace '##other'.
BOM is not valid.
cyclonedx-cli version
Running on Windows 10 with the prebuilt binaries.
cyclonedx-cli --version
0.24.2
Reproduction
Try to merge the two attached files from the ZIP (one created by cyclonedx-npm, one from the example repo): property_merge.zip
cyclonedx-cli merge --hierarchical --name propexample --version 1.0 --output-file bom.xml --input-files example1.cdx.xml proton-bridge-v1.8.0.bom.xml
Processing input file example1.cdx.xml
    Contains 5 components
Processing input file proton-bridge-v1.8.0.bom.xml
    Contains 201 components
Writing output file...
    Total 2 components
cyclonedx-cli validate --input-file bom.xml --fail-on-errors --input-version v1_4
Validating XML BOM...
Validation failed at line number 432 and position 12: The element 'component' in namespace 'http://cyclonedx.org/schema/bom/1.4' has invalid child element 'properties' in namespace 'http://cyclonedx.org/schema/bom/1.4'. List of possible elements expected: 'evidence, releaseNotes' in namespace 'http://cyclonedx.org/schema/bom/1.4' as well as any element in namespace '##other'.
BOM is not valid.
                                    
                                    
                                    
                                
As far as I can see, one could either swap the Properties and Components member here:
https://github.com/CycloneDX/cyclonedx-dotnet-library/blob/b6790529c1da67f98ae63fba47a444a80ceae24a/src/CycloneDX.Core/Models/Component.cs#L181-L189
or one could use the Order argument in all XmlArray and XmlElement in the Component class to correct the order.
By default, XmlSerialization seems to use the order in which the items are defined, compare also
https://learn.microsoft.com/en-us/dotnet/api/system.xml.serialization.xmlelementattribute.order?view=net-6.0#system-xml-serialization-xmlelementattribute-order
Should be fixed in 0.25.1