Skip to content

Commit

Permalink
Improve OpenAPI v3 integration (#820)
Browse files Browse the repository at this point in the history
  • Loading branch information
nscuro authored Aug 2, 2024
1 parent 71d9066 commit f040e25
Show file tree
Hide file tree
Showing 41 changed files with 886 additions and 210 deletions.
9 changes: 6 additions & 3 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,7 @@
<lib.protobuf-java.version>3.25.3</lib.protobuf-java.version>
<lib.testcontainers.version>1.20.0</lib.testcontainers.version>
<lib.resilience4j.version>2.2.0</lib.resilience4j.version>
<lib.swagger-parser.version>2.1.22</lib.swagger-parser.version>
<lib.system-rules.version>1.19.0</lib.system-rules.version>
<lib.versatile.version>0.7.0</lib.versatile.version>
<lib.woodstox.version>6.6.2</lib.woodstox.version>
Expand Down Expand Up @@ -298,9 +299,10 @@
<version>${lib.swagger.version}</version>
</dependency>
<dependency>
<groupId>io.swagger.core.v3</groupId>
<artifactId>swagger-jaxrs2-servlet-initializer-v2</artifactId>
<version>${lib.swagger.version}</version>
<groupId>io.swagger.parser.v3</groupId>
<artifactId>swagger-parser</artifactId>
<version>${lib.swagger-parser.version}</version>
<scope>test</scope>
</dependency>

<dependency>
Expand Down Expand Up @@ -550,6 +552,7 @@
<filtering>true</filtering>
<includes>
<include>application.version</include>
<include>openapi-configuration.yaml</include>
</includes>
</resource>
</resources>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ public class AccessControlResource extends AlpineResource {
@ApiResponses(value = {
@ApiResponse(
responseCode = "200",
description = "Projects assigned to the specified team",
headers = @Header(name = TOTAL_COUNT_HEADER, description = "The total number of projects", schema = @Schema(format = "integer")),
content = @Content(array = @ArraySchema(schema = @Schema(implementation = Project.class)))
),
Expand Down Expand Up @@ -113,7 +114,7 @@ public Response retrieveProjects(@Parameter(description = "The UUID of the team
description = "<p>Requires permission <strong>ACCESS_MANAGEMENT</strong></p>"
)
@ApiResponses(value = {
@ApiResponse(responseCode = "200", content = @Content(schema = @Schema(implementation = AclMappingRequest.class))),
@ApiResponse(responseCode = "200", description = "Mapping created successfully", content = @Content(schema = @Schema(implementation = AclMappingRequest.class))),
@ApiResponse(responseCode = "401", description = "Unauthorized"),
@ApiResponse(responseCode = "404", description = "The UUID of the team or project could not be found"),
@ApiResponse(responseCode = "409", description = "A mapping with the same team and project already exists")
Expand Down Expand Up @@ -151,6 +152,7 @@ public Response addMapping(AclMappingRequest request) {
description = "<p>Requires permission <strong>ACCESS_MANAGEMENT</strong> or <strong>ACCESS_MANAGEMENT_DELETE</strong></p>"
)
@ApiResponses(value = {
@ApiResponse(responseCode = "200", description = "Mapping removed successfully"),
@ApiResponse(responseCode = "401", description = "Unauthorized"),
@ApiResponse(responseCode = "404", description = "The UUID of the team or project could not be found"),
})
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,11 @@ public class AnalysisResource extends AlpineResource {
description = "<p>Requires permission <strong>VIEW_VULNERABILITY</strong></p>"
)
@ApiResponses(value = {
@ApiResponse(
responseCode = "200",
description = "An analysis trail",
content = @Content(schema = @Schema(implementation = Analysis.class))
),
@ApiResponse(responseCode = "401", description = "Unauthorized"),
@ApiResponse(responseCode = "404", description = "The project, component, or vulnerability could not be found")
})
Expand Down Expand Up @@ -128,7 +133,11 @@ public Response retrieveAnalysis(@Parameter(description = "The UUID of the proje
description = "<p>Requires permission <strong>VULNERABILITY_ANALYSIS</strong></strong> or <strong>VULNERABILITY_ANALYSIS_UPDATE</strong></p>"
)
@ApiResponses(value = {
@ApiResponse(responseCode = "200", content = @Content(schema = @Schema(implementation = Analysis.class))),
@ApiResponse(
responseCode = "200",
description = "The created analysis",
content = @Content(schema = @Schema(implementation = Analysis.class))
),
@ApiResponse(responseCode = "401", description = "Unauthorized"),
@ApiResponse(responseCode = "404", description = "The project, component, or vulnerability could not be found")
})
Expand Down
24 changes: 20 additions & 4 deletions src/main/java/org/dependencytrack/resources/v1/BadgeResource.java
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,11 @@ private boolean isBadgeSupportEnabled(final QueryManager qm) {
summary = "Returns current metrics for a specific project"
)
@ApiResponses(value = {
@ApiResponse(responseCode = "200", content = @Content(schema = @Schema(type = "string", implementation = ProjectMetrics.class))),
@ApiResponse(
responseCode = "200",
description = "A badge displaying current vulnerability metrics for a project in SVG format",
content = @Content(schema = @Schema(type = "string"))
),
@ApiResponse(responseCode = "204", description = "Badge support is disabled. No content will be returned."),
@ApiResponse(responseCode = "401", description = "Unauthorized"),
@ApiResponse(responseCode = "404", description = "The project could not be found")
Expand Down Expand Up @@ -99,7 +103,11 @@ public Response getProjectVulnerabilitiesBadge(
summary = "Returns current metrics for a specific project"
)
@ApiResponses(value = {
@ApiResponse(responseCode = "200", content = @Content(schema = @Schema(type = "string", implementation = ProjectMetrics.class))),
@ApiResponse(
responseCode = "200",
description = "A badge displaying current vulnerability metrics for a project in SVG format",
content = @Content(schema = @Schema(type = "string"))
),
@ApiResponse(responseCode = "204", description = "Badge support is disabled. No content will be returned."),
@ApiResponse(responseCode = "401", description = "Unauthorized"),
@ApiResponse(responseCode = "404", description = "The project could not be found")
Expand Down Expand Up @@ -133,7 +141,11 @@ public Response getProjectVulnerabilitiesBadge(
summary = "Returns a policy violations badge for a specific project"
)
@ApiResponses(value = {
@ApiResponse(responseCode = "200", content = @Content(schema = @Schema(type = "string"))),
@ApiResponse(
responseCode = "200",
description = "A badge displaying current policy violation metrics of a project in SVG format",
content = @Content(schema = @Schema(type = "string"))
),
@ApiResponse(responseCode = "204", description = "Badge support is disabled. No content will be returned."),
@ApiResponse(responseCode = "401", description = "Unauthorized"),
@ApiResponse(responseCode = "404", description = "The project could not be found")
Expand Down Expand Up @@ -165,7 +177,11 @@ public Response getProjectPolicyViolationsBadge(
summary = "Returns a policy violations badge for a specific project"
)
@ApiResponses(value = {
@ApiResponse(responseCode = "200", content = @Content(schema = @Schema(type = "string"))),
@ApiResponse(
responseCode = "200",
description = "A badge displaying current policy violation metrics of a project in SVG format",
content = @Content(schema = @Schema(type = "string"))
),
@ApiResponse(responseCode = "204", description = "Badge support is disabled. No content will be returned."),
@ApiResponse(responseCode = "401", description = "Unauthorized"),
@ApiResponse(responseCode = "404", description = "The project could not be found")
Expand Down
53 changes: 41 additions & 12 deletions src/main/java/org/dependencytrack/resources/v1/BomResource.java
Original file line number Diff line number Diff line change
Expand Up @@ -109,8 +109,12 @@ public class BomResource extends AlpineResource {
description = "<p>Requires permission <strong>VIEW_PORTFOLIO</strong></p>"
)
@ApiResponses(value = {
@ApiResponse(
responseCode = "200",
description = "Dependency metadata for a project in CycloneDX format",
content = @Content(schema = @Schema(type = "string"))
),
@ApiResponse(responseCode = "401", description = "Unauthorized"),
@ApiResponse(responseCode = "200", content = @Content(schema = @Schema(type = "string"))),
@ApiResponse(responseCode = "403", description = "Access to the specified project is forbidden"),
@ApiResponse(responseCode = "404", description = "The project could not be found")
})
Expand Down Expand Up @@ -179,7 +183,11 @@ public Response exportProjectAsCycloneDx(
description = "<p>Requires permission <strong>VIEW_PORTFOLIO</strong></p>"
)
@ApiResponses(value = {
@ApiResponse(responseCode = "200", content = @Content(schema = @Schema(type = "string"))),
@ApiResponse(
responseCode = "200",
description = "Dependency metadata for a specific component in CycloneDX format",
content = @Content(schema = @Schema(type = "string"))
),
@ApiResponse(responseCode = "401", description = "Unauthorized"),
@ApiResponse(responseCode = "403", description = "Access to the specified component is forbidden"),
@ApiResponse(responseCode = "404", description = "The component could not be found")
Expand Down Expand Up @@ -245,9 +253,19 @@ public Response exportComponentAsCycloneDx(
operationId = "UploadBomBase64Encoded"
)
@ApiResponses(value = {
@ApiResponse(responseCode = "200", content = @Content(schema = @Schema(implementation = BomUploadResponse.class))),
@ApiResponse(responseCode = "400", description = "Invalid BOM", content = @Content(schema = @Schema(implementation = InvalidBomProblemDetails.class),
mediaType = ProblemDetails.MEDIA_TYPE_JSON)),
@ApiResponse(
responseCode = "200",
description = "Token to be used for checking BOM processing progress",
content = @Content(schema = @Schema(implementation = BomUploadResponse.class))
),
@ApiResponse(
responseCode = "400",
description = "Invalid BOM",
content = @Content(
schema = @Schema(implementation = InvalidBomProblemDetails.class),
mediaType = ProblemDetails.MEDIA_TYPE_JSON
)
),
@ApiResponse(responseCode = "400", description = "The uploaded BOM is invalid"),
@ApiResponse(responseCode = "401", description = "Unauthorized"),
@ApiResponse(responseCode = "403", description = "Access to the specified project is forbidden"),
Expand Down Expand Up @@ -332,11 +350,18 @@ public Response uploadBom(@Parameter(required = true) BomSubmitRequest request)
operationId = "UploadBom"
)
@ApiResponses(value = {
@ApiResponse(responseCode = "200", content = @Content(schema = @Schema(implementation = BomUploadResponse.class))),
@ApiResponse(responseCode = "400", description = "Invalid BOM", content = @Content(
schema = @Schema(implementation = InvalidBomProblemDetails.class),
mediaType = ProblemDetails.MEDIA_TYPE_JSON
)
@ApiResponse(
responseCode = "200",
description = "Token to be used for checking BOM processing progress",
content = @Content(schema = @Schema(implementation = BomUploadResponse.class))
),
@ApiResponse(
responseCode = "400",
description = "Invalid BOM",
content = @Content(
schema = @Schema(implementation = InvalidBomProblemDetails.class),
mediaType = ProblemDetails.MEDIA_TYPE_JSON
)
),
@ApiResponse(responseCode = "400", description = "The uploaded BOM is invalid"),
@ApiResponse(responseCode = "401", description = "Unauthorized"),
Expand Down Expand Up @@ -419,7 +444,11 @@ determine if any tasks (such as vulnerability analysis) is being performed on th
<p>Requires permission <strong>BOM_UPLOAD</strong></p>
<p><strong>Deprecated</strong>. Use <code>/v1/event/token/{uuid}</code> instead.</p>""")
@ApiResponses(value = {
@ApiResponse(responseCode = "200", content = @Content(schema = @Schema(implementation = IsTokenBeingProcessedResponse.class))),
@ApiResponse(
responseCode = "200",
description = "The processing status of the provided token",
content = @Content(schema = @Schema(implementation = IsTokenBeingProcessedResponse.class))
),
@ApiResponse(responseCode = "401", description = "Unauthorized")
})
@PermissionRequired(Permissions.Constants.BOM_UPLOAD)
Expand All @@ -435,7 +464,7 @@ public Response isTokenBeingProcessed(
AtomicBoolean hasTerminalStatus = new AtomicBoolean(true);
IsTokenBeingProcessedResponse response = new IsTokenBeingProcessedResponse();
workflowStates.stream().forEach(workflowState -> hasTerminalStatus.set(hasTerminalStatus.get() && (workflowState.getStatus() != WorkflowStatus.PENDING
&& workflowState.getStatus() != WorkflowStatus.TIMED_OUT)));
&& workflowState.getStatus() != WorkflowStatus.TIMED_OUT)));
response.setProcessing(!hasTerminalStatus.get());
return Response.ok(response).build();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,11 +57,13 @@ public class CalculatorResource extends AlpineResource {
@GET
@Path("/cvss")
@Produces(MediaType.APPLICATION_JSON)
@Operation(
summary = "Returns the CVSS base score, impact sub-score and exploitability sub-score"
)
@Operation(summary = "Returns the CVSS base score, impact sub-score and exploitability sub-score")
@ApiResponses(value = {
@ApiResponse(responseCode = "200", content = @Content(schema = @Schema(type = "number"))),
@ApiResponse(
responseCode = "200",
description = "The calculated scores",
content = @Content(schema = @Schema(implementation = Score.class))
),
@ApiResponse(responseCode = "401", description = "Unauthorized")
})
public Response getCvssScores(
Expand All @@ -80,11 +82,13 @@ public Response getCvssScores(
@GET
@Path("/owasp")
@Produces(MediaType.APPLICATION_JSON)
@Operation(
summary = "Returns the OWASP Risk Rating likelihood score, technical impact score and business impact score"
)
@Operation(summary = "Returns the OWASP Risk Rating likelihood score, technical impact score and business impact score")
@ApiResponses(value = {
@ApiResponse(responseCode = "200", content = @Content(schema = @Schema(type = "number"))),
@ApiResponse(
responseCode = "200",
description = "The calculated scores",
content = @Content(schema = @Schema(implementation = us.springett.owasp.riskrating.Score.class))
),
@ApiResponse(responseCode = "401", description = "Unauthorized")
})
public Response getOwaspRRScores(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,11 +63,15 @@ public class ComponentPropertyResource extends AbstractConfigPropertyResource {
@GET
@Produces(MediaType.APPLICATION_JSON)
@Operation(
summary = "Returns a list of all ComponentProperties for the specified component",
summary = "Returns a list of all properties for the specified component",
description = "<p>Requires permission <strong>VIEW_PORTFOLIO</strong></p>"
)
@ApiResponses(value = {
@ApiResponse(responseCode = "200", content = @Content(array = @ArraySchema(schema = @Schema(implementation = ComponentProperty.class)))),
@ApiResponse(
responseCode = "200",
description = "A list of all properties for the specified component",
content = @Content(array = @ArraySchema(schema = @Schema(implementation = ComponentProperty.class)))
),
@ApiResponse(responseCode = "401", description = "Unauthorized"),
@ApiResponse(responseCode = "403", description = "Access to the specified project is forbidden"),
@ApiResponse(responseCode = "404", description = "The project could not be found")
Expand Down Expand Up @@ -109,7 +113,11 @@ public Response getProperties(
description = "<p>Requires permission <strong>PORTFOLIO_MANAGEMENT</strong> or <strong>PORTFOLIO_MANAGEMENT_CREATE</strong></p>"
)
@ApiResponses(value = {
@ApiResponse(responseCode = "201", content = @Content(schema = @Schema(implementation = ComponentProperty.class))),
@ApiResponse(
responseCode = "201",
description = "The created component",
content = @Content(schema = @Schema(implementation = ComponentProperty.class))
),
@ApiResponse(responseCode = "401", description = "Unauthorized"),
@ApiResponse(responseCode = "403", description = "Access to the specified component is forbidden"),
@ApiResponse(responseCode = "404", description = "The component could not be found"),
Expand Down Expand Up @@ -167,7 +175,7 @@ public Response createProperty(
description = "<p>Requires permission <strong>PORTFOLIO_MANAGEMENT</strong> or <strong>PORTFOLIO_MANAGEMENT_DELETE</strong></p>"
)
@ApiResponses(value = {
@ApiResponse(responseCode = "204"),
@ApiResponse(responseCode = "204", description = "Property removed successfully"),
@ApiResponse(responseCode = "401", description = "Unauthorized"),
@ApiResponse(responseCode = "403", description = "Access to the specified component is forbidden"),
@ApiResponse(responseCode = "404", description = "The component or component property could not be found"),
Expand Down
Loading

0 comments on commit f040e25

Please sign in to comment.