From 99b97108f5cd54b51d2713814bf7aff152da60c2 Mon Sep 17 00:00:00 2001 From: DmitriyLewen Date: Fri, 20 Dec 2024 17:18:41 +0600 Subject: [PATCH 1/7] fix(bom): attack direct and nested deps to app --- pkg/sbom/io/decode.go | 26 ++++++++++++++++++-------- 1 file changed, 18 insertions(+), 8 deletions(-) diff --git a/pkg/sbom/io/decode.go b/pkg/sbom/io/decode.go index 6cfc79a0871c..dd57515b39f7 100644 --- a/pkg/sbom/io/decode.go +++ b/pkg/sbom/io/decode.go @@ -348,18 +348,28 @@ func (m *Decoder) addOSPkgs(sbom *types.SBOM) { // addLangPkgs traverses relationships and adds language-specific packages func (m *Decoder) addLangPkgs(sbom *types.SBOM) { for id, app := range m.apps { - for _, rel := range m.bom.Relationships()[id] { - pkg, ok := m.pkgs[rel.Dependency] - if !ok { - continue - } - app.Packages = append(app.Packages, *pkg) - delete(m.pkgs, rel.Dependency) // Delete the added package - } + m.addNestedPackageToApp(id, app) sbom.Applications = append(sbom.Applications, *app) } } +// addNestedPackageToApp recursively finds all dependencies and adds these packages to the application +// This is necessary to avoid creating orphan packages. +// for example, for `Application -> RootPkg -> DirectPkg`: +// `DirectPkg` will become an orphan if we add only `RootPkg` and remove `RootPkg` from `m.pkgs` +func (m *Decoder) addNestedPackageToApp(id uuid.UUID, app *ftypes.Application) { + for _, rel := range m.bom.Relationships()[id] { + pkg, ok := m.pkgs[rel.Dependency] + if !ok { + continue + } + app.Packages = append(app.Packages, *pkg) + delete(m.pkgs, rel.Dependency) // Delete the added package + + m.addNestedPackageToApp(rel.Dependency, app) + } +} + // addOrphanPkgs adds orphan packages. // Orphan packages are packages that are not related to any components. func (m *Decoder) addOrphanPkgs(ctx context.Context, sbom *types.SBOM) error { From b697a39877e94880befea65a042abbe11d8f36af Mon Sep 17 00:00:00 2001 From: DmitriyLewen Date: Fri, 20 Dec 2024 17:18:47 +0600 Subject: [PATCH 2/7] test: add test case --- .../testdata/happy/nested-packages-bom.json | 175 ++++++++++++++++++ pkg/sbom/cyclonedx/unmarshal_test.go | 87 +++++++++ 2 files changed, 262 insertions(+) create mode 100644 pkg/sbom/cyclonedx/testdata/happy/nested-packages-bom.json diff --git a/pkg/sbom/cyclonedx/testdata/happy/nested-packages-bom.json b/pkg/sbom/cyclonedx/testdata/happy/nested-packages-bom.json new file mode 100644 index 000000000000..3c6ccb4289cd --- /dev/null +++ b/pkg/sbom/cyclonedx/testdata/happy/nested-packages-bom.json @@ -0,0 +1,175 @@ +{ + "$schema": "http://cyclonedx.org/schema/bom-1.6.schema.json", + "bomFormat": "CycloneDX", + "specVersion": "1.6", + "serialNumber": "urn:uuid:12346a7a-5819-43bf-9411-5c146304f023", + "version": 1, + "metadata": { + "timestamp": "2024-12-20T10:57:13+00:00", + "tools": { + "components": [ + { + "type": "application", + "group": "aquasecurity", + "name": "trivy", + "version": "0.38.7-764-g30c7cb137" + } + ] + }, + "component": { + "bom-ref": "1cb40520-a22c-481f-ad77-6bc6960430c5", + "type": "application", + "name": "/Users/dmitriy/work/tmp/7169", + "properties": [ + { + "name": "aquasecurity:trivy:SchemaVersion", + "value": "2" + } + ] + } + }, + "components": [ + { + "bom-ref": "4021d631-e242-4e69-8a93-928665810a27", + "type": "application", + "name": "foo/bar/test.elf", + "properties": [ + { + "name": "aquasecurity:trivy:Class", + "value": "lang-pkgs" + }, + { + "name": "aquasecurity:trivy:Type", + "value": "gobinary" + } + ] + }, + { + "bom-ref": "pkg:golang/github.com/aquasecurity/go-pep440-version@v0.0.0-20210121094942-22b2f8951d46", + "type": "library", + "name": "github.com/aquasecurity/go-pep440-version", + "version": "v0.0.0-20210121094942-22b2f8951d46", + "purl": "pkg:golang/github.com/aquasecurity/go-pep440-version@v0.0.0-20210121094942-22b2f8951d46", + "properties": [ + { + "name": "aquasecurity:trivy:PkgID", + "value": "github.com/aquasecurity/go-pep440-version@v0.0.0-20210121094942-22b2f8951d46" + }, + { + "name": "aquasecurity:trivy:PkgType", + "value": "gobinary" + } + ] + }, + { + "bom-ref": "pkg:golang/github.com/aquasecurity/go-version@v0.0.0-20210121072130-637058cfe492", + "type": "library", + "name": "github.com/aquasecurity/go-version", + "version": "v0.0.0-20210121072130-637058cfe492", + "purl": "pkg:golang/github.com/aquasecurity/go-version@v0.0.0-20210121072130-637058cfe492", + "properties": [ + { + "name": "aquasecurity:trivy:PkgID", + "value": "github.com/aquasecurity/go-version@v0.0.0-20210121072130-637058cfe492" + }, + { + "name": "aquasecurity:trivy:PkgType", + "value": "gobinary" + } + ] + }, + { + "bom-ref": "pkg:golang/github.com/aquasecurity/test", + "type": "library", + "name": "github.com/aquasecurity/test", + "purl": "pkg:golang/github.com/aquasecurity/test", + "properties": [ + { + "name": "aquasecurity:trivy:PkgID", + "value": "github.com/aquasecurity/test" + }, + { + "name": "aquasecurity:trivy:PkgType", + "value": "gobinary" + } + ] + }, + { + "bom-ref": "pkg:golang/golang.org/x/xerrors@v0.0.0-20200804184101-5ec99f83aff1", + "type": "library", + "name": "golang.org/x/xerrors", + "version": "v0.0.0-20200804184101-5ec99f83aff1", + "purl": "pkg:golang/golang.org/x/xerrors@v0.0.0-20200804184101-5ec99f83aff1", + "properties": [ + { + "name": "aquasecurity:trivy:PkgID", + "value": "golang.org/x/xerrors@v0.0.0-20200804184101-5ec99f83aff1" + }, + { + "name": "aquasecurity:trivy:PkgType", + "value": "gobinary" + } + ] + }, + { + "bom-ref": "pkg:golang/stdlib@v1.15.2", + "type": "library", + "name": "stdlib", + "version": "v1.15.2", + "purl": "pkg:golang/stdlib@v1.15.2", + "properties": [ + { + "name": "aquasecurity:trivy:PkgID", + "value": "stdlib@v1.15.2" + }, + { + "name": "aquasecurity:trivy:PkgType", + "value": "gobinary" + } + ] + } + ], + "dependencies": [ + { + "ref": "1cb40520-a22c-481f-ad77-6bc6960430c5", + "dependsOn": [ + "4021d631-e242-4e69-8a93-928665810a27" + ] + }, + { + "ref": "4021d631-e242-4e69-8a93-928665810a27", + "dependsOn": [ + "pkg:golang/github.com/aquasecurity/go-pep440-version@v0.0.0-20210121094942-22b2f8951d46", + "pkg:golang/github.com/aquasecurity/go-version@v0.0.0-20210121072130-637058cfe492", + "pkg:golang/github.com/aquasecurity/test", + "pkg:golang/golang.org/x/xerrors@v0.0.0-20200804184101-5ec99f83aff1" + ] + }, + { + "ref": "pkg:golang/github.com/aquasecurity/go-pep440-version@v0.0.0-20210121094942-22b2f8951d46", + "dependsOn": [] + }, + { + "ref": "pkg:golang/github.com/aquasecurity/go-version@v0.0.0-20210121072130-637058cfe492", + "dependsOn": [] + }, + { + "ref": "pkg:golang/github.com/aquasecurity/test", + "dependsOn": [ + "pkg:golang/github.com/aquasecurity/go-pep440-version@v0.0.0-20210121094942-22b2f8951d46", + "pkg:golang/github.com/aquasecurity/go-version@v0.0.0-20210121072130-637058cfe492", + "pkg:golang/golang.org/x/xerrors@v0.0.0-20200804184101-5ec99f83aff1", + "pkg:golang/stdlib@v1.15.2" + ] + }, + { + "ref": "pkg:golang/golang.org/x/xerrors@v0.0.0-20200804184101-5ec99f83aff1", + "dependsOn": [] + }, + { + "ref": "pkg:golang/stdlib@v1.15.2", + "dependsOn": [] + } + ], + "vulnerabilities": [] +} diff --git a/pkg/sbom/cyclonedx/unmarshal_test.go b/pkg/sbom/cyclonedx/unmarshal_test.go index 7008efb8e9eb..3d2b4bac35d6 100644 --- a/pkg/sbom/cyclonedx/unmarshal_test.go +++ b/pkg/sbom/cyclonedx/unmarshal_test.go @@ -668,6 +668,93 @@ func TestUnmarshaler_Unmarshal(t *testing.T) { }, }, }, + { + name: "happy path for BOM with nested packages", + inputFile: "testdata/happy/nested-packages-bom.json", + want: types.SBOM{ + Applications: []ftypes.Application{ + { + Type: "gobinary", + FilePath: "foo/bar/test.elf", + Packages: ftypes.Packages{ + { + ID: "github.com/aquasecurity/go-pep440-version@v0.0.0-20210121094942-22b2f8951d46", + Name: "github.com/aquasecurity/go-pep440-version", + Version: "v0.0.0-20210121094942-22b2f8951d46", + Identifier: ftypes.PkgIdentifier{ + PURL: &packageurl.PackageURL{ + Type: packageurl.TypeGolang, + Namespace: "github.com/aquasecurity", + Name: "go-pep440-version", + Version: "v0.0.0-20210121094942-22b2f8951d46", + }, + BOMRef: "pkg:golang/github.com/aquasecurity/go-pep440-version@v0.0.0-20210121094942-22b2f8951d46", + }, + }, + { + ID: "github.com/aquasecurity/go-version@v0.0.0-20210121072130-637058cfe492", + Name: "github.com/aquasecurity/go-version", + Version: "v0.0.0-20210121072130-637058cfe492", + Identifier: ftypes.PkgIdentifier{ + PURL: &packageurl.PackageURL{ + Type: packageurl.TypeGolang, + Namespace: "github.com/aquasecurity", + Name: "go-version", + Version: "v0.0.0-20210121072130-637058cfe492", + }, + BOMRef: "pkg:golang/github.com/aquasecurity/go-version@v0.0.0-20210121072130-637058cfe492", + }, + }, + { + ID: "github.com/aquasecurity/test", + Name: "github.com/aquasecurity/test", + Identifier: ftypes.PkgIdentifier{ + PURL: &packageurl.PackageURL{ + Type: packageurl.TypeGolang, + Namespace: "github.com/aquasecurity", + Name: "test", + }, + BOMRef: "pkg:golang/github.com/aquasecurity/test", + }, + DependsOn: []string{ + "github.com/aquasecurity/go-pep440-version@v0.0.0-20210121094942-22b2f8951d46", + "github.com/aquasecurity/go-version@v0.0.0-20210121072130-637058cfe492", + "golang.org/x/xerrors@v0.0.0-20200804184101-5ec99f83aff1", + "stdlib@v1.15.2", + }, + }, + { + ID: "golang.org/x/xerrors@v0.0.0-20200804184101-5ec99f83aff1", + Name: "golang.org/x/xerrors", + Version: "v0.0.0-20200804184101-5ec99f83aff1", + Identifier: ftypes.PkgIdentifier{ + PURL: &packageurl.PackageURL{ + Type: packageurl.TypeGolang, + Namespace: "golang.org/x", + Name: "xerrors", + Version: "v0.0.0-20200804184101-5ec99f83aff1", + }, + BOMRef: "pkg:golang/golang.org/x/xerrors@v0.0.0-20200804184101-5ec99f83aff1", + }, + }, + { + ID: "stdlib@v1.15.2", + Name: "stdlib", + Version: "v1.15.2", + Identifier: ftypes.PkgIdentifier{ + PURL: &packageurl.PackageURL{ + Type: packageurl.TypeGolang, + Name: "stdlib", + Version: "v1.15.2", + }, + BOMRef: "pkg:golang/stdlib@v1.15.2", + }, + }, + }, + }, + }, + }, + }, { name: "happy path only os component", inputFile: "testdata/happy/os-only-bom.json", From 40d5dac6f0891aea3acfad955e5059e2e14ac28d Mon Sep 17 00:00:00 2001 From: DmitriyLewen Date: Tue, 24 Dec 2024 11:49:40 +0600 Subject: [PATCH 3/7] test: update testcase --- .../testdata/happy/nested-packages-bom.json | 7 ++-- pkg/sbom/cyclonedx/unmarshal_test.go | 36 +++++++++---------- 2 files changed, 20 insertions(+), 23 deletions(-) diff --git a/pkg/sbom/cyclonedx/testdata/happy/nested-packages-bom.json b/pkg/sbom/cyclonedx/testdata/happy/nested-packages-bom.json index 3c6ccb4289cd..fd7623c73028 100644 --- a/pkg/sbom/cyclonedx/testdata/happy/nested-packages-bom.json +++ b/pkg/sbom/cyclonedx/testdata/happy/nested-packages-bom.json @@ -19,7 +19,7 @@ "component": { "bom-ref": "1cb40520-a22c-481f-ad77-6bc6960430c5", "type": "application", - "name": "/Users/dmitriy/work/tmp/7169", + "name": "/test", "properties": [ { "name": "aquasecurity:trivy:SchemaVersion", @@ -139,10 +139,7 @@ { "ref": "4021d631-e242-4e69-8a93-928665810a27", "dependsOn": [ - "pkg:golang/github.com/aquasecurity/go-pep440-version@v0.0.0-20210121094942-22b2f8951d46", - "pkg:golang/github.com/aquasecurity/go-version@v0.0.0-20210121072130-637058cfe492", - "pkg:golang/github.com/aquasecurity/test", - "pkg:golang/golang.org/x/xerrors@v0.0.0-20200804184101-5ec99f83aff1" + "pkg:golang/github.com/aquasecurity/test" ] }, { diff --git a/pkg/sbom/cyclonedx/unmarshal_test.go b/pkg/sbom/cyclonedx/unmarshal_test.go index 3d2b4bac35d6..27a116a8e42c 100644 --- a/pkg/sbom/cyclonedx/unmarshal_test.go +++ b/pkg/sbom/cyclonedx/unmarshal_test.go @@ -677,6 +677,24 @@ func TestUnmarshaler_Unmarshal(t *testing.T) { Type: "gobinary", FilePath: "foo/bar/test.elf", Packages: ftypes.Packages{ + { + ID: "github.com/aquasecurity/test", + Name: "github.com/aquasecurity/test", + Identifier: ftypes.PkgIdentifier{ + PURL: &packageurl.PackageURL{ + Type: packageurl.TypeGolang, + Namespace: "github.com/aquasecurity", + Name: "test", + }, + BOMRef: "pkg:golang/github.com/aquasecurity/test", + }, + DependsOn: []string{ + "github.com/aquasecurity/go-pep440-version@v0.0.0-20210121094942-22b2f8951d46", + "github.com/aquasecurity/go-version@v0.0.0-20210121072130-637058cfe492", + "golang.org/x/xerrors@v0.0.0-20200804184101-5ec99f83aff1", + "stdlib@v1.15.2", + }, + }, { ID: "github.com/aquasecurity/go-pep440-version@v0.0.0-20210121094942-22b2f8951d46", Name: "github.com/aquasecurity/go-pep440-version", @@ -705,24 +723,6 @@ func TestUnmarshaler_Unmarshal(t *testing.T) { BOMRef: "pkg:golang/github.com/aquasecurity/go-version@v0.0.0-20210121072130-637058cfe492", }, }, - { - ID: "github.com/aquasecurity/test", - Name: "github.com/aquasecurity/test", - Identifier: ftypes.PkgIdentifier{ - PURL: &packageurl.PackageURL{ - Type: packageurl.TypeGolang, - Namespace: "github.com/aquasecurity", - Name: "test", - }, - BOMRef: "pkg:golang/github.com/aquasecurity/test", - }, - DependsOn: []string{ - "github.com/aquasecurity/go-pep440-version@v0.0.0-20210121094942-22b2f8951d46", - "github.com/aquasecurity/go-version@v0.0.0-20210121072130-637058cfe492", - "golang.org/x/xerrors@v0.0.0-20200804184101-5ec99f83aff1", - "stdlib@v1.15.2", - }, - }, { ID: "golang.org/x/xerrors@v0.0.0-20200804184101-5ec99f83aff1", Name: "golang.org/x/xerrors", From 76374dcdf4a32ad164baa75055fb51f44addfd24 Mon Sep 17 00:00:00 2001 From: knqyf263 Date: Tue, 24 Dec 2024 10:25:06 +0400 Subject: [PATCH 4/7] refactor: return packages Signed-off-by: knqyf263 --- pkg/sbom/io/decode.go | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/pkg/sbom/io/decode.go b/pkg/sbom/io/decode.go index dd57515b39f7..03e1c7979a22 100644 --- a/pkg/sbom/io/decode.go +++ b/pkg/sbom/io/decode.go @@ -348,26 +348,31 @@ func (m *Decoder) addOSPkgs(sbom *types.SBOM) { // addLangPkgs traverses relationships and adds language-specific packages func (m *Decoder) addLangPkgs(sbom *types.SBOM) { for id, app := range m.apps { - m.addNestedPackageToApp(id, app) + app.Packages = append(app.Packages, m.traverseDependencies(id)...) sbom.Applications = append(sbom.Applications, *app) } } -// addNestedPackageToApp recursively finds all dependencies and adds these packages to the application -// This is necessary to avoid creating orphan packages. -// for example, for `Application -> RootPkg -> DirectPkg`: -// `DirectPkg` will become an orphan if we add only `RootPkg` and remove `RootPkg` from `m.pkgs` -func (m *Decoder) addNestedPackageToApp(id uuid.UUID, app *ftypes.Application) { +// traverseDependencies recursively retrieves all packages that the specified component depends on. +// It starts from the given component ID and traverses the dependency tree, collecting all +// dependent packages. The collected packages are removed from m.pkgs to prevent duplicate +// processing. This ensures that all dependencies, including transitive ones, are properly +// captured and associated with their parent component. +func (m *Decoder) traverseDependencies(id uuid.UUID) ftypes.Packages { + var pkgs ftypes.Packages for _, rel := range m.bom.Relationships()[id] { pkg, ok := m.pkgs[rel.Dependency] if !ok { continue } - app.Packages = append(app.Packages, *pkg) + // Add the current package + pkgs = append(pkgs, *pkg) delete(m.pkgs, rel.Dependency) // Delete the added package - m.addNestedPackageToApp(rel.Dependency, app) + // Add the nested packages + pkgs = append(pkgs, m.traverseDependencies(rel.Dependency)...) } + return pkgs } // addOrphanPkgs adds orphan packages. From ec0ad450d025cbcc131e429267758104add79265 Mon Sep 17 00:00:00 2001 From: knqyf263 Date: Tue, 24 Dec 2024 10:25:56 +0400 Subject: [PATCH 5/7] refactor: apply the same fix to OS packages Signed-off-by: knqyf263 --- pkg/sbom/io/decode.go | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/pkg/sbom/io/decode.go b/pkg/sbom/io/decode.go index 03e1c7979a22..4920f08b7323 100644 --- a/pkg/sbom/io/decode.go +++ b/pkg/sbom/io/decode.go @@ -330,15 +330,7 @@ func (m *Decoder) parseSrcVersion(ctx context.Context, pkg *ftypes.Package, ver // addOSPkgs traverses relationships and adds OS packages func (m *Decoder) addOSPkgs(sbom *types.SBOM) { - var pkgs []ftypes.Package - for _, rel := range m.bom.Relationships()[m.osID] { - pkg, ok := m.pkgs[rel.Dependency] - if !ok { - continue - } - pkgs = append(pkgs, *pkg) - delete(m.pkgs, rel.Dependency) // Delete the added package - } + pkgs := m.traverseDependencies(m.osID) if len(pkgs) == 0 { return } From b9e85e731173ce981ce93573d31e82f3fb4d0525 Mon Sep 17 00:00:00 2001 From: knqyf263 Date: Tue, 24 Dec 2024 10:31:28 +0400 Subject: [PATCH 6/7] fix: avoid infinite loop and duplicated packages Signed-off-by: knqyf263 --- pkg/sbom/io/decode.go | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/pkg/sbom/io/decode.go b/pkg/sbom/io/decode.go index 4920f08b7323..96d30218b959 100644 --- a/pkg/sbom/io/decode.go +++ b/pkg/sbom/io/decode.go @@ -19,6 +19,7 @@ import ( "github.com/aquasecurity/trivy/pkg/log" "github.com/aquasecurity/trivy/pkg/purl" "github.com/aquasecurity/trivy/pkg/sbom/core" + "github.com/aquasecurity/trivy/pkg/set" "github.com/aquasecurity/trivy/pkg/types" "github.com/aquasecurity/trivy/pkg/uuid" ) @@ -330,7 +331,7 @@ func (m *Decoder) parseSrcVersion(ctx context.Context, pkg *ftypes.Package, ver // addOSPkgs traverses relationships and adds OS packages func (m *Decoder) addOSPkgs(sbom *types.SBOM) { - pkgs := m.traverseDependencies(m.osID) + pkgs := m.traverseDependencies(m.osID, set.New[uuid.UUID]()) if len(pkgs) == 0 { return } @@ -340,7 +341,7 @@ func (m *Decoder) addOSPkgs(sbom *types.SBOM) { // addLangPkgs traverses relationships and adds language-specific packages func (m *Decoder) addLangPkgs(sbom *types.SBOM) { for id, app := range m.apps { - app.Packages = append(app.Packages, m.traverseDependencies(id)...) + app.Packages = append(app.Packages, m.traverseDependencies(id, set.New[uuid.UUID]())...) sbom.Applications = append(sbom.Applications, *app) } } @@ -350,19 +351,23 @@ func (m *Decoder) addLangPkgs(sbom *types.SBOM) { // dependent packages. The collected packages are removed from m.pkgs to prevent duplicate // processing. This ensures that all dependencies, including transitive ones, are properly // captured and associated with their parent component. -func (m *Decoder) traverseDependencies(id uuid.UUID) ftypes.Packages { +func (m *Decoder) traverseDependencies(id uuid.UUID, seen set.Set[uuid.UUID]) ftypes.Packages { var pkgs ftypes.Packages for _, rel := range m.bom.Relationships()[id] { + if seen.Contains(rel.Dependency) { + continue // Skip if already seen to avoid infinite loop and duplicate processing + } pkg, ok := m.pkgs[rel.Dependency] if !ok { continue } // Add the current package pkgs = append(pkgs, *pkg) + seen.Append(rel.Dependency) delete(m.pkgs, rel.Dependency) // Delete the added package // Add the nested packages - pkgs = append(pkgs, m.traverseDependencies(rel.Dependency)...) + pkgs = append(pkgs, m.traverseDependencies(rel.Dependency, seen)...) } return pkgs } From 4db29eb054a7d8291bf9914b0827bd8e2572c265 Mon Sep 17 00:00:00 2001 From: knqyf263 Date: Tue, 24 Dec 2024 10:50:54 +0400 Subject: [PATCH 7/7] revert Signed-off-by: knqyf263 --- pkg/sbom/io/decode.go | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/pkg/sbom/io/decode.go b/pkg/sbom/io/decode.go index 96d30218b959..4920f08b7323 100644 --- a/pkg/sbom/io/decode.go +++ b/pkg/sbom/io/decode.go @@ -19,7 +19,6 @@ import ( "github.com/aquasecurity/trivy/pkg/log" "github.com/aquasecurity/trivy/pkg/purl" "github.com/aquasecurity/trivy/pkg/sbom/core" - "github.com/aquasecurity/trivy/pkg/set" "github.com/aquasecurity/trivy/pkg/types" "github.com/aquasecurity/trivy/pkg/uuid" ) @@ -331,7 +330,7 @@ func (m *Decoder) parseSrcVersion(ctx context.Context, pkg *ftypes.Package, ver // addOSPkgs traverses relationships and adds OS packages func (m *Decoder) addOSPkgs(sbom *types.SBOM) { - pkgs := m.traverseDependencies(m.osID, set.New[uuid.UUID]()) + pkgs := m.traverseDependencies(m.osID) if len(pkgs) == 0 { return } @@ -341,7 +340,7 @@ func (m *Decoder) addOSPkgs(sbom *types.SBOM) { // addLangPkgs traverses relationships and adds language-specific packages func (m *Decoder) addLangPkgs(sbom *types.SBOM) { for id, app := range m.apps { - app.Packages = append(app.Packages, m.traverseDependencies(id, set.New[uuid.UUID]())...) + app.Packages = append(app.Packages, m.traverseDependencies(id)...) sbom.Applications = append(sbom.Applications, *app) } } @@ -351,23 +350,19 @@ func (m *Decoder) addLangPkgs(sbom *types.SBOM) { // dependent packages. The collected packages are removed from m.pkgs to prevent duplicate // processing. This ensures that all dependencies, including transitive ones, are properly // captured and associated with their parent component. -func (m *Decoder) traverseDependencies(id uuid.UUID, seen set.Set[uuid.UUID]) ftypes.Packages { +func (m *Decoder) traverseDependencies(id uuid.UUID) ftypes.Packages { var pkgs ftypes.Packages for _, rel := range m.bom.Relationships()[id] { - if seen.Contains(rel.Dependency) { - continue // Skip if already seen to avoid infinite loop and duplicate processing - } pkg, ok := m.pkgs[rel.Dependency] if !ok { continue } // Add the current package pkgs = append(pkgs, *pkg) - seen.Append(rel.Dependency) delete(m.pkgs, rel.Dependency) // Delete the added package // Add the nested packages - pkgs = append(pkgs, m.traverseDependencies(rel.Dependency, seen)...) + pkgs = append(pkgs, m.traverseDependencies(rel.Dependency)...) } return pkgs }