diff --git a/src/main/java/org/dependencytrack/resources/v1/VulnerabilityResource.java b/src/main/java/org/dependencytrack/resources/v1/VulnerabilityResource.java index 1e4d89978a..56ea6ba5e4 100644 --- a/src/main/java/org/dependencytrack/resources/v1/VulnerabilityResource.java +++ b/src/main/java/org/dependencytrack/resources/v1/VulnerabilityResource.java @@ -51,6 +51,7 @@ import org.dependencytrack.model.Cwe; import org.dependencytrack.model.Project; import org.dependencytrack.model.Vulnerability; +import org.dependencytrack.model.VulnerabilityAlias; import org.dependencytrack.model.VulnerableSoftware; import org.dependencytrack.model.validation.ValidUuid; import org.dependencytrack.parser.common.resolver.CweResolver; @@ -68,6 +69,7 @@ import java.security.Principal; import java.util.ArrayList; import java.util.List; +import java.util.UUID; /** * JAX-RS resources for processing vulnerabilities. @@ -350,13 +352,24 @@ public Response createVulnerability(Vulnerability jsonVulnerability) { validator.validateProperty(jsonVulnerability, "cvssV3Vector"), validator.validateProperty(jsonVulnerability, "owaspRRVector"), validator.validateProperty(jsonVulnerability, "vulnerableVersions"), - validator.validateProperty(jsonVulnerability, "patchedVersions") + validator.validateProperty(jsonVulnerability, "patchedVersions"), + validator.validateProperty(jsonVulnerability, "aliases") ); try (QueryManager qm = new QueryManager()) { Vulnerability vulnerability = qm.getVulnerabilityByVulnId( Vulnerability.Source.INTERNAL, jsonVulnerability.getVulnId().trim()); if (vulnerability == null) { + List aliases = new ArrayList<>(); + if (!jsonVulnerability.getAliases().isEmpty()) { + VulnerabilityAlias alias = new VulnerabilityAlias(); + alias.setInternalId(jsonVulnerability.getVulnId()); + alias.setCveId(jsonVulnerability.getAliases().getFirst().getCveId()); + alias.setGhsaId(jsonVulnerability.getAliases().getFirst().getGhsaId()); + alias.setOsvId(jsonVulnerability.getAliases().getFirst().getOsvId()); + aliases.add(alias); + } + jsonVulnerability.setAliases(aliases); final List cweIds = new ArrayList<>(); if (jsonVulnerability.getCwes() != null) { for (int i = 0; i < jsonVulnerability.getCwes().size(); i++) { @@ -381,6 +394,7 @@ public Response createVulnerability(Vulnerability jsonVulnerability) { return qm.callInTransaction(() -> { final Vulnerability persistentVuln = qm.createVulnerability(jsonVulnerability, true); qm.synchronizeVulnerableSoftware(persistentVuln, vsList, Vulnerability.Source.INTERNAL); + if (!persistentVuln.getAliases().isEmpty()) qm.synchronizeVulnerabilityAlias(persistentVuln.getAliases().getFirst()); if (persistentVuln.getVulnerableSoftware() != null && !persistentVuln.getVulnerableSoftware().isEmpty()) { persistentVuln.setAffectedComponents(persistentVuln.getVulnerableSoftware().stream() .peek(vs -> vs.setAffectedVersionAttributions(qm.getAffectedVersionAttributions(persistentVuln, vs))) @@ -431,7 +445,8 @@ public Response updateVulnerability(Vulnerability jsonVuln) { validator.validateProperty(jsonVuln, "cvssV3Vector"), validator.validateProperty(jsonVuln, "owaspRRVector"), validator.validateProperty(jsonVuln, "vulnerableVersions"), - validator.validateProperty(jsonVuln, "patchedVersions") + validator.validateProperty(jsonVuln, "patchedVersions"), + validator.validateProperty(jsonVuln, "aliases") ); try (QueryManager qm = new QueryManager()) { Vulnerability vulnerability = qm.getObjectByUuid(Vulnerability.class, jsonVuln.getUuid()); @@ -439,7 +454,25 @@ public Response updateVulnerability(Vulnerability jsonVuln) { if (!vulnerability.getVulnId().equals(jsonVuln.getVulnId())) { return Response.status(Response.Status.NOT_ACCEPTABLE).entity("The vulnId may not be changed.").build(); } + List aliases = qm.getVulnerabilityAliases(vulnerability); + VulnerabilityAlias alias; + if (aliases == null || aliases.isEmpty()) { + alias = new VulnerabilityAlias(); + alias.setUuid(UUID.randomUUID()); + aliases = new ArrayList<>(); + aliases.add(alias); + } + alias = aliases.get(0); + + VulnerabilityAlias incoming = jsonVuln.getAliases().isEmpty() ? null : jsonVuln.getAliases().getFirst(); + if (incoming != null) { + alias.setInternalId(incoming.getInternalId()); + alias.setCveId(incoming.getCveId()); + alias.setGhsaId(incoming.getGhsaId()); + alias.setOsvId(incoming.getOsvId()); + } + jsonVuln.setAliases(aliases); final List cweIds = new ArrayList<>(); if (jsonVuln.getCwes() != null) { for (int i = 0; i < jsonVuln.getCwes().size(); i++) { @@ -464,6 +497,7 @@ public Response updateVulnerability(Vulnerability jsonVuln) { return qm.callInTransaction(() -> { final Vulnerability persistentVuln = qm.updateVulnerability(jsonVuln, true); qm.synchronizeVulnerableSoftware(persistentVuln, vsList, Vulnerability.Source.INTERNAL); + qm.synchronizeVulnerabilityAlias(jsonVuln.getAliases().getFirst()); if (persistentVuln.getVulnerableSoftware() != null && !persistentVuln.getVulnerableSoftware().isEmpty()) { persistentVuln.setAffectedComponents(persistentVuln.getVulnerableSoftware().stream() .peek(vs -> vs.setAffectedVersionAttributions(qm.getAffectedVersionAttributions(persistentVuln, vs))) @@ -501,11 +535,13 @@ public Response deleteVulnerability( @PathParam("uuid") @ValidUuid String uuid) { try (QueryManager qm = new QueryManager()) { final Vulnerability vulnerability = qm.getObjectByUuid(Vulnerability.class, uuid); + List aliases = qm.getVulnerabilityAliases(vulnerability); if (vulnerability != null) { if (Vulnerability.Source.INTERNAL.name().equals(vulnerability.getSource())) { if (vulnerability.getComponents().size() > 0) { return Response.status(Response.Status.PRECONDITION_FAILED).entity("Portfolio components or services are affected by this vulnerability. Unable to delete.").build(); } else { + if (!aliases.isEmpty()) aliases.getFirst().setInternalId(null); qm.deleteAffectedVersionAttributions(vulnerability); qm.delete(vulnerability); return Response.status(Response.Status.NO_CONTENT).build();