diff --git a/src/main/java/org/dependencytrack/persistence/jdbi/VulnerabilityDao.java b/src/main/java/org/dependencytrack/persistence/jdbi/VulnerabilityDao.java index f3a3fadcb..96f6afda8 100644 --- a/src/main/java/org/dependencytrack/persistence/jdbi/VulnerabilityDao.java +++ b/src/main/java/org/dependencytrack/persistence/jdbi/VulnerabilityDao.java @@ -21,8 +21,10 @@ import org.dependencytrack.model.Component; import org.dependencytrack.model.Vulnerability; import org.dependencytrack.model.VulnerableSoftware; +import org.dependencytrack.persistence.jdbi.mapping.ExternalReferenceMapper; import org.dependencytrack.persistence.jdbi.mapping.VulnerabilityRowMapper; import org.dependencytrack.persistence.jdbi.mapping.VulnerableSoftwareRowMapper; +import org.jdbi.v3.sqlobject.config.RegisterColumnMapper; import org.jdbi.v3.sqlobject.config.RegisterConstructorMapper; import org.jdbi.v3.sqlobject.config.RegisterFieldMapper; import org.jdbi.v3.sqlobject.config.RegisterRowMapper; @@ -394,6 +396,7 @@ SELECT DISTINCT ON ("V"."ID") and "C"."PROJECT_ID" = :projectId """) @RegisterFieldMapper(Component.class) + @RegisterColumnMapper(ExternalReferenceMapper.class) List getVulnerableComponents(@Bind long projectId, @Bind List vulnerabilityIds); @SqlUpdate(""" diff --git a/src/main/java/org/dependencytrack/persistence/jdbi/mapping/ExternalReferenceMapper.java b/src/main/java/org/dependencytrack/persistence/jdbi/mapping/ExternalReferenceMapper.java new file mode 100644 index 000000000..34387fe19 --- /dev/null +++ b/src/main/java/org/dependencytrack/persistence/jdbi/mapping/ExternalReferenceMapper.java @@ -0,0 +1,40 @@ +/* + * This file is part of Dependency-Track. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + * Copyright (c) OWASP Foundation. All Rights Reserved. + */ +package org.dependencytrack.persistence.jdbi.mapping; + +import org.apache.commons.lang3.SerializationUtils; +import org.dependencytrack.model.ExternalReference; +import org.jdbi.v3.core.mapper.ColumnMapper; +import org.jdbi.v3.core.statement.StatementContext; + +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.List; + +public class ExternalReferenceMapper implements ColumnMapper> { + + @Override + public List map(ResultSet r, int columnNumber, StatementContext ctx) throws SQLException { + if (r.getBytes(columnNumber) == null) { + return new ArrayList<>(); + } + return SerializationUtils.deserialize(r.getBytes(columnNumber)); + } +} diff --git a/src/test/java/org/dependencytrack/persistence/VulnerabilityQueryManagerTest.java b/src/test/java/org/dependencytrack/persistence/VulnerabilityQueryManagerTest.java index 663cdd444..67c98aadc 100644 --- a/src/test/java/org/dependencytrack/persistence/VulnerabilityQueryManagerTest.java +++ b/src/test/java/org/dependencytrack/persistence/VulnerabilityQueryManagerTest.java @@ -23,6 +23,7 @@ import org.dependencytrack.PersistenceCapableTest; import org.dependencytrack.model.Component; import org.dependencytrack.model.Epss; +import org.dependencytrack.model.ExternalReference; import org.dependencytrack.model.Project; import org.dependencytrack.model.Severity; import org.dependencytrack.model.Vulnerability; @@ -704,6 +705,10 @@ public void setupData() { component.setProject(project); component.setName("ABC"); component.setPurl("pkg:maven/org.acme/abc"); + var extRef = new ExternalReference(); + extRef.setType(org.cyclonedx.model.ExternalReference.Type.WEBSITE); + extRef.setUrl("www.test.com"); + component.addExternalReference(extRef); component.setVulnerabilities(List.of(vulnA, vulnB)); Component component2 = new Component(); @@ -750,11 +755,13 @@ public void getVulnerabilitiesByProjectTest() { assertThat(vuln.getVulnId()).isEqualTo("INT-001"); assertThat(vuln.getEpssScore()).isEqualByComparingTo("1.2"); assertThat(vuln.getEpssPercentile()).isEqualByComparingTo("3.4"); + assertThat(vuln.getComponents().size()).isEqualTo(2); }, vuln -> { assertThat(vuln.getVulnId()).isEqualTo("INT-002"); assertThat(vuln.getEpssScore()).isNull(); assertThat(vuln.getEpssPercentile()).isNull(); + assertThat(vuln.getComponents().size()).isEqualTo(1); } ); } diff --git a/src/test/java/org/dependencytrack/resources/v1/VulnerabilityResourceTest.java b/src/test/java/org/dependencytrack/resources/v1/VulnerabilityResourceTest.java index c8616506c..f9f6adc70 100644 --- a/src/test/java/org/dependencytrack/resources/v1/VulnerabilityResourceTest.java +++ b/src/test/java/org/dependencytrack/resources/v1/VulnerabilityResourceTest.java @@ -179,7 +179,7 @@ public void getVulnerabilitiesByComponentUuidIncludeSuppressedTest() { } @Test - public void getVulnerabilitiesByProjectTest() throws Exception { + public void getVulnerabilitiesByProjectTest() { SampleData sampleData = new SampleData(); Response response = jersey.target(V1_VULNERABILITY + "/project/" + sampleData.p1.getUuid().toString()).request() .header(X_API_KEY, apiKey) @@ -208,7 +208,8 @@ public void getVulnerabilitiesByProjectTest() throws Exception { "sha256": "47602d7dfe910ad941fea52e85e6e3f1c175434b0e6e261c31c766fe4c078a25", "uuid": "${json-unit.any-string}", "expandDependencyGraph": false, - "isInternal": false + "isInternal": false, + "externalReferences":[] } ], "uuid": "${json-unit.any-string}", @@ -236,7 +237,8 @@ public void getVulnerabilitiesByProjectTest() throws Exception { "sha256": "47602d7dfe910ad941fea52e85e6e3f1c175434b0e6e261c31c766fe4c078a25", "uuid": "${json-unit.any-string}", "expandDependencyGraph": false, - "isInternal": false + "isInternal": false, + "externalReferences":[] } ], "uuid": "${json-unit.any-string}", @@ -268,7 +270,8 @@ public void getVulnerabilitiesByProjectTest() throws Exception { "sha256": "418716b003fe0268b6521ef7acbed13f5ba491d593896d5deb2058c42d87002d", "uuid": "${json-unit.any-string}", "expandDependencyGraph": false, - "isInternal": false + "isInternal": false, + "externalReferences":[] } ], "uuid": "${json-unit.any-string}", @@ -290,7 +293,8 @@ public void getVulnerabilitiesByProjectTest() throws Exception { "sha256": "418716b003fe0268b6521ef7acbed13f5ba491d593896d5deb2058c42d87002d", "uuid": "${json-unit.any-string}", "expandDependencyGraph": false, - "isInternal": false + "isInternal": false, + "externalReferences":[] } ], "uuid": "${json-unit.any-string}", @@ -303,7 +307,7 @@ public void getVulnerabilitiesByProjectTest() throws Exception { } @Test - public void getVulnerabilitiesByProjectIncludeProjectSuppressedTest() throws Exception { + public void getVulnerabilitiesByProjectIncludeProjectSuppressedTest() { SampleData sampleData = new SampleData(); Response response = jersey.target(V1_VULNERABILITY + "/project/" + sampleData.p2.getUuid().toString()) .queryParam("suppressed", "true") @@ -338,7 +342,8 @@ public void getVulnerabilitiesByProjectIncludeProjectSuppressedTest() throws Exc "sha256": "418716b003fe0268b6521ef7acbed13f5ba491d593896d5deb2058c42d87002d", "uuid": "${json-unit.any-string}", "expandDependencyGraph": false, - "isInternal": false + "isInternal": false, + "externalReferences":[] } ], "uuid": "${json-unit.any-string}", @@ -360,7 +365,8 @@ public void getVulnerabilitiesByProjectIncludeProjectSuppressedTest() throws Exc "sha256": "418716b003fe0268b6521ef7acbed13f5ba491d593896d5deb2058c42d87002d", "uuid": "${json-unit.any-string}", "expandDependencyGraph": false, - "isInternal": false + "isInternal": false, + "externalReferences":[] } ], "uuid": "${json-unit.any-string}",