From f5c6566766fa5241c7c9f42750e53b5d7b3a1780 Mon Sep 17 00:00:00 2001 From: Adam Setch Date: Wed, 31 Jan 2024 14:57:56 -0500 Subject: [PATCH] feat(vulnerabilities): enhance API to support frontend changes around active/inactive affected projects Signed-off-by: Adam Setch --- .../dependencytrack/model/Vulnerability.java | 20 ++++++++++++++++ .../VulnerabilityQueryManager.java | 10 +++++++- .../resources/v1/VulnerabilityResource.java | 23 ++++++++++++------- .../resources/v1/vo/AffectedProject.java | 9 +++++++- 4 files changed, 52 insertions(+), 10 deletions(-) diff --git a/src/main/java/org/dependencytrack/model/Vulnerability.java b/src/main/java/org/dependencytrack/model/Vulnerability.java index 95bb646016..fd8fc4bc96 100644 --- a/src/main/java/org/dependencytrack/model/Vulnerability.java +++ b/src/main/java/org/dependencytrack/model/Vulnerability.java @@ -311,6 +311,10 @@ public static boolean isKnownSource(String source) { private transient int affectedProjectCount; + private transient int affectedActiveProjectCount; + + private transient int affectedInactiveProjectCount; + private transient FindingAttribution findingAttribution; private transient List affectedComponents; @@ -646,6 +650,22 @@ public void setAffectedProjectCount(int affectedProjectCount) { this.affectedProjectCount = affectedProjectCount; } + public int getAffectedActiveProjectCount() { + return affectedActiveProjectCount; + } + + public void setAffectedActiveProjectCount(int affectedActiveProjectCount) { + this.affectedActiveProjectCount = affectedActiveProjectCount; + } + + public int getAffectedInactiveProjectCount() { + return affectedInactiveProjectCount; + } + + public void setAffectedInactiveProjectCount(int affectedInactiveProjectCount) { + this.affectedInactiveProjectCount = affectedInactiveProjectCount; + } + public FindingAttribution getFindingAttribution() { return findingAttribution; } diff --git a/src/main/java/org/dependencytrack/persistence/VulnerabilityQueryManager.java b/src/main/java/org/dependencytrack/persistence/VulnerabilityQueryManager.java index b41a878915..3d32787125 100644 --- a/src/main/java/org/dependencytrack/persistence/VulnerabilityQueryManager.java +++ b/src/main/java/org/dependencytrack/persistence/VulnerabilityQueryManager.java @@ -303,7 +303,14 @@ public PaginatedResult getVulnerabilities() { result = execute(query); } for (final Vulnerability vulnerability: result.getList(Vulnerability.class)) { - vulnerability.setAffectedProjectCount(this.getAffectedProjects(vulnerability).size()); + List affectedProjects = this.getAffectedProjects(vulnerability); + int affectedProjectsCount = affectedProjects.size(); + int affectedActiveProjectsCount = (int) affectedProjects.stream().filter(AffectedProject::getActive).count(); + int affectedInactiveProjectsCount = affectedProjectsCount - affectedActiveProjectsCount; + + vulnerability.setAffectedProjectCount(affectedProjectsCount); + vulnerability.setAffectedActiveProjectCount(affectedActiveProjectsCount); + vulnerability.setAffectedInactiveProjectCount(affectedInactiveProjectsCount); vulnerability.setAliases(getVulnerabilityAliases(vulnerability)); } return result; @@ -494,6 +501,7 @@ public List getAffectedProjects(Vulnerability vulnerability) { project.getDirectDependencies() != null, project.getName(), project.getVersion(), + project.isActive(), null); affectedProjectMap.put(project.getUuid(), affectedProject); } diff --git a/src/main/java/org/dependencytrack/resources/v1/VulnerabilityResource.java b/src/main/java/org/dependencytrack/resources/v1/VulnerabilityResource.java index 2282c823be..5116150781 100644 --- a/src/main/java/org/dependencytrack/resources/v1/VulnerabilityResource.java +++ b/src/main/java/org/dependencytrack/resources/v1/VulnerabilityResource.java @@ -151,7 +151,7 @@ public Response getVulnerabilitiesByProject(@PathParam("uuid") String uuid, }) @PermissionRequired(Permissions.Constants.VULNERABILITY_MANAGEMENT) public Response getVulnerabilityByUuid(@ApiParam(value = "The UUID of the vulnerability", required = true) - @PathParam("uuid") String uuid) { + @PathParam("uuid") String uuid) { try (QueryManager qm = new QueryManager()) { final Vulnerability vulnerability = qm.getObjectByUuid(Vulnerability.class, uuid); if (vulnerability != null) { @@ -180,7 +180,7 @@ public Response getVulnerabilityByVulnId(@PathParam("source") String source, final Vulnerability vulnerability = qm.getVulnerabilityByVulnId(source, vuln); if (vulnerability != null) { final List affectedComponents = new ArrayList<>(); - for (final VulnerableSoftware vs: vulnerability.getVulnerableSoftware()) { + for (final VulnerableSoftware vs : vulnerability.getVulnerableSoftware()) { AffectedComponent affectedComponent = new AffectedComponent(vs); final List attributions = qm.getAffectedVersionAttributions(vulnerability, vs); affectedComponent.setAffectedVersionAttributions(attributions); @@ -209,10 +209,17 @@ public Response getVulnerabilityByVulnId(@PathParam("source") String source, }) @PermissionRequired(Permissions.Constants.VIEW_PORTFOLIO) public Response getAffectedProject(@PathParam("source") String source, - @PathParam("vuln") String vuln) { + @PathParam("vuln") String vuln, + @ApiParam(value = "Optionally excludes inactive projects from being returned", required = false) + @QueryParam("excludeInactive") boolean excludeInactive) { try (QueryManager qm = new QueryManager(getAlpineRequest())) { final Vulnerability vulnerability = qm.getVulnerabilityByVulnId(source, vuln); if (vulnerability != null) { + if (excludeInactive) { + final List filteredProjects = qm.getAffectedProjects(vulnerability).stream().filter(AffectedProject::getActive).toList(); + final long filteredCount = filteredProjects.size(); + return Response.ok(filteredProjects).header(TOTAL_COUNT_HEADER, filteredCount).build(); + } final List projects = qm.getAffectedProjects(vulnerability); final long totalCount = projects.size(); return Response.ok(projects).header(TOTAL_COUNT_HEADER, totalCount).build(); @@ -280,7 +287,7 @@ public Response createVulnerability(Vulnerability jsonVulnerability) { if (vulnerability == null) { final List cweIds = new ArrayList<>(); if (jsonVulnerability.getCwes() != null) { - for (int i=0; i vsList = new ArrayList<>(); if (jsonVulnerability.getAffectedComponents() != null) { - for (final AffectedComponent ac: jsonVulnerability.getAffectedComponents()) { + for (final AffectedComponent ac : jsonVulnerability.getAffectedComponents()) { final VulnerableSoftware vs = ac.toVulnerableSoftware(); if (vs != null) { vsList.add(vs); @@ -308,7 +315,7 @@ public Response createVulnerability(Vulnerability jsonVulnerability) { } else { return Response.status(Response.Status.CONFLICT).entity("A vulnerability with the specified vulnId already exists.").build(); } - } catch (MissingFactorException|IllegalArgumentException exception) { + } catch (MissingFactorException | IllegalArgumentException exception) { return Response.status(Response.Status.BAD_REQUEST).entity(exception.getMessage()).build(); } } @@ -353,7 +360,7 @@ public Response updateVulnerability(Vulnerability jsonVuln) { final List cweIds = new ArrayList<>(); if (jsonVuln.getCwes() != null) { - for (int i=0; i vsListOld = qm.getVulnerableSoftwareByVulnId(vulnerability.getSource(), vulnerability.getVulnId()); List vsList = new ArrayList<>(); if (jsonVuln.getAffectedComponents() != null) { - for (final AffectedComponent ac: jsonVuln.getAffectedComponents()) { + for (final AffectedComponent ac : jsonVuln.getAffectedComponents()) { final VulnerableSoftware vs = ac.toVulnerableSoftware(); if (vs != null) { vsList.add(vs); diff --git a/src/main/java/org/dependencytrack/resources/v1/vo/AffectedProject.java b/src/main/java/org/dependencytrack/resources/v1/vo/AffectedProject.java index e119b876f8..321105a04a 100644 --- a/src/main/java/org/dependencytrack/resources/v1/vo/AffectedProject.java +++ b/src/main/java/org/dependencytrack/resources/v1/vo/AffectedProject.java @@ -38,13 +38,16 @@ public class AffectedProject { private final String version; + private final boolean active; + private final List affectedComponentUuids; - public AffectedProject(UUID uuid, boolean dependencyGraphAvailable, String name, String version, List affectedComponentUuids) { + public AffectedProject(UUID uuid, boolean dependencyGraphAvailable, String name, String version, boolean active, List affectedComponentUuids) { this.uuid = uuid; this.dependencyGraphAvailable = dependencyGraphAvailable; this.name = name; this.version = version; + this.active = active; this.affectedComponentUuids = affectedComponentUuids == null ? new ArrayList<>() : affectedComponentUuids; } @@ -63,6 +66,10 @@ public String getVersion() { return version; } + public boolean getActive() { + return active; + } + public List getAffectedComponentUuids() { return affectedComponentUuids; }