diff --git a/src/main/java/org/dependencytrack/parser/cyclonedx/util/ModelConverter.java b/src/main/java/org/dependencytrack/parser/cyclonedx/util/ModelConverter.java index 003d85a18f..d85180c21f 100644 --- a/src/main/java/org/dependencytrack/parser/cyclonedx/util/ModelConverter.java +++ b/src/main/java/org/dependencytrack/parser/cyclonedx/util/ModelConverter.java @@ -562,14 +562,14 @@ public static Component convert(final QueryManager qm, final org.cyclonedx.model for (final org.cyclonedx.model.License cycloneLicense : licenseOptions) { if (cycloneLicense != null) { if (StringUtils.isNotBlank(cycloneLicense.getId())) { - final License license = qm.getLicense(StringUtils.trimToNull(cycloneLicense.getId())); + final License license = qm.getLicenseByIdOrName(StringUtils.trimToNull(cycloneLicense.getId())); if (license != null) { component.setResolvedLicense(license); } } else if (StringUtils.isNotBlank(cycloneLicense.getName())) { - final License license = qm.getLicense(StringUtils.trimToNull(cycloneLicense.getName())); + final License license = qm.getLicenseByIdOrName(StringUtils.trimToNull(cycloneLicense.getName())); if (license != null) { component.setResolvedLicense(license); } else { diff --git a/src/main/java/org/dependencytrack/persistence/LicenseQueryManager.java b/src/main/java/org/dependencytrack/persistence/LicenseQueryManager.java index 0830237886..a404b5e954 100644 --- a/src/main/java/org/dependencytrack/persistence/LicenseQueryManager.java +++ b/src/main/java/org/dependencytrack/persistence/LicenseQueryManager.java @@ -28,6 +28,7 @@ import javax.jdo.PersistenceManager; import javax.jdo.Query; import java.util.List; +import java.util.Map; final class LicenseQueryManager extends QueryManager implements IQueryManager { @@ -93,6 +94,18 @@ public License getLicense(String licenseId) { return singleResult(query.execute(licenseId)); } + public License getLicenseByIdOrName(final String licenseIdOrName) { + final Query query = pm.newQuery(License.class); + query.setFilter("licenseId == :licenseIdOrName || name == :licenseIdOrName"); + query.setNamedParameters(Map.of("licenseIdOrName", licenseIdOrName)); + try { + final License license = query.executeUnique(); + return license != null ? license : License.UNRESOLVED; + } finally { + query.closeAll(); + } + } + /** * Returns a Custom License object from the specified name * @param licenseName license name of custom license diff --git a/src/main/java/org/dependencytrack/persistence/QueryManager.java b/src/main/java/org/dependencytrack/persistence/QueryManager.java index 5a8285585f..8203c38f43 100644 --- a/src/main/java/org/dependencytrack/persistence/QueryManager.java +++ b/src/main/java/org/dependencytrack/persistence/QueryManager.java @@ -620,6 +620,10 @@ public License getLicense(String licenseId) { return getLicenseQueryManager().getLicense(licenseId); } + public License getLicenseByIdOrName(final String licenseIdOrName) { + return getLicenseQueryManager().getLicenseByIdOrName(licenseIdOrName); + } + public License getCustomLicense(String licenseName) { return getLicenseQueryManager().getCustomLicense(licenseName); } diff --git a/src/main/java/org/dependencytrack/tasks/BomUploadProcessingTaskV2.java b/src/main/java/org/dependencytrack/tasks/BomUploadProcessingTaskV2.java index b6b0619e04..56df402fc3 100644 --- a/src/main/java/org/dependencytrack/tasks/BomUploadProcessingTaskV2.java +++ b/src/main/java/org/dependencytrack/tasks/BomUploadProcessingTaskV2.java @@ -673,8 +673,7 @@ private static void resolveAndApplyLicense(final QueryManager qm, // by priority, and simply take the first resolvable candidate. for (final org.cyclonedx.model.License licenseCandidate : component.getLicenseCandidates()) { if (isNotBlank(licenseCandidate.getId())) { - final License resolvedLicense = licenseCache.computeIfAbsent(licenseCandidate.getId(), - licenseId -> resolveLicense(qm, licenseId)); + final License resolvedLicense = licenseCache.computeIfAbsent(licenseCandidate.getId(), qm::getLicenseByIdOrName); if (resolvedLicense != License.UNRESOLVED) { component.setResolvedLicense(resolvedLicense); component.setLicenseUrl(trimToNull(licenseCandidate.getUrl())); @@ -683,8 +682,7 @@ private static void resolveAndApplyLicense(final QueryManager qm, } if (isNotBlank(licenseCandidate.getName())) { - final License resolvedLicense = licenseCache.computeIfAbsent(licenseCandidate.getName(), - licenseName -> resolveLicense(qm, licenseName)); + final License resolvedLicense = licenseCache.computeIfAbsent(licenseCandidate.getName(), qm::getLicenseByIdOrName); if (resolvedLicense != License.UNRESOLVED) { component.setResolvedLicense(resolvedLicense); component.setLicenseUrl(trimToNull(licenseCandidate.getUrl())); @@ -714,18 +712,6 @@ private static void resolveAndApplyLicense(final QueryManager qm, } } - private static License resolveLicense(final QueryManager qm, final String licenseId) { - final Query query = qm.getPersistenceManager().newQuery(License.class); - query.setFilter("licenseId == :licenseId"); - query.setParameters(licenseId); - try { - final License license = query.executeUnique(); - return license != null ? license : License.UNRESOLVED; - } finally { - query.closeAll(); - } - } - private static License resolveCustomLicense(final QueryManager qm, final String licenseName) { final Query query = qm.getPersistenceManager().newQuery(License.class); query.setFilter("name == :name && customLicense == true"); diff --git a/src/test/java/org/dependencytrack/tasks/BomUploadProcessingTaskTest.java b/src/test/java/org/dependencytrack/tasks/BomUploadProcessingTaskTest.java index 72e972ab38..aaf55fcbcd 100644 --- a/src/test/java/org/dependencytrack/tasks/BomUploadProcessingTaskTest.java +++ b/src/test/java/org/dependencytrack/tasks/BomUploadProcessingTaskTest.java @@ -1046,6 +1046,49 @@ public void informWithExistingComponentPropertiesAndBomWithComponentProperties() }); } + @Test + public void informWithLicenseResolutionByNameTest() { + final var license = new License(); + license.setLicenseId("MIT"); + license.setName("MIT License"); + qm.persist(license); + + final var project = new Project(); + project.setName("acme-license-app"); + qm.persist(project); + + final byte[] bomBytes = """ + { + "bomFormat": "CycloneDX", + "specVersion": "1.4", + "serialNumber": "urn:uuid:3e671687-395b-41f5-a30f-a58921a69b80", + "version": 1, + "components": [ + { + "type": "library", + "name": "acme-lib-x", + "licenses": [ + { + "license": { + "name": "MIT License" + } + } + ] + } + ] + } + """.getBytes(StandardCharsets.UTF_8); + + final var bomUploadEvent = new BomUploadEvent(qm.detach(Project.class, project.getId()), bomBytes); + new BomUploadProcessingTaskV2().inform(bomUploadEvent); + awaitBomProcessedNotification(bomUploadEvent); + + assertThat(qm.getAllComponents(project)).satisfiesExactly(component -> { + assertThat(component.getResolvedLicense()).isNotNull(); + assertThat(component.getResolvedLicense().getLicenseId()).isEqualTo("MIT"); + }); + } + @Test // https://github.com/DependencyTrack/dependency-track/issues/1905 public void informIssue1905Test() throws Exception { // Known to now work with old task implementation.