Skip to content
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.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion api/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@
<plugin>
<groupId>org.openapitools</groupId>
<artifactId>openapi-generator-maven-plugin</artifactId>
<version>7.17.0</version>
<version>7.21.0</version>
<executions>
<execution>
<id>generate-api-v2</id>
Expand Down
4 changes: 2 additions & 2 deletions api/src/main/openapi/openapi.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -133,8 +133,8 @@ paths:
$ref: "./paths/metrics_vulnerabilities.yaml"
/projects/{uuid}/advisories:
$ref: "./paths/projects__uuid__advisories.yaml"
/projects/{projectUuid}/advisories/{advisoryId}/findings:
$ref: "./paths/projects__projectUuid__advisories__advisoryId__findings.yaml"
/projects/{uuid}/advisories/{advisoryId}/findings:
$ref: "./paths/projects__uuid__advisories__advisoryId__findings.yaml"
/projects/{uuid}/clone:
$ref: "./paths/projects__uuid__clone.yaml"
/projects/{uuid}/components:
Expand Down
2 changes: 1 addition & 1 deletion api/src/main/openapi/paths/projects__uuid__advisories.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ get:

Requires the `VIEW_VULNERABILITY` permission.
tags:
- Advisories
- Projects
parameters:
- name: uuid
in: path
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,9 @@ get:
summary: List findings by project and advisory
description: Requires permission <strong>VIEW_VULNERABILITY</strong>
tags:
- Advisories
- Projects
parameters:
- name: projectUuid
- name: uuid
in: path
description: The UUID of the project
required: true
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,15 +21,12 @@
import alpine.server.auth.PermissionRequired;
import io.csaf.retrieval.RetrievedDocument;
import jakarta.ws.rs.NotFoundException;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.core.Response;
import jakarta.ws.rs.ext.Provider;
import org.dependencytrack.api.v2.AdvisoriesApi;
import org.dependencytrack.api.v2.model.GetAdvisoryResponse;
import org.dependencytrack.api.v2.model.ListAdvisoriesResponse;
import org.dependencytrack.api.v2.model.ListAdvisoriesResponseItem;
import org.dependencytrack.api.v2.model.ListProjectAdvisoriesResponse;
import org.dependencytrack.api.v2.model.ListProjectAdvisoriesResponseItem;
import org.dependencytrack.api.v2.model.ListProjectAdvisoryFindingsResponseItem;
import org.dependencytrack.auth.Permissions;
import org.dependencytrack.common.pagination.Page;
import org.dependencytrack.csaf.CsafModelConverter;
Expand All @@ -39,9 +36,6 @@
import org.dependencytrack.persistence.jdbi.AdvisoryDao;
import org.dependencytrack.persistence.jdbi.AdvisoryDao.AdvisoryDetailRow;
import org.dependencytrack.persistence.jdbi.AdvisoryDao.ListAdvisoriesRow;
import org.dependencytrack.persistence.jdbi.AdvisoryDao.ListProjectAdvisoriesRow;
import org.dependencytrack.persistence.jdbi.ProjectDao;
import org.dependencytrack.persistence.jdbi.query.ListAdvisoriesForProjectQuery;
import org.dependencytrack.persistence.jdbi.query.ListAdvisoriesQuery;
import org.dependencytrack.resources.AbstractApiResource;
import org.owasp.security.logging.SecurityMarkers;
Expand All @@ -54,7 +48,6 @@
import java.io.UncheckedIOException;
import java.time.Instant;
import java.util.HashSet;
import java.util.List;
import java.util.UUID;

