Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Show version status information on dependency graph nodes #2273

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
Expand Up @@ -583,9 +583,21 @@ public Map<String, Component> getDependencyGraphForComponent(Project project, Co
transientComponent.setUuid(entry.getValue().getUuid());
transientComponent.setName(entry.getValue().getName());
transientComponent.setVersion(entry.getValue().getVersion());
transientComponent.setPurl(entry.getValue().getPurl());
transientComponent.setPurlCoordinates(entry.getValue().getPurlCoordinates());
transientComponent.setDependencyGraph(entry.getValue().getDependencyGraph());
transientComponent.setExpandDependencyGraph(entry.getValue().isExpandDependencyGraph());
if (transientComponent.getPurl() != null) {
final RepositoryType type = RepositoryType.resolve(transientComponent.getPurl());
if (RepositoryType.UNSUPPORTED != type) {
final RepositoryMetaComponent repoMetaComponent = getRepositoryMetaComponent(type, transientComponent.getPurl().getNamespace(), transientComponent.getPurl().getName());
if (repoMetaComponent != null) {
RepositoryMetaComponent transientRepoMetaComponent = new RepositoryMetaComponent();
transientRepoMetaComponent.setLatestVersion(repoMetaComponent.getLatestVersion());
transientComponent.setRepositoryMeta(transientRepoMetaComponent);
}
}
}
dependencyGraph.put(entry.getKey(), transientComponent);
}
return dependencyGraph;
Expand Down
Expand Up @@ -40,6 +40,8 @@
import org.dependencytrack.model.ComponentIdentity;
import org.dependencytrack.model.License;
import org.dependencytrack.model.Project;
import org.dependencytrack.model.RepositoryType;
import org.dependencytrack.model.RepositoryMetaComponent;
import org.dependencytrack.persistence.QueryManager;
import org.dependencytrack.util.InternalComponentIdentificationUtil;

Expand Down Expand Up @@ -115,13 +117,22 @@ public Response getAllComponents(@PathParam("uuid") String uuid) {
@PermissionRequired(Permissions.Constants.VIEW_PORTFOLIO)
public Response getComponentByUuid(
@ApiParam(value = "The UUID of the component to retrieve", required = true)
@PathParam("uuid") String uuid) {
@PathParam("uuid") String uuid,
@ApiParam(value = "Optionally includes third-party metadata about the component from external repositories", required = false)
@QueryParam("includeRepositoryMetaData") boolean includeRepositoryMetaData) {
try (QueryManager qm = new QueryManager()) {
final Component component = qm.getObjectByUuid(Component.class, uuid);
if (component != null) {
final Project project = component.getProject();
if (qm.hasAccess(super.getPrincipal(), project)) {
final Component detachedComponent = qm.detach(Component.class, component.getId()); // TODO: Force project to be loaded. It should be anyway, but JDO seems to be having issues here.
if (includeRepositoryMetaData && detachedComponent.getPurl() != null) {
final RepositoryType type = RepositoryType.resolve(detachedComponent.getPurl());
rbt-mm marked this conversation as resolved.
Show resolved Hide resolved
if (RepositoryType.UNSUPPORTED != type) {
final RepositoryMetaComponent repoMetaComponent = qm.getRepositoryMetaComponent(type, detachedComponent.getPurl().getNamespace(), detachedComponent.getPurl().getName());
detachedComponent.setRepositoryMeta(repoMetaComponent);
}
}
return Response.ok(detachedComponent).build();
} else {
return Response.status(Response.Status.FORBIDDEN).entity("Access to the specified component is forbidden").build();
Expand Down
Expand Up @@ -25,6 +25,8 @@
import org.dependencytrack.ResourceTest;
import org.dependencytrack.model.Component;
import org.dependencytrack.model.Project;
import org.dependencytrack.model.RepositoryMetaComponent;
import org.dependencytrack.model.RepositoryType;
import org.glassfish.jersey.server.ResourceConfig;
import org.glassfish.jersey.servlet.ServletContainer;
import org.glassfish.jersey.test.DeploymentContext;
Expand All @@ -37,6 +39,7 @@
import javax.ws.rs.client.Entity;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import java.util.Date;
import java.util.UUID;

import static org.assertj.core.api.Assertions.assertThat;
Expand Down Expand Up @@ -108,6 +111,37 @@ public void getComponentByInvalidUuidTest() {
Assert.assertEquals("The component could not be found.", body);
}

@Test
public void getComponentByUuidWithRepositoryMetaDataTest() {
Project project = qm.createProject("Acme Application", null, null, null, null, null, true, false);
Component component = new Component();
component.setProject(project);
component.setName("ABC");
component.setPurl("pkg:maven/org.acme/abc");
RepositoryMetaComponent meta = new RepositoryMetaComponent();
Date lastCheck = new Date();
meta.setLastCheck(lastCheck);
meta.setNamespace("org.acme");
meta.setName("abc");
meta.setLatestVersion("2.0.0");
meta.setRepositoryType(RepositoryType.MAVEN);
qm.persist(meta);
component = qm.createComponent(component, false);
Response response = target(V1_COMPONENT + "/" + component.getUuid())
.queryParam("includeRepositoryMetaData", true)
.request().header(X_API_KEY, apiKey).get(Response.class);
Assert.assertEquals(200, response.getStatus(), 0);
Assert.assertNull(response.getHeaderString(TOTAL_COUNT_HEADER));
JsonObject json = parseJsonObject(response);
Assert.assertNotNull(json);
Assert.assertEquals("ABC", json.getString("name"));
Assert.assertEquals("MAVEN", json.getJsonObject("repositoryMeta").getString("repositoryType"));
Assert.assertEquals("org.acme", json.getJsonObject("repositoryMeta").getString("namespace"));
Assert.assertEquals("abc", json.getJsonObject("repositoryMeta").getString("name"));
Assert.assertEquals("2.0.0", json.getJsonObject("repositoryMeta").getString("latestVersion"));
Assert.assertEquals(lastCheck.getTime(), json.getJsonObject("repositoryMeta").getJsonNumber("lastCheck").longValue());
}

@Test
public void getComponentByIdentityWithCoordinatesTest() {
final Project projectA = qm.createProject("projectA", null, "1.0", null, null, null, true, false);
Expand Down Expand Up @@ -480,6 +514,70 @@ public void getDependencyGraphForComponentTest() {
Assert.assertThrows(NullPointerException.class, () -> json.get(finalComponent2_1_1_1.getUuid().toString()).asJsonObject().asJsonObject());
}

@Test
public void getDependencyGraphForComponentTestWithRepositoryMetaData() {
Project project = qm.createProject("Acme Application", null, null, null, null, null, true, false);

Component component1 = new Component();
component1.setProject(project);
component1.setName("Component1");
component1.setVersion("1.0.0");
component1.setPurl("pkg:maven/org.acme/component1");
RepositoryMetaComponent meta1 = new RepositoryMetaComponent();
Date lastCheck = new Date();
meta1.setLastCheck(lastCheck);
meta1.setNamespace("org.acme");
meta1.setName("component1");
meta1.setLatestVersion("2.0.0");
meta1.setRepositoryType(RepositoryType.MAVEN);
qm.persist(meta1);
component1 = qm.createComponent(component1, false);

Component component1_1 = new Component();
component1_1.setProject(project);
component1_1.setName("Component1_1");
component1_1.setVersion("2.0.0");
component1_1.setPurl("pkg:maven/org.acme/component1_1");
RepositoryMetaComponent meta1_1 = new RepositoryMetaComponent();
meta1_1.setLastCheck(lastCheck);
meta1_1.setNamespace("org.acme");
meta1_1.setName("component1_1");
meta1_1.setLatestVersion("3.0.0");
meta1_1.setRepositoryType(RepositoryType.MAVEN);
qm.persist(meta1_1);
component1_1 = qm.createComponent(component1_1, false);

Component component1_1_1 = new Component();
component1_1_1.setProject(project);
component1_1_1.setName("Component1_1_1");
component1_1_1.setVersion("3.0.0");
component1_1_1.setPurl("pkg:maven/org.acme/component1_1_1");
RepositoryMetaComponent meta1_1_1 = new RepositoryMetaComponent();
meta1_1_1.setLastCheck(lastCheck);
meta1_1_1.setNamespace("org.acme");
meta1_1_1.setName("component1_1_1");
meta1_1_1.setLatestVersion("4.0.0");
meta1_1_1.setRepositoryType(RepositoryType.MAVEN);
qm.persist(meta1_1_1);
component1_1_1 = qm.createComponent(component1_1_1, false);

project.setDirectDependencies("[{\"uuid\":\"" + component1.getUuid() + "\"}]");
component1.setDirectDependencies("[{\"uuid\":\"" + component1_1.getUuid() + "\"}]");
component1_1.setDirectDependencies("[{\"uuid\":\"" + component1_1_1.getUuid() + "\"}]");

Response response = target(V1_COMPONENT + "/project/" + project.getUuid() + "/dependencyGraph/" + component1_1_1.getUuid())
.request().header(X_API_KEY, apiKey).get();
JsonObject json = parseJsonObject(response);
Assert.assertEquals(200, response.getStatus(), 0);

Assert.assertTrue(json.get(component1.getUuid().toString()).asJsonObject().getBoolean("expandDependencyGraph"));
Assert.assertEquals("2.0.0", json.get(component1.getUuid().toString()).asJsonObject().get("repositoryMeta").asJsonObject().getString("latestVersion"));
Assert.assertTrue(json.get(component1_1.getUuid().toString()).asJsonObject().getBoolean("expandDependencyGraph"));
Assert.assertEquals("3.0.0", json.get(component1_1.getUuid().toString()).asJsonObject().get("repositoryMeta").asJsonObject().getString("latestVersion"));
Assert.assertFalse(json.get(component1_1_1.getUuid().toString()).asJsonObject().getBoolean("expandDependencyGraph"));
Assert.assertEquals("4.0.0", json.get(component1_1_1.getUuid().toString()).asJsonObject().get("repositoryMeta").asJsonObject().getString("latestVersion"));
}

@Test
public void getDependencyGraphForComponentInvalidProjectUuidTest() {
Project project = qm.createProject("Acme Application", null, null, null, null, null, true, false);
Expand Down