Skip to content

Commit

Permalink
Merge pull request #137 from ruromero/dep-tree
Browse files Browse the repository at this point in the history
fix: Resolve CycloneDX dependency common tree
  • Loading branch information
zvigrinberg authored Sep 5, 2023
2 parents 2951f51 + c9b932c commit 0c7a342
Showing 1 changed file with 51 additions and 37 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -20,15 +20,18 @@

import java.io.IOException;
import java.io.InputStream;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.stream.Collectors;

import org.cyclonedx.model.Bom;
import org.cyclonedx.model.Component;
import org.cyclonedx.model.Dependency;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

Expand All @@ -39,6 +42,7 @@
import com.redhat.exhort.integration.backend.sbom.SbomParser;
import com.redhat.exhort.model.DependencyTree;
import com.redhat.exhort.model.DirectDependency;
import com.redhat.exhort.model.DirectDependency.Builder;

import jakarta.ws.rs.ClientErrorException;
import jakarta.ws.rs.core.Response;
Expand Down Expand Up @@ -75,49 +79,43 @@ protected DependencyTree buildTree(InputStream input) {
Optional<Component> rootComponent = Optional.ofNullable(bom.getMetadata().getComponent());
if (rootComponent.isPresent()) {
treeBuilder.root(PackageRef.builder().purl(rootComponent.get().getPurl()).build());
if (!componentPurls.containsKey(rootComponent.get().getBomRef())) {
componentPurls.put(
rootComponent.get().getBomRef(), new PackageRef(rootComponent.get().getPurl()));
}
} else { // rootless SBOM
treeBuilder.root(DependencyTree.getDefaultRoot(packageManager));
}

bom.getDependencies().stream()
.forEach(
if (rootComponent.isPresent()) {
Map<String, List<Dependency>> indexedDeps =
bom.getDependencies().stream()
.collect(
Collectors.toMap(
d -> d.getRef(),
d ->
Optional.ofNullable(d.getDependencies())
.orElse(Collections.emptyList())));
List<Dependency> directDeps = indexedDeps.get(rootComponent.get().getBomRef());
if (directDeps != null) {
directDeps.forEach(
d -> {
if (rootComponent.isEmpty()) {
PackageRef ref = componentPurls.get(d.getRef());
direct.put(ref, DirectDependency.builder().ref(ref));
} else if (d.getRef().equals(rootComponent.get().getBomRef())) {
d.getDependencies()
.forEach(
rootDep -> {
PackageRef ref = componentPurls.get(rootDep.getRef());
direct.put(
ref,
DirectDependency.builder().ref(ref).transitive(new HashSet<>()));
});
} else if (d.getDependencies() != null) {
PackageRef source = componentPurls.get(d.getRef());
DirectDependency.Builder directBuilder = direct.get(source);
if (directBuilder == null) {
direct.values().stream()
.filter(v -> v.transitive.contains(source))
.forEach(
v ->
d.getDependencies()
.forEach(
t -> {
PackageRef target = componentPurls.get(t.getRef());
v.transitive.add(target);
}));
} else {
d.getDependencies()
.forEach(
t -> {
PackageRef target = componentPurls.get(t.getRef());
directBuilder.transitive.add(target);
});
}
}
PackageRef pkgRef = componentPurls.get(d.getRef());
direct.put(pkgRef, new Builder().ref(pkgRef).transitive(new HashSet<>()));
addDependencies(d.getRef(), indexedDeps, direct.get(pkgRef), componentPurls);
});
}
} else {
// Rootless sboms are expected to be flat. i.e. no transitive dependencies
bom.getDependencies().stream()
.map(d -> componentPurls.get(d.getRef()))
.filter(Objects::nonNull)
.forEach(
c ->
direct.put(
c,
new DirectDependency.Builder().ref(c).transitive(Collections.emptySet())));
}
Map<PackageRef, DirectDependency> deps =
direct.entrySet().stream()
.map(e -> Map.entry(e.getKey(), e.getValue().build()))
Expand All @@ -129,4 +127,20 @@ protected DependencyTree buildTree(InputStream input) {
"Unable to parse received CycloneDX SBOM file", Response.Status.BAD_REQUEST);
}
}

private void addDependencies(
String bomRef,
Map<String, List<Dependency>> indexedDeps,
Builder builder,
Map<String, PackageRef> componentPurls) {
List<Dependency> deps = indexedDeps.get(bomRef);
if (deps == null || deps.isEmpty()) {
return;
}
deps.forEach(
d -> {
builder.transitive.add(componentPurls.get(d.getRef()));
addDependencies(d.getRef(), indexedDeps, builder, componentPurls);
});
}
}

0 comments on commit 0c7a342

Please sign in to comment.