From 702133779dd2868e45e98de8450de64f099f7f29 Mon Sep 17 00:00:00 2001 From: dervoeti Date: Fri, 2 Aug 2024 15:28:42 +0200 Subject: [PATCH 1/6] feat: pick up CycloneDX BOM components from metadata as well Signed-off-by: dervoeti --- .../internal/cyclonedxutil/helpers/decoder.go | 22 ++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/syft/format/internal/cyclonedxutil/helpers/decoder.go b/syft/format/internal/cyclonedxutil/helpers/decoder.go index fdf8ffe98c1..ced92ac2fa5 100644 --- a/syft/format/internal/cyclonedxutil/helpers/decoder.go +++ b/syft/format/internal/cyclonedxutil/helpers/decoder.go @@ -39,11 +39,27 @@ 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 { + components := []cyclonedx.Component{} + components_present := false + if bom.Components != nil { + components = *bom.Components + components_present = true + } + + if bom.Metadata.Component != nil { + components = append(components, *bom.Metadata.Component) + components_present = true + if bom.Metadata.Component.Components != nil { + components = append(components, *bom.Metadata.Component.Components...) + } + } + + if !components_present { return fmt.Errorf("no components are defined in the CycloneDX BOM") } - for i := range *bom.Components { - collectPackages(&(*bom.Components)[i], s, idMap) + + for i := range components { + collectPackages(&components[i], s, idMap) } return nil } From 671684eb78bfdaf64c14545e159b43057bacafd3 Mon Sep 17 00:00:00 2001 From: dervoeti Date: Fri, 2 Aug 2024 17:49:30 +0200 Subject: [PATCH 2/6] fix: change var name to camel case Signed-off-by: dervoeti --- syft/format/internal/cyclonedxutil/helpers/decoder.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/syft/format/internal/cyclonedxutil/helpers/decoder.go b/syft/format/internal/cyclonedxutil/helpers/decoder.go index ced92ac2fa5..79dd8a40089 100644 --- a/syft/format/internal/cyclonedxutil/helpers/decoder.go +++ b/syft/format/internal/cyclonedxutil/helpers/decoder.go @@ -40,21 +40,21 @@ func ToSyftModel(bom *cyclonedx.BOM) (*sbom.SBOM, error) { func collectBomPackages(bom *cyclonedx.BOM, s *sbom.SBOM, idMap map[string]interface{}) error { components := []cyclonedx.Component{} - components_present := false + componentsPresent := false if bom.Components != nil { components = *bom.Components - components_present = true + componentsPresent = true } if bom.Metadata.Component != nil { components = append(components, *bom.Metadata.Component) - components_present = true + componentsPresent = true if bom.Metadata.Component.Components != nil { components = append(components, *bom.Metadata.Component.Components...) } } - if !components_present { + if !componentsPresent { return fmt.Errorf("no components are defined in the CycloneDX BOM") } From 390fc91743b257ee617ee2aabd422169858ba2f1 Mon Sep 17 00:00:00 2001 From: dervoeti Date: Mon, 5 Aug 2024 22:13:28 +0200 Subject: [PATCH 3/6] feat: added integration test Signed-off-by: dervoeti --- .../sbom_metadata_component_test.go | 25 +++++++++++++++ .../image-sbom-metadata-component/Dockerfile | 2 ++ .../test.cdx.json | 32 +++++++++++++++++++ 3 files changed, 59 insertions(+) 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 From a49f8ab40963f75ebd3f2cc9dbb2973369df46ec Mon Sep 17 00:00:00 2001 From: dervoeti Date: Mon, 5 Aug 2024 23:04:59 +0200 Subject: [PATCH 4/6] fix: only include .metadata.component as package if it has a certain type Signed-off-by: dervoeti --- syft/format/internal/cyclonedxutil/helpers/decoder.go | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/syft/format/internal/cyclonedxutil/helpers/decoder.go b/syft/format/internal/cyclonedxutil/helpers/decoder.go index 79dd8a40089..749fd514ab5 100644 --- a/syft/format/internal/cyclonedxutil/helpers/decoder.go +++ b/syft/format/internal/cyclonedxutil/helpers/decoder.go @@ -46,7 +46,12 @@ func collectBomPackages(bom *cyclonedx.BOM, s *sbom.SBOM, idMap map[string]inter componentsPresent = true } - if bom.Metadata.Component != nil { + if bom.Metadata.Component != nil && + (bom.Metadata.Component.Type == cyclonedx.ComponentTypeApplication || + bom.Metadata.Component.Type == cyclonedx.ComponentTypeFramework || + bom.Metadata.Component.Type == cyclonedx.ComponentTypeLibrary || + bom.Metadata.Component.Type == cyclonedx.ComponentTypePlatform) { + components = append(components, *bom.Metadata.Component) componentsPresent = true if bom.Metadata.Component.Components != nil { From 730b877c7c5d66fc3f698e54c1706f3b09ea0ce3 Mon Sep 17 00:00:00 2001 From: dervoeti Date: Mon, 5 Aug 2024 23:35:02 +0200 Subject: [PATCH 5/6] refactor: simplified the change Signed-off-by: dervoeti --- .../internal/cyclonedxutil/helpers/decoder.go | 20 +++++-------------- 1 file changed, 5 insertions(+), 15 deletions(-) diff --git a/syft/format/internal/cyclonedxutil/helpers/decoder.go b/syft/format/internal/cyclonedxutil/helpers/decoder.go index 749fd514ab5..c085456a1e7 100644 --- a/syft/format/internal/cyclonedxutil/helpers/decoder.go +++ b/syft/format/internal/cyclonedxutil/helpers/decoder.go @@ -39,33 +39,23 @@ func ToSyftModel(bom *cyclonedx.BOM) (*sbom.SBOM, error) { } func collectBomPackages(bom *cyclonedx.BOM, s *sbom.SBOM, idMap map[string]interface{}) error { - components := []cyclonedx.Component{} componentsPresent := false if bom.Components != nil { - components = *bom.Components + for i := range *bom.Components { + collectPackages(&(*bom.Components)[i], s, idMap) + } componentsPresent = true } - if bom.Metadata.Component != nil && - (bom.Metadata.Component.Type == cyclonedx.ComponentTypeApplication || - bom.Metadata.Component.Type == cyclonedx.ComponentTypeFramework || - bom.Metadata.Component.Type == cyclonedx.ComponentTypeLibrary || - bom.Metadata.Component.Type == cyclonedx.ComponentTypePlatform) { - - components = append(components, *bom.Metadata.Component) + if bom.Metadata.Component != nil { + collectPackages(bom.Metadata.Component, s, idMap) componentsPresent = true - if bom.Metadata.Component.Components != nil { - components = append(components, *bom.Metadata.Component.Components...) - } } if !componentsPresent { return fmt.Errorf("no components are defined in the CycloneDX BOM") } - for i := range components { - collectPackages(&components[i], s, idMap) - } return nil } From 2e460bb521c1053ab26247a9dd6ccea8497b9577 Mon Sep 17 00:00:00 2001 From: dervoeti Date: Tue, 6 Aug 2024 08:59:18 +0200 Subject: [PATCH 6/6] fix: metadata nil check Signed-off-by: dervoeti --- syft/format/internal/cyclonedxutil/helpers/decoder.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/syft/format/internal/cyclonedxutil/helpers/decoder.go b/syft/format/internal/cyclonedxutil/helpers/decoder.go index c085456a1e7..c4c706e380b 100644 --- a/syft/format/internal/cyclonedxutil/helpers/decoder.go +++ b/syft/format/internal/cyclonedxutil/helpers/decoder.go @@ -47,7 +47,7 @@ func collectBomPackages(bom *cyclonedx.BOM, s *sbom.SBOM, idMap map[string]inter componentsPresent = true } - if bom.Metadata.Component != nil { + if bom.Metadata != nil && bom.Metadata.Component != nil { collectPackages(bom.Metadata.Component, s, idMap) componentsPresent = true }