Skip to content

Commit

Permalink
fix: support cyclic dependencies
Browse files Browse the repository at this point in the history
Signed-off-by: Ruben Romero Montes <[email protected]>
  • Loading branch information
ruromero committed Sep 15, 2023
1 parent cc7b7ca commit 035c70c
Show file tree
Hide file tree
Showing 7 changed files with 430 additions and 7 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -139,8 +139,11 @@ private void addDependencies(
}
deps.forEach(
d -> {
builder.transitive.add(componentPurls.get(d.getRef()));
addDependencies(d.getRef(), indexedDeps, builder, componentPurls);
PackageRef tRef = componentPurls.get(d.getRef());
if (!builder.transitive.contains(tRef)) {
builder.transitive.add(tRef);
addDependencies(d.getRef(), indexedDeps, builder, componentPurls);
}
});
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,11 @@ private Map<PackageRef, DirectDependency> buildDeps(SpdxWrapper wrapper) {
.filter(e -> !e.getKey().equals(k))
.noneMatch(e -> e.getValue().contains(k)))
.collect(Collectors.toSet());
if (!links.isEmpty() && directDeps.isEmpty()) {
throw new SpdxProcessingException(
"Unable to calculate direct dependencies due to a cyclic relationship");
}

Map<String, Set<String>> flatDepTree = new HashMap<>();
directDeps.stream()
.forEach(
Expand Down
12 changes: 8 additions & 4 deletions src/main/java/com/redhat/exhort/model/DependencyTree.java
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@

package com.redhat.exhort.model;

import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.Map;
Expand Down Expand Up @@ -55,10 +56,13 @@ public int directCount() {
}

public int transitiveCount() {
return dependencies.values().stream()
.map(d -> d.transitive().size())
.reduce(Integer::sum)
.orElse(0);
return Long.valueOf(
dependencies.values().stream()
.map(d -> d.transitive())
.flatMap(Collection::stream)
.distinct()
.count())
.intValue();
}

public int count() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,35 @@ void testMinimalSbom(String mediaType) {
assertEquals(EXPECTED_ROOT, tree.root());
}

@Test
void testCyclicReferencesCycloneDX() {
SbomParser parser =
SbomParserFactory.newInstance(CycloneDxMediaType.APPLICATION_CYCLONEDX_JSON);
String fileName =
String.format(
"%s/cyclic-sbom.json", getFolder(CycloneDxMediaType.APPLICATION_CYCLONEDX_JSON));
InputStream file = getClass().getClassLoader().getResourceAsStream(fileName);

DependencyTree tree = parser.buildTree(file);
assertEquals(2, tree.dependencies().size());
assertEquals(9, tree.transitiveCount());
assertEquals(EXPECTED_ROOT, tree.root());
}

@Test
void testCyclicReferencesSPDX() {
SbomParser parser = SbomParserFactory.newInstance(Constants.SPDX_MEDIATYPE_JSON);
String fileName =
String.format("%s/cyclic-sbom.json", getFolder(Constants.SPDX_MEDIATYPE_JSON));
InputStream file = getClass().getClassLoader().getResourceAsStream(fileName);

ClientErrorException e = assertThrows(ClientErrorException.class, () -> parser.buildTree(file));
assertEquals(
"Unable to parse received SPDX SBOM file: Unable to calculate direct dependencies due to a"
+ " cyclic relationship",
e.getMessage());
}

@ParameterizedTest
@MethodSource("getSbomUseCases")
void testSbom(String mediaType, String pkgManager, int direct, int transitive, PackageRef root) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ public void testIgnoreDuplicates() {
assertEquals(1, report.getDependencies().get(1).getTransitive().size());

assertEquals(2, report.getSummary().getDependencies().getScanned());
assertEquals(4, report.getSummary().getDependencies().getTransitive());
assertEquals(3, report.getSummary().getDependencies().getTransitive());

assertEquals(2, report.getSummary().getVulnerabilities().getTotal());
}
Expand Down
127 changes: 127 additions & 0 deletions src/test/resources/cyclonedx/cyclic-sbom.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
{
"bomFormat" : "CycloneDX",
"specVersion" : "1.4",
"version" : 1,
"metadata" : {
"component" : {
"name" : "postgresql-orm-quarkus",
"purl" : "pkg:maven/org.acme.dbaas/[email protected]?type=jar",
"type" : "library",
"bom-ref" : "pkg:maven/org.acme.dbaas/[email protected]?type=jar"
}
},
"components" : [
{
"name" : "quarkus-hibernate-orm",
"purl" : "pkg:maven/io.quarkus/[email protected]?type=jar",
"type" : "library",
"bom-ref" : "pkg:maven/io.quarkus/[email protected]?type=jar"
},
{
"name" : "quarkus-core",
"purl" : "pkg:maven/io.quarkus/[email protected]?type=jar",
"type" : "library",
"bom-ref" : "pkg:maven/io.quarkus/[email protected]?type=jar"
},
{
"name" : "jakarta.enterprise.cdi-api",
"purl" : "pkg:maven/jakarta.enterprise/[email protected]?type=jar",
"type" : "library",
"bom-ref" : "pkg:maven/jakarta.enterprise/[email protected]?type=jar"
},
{
"name" : "jakarta.el-api",
"purl" : "pkg:maven/jakarta.el/[email protected]?type=jar",
"type" : "library",
"bom-ref" : "pkg:maven/jakarta.el/[email protected]?type=jar"
},
{
"name" : "quarkus-jdbc-postgresql",
"purl" : "pkg:maven/io.quarkus/[email protected]?type=jar",
"type" : "library",
"bom-ref" : "pkg:maven/io.quarkus/[email protected]?type=jar"
},
{
"name" : "postgresql",
"purl" : "pkg:maven/org.postgresql/[email protected]?type=jar",
"type" : "library",
"bom-ref" : "pkg:maven/org.postgresql/[email protected]?type=jar"
},
{
"name" : "jackson-databind",
"purl" : "pkg:maven/com.fasterxml.jackson.core/[email protected]?type=jar",
"type" : "library",
"bom-ref" : "pkg:maven/com.fasterxml.jackson.core/[email protected]?type=jar"
},
{
"name" : "quarkus-narayana-jta",
"purl" : "pkg:maven/io.quarkus/[email protected]?type=jar",
"type" : "library",
"bom-ref" : "pkg:maven/io.quarkus/[email protected]?type=jar"
},
{
"name" : "jakarta.interceptor-api",
"purl" : "pkg:maven/jakarta.interceptor/[email protected]?type=jar",
"type" : "library",
"bom-ref" : "pkg:maven/jakarta.interceptor/[email protected]?type=jar"
}
],
"dependencies" : [
{
"ref" : "pkg:maven/org.acme.dbaas/[email protected]?type=jar",
"dependsOn" : [
"pkg:maven/io.quarkus/[email protected]?type=jar",
"pkg:maven/io.quarkus/[email protected]?type=jar"
]
},
{
"ref" : "pkg:maven/io.quarkus/[email protected]?type=jar",
"dependsOn" : [
"pkg:maven/io.quarkus/[email protected]?type=jar",
"pkg:maven/io.quarkus/[email protected]?type=jar",
"pkg:maven/io.quarkus/[email protected]?type=jar"
]
},
{
"ref" : "pkg:maven/io.quarkus/[email protected]?type=jar",
"dependsOn" : [
"pkg:maven/com.fasterxml.jackson.core/[email protected]?type=jar",
"pkg:maven/jakarta.enterprise/[email protected]?type=jar"
]
},
{
"ref" : "pkg:maven/io.quarkus/[email protected]?type=jar",
"dependsOn" : [ ]
},
{
"ref" : "pkg:maven/com.fasterxml.jackson.core/[email protected]?type=jar",
"dependsOn" : [ ]
},
{
"ref" : "pkg:maven/jakarta.enterprise/[email protected]?type=jar",
"dependsOn" : [
"pkg:maven/jakarta.el/[email protected]?type=jar",
"pkg:maven/jakarta.interceptor/[email protected]?type=jar"
]
},
{
"ref" : "pkg:maven/io.quarkus/[email protected]?type=jar",
"dependsOn" : [
"pkg:maven/org.postgresql/[email protected]?type=jar",
"pkg:maven/io.quarkus/[email protected]?type=jar"
]
},
{
"ref" : "pkg:maven/jakarta.el/[email protected]?type=jar",
"dependsOn" : [ ]
},
{
"ref" : "pkg:maven/jakarta.interceptor/[email protected]?type=jar",
"dependsOn" : [ ]
},
{
"ref" : "pkg:maven/org.postgresql/[email protected]?type=jar",
"dependsOn" : [ ]
}
]
}
Loading

0 comments on commit 035c70c

Please sign in to comment.