diff --git a/pkg/dependencies/dependents.go b/pkg/dependencies/dependents.go index ae5fa30698f..2fb663b4f3c 100644 --- a/pkg/dependencies/dependents.go +++ b/pkg/dependencies/dependents.go @@ -89,7 +89,6 @@ func findDependentsOfDependencies(ctx context.Context, gqlClient graphql.Client) idToName := make(map[string]string) sboms, err := model.HasSBOMs(ctx, gqlClient, model.HasSBOMSpec{}) - if err != nil { return nil, fmt.Errorf("error getting dependencies: %v", err) } @@ -100,29 +99,34 @@ func findDependentsOfDependencies(ctx context.Context, gqlClient graphql.Client) continue } // Iterate through the included dependencies of each SBOM. - for _, dependency := range resp.IncludedDependencies { + for _, isDependency := range resp.IncludedDependencies { // Construct unique names for the dependency package and the package itself. - depPkgName := helpers.AllPkgTreeToPurl(&dependency.DependencyPackage.AllPkgTree) - pkgName := helpers.AllPkgTreeToPurl(&dependency.Package.AllPkgTree) + depPkgName := helpers.PkgToPurl(isDependency.DependencyPackage.Type, isDependency.DependencyPackage.Namespaces[0].Namespace, isDependency.DependencyPackage.Namespaces[0].Names[0].Name, "", "", []string{}) + pkgName := helpers.PkgToPurl(isDependency.Package.Type, isDependency.Package.Namespaces[0].Namespace, isDependency.Package.Namespaces[0].Names[0].Name, "", "", []string{}) var depPkgIds []string - pkgId := dependency.Package.Namespaces[0].Names[0].Versions[0].Id + pkgId := isDependency.Package.Namespaces[0].Names[0].Versions[0].Id - if len(dependency.DependencyPackage.Namespaces[0].Names[0].Versions) == 0 { - findMatchingDepPkgVersionIDs, err := FindDepPkgVersionIDs(ctx, gqlClient, dependency.DependencyPackage.Type, - dependency.DependencyPackage.Namespaces[0].Namespace, - dependency.DependencyPackage.Namespaces[0].Names[0].Name, dependency.VersionRange) + if len(isDependency.DependencyPackage.Namespaces[0].Names[0].Versions) == 0 { + findMatchingDepPkgVersionIDs, err := FindDepPkgVersionIDs(ctx, gqlClient, isDependency.DependencyPackage.Type, + isDependency.DependencyPackage.Namespaces[0].Namespace, + isDependency.DependencyPackage.Namespaces[0].Names[0].Name, isDependency.VersionRange) if err != nil { return nil, fmt.Errorf("error from FindMatchingDepPkgVersionIDs:%w", err) } depPkgIds = append(depPkgIds, findMatchingDepPkgVersionIDs...) } else { - depPkgIds = append(depPkgIds, dependency.DependencyPackage.Namespaces[0].Names[0].Versions[0].Id) + depPkgIds = append(depPkgIds, isDependency.DependencyPackage.Namespaces[0].Names[0].Versions[0].Id) } for _, depPkgId := range depPkgIds { + // Skip "guac" files. + if isDependency.DependencyPackage.Type == "guac" && isDependency.DependencyPackage.Namespaces[0].Namespace == "files" { + continue + } + // Inside the loop where you iterate through dependencies - updatePackagesAndNames(idToName, packages, depPkgId, pkgId, depPkgName, pkgName, dependency.DependencyPackage.Type, dependency.DependencyPackage.Namespaces[0].Namespace, dependencyEdges, dependentEdges) + updatePackagesAndNames(idToName, packages, depPkgId, pkgId, depPkgName, pkgName, dependencyEdges, dependentEdges) // Update the edges with pkgId and depPkgId. dependentEdges[depPkgId] = append(dependentEdges[depPkgId], pkgId) // pkgId is dependent on depPkgId @@ -140,25 +144,19 @@ func findDependentsOfDependencies(ctx context.Context, gqlClient graphql.Client) // This function skips processing for "guac" files in the "files" namespace and updates the provided maps with // the relationships between packages and their dependencies. It leverages traverseGraph to find all packages // that are either dependencies of or dependents on the given package, and updates the packages map accordingly. -func updatePackagesAndNames(idToName map[string]string, packages map[string]dependencyNode, depPkgId, pkgId, depPkgName, pkgName, depPkgType, depPkgNamespace string, dependencyEdges, dependentEdges map[string][]string) { - // Skip "guac" files. - if depPkgType == "guac" && depPkgNamespace == "files" { - return - } - +func updatePackagesAndNames(idToName map[string]string, packages map[string]dependencyNode, depPkgId, pkgId, depPkgName, pkgName string, dependencyEdges, dependentEdges map[string][]string) { // Map the IDs to their names. idToName[depPkgId] = depPkgName idToName[pkgId] = pkgName - // First, we need to find all the packages that have pkgName as a dependency. - // Note that we are only searching of packages with pkgName as a dependency from the packages that have scanned so far. - - // This dependencyPackages map finds all packages that have pkgName as a dependent out of our pre-scanned packages. + // First, we need to find all the packages that are dependencies of pkgName. + // We need to add them all to the dependencies of all nodes that have pkgName as a dependent. + // Note that we are only searching for dependencies of pkgName from the edges that have scanned so far dependencyPackages := traverseGraph(depPkgId, dependencyEdges) - // Next we want to find all the packages that are dependencies of pkgName. - // We need to add them all to the dependencies of all nodes that have pkgName as a dependent. - // Note that we are only searching for dependencies of pkgName from the packages that have scanned so far + // Next we want to find all the packages that have pkgName as a dependency. + // Note that we are only searching of packages with pkgName as a dependency from the edges that have scanned so far. + // This dependentPackages map finds all packages that have pkgName as a dependent out of our pre-scanned packages. dependentPackages := traverseGraph(pkgId, dependentEdges) for depPkgNodeId := range dependencyPackages { diff --git a/pkg/dependencies/dependents_test.go b/pkg/dependencies/dependents_test.go index 603b26caa28..5b0aabc904a 100644 --- a/pkg/dependencies/dependents_test.go +++ b/pkg/dependencies/dependents_test.go @@ -20,7 +20,7 @@ package dependencies import ( "context" "fmt" - "net/http" + clients "github.com/guacsec/guac/internal/testing/graphqlClients" "testing" "time" @@ -48,10 +48,7 @@ type specInfo struct { } func Test_findAllDependencies(t *testing.T) { - graphqlEndpoint := "http://localhost:8080/query" - - httpClient := http.Client{} - gqlClient := graphql.NewClient(graphqlEndpoint, &httpClient) + gqlClient := clients.SetupTest(t) ctx := context.Background() @@ -82,7 +79,7 @@ func Test_findAllDependencies(t *testing.T) { D1, E1, F1, G1, B1 and C1 all depend on A1 */ - check(t, false, map[string]int{"test__A1": 6, "test__B1": 2, "test__C1": 2}) + check(t, false, map[string]int{"pkg:test/A1": 6, "pkg:test/B1": 2, "pkg:test/C1": 2}, gqlClient) }) t.Run("two separate graphs", func(t *testing.T) { @@ -121,7 +118,7 @@ func Test_findAllDependencies(t *testing.T) { they have the same Name. */ - check(t, false, map[string]int{"test__A2": 6, "test__B2": 3, "test__C2": 2}) + check(t, false, map[string]int{"pkg:test/A2": 6, "pkg:test/B2": 3, "pkg:test/C2": 2}, gqlClient) }) t.Run("two different versions in same graph", func(t *testing.T) { @@ -158,7 +155,7 @@ func Test_findAllDependencies(t *testing.T) { A3 -------+ */ - check(t, false, map[string]int{"test__A3": 7, "test__B3": 3, "test__C3": 2}) + check(t, false, map[string]int{"pkg:test/A3": 8, "pkg:test/B3": 3, "pkg:test/C3": 2}, gqlClient) }) t.Run("different versions same graph 2", func(t *testing.T) { @@ -199,7 +196,7 @@ func Test_findAllDependencies(t *testing.T) { A4 */ - check(t, false, map[string]int{"test__A4": 7, "test__B4": 3, "test__C4": 4, "test__F4": 2}) + check(t, false, map[string]int{"pkg:test/A4": 8, "pkg:test/B4": 3, "pkg:test/C4": 4, "pkg:test/F4": 2}, gqlClient) }) } @@ -326,10 +323,7 @@ func createOccurrenceAndArtifact(t *testing.T, ctx context.Context, gqlClient gr return err, id } -func check(t *testing.T, wantErr bool, want map[string]int) { - endpoint := "http://localhost:8080/query" - httpClient := http.Client{} - gqlClient := graphql.NewClient(endpoint, &httpClient) +func check(t *testing.T, wantErr bool, want map[string]int, gqlClient graphql.Client) { ctx := context.Background() got, err := findDependentsOfDependencies(ctx, gqlClient)