From a7142b5f45b6bfc3c54e65917f4a2422bf0f7ec4 Mon Sep 17 00:00:00 2001 From: leec94 Date: Thu, 25 Apr 2024 16:07:17 -0400 Subject: [PATCH] porting feature from issue-3260 Signed-off-by: leec94 --- .../resources/v1/BomResource.java | 3 +- .../resources/v1/EventResource.java | 69 +++++++++++++++++++ .../resources/v1/ProjectResource.java | 4 +- .../resources/v1/ProjectResourceTest.java | 10 ++- 4 files changed, 82 insertions(+), 4 deletions(-) create mode 100644 src/main/java/org/dependencytrack/resources/v1/EventResource.java diff --git a/src/main/java/org/dependencytrack/resources/v1/BomResource.java b/src/main/java/org/dependencytrack/resources/v1/BomResource.java index 8c95c5b39..868f11c6c 100644 --- a/src/main/java/org/dependencytrack/resources/v1/BomResource.java +++ b/src/main/java/org/dependencytrack/resources/v1/BomResource.java @@ -339,11 +339,12 @@ public Response uploadBom(@FormDataParam("project") String projectUuid, @GET @Path("/token/{uuid}") @Produces(MediaType.APPLICATION_JSON) - @ApiOperation(value = "Determines if there are any tasks associated with the token that are being processed, or in the queue to be processed.", notes = "This endpoint is intended to be used in conjunction with uploading a supported BOM document. Upon upload, a token will be returned. The token can then be queried using this endpoint to determine if any tasks (such as vulnerability analysis) is being performed on the BOM. A value of true indicates processing is occurring. A value of false indicates that no processing is occurring for the specified token. However, a value of false also does not confirm the token is valid, only that no processing is associated with the specified token.", response = IsTokenBeingProcessedResponse.class) + @ApiOperation(value = "Determines if there are any tasks associated with the token that are being processed, or in the queue to be processed.", notes = "Deprecated. Use /v1/event/token/{uuid} instead.", response = IsTokenBeingProcessedResponse.class) @ApiResponses(value = { @ApiResponse(code = 401, message = "Unauthorized") }) @PermissionRequired(Permissions.Constants.BOM_UPLOAD) + @Deprecated(since = "4.11.0") public Response isTokenBeingProcessed( @ApiParam(value = "The UUID of the token to query", required = true) @PathParam("uuid") String uuid) { diff --git a/src/main/java/org/dependencytrack/resources/v1/EventResource.java b/src/main/java/org/dependencytrack/resources/v1/EventResource.java new file mode 100644 index 000000000..8b65c4435 --- /dev/null +++ b/src/main/java/org/dependencytrack/resources/v1/EventResource.java @@ -0,0 +1,69 @@ +/* + * This file is part of Dependency-Track. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + * Copyright (c) Steve Springett. All Rights Reserved. + */ +package org.dependencytrack.resources.v1; + +import alpine.event.framework.Event; +import alpine.server.resources.AlpineResource; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import io.swagger.annotations.ApiResponses; +import io.swagger.annotations.Authorization; +import io.swagger.annotations.ApiParam; +import io.swagger.annotations.ApiResponse; +import org.dependencytrack.resources.v1.vo.IsTokenBeingProcessedResponse; + +import javax.ws.rs.GET; +import javax.ws.rs.Path; +import javax.ws.rs.PathParam; +import javax.ws.rs.Produces; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; +import java.util.UUID; + +/** + * JAX-RS resources for processing Events + * + * @author Ralf King + * @since 4.11.0 + */ +@Path("/v1/event") +@Api(value = "event", authorizations = @Authorization(value = "X-Api-Key")) +public class EventResource extends AlpineResource { + + @GET + @Path("/token/{uuid}") + @Produces(MediaType.APPLICATION_JSON) + @ApiOperation(value = "Determines if there are any tasks associated with the token that are being processed, or in the queue to be processed.", + notes = "This endpoint is intended to be used in conjunction with other API calls which return a token for asynchronous tasks. " + + "The token can then be queried using this endpoint to determine if the task is complete. " + + "A value of true indicates processing is occurring. A value of false indicates that no processing is " + + "occurring for the specified token. However, a value of false also does not confirm the token is valid, " + + "only that no processing is associated with the specified token.", response = IsTokenBeingProcessedResponse.class) + @ApiResponses(value = { + @ApiResponse(code = 401, message = "Unauthorized") + }) + public Response isTokenBeingProcessed ( + @ApiParam(value = "The UUID of the token to query", required = true) + @PathParam("uuid") String uuid) { + final boolean value = Event.isEventBeingProcessed(UUID.fromString(uuid)); + IsTokenBeingProcessedResponse response = new IsTokenBeingProcessedResponse(); + response.setProcessing(value); + return Response.ok(response).build(); + } +} \ No newline at end of file diff --git a/src/main/java/org/dependencytrack/resources/v1/ProjectResource.java b/src/main/java/org/dependencytrack/resources/v1/ProjectResource.java index c7dd7beb3..9dc9d4f49 100644 --- a/src/main/java/org/dependencytrack/resources/v1/ProjectResource.java +++ b/src/main/java/org/dependencytrack/resources/v1/ProjectResource.java @@ -528,7 +528,9 @@ public Response cloneProject(CloneProjectRequest jsonRequest) { } LOGGER.info("Project " + sourceProject + " is being cloned by " + super.getPrincipal().getName()); Event.dispatch(new CloneProjectEvent(jsonRequest)); - return Response.ok().build(); + CloneProjectEvent event = new CloneProjectEvent(jsonRequest); + Event.dispatch(event); + return Response.ok(java.util.Collections.singletonMap("token", event.getChainIdentifier())).build(); } else { return Response.status(Response.Status.NOT_FOUND).entity("The UUID of the project could not be found.").build(); } diff --git a/src/test/java/org/dependencytrack/resources/v1/ProjectResourceTest.java b/src/test/java/org/dependencytrack/resources/v1/ProjectResourceTest.java index b0ab51af9..b5210de2a 100644 --- a/src/test/java/org/dependencytrack/resources/v1/ProjectResourceTest.java +++ b/src/test/java/org/dependencytrack/resources/v1/ProjectResourceTest.java @@ -1006,7 +1006,10 @@ public void cloneProjectTest() { """.formatted(project.getUuid()))); assertThat(response.getStatus()).isEqualTo(200); - assertThat(getPlainTextBody(response)).isEmpty(); + JsonObject json = parseJsonObject(response); + Assert.assertNotNull(json); + Assert.assertNotNull(json.getString("token")); + Assert.assertTrue(UuidUtil.isValidUUID(json.getString("token"))); await("Cloning completion") .atMost(Duration.ofSeconds(15)) @@ -1129,6 +1132,9 @@ public void cloneProjectWithAclTest() { } """.formatted(accessProject.getUuid()))); assertThat(response.getStatus()).isEqualTo(200); - assertThat(getPlainTextBody(response)).isEmpty(); + JsonObject json = parseJsonObject(response); + Assert.assertNotNull(json); + Assert.assertNotNull(json.getString("token")); + Assert.assertTrue(UuidUtil.isValidUUID(json.getString("token"))); } }