Skip to content

Commit

Permalink
added new endpoint for DependencyGraph
Browse files Browse the repository at this point in the history
  • Loading branch information
sahibamittal committed Oct 19, 2023
1 parent 6560d2e commit c7f1f0a
Show file tree
Hide file tree
Showing 8 changed files with 827 additions and 0 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
import org.dependencytrack.model.Project;
import org.dependencytrack.model.RepositoryMetaComponent;
import org.dependencytrack.model.RepositoryType;
import org.dependencytrack.resources.v1.vo.DependencyGraphResponse;

import javax.jdo.PersistenceManager;
import javax.jdo.Query;
Expand All @@ -47,6 +48,7 @@
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.UUID;

final class ComponentQueryManager extends QueryManager implements IQueryManager {

Expand Down Expand Up @@ -706,6 +708,18 @@ public Map<String, Component> getDependencyGraphForComponent(Project project, Co
return dependencyGraph;
}

/**
* Returns a list of all {@link DependencyGraphResponse} objects by {@link Component} UUID.
* @param uuids a list of {@link Component} UUIDs
* @return a list of {@link DependencyGraphResponse} objects
* @since 4.9.0
*/
public List<DependencyGraphResponse> getDependencyGraphByUUID(final List<UUID> uuids) {
final Query<Component> query = this.getObjectsByUuidsQuery(Component.class, uuids);
query.setResult("uuid, name, version, purl, directDependencies, null");
return List.copyOf(query.executeResultList(DependencyGraphResponse.class));
}

private void getParentDependenciesOfComponent(Project project, Component parentNode, Map<String, Component> dependencyGraph, Component searchedComponent) {
String queryUuid = ".*" + parentNode.getUuid().toString() + ".*";
final Query<Component> query = pm.newQuery(Component.class, "directDependencies.matches(:queryUuid) && project == :project");
Expand Down
80 changes: 80 additions & 0 deletions src/main/java/org/dependencytrack/persistence/QueryManager.java
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
import alpine.persistence.PaginatedResult;
import alpine.resources.AlpineRequest;
import com.github.packageurl.PackageURL;
import com.google.common.collect.Lists;
import io.github.resilience4j.retry.Retry;
import io.github.resilience4j.retry.RetryConfig;
import org.apache.commons.lang3.ClassUtils;
Expand Down Expand Up @@ -83,6 +84,7 @@
import org.dependencytrack.model.WorkflowStep;
import org.dependencytrack.notification.NotificationScope;
import org.dependencytrack.notification.publisher.PublisherClass;
import org.dependencytrack.resources.v1.vo.DependencyGraphResponse;
import org.hyades.proto.vulnanalysis.v1.ScanResult;
import org.hyades.proto.vulnanalysis.v1.ScanStatus;
import org.hyades.proto.vulnanalysis.v1.ScannerResult;
Expand All @@ -97,6 +99,7 @@
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.HashSet;
Expand Down Expand Up @@ -1379,6 +1382,35 @@ public <T> T detachWithGroups(final T object, final List<String> fetchGroups) {
}
}

/**
* Fetch a list of object from the datastore by theirs {@link UUID}
*
* @param clazz Class of the object to fetch
* @param uuids {@link UUID} list of uuids to fetch
* @return The list of objects found
* @param <T> Type of the object
* @since 4.9.0
*/
public <T> List<T> getObjectsByUuids(final Class<T> clazz, final List<UUID> uuids) {
final Query<T> query = getObjectsByUuidsQuery(clazz, uuids);
return query.executeList();
}

/**
* Create the query to fetch a list of object from the datastore by theirs {@link UUID}
*
* @param clazz Class of the object to fetch
* @param uuids {@link UUID} list of uuids to fetch
* @return The query to execute
* @param <T> Type of the object
* @since 4.9.0
*/
public <T> Query<T> getObjectsByUuidsQuery(final Class<T> clazz, final List<UUID> uuids) {
final Query<T> query = pm.newQuery(clazz, ":uuids.contains(uuid)");
query.setParameters(uuids);
return query;
}

/**
* Fetch an object from the datastore by its {@link UUID}, using the provided fetch groups.
* <p>
Expand Down Expand Up @@ -1473,6 +1505,54 @@ public void recursivelyDeleteTeam(Team team) {
pm.currentTransaction().commit();
}

/**
* Returns a list of all {@link DependencyGraphResponse} objects by {@link Component} UUID.
* @param uuids a list of {@link Component} UUIDs
* @return a list of {@link DependencyGraphResponse} objects
* @since 4.9.0
*/
public List<DependencyGraphResponse> getComponentDependencyGraphByUuids(final List<UUID> uuids) {
return this.getComponentQueryManager().getDependencyGraphByUUID(uuids);
}

/**
* Returns a list of all {@link DependencyGraphResponse} objects by {@link ServiceComponent} UUID.
* @param uuids a list of {@link ServiceComponent} UUIDs
* @return a list of {@link DependencyGraphResponse} objects
* @since 4.9.0
*/
public List<DependencyGraphResponse> getServiceDependencyGraphByUuids(final List<UUID> uuids) {
return this.getServiceComponentQueryManager().getDependencyGraphByUUID(uuids);
}

/**
* Returns a list of all {@link RepositoryMetaComponent} objects by {@link RepositoryQueryManager.RepositoryMetaComponentSearch} with batchSize 10.
* @param list a list of {@link RepositoryQueryManager.RepositoryMetaComponentSearch}
* @return a list of {@link RepositoryMetaComponent} objects
* @since 4.9.0
*/
public List<RepositoryMetaComponent> getRepositoryMetaComponentsBatch(final List<RepositoryQueryManager.RepositoryMetaComponentSearch> list) {
return getRepositoryMetaComponentsBatch(list, 10);
}

/**
* Returns a list of all {@link RepositoryMetaComponent} objects by {@link RepositoryQueryManager.RepositoryMetaComponentSearch} UUID.
* @param list a list of {@link RepositoryQueryManager.RepositoryMetaComponentSearch}
* @param batchSize the batch size
* @return a list of {@link RepositoryMetaComponent} objects
* @since 4.9.0
*/
public List<RepositoryMetaComponent> getRepositoryMetaComponentsBatch(final List<RepositoryQueryManager.RepositoryMetaComponentSearch> list, final int batchSize) {
final List<RepositoryMetaComponent> results = new ArrayList<>(list.size());

// Split the list into batches
for (List<RepositoryQueryManager.RepositoryMetaComponentSearch> batch : Lists.partition(list, batchSize)) {
results.addAll(this.getRepositoryQueryManager().getRepositoryMetaComponents(batch));
}

return results;
}

/**
* Create a new {@link VulnerabilityScan} record.
* <p>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,11 @@

import javax.jdo.PersistenceManager;
import javax.jdo.Query;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;

public class RepositoryQueryManager extends QueryManager implements IQueryManager {
Expand Down Expand Up @@ -242,4 +246,60 @@ public synchronized RepositoryMetaComponent synchronizeRepositoryMetaComponent(f
return persist(transientRepositoryMetaComponent);
}
}

/**
* Returns a list of {@link RepositoryMetaComponent} objects from the specified type, group, and name.
* @param list a list of {@link RepositoryQueryManager.RepositoryMetaComponentSearch} used to filter
* @return a List of {@link RepositoryMetaComponent} objects
* @since 4.9.0
*/
public List<RepositoryMetaComponent> getRepositoryMetaComponents(final List<RepositoryQueryManager.RepositoryMetaComponentSearch> list) {
final Query<RepositoryMetaComponent> query = pm.newQuery(RepositoryMetaComponent.class);

// Dynamically build the filter string and populate the parameters
final String filterTemplate = "(repositoryType == :%s && name == :%s && namespace == :%s)";

// List with all the filters
final List<String> filters = new ArrayList<>(list.size());

// Map with all the parameters
final Map<String, Object> params = new HashMap<>(list.size() * 3);

final String repositoryTypeTemplate = "repositoryType_%d";
final String nameTemplate = "name_%d";
final String namespaceTemplate = "namespace_%d";

String repositoryTypeTemplatePopulate;
String nameTemplatePopulate;
String namespaceTemplatePopulate;

for (int i = 0; i < list.size(); i++) {
// Create the template strings for this iteration
repositoryTypeTemplatePopulate = String.format(repositoryTypeTemplate, i);
namespaceTemplatePopulate = String.format(namespaceTemplate, i);
nameTemplatePopulate = String.format(nameTemplate, i);

// Add the filter to the list
filters.add(String.format(filterTemplate, repositoryTypeTemplatePopulate, nameTemplatePopulate, namespaceTemplatePopulate));

// Add the parameters to the map
params.put(repositoryTypeTemplatePopulate, list.get(i).type());
params.put(nameTemplatePopulate, list.get(i).name());
params.put(namespaceTemplatePopulate, list.get(i).namespace());
}

// Join all filters with OR operator
query.setFilter(String.join(" || ", filters));
query.setNamedParameters(params);
return query.executeList();
}


/**
* Object used to search for a RepositoryMetaComponent by type, namespace, and name.
*
* @author Nathan Mittelette <[email protected]>
* @since 4.9.0
*/
public record RepositoryMetaComponentSearch(RepositoryType type, String namespace, String name) implements Serializable { }
}
Original file line number Diff line number Diff line change
Expand Up @@ -23,12 +23,14 @@
import org.dependencytrack.model.ComponentIdentity;
import org.dependencytrack.model.Project;
import org.dependencytrack.model.ServiceComponent;
import org.dependencytrack.resources.v1.vo.DependencyGraphResponse;

import javax.jdo.PersistenceManager;
import javax.jdo.Query;
import javax.jdo.Transaction;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;

final class ServiceComponentQueryManager extends QueryManager implements IQueryManager {

Expand Down Expand Up @@ -287,4 +289,16 @@ public void recursivelyDelete(ServiceComponent service, boolean commitIndex) {
}
}
}

/**
* Returns a list of all {@link DependencyGraphResponse} objects by {@link ServiceComponent} UUID.
* @param uuids a list of {@link ServiceComponent} UUIDs
* @return a list of {@link DependencyGraphResponse} objects
* @since 4.9.0
*/
public List<DependencyGraphResponse> getDependencyGraphByUUID(final List<UUID> uuids) {
final Query<ServiceComponent> query = this.getObjectsByUuidsQuery(ServiceComponent.class, uuids);
query.setResult("uuid, name, version, null, null, null");
return List.copyOf(query.executeResultList(DependencyGraphResponse.class));
}
}
Loading

0 comments on commit c7f1f0a

Please sign in to comment.