diff --git a/hooks/persistence-defectdojo/src/main/java/io/securecodebox/persistence/mapping/SecureCodeBoxFindingsToDefectDojoMapper.java b/hooks/persistence-defectdojo/src/main/java/io/securecodebox/persistence/mapping/SecureCodeBoxFindingsToDefectDojoMapper.java index 856507be54..a594655199 100644 --- a/hooks/persistence-defectdojo/src/main/java/io/securecodebox/persistence/mapping/SecureCodeBoxFindingsToDefectDojoMapper.java +++ b/hooks/persistence-defectdojo/src/main/java/io/securecodebox/persistence/mapping/SecureCodeBoxFindingsToDefectDojoMapper.java @@ -14,9 +14,13 @@ import java.io.IOException; import java.net.URI; -import java.time.*; +import java.time.Instant; +import java.time.LocalDateTime; +import java.time.ZoneId; import java.time.format.DateTimeFormatter; -import java.util.*; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; public class SecureCodeBoxFindingsToDefectDojoMapper { private static final Logger LOG = LoggerFactory.getLogger(SecureCodeBoxFindingsToDefectDojoMapper.class); @@ -25,6 +29,7 @@ public class SecureCodeBoxFindingsToDefectDojoMapper { /** * Converts a SecureCodeBox Findings JSON String to a DefectDojo Findings JSON String. + * * @param scbFindingsJson SecureCodeBox Findings JSON File as String * @return DefectDojo Findings JSON File as String, compatible with the DefectDojo Generic JSON Parser * @throws IOException @@ -33,9 +38,10 @@ public static String fromSecureCodeboxFindingsJson(String scbFindingsJson) throw LOG.debug("Converting SecureCodeBox Findings to DefectDojo Findings"); ObjectMapper mapper = new ObjectMapper().configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); List DefectDojoImportFindings = new ArrayList<>(); - List secureCodeBoxFindings = mapper.readValue(scbFindingsJson, new TypeReference<>() {}); - for (SecureCodeBoxFinding secureCodeBoxFinding : secureCodeBoxFindings){ - DefectDojoImportFindings.add(fromSecureCodeBoxFinding(secureCodeBoxFinding)); + List secureCodeBoxFindings = mapper.readValue(scbFindingsJson, new TypeReference<>() { + }); + for (SecureCodeBoxFinding secureCodeBoxFinding : secureCodeBoxFindings) { + DefectDojoImportFindings.add(fromSecureCodeBoxFinding(secureCodeBoxFinding)); } // create the result where the format has to be {"findings": [finding1, findings2, ...]} ObjectNode ddFindingJson = mapper.createObjectNode(); @@ -47,48 +53,54 @@ public static String fromSecureCodeboxFindingsJson(String scbFindingsJson) throw /** * Converts a SecureCodeBox Finding to a DefectDojo Finding, * that can be imported by the DefectDojo Generic JSON Parser. + * * @param secureCodeBoxFinding Finding in SecureCodeBox format. * @return Finding in DefectDojo Format, compatible with the DefectDojo Generic JSON Parser * @throws JsonProcessingException */ protected static DefectDojoImportFinding fromSecureCodeBoxFinding(SecureCodeBoxFinding secureCodeBoxFinding) throws JsonProcessingException { - //set basic info + //set basic Finding info DefectDojoImportFinding result = new DefectDojoImportFinding(); result.setTitle(secureCodeBoxFinding.getName()); - result.setSeverity(capitalize(secureCodeBoxFinding.getSeverity().toString())); + if (secureCodeBoxFinding.getSeverity() != null) + result.setSeverity(capitalize(secureCodeBoxFinding.getSeverity().toString())); result.setUniqueIdFromTool(secureCodeBoxFinding.getId()); - - // set Description as combination of finding description and finding attributes + // set DefectDojo description as combination of SecureCodeBox Finding description and Finding attributes String description = secureCodeBoxFinding.getDescription(); - if (secureCodeBoxFinding.getAttributes()!=null) { + if (secureCodeBoxFinding.getAttributes() != null) { String attributesJson = prettyJSONPrinter.writeValueAsString(secureCodeBoxFinding.getAttributes()); - description = description + "\n " + attributesJson; + description = description + "\n " + attributesJson; } result.setDescription(description); + setFindingTimestamp(secureCodeBoxFinding, result); + setFindingLocation(secureCodeBoxFinding, result); + return result; + } + + private static void setFindingLocation(SecureCodeBoxFinding secureCodeBoxFinding, DefectDojoImportFinding result) { + if (secureCodeBoxFinding.getLocation() != null && !secureCodeBoxFinding.getLocation().isEmpty()) { + try { + URI.create(secureCodeBoxFinding.getLocation()); + result.setEndpoints(Collections.singletonList(secureCodeBoxFinding.getLocation())); + } catch (IllegalArgumentException e) { + LOG.warn("Couldn't parse the secureCodeBox location, because it: {} is not a vailid uri: {}", e, secureCodeBoxFinding.getLocation()); + } + } + } - //set finding date + private static void setFindingTimestamp(SecureCodeBoxFinding secureCodeBoxFinding, DefectDojoImportFinding result) { Instant instant; if (secureCodeBoxFinding.getTimestamp() != null) { instant = Instant.from(DateTimeFormatter.ISO_INSTANT.parse(secureCodeBoxFinding.getTimestamp())); - } - else { + } else { instant = Instant.now(); } LocalDateTime localDateTime = LocalDateTime.ofInstant(instant, ZoneId.systemDefault()); result.setDate(dtf.format(localDateTime)); - - //set finding location - try { - URI.create(secureCodeBoxFinding.getLocation()); - result.setEndpoints(Collections.singletonList(secureCodeBoxFinding.getLocation())); - } catch (IllegalArgumentException e) { - LOG.warn("Couldn't parse the secureCodeBox location, because it: {} s not a vailid uri: {}", e, secureCodeBoxFinding.getLocation()); - } - return result; } private static String capitalize(String str) { - if(str == null || str.isEmpty()) { + if (str == null || str.isEmpty()) { return str; } diff --git a/hooks/persistence-defectdojo/src/test/java/io/securecodebox/persistence/mapping/SecureCodeBoxFindingsToDefectDojoMapperTest.java b/hooks/persistence-defectdojo/src/test/java/io/securecodebox/persistence/mapping/SecureCodeBoxFindingsToDefectDojoMapperTest.java index d757437d4c..0eb079a9d3 100644 --- a/hooks/persistence-defectdojo/src/test/java/io/securecodebox/persistence/mapping/SecureCodeBoxFindingsToDefectDojoMapperTest.java +++ b/hooks/persistence-defectdojo/src/test/java/io/securecodebox/persistence/mapping/SecureCodeBoxFindingsToDefectDojoMapperTest.java @@ -1,5 +1,6 @@ package io.securecodebox.persistence.mapping; +import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; import io.securecodebox.persistence.models.SecureCodeBoxFinding; @@ -36,7 +37,7 @@ public void yieldsCorrectResult() throws IOException { // if whitespaces should be ignored in strings, a Custom Comperator could be used // then the result and expected result would not have to match exactly. // see https://www.baeldung.com/jackson-compare-two-json-objects - assertEquals(actualJSON,expectedJSON); + assertEquals(actualJSON, expectedJSON); } @Test @@ -63,7 +64,7 @@ public void correctlyParsesFindings() throws IOException { assertEquals(ddFinding.getEndpoints().get(0), location); assertTrue(ddFinding.getDescription().startsWith(description)); //Description should consist of description and attributes as JSON - String attributesJson = ddFinding.getDescription().substring(description.length()+1); + String attributesJson = ddFinding.getDescription().substring(description.length() + 1); String expectedAttributeJson = "{\n" + " \"attribute_1\" : {\n" + " \"sub_attribute\" : \"1\"\n" + @@ -75,6 +76,14 @@ public void correctlyParsesFindings() throws IOException { var expectedJson = mapper.readTree(attributesJson); var actualJson = mapper.readTree(expectedAttributeJson); assertNotNull(actualJson); - assertEquals(mapper.readTree(attributesJson),mapper.readTree(expectedAttributeJson)); + assertEquals(mapper.readTree(attributesJson), mapper.readTree(expectedAttributeJson)); + } + + @Test + public void doesntThrowUnexpectedExceptionOnEmptyFinding() throws JsonProcessingException { + var emptyScbFinding = SecureCodeBoxFinding.builder().build(); + var ddFinding = SecureCodeBoxFindingsToDefectDojoMapper.fromSecureCodeBoxFinding(emptyScbFinding); + assertNull(ddFinding.getTitle()); + assertNull(ddFinding.getDescription()); } }