From a6caad237301e303236c289629390551000c7908 Mon Sep 17 00:00:00 2001 From: Johannes Zahn Date: Wed, 18 Aug 2021 14:06:10 +0200 Subject: [PATCH 1/8] improve test structure and tests Signed-off-by: Johannes Zahn --- .../persistence-defectdojo/hook/build.gradle | 1 + .../DefectDojoPersistenceProvider.java | 2 +- ...cureCodeBoxFindingsToDefectDojoMapper.java | 62 +- .../persistence/service/ScanService.java | 28 +- ...CodeBoxFindingsToDefectDojoMapperTest.java | 99 ++- .../persistence/service/ScanServiceTest.java | 98 +++ .../src/test/resources/nikto-raw-result.json | 715 ++++++++++++++++++ 7 files changed, 901 insertions(+), 104 deletions(-) create mode 100644 hooks/persistence-defectdojo/hook/src/test/java/io/securecodebox/persistence/service/ScanServiceTest.java create mode 100644 hooks/persistence-defectdojo/hook/src/test/resources/nikto-raw-result.json diff --git a/hooks/persistence-defectdojo/hook/build.gradle b/hooks/persistence-defectdojo/hook/build.gradle index 403270147d..5b44bd2519 100644 --- a/hooks/persistence-defectdojo/hook/build.gradle +++ b/hooks/persistence-defectdojo/hook/build.gradle @@ -35,6 +35,7 @@ dependencies { testImplementation(platform('org.junit:junit-bom:5.7.0')) testImplementation('org.junit.jupiter:junit-jupiter') + testImplementation 'org.skyscreamer:jsonassert:1.2.3' testImplementation "org.mockito:mockito-core:2.+" testImplementation "org.mockito:mockito-junit-jupiter:2.+" diff --git a/hooks/persistence-defectdojo/hook/src/main/java/io/securecodebox/persistence/DefectDojoPersistenceProvider.java b/hooks/persistence-defectdojo/hook/src/main/java/io/securecodebox/persistence/DefectDojoPersistenceProvider.java index 9c87c8cfba..2d7dbb2606 100644 --- a/hooks/persistence-defectdojo/hook/src/main/java/io/securecodebox/persistence/DefectDojoPersistenceProvider.java +++ b/hooks/persistence-defectdojo/hook/src/main/java/io/securecodebox/persistence/DefectDojoPersistenceProvider.java @@ -33,7 +33,7 @@ public static void main(String[] args) throws Exception { scan.validate(); LOG.info("Downloading Scan Result"); - var scanResultFile = ScanService.downloadScan(scan, persistenceProviderConfig, s3Service); + var scanResultFile = ScanService.getDefectDojoCompatibleScanResult(scan, persistenceProviderConfig, s3Service); var config = DefectDojoConfig.fromEnv(); LOG.info("Uploading Findings to DefectDojo at: {}", config.getUrl()); diff --git a/hooks/persistence-defectdojo/hook/src/main/java/io/securecodebox/persistence/mapping/SecureCodeBoxFindingsToDefectDojoMapper.java b/hooks/persistence-defectdojo/hook/src/main/java/io/securecodebox/persistence/mapping/SecureCodeBoxFindingsToDefectDojoMapper.java index 770ae51fa0..0c104dd0c4 100644 --- a/hooks/persistence-defectdojo/hook/src/main/java/io/securecodebox/persistence/mapping/SecureCodeBoxFindingsToDefectDojoMapper.java +++ b/hooks/persistence-defectdojo/hook/src/main/java/io/securecodebox/persistence/mapping/SecureCodeBoxFindingsToDefectDojoMapper.java @@ -1,62 +1,30 @@ package io.securecodebox.persistence.mapping; import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.core.type.TypeReference; -import com.fasterxml.jackson.databind.DeserializationFeature; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.ObjectWriter; -import com.fasterxml.jackson.databind.node.ArrayNode; -import com.fasterxml.jackson.databind.node.ObjectNode; import io.securecodebox.persistence.models.DefectDojoImportFinding; import io.securecodebox.persistence.models.SecureCodeBoxFinding; +import io.securecodebox.persistence.service.KubernetesService; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import java.io.IOException; import java.net.URI; import java.time.Instant; import java.time.LocalDateTime; import java.time.ZoneId; import java.time.format.DateTimeFormatter; -import java.util.ArrayList; import java.util.Collections; -import java.util.List; public class SecureCodeBoxFindingsToDefectDojoMapper { - private static final Logger LOG = LoggerFactory.getLogger(SecureCodeBoxFindingsToDefectDojoMapper.class); - private static final DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy-MM-dd"); - private static final ObjectWriter prettyJSONPrinter = new ObjectMapper().findAndRegisterModules().writerWithDefaultPrettyPrinter(); + private static final Logger LOG = LoggerFactory.getLogger(KubernetesService.class); + private final DateTimeFormatter ddDateFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd"); + private final ObjectWriter attributeJsonPrinter = new ObjectMapper().writerWithDefaultPrettyPrinter(); - /** - * 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 - */ - public static String fromSecureCodeboxFindingsJson(String scbFindingsJson) throws IOException { - LOG.debug("Converting SecureCodeBox Findings to DefectDojo Findings"); - ObjectMapper mapper = new ObjectMapper() - .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false) - .findAndRegisterModules(); - List DefectDojoImportFindings = new ArrayList<>(); - 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(); - ArrayNode arrayNode = mapper.valueToTree(DefectDojoImportFindings); - ddFindingJson.putArray("findings").addAll(arrayNode); - return ddFindingJson.toString(); - } - - protected static String convertToDefectDojoSeverity(SecureCodeBoxFinding.Severities severity) { + protected String convertToDefectDojoSeverity(SecureCodeBoxFinding.Severities severity) { if (severity == null) { return "Info"; } - switch (severity) { case HIGH: return "High"; @@ -67,7 +35,6 @@ protected static String convertToDefectDojoSeverity(SecureCodeBoxFinding.Severit case INFORMATIONAL: return "Info"; } - return "Info"; } @@ -77,9 +44,8 @@ protected static String convertToDefectDojoSeverity(SecureCodeBoxFinding.Severit * * @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 { + public DefectDojoImportFinding fromSecureCodeBoxFinding(SecureCodeBoxFinding secureCodeBoxFinding){ //set basic Finding info DefectDojoImportFinding result = new DefectDojoImportFinding(); result.setTitle(secureCodeBoxFinding.getName()); @@ -88,8 +54,12 @@ protected static DefectDojoImportFinding fromSecureCodeBoxFinding(SecureCodeBoxF // 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; + try { + var attributesJson = attributeJsonPrinter.writeValueAsString(secureCodeBoxFinding.getAttributes()); + description = description + "\n " + attributesJson; + } catch (JsonProcessingException e) { + LOG.warn("Could not write the secureCodeBox Finding Attributes as JSON: ",e); + } } result.setDescription(description); setFindingDate(secureCodeBoxFinding, result); @@ -97,7 +67,7 @@ protected static DefectDojoImportFinding fromSecureCodeBoxFinding(SecureCodeBoxF return result; } - private static void setFindingLocation(SecureCodeBoxFinding secureCodeBoxFinding, DefectDojoImportFinding result) { + private void setFindingLocation(SecureCodeBoxFinding secureCodeBoxFinding, DefectDojoImportFinding result) { if (secureCodeBoxFinding.getLocation() != null && !secureCodeBoxFinding.getLocation().isEmpty()) { try { URI.create(secureCodeBoxFinding.getLocation()); @@ -108,8 +78,8 @@ private static void setFindingLocation(SecureCodeBoxFinding secureCodeBoxFinding } } - private static void setFindingDate(SecureCodeBoxFinding secureCodeBoxFinding, DefectDojoImportFinding result) { - Instant instant = null; + private void setFindingDate(SecureCodeBoxFinding secureCodeBoxFinding, DefectDojoImportFinding result) { + Instant instant; if (secureCodeBoxFinding.getIdentifiedAt() != null && !secureCodeBoxFinding.getIdentifiedAt().isEmpty()) { instant = Instant.parse(secureCodeBoxFinding.getIdentifiedAt()); } else if (secureCodeBoxFinding.getParsedAt() != null && !secureCodeBoxFinding.getParsedAt().isEmpty()){ @@ -119,7 +89,7 @@ private static void setFindingDate(SecureCodeBoxFinding secureCodeBoxFinding, De instant = Instant.now(); } LocalDateTime localDateTime = LocalDateTime.ofInstant(instant, ZoneId.systemDefault()); - result.setDate(dtf.format(localDateTime)); + result.setDate(ddDateFormatter.format(localDateTime)); } private static String capitalize(String str) { diff --git a/hooks/persistence-defectdojo/hook/src/main/java/io/securecodebox/persistence/service/ScanService.java b/hooks/persistence-defectdojo/hook/src/main/java/io/securecodebox/persistence/service/ScanService.java index 3d5864d5dd..7976213097 100644 --- a/hooks/persistence-defectdojo/hook/src/main/java/io/securecodebox/persistence/service/ScanService.java +++ b/hooks/persistence-defectdojo/hook/src/main/java/io/securecodebox/persistence/service/ScanService.java @@ -1,9 +1,13 @@ package io.securecodebox.persistence.service; +import com.fasterxml.jackson.databind.DeserializationFeature; +import com.fasterxml.jackson.databind.ObjectMapper; import io.securecodebox.persistence.config.PersistenceProviderConfig; import io.securecodebox.persistence.defectdojo.models.ScanFile; import io.securecodebox.persistence.mapping.SecureCodeBoxFindingsToDefectDojoMapper; +import io.securecodebox.persistence.models.DefectDojoImportFinding; import io.securecodebox.persistence.models.Scan; +import io.securecodebox.persistence.models.SecureCodeBoxFinding; import io.securecodebox.persistence.util.ScanNameMapping; import org.apache.commons.io.FilenameUtils; import org.slf4j.Logger; @@ -11,28 +15,40 @@ import java.io.IOException; import java.net.URL; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.stream.Collectors; public class ScanService { private static final Logger LOG = LoggerFactory.getLogger(ScanService.class); + private static final ObjectMapper jsonObjectMapper = new ObjectMapper() + .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false).findAndRegisterModules(); - public static ScanFile downloadScan(Scan scan, PersistenceProviderConfig ppConfig, S3Service s3Service) throws IOException, InterruptedException { + // gets the + public static ScanFile getDefectDojoCompatibleScanResult(Scan scan, PersistenceProviderConfig ppConfig, S3Service s3Service) throws IOException, InterruptedException { String downloadUrl; - String scanResults; + String scanResult; String scanType = scan.getSpec().getScanType(); ScanNameMapping scanNameMapping = ScanNameMapping.bySecureCodeBoxScanType(scanType); if (scanNameMapping == ScanNameMapping.GENERIC) { LOG.debug("No explicit Parser specified for ScanType {}, using Findings JSON Scan Result", scanType); + var scbToDdMapper = new SecureCodeBoxFindingsToDefectDojoMapper(); downloadUrl = ppConfig.getFindingDownloadUrl(); var findingsJSON = s3Service.downloadFile(downloadUrl); - scanResults = SecureCodeBoxFindingsToDefectDojoMapper.fromSecureCodeboxFindingsJson(findingsJSON); + List secureCodeBoxFindings = Arrays.asList(jsonObjectMapper.readValue(findingsJSON, SecureCodeBoxFinding[].class)); + List defectDojoImportFindings = secureCodeBoxFindings.stream().map(scbToDdMapper::fromSecureCodeBoxFinding).collect(Collectors.toList()); + // for the generic defectDojo Parser the findings need to be wrapper in a json object called "findings" + var defectDojoFindingJson = Collections.singletonMap("findings",defectDojoImportFindings); + scanResult = jsonObjectMapper.writeValueAsString(defectDojoFindingJson); } else { LOG.debug("Explicit Parser is specified for ScanType {}, using Raw Scan Result", scanNameMapping.scanType); downloadUrl = ppConfig.getRawResultDownloadUrl(); - scanResults = s3Service.downloadFile(downloadUrl); + scanResult = s3Service.downloadFile(downloadUrl); } LOG.info("Finished Downloading Scan Result"); - LOG.debug("Scan Result: {}", scanResults); + LOG.debug("Scan Result: {}", scanResult); - return new ScanFile(scanResults, FilenameUtils.getName(new URL(downloadUrl).getPath())); + return new ScanFile(scanResult, FilenameUtils.getName(new URL(downloadUrl).getPath())); } } diff --git a/hooks/persistence-defectdojo/hook/src/test/java/io/securecodebox/persistence/mapping/SecureCodeBoxFindingsToDefectDojoMapperTest.java b/hooks/persistence-defectdojo/hook/src/test/java/io/securecodebox/persistence/mapping/SecureCodeBoxFindingsToDefectDojoMapperTest.java index a09b6e8b16..ebe56026a1 100644 --- a/hooks/persistence-defectdojo/hook/src/test/java/io/securecodebox/persistence/mapping/SecureCodeBoxFindingsToDefectDojoMapperTest.java +++ b/hooks/persistence-defectdojo/hook/src/test/java/io/securecodebox/persistence/mapping/SecureCodeBoxFindingsToDefectDojoMapperTest.java @@ -1,51 +1,26 @@ 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; +import org.json.JSONException; +import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.mockito.junit.jupiter.MockitoExtension; +import org.skyscreamer.jsonassert.JSONAssert; +import org.skyscreamer.jsonassert.JSONCompareMode; -import java.io.File; -import java.io.IOException; -import java.nio.file.Files; import java.util.HashMap; import static org.junit.jupiter.api.Assertions.*; -@ExtendWith(MockitoExtension.class) public class SecureCodeBoxFindingsToDefectDojoMapperTest { + private static SecureCodeBoxFindingsToDefectDojoMapper scbToDdMapper = new SecureCodeBoxFindingsToDefectDojoMapper(); + private static SecureCodeBoxFinding genericTestFinding; - @Test - public void yieldsCorrectResult() throws IOException { - String ddFindingsPath = "kubehunter-dd-findings.json"; - String scbFindingsPath = "kubehunter-scb-findings.json"; - ClassLoader cl = getClass().getClassLoader(); - - File ddFindingsFile = new File(cl.getResource(ddFindingsPath).getFile()); - File scbFindingsFile = new File(cl.getResource(scbFindingsPath).getFile()); - String expectedResult = new String(Files.readAllBytes(ddFindingsFile.toPath())); - String scbFindingsContent = new String(Files.readAllBytes(scbFindingsFile.toPath())); - String result = SecureCodeBoxFindingsToDefectDojoMapper.fromSecureCodeboxFindingsJson(scbFindingsContent); - ObjectMapper mapper = new ObjectMapper(); - JsonNode actualJSON = mapper.readTree(result); - JsonNode expectedJSON = mapper.readTree(expectedResult); - assertNotNull(actualJSON); - // 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); - } - - @Test - public void correctlyParsesFindings() throws IOException { + @BeforeAll + public static void init(){ var name = "Name"; var description = "Description"; - var severity = "High"; - var id = "123"; + var id = "e18cdc5e-6b49-4346-b623-28a4e878e154"; var parsedAt = "2020-04-15T12:27:28.153Z"; var location = "ldap://[2001:db8::7]/c=GB?objectClass?one"; var attributes = new HashMap(); @@ -54,21 +29,48 @@ public void correctlyParsesFindings() throws IOException { attributes.put("attribute_1", subAttribute); attributes.put("attribute_2", "2"); attributes.put("attribute_3", "3"); - var scbFinding = SecureCodeBoxFinding.builder().name(name).description(description) + genericTestFinding = SecureCodeBoxFinding.builder().name(name).description(description) .severity(SecureCodeBoxFinding.Severities.HIGH).id(id).location(location).attributes(attributes) .parsedAt(parsedAt).build(); + } - var ddFinding = SecureCodeBoxFindingsToDefectDojoMapper.fromSecureCodeBoxFinding(scbFinding); + @Test + public void correctlyParsesBasicFinding() { + var ddFinding = scbToDdMapper.fromSecureCodeBoxFinding(genericTestFinding); + assertEquals(ddFinding.getTitle(), genericTestFinding.getName()); + assertEquals(ddFinding.getUniqueIdFromTool(), genericTestFinding.getId()); + assertEquals(ddFinding.getEndpoints().get(0), genericTestFinding.getLocation()); + } - assertEquals(ddFinding.getTitle(), name); - assertEquals(ddFinding.getSeverity(), severity); - assertEquals(ddFinding.getUniqueIdFromTool(), id); - assertEquals(ddFinding.getEndpoints().get(0), location); + @Test + public void correctlyParsesSeverities(){ + var nullSeverityFinding = SecureCodeBoxFinding.builder().build(); + var infoSeverityFinding = SecureCodeBoxFinding.builder().severity(SecureCodeBoxFinding.Severities.INFORMATIONAL).build(); + var lowSeverityFinding = SecureCodeBoxFinding.builder().severity(SecureCodeBoxFinding.Severities.LOW).build(); + var mediumSeverityFinding = SecureCodeBoxFinding.builder().severity(SecureCodeBoxFinding.Severities.MEDIUM).build(); + var highSeverityFinding = SecureCodeBoxFinding.builder().severity((SecureCodeBoxFinding.Severities.HIGH)).build(); + assertEquals(scbToDdMapper.fromSecureCodeBoxFinding(nullSeverityFinding).getSeverity(),"Info"); + assertEquals(scbToDdMapper.fromSecureCodeBoxFinding(infoSeverityFinding).getSeverity(),"Info"); + assertEquals(scbToDdMapper.fromSecureCodeBoxFinding(lowSeverityFinding).getSeverity(),"Low"); + assertEquals(scbToDdMapper.fromSecureCodeBoxFinding(mediumSeverityFinding).getSeverity(),"Medium"); + assertEquals(scbToDdMapper.fromSecureCodeBoxFinding(highSeverityFinding).getSeverity(),"High"); + } + + @Test + public void correctlyParsesDate(){ + var ddFinding = scbToDdMapper.fromSecureCodeBoxFinding(genericTestFinding); assertEquals(ddFinding.getDate(), "2020-04-15"); - assertTrue(ddFinding.getDescription().startsWith(description)); + var dateTestFinding = SecureCodeBoxFinding.builder().parsedAt("2030-12-01T14:22:28Z").build(); + var dateTestResultFinding = scbToDdMapper.fromSecureCodeBoxFinding(dateTestFinding); + assertEquals(dateTestResultFinding.getDate(),"2030-12-01"); + } + @Test + public void correctlyParsesDescription() throws JSONException { + var ddFinding = scbToDdMapper.fromSecureCodeBoxFinding(genericTestFinding); + assertTrue(ddFinding.getDescription().startsWith(genericTestFinding.getDescription())); //Description should consist of description and attributes as JSON - String attributesJson = ddFinding.getDescription().substring(description.length() + 1); + String attributesJson = ddFinding.getDescription().substring(genericTestFinding.getDescription().length() + 1); String expectedAttributeJson = "{\n" + " \"attribute_1\" : {\n" + " \"sub_attribute\" : \"1\"\n" + @@ -76,18 +78,13 @@ public void correctlyParsesFindings() throws IOException { " \"attribute_2\" : \"2\",\n" + " \"attribute_3\" : \"3\"\n" + "}"; - ObjectMapper mapper = new ObjectMapper(); - var actualJson = mapper.readTree(expectedAttributeJson); - - assertNotNull(actualJson); - assertEquals(mapper.readTree(attributesJson), mapper.readTree(expectedAttributeJson)); + // We do not care how exactly the JSON looks as long as it is correct. + JSONAssert.assertEquals(expectedAttributeJson,attributesJson, JSONCompareMode.NON_EXTENSIBLE); } @Test - public void doesntThrowUnexpectedExceptionOnEmptyFinding() throws JsonProcessingException { + public void doesNotThrowUnexpectedExceptionOnEmptyFinding(){ var emptyScbFinding = SecureCodeBoxFinding.builder().build(); - var ddFinding = SecureCodeBoxFindingsToDefectDojoMapper.fromSecureCodeBoxFinding(emptyScbFinding); - assertNull(ddFinding.getTitle()); - assertNull(ddFinding.getDescription()); + assertDoesNotThrow(() -> scbToDdMapper.fromSecureCodeBoxFinding(emptyScbFinding)); } } diff --git a/hooks/persistence-defectdojo/hook/src/test/java/io/securecodebox/persistence/service/ScanServiceTest.java b/hooks/persistence-defectdojo/hook/src/test/java/io/securecodebox/persistence/service/ScanServiceTest.java new file mode 100644 index 0000000000..5e283b55a1 --- /dev/null +++ b/hooks/persistence-defectdojo/hook/src/test/java/io/securecodebox/persistence/service/ScanServiceTest.java @@ -0,0 +1,98 @@ +package io.securecodebox.persistence.service; + +import io.securecodebox.models.V1ScanSpec; +import io.securecodebox.persistence.config.PersistenceProviderConfig; +import io.securecodebox.persistence.defectdojo.models.ScanFile; +import io.securecodebox.persistence.models.Scan; +import org.apache.log4j.LogMF; +import org.json.JSONException; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.Mock; +import org.mockito.Mockito; +import org.mockito.junit.jupiter.MockitoExtension; +import org.skyscreamer.jsonassert.JSONAssert; +import org.skyscreamer.jsonassert.JSONCompareMode; + +import java.io.File; +import java.io.IOException; +import java.net.URISyntaxException; +import java.nio.file.Files; + +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.Mockito.when; +import static org.junit.jupiter.api.Assertions.*; + +@ExtendWith(MockitoExtension.class) +public class ScanServiceTest { + @Mock + S3Service s3Service; + @Mock + PersistenceProviderConfig ppConfig; + @Mock + Scan scan; + + private static String expectedDdFindingsString; + private static String givenScbFindingsString; + private static String rawNiktoScanString; + + @BeforeAll + public static void init() throws IOException{ + expectedDdFindingsString = readResourceAsString("kubehunter-dd-findings.json"); + assertNotNull(expectedDdFindingsString); + assertNotEquals(expectedDdFindingsString,""); + givenScbFindingsString = readResourceAsString("kubehunter-scb-findings.json"); + assertNotNull(givenScbFindingsString); + assertNotEquals(givenScbFindingsString,""); + rawNiktoScanString = readResourceAsString("nikto-raw-result.json"); + } + + /*** + * When a unknown scanner is encountered the findings json has to be converted into defectdojo compatible json and + * the correct file ending must be used so DefectDojo can choose the right parser (usually xml or json) + * @throws IOException + * @throws InterruptedException + * @throws JSONException + */ + @Test + public void correctlyParsesGenericResults() throws IOException, InterruptedException, JSONException { + String findingsUrl = "https://foo.com/findings.json"; + when(ppConfig.getFindingDownloadUrl()).thenReturn(findingsUrl); + when(s3Service.downloadFile(findingsUrl)).thenReturn(givenScbFindingsString); + V1ScanSpec scanSpec = new V1ScanSpec(); + scanSpec.setScanType("some-unknown-scanner-type"); + when(scan.getSpec()).thenReturn(scanSpec); + ScanFile result = ScanService.getDefectDojoCompatibleScanResult(scan,ppConfig,s3Service); + JSONAssert.assertEquals(expectedDdFindingsString,result.getContent(), JSONCompareMode.NON_EXTENSIBLE); + assertTrue(result.getName().endsWith(".json")); + } + + /*** + * When a known scanner like nikto is encountered the raw result must be passed and the correct file ending must + * be used so DefectDojo can choose the right parser (usually xml or json) + * @throws IOException + * @throws InterruptedException + */ + @Test + public void correctlyReturnsScannerSpecificResults() throws IOException, InterruptedException { + String rawResultDownloadUrl = "https://foo.com/nikto-raw-results.json"; + when(ppConfig.getRawResultDownloadUrl()).thenReturn(rawResultDownloadUrl); + V1ScanSpec scanSpec = new V1ScanSpec(); + scanSpec.setScanType("nikto"); + when(scan.getSpec()).thenReturn(scanSpec); + when(s3Service.downloadFile(rawResultDownloadUrl)).thenReturn(rawNiktoScanString); + ScanFile result = ScanService.getDefectDojoCompatibleScanResult(scan,ppConfig,s3Service); + assertEquals(rawNiktoScanString,result.getContent()); + assertTrue(result.getName().endsWith(".json")); + } + + public static String readResourceAsString(String resourceName) throws IOException { + ClassLoader cl = ScanServiceTest.class.getClassLoader(); + File resourceFile = new File(cl.getResource(resourceName).getFile()); + return Files.readString(resourceFile.toPath()); + } + + +} diff --git a/hooks/persistence-defectdojo/hook/src/test/resources/nikto-raw-result.json b/hooks/persistence-defectdojo/hook/src/test/resources/nikto-raw-result.json new file mode 100644 index 0000000000..f59e30704f --- /dev/null +++ b/hooks/persistence-defectdojo/hook/src/test/resources/nikto-raw-result.json @@ -0,0 +1,715 @@ +{ + "host": "juice-shop", + "ip": "10.101.101.50", + "port": "3000", + "banner": "", + "vulnerabilities": [ + { + "id": "999986", + "OSVDB": "0", + "method": "GET", + "url": "/", + "msg": "Retrieved access-control-allow-origin header: *" + }, + { + "id": "999997", + "OSVDB": "0", + "method": "GET", + "url": "/ftp/", + "msg": "Entry '/ftp/' in robots.txt returned a non-forbidden or redirect HTTP code (200)" + }, + { + "id": "999996", + "OSVDB": "0", + "method": "GET", + "url": "/robots.txt", + "msg": "\"robots.txt\" contains 1 entry which should be manually viewed." + }, + { + "id": "740001", + "OSVDB": "0", + "method": "HEAD", + "url": "/site.alz", + "msg": "Potentially interesting backup/cert file found. " + }, + { + "id": "740001", + "OSVDB": "0", + "method": "HEAD", + "url": "/site.pem", + "msg": "Potentially interesting backup/cert file found. " + }, + { + "id": "740001", + "OSVDB": "0", + "method": "HEAD", + "url": "/archive.tar.gz", + "msg": "Potentially interesting backup/cert file found. " + }, + { + "id": "740001", + "OSVDB": "0", + "method": "HEAD", + "url": "/juice-shop.sql", + "msg": "Potentially interesting backup/cert file found. " + }, + { + "id": "740001", + "OSVDB": "0", + "method": "HEAD", + "url": "/database.tgz", + "msg": "Potentially interesting backup/cert file found. " + }, + { + "id": "740001", + "OSVDB": "0", + "method": "HEAD", + "url": "/10.101.101.50.tar.bz2", + "msg": "Potentially interesting backup/cert file found. " + }, + { + "id": "740001", + "OSVDB": "0", + "method": "HEAD", + "url": "/10.101.101.50.pem", + "msg": "Potentially interesting backup/cert file found. " + }, + { + "id": "740001", + "OSVDB": "0", + "method": "HEAD", + "url": "/archive.war", + "msg": "Potentially interesting backup/cert file found. " + }, + { + "id": "740001", + "OSVDB": "0", + "method": "HEAD", + "url": "/juice-shop.war", + "msg": "Potentially interesting backup/cert file found. " + }, + { + "id": "740001", + "OSVDB": "0", + "method": "HEAD", + "url": "/database.jks", + "msg": "Potentially interesting backup/cert file found. " + }, + { + "id": "740001", + "OSVDB": "0", + "method": "HEAD", + "url": "/10.101.101.50.war", + "msg": "Potentially interesting backup/cert file found. " + }, + { + "id": "740001", + "OSVDB": "0", + "method": "HEAD", + "url": "/database.tar", + "msg": "Potentially interesting backup/cert file found. " + }, + { + "id": "740001", + "OSVDB": "0", + "method": "HEAD", + "url": "/dump.alz", + "msg": "Potentially interesting backup/cert file found. " + }, + { + "id": "740001", + "OSVDB": "0", + "method": "HEAD", + "url": "/juice-shop.pem", + "msg": "Potentially interesting backup/cert file found. " + }, + { + "id": "740001", + "OSVDB": "0", + "method": "HEAD", + "url": "/dump.pem", + "msg": "Potentially interesting backup/cert file found. " + }, + { + "id": "740001", + "OSVDB": "0", + "method": "HEAD", + "url": "/10.101.101.50.tgz", + "msg": "Potentially interesting backup/cert file found. " + }, + { + "id": "740001", + "OSVDB": "0", + "method": "HEAD", + "url": "/archive.cer", + "msg": "Potentially interesting backup/cert file found. " + }, + { + "id": "740001", + "OSVDB": "0", + "method": "HEAD", + "url": "/site.tar.bz2", + "msg": "Potentially interesting backup/cert file found. " + }, + { + "id": "740001", + "OSVDB": "0", + "method": "HEAD", + "url": "/dump.war", + "msg": "Potentially interesting backup/cert file found. " + }, + { + "id": "740001", + "OSVDB": "0", + "method": "HEAD", + "url": "/database.alz", + "msg": "Potentially interesting backup/cert file found. " + }, + { + "id": "740001", + "OSVDB": "0", + "method": "HEAD", + "url": "/juice-shop.tar.gz", + "msg": "Potentially interesting backup/cert file found. " + }, + { + "id": "740001", + "OSVDB": "0", + "method": "HEAD", + "url": "/backup.tar.bz2", + "msg": "Potentially interesting backup/cert file found. " + }, + { + "id": "740001", + "OSVDB": "0", + "method": "HEAD", + "url": "/juice-shop.tgz", + "msg": "Potentially interesting backup/cert file found. " + }, + { + "id": "740001", + "OSVDB": "0", + "method": "HEAD", + "url": "/10.101.101.50.jks", + "msg": "Potentially interesting backup/cert file found. " + }, + { + "id": "740001", + "OSVDB": "0", + "method": "HEAD", + "url": "/backup.tar", + "msg": "Potentially interesting backup/cert file found. " + }, + { + "id": "740001", + "OSVDB": "0", + "method": "HEAD", + "url": "/backup.cer", + "msg": "Potentially interesting backup/cert file found. " + }, + { + "id": "740001", + "OSVDB": "0", + "method": "HEAD", + "url": "/site.tar.lzma", + "msg": "Potentially interesting backup/cert file found. " + }, + { + "id": "740001", + "OSVDB": "0", + "method": "HEAD", + "url": "/backup.war", + "msg": "Potentially interesting backup/cert file found. " + }, + { + "id": "740001", + "OSVDB": "0", + "method": "HEAD", + "url": "/10.101.101.50.tar.lzma", + "msg": "Potentially interesting backup/cert file found. " + }, + { + "id": "740001", + "OSVDB": "0", + "method": "HEAD", + "url": "/database.pem", + "msg": "Potentially interesting backup/cert file found. " + }, + { + "id": "740001", + "OSVDB": "0", + "method": "HEAD", + "url": "/dump.tgz", + "msg": "Potentially interesting backup/cert file found. " + }, + { + "id": "740001", + "OSVDB": "0", + "method": "HEAD", + "url": "/dump.sql", + "msg": "Potentially interesting backup/cert file found. " + }, + { + "id": "740001", + "OSVDB": "0", + "method": "HEAD", + "url": "/dump.tar.lzma", + "msg": "Potentially interesting backup/cert file found. " + }, + { + "id": "740001", + "OSVDB": "0", + "method": "HEAD", + "url": "/backup.tar.gz", + "msg": "Potentially interesting backup/cert file found. " + }, + { + "id": "740001", + "OSVDB": "0", + "method": "HEAD", + "url": "/backup.gz", + "msg": "Potentially interesting backup/cert file found. " + }, + { + "id": "740001", + "OSVDB": "0", + "method": "HEAD", + "url": "/juice-shop.jks", + "msg": "Potentially interesting backup/cert file found. " + }, + { + "id": "740001", + "OSVDB": "0", + "method": "HEAD", + "url": "/site.tgz", + "msg": "Potentially interesting backup/cert file found. " + }, + { + "id": "740001", + "OSVDB": "0", + "method": "HEAD", + "url": "/database.cer", + "msg": "Potentially interesting backup/cert file found. " + }, + { + "id": "740001", + "OSVDB": "0", + "method": "HEAD", + "url": "/site.sql", + "msg": "Potentially interesting backup/cert file found. " + }, + { + "id": "740001", + "OSVDB": "0", + "method": "HEAD", + "url": "/archive.tgz", + "msg": "Potentially interesting backup/cert file found. " + }, + { + "id": "740001", + "OSVDB": "0", + "method": "HEAD", + "url": "/backup.jks", + "msg": "Potentially interesting backup/cert file found. " + }, + { + "id": "740001", + "OSVDB": "0", + "method": "HEAD", + "url": "/database.zip", + "msg": "Potentially interesting backup/cert file found. " + }, + { + "id": "740001", + "OSVDB": "0", + "method": "HEAD", + "url": "/juice-shop.tar", + "msg": "Potentially interesting backup/cert file found. " + }, + { + "id": "740001", + "OSVDB": "0", + "method": "HEAD", + "url": "/dump.tar.bz2", + "msg": "Potentially interesting backup/cert file found. " + }, + { + "id": "740001", + "OSVDB": "0", + "method": "HEAD", + "url": "/database.tar.bz2", + "msg": "Potentially interesting backup/cert file found. " + }, + { + "id": "740001", + "OSVDB": "0", + "method": "HEAD", + "url": "/site.war", + "msg": "Potentially interesting backup/cert file found. " + }, + { + "id": "740001", + "OSVDB": "0", + "method": "HEAD", + "url": "/10.101.101.50.egg", + "msg": "Potentially interesting backup/cert file found. " + }, + { + "id": "740001", + "OSVDB": "0", + "method": "HEAD", + "url": "/site.gz", + "msg": "Potentially interesting backup/cert file found. " + }, + { + "id": "740001", + "OSVDB": "0", + "method": "HEAD", + "url": "/database.tar.lzma", + "msg": "Potentially interesting backup/cert file found. " + }, + { + "id": "740001", + "OSVDB": "0", + "method": "HEAD", + "url": "/juice-shop.tar.lzma", + "msg": "Potentially interesting backup/cert file found. " + }, + { + "id": "740001", + "OSVDB": "0", + "method": "HEAD", + "url": "/10.101.101.50.sql", + "msg": "Potentially interesting backup/cert file found. " + }, + { + "id": "740001", + "OSVDB": "0", + "method": "HEAD", + "url": "/backup.zip", + "msg": "Potentially interesting backup/cert file found. " + }, + { + "id": "740001", + "OSVDB": "0", + "method": "HEAD", + "url": "/database.egg", + "msg": "Potentially interesting backup/cert file found. " + }, + { + "id": "740001", + "OSVDB": "0", + "method": "HEAD", + "url": "/site.cer", + "msg": "Potentially interesting backup/cert file found. " + }, + { + "id": "740001", + "OSVDB": "0", + "method": "HEAD", + "url": "/archive.jks", + "msg": "Potentially interesting backup/cert file found. " + }, + { + "id": "740001", + "OSVDB": "0", + "method": "HEAD", + "url": "/juice-shop.alz", + "msg": "Potentially interesting backup/cert file found. " + }, + { + "id": "740001", + "OSVDB": "0", + "method": "HEAD", + "url": "/dump.tar.gz", + "msg": "Potentially interesting backup/cert file found. " + }, + { + "id": "740001", + "OSVDB": "0", + "method": "HEAD", + "url": "/backup.pem", + "msg": "Potentially interesting backup/cert file found. " + }, + { + "id": "740001", + "OSVDB": "0", + "method": "HEAD", + "url": "/archive.zip", + "msg": "Potentially interesting backup/cert file found. " + }, + { + "id": "740001", + "OSVDB": "0", + "method": "HEAD", + "url": "/site.egg", + "msg": "Potentially interesting backup/cert file found. " + }, + { + "id": "740001", + "OSVDB": "0", + "method": "HEAD", + "url": "/archive.tar", + "msg": "Potentially interesting backup/cert file found. " + }, + { + "id": "740001", + "OSVDB": "0", + "method": "HEAD", + "url": "/10.101.101.50.zip", + "msg": "Potentially interesting backup/cert file found. " + }, + { + "id": "740001", + "OSVDB": "0", + "method": "HEAD", + "url": "/site.tar.gz", + "msg": "Potentially interesting backup/cert file found. " + }, + { + "id": "740001", + "OSVDB": "0", + "method": "HEAD", + "url": "/archive.egg", + "msg": "Potentially interesting backup/cert file found. " + }, + { + "id": "740001", + "OSVDB": "0", + "method": "HEAD", + "url": "/juice-shop.cer", + "msg": "Potentially interesting backup/cert file found. " + }, + { + "id": "740001", + "OSVDB": "0", + "method": "HEAD", + "url": "/10.101.101.50.tar.gz", + "msg": "Potentially interesting backup/cert file found. " + }, + { + "id": "740001", + "OSVDB": "0", + "method": "HEAD", + "url": "/dump.egg", + "msg": "Potentially interesting backup/cert file found. " + }, + { + "id": "740001", + "OSVDB": "0", + "method": "HEAD", + "url": "/backup.tgz", + "msg": "Potentially interesting backup/cert file found. " + }, + { + "id": "740001", + "OSVDB": "0", + "method": "HEAD", + "url": "/archive.tar.lzma", + "msg": "Potentially interesting backup/cert file found. " + }, + { + "id": "740001", + "OSVDB": "0", + "method": "HEAD", + "url": "/dump.gz", + "msg": "Potentially interesting backup/cert file found. " + }, + { + "id": "740001", + "OSVDB": "0", + "method": "HEAD", + "url": "/juice-shop.tar.bz2", + "msg": "Potentially interesting backup/cert file found. " + }, + { + "id": "740001", + "OSVDB": "0", + "method": "HEAD", + "url": "/backup.alz", + "msg": "Potentially interesting backup/cert file found. " + }, + { + "id": "740001", + "OSVDB": "0", + "method": "HEAD", + "url": "/juice-shop.zip", + "msg": "Potentially interesting backup/cert file found. " + }, + { + "id": "740001", + "OSVDB": "0", + "method": "HEAD", + "url": "/dump.cer", + "msg": "Potentially interesting backup/cert file found. " + }, + { + "id": "740001", + "OSVDB": "0", + "method": "HEAD", + "url": "/database.tar.gz", + "msg": "Potentially interesting backup/cert file found. " + }, + { + "id": "740001", + "OSVDB": "0", + "method": "HEAD", + "url": "/site.zip", + "msg": "Potentially interesting backup/cert file found. " + }, + { + "id": "740001", + "OSVDB": "0", + "method": "HEAD", + "url": "/database.war", + "msg": "Potentially interesting backup/cert file found. " + }, + { + "id": "740001", + "OSVDB": "0", + "method": "HEAD", + "url": "/archive.alz", + "msg": "Potentially interesting backup/cert file found. " + }, + { + "id": "740001", + "OSVDB": "0", + "method": "HEAD", + "url": "/backup.egg", + "msg": "Potentially interesting backup/cert file found. " + }, + { + "id": "740001", + "OSVDB": "0", + "method": "HEAD", + "url": "/database.gz", + "msg": "Potentially interesting backup/cert file found. " + }, + { + "id": "740001", + "OSVDB": "0", + "method": "HEAD", + "url": "/juice-shop.gz", + "msg": "Potentially interesting backup/cert file found. " + }, + { + "id": "740001", + "OSVDB": "0", + "method": "HEAD", + "url": "/dump.jks", + "msg": "Potentially interesting backup/cert file found. " + }, + { + "id": "740001", + "OSVDB": "0", + "method": "HEAD", + "url": "/archive.pem", + "msg": "Potentially interesting backup/cert file found. " + }, + { + "id": "740001", + "OSVDB": "0", + "method": "HEAD", + "url": "/dump.tar", + "msg": "Potentially interesting backup/cert file found. " + }, + { + "id": "740001", + "OSVDB": "0", + "method": "HEAD", + "url": "/backup.sql", + "msg": "Potentially interesting backup/cert file found. " + }, + { + "id": "740001", + "OSVDB": "0", + "method": "HEAD", + "url": "/10.101.101.50.cer", + "msg": "Potentially interesting backup/cert file found. " + }, + { + "id": "740001", + "OSVDB": "0", + "method": "HEAD", + "url": "/site.jks", + "msg": "Potentially interesting backup/cert file found. " + }, + { + "id": "740001", + "OSVDB": "0", + "method": "HEAD", + "url": "/archive.gz", + "msg": "Potentially interesting backup/cert file found. " + }, + { + "id": "740001", + "OSVDB": "0", + "method": "HEAD", + "url": "/backup.tar.lzma", + "msg": "Potentially interesting backup/cert file found. " + }, + { + "id": "740001", + "OSVDB": "0", + "method": "HEAD", + "url": "/10.101.101.50.gz", + "msg": "Potentially interesting backup/cert file found. " + }, + { + "id": "740001", + "OSVDB": "0", + "method": "HEAD", + "url": "/site.tar", + "msg": "Potentially interesting backup/cert file found. " + }, + { + "id": "740001", + "OSVDB": "0", + "method": "HEAD", + "url": "/database.sql", + "msg": "Potentially interesting backup/cert file found. " + }, + { + "id": "740001", + "OSVDB": "0", + "method": "HEAD", + "url": "/archive.tar.bz2", + "msg": "Potentially interesting backup/cert file found. " + }, + { + "id": "740001", + "OSVDB": "0", + "method": "HEAD", + "url": "/dump.zip", + "msg": "Potentially interesting backup/cert file found. " + }, + { + "id": "740001", + "OSVDB": "0", + "method": "HEAD", + "url": "/archive.sql", + "msg": "Potentially interesting backup/cert file found. " + }, + { + "id": "740001", + "OSVDB": "0", + "method": "HEAD", + "url": "/10.101.101.50.alz", + "msg": "Potentially interesting backup/cert file found. " + }, + { + "id": "740001", + "OSVDB": "0", + "method": "HEAD", + "url": "/10.101.101.50.tar", + "msg": "Potentially interesting backup/cert file found. " + }, + { + "id": "740001", + "OSVDB": "0", + "method": "HEAD", + "url": "/juice-shop.egg", + "msg": "Potentially interesting backup/cert file found. " + } + ] +} From e918d3d2ebc847b3ccb14f9cef518181b68d71b3 Mon Sep 17 00:00:00 2001 From: Johannes Zahn Date: Wed, 18 Aug 2021 17:23:06 +0200 Subject: [PATCH 2/8] add timezone independece, introduce ScanResult factory Signed-off-by: Johannes Zahn --- .../DefectDojoPersistenceProvider.java | 4 +- .../config/PersistenceProviderConfig.java | 7 +++ ...cureCodeBoxFindingsToDefectDojoMapper.java | 9 +++- .../persistence/service/ScanService.java | 54 ------------------- .../scan/GenericParserScanResultService.java | 42 +++++++++++++++ .../service/scan/ScanResultService.java | 31 +++++++++++ .../scan/SpecificParserScanResultService.java | 24 +++++++++ ...CodeBoxFindingsToDefectDojoMapperTest.java | 25 +++++++-- .../persistence/service/ScanServiceTest.java | 29 +++++----- 9 files changed, 148 insertions(+), 77 deletions(-) delete mode 100644 hooks/persistence-defectdojo/hook/src/main/java/io/securecodebox/persistence/service/ScanService.java create mode 100644 hooks/persistence-defectdojo/hook/src/main/java/io/securecodebox/persistence/service/scan/GenericParserScanResultService.java create mode 100644 hooks/persistence-defectdojo/hook/src/main/java/io/securecodebox/persistence/service/scan/ScanResultService.java create mode 100644 hooks/persistence-defectdojo/hook/src/main/java/io/securecodebox/persistence/service/scan/SpecificParserScanResultService.java diff --git a/hooks/persistence-defectdojo/hook/src/main/java/io/securecodebox/persistence/DefectDojoPersistenceProvider.java b/hooks/persistence-defectdojo/hook/src/main/java/io/securecodebox/persistence/DefectDojoPersistenceProvider.java index 2d7dbb2606..1db62c7f75 100644 --- a/hooks/persistence-defectdojo/hook/src/main/java/io/securecodebox/persistence/DefectDojoPersistenceProvider.java +++ b/hooks/persistence-defectdojo/hook/src/main/java/io/securecodebox/persistence/DefectDojoPersistenceProvider.java @@ -8,7 +8,7 @@ import io.securecodebox.persistence.defectdojo.service.EndpointService; import io.securecodebox.persistence.mapping.DefectDojoFindingToSecureCodeBoxMapper; import io.securecodebox.persistence.models.Scan; -import io.securecodebox.persistence.service.ScanService; +import io.securecodebox.persistence.service.scan.ScanResultService; import io.securecodebox.persistence.service.KubernetesService; import io.securecodebox.persistence.service.S3Service; import io.securecodebox.persistence.strategies.VersionedEngagementsStrategy; @@ -33,7 +33,7 @@ public static void main(String[] args) throws Exception { scan.validate(); LOG.info("Downloading Scan Result"); - var scanResultFile = ScanService.getDefectDojoCompatibleScanResult(scan, persistenceProviderConfig, s3Service); + var scanResultFile = ScanResultService.build(scan, s3Service).getScanResult(persistenceProviderConfig); var config = DefectDojoConfig.fromEnv(); LOG.info("Uploading Findings to DefectDojo at: {}", config.getUrl()); diff --git a/hooks/persistence-defectdojo/hook/src/main/java/io/securecodebox/persistence/config/PersistenceProviderConfig.java b/hooks/persistence-defectdojo/hook/src/main/java/io/securecodebox/persistence/config/PersistenceProviderConfig.java index 96e891c06e..72e26c7b55 100644 --- a/hooks/persistence-defectdojo/hook/src/main/java/io/securecodebox/persistence/config/PersistenceProviderConfig.java +++ b/hooks/persistence-defectdojo/hook/src/main/java/io/securecodebox/persistence/config/PersistenceProviderConfig.java @@ -8,6 +8,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import java.time.ZoneId; import java.util.List; /** @@ -23,6 +24,12 @@ public class PersistenceProviderConfig { final int RAW_RESULT_UPLOAD_ARG_POSITION = 2; final int FINDING_UPLOAD_ARG_POSITION = 3; + // DefectDojo does in contrast to secureCodeBox not pay attention to time zones + // to guarantee consistent results when converting back and forth a time zone + // has to be assumed for DefectDojo. It defaults to the Time Zone of the system clock + @Getter + ZoneId defectDojoTimezoneId = ZoneId.systemDefault(); + // Download Urls @Getter final String rawResultDownloadUrl; diff --git a/hooks/persistence-defectdojo/hook/src/main/java/io/securecodebox/persistence/mapping/SecureCodeBoxFindingsToDefectDojoMapper.java b/hooks/persistence-defectdojo/hook/src/main/java/io/securecodebox/persistence/mapping/SecureCodeBoxFindingsToDefectDojoMapper.java index 0c104dd0c4..7d859be248 100644 --- a/hooks/persistence-defectdojo/hook/src/main/java/io/securecodebox/persistence/mapping/SecureCodeBoxFindingsToDefectDojoMapper.java +++ b/hooks/persistence-defectdojo/hook/src/main/java/io/securecodebox/persistence/mapping/SecureCodeBoxFindingsToDefectDojoMapper.java @@ -3,6 +3,7 @@ import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.ObjectWriter; +import io.securecodebox.persistence.config.PersistenceProviderConfig; import io.securecodebox.persistence.models.DefectDojoImportFinding; import io.securecodebox.persistence.models.SecureCodeBoxFinding; import io.securecodebox.persistence.service.KubernetesService; @@ -12,7 +13,6 @@ import java.net.URI; import java.time.Instant; import java.time.LocalDateTime; -import java.time.ZoneId; import java.time.format.DateTimeFormatter; import java.util.Collections; @@ -20,6 +20,11 @@ public class SecureCodeBoxFindingsToDefectDojoMapper { private static final Logger LOG = LoggerFactory.getLogger(KubernetesService.class); private final DateTimeFormatter ddDateFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd"); private final ObjectWriter attributeJsonPrinter = new ObjectMapper().writerWithDefaultPrettyPrinter(); + private PersistenceProviderConfig ppConfig; + + public SecureCodeBoxFindingsToDefectDojoMapper(PersistenceProviderConfig ppConfig){ + this.ppConfig= ppConfig; + } protected String convertToDefectDojoSeverity(SecureCodeBoxFinding.Severities severity) { if (severity == null) { @@ -88,7 +93,7 @@ private void setFindingDate(SecureCodeBoxFinding secureCodeBoxFinding, DefectDoj else { instant = Instant.now(); } - LocalDateTime localDateTime = LocalDateTime.ofInstant(instant, ZoneId.systemDefault()); + LocalDateTime localDateTime = LocalDateTime.ofInstant(instant, ppConfig.getDefectDojoTimezoneId()); result.setDate(ddDateFormatter.format(localDateTime)); } diff --git a/hooks/persistence-defectdojo/hook/src/main/java/io/securecodebox/persistence/service/ScanService.java b/hooks/persistence-defectdojo/hook/src/main/java/io/securecodebox/persistence/service/ScanService.java deleted file mode 100644 index 7976213097..0000000000 --- a/hooks/persistence-defectdojo/hook/src/main/java/io/securecodebox/persistence/service/ScanService.java +++ /dev/null @@ -1,54 +0,0 @@ -package io.securecodebox.persistence.service; - -import com.fasterxml.jackson.databind.DeserializationFeature; -import com.fasterxml.jackson.databind.ObjectMapper; -import io.securecodebox.persistence.config.PersistenceProviderConfig; -import io.securecodebox.persistence.defectdojo.models.ScanFile; -import io.securecodebox.persistence.mapping.SecureCodeBoxFindingsToDefectDojoMapper; -import io.securecodebox.persistence.models.DefectDojoImportFinding; -import io.securecodebox.persistence.models.Scan; -import io.securecodebox.persistence.models.SecureCodeBoxFinding; -import io.securecodebox.persistence.util.ScanNameMapping; -import org.apache.commons.io.FilenameUtils; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.io.IOException; -import java.net.URL; -import java.util.Arrays; -import java.util.Collections; -import java.util.List; -import java.util.stream.Collectors; - -public class ScanService { - private static final Logger LOG = LoggerFactory.getLogger(ScanService.class); - private static final ObjectMapper jsonObjectMapper = new ObjectMapper() - .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false).findAndRegisterModules(); - - // gets the - public static ScanFile getDefectDojoCompatibleScanResult(Scan scan, PersistenceProviderConfig ppConfig, S3Service s3Service) throws IOException, InterruptedException { - String downloadUrl; - String scanResult; - String scanType = scan.getSpec().getScanType(); - ScanNameMapping scanNameMapping = ScanNameMapping.bySecureCodeBoxScanType(scanType); - if (scanNameMapping == ScanNameMapping.GENERIC) { - LOG.debug("No explicit Parser specified for ScanType {}, using Findings JSON Scan Result", scanType); - var scbToDdMapper = new SecureCodeBoxFindingsToDefectDojoMapper(); - downloadUrl = ppConfig.getFindingDownloadUrl(); - var findingsJSON = s3Service.downloadFile(downloadUrl); - List secureCodeBoxFindings = Arrays.asList(jsonObjectMapper.readValue(findingsJSON, SecureCodeBoxFinding[].class)); - List defectDojoImportFindings = secureCodeBoxFindings.stream().map(scbToDdMapper::fromSecureCodeBoxFinding).collect(Collectors.toList()); - // for the generic defectDojo Parser the findings need to be wrapper in a json object called "findings" - var defectDojoFindingJson = Collections.singletonMap("findings",defectDojoImportFindings); - scanResult = jsonObjectMapper.writeValueAsString(defectDojoFindingJson); - } else { - LOG.debug("Explicit Parser is specified for ScanType {}, using Raw Scan Result", scanNameMapping.scanType); - downloadUrl = ppConfig.getRawResultDownloadUrl(); - scanResult = s3Service.downloadFile(downloadUrl); - } - LOG.info("Finished Downloading Scan Result"); - LOG.debug("Scan Result: {}", scanResult); - - return new ScanFile(scanResult, FilenameUtils.getName(new URL(downloadUrl).getPath())); - } -} diff --git a/hooks/persistence-defectdojo/hook/src/main/java/io/securecodebox/persistence/service/scan/GenericParserScanResultService.java b/hooks/persistence-defectdojo/hook/src/main/java/io/securecodebox/persistence/service/scan/GenericParserScanResultService.java new file mode 100644 index 0000000000..67b04a3f88 --- /dev/null +++ b/hooks/persistence-defectdojo/hook/src/main/java/io/securecodebox/persistence/service/scan/GenericParserScanResultService.java @@ -0,0 +1,42 @@ +package io.securecodebox.persistence.service.scan; + +import com.fasterxml.jackson.databind.DeserializationFeature; +import com.fasterxml.jackson.databind.ObjectMapper; +import io.securecodebox.persistence.config.PersistenceProviderConfig; +import io.securecodebox.persistence.defectdojo.models.ScanFile; +import io.securecodebox.persistence.mapping.SecureCodeBoxFindingsToDefectDojoMapper; +import io.securecodebox.persistence.models.DefectDojoImportFinding; +import io.securecodebox.persistence.models.SecureCodeBoxFinding; +import io.securecodebox.persistence.service.S3Service; +import org.apache.commons.io.FilenameUtils; + +import java.io.IOException; +import java.net.URL; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.stream.Collectors; + +public class GenericParserScanResultService extends ScanResultService { + + private static final ObjectMapper jsonObjectMapper = new ObjectMapper() + .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false).findAndRegisterModules(); + + public GenericParserScanResultService(S3Service s3Service) { + super(s3Service); + } + + @Override + public ScanFile getScanResult(PersistenceProviderConfig ppConfig) throws IOException, InterruptedException { + LOG.debug("No explicit Parser specified using Findings JSON Scan Result"); + var scbToDdMapper = new SecureCodeBoxFindingsToDefectDojoMapper(ppConfig); + var downloadUrl = ppConfig.getFindingDownloadUrl(); + var findingsJSON = s3Service.downloadFile(downloadUrl); + List secureCodeBoxFindings = Arrays.asList(jsonObjectMapper.readValue(findingsJSON, SecureCodeBoxFinding[].class)); + List defectDojoImportFindings = secureCodeBoxFindings.stream().map(scbToDdMapper::fromSecureCodeBoxFinding).collect(Collectors.toList()); + // for the generic defectDojo Parser the findings need to be wrapper in a json object called "findings" + var defectDojoFindingJson = Collections.singletonMap("findings",defectDojoImportFindings); + var scanResult = jsonObjectMapper.writeValueAsString(defectDojoFindingJson); + return new ScanFile(scanResult, FilenameUtils.getName(new URL(downloadUrl).getPath())); + } +} diff --git a/hooks/persistence-defectdojo/hook/src/main/java/io/securecodebox/persistence/service/scan/ScanResultService.java b/hooks/persistence-defectdojo/hook/src/main/java/io/securecodebox/persistence/service/scan/ScanResultService.java new file mode 100644 index 0000000000..555ca66250 --- /dev/null +++ b/hooks/persistence-defectdojo/hook/src/main/java/io/securecodebox/persistence/service/scan/ScanResultService.java @@ -0,0 +1,31 @@ +package io.securecodebox.persistence.service.scan; + +import io.securecodebox.persistence.config.PersistenceProviderConfig; +import io.securecodebox.persistence.defectdojo.models.ScanFile; +import io.securecodebox.persistence.models.Scan; +import io.securecodebox.persistence.service.S3Service; +import io.securecodebox.persistence.util.ScanNameMapping; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.IOException; + +/** + * Enables fetching Scan Results for uploading to DefectDojo depending on the Scan (especially it's type) + */ +public abstract class ScanResultService { + protected static final Logger LOG = LoggerFactory.getLogger(ScanResultService.class); + protected S3Service s3Service; + protected ScanResultService(S3Service s3Service) { + this.s3Service = s3Service; + } + + public static ScanResultService build(Scan scan, S3Service s3Service){ + ScanNameMapping scanNameMapping = ScanNameMapping.bySecureCodeBoxScanType(scan.getSpec().getScanType()); + if (scanNameMapping.equals(ScanNameMapping.GENERIC)) + return new GenericParserScanResultService(s3Service); + else return new SpecificParserScanResultService(s3Service); + } + + public abstract ScanFile getScanResult(PersistenceProviderConfig ppConfig) throws IOException, InterruptedException; +} diff --git a/hooks/persistence-defectdojo/hook/src/main/java/io/securecodebox/persistence/service/scan/SpecificParserScanResultService.java b/hooks/persistence-defectdojo/hook/src/main/java/io/securecodebox/persistence/service/scan/SpecificParserScanResultService.java new file mode 100644 index 0000000000..caf1570778 --- /dev/null +++ b/hooks/persistence-defectdojo/hook/src/main/java/io/securecodebox/persistence/service/scan/SpecificParserScanResultService.java @@ -0,0 +1,24 @@ +package io.securecodebox.persistence.service.scan; + +import io.securecodebox.persistence.config.PersistenceProviderConfig; +import io.securecodebox.persistence.defectdojo.models.ScanFile; +import io.securecodebox.persistence.service.S3Service; +import org.apache.commons.io.FilenameUtils; + +import java.io.IOException; +import java.net.URL; + +public class SpecificParserScanResultService extends ScanResultService { + + public SpecificParserScanResultService(S3Service s3Service) { + super(s3Service); + } + + @Override + public ScanFile getScanResult(PersistenceProviderConfig ppConfig) throws IOException, InterruptedException { + LOG.debug("Explicit Parser is specified, using Raw Scan Result"); + var downloadUrl = ppConfig.getRawResultDownloadUrl(); + var scanResult = s3Service.downloadFile(downloadUrl); + return new ScanFile(scanResult, FilenameUtils.getName(new URL(downloadUrl).getPath())); + } +} diff --git a/hooks/persistence-defectdojo/hook/src/test/java/io/securecodebox/persistence/mapping/SecureCodeBoxFindingsToDefectDojoMapperTest.java b/hooks/persistence-defectdojo/hook/src/test/java/io/securecodebox/persistence/mapping/SecureCodeBoxFindingsToDefectDojoMapperTest.java index ebe56026a1..b3735edd26 100644 --- a/hooks/persistence-defectdojo/hook/src/test/java/io/securecodebox/persistence/mapping/SecureCodeBoxFindingsToDefectDojoMapperTest.java +++ b/hooks/persistence-defectdojo/hook/src/test/java/io/securecodebox/persistence/mapping/SecureCodeBoxFindingsToDefectDojoMapperTest.java @@ -1,23 +1,33 @@ package io.securecodebox.persistence.mapping; +import io.securecodebox.persistence.config.PersistenceProviderConfig; import io.securecodebox.persistence.models.SecureCodeBoxFinding; import org.json.JSONException; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestInstance; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.junit.jupiter.MockitoExtension; import org.skyscreamer.jsonassert.JSONAssert; import org.skyscreamer.jsonassert.JSONCompareMode; +import java.time.ZoneId; import java.util.HashMap; import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; - +@TestInstance(TestInstance.Lifecycle.PER_CLASS) +@ExtendWith(MockitoExtension.class) public class SecureCodeBoxFindingsToDefectDojoMapperTest { - private static SecureCodeBoxFindingsToDefectDojoMapper scbToDdMapper = new SecureCodeBoxFindingsToDefectDojoMapper(); - private static SecureCodeBoxFinding genericTestFinding; + + private SecureCodeBoxFindingsToDefectDojoMapper scbToDdMapper; + private SecureCodeBoxFinding genericTestFinding; + private PersistenceProviderConfig ppConfig; @BeforeAll - public static void init(){ + public void init(){ var name = "Name"; var description = "Description"; var id = "e18cdc5e-6b49-4346-b623-28a4e878e154"; @@ -32,6 +42,11 @@ public static void init(){ genericTestFinding = SecureCodeBoxFinding.builder().name(name).description(description) .severity(SecureCodeBoxFinding.Severities.HIGH).id(id).location(location).attributes(attributes) .parsedAt(parsedAt).build(); + ppConfig = mock(PersistenceProviderConfig.class); + // usually the default TimeZone on a machine is used to create the DefectDojo Dates. To ensure that the test + // results are the same regardless of the machine the test runs on we assume UTC+0 for tests. + when(ppConfig.getDefectDojoTimezoneId()).thenReturn(ZoneId.of("+0")); + scbToDdMapper = new SecureCodeBoxFindingsToDefectDojoMapper(ppConfig); } @Test @@ -69,7 +84,7 @@ public void correctlyParsesDate(){ public void correctlyParsesDescription() throws JSONException { var ddFinding = scbToDdMapper.fromSecureCodeBoxFinding(genericTestFinding); assertTrue(ddFinding.getDescription().startsWith(genericTestFinding.getDescription())); - //Description should consist of description and attributes as JSON + //Description should consist of the secureCodeBox description and attributes as JSON String attributesJson = ddFinding.getDescription().substring(genericTestFinding.getDescription().length() + 1); String expectedAttributeJson = "{\n" + " \"attribute_1\" : {\n" + diff --git a/hooks/persistence-defectdojo/hook/src/test/java/io/securecodebox/persistence/service/ScanServiceTest.java b/hooks/persistence-defectdojo/hook/src/test/java/io/securecodebox/persistence/service/ScanServiceTest.java index 5e283b55a1..58b772f745 100644 --- a/hooks/persistence-defectdojo/hook/src/test/java/io/securecodebox/persistence/service/ScanServiceTest.java +++ b/hooks/persistence-defectdojo/hook/src/test/java/io/securecodebox/persistence/service/ScanServiceTest.java @@ -4,28 +4,28 @@ import io.securecodebox.persistence.config.PersistenceProviderConfig; import io.securecodebox.persistence.defectdojo.models.ScanFile; import io.securecodebox.persistence.models.Scan; -import org.apache.log4j.LogMF; +import io.securecodebox.persistence.service.scan.ScanResultService; import org.json.JSONException; -import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestInstance; import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.Mock; -import org.mockito.Mockito; +import org.mockito.MockitoAnnotations; import org.mockito.junit.jupiter.MockitoExtension; import org.skyscreamer.jsonassert.JSONAssert; import org.skyscreamer.jsonassert.JSONCompareMode; import java.io.File; import java.io.IOException; -import java.net.URISyntaxException; import java.nio.file.Files; +import java.time.ZoneId; -import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.Mockito.when; import static org.junit.jupiter.api.Assertions.*; @ExtendWith(MockitoExtension.class) +@TestInstance(TestInstance.Lifecycle.PER_CLASS) public class ScanServiceTest { @Mock S3Service s3Service; @@ -34,12 +34,12 @@ public class ScanServiceTest { @Mock Scan scan; - private static String expectedDdFindingsString; - private static String givenScbFindingsString; - private static String rawNiktoScanString; + private String expectedDdFindingsString; + private String givenScbFindingsString; + private String rawNiktoScanString; @BeforeAll - public static void init() throws IOException{ + public void init() throws IOException{ expectedDdFindingsString = readResourceAsString("kubehunter-dd-findings.json"); assertNotNull(expectedDdFindingsString); assertNotEquals(expectedDdFindingsString,""); @@ -59,12 +59,13 @@ public static void init() throws IOException{ @Test public void correctlyParsesGenericResults() throws IOException, InterruptedException, JSONException { String findingsUrl = "https://foo.com/findings.json"; - when(ppConfig.getFindingDownloadUrl()).thenReturn(findingsUrl); - when(s3Service.downloadFile(findingsUrl)).thenReturn(givenScbFindingsString); V1ScanSpec scanSpec = new V1ScanSpec(); scanSpec.setScanType("some-unknown-scanner-type"); when(scan.getSpec()).thenReturn(scanSpec); - ScanFile result = ScanService.getDefectDojoCompatibleScanResult(scan,ppConfig,s3Service); + when(ppConfig.getFindingDownloadUrl()).thenReturn(findingsUrl); + when(ppConfig.getDefectDojoTimezoneId()).thenReturn(ZoneId.of("+0")); + when(s3Service.downloadFile(findingsUrl)).thenReturn(givenScbFindingsString); + var result = ScanResultService.build(scan,s3Service).getScanResult(ppConfig); JSONAssert.assertEquals(expectedDdFindingsString,result.getContent(), JSONCompareMode.NON_EXTENSIBLE); assertTrue(result.getName().endsWith(".json")); } @@ -78,12 +79,12 @@ public void correctlyParsesGenericResults() throws IOException, InterruptedExcep @Test public void correctlyReturnsScannerSpecificResults() throws IOException, InterruptedException { String rawResultDownloadUrl = "https://foo.com/nikto-raw-results.json"; - when(ppConfig.getRawResultDownloadUrl()).thenReturn(rawResultDownloadUrl); V1ScanSpec scanSpec = new V1ScanSpec(); scanSpec.setScanType("nikto"); + when(ppConfig.getRawResultDownloadUrl()).thenReturn(rawResultDownloadUrl); when(scan.getSpec()).thenReturn(scanSpec); when(s3Service.downloadFile(rawResultDownloadUrl)).thenReturn(rawNiktoScanString); - ScanFile result = ScanService.getDefectDojoCompatibleScanResult(scan,ppConfig,s3Service); + ScanFile result = ScanResultService.build(scan,s3Service).getScanResult(ppConfig); assertEquals(rawNiktoScanString,result.getContent()); assertTrue(result.getName().endsWith(".json")); } From 5a3c9aa38612ecf73cb83ad46a5ceb21b0aa2ac4 Mon Sep 17 00:00:00 2001 From: Johannes Zahn Date: Thu, 19 Aug 2021 09:57:31 +0200 Subject: [PATCH 3/8] rename package, refactor some methods Signed-off-by: Johannes Zahn --- .../DefectDojoPersistenceProvider.java | 2 +- .../GenericParserScanResultService.java | 2 +- .../ScanResultService.java | 6 ++- .../SpecificParserScanResultService.java | 2 +- ...CodeBoxFindingsToDefectDojoMapperTest.java | 29 +++++----- .../persistence/service/ScanServiceTest.java | 54 +++++++++---------- 6 files changed, 48 insertions(+), 47 deletions(-) rename hooks/persistence-defectdojo/hook/src/main/java/io/securecodebox/persistence/service/{scan => scanresult}/GenericParserScanResultService.java (97%) rename hooks/persistence-defectdojo/hook/src/main/java/io/securecodebox/persistence/service/{scan => scanresult}/ScanResultService.java (78%) rename hooks/persistence-defectdojo/hook/src/main/java/io/securecodebox/persistence/service/{scan => scanresult}/SpecificParserScanResultService.java (93%) diff --git a/hooks/persistence-defectdojo/hook/src/main/java/io/securecodebox/persistence/DefectDojoPersistenceProvider.java b/hooks/persistence-defectdojo/hook/src/main/java/io/securecodebox/persistence/DefectDojoPersistenceProvider.java index 1db62c7f75..88d9cf13cd 100644 --- a/hooks/persistence-defectdojo/hook/src/main/java/io/securecodebox/persistence/DefectDojoPersistenceProvider.java +++ b/hooks/persistence-defectdojo/hook/src/main/java/io/securecodebox/persistence/DefectDojoPersistenceProvider.java @@ -8,7 +8,7 @@ import io.securecodebox.persistence.defectdojo.service.EndpointService; import io.securecodebox.persistence.mapping.DefectDojoFindingToSecureCodeBoxMapper; import io.securecodebox.persistence.models.Scan; -import io.securecodebox.persistence.service.scan.ScanResultService; +import io.securecodebox.persistence.service.scanresult.ScanResultService; import io.securecodebox.persistence.service.KubernetesService; import io.securecodebox.persistence.service.S3Service; import io.securecodebox.persistence.strategies.VersionedEngagementsStrategy; diff --git a/hooks/persistence-defectdojo/hook/src/main/java/io/securecodebox/persistence/service/scan/GenericParserScanResultService.java b/hooks/persistence-defectdojo/hook/src/main/java/io/securecodebox/persistence/service/scanresult/GenericParserScanResultService.java similarity index 97% rename from hooks/persistence-defectdojo/hook/src/main/java/io/securecodebox/persistence/service/scan/GenericParserScanResultService.java rename to hooks/persistence-defectdojo/hook/src/main/java/io/securecodebox/persistence/service/scanresult/GenericParserScanResultService.java index 67b04a3f88..32259eda9d 100644 --- a/hooks/persistence-defectdojo/hook/src/main/java/io/securecodebox/persistence/service/scan/GenericParserScanResultService.java +++ b/hooks/persistence-defectdojo/hook/src/main/java/io/securecodebox/persistence/service/scanresult/GenericParserScanResultService.java @@ -1,4 +1,4 @@ -package io.securecodebox.persistence.service.scan; +package io.securecodebox.persistence.service.scanresult; import com.fasterxml.jackson.databind.DeserializationFeature; import com.fasterxml.jackson.databind.ObjectMapper; diff --git a/hooks/persistence-defectdojo/hook/src/main/java/io/securecodebox/persistence/service/scan/ScanResultService.java b/hooks/persistence-defectdojo/hook/src/main/java/io/securecodebox/persistence/service/scanresult/ScanResultService.java similarity index 78% rename from hooks/persistence-defectdojo/hook/src/main/java/io/securecodebox/persistence/service/scan/ScanResultService.java rename to hooks/persistence-defectdojo/hook/src/main/java/io/securecodebox/persistence/service/scanresult/ScanResultService.java index 555ca66250..ba4cc3b49c 100644 --- a/hooks/persistence-defectdojo/hook/src/main/java/io/securecodebox/persistence/service/scan/ScanResultService.java +++ b/hooks/persistence-defectdojo/hook/src/main/java/io/securecodebox/persistence/service/scanresult/ScanResultService.java @@ -1,4 +1,4 @@ -package io.securecodebox.persistence.service.scan; +package io.securecodebox.persistence.service.scanresult; import io.securecodebox.persistence.config.PersistenceProviderConfig; import io.securecodebox.persistence.defectdojo.models.ScanFile; @@ -11,7 +11,9 @@ import java.io.IOException; /** - * Enables fetching Scan Results for uploading to DefectDojo depending on the Scan (especially it's type) + * Abstract class that forces children to implement a method to get the scan results from a source + * (e.g. download link) specified in the PersistenceProviderConfig. + * It also builds the correct subclass to use, depending on the Scan (especially it's type) */ public abstract class ScanResultService { protected static final Logger LOG = LoggerFactory.getLogger(ScanResultService.class); diff --git a/hooks/persistence-defectdojo/hook/src/main/java/io/securecodebox/persistence/service/scan/SpecificParserScanResultService.java b/hooks/persistence-defectdojo/hook/src/main/java/io/securecodebox/persistence/service/scanresult/SpecificParserScanResultService.java similarity index 93% rename from hooks/persistence-defectdojo/hook/src/main/java/io/securecodebox/persistence/service/scan/SpecificParserScanResultService.java rename to hooks/persistence-defectdojo/hook/src/main/java/io/securecodebox/persistence/service/scanresult/SpecificParserScanResultService.java index caf1570778..4211f1bf4e 100644 --- a/hooks/persistence-defectdojo/hook/src/main/java/io/securecodebox/persistence/service/scan/SpecificParserScanResultService.java +++ b/hooks/persistence-defectdojo/hook/src/main/java/io/securecodebox/persistence/service/scanresult/SpecificParserScanResultService.java @@ -1,4 +1,4 @@ -package io.securecodebox.persistence.service.scan; +package io.securecodebox.persistence.service.scanresult; import io.securecodebox.persistence.config.PersistenceProviderConfig; import io.securecodebox.persistence.defectdojo.models.ScanFile; diff --git a/hooks/persistence-defectdojo/hook/src/test/java/io/securecodebox/persistence/mapping/SecureCodeBoxFindingsToDefectDojoMapperTest.java b/hooks/persistence-defectdojo/hook/src/test/java/io/securecodebox/persistence/mapping/SecureCodeBoxFindingsToDefectDojoMapperTest.java index b3735edd26..5634f0b79f 100644 --- a/hooks/persistence-defectdojo/hook/src/test/java/io/securecodebox/persistence/mapping/SecureCodeBoxFindingsToDefectDojoMapperTest.java +++ b/hooks/persistence-defectdojo/hook/src/test/java/io/securecodebox/persistence/mapping/SecureCodeBoxFindingsToDefectDojoMapperTest.java @@ -7,6 +7,7 @@ import org.junit.jupiter.api.Test; import org.junit.jupiter.api.TestInstance; import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; import org.skyscreamer.jsonassert.JSONAssert; import org.skyscreamer.jsonassert.JSONCompareMode; @@ -18,16 +19,20 @@ import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; +// Create one instance for the whole class instead for each method to reuse the genericTestFinding in all methods @TestInstance(TestInstance.Lifecycle.PER_CLASS) @ExtendWith(MockitoExtension.class) public class SecureCodeBoxFindingsToDefectDojoMapperTest { + // test class private SecureCodeBoxFindingsToDefectDojoMapper scbToDdMapper; + // test data private SecureCodeBoxFinding genericTestFinding; + // Mock private PersistenceProviderConfig ppConfig; @BeforeAll - public void init(){ + public void init() { var name = "Name"; var description = "Description"; var id = "e18cdc5e-6b49-4346-b623-28a4e878e154"; @@ -50,7 +55,7 @@ public void init(){ } @Test - public void correctlyParsesBasicFinding() { + public void correctlyParsesBasicFindingProperties() { var ddFinding = scbToDdMapper.fromSecureCodeBoxFinding(genericTestFinding); assertEquals(ddFinding.getTitle(), genericTestFinding.getName()); assertEquals(ddFinding.getUniqueIdFromTool(), genericTestFinding.getId()); @@ -58,26 +63,26 @@ public void correctlyParsesBasicFinding() { } @Test - public void correctlyParsesSeverities(){ + public void correctlyParsesSeverities() { var nullSeverityFinding = SecureCodeBoxFinding.builder().build(); var infoSeverityFinding = SecureCodeBoxFinding.builder().severity(SecureCodeBoxFinding.Severities.INFORMATIONAL).build(); var lowSeverityFinding = SecureCodeBoxFinding.builder().severity(SecureCodeBoxFinding.Severities.LOW).build(); var mediumSeverityFinding = SecureCodeBoxFinding.builder().severity(SecureCodeBoxFinding.Severities.MEDIUM).build(); var highSeverityFinding = SecureCodeBoxFinding.builder().severity((SecureCodeBoxFinding.Severities.HIGH)).build(); - assertEquals(scbToDdMapper.fromSecureCodeBoxFinding(nullSeverityFinding).getSeverity(),"Info"); - assertEquals(scbToDdMapper.fromSecureCodeBoxFinding(infoSeverityFinding).getSeverity(),"Info"); - assertEquals(scbToDdMapper.fromSecureCodeBoxFinding(lowSeverityFinding).getSeverity(),"Low"); - assertEquals(scbToDdMapper.fromSecureCodeBoxFinding(mediumSeverityFinding).getSeverity(),"Medium"); - assertEquals(scbToDdMapper.fromSecureCodeBoxFinding(highSeverityFinding).getSeverity(),"High"); + assertEquals(scbToDdMapper.fromSecureCodeBoxFinding(nullSeverityFinding).getSeverity(), "Info"); + assertEquals(scbToDdMapper.fromSecureCodeBoxFinding(infoSeverityFinding).getSeverity(), "Info"); + assertEquals(scbToDdMapper.fromSecureCodeBoxFinding(lowSeverityFinding).getSeverity(), "Low"); + assertEquals(scbToDdMapper.fromSecureCodeBoxFinding(mediumSeverityFinding).getSeverity(), "Medium"); + assertEquals(scbToDdMapper.fromSecureCodeBoxFinding(highSeverityFinding).getSeverity(), "High"); } @Test - public void correctlyParsesDate(){ + public void correctlyParsesDate() { var ddFinding = scbToDdMapper.fromSecureCodeBoxFinding(genericTestFinding); assertEquals(ddFinding.getDate(), "2020-04-15"); var dateTestFinding = SecureCodeBoxFinding.builder().parsedAt("2030-12-01T14:22:28Z").build(); var dateTestResultFinding = scbToDdMapper.fromSecureCodeBoxFinding(dateTestFinding); - assertEquals(dateTestResultFinding.getDate(),"2030-12-01"); + assertEquals(dateTestResultFinding.getDate(), "2030-12-01"); } @Test @@ -94,11 +99,11 @@ public void correctlyParsesDescription() throws JSONException { " \"attribute_3\" : \"3\"\n" + "}"; // We do not care how exactly the JSON looks as long as it is correct. - JSONAssert.assertEquals(expectedAttributeJson,attributesJson, JSONCompareMode.NON_EXTENSIBLE); + JSONAssert.assertEquals(expectedAttributeJson, attributesJson, JSONCompareMode.NON_EXTENSIBLE); } @Test - public void doesNotThrowUnexpectedExceptionOnEmptyFinding(){ + public void doesNotThrowUnexpectedExceptionOnEmptyFinding() { var emptyScbFinding = SecureCodeBoxFinding.builder().build(); assertDoesNotThrow(() -> scbToDdMapper.fromSecureCodeBoxFinding(emptyScbFinding)); } diff --git a/hooks/persistence-defectdojo/hook/src/test/java/io/securecodebox/persistence/service/ScanServiceTest.java b/hooks/persistence-defectdojo/hook/src/test/java/io/securecodebox/persistence/service/ScanServiceTest.java index 58b772f745..cacac8ea6d 100644 --- a/hooks/persistence-defectdojo/hook/src/test/java/io/securecodebox/persistence/service/ScanServiceTest.java +++ b/hooks/persistence-defectdojo/hook/src/test/java/io/securecodebox/persistence/service/ScanServiceTest.java @@ -4,14 +4,12 @@ import io.securecodebox.persistence.config.PersistenceProviderConfig; import io.securecodebox.persistence.defectdojo.models.ScanFile; import io.securecodebox.persistence.models.Scan; -import io.securecodebox.persistence.service.scan.ScanResultService; +import io.securecodebox.persistence.service.scanresult.ScanResultService; import org.json.JSONException; -import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.TestInstance; import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.Mock; -import org.mockito.MockitoAnnotations; import org.mockito.junit.jupiter.MockitoExtension; import org.skyscreamer.jsonassert.JSONAssert; import org.skyscreamer.jsonassert.JSONCompareMode; @@ -21,11 +19,10 @@ import java.nio.file.Files; import java.time.ZoneId; -import static org.mockito.Mockito.when; import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.Mockito.when; @ExtendWith(MockitoExtension.class) -@TestInstance(TestInstance.Lifecycle.PER_CLASS) public class ScanServiceTest { @Mock S3Service s3Service; @@ -34,19 +31,10 @@ public class ScanServiceTest { @Mock Scan scan; - private String expectedDdFindingsString; - private String givenScbFindingsString; - private String rawNiktoScanString; - - @BeforeAll - public void init() throws IOException{ - expectedDdFindingsString = readResourceAsString("kubehunter-dd-findings.json"); - assertNotNull(expectedDdFindingsString); - assertNotEquals(expectedDdFindingsString,""); - givenScbFindingsString = readResourceAsString("kubehunter-scb-findings.json"); - assertNotNull(givenScbFindingsString); - assertNotEquals(givenScbFindingsString,""); - rawNiktoScanString = readResourceAsString("nikto-raw-result.json"); + public static String readResourceAsString(String resourceName) throws IOException { + ClassLoader cl = ScanServiceTest.class.getClassLoader(); + File resourceFile = new File(cl.getResource(resourceName).getFile()); + return Files.readString(resourceFile.toPath()); } /*** @@ -58,15 +46,28 @@ public void init() throws IOException{ */ @Test public void correctlyParsesGenericResults() throws IOException, InterruptedException, JSONException { + // read data + String expectedDdFindingsString = readResourceAsString("kubehunter-dd-findings.json"); + String givenScbFindingsString = readResourceAsString("kubehunter-scb-findings.json"); + + // check if null or empty + assertNotEquals(expectedDdFindingsString, ""); + assertNotEquals(givenScbFindingsString, ""); String findingsUrl = "https://foo.com/findings.json"; V1ScanSpec scanSpec = new V1ScanSpec(); scanSpec.setScanType("some-unknown-scanner-type"); + + // mock methods when(scan.getSpec()).thenReturn(scanSpec); when(ppConfig.getFindingDownloadUrl()).thenReturn(findingsUrl); when(ppConfig.getDefectDojoTimezoneId()).thenReturn(ZoneId.of("+0")); when(s3Service.downloadFile(findingsUrl)).thenReturn(givenScbFindingsString); - var result = ScanResultService.build(scan,s3Service).getScanResult(ppConfig); - JSONAssert.assertEquals(expectedDdFindingsString,result.getContent(), JSONCompareMode.NON_EXTENSIBLE); + + // test for correctness + var result = ScanResultService.build(scan, s3Service).getScanResult(ppConfig); + // check that the produced and expected JSON are the same. Non-strict array ordering and not extensible. + JSONAssert.assertEquals(expectedDdFindingsString, result.getContent(), JSONCompareMode.NON_EXTENSIBLE); + // file name must have the right ending assertTrue(result.getName().endsWith(".json")); } @@ -78,22 +79,15 @@ public void correctlyParsesGenericResults() throws IOException, InterruptedExcep */ @Test public void correctlyReturnsScannerSpecificResults() throws IOException, InterruptedException { + var rawNiktoScanString = readResourceAsString("nikto-raw-result.json"); String rawResultDownloadUrl = "https://foo.com/nikto-raw-results.json"; V1ScanSpec scanSpec = new V1ScanSpec(); scanSpec.setScanType("nikto"); when(ppConfig.getRawResultDownloadUrl()).thenReturn(rawResultDownloadUrl); when(scan.getSpec()).thenReturn(scanSpec); when(s3Service.downloadFile(rawResultDownloadUrl)).thenReturn(rawNiktoScanString); - ScanFile result = ScanResultService.build(scan,s3Service).getScanResult(ppConfig); - assertEquals(rawNiktoScanString,result.getContent()); + ScanFile result = ScanResultService.build(scan, s3Service).getScanResult(ppConfig); + assertEquals(rawNiktoScanString, result.getContent()); assertTrue(result.getName().endsWith(".json")); } - - public static String readResourceAsString(String resourceName) throws IOException { - ClassLoader cl = ScanServiceTest.class.getClassLoader(); - File resourceFile = new File(cl.getResource(resourceName).getFile()); - return Files.readString(resourceFile.toPath()); - } - - } From 5b5cdcdf4f334c1ba3cb9d66d43de82c200aa33d Mon Sep 17 00:00:00 2001 From: Johannes Zahn Date: Thu, 19 Aug 2021 10:07:17 +0200 Subject: [PATCH 4/8] add comments Signed-off-by: Johannes Zahn --- .../scanresult/GenericParserScanResultService.java | 12 ++++++++++++ .../scanresult/SpecificParserScanResultService.java | 12 ++++++++++++ 2 files changed, 24 insertions(+) diff --git a/hooks/persistence-defectdojo/hook/src/main/java/io/securecodebox/persistence/service/scanresult/GenericParserScanResultService.java b/hooks/persistence-defectdojo/hook/src/main/java/io/securecodebox/persistence/service/scanresult/GenericParserScanResultService.java index 32259eda9d..cd05666d9b 100644 --- a/hooks/persistence-defectdojo/hook/src/main/java/io/securecodebox/persistence/service/scanresult/GenericParserScanResultService.java +++ b/hooks/persistence-defectdojo/hook/src/main/java/io/securecodebox/persistence/service/scanresult/GenericParserScanResultService.java @@ -17,6 +17,9 @@ import java.util.List; import java.util.stream.Collectors; +/** + * Responsible for returning scan results that are compatible with the DefectDojo Generic JSON Parser + */ public class GenericParserScanResultService extends ScanResultService { private static final ObjectMapper jsonObjectMapper = new ObjectMapper() @@ -26,6 +29,15 @@ public GenericParserScanResultService(S3Service s3Service) { super(s3Service); } + /** + * Fetches the secureCodeBox Findings.json file and converts it to a json file that is compatible with + * the DefectDojo Generic JSON Parser. This result as a string is then returned together with a filename + * in a ScanFile object. The ending of the filename is essential as it is evaluated by DefectDojo + * @param ppConfig config where the location of the scan result is specified + * @return + * @throws IOException + * @throws InterruptedException + */ @Override public ScanFile getScanResult(PersistenceProviderConfig ppConfig) throws IOException, InterruptedException { LOG.debug("No explicit Parser specified using Findings JSON Scan Result"); diff --git a/hooks/persistence-defectdojo/hook/src/main/java/io/securecodebox/persistence/service/scanresult/SpecificParserScanResultService.java b/hooks/persistence-defectdojo/hook/src/main/java/io/securecodebox/persistence/service/scanresult/SpecificParserScanResultService.java index 4211f1bf4e..71ae15f900 100644 --- a/hooks/persistence-defectdojo/hook/src/main/java/io/securecodebox/persistence/service/scanresult/SpecificParserScanResultService.java +++ b/hooks/persistence-defectdojo/hook/src/main/java/io/securecodebox/persistence/service/scanresult/SpecificParserScanResultService.java @@ -8,12 +8,24 @@ import java.io.IOException; import java.net.URL; +/** + * Responsible for returning the raw scan results produced by the secureCodeBox + */ public class SpecificParserScanResultService extends ScanResultService { public SpecificParserScanResultService(S3Service s3Service) { super(s3Service); } + /** + * Fetches the secureCodeBox raw scan results and returns it together with the filename + * in a ScanFile object. The ending of the filename is essential as it is evaluated by DefectDojo. + * This is usually used when DefectDojo natively supports the scanner that produced the raw result. + * @param ppConfig config where the location of the scan result is specified + * @return + * @throws IOException + * @throws InterruptedException + */ @Override public ScanFile getScanResult(PersistenceProviderConfig ppConfig) throws IOException, InterruptedException { LOG.debug("Explicit Parser is specified, using Raw Scan Result"); From 9e2eefe025d31930e669b3be0b8df62ac9e19a9b Mon Sep 17 00:00:00 2001 From: Johannes Zahn Date: Thu, 19 Aug 2021 14:17:46 +0200 Subject: [PATCH 5/8] fix windows tests by adding uniform linefeed to jackson printer Signed-off-by: Johannes Zahn --- .../mapping/SecureCodeBoxFindingsToDefectDojoMapper.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/hooks/persistence-defectdojo/hook/src/main/java/io/securecodebox/persistence/mapping/SecureCodeBoxFindingsToDefectDojoMapper.java b/hooks/persistence-defectdojo/hook/src/main/java/io/securecodebox/persistence/mapping/SecureCodeBoxFindingsToDefectDojoMapper.java index 7d859be248..6a3405ecf5 100644 --- a/hooks/persistence-defectdojo/hook/src/main/java/io/securecodebox/persistence/mapping/SecureCodeBoxFindingsToDefectDojoMapper.java +++ b/hooks/persistence-defectdojo/hook/src/main/java/io/securecodebox/persistence/mapping/SecureCodeBoxFindingsToDefectDojoMapper.java @@ -1,6 +1,8 @@ package io.securecodebox.persistence.mapping; import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.core.util.DefaultIndenter; +import com.fasterxml.jackson.core.util.DefaultPrettyPrinter; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.ObjectWriter; import io.securecodebox.persistence.config.PersistenceProviderConfig; @@ -19,7 +21,8 @@ public class SecureCodeBoxFindingsToDefectDojoMapper { private static final Logger LOG = LoggerFactory.getLogger(KubernetesService.class); private final DateTimeFormatter ddDateFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd"); - private final ObjectWriter attributeJsonPrinter = new ObjectMapper().writerWithDefaultPrettyPrinter(); + private final ObjectWriter attributeJsonPrinter = new ObjectMapper().writer(new DefaultPrettyPrinter() + .withObjectIndenter(new DefaultIndenter().withLinefeed("\n"))); private PersistenceProviderConfig ppConfig; public SecureCodeBoxFindingsToDefectDojoMapper(PersistenceProviderConfig ppConfig){ From 7e6783bcd12593191af5807b918e58e2cebf5972 Mon Sep 17 00:00:00 2001 From: Johannes Zahn Date: Thu, 19 Aug 2021 16:41:19 +0200 Subject: [PATCH 6/8] replace jsonassert with jackson json node comparison Signed-off-by: Johannes Zahn --- hooks/persistence-defectdojo/hook/build.gradle | 1 - ...SecureCodeBoxFindingsToDefectDojoMapperTest.java | 11 +++++------ .../persistence/service/ScanServiceTest.java | 13 +++++-------- 3 files changed, 10 insertions(+), 15 deletions(-) diff --git a/hooks/persistence-defectdojo/hook/build.gradle b/hooks/persistence-defectdojo/hook/build.gradle index 5b44bd2519..403270147d 100644 --- a/hooks/persistence-defectdojo/hook/build.gradle +++ b/hooks/persistence-defectdojo/hook/build.gradle @@ -35,7 +35,6 @@ dependencies { testImplementation(platform('org.junit:junit-bom:5.7.0')) testImplementation('org.junit.jupiter:junit-jupiter') - testImplementation 'org.skyscreamer:jsonassert:1.2.3' testImplementation "org.mockito:mockito-core:2.+" testImplementation "org.mockito:mockito-junit-jupiter:2.+" diff --git a/hooks/persistence-defectdojo/hook/src/test/java/io/securecodebox/persistence/mapping/SecureCodeBoxFindingsToDefectDojoMapperTest.java b/hooks/persistence-defectdojo/hook/src/test/java/io/securecodebox/persistence/mapping/SecureCodeBoxFindingsToDefectDojoMapperTest.java index 5634f0b79f..51b24d9a87 100644 --- a/hooks/persistence-defectdojo/hook/src/test/java/io/securecodebox/persistence/mapping/SecureCodeBoxFindingsToDefectDojoMapperTest.java +++ b/hooks/persistence-defectdojo/hook/src/test/java/io/securecodebox/persistence/mapping/SecureCodeBoxFindingsToDefectDojoMapperTest.java @@ -1,16 +1,14 @@ package io.securecodebox.persistence.mapping; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; import io.securecodebox.persistence.config.PersistenceProviderConfig; import io.securecodebox.persistence.models.SecureCodeBoxFinding; -import org.json.JSONException; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.TestInstance; import org.junit.jupiter.api.extension.ExtendWith; -import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; -import org.skyscreamer.jsonassert.JSONAssert; -import org.skyscreamer.jsonassert.JSONCompareMode; import java.time.ZoneId; import java.util.HashMap; @@ -86,7 +84,7 @@ public void correctlyParsesDate() { } @Test - public void correctlyParsesDescription() throws JSONException { + public void correctlyParsesDescription() throws JsonProcessingException { var ddFinding = scbToDdMapper.fromSecureCodeBoxFinding(genericTestFinding); assertTrue(ddFinding.getDescription().startsWith(genericTestFinding.getDescription())); //Description should consist of the secureCodeBox description and attributes as JSON @@ -99,7 +97,8 @@ public void correctlyParsesDescription() throws JSONException { " \"attribute_3\" : \"3\"\n" + "}"; // We do not care how exactly the JSON looks as long as it is correct. - JSONAssert.assertEquals(expectedAttributeJson, attributesJson, JSONCompareMode.NON_EXTENSIBLE); + ObjectMapper mapper = new ObjectMapper(); + assertEquals(mapper.readTree(expectedAttributeJson), mapper.readTree(attributesJson)); } @Test diff --git a/hooks/persistence-defectdojo/hook/src/test/java/io/securecodebox/persistence/service/ScanServiceTest.java b/hooks/persistence-defectdojo/hook/src/test/java/io/securecodebox/persistence/service/ScanServiceTest.java index cacac8ea6d..a3a1a64a78 100644 --- a/hooks/persistence-defectdojo/hook/src/test/java/io/securecodebox/persistence/service/ScanServiceTest.java +++ b/hooks/persistence-defectdojo/hook/src/test/java/io/securecodebox/persistence/service/ScanServiceTest.java @@ -1,18 +1,15 @@ package io.securecodebox.persistence.service; +import com.fasterxml.jackson.databind.ObjectMapper; import io.securecodebox.models.V1ScanSpec; import io.securecodebox.persistence.config.PersistenceProviderConfig; import io.securecodebox.persistence.defectdojo.models.ScanFile; import io.securecodebox.persistence.models.Scan; import io.securecodebox.persistence.service.scanresult.ScanResultService; -import org.json.JSONException; import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.TestInstance; import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; -import org.skyscreamer.jsonassert.JSONAssert; -import org.skyscreamer.jsonassert.JSONCompareMode; import java.io.File; import java.io.IOException; @@ -42,10 +39,9 @@ public static String readResourceAsString(String resourceName) throws IOExceptio * the correct file ending must be used so DefectDojo can choose the right parser (usually xml or json) * @throws IOException * @throws InterruptedException - * @throws JSONException */ @Test - public void correctlyParsesGenericResults() throws IOException, InterruptedException, JSONException { + public void correctlyParsesGenericResults() throws IOException, InterruptedException { // read data String expectedDdFindingsString = readResourceAsString("kubehunter-dd-findings.json"); String givenScbFindingsString = readResourceAsString("kubehunter-scb-findings.json"); @@ -65,8 +61,9 @@ public void correctlyParsesGenericResults() throws IOException, InterruptedExcep // test for correctness var result = ScanResultService.build(scan, s3Service).getScanResult(ppConfig); - // check that the produced and expected JSON are the same. Non-strict array ordering and not extensible. - JSONAssert.assertEquals(expectedDdFindingsString, result.getContent(), JSONCompareMode.NON_EXTENSIBLE); + // check that the produced and expected JSON are the same. + ObjectMapper mapper = new ObjectMapper(); + assertEquals(mapper.readTree(expectedDdFindingsString), mapper.readTree(result.getContent())); // file name must have the right ending assertTrue(result.getName().endsWith(".json")); } From ba55ae35d866efa49156f818c6b2a18db4243138 Mon Sep 17 00:00:00 2001 From: Johannes Zahn Date: Fri, 20 Aug 2021 12:27:15 +0200 Subject: [PATCH 7/8] Update hooks/persistence-defectdojo/hook/src/main/java/io/securecodebox/persistence/service/scanresult/GenericParserScanResultService.java Co-authored-by: Jannik Hollenbach Signed-off-by: Johannes Zahn --- .../service/scanresult/GenericParserScanResultService.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hooks/persistence-defectdojo/hook/src/main/java/io/securecodebox/persistence/service/scanresult/GenericParserScanResultService.java b/hooks/persistence-defectdojo/hook/src/main/java/io/securecodebox/persistence/service/scanresult/GenericParserScanResultService.java index cd05666d9b..bec1078bd0 100644 --- a/hooks/persistence-defectdojo/hook/src/main/java/io/securecodebox/persistence/service/scanresult/GenericParserScanResultService.java +++ b/hooks/persistence-defectdojo/hook/src/main/java/io/securecodebox/persistence/service/scanresult/GenericParserScanResultService.java @@ -40,7 +40,7 @@ public GenericParserScanResultService(S3Service s3Service) { */ @Override public ScanFile getScanResult(PersistenceProviderConfig ppConfig) throws IOException, InterruptedException { - LOG.debug("No explicit Parser specified using Findings JSON Scan Result"); + LOG.debug("No explicit Parser specified. Using Findings JSON Scan Result"); var scbToDdMapper = new SecureCodeBoxFindingsToDefectDojoMapper(ppConfig); var downloadUrl = ppConfig.getFindingDownloadUrl(); var findingsJSON = s3Service.downloadFile(downloadUrl); From 6921b3569aa48c738f0f87e6bb39be9b8900a95a Mon Sep 17 00:00:00 2001 From: Johannes Zahn Date: Fri, 20 Aug 2021 12:27:23 +0200 Subject: [PATCH 8/8] Update hooks/persistence-defectdojo/hook/src/main/java/io/securecodebox/persistence/service/scanresult/SpecificParserScanResultService.java Co-authored-by: Jannik Hollenbach Signed-off-by: Johannes Zahn --- .../service/scanresult/SpecificParserScanResultService.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hooks/persistence-defectdojo/hook/src/main/java/io/securecodebox/persistence/service/scanresult/SpecificParserScanResultService.java b/hooks/persistence-defectdojo/hook/src/main/java/io/securecodebox/persistence/service/scanresult/SpecificParserScanResultService.java index 71ae15f900..76316210b2 100644 --- a/hooks/persistence-defectdojo/hook/src/main/java/io/securecodebox/persistence/service/scanresult/SpecificParserScanResultService.java +++ b/hooks/persistence-defectdojo/hook/src/main/java/io/securecodebox/persistence/service/scanresult/SpecificParserScanResultService.java @@ -28,7 +28,7 @@ public SpecificParserScanResultService(S3Service s3Service) { */ @Override public ScanFile getScanResult(PersistenceProviderConfig ppConfig) throws IOException, InterruptedException { - LOG.debug("Explicit Parser is specified, using Raw Scan Result"); + LOG.debug("Explicit Parser is specified. Using Raw Scan Result"); var downloadUrl = ppConfig.getRawResultDownloadUrl(); var scanResult = s3Service.downloadFile(downloadUrl); return new ScanFile(scanResult, FilenameUtils.getName(new URL(downloadUrl).getPath()));