Skip to content

Commit bb89346

Browse files
authored
Merge pull request #2044 from nscuro/issue-2043
Ensure that policy is part of policy violations API response
2 parents 1b32af4 + fc00022 commit bb89346

File tree

3 files changed

+76
-3
lines changed

3 files changed

+76
-3
lines changed

docs/_posts/2022-10-13-v4.6.1.md

+32
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
---
2+
title: v4.6.1
3+
type: patch
4+
---
5+
6+
**Fixes:**
7+
8+
* Resolved defect that caused policy name and violation state to not be displayed in the violations audit tab - [#2043]
9+
10+
For a complete list of changes, refer to the respective GitHub milestones:
11+
12+
* [API server milestone 4.6.1](https://github.com/DependencyTrack/dependency-track/milestone/28?closed=1)
13+
14+
###### dependency-track-apiserver.jar
15+
16+
| Algorithm | Checksum |
17+
|:----------|:---------|
18+
| SHA-1 | |
19+
| SHA-256 | |
20+
21+
###### dependency-track-bundled.jar
22+
23+
| Algorithm | Checksum |
24+
|:----------|:---------|
25+
| SHA-1 | |
26+
| SHA-256 | |
27+
28+
###### Software Bill of Materials (SBOM)
29+
30+
* API Server: [bom.json](https://github.com/DependencyTrack/dependency-track/releases/download/4.6.1/bom.json)
31+
32+
[#2043]: https://github.com/DependencyTrack/dependency-track/issues/2043

src/main/java/org/dependencytrack/resources/v1/PolicyViolationResource.java

+31-3
Original file line numberDiff line numberDiff line change
@@ -34,13 +34,16 @@
3434
import org.dependencytrack.model.Project;
3535
import org.dependencytrack.persistence.QueryManager;
3636

37+
import javax.jdo.FetchPlan;
38+
import javax.jdo.PersistenceManager;
3739
import javax.ws.rs.GET;
3840
import javax.ws.rs.Path;
3941
import javax.ws.rs.PathParam;
4042
import javax.ws.rs.Produces;
4143
import javax.ws.rs.QueryParam;
4244
import javax.ws.rs.core.MediaType;
4345
import javax.ws.rs.core.Response;
46+
import java.util.Collection;
4447

4548
/**
4649
* JAX-RS resources for processing policy violations.
@@ -68,7 +71,9 @@ public Response getViolations(@ApiParam(value = "Optionally includes suppressed
6871
@QueryParam("suppressed") boolean suppressed) {
6972
try (QueryManager qm = new QueryManager(getAlpineRequest())) {
7073
final PaginatedResult result = qm.getPolicyViolations(suppressed);
71-
return Response.ok(result.getObjects()).header(TOTAL_COUNT_HEADER, result.getTotal()).build();
74+
return Response.ok(detachViolations(qm, result.getList(PolicyViolation.class)))
75+
.header(TOTAL_COUNT_HEADER, result.getTotal())
76+
.build();
7277
}
7378
}
7479

@@ -95,7 +100,9 @@ public Response getViolationsByProject(@PathParam("uuid") String uuid,
95100
if (project != null) {
96101
if (qm.hasAccess(super.getPrincipal(), project)) {
97102
final PaginatedResult result = qm.getPolicyViolations(project, suppressed);
98-
return Response.ok(result.getObjects()).header(TOTAL_COUNT_HEADER, result.getTotal()).build();
103+
return Response.ok(detachViolations(qm, result.getList(PolicyViolation.class)))
104+
.header(TOTAL_COUNT_HEADER, result.getTotal())
105+
.build();
99106
} else {
100107
return Response.status(Response.Status.FORBIDDEN).entity("Access to the specified project is forbidden").build();
101108
}
@@ -128,7 +135,9 @@ public Response getViolationsByComponent(@PathParam("uuid") String uuid,
128135
if (component != null) {
129136
if (qm.hasAccess(super.getPrincipal(), component.getProject())) {
130137
final PaginatedResult result = qm.getPolicyViolations(component, suppressed);
131-
return Response.ok(result.getObjects()).header(TOTAL_COUNT_HEADER, result.getTotal()).build();
138+
return Response.ok(detachViolations(qm, result.getList(PolicyViolation.class)))
139+
.header(TOTAL_COUNT_HEADER, result.getTotal())
140+
.build();
132141
} else {
133142
return Response.status(Response.Status.FORBIDDEN).entity("Access to the specified component is forbidden").build();
134143
}
@@ -137,4 +146,23 @@ public Response getViolationsByComponent(@PathParam("uuid") String uuid,
137146
}
138147
}
139148
}
149+
150+
/**
151+
* Detach a given {@link Collection} of {@link PolicyViolation} suitable for use in API responses.
152+
* <p>
153+
* This ensures that responses include not only the violations themselves, but also the associated
154+
* {@link org.dependencytrack.model.Policy}, which is required to tell the policy name and violation state.
155+
*
156+
* @param qm The {@link QueryManager} to use
157+
* @param violations The {@link PolicyViolation}s to detach
158+
* @return A detached {@link Collection} of {@link PolicyViolation}s
159+
* @see <a href="https://github.com/DependencyTrack/dependency-track/issues/2043">GitHub issue</a>
160+
*/
161+
private Collection<PolicyViolation> detachViolations(final QueryManager qm, final Collection<PolicyViolation> violations) {
162+
final PersistenceManager pm = qm.getPersistenceManager();
163+
pm.getFetchPlan().setMaxFetchDepth(2); // Ensure policy is included
164+
pm.getFetchPlan().setDetachmentOptions(FetchPlan.DETACH_LOAD_FIELDS);
165+
return qm.getPersistenceManager().detachCopyAll(violations);
166+
}
167+
140168
}

src/test/java/org/dependencytrack/resources/v1/PolicyViolationResourceTest.java

+13
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,11 @@ public void getViolationsTest() {
8989
final JsonObject jsonObject = jsonArray.getJsonObject(0);
9090
assertThat(jsonObject.getString("uuid")).isEqualTo(violation.getUuid().toString());
9191
assertThat(jsonObject.getString("type")).isEqualTo(PolicyViolation.Type.OPERATIONAL.name());
92+
assertThat(jsonObject.getJsonObject("policyCondition")).isNotNull();
93+
assertThat(jsonObject.getJsonObject("policyCondition").getJsonObject("policy")).isNotNull();
94+
assertThat(jsonObject.getJsonObject("policyCondition").getJsonObject("policy").getString("name")).isEqualTo("Blacklisted Version");
95+
assertThat(jsonObject.getJsonObject("policyCondition").getJsonObject("policy").getString("violationState")).isEqualTo("FAIL");
96+
9297
}
9398

9499
@Test
@@ -137,6 +142,10 @@ public void getViolationsByProjectTest() {
137142
final JsonObject jsonObject = jsonArray.getJsonObject(0);
138143
assertThat(jsonObject.getString("uuid")).isEqualTo(violation.getUuid().toString());
139144
assertThat(jsonObject.getString("type")).isEqualTo(PolicyViolation.Type.OPERATIONAL.name());
145+
assertThat(jsonObject.getJsonObject("policyCondition")).isNotNull();
146+
assertThat(jsonObject.getJsonObject("policyCondition").getJsonObject("policy")).isNotNull();
147+
assertThat(jsonObject.getJsonObject("policyCondition").getJsonObject("policy").getString("name")).isEqualTo("Blacklisted Version");
148+
assertThat(jsonObject.getJsonObject("policyCondition").getJsonObject("policy").getString("violationState")).isEqualTo("FAIL");
140149
}
141150

142151
@Test
@@ -200,6 +209,10 @@ public void getViolationsByComponentTest() {
200209
final JsonObject jsonObject = jsonArray.getJsonObject(0);
201210
assertThat(jsonObject.getString("uuid")).isEqualTo(violation.getUuid().toString());
202211
assertThat(jsonObject.getString("type")).isEqualTo(PolicyViolation.Type.OPERATIONAL.name());
212+
assertThat(jsonObject.getJsonObject("policyCondition")).isNotNull();
213+
assertThat(jsonObject.getJsonObject("policyCondition").getJsonObject("policy")).isNotNull();
214+
assertThat(jsonObject.getJsonObject("policyCondition").getJsonObject("policy").getString("name")).isEqualTo("Blacklisted Version");
215+
assertThat(jsonObject.getJsonObject("policyCondition").getJsonObject("policy").getString("violationState")).isEqualTo("FAIL");
203216
}
204217

205218
@Test

0 commit comments

Comments
 (0)