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 83b6d04c94..9f275ec165 100644 --- a/src/main/java/org/dependencytrack/parser/cyclonedx/util/ModelConverter.java +++ b/src/main/java/org/dependencytrack/parser/cyclonedx/util/ModelConverter.java @@ -567,7 +567,11 @@ public static org.cyclonedx.model.Component convert(final QueryManager qm, final final LicenseChoice licenseChoice = new LicenseChoice(); if (component.getResolvedLicense() != null) { final org.cyclonedx.model.License license = new org.cyclonedx.model.License(); - license.setId(component.getResolvedLicense().getLicenseId()); + if(!component.getResolvedLicense().isCustomLicense()){ + license.setId(component.getResolvedLicense().getLicenseId()); + } else{ + license.setName(component.getResolvedLicense().getName()); + } license.setUrl(component.getLicenseUrl()); licenseChoice.addLicense(license); cycloneComponent.setLicenseChoice(licenseChoice); diff --git a/src/test/java/org/dependencytrack/resources/v1/BomResourceTest.java b/src/test/java/org/dependencytrack/resources/v1/BomResourceTest.java index c99eb4c63b..88b8711d68 100644 --- a/src/test/java/org/dependencytrack/resources/v1/BomResourceTest.java +++ b/src/test/java/org/dependencytrack/resources/v1/BomResourceTest.java @@ -315,6 +315,81 @@ public void exportProjectAsCycloneDxInventoryTest() { assertThat(componentWithVulnAndAnalysis.getDirectDependencies()).isNotNull(); } + @Test + public void exportProjectAsCycloneDxLicenseTest() { + Project project = qm.createProject("Acme Example", null, "1.0", null, null, null, true, false); + Component c = new Component(); + c.setProject(project); + c.setName("sample-component"); + c.setVersion("1.0"); + org.dependencytrack.model.License license = new org.dependencytrack.model.License(); + license.setId(1234); + license.setName("CustomName"); + license.setCustomLicense(true); + c.setResolvedLicense(license); + c.setDirectDependencies("[]"); + Component component = qm.createComponent(c, false); + qm.persist(project); + Response response = jersey.target(V1_BOM + "/cyclonedx/project/" + project.getUuid()).request() + .header(X_API_KEY, apiKey) + .get(Response.class); + + final String jsonResponse = getPlainTextBody(response); + assertThatNoException().isThrownBy(() -> CycloneDxValidator.getInstance().validate(jsonResponse.getBytes())); + assertThatJson(jsonResponse) + .withMatcher("component", equalTo(component.getUuid().toString())) + .withMatcher("projectUuid", equalTo(project.getUuid().toString())) + .isEqualTo(json(""" + { + "bomFormat": "CycloneDX", + "specVersion": "1.5", + "serialNumber": "${json-unit.ignore}", + "version": 1, + "metadata": { + "timestamp": "${json-unit.any-string}", + "tools": [ + { + "vendor": "OWASP", + "name": "Dependency-Track", + "version": "${json-unit.any-string}" + } + ], + "component": { + "type": "library", + "bom-ref": "${json-unit.matches:projectUuid}", + "name": "Acme Example", + "version": "1.0" + } + }, + "components": [ + { + "type": "library", + "bom-ref": "${json-unit.matches:component}", + "name": "sample-component", + "version": "1.0", + "licenses": [ + { + "license": { + "name": "CustomName" + } + } + ] + } + ], + "dependencies": [ + { + "ref": "${json-unit.matches:projectUuid}", + "dependsOn": [] + }, + { + "ref": "${json-unit.matches:component}", + "dependsOn": [] + } + ] + } + """)); + } + @Test public void exportProjectAsCycloneDxInventoryWithVulnerabilitiesTest() { var vulnerability = new Vulnerability();