From a35c5b232e354e3be693ea55fac6824f27c17f8f Mon Sep 17 00:00:00 2001 From: Johannes Zahn Date: Thu, 1 Jul 2021 07:55:46 +0200 Subject: [PATCH 1/2] Fix that Findings with empty locations throw Error Signed-off-by: Johannes Zahn --- ...cureCodeBoxFindingsToDefectDojoMapper.java | 39 +++++++++++-------- ...CodeBoxFindingsToDefectDojoMapperTest.java | 15 +++++-- 2 files changed, 35 insertions(+), 19 deletions(-) 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..6c59f818ac 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 @@ -34,8 +39,8 @@ public static String fromSecureCodeboxFindingsJson(String scbFindingsJson) throw 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)); + 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,6 +52,7 @@ 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 @@ -55,14 +61,14 @@ protected static DefectDojoImportFinding fromSecureCodeBoxFinding(SecureCodeBoxF //set basic 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 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); @@ -70,25 +76,26 @@ protected static DefectDojoImportFinding fromSecureCodeBoxFinding(SecureCodeBoxF 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()); + 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()); + } } 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()); } } From 68cf851d0d2200d1e2b97430168a00fef34e5b95 Mon Sep 17 00:00:00 2001 From: Johannes Zahn Date: Thu, 1 Jul 2021 08:23:20 +0200 Subject: [PATCH 2/2] extract methods to reduce complexity Signed-off-by: Johannes Zahn --- ...cureCodeBoxFindingsToDefectDojoMapper.java | 35 +++++++++++-------- 1 file changed, 20 insertions(+), 15 deletions(-) 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 6c59f818ac..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 @@ -38,7 +38,8 @@ 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<>() {}); + List secureCodeBoxFindings = mapper.readValue(scbFindingsJson, new TypeReference<>() { + }); for (SecureCodeBoxFinding secureCodeBoxFinding : secureCodeBoxFindings) { DefectDojoImportFindings.add(fromSecureCodeBoxFinding(secureCodeBoxFinding)); } @@ -58,31 +59,25 @@ public static String fromSecureCodeboxFindingsJson(String scbFindingsJson) throw * @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()); 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) { String attributesJson = prettyJSONPrinter.writeValueAsString(secureCodeBoxFinding.getAttributes()); description = description + "\n " + attributesJson; } result.setDescription(description); + setFindingTimestamp(secureCodeBoxFinding, result); + setFindingLocation(secureCodeBoxFinding, result); + return result; + } - //set finding date - Instant instant; - if (secureCodeBoxFinding.getTimestamp() != null) { - instant = Instant.from(DateTimeFormatter.ISO_INSTANT.parse(secureCodeBoxFinding.getTimestamp())); - } else { - instant = Instant.now(); - } - LocalDateTime localDateTime = LocalDateTime.ofInstant(instant, ZoneId.systemDefault()); - result.setDate(dtf.format(localDateTime)); - - //set finding location + private static void setFindingLocation(SecureCodeBoxFinding secureCodeBoxFinding, DefectDojoImportFinding result) { if (secureCodeBoxFinding.getLocation() != null && !secureCodeBoxFinding.getLocation().isEmpty()) { try { URI.create(secureCodeBoxFinding.getLocation()); @@ -91,7 +86,17 @@ protected static DefectDojoImportFinding fromSecureCodeBoxFinding(SecureCodeBoxF LOG.warn("Couldn't parse the secureCodeBox location, because it: {} is not a vailid uri: {}", e, secureCodeBoxFinding.getLocation()); } } - return result; + } + + private static void setFindingTimestamp(SecureCodeBoxFinding secureCodeBoxFinding, DefectDojoImportFinding result) { + Instant instant; + if (secureCodeBoxFinding.getTimestamp() != null) { + instant = Instant.from(DateTimeFormatter.ISO_INSTANT.parse(secureCodeBoxFinding.getTimestamp())); + } else { + instant = Instant.now(); + } + LocalDateTime localDateTime = LocalDateTime.ofInstant(instant, ZoneId.systemDefault()); + result.setDate(dtf.format(localDateTime)); } private static String capitalize(String str) {