Skip to content

Commit

Permalink
Merge pull request #2273 from rbt-mm/master-show-update-available-ico…
Browse files Browse the repository at this point in the history
…n-on-dependency-graph-nodes

Show version status information on dependency graph nodes
  • Loading branch information
nscuro authored Jan 30, 2023
2 parents 7f80a76 + 5b4a706 commit c03c8c2
Show file tree
Hide file tree
Showing 3 changed files with 122 additions and 1 deletion.
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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());
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
Original file line number Diff line number Diff line change
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

0 comments on commit c03c8c2

Please sign in to comment.