Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add option to deactivate old project versions on BOM upload #4533

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
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
39 changes: 39 additions & 0 deletions src/main/java/org/dependencytrack/resources/v1/BomResource.java
Original file line number Diff line number Diff line change
Expand Up @@ -344,6 +344,14 @@ public Response uploadBom(@Parameter(required = true) BomSubmitRequest request)
null, true, request.isLatestProjectVersion(), true);
Principal principal = getPrincipal();
qm.updateNewProjectACL(project, principal);
if (request.isDeactivateOtherVersions()) {
if (!request.isLatestProjectVersion()) {
var message = "Value \"isLatest=true\" required when \"deactivateOtherVersions=true\".";
LOGGER.error(message);
return Response.status(Response.Status.NOT_ACCEPTABLE).entity(message).build();
}
qm.runInTransaction(() -> deactivateOtherVersions(qm, trimmedProjectName));
}
} else {
return Response.status(Response.Status.UNAUTHORIZED).entity("The principal does not have permission to create project.").build();
}
Expand Down Expand Up @@ -404,6 +412,7 @@ public Response uploadBom(
@FormDataParam("parentVersion") String parentVersion,
@FormDataParam("parentUUID") String parentUUID,
@DefaultValue("false") @FormDataParam("isLatest") boolean isLatest,
@DefaultValue("false") @FormDataParam("deactivateOtherVersions") boolean deactivateOtherVersions,
@Parameter(schema = @Schema(type = "string")) @FormDataParam("bom") final List<FormDataBodyPart> artifactParts
) {
if (projectUuid != null) { // behavior in v3.0.0
Expand Down Expand Up @@ -450,6 +459,15 @@ public Response uploadBom(
project = qm.createProject(trimmedProjectName, null, trimmedProjectVersion, tags, parent, null, true, isLatest, true);
Principal principal = getPrincipal();
qm.updateNewProjectACL(project, principal);

if (deactivateOtherVersions) {
if (!isLatest) {
var message = "Value \"isLatest=true\" required when \"deactivateOtherVersions=true\".";
LOGGER.error(message);
return Response.status(Response.Status.NOT_ACCEPTABLE).entity(message).build();
}
qm.runInTransaction(() -> deactivateOtherVersions(qm, trimmedProjectName));
}
} else {
return Response.status(Response.Status.UNAUTHORIZED).entity("The principal does not have permission to create project.").build();
}
Expand All @@ -459,6 +477,7 @@ public Response uploadBom(
}
}


@GET
@Path("/token/{uuid}")
@Produces(MediaType.APPLICATION_JSON)
Expand Down Expand Up @@ -501,6 +520,26 @@ public Response isTokenBeingProcessed (
return Response.ok(response).build();
}

/**
* Deactivates all non-latest versions of a specific project.
* Ensures that only the latest version of a project remains active.
* If the principal does not have access to a project version, an exception is thrown.
*
* @param qm The QueryManager instance used to query and manage projects.
* @param projectName A string representing the name of the project versions to be evaluated.
*/
private void deactivateOtherVersions(QueryManager qm, String projectName) {
qm.getProjects(projectName, true, false, null).getList(Project.class).forEach(p -> {
if (p.isLatest()) {
return;
} else if (!qm.hasAccess(super.getPrincipal(), p)) {
throw new WebApplicationException("Could not deactivate project, no access: " + p.getUuid() + " / " + p.getName());
}
p.setActive(false);
qm.updateProject(p, true);
});
}

/**
* Common logic that processes a BOM given a project and encoded payload.
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -74,14 +74,17 @@ public final class BomSubmitRequest {

private final boolean isLatestProjectVersion;

private final boolean deactivateOtherVersions;

public BomSubmitRequest(String project,
String projectName,
String projectVersion,
List<Tag> projectTags,
boolean autoCreate,
boolean isLatestProjectVersion,
boolean deactivateOtherProjectVersions,
String bom) {
this(project, projectName, projectVersion, projectTags, autoCreate, null, null, null, isLatestProjectVersion, bom);
this(project, projectName, projectVersion, projectTags, autoCreate, null, null, null, isLatestProjectVersion, deactivateOtherProjectVersions, bom);
}

@JsonCreator
Expand All @@ -94,6 +97,7 @@ public BomSubmitRequest(@JsonProperty(value = "project") String project,
@JsonProperty(value = "parentName") String parentName,
@JsonProperty(value = "parentVersion") String parentVersion,
@JsonProperty(value = "isLatestProjectVersion", defaultValue = "false") boolean isLatestProjectVersion,
@JsonProperty(value = "deactivateOtherVersions", defaultValue = "false") boolean deactivateOtherVersions,
@JsonProperty(value = "bom", required = true) String bom) {
this.project = project;
this.projectName = projectName;
Expand All @@ -104,6 +108,7 @@ public BomSubmitRequest(@JsonProperty(value = "project") String project,
this.parentName = parentName;
this.parentVersion = parentVersion;
this.isLatestProjectVersion = isLatestProjectVersion;
this.deactivateOtherVersions = deactivateOtherVersions;
this.bom = bom;
}

Expand Down Expand Up @@ -149,6 +154,10 @@ public boolean isAutoCreate() {
@JsonProperty("isLatestProjectVersion")
public boolean isLatestProjectVersion() { return isLatestProjectVersion; }

public boolean isDeactivateOtherVersions() {
return deactivateOtherVersions;
}

@Schema(
description = "Base64 encoded BOM",
required = true,
Expand Down
Loading
Loading