diff --git a/src/main/java/eu/fasten/vulnerabilityproducer/utils/mappers/JSONHandler.java b/src/main/java/eu/fasten/vulnerabilityproducer/utils/mappers/JSONHandler.java index a7ca2db..f2fa2a6 100644 --- a/src/main/java/eu/fasten/vulnerabilityproducer/utils/mappers/JSONHandler.java +++ b/src/main/java/eu/fasten/vulnerabilityproducer/utils/mappers/JSONHandler.java @@ -88,6 +88,7 @@ public static class GHPageInfo { public static class GHAdvisory { public String description; + public String withdrawnAt; public List identifiers; public Severity severity; public GHCVSS cvss; @@ -106,6 +107,10 @@ public void setDescription(String description) { this.description = description; } + public String getWithdrawnAt() { return withdrawnAt; } + + public void setWithdrawnAt(String withdrawnAt ) { this.withdrawnAt = withdrawnAt; } + public List getIdentifiers() { return identifiers; } diff --git a/src/main/java/eu/fasten/vulnerabilityproducer/utils/parsers/GHParser.java b/src/main/java/eu/fasten/vulnerabilityproducer/utils/parsers/GHParser.java index 6a57450..4783060 100644 --- a/src/main/java/eu/fasten/vulnerabilityproducer/utils/parsers/GHParser.java +++ b/src/main/java/eu/fasten/vulnerabilityproducer/utils/parsers/GHParser.java @@ -121,6 +121,7 @@ public String buildQuery(String cursor) { " references {\n" + " url\n" + " }\n" + + " withdrawnAt\n" + " vulnerabilities(first: 10) {\n" + " nodes {\n" + " package {\n" + @@ -151,43 +152,48 @@ public String buildQuery(String cursor) { public void parseGHResponse(JSONHandler.GHResponse response, HashMap vulnerabilities) { for (JSONHandler.GHAdvisory advisory : response.getData().getSecurityAdvisories().getNodes()) { logger.info("Parsing information of Vulnerability with ID - " + advisory.getAdvisoryId()); - var v = new Vulnerability(advisory.getAdvisoryId()); - v.setSeverity(advisory.getSeverity()); - v.setDescription(advisory.getDescription()); - advisory.getReferences().forEach(ref -> v.addReference(ref.getUrl())); - extractCweIds(v, advisory); + if(advisory.getWithdrawnAt() != null) { + logger.info("Vulnerability with ID was withdrawn at " + advisory.getWithdrawnAt() + " , skipping."); + } + else { + var v = new Vulnerability(advisory.getAdvisoryId()); + v.setSeverity(advisory.getSeverity()); + v.setDescription(advisory.getDescription()); + advisory.getReferences().forEach(ref -> v.addReference(ref.getUrl())); + extractCweIds(v, advisory); - for (JSONHandler.GHNodes node : advisory.getVulnerabilities().getNodes()) { - var ecosystem = node.ghPackage.ecosystem; - String pgkIdentifier = null; - if (ecosystem.equals("PIP")) { - pgkIdentifier = "pkg:pypi/" + node.getGhPackage().name; - } - if (ecosystem.equals("MAVEN")) { - var coordinates = node.getGhPackage().getName().split(":"); - if (coordinates.length > 1) { - pgkIdentifier = "pkg:maven/" + coordinates[0] + "/" + coordinates[1]; - } else { - String[] splits = coordinates[0].split("\\."); - pgkIdentifier = "pkg:maven/" + coordinates[0] + "/" + splits[splits.length - 1]; + for (JSONHandler.GHNodes node : advisory.getVulnerabilities().getNodes()) { + var ecosystem = node.ghPackage.ecosystem; + String pgkIdentifier = null; + if (ecosystem.equals("PIP")) { + pgkIdentifier = "pkg:pypi/" + node.getGhPackage().name; } - } - if (pgkIdentifier != null) { - List allVersions = versionRanger.getVersions(pgkIdentifier); - if (allVersions != null) { - var vulnerableVersions = versionRanger.getVulnerableVersionsJSON(node.vulnerableVersionRange, allVersions); - for (String version : vulnerableVersions) { - v.addPurl(pgkIdentifier + "@" + version); + if (ecosystem.equals("MAVEN")) { + var coordinates = node.getGhPackage().getName().split(":"); + if (coordinates.length > 1) { + pgkIdentifier = "pkg:maven/" + coordinates[0] + "/" + coordinates[1]; + } else { + String[] splits = coordinates[0].split("\\."); + pgkIdentifier = "pkg:maven/" + coordinates[0] + "/" + splits[splits.length - 1]; } } + if (pgkIdentifier != null) { + List allVersions = versionRanger.getVersions(pgkIdentifier); + if (allVersions != null) { + var vulnerableVersions = versionRanger.getVulnerableVersionsJSON(node.vulnerableVersionRange, allVersions); + for (String version : vulnerableVersions) { + v.addPurl(pgkIdentifier + "@" + version); + } + } - if (node.firstPatchedVersion != null) - v.addFirstPatchedPurl(pgkIdentifier + "@" + node.firstPatchedVersion.identifier); + if (node.firstPatchedVersion != null) + v.addFirstPatchedPurl(pgkIdentifier + "@" + node.firstPatchedVersion.identifier); + } } + // Add the vulnerability to the Hash Map + vulnerabilities.put(v.getId(), v); + storeAdvisory(advisory); } - // Add the vulnerability to the Hash Map - vulnerabilities.put(v.getId(), v); - storeAdvisory(advisory); } } diff --git a/src/test/java/eu/fasten/vulnerabilityproducer/parsers/GHParserTest.java b/src/test/java/eu/fasten/vulnerabilityproducer/parsers/GHParserTest.java index b5a603b..9a2f3fe 100644 --- a/src/test/java/eu/fasten/vulnerabilityproducer/parsers/GHParserTest.java +++ b/src/test/java/eu/fasten/vulnerabilityproducer/parsers/GHParserTest.java @@ -70,6 +70,7 @@ public class GHParserTest { " references {\n" + " url\n" + " }\n" + + " withdrawnAt\n" + " vulnerabilities(first: 10) {\n" + " nodes {\n" + " package {\n" + @@ -111,6 +112,7 @@ public class GHParserTest { " references {\n" + " url\n" + " }\n" + + " withdrawnAt\n" + " vulnerabilities(first: 10) {\n" + " nodes {\n" + " package {\n" + @@ -141,6 +143,16 @@ public class GHParserTest { } } + String ghResponseAPIWithdrawn; + + { + try { + ghResponseAPIWithdrawn = FileUtils.readFileToString(new File("./src/test/resources/parsers/ghAPISecurityWithdrawn.json"), StandardCharsets.UTF_8); + } catch (IOException e) { + e.printStackTrace(); + } + } + @Test public void testQueryBuilder() { String queryWithoutCursor = ghParser.buildQuery(null); @@ -173,12 +185,25 @@ public void testParseGHResponse() throws Exception { "unmarshalling, leading to a remote application crash, as demonstrated by an" + " xstream.fromXML(\"\") call."); - // ASSERT assertEquals(1, result.size()); assertEquals(vCheck, result.get("CVE-2017-7957")); } + @Test + public void testParseGHResponseWithdrawn() throws Exception { + HashMap values = new HashMap<>(); + values.put("query", queryNoCursor); + when(clientMock.sendPost("https://api.github.com/graphql", token, values)).thenReturn(ghResponseAPIWithdrawn); + var versions = Stream.of("1.3.2", "1.4.9", "1.4.10", "1.4.12").map(x -> new ImmutablePair<>(x, new DateTime())).collect(Collectors.toList()); + ghParser.getVersionRanger().versionsMappings.put("pkg:maven/com.thoughtworks.xstream/xstream", versions); + ghParser.setCursor(null); + + HashMap result = ghParser.getVulnerabilities(false); + + assertEquals(0, result.size()); + } + @AfterAll public static void deleteCursor() { File ghCursor = new File("./src/test/resources/parsers/cursor.txt.txt"); diff --git a/src/test/resources/parsers/ghAPISecurity.json b/src/test/resources/parsers/ghAPISecurity.json index 3aa30e5..8a02d43 100644 --- a/src/test/resources/parsers/ghAPISecurity.json +++ b/src/test/resources/parsers/ghAPISecurity.json @@ -23,6 +23,7 @@ "url": "https://github.com/advisories/GHSA-7hwc-46rm-65jh" } ], + "withdrawnAt" : null, "vulnerabilities": { "nodes": [ { diff --git a/src/test/resources/parsers/ghAPISecurityWithdrawn.json b/src/test/resources/parsers/ghAPISecurityWithdrawn.json new file mode 100644 index 0000000..f15a43b --- /dev/null +++ b/src/test/resources/parsers/ghAPISecurityWithdrawn.json @@ -0,0 +1,46 @@ +{ + "data": { + "securityAdvisories": { + "nodes": [ + { + "description": "XStream through 1.4.9, when a certain denyTypes workaround is not used, mishandles attempts to create an instance of the primitive type 'void' during unmarshalling, leading to a remote application crash, as demonstrated by an xstream.fromXML(\"\") call.", + "identifiers": [ + { + "type": "GHSA", + "value": "GHSA-7hwc-46rm-65jh" + }, + { + "type": "CVE", + "value": "CVE-2017-7957" + } + ], + "severity": "HIGH", + "references": [ + { + "url": "https://nvd.nist.gov/vuln/detail/CVE-2017-7957" + }, + { + "url": "https://github.com/advisories/GHSA-7hwc-46rm-65jh" + } + ], + "withdrawnAt" : "placeholder date", + "vulnerabilities": { + "nodes": [ + { + "package": { + "ecosystem": "MAVEN", + "name": "com.thoughtworks.xstream:xstream" + }, + "vulnerableVersionRange": "< 1.4.10" + } + ] + } + } + ], + "pageInfo": { + "endCursor": "Y3Vyc29yOnYyOpK5MjAyMC0wNi0wNFQwMDowMjoxOSswMjowMM0ITw==", + "hasNextPage": false + } + } + } +} \ No newline at end of file