From 4312699dd6f3d0d97e69a3a3fa6a0f2465239974 Mon Sep 17 00:00:00 2001 From: ChrisJr404 Date: Mon, 13 Jul 2026 15:33:51 -0400 Subject: [PATCH] cyclonedx: import firmware-typed components as packages (#4855) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The CycloneDX decoder was filtering on a hard-coded set of component types (application/framework/library/machine-learning-model). Anything else — including "firmware" — fell through silently, so a BOM describing u-boot or other firmware ended up with no packages and grype reported no matches (anchore/grype#2537). @kzantow confirmed in the issue thread that firmware should be included and gave this section as the spot to update. Add ComponentTypeFirmware to the case list and a regression test that constructs a single-firmware-component BOM and asserts the decoded SBOM contains the package. Closes anchore/grype#2537 Signed-off-by: Chris (ChrisJr404) <11917633+ChrisJr404@users.noreply.github.com> Co-authored-by: Chris (ChrisJr404) <11917633+ChrisJr404@users.noreply.github.com> --- .../internal/cyclonedxutil/helpers/decoder.go | 2 +- .../cyclonedxutil/helpers/decoder_test.go | 24 +++++++++++++++++++ 2 files changed, 25 insertions(+), 1 deletion(-) diff --git a/syft/format/internal/cyclonedxutil/helpers/decoder.go b/syft/format/internal/cyclonedxutil/helpers/decoder.go index 0f1783362..aff76f66a 100644 --- a/syft/format/internal/cyclonedxutil/helpers/decoder.go +++ b/syft/format/internal/cyclonedxutil/helpers/decoder.go @@ -62,7 +62,7 @@ func collectPackages(component *cyclonedx.Component, s *sbom.SBOM, idMap map[str switch component.Type { case cyclonedx.ComponentTypeOS: case cyclonedx.ComponentTypeContainer: - case cyclonedx.ComponentTypeApplication, cyclonedx.ComponentTypeFramework, cyclonedx.ComponentTypeLibrary, cyclonedx.ComponentTypeMachineLearningModel: + case cyclonedx.ComponentTypeApplication, cyclonedx.ComponentTypeFramework, cyclonedx.ComponentTypeLibrary, cyclonedx.ComponentTypeMachineLearningModel, cyclonedx.ComponentTypeFirmware: p := decodeComponent(component) idMap[component.BOMRef] = p if component.BOMRef != "" { diff --git a/syft/format/internal/cyclonedxutil/helpers/decoder_test.go b/syft/format/internal/cyclonedxutil/helpers/decoder_test.go index b5c1f3c27..5092c3ff0 100644 --- a/syft/format/internal/cyclonedxutil/helpers/decoder_test.go +++ b/syft/format/internal/cyclonedxutil/helpers/decoder_test.go @@ -259,6 +259,30 @@ func Test_decode(t *testing.T) { } } +func Test_decode_includesFirmwareComponents(t *testing.T) { + // CycloneDX BOMs that describe firmware (e.g. u-boot) use + // component type "firmware". Prior to issue #2537 the decoder skipped + // these and downstream tools (e.g. grype) reported zero matches. + bom := cyclonedx.BOM{ + Components: &[]cyclonedx.Component{ + { + BOMRef: "u-boot", + Type: cyclonedx.ComponentTypeFirmware, + Name: "u-boot", + Version: "2024.04", + PackageURL: "pkg:generic/u-boot@2024.04", + }, + }, + } + model, err := ToSyftModel(&bom) + require.NoError(t, err) + + pkgs := model.Artifacts.Packages.Sorted() + require.Len(t, pkgs, 1, "firmware component should be imported as a package") + assert.Equal(t, "u-boot", pkgs[0].Name) + assert.Equal(t, "2024.04", pkgs[0].Version) +} + func Test_relationshipDirection(t *testing.T) { cyclonedx_bom := cyclonedx.BOM{Metadata: nil, Components: &[]cyclonedx.Component{