import static org.dependencytrack.persistence.jdbi.JdbiFactory.inJdbiTransaction;
Expand All @@ -67,7 +60,7 @@
* @author Christian Banse
* @since 5.7.0
*/
@Path("/")
@Provider
public class AdvisoriesResource extends AbstractApiResource implements AdvisoriesApi {

private static final Logger LOGGER = LoggerFactory.getLogger(AdvisoriesResource.class);
Expand Down Expand Up @@ -252,78 +245,4 @@ public Response getAdvisoryById(UUID id) {
return Response.ok(response).build();
}

@Override
@PermissionRequired(Permissions.Constants.VIEW_VULNERABILITY)
public Response listAdvisoriesForProject(UUID projectUuid, String pageToken, Integer limit) {
final Page<ListProjectAdvisoriesRow> projectAdvisories =
inJdbiTransaction(getAlpineRequest(), handle -> {
requireProjectAccess(handle, projectUuid);

final long projectId = handle.attach(ProjectDao.class).getProjectId(projectUuid);

return handle.attach(AdvisoryDao.class).listForProject(
new ListAdvisoriesForProjectQuery(projectId)
.withPageToken(pageToken)
.withLimit(limit));
});

final var responseItems = projectAdvisories.items().stream()
.<ListProjectAdvisoriesResponseItem>map(
advisory -> ListProjectAdvisoriesResponseItem.builder()
.id(advisory.id())
.publisher(advisory.publisher())
.name(advisory.name())
.version(advisory.version())
.url(advisory.url())
.title(advisory.title())
.format(advisory.format())
.seenAt(advisory.seenAt() != null
? advisory.seenAt().toEpochMilli()
: null)
.lastFetched(advisory.lastFetched() != null
? advisory.lastFetched().toEpochMilli()
: null)
.findingsCount(advisory.findingsCount())
.build())
.toList();

final var response = ListProjectAdvisoriesResponse.builder()
.items(responseItems)
.nextPageToken(projectAdvisories.nextPageToken())
.total(convertTotalCount(projectAdvisories.totalCount()))
.build();

return Response.ok(response).build();
}

// TODO: What is the purpose of this endpoint? Do we really need it?
// Can we include this in a more general /findings endpoint and add a filter option
// for advisories, e.g. `/findings?project_uuid=foo&advisory_id=bar`?
@Override
@PermissionRequired(Permissions.Constants.VIEW_VULNERABILITY)
public Response getFindingsByProjectAdvisory(UUID projectUuid, UUID advisoryId) {
return inJdbiTransaction(getAlpineRequest(), handle -> {
requireProjectAccess(handle, projectUuid);

final long projectId = handle.attach(ProjectDao.class).getProjectId(projectUuid);

List<AdvisoryDao.ProjectAdvisoryFindingRow> advisoryRows = handle.attach(AdvisoryDao.class)
.getFindingsByProjectAdvisory(projectId, advisoryId);
final long totalCount = advisoryRows.size();

final List<ListProjectAdvisoryFindingsResponseItem> responseItems = advisoryRows.stream()
.<ListProjectAdvisoryFindingsResponseItem>map(
row -> ListProjectAdvisoryFindingsResponseItem.builder()
.name(row.name())
.confidence((int) row.confidence())
.desc(row.desc())
.group(row.group())
.version(row.version())
.componentUuid(UUID.fromString(row.componentUuid()))
.build())
.toList();

return Response.ok(responseItems).header(TOTAL_COUNT_HEADER, totalCount).build();
});
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,10 @@
import jakarta.ws.rs.ClientErrorException;
import jakarta.ws.rs.NotAuthorizedException;
import jakarta.ws.rs.NotFoundException;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.core.Context;
import jakarta.ws.rs.core.Response;
import jakarta.ws.rs.core.UriInfo;
import jakarta.ws.rs.ext.Provider;
import org.apache.commons.lang3.StringUtils;
import org.dependencytrack.api.v2.ComponentsApi;
import org.dependencytrack.api.v2.model.CreateComponentRequest;
Expand All @@ -48,7 +48,7 @@
import static org.dependencytrack.resources.v2.mapping.ModelMapper.mapOrganizationalContacts;
import static org.dependencytrack.util.PersistenceUtil.isUniqueConstraintViolation;

@Path("/")
@Provider
public class ComponentsResource extends AbstractApiResource implements ComponentsApi {

private static final Logger LOGGER = LoggerFactory.getLogger(ComponentsResource.class);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,8 @@
import jakarta.inject.Inject;
import jakarta.ws.rs.BadRequestException;
import jakarta.ws.rs.NotFoundException;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.core.Response;
import jakarta.ws.rs.ext.Provider;
import org.dependencytrack.api.v2.CsafApi;
import org.dependencytrack.api.v2.model.CreateCsafAggregatorRequest;
import org.dependencytrack.api.v2.model.CreateCsafProviderRequest;
Expand Down Expand Up @@ -59,7 +59,7 @@
*
* @since 5.7.0
*/
@Path("/")
@Provider
public class CsafResource extends AbstractApiResource implements CsafApi {

private static final Logger LOGGER = LoggerFactory.getLogger(CsafResource.class);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,8 @@
import jakarta.json.Json;
import jakarta.ws.rs.BadRequestException;
import jakarta.ws.rs.NotFoundException;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.core.Response;
import jakarta.ws.rs.ext.Provider;
import org.dependencytrack.api.v2.ExtensionsApi;
import org.dependencytrack.api.v2.model.GetExtensionConfigResponse;
import org.dependencytrack.api.v2.model.ListExtensionPointsResponse;
Expand Down Expand Up @@ -69,7 +69,7 @@
/**
* @since 5.7.0
*/
@Path("/")
@Provider
public class ExtensionsResource extends AbstractApiResource implements ExtensionsApi {

private static final Logger LOGGER = LoggerFactory.getLogger(ExtensionsResource.class);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,8 @@
package org.dependencytrack.resources.v2;

import alpine.server.auth.PermissionRequired;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.core.Response;
import jakarta.ws.rs.ext.Provider;
import org.dependencytrack.api.v2.MetricsApi;
import org.dependencytrack.api.v2.model.ListVulnerabilityMetricsResponse;
import org.dependencytrack.api.v2.model.ListVulnerabilityMetricsResponseItem;
Expand All @@ -34,7 +34,7 @@
import static org.dependencytrack.persistence.jdbi.JdbiFactory.inJdbiTransaction;
import static org.dependencytrack.persistence.jdbi.JdbiFactory.withJdbiHandle;

@Path("/")
@Provider
public class MetricsResource extends AbstractApiResource implements MetricsApi {

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,34 +20,41 @@

import alpine.server.auth.PermissionRequired;
import jakarta.ws.rs.NotFoundException;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.core.Context;
import jakarta.ws.rs.core.Response;
import jakarta.ws.rs.core.UriInfo;
import jakarta.ws.rs.ext.Provider;
import org.dependencytrack.api.v2.ProjectsApi;
import org.dependencytrack.api.v2.model.CloneProjectInclude;
import org.dependencytrack.api.v2.model.CloneProjectRequest;
import org.dependencytrack.api.v2.model.CloneProjectResponse;
import org.dependencytrack.api.v2.model.ListComponentsResponse;
import org.dependencytrack.api.v2.model.ListComponentsResponseItem;
import org.dependencytrack.api.v2.model.ListProjectAdvisoriesResponse;
import org.dependencytrack.api.v2.model.ListProjectAdvisoriesResponseItem;
import org.dependencytrack.api.v2.model.ListProjectAdvisoryFindingsResponseItem;
import org.dependencytrack.auth.Permissions;
import org.dependencytrack.common.pagination.Page;
import org.dependencytrack.model.Component;
import org.dependencytrack.persistence.jdbi.AdvisoryDao;
import org.dependencytrack.persistence.jdbi.AdvisoryDao.ListProjectAdvisoriesRow;
import org.dependencytrack.persistence.jdbi.ComponentDao;
import org.dependencytrack.persistence.jdbi.ProjectDao;
import org.dependencytrack.persistence.jdbi.command.CloneProjectCommand;
import org.dependencytrack.persistence.jdbi.query.ListAdvisoriesForProjectQuery;
import org.dependencytrack.resources.AbstractApiResource;
import org.owasp.security.logging.SecurityMarkers;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.List;
import java.util.UUID;

import static org.dependencytrack.persistence.jdbi.JdbiFactory.inJdbiTransaction;
import static org.dependencytrack.resources.v2.mapping.ModelMapper.mapHashes;
import static org.dependencytrack.resources.v2.mapping.ModelMapper.mapLicense;

@Path("/")
@Provider
public class ProjectsResource extends AbstractApiResource implements ProjectsApi {

private static final Logger LOGGER = LoggerFactory.getLogger(ProjectsResource.class);
Expand Down Expand Up @@ -136,4 +143,76 @@ public Response cloneProject(final UUID projectUuid, final CloneProjectRequest r
.build();
}

@Override
@PermissionRequired(Permissions.Constants.VIEW_VULNERABILITY)
public Response listAdvisoriesForProject(UUID uuid, String pageToken, Integer limit) {
final Page<ListProjectAdvisoriesRow> projectAdvisories =
inJdbiTransaction(getAlpineRequest(), handle -> {
requireProjectAccess(handle, uuid);

final long projectId = handle.attach(ProjectDao.class).getProjectId(uuid);

return handle.attach(AdvisoryDao.class).listForProject(
new ListAdvisoriesForProjectQuery(projectId)
.withPageToken(pageToken)
.withLimit(limit));
});

final var responseItems = projectAdvisories.items().stream()
.<ListProjectAdvisoriesResponseItem>map(
advisory -> ListProjectAdvisoriesResponseItem.builder()
.id(advisory.id())
.publisher(advisory.publisher())
.name(advisory.name())
.version(advisory.version())
.url(advisory.url())
.title(advisory.title())
.format(advisory.format())
.seenAt(advisory.seenAt() != null
? advisory.seenAt().toEpochMilli()
: null)
.lastFetched(advisory.lastFetched() != null
? advisory.lastFetched().toEpochMilli()
: null)
.findingsCount(advisory.findingsCount())
.build())
.toList();

final var response = ListProjectAdvisoriesResponse.builder()
.items(responseItems)
.nextPageToken(projectAdvisories.nextPageToken())
.total(convertTotalCount(projectAdvisories.totalCount()))
.build();

return Response.ok(response).build();
}

@Override
@PermissionRequired(Permissions.Constants.VIEW_VULNERABILITY)
public Response getFindingsByProjectAdvisory(UUID uuid, UUID advisoryId) {
return inJdbiTransaction(getAlpineRequest(), handle -> {
requireProjectAccess(handle, uuid);

final long projectId = handle.attach(ProjectDao.class).getProjectId(uuid);

List<AdvisoryDao.ProjectAdvisoryFindingRow> advisoryRows = handle.attach(AdvisoryDao.class)
.getFindingsByProjectAdvisory(projectId, advisoryId);
final long totalCount = advisoryRows.size();

final List<ListProjectAdvisoryFindingsResponseItem> responseItems = advisoryRows.stream()
.<ListProjectAdvisoryFindingsResponseItem>map(
row -> ListProjectAdvisoryFindingsResponseItem.builder()
.name(row.name())
.confidence((int) row.confidence())
.desc(row.desc())
.group(row.group())
.version(row.version())
.componentUuid(UUID.fromString(row.componentUuid()))
.build())
.toList();

return Response.ok(responseItems).header(TOTAL_COUNT_HEADER, totalCount).build();
});
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,8 @@
import jakarta.inject.Inject;
import jakarta.ws.rs.BadRequestException;
import jakarta.ws.rs.NotFoundException;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.core.Response;
import jakarta.ws.rs.ext.Provider;
import org.dependencytrack.api.v2.SecretsApi;
import org.dependencytrack.api.v2.model.CreateSecretRequest;
import org.dependencytrack.api.v2.model.ListSecretsResponse;
Expand All @@ -40,7 +40,7 @@
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

@Path("/")
@Provider
public class SecretsResource extends AbstractApiResource implements SecretsApi {

private static final Logger LOGGER = LoggerFactory.getLogger(SecretsResource.class);
Expand Down
Loading
Loading