From 7bfb4c86a6d7e5343c45c2844a232b6c7ba4c51c Mon Sep 17 00:00:00 2001 From: Keith Zantow Date: Wed, 21 May 2025 21:28:40 -0400 Subject: [PATCH] fix(dotnet-deps-cataloger): avoid repeated dependency resolution (#3930) Signed-off-by: Keith Zantow --- syft/pkg/cataloger/dotnet/deps_json.go | 20 ++++++++++++-------- syft/pkg/cataloger/dotnet/deps_json_test.go | 5 +++++ 2 files changed, 17 insertions(+), 8 deletions(-) diff --git a/syft/pkg/cataloger/dotnet/deps_json.go b/syft/pkg/cataloger/dotnet/deps_json.go index d61f09ce5..b0a8d2af8 100644 --- a/syft/pkg/cataloger/dotnet/deps_json.go +++ b/syft/pkg/cataloger/dotnet/deps_json.go @@ -252,8 +252,8 @@ func getLogicalDepsJSON(deps depsJSON, lm *libmanJSON) logicalDepsJSON { if !bundlingDetected && knownBundlers.Has(name) { bundlingDetected = true } - p.AnyChildClaimsDLLs = searchForDLLClaims(packageMap, p.dependencyNameVersions()...) - p.AnyChildHasDLLs = searchForDLLEvidence(packageMap, p.dependencyNameVersions()...) + p.AnyChildClaimsDLLs = searchForDLLClaims(packageMap, strset.New(), p.dependencyNameVersions()...) + p.AnyChildHasDLLs = searchForDLLEvidence(packageMap, strset.New(), p.dependencyNameVersions()...) packages[p.NameVersion] = *p } @@ -286,31 +286,35 @@ func mergeSets(s1, s2 *strset.Set) *strset.Set { type visitorFunc func(p *logicalDepsJSONPackage) bool // searchForDLLEvidence recursively searches for executables found for any of the given nameVersions and children recursively. -func searchForDLLEvidence(packageMap map[string]*logicalDepsJSONPackage, nameVersions ...string) bool { +func searchForDLLEvidence(packageMap map[string]*logicalDepsJSONPackage, visited *strset.Set, nameVersions ...string) bool { return traverseDependencies(packageMap, func(p *logicalDepsJSONPackage) bool { return p.FoundDLLs(true) - }, nameVersions...) + }, visited, nameVersions...) } // searchForDLLClaims recursively searches for DLL claims in the deps.json for any of the given nameVersions and children recursively. -func searchForDLLClaims(packageMap map[string]*logicalDepsJSONPackage, nameVersions ...string) bool { +func searchForDLLClaims(packageMap map[string]*logicalDepsJSONPackage, visited *strset.Set, nameVersions ...string) bool { return traverseDependencies(packageMap, func(p *logicalDepsJSONPackage) bool { return p.ClaimsDLLs(true) - }, nameVersions...) + }, visited, nameVersions...) } -func traverseDependencies(packageMap map[string]*logicalDepsJSONPackage, visitor visitorFunc, nameVersions ...string) bool { +func traverseDependencies(packageMap map[string]*logicalDepsJSONPackage, visitor visitorFunc, visited *strset.Set, nameVersions ...string) bool { if len(nameVersions) == 0 { return false } for _, nameVersion := range nameVersions { + if visited.Has(nameVersion) { + continue + } + visited.Add(nameVersion) if p, ok := packageMap[nameVersion]; ok { if visitor(p) { return true } - if traverseDependencies(packageMap, visitor, p.dependencyNameVersions()...) { + if traverseDependencies(packageMap, visitor, visited, p.dependencyNameVersions()...) { return true } } diff --git a/syft/pkg/cataloger/dotnet/deps_json_test.go b/syft/pkg/cataloger/dotnet/deps_json_test.go index 96fd34571..d8e391558 100644 --- a/syft/pkg/cataloger/dotnet/deps_json_test.go +++ b/syft/pkg/cataloger/dotnet/deps_json_test.go @@ -149,6 +149,11 @@ func TestGetLogicalDepsJSON_MergeTargets(t *testing.T) { "lib/netcoreapp3.1/Microsoft.CodeAnalysis.CSharp.dll": {}, }, }, + "Microsoft.CodeAnalysis.Common/4.0.0": { + Dependencies: map[string]string{ + "Microsoft.CodeAnalysis.CSharp": "4.0.0", + }, + }, }, }, Libraries: map[string]depsLibrary{