diff --git a/src/main/java/org/dependencytrack/model/Project.java b/src/main/java/org/dependencytrack/model/Project.java index f505cb1e4a..28c7cbcef1 100644 --- a/src/main/java/org/dependencytrack/model/Project.java +++ b/src/main/java/org/dependencytrack/model/Project.java @@ -47,6 +47,7 @@ import javax.jdo.annotations.Persistent; import javax.jdo.annotations.PrimaryKey; import javax.jdo.annotations.Unique; +import javax.jdo.annotations.Serialized; import javax.validation.constraints.NotBlank; import javax.validation.constraints.NotNull; import javax.validation.constraints.Pattern; @@ -249,6 +250,11 @@ public enum FetchGroup { @JsonIgnore private List accessTeams; + @Persistent(defaultFetchGroup = "true") + @Column(name = "EXTERNAL_REFERENCES") + @Serialized + private List externalReferences; + @JsonProperty("parentUuid") private UUID getParentUuid() { return (this.getParent() == null) ? null : this.getParent().getUuid(); @@ -429,6 +435,14 @@ public void setLastInheritedRiskScore(Double lastInheritedRiskScore) { this.lastInheritedRiskScore = lastInheritedRiskScore; } + public List getExternalReferences() { + return externalReferences; + } + + public void setExternalReferences(List externalReferences) { + this.externalReferences = externalReferences; + } + public Boolean isActive() { return active; } 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 e6111c2647..d9e28ce411 100644 --- a/src/main/java/org/dependencytrack/parser/cyclonedx/util/ModelConverter.java +++ b/src/main/java/org/dependencytrack/parser/cyclonedx/util/ModelConverter.java @@ -329,6 +329,17 @@ public static org.cyclonedx.model.Metadata createMetadata(final Project project) } else { cycloneComponent.setType(org.cyclonedx.model.Component.Type.LIBRARY); } + if (project.getExternalReferences() != null && project.getExternalReferences().size() > 0) { + List references = new ArrayList<>(); + project.getExternalReferences().stream().forEach(externalReference -> { + org.cyclonedx.model.ExternalReference ref = new org.cyclonedx.model.ExternalReference(); + ref.setUrl(externalReference.getUrl()); + ref.setType(externalReference.getType()); + ref.setComment(externalReference.getComment()); + references.add(ref); + }); + cycloneComponent.setExternalReferences(references); + } metadata.setComponent(cycloneComponent); } return metadata; @@ -689,6 +700,27 @@ public static void generateDependencies(final QueryManager qm, final Bom bom, fi } } + public static List convertBomMetadataExternalReferences(Bom bom) { + if (bom.getMetadata() != null && bom.getMetadata().getComponent() != null) { + org.cyclonedx.model.Component cycloneDxComponent = bom.getMetadata().getComponent(); + if (cycloneDxComponent.getExternalReferences() != null && cycloneDxComponent.getExternalReferences().size() > 0) { + List references = new ArrayList<>(); + for (org.cyclonedx.model.ExternalReference cycloneDxRef : cycloneDxComponent.getExternalReferences()) { + ExternalReference ref = new ExternalReference(); + ref.setType(cycloneDxRef.getType()); + ref.setUrl(cycloneDxRef.getUrl()); + ref.setComment(cycloneDxRef.getComment()); + references.add(ref); + } + return references; + } else { + return null; + } + } else { + return null; + } + } + private static Component getComponentFromBomRef(final String bomRef, final List components) { if (components != null) { for (Component c : components) { diff --git a/src/main/java/org/dependencytrack/tasks/BomUploadProcessingTask.java b/src/main/java/org/dependencytrack/tasks/BomUploadProcessingTask.java index a88f39a239..504f830b49 100644 --- a/src/main/java/org/dependencytrack/tasks/BomUploadProcessingTask.java +++ b/src/main/java/org/dependencytrack/tasks/BomUploadProcessingTask.java @@ -102,6 +102,7 @@ public void inform(final Event e) { .orElse(Classifier.APPLICATION); project.setClassifier(classifier); } + project.setExternalReferences(ModelConverter.convertBomMetadataExternalReferences(cycloneDxBom)); serialNumnber = (cycloneDxBom.getSerialNumber() != null) ? cycloneDxBom.getSerialNumber().replaceFirst("urn:uuid:", "") : null; components = ModelConverter.convertComponents(qm, cycloneDxBom, project); services = ModelConverter.convertServices(qm, cycloneDxBom, project); diff --git a/src/test/java/org/dependencytrack/tasks/BomUploadProcessingTaskTest.java b/src/test/java/org/dependencytrack/tasks/BomUploadProcessingTaskTest.java index c4296caf1e..98e8648bd5 100644 --- a/src/test/java/org/dependencytrack/tasks/BomUploadProcessingTaskTest.java +++ b/src/test/java/org/dependencytrack/tasks/BomUploadProcessingTaskTest.java @@ -131,6 +131,8 @@ public void informTest() throws Exception { qm.getPersistenceManager().refresh(project); assertThat(project.getClassifier()).isEqualTo(Classifier.APPLICATION); assertThat(project.getLastBomImport()).isNotNull(); + assertThat(project.getExternalReferences()).isNotNull(); + assertThat(project.getExternalReferences()).hasSize(4); final List components = qm.getAllComponents(project); assertThat(components).hasSize(1); diff --git a/src/test/resources/bom-1.xml b/src/test/resources/bom-1.xml index a243cd4132..8bc5a3dfc6 100644 --- a/src/test/resources/bom-1.xml +++ b/src/test/resources/bom-1.xml @@ -1,5 +1,25 @@ - + + + + DependencyTrack + Acme example + + + https://acme.example + + + https://acme.example + + + https://acme.example + + + https://acme.example + + + + Example Author