From 3161e1847efab3815b51eceb2f1a81cd8944eb34 Mon Sep 17 00:00:00 2001 From: Lukas Voetmand Date: Mon, 12 Aug 2024 22:37:23 +0200 Subject: [PATCH] fix: read CycloneDX BOM components from metadata (#3092) Signed-off-by: dervoeti --- .../sbom_metadata_component_test.go | 25 +++++++++++++++ .../image-sbom-metadata-component/Dockerfile | 2 ++ .../test.cdx.json | 32 +++++++++++++++++++ .../internal/cyclonedxutil/helpers/decoder.go | 19 ++++++++--- 4 files changed, 74 insertions(+), 4 deletions(-) create mode 100644 cmd/syft/internal/test/integration/sbom_metadata_component_test.go create mode 100644 cmd/syft/internal/test/integration/test-fixtures/image-sbom-metadata-component/Dockerfile create mode 100644 cmd/syft/internal/test/integration/test-fixtures/image-sbom-metadata-component/test.cdx.json diff --git a/cmd/syft/internal/test/integration/sbom_metadata_component_test.go b/cmd/syft/internal/test/integration/sbom_metadata_component_test.go new file mode 100644 index 00000000000..d45a2f1cd5d --- /dev/null +++ b/cmd/syft/internal/test/integration/sbom_metadata_component_test.go @@ -0,0 +1,25 @@ +package integration + +import ( + "reflect" + "testing" + + "github.com/anchore/syft/syft/pkg" + "github.com/anchore/syft/syft/source" +) + +func TestSbomMetadataComponent(t *testing.T) { + sbom, _ := catalogFixtureImage(t, "image-sbom-metadata-component", source.SquashedScope, "+sbom-cataloger") + + expectedPkgs := []string{"first-subcomponent", "main-component"} + foundPkgs := []string{} + + for sbomPkg := range sbom.Artifacts.Packages.Enumerate(pkg.JavaPkg) { + foundPkgs = append(foundPkgs, sbomPkg.Name) + } + + // check if both the package in `.metadata.component` and the one in `.components` were found + if !reflect.DeepEqual(expectedPkgs, foundPkgs) { + t.Errorf("expected packages %v, got %v", expectedPkgs, foundPkgs) + } +} diff --git a/cmd/syft/internal/test/integration/test-fixtures/image-sbom-metadata-component/Dockerfile b/cmd/syft/internal/test/integration/test-fixtures/image-sbom-metadata-component/Dockerfile new file mode 100644 index 00000000000..6861c4d6352 --- /dev/null +++ b/cmd/syft/internal/test/integration/test-fixtures/image-sbom-metadata-component/Dockerfile @@ -0,0 +1,2 @@ +FROM scratch +COPY test.cdx.json / diff --git a/cmd/syft/internal/test/integration/test-fixtures/image-sbom-metadata-component/test.cdx.json b/cmd/syft/internal/test/integration/test-fixtures/image-sbom-metadata-component/test.cdx.json new file mode 100644 index 00000000000..6695b7c0a75 --- /dev/null +++ b/cmd/syft/internal/test/integration/test-fixtures/image-sbom-metadata-component/test.cdx.json @@ -0,0 +1,32 @@ +{ + "bomFormat" : "CycloneDX", + "specVersion" : "1.5", + "serialNumber" : "urn:uuid:dc807d4b-0415-35ab-ba61-49b5d39bc2d9", + "version" : 1, + "metadata" : { + "component" : { + "name" : "main-component", + "version" : "1.2.3", + "purl" : "pkg:maven/org.example/main-component@1.2.3", + "type" : "library", + "bom-ref" : "pkg:maven/org.example/main-component@1.2.3" + } + }, + "components" : [ + { + "name" : "first-subcomponent", + "version" : "2.3.4", + "purl" : "pkg:maven/org.example/first-subcomponent@2.3.4", + "type" : "library", + "bom-ref" : "pkg:maven/org.example/first-subcomponent@2.3.4" + } + ], + "dependencies" : [ + { + "ref" : "pkg:maven/org.example/main-component-assembly@1.2.3", + "dependsOn" : [ + "pkg:maven/org.example/first-subcomponent@2.3.4" + ] + } + ] +} \ No newline at end of file diff --git a/syft/format/internal/cyclonedxutil/helpers/decoder.go b/syft/format/internal/cyclonedxutil/helpers/decoder.go index fdf8ffe98c1..c4c706e380b 100644 --- a/syft/format/internal/cyclonedxutil/helpers/decoder.go +++ b/syft/format/internal/cyclonedxutil/helpers/decoder.go @@ -39,12 +39,23 @@ func ToSyftModel(bom *cyclonedx.BOM) (*sbom.SBOM, error) { } func collectBomPackages(bom *cyclonedx.BOM, s *sbom.SBOM, idMap map[string]interface{}) error { - if bom.Components == nil { - return fmt.Errorf("no components are defined in the CycloneDX BOM") + componentsPresent := false + if bom.Components != nil { + for i := range *bom.Components { + collectPackages(&(*bom.Components)[i], s, idMap) + } + componentsPresent = true } - for i := range *bom.Components { - collectPackages(&(*bom.Components)[i], s, idMap) + + if bom.Metadata != nil && bom.Metadata.Component != nil { + collectPackages(bom.Metadata.Component, s, idMap) + componentsPresent = true } + + if !componentsPresent { + return fmt.Errorf("no components are defined in the CycloneDX BOM") + } + return nil }