Skip to content

Commit 0e699dd

Browse files
committed
#65 - Reader for Snyk and Semgrep SARIF files
1 parent bc1690b commit 0e699dd

File tree

11 files changed

+648
-593
lines changed

11 files changed

+648
-593
lines changed

plugin/src/main/java/org/owasp/benchmarkutils/score/parsers/CodeQLReader.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,8 @@ public boolean canRead(ResultFile resultFile) {
4343
.getJSONObject(0)
4444
.getJSONObject("tool")
4545
.getJSONObject("driver")
46-
.has("semanticVersion");
46+
.get("name")
47+
.equals("CodeQL");
4748
} catch (Exception e) {
4849
return false;
4950
}

plugin/src/main/java/org/owasp/benchmarkutils/score/parsers/Reader.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,7 @@ public static List<Reader> allReaders() {
8888
new ScnrReader(),
8989
new SeekerReader(),
9090
new SemgrepReader(),
91+
new SemgrepSarifReader(),
9192
new ShiftLeftReader(),
9293
new ShiftLeftScanReader(),
9394
new SnappyTickReader(),
Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
/**
2+
* OWASP Benchmark Project
3+
*
4+
* <p>This file is part of the Open Web Application Security Project (OWASP) Benchmark Project For
5+
* details, please see <a
6+
* href="https://owasp.org/www-project-benchmark/">https://owasp.org/www-project-benchmark/</a>.
7+
*
8+
* <p>The OWASP Benchmark is free software: you can redistribute it and/or modify it under the terms
9+
* of the GNU General Public License as published by the Free Software Foundation, version 2.
10+
*
11+
* <p>The OWASP Benchmark is distributed in the hope that it will be useful, but WITHOUT ANY
12+
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
13+
* PURPOSE. See the GNU General Public License for more details.
14+
*
15+
* @author Sascha Knoop
16+
* @created 2024
17+
*/
18+
package org.owasp.benchmarkutils.score.parsers;
19+
20+
import java.util.Map;
21+
import org.json.JSONArray;
22+
import org.json.JSONObject;
23+
import org.owasp.benchmarkutils.score.BenchmarkScore;
24+
import org.owasp.benchmarkutils.score.ResultFile;
25+
import org.owasp.benchmarkutils.score.TestCaseResult;
26+
import org.owasp.benchmarkutils.score.TestSuiteResults;
27+
28+
public abstract class SarifReader extends Reader {
29+
30+
private static final int INVALID_RULE_ID = -1;
31+
32+
protected abstract String expectedSarifToolName();
33+
34+
protected abstract boolean isCommercial();
35+
36+
protected abstract Map<String, Integer> ruleCweMappings(JSONArray rules);
37+
38+
@Override
39+
public boolean canRead(ResultFile resultFile) {
40+
try {
41+
return resultFile.isJson() && sarifToolName(resultFile).equals(expectedSarifToolName());
42+
} catch (Exception e) {
43+
return false;
44+
}
45+
}
46+
47+
private String sarifToolName(ResultFile resultFile) {
48+
return toolDriver(resultFile).getString("name");
49+
}
50+
51+
private static JSONObject toolDriver(ResultFile resultFile) {
52+
return firstRun(resultFile).getJSONObject("tool").getJSONObject("driver");
53+
}
54+
55+
private static JSONObject firstRun(ResultFile resultFile) {
56+
return resultFile.json().getJSONArray("runs").getJSONObject(0);
57+
}
58+
59+
@Override
60+
public TestSuiteResults parse(ResultFile resultFile) throws Exception {
61+
JSONObject driver = toolDriver(resultFile);
62+
63+
Map<String, Integer> mappings = ruleCweMappings(driver.getJSONArray("rules"));
64+
65+
TestSuiteResults testSuiteResults =
66+
new TestSuiteResults(
67+
sarifToolName(resultFile), isCommercial(), TestSuiteResults.ToolType.SAST);
68+
69+
testSuiteResults.setToolVersion(driver.getString("semanticVersion"));
70+
71+
JSONArray results = firstRun(resultFile).getJSONArray("results");
72+
73+
for (int i = 0; i < results.length(); i++) {
74+
JSONObject result = results.getJSONObject(i);
75+
76+
String className = extractFilename(resultUri(result));
77+
78+
if (!className.startsWith(BenchmarkScore.TESTCASENAME)) {
79+
continue;
80+
}
81+
82+
TestCaseResult tcr = new TestCaseResult();
83+
84+
String ruleId = result.getString("ruleId");
85+
86+
int cwe = mappings.getOrDefault(ruleId, INVALID_RULE_ID);
87+
88+
if (cwe == INVALID_RULE_ID) {
89+
System.out.println("CWE # not parseable from: " + ruleId);
90+
continue;
91+
}
92+
93+
String evidence = result.getJSONObject("message").getString("text");
94+
95+
tcr.setCWE(cwe);
96+
tcr.setCategory(ruleId);
97+
tcr.setEvidence(evidence);
98+
tcr.setConfidence(0);
99+
tcr.setNumber(testNumber(className));
100+
101+
testSuiteResults.put(tcr);
102+
}
103+
104+
return testSuiteResults;
105+
}
106+
107+
private static String resultUri(JSONObject result) {
108+
return result.getJSONArray("locations")
109+
.getJSONObject(0)
110+
.getJSONObject("physicalLocation")
111+
.getJSONObject("artifactLocation")
112+
.getString("uri");
113+
}
114+
}
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
/**
2+
* OWASP Benchmark Project
3+
*
4+
* <p>This file is part of the Open Web Application Security Project (OWASP) Benchmark Project For
5+
* details, please see <a
6+
* href="https://owasp.org/www-project-benchmark/">https://owasp.org/www-project-benchmark/</a>.
7+
*
8+
* <p>The OWASP Benchmark is free software: you can redistribute it and/or modify it under the terms
9+
* of the GNU General Public License as published by the Free Software Foundation, version 2.
10+
*
11+
* <p>The OWASP Benchmark is distributed in the hope that it will be useful, but WITHOUT ANY
12+
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
13+
* PURPOSE. See the GNU General Public License for more details.
14+
*
15+
* @author Sascha Knoop
16+
* @created 2024
17+
*/
18+
package org.owasp.benchmarkutils.score.parsers;
19+
20+
import static java.lang.Integer.parseInt;
21+
22+
import java.util.HashMap;
23+
import java.util.Map;
24+
import org.json.JSONArray;
25+
import org.json.JSONObject;
26+
27+
public class SemgrepSarifReader extends SarifReader {
28+
29+
@Override
30+
protected String expectedSarifToolName() {
31+
return "Semgrep OSS";
32+
}
33+
34+
@Override
35+
protected boolean isCommercial() {
36+
return false;
37+
}
38+
39+
@Override
40+
protected Map<String, Integer> ruleCweMappings(JSONArray rules) {
41+
Map<String, Integer> mappings = new HashMap<>();
42+
43+
for (int i = 0; i < rules.length(); i++) {
44+
JSONObject rule = rules.getJSONObject(i);
45+
46+
JSONArray tags = rule.getJSONObject("properties").getJSONArray("tags");
47+
48+
for (int j = 0; j < tags.length(); j++) {
49+
String tag = tags.getString(j);
50+
51+
if (tag.startsWith("CWE")) {
52+
int cwe = parseInt(tag.split(":")[0].substring(4));
53+
54+
mappings.put(rule.getString("id"), cwe);
55+
}
56+
}
57+
}
58+
59+
return mappings;
60+
}
61+
}
Lines changed: 37 additions & 100 deletions
Original file line numberDiff line numberDiff line change
@@ -1,121 +1,58 @@
1+
/**
2+
* OWASP Benchmark Project
3+
*
4+
* <p>This file is part of the Open Web Application Security Project (OWASP) Benchmark Project For
5+
* details, please see <a
6+
* href="https://owasp.org/www-project-benchmark/">https://owasp.org/www-project-benchmark/</a>.
7+
*
8+
* <p>The OWASP Benchmark is free software: you can redistribute it and/or modify it under the terms
9+
* of the GNU General Public License as published by the Free Software Foundation, version 2.
10+
*
11+
* <p>The OWASP Benchmark is distributed in the hope that it will be useful, but WITHOUT ANY
12+
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
13+
* PURPOSE. See the GNU General Public License for more details
14+
*
15+
* @author Raj Barath
16+
* @created 2023
17+
*/
118
package org.owasp.benchmarkutils.score.parsers;
219

20+
import static java.lang.Integer.parseInt;
21+
322
import java.util.HashMap;
423
import java.util.Map;
524
import org.json.JSONArray;
6-
import org.json.JSONException;
725
import org.json.JSONObject;
8-
import org.owasp.benchmarkutils.score.BenchmarkScore;
9-
import org.owasp.benchmarkutils.score.CweNumber;
10-
import org.owasp.benchmarkutils.score.ResultFile;
11-
import org.owasp.benchmarkutils.score.TestCaseResult;
12-
import org.owasp.benchmarkutils.score.TestSuiteResults;
13-
14-
public class SnykReader extends Reader {
1526

16-
public static final int INVALID_RULE_ID = -1;
17-
private static final Map<String, Integer> snykCweMap =
18-
new HashMap<String, Integer>() {
19-
{
20-
put("Xpath", CweNumber.XPATH_INJECTION);
21-
put("WebCookieWithSecureFalse", CweNumber.INSECURE_COOKIE);
22-
put("Sqli", CweNumber.SQL_INJECTION);
23-
put("PT", CweNumber.PATH_TRAVERSAL);
24-
put("HardcodedPassword", 0);
25-
put("NoHardcodedCredentials", 0);
26-
put("WebCookieMissesCallToSetHttpOnly", CweNumber.COOKIE_WITHOUT_HTTPONLY);
27-
put("ServerInformationExposure", 0);
28-
put("UserControlledFormatString", CweNumber.EXTERNALLY_CONTROLLED_STRING);
29-
put("SpringCSRF", CweNumber.CSRF);
30-
put("TrustBoundaryViolation", CweNumber.TRUST_BOUNDARY_VIOLATION);
31-
put("CommandInjection", CweNumber.COMMAND_INJECTION);
32-
put("EnvCommandInjection", CweNumber.COMMAND_INJECTION);
33-
put("DOMXSS", CweNumber.XSS);
34-
put("XSS", CweNumber.XSS);
35-
put("InsecureCipherNoIntegrity", CweNumber.WEAK_CRYPTO_ALGO);
36-
put("InsecureDefaultAesCipher", CweNumber.WEAK_CRYPTO_ALGO);
37-
put("HttpResponseSplitting", CweNumber.HTTP_RESPONSE_SPLITTING);
38-
put("InsecureSecret", CweNumber.WEAK_RANDOM);
39-
put("LdapInjection", CweNumber.LDAP_INJECTION);
40-
put("InsecureCipher", CweNumber.WEAK_CRYPTO_ALGO);
41-
put("InsecureHash", CweNumber.WEAK_HASH_ALGO);
42-
}
43-
};
27+
public class SnykReader extends SarifReader {
4428

4529
@Override
46-
public boolean canRead(ResultFile resultFile) {
47-
return resultFile.isJson() && isSnyk(resultFile);
30+
protected String expectedSarifToolName() {
31+
return "SnykCode";
4832
}
4933

5034
@Override
51-
public TestSuiteResults parse(ResultFile resultFile) throws Exception {
52-
TestSuiteResults tr = new TestSuiteResults("Snyk", true, TestSuiteResults.ToolType.SAST);
53-
54-
JSONArray results =
55-
resultFile.json().getJSONArray("runs").getJSONObject(0).getJSONArray("results");
56-
57-
for (int result = 0; result < results.length(); result++) {
58-
TestCaseResult tcr = parseSnykFindings(results.getJSONObject(result));
59-
if (tcr != null) {
60-
tr.put(tcr);
61-
}
62-
}
63-
return tr;
35+
protected boolean isCommercial() {
36+
return true;
6437
}
6538

66-
private TestCaseResult parseSnykFindings(JSONObject result) {
67-
try {
68-
String className =
69-
result.getJSONArray("locations")
70-
.getJSONObject(0)
71-
.getJSONObject("physicalLocation")
72-
.getJSONObject("artifactLocation")
73-
.getString("uri");
74-
className = (className.substring(className.lastIndexOf('/') + 1)).split("\\.")[0];
75-
if (className.startsWith(BenchmarkScore.TESTCASENAME)) {
76-
77-
TestCaseResult tcr = new TestCaseResult();
78-
79-
String ruleId = result.getString("ruleId");
80-
ruleId = (ruleId.substring(ruleId.lastIndexOf('/') + 1)).split("\\.")[0];
81-
82-
int cwe = snykCweMap.getOrDefault(ruleId, INVALID_RULE_ID);
83-
84-
if (cwe == INVALID_RULE_ID) {
85-
System.out.println("CWE # not parseable from: " + ruleId);
86-
return null;
87-
}
39+
@Override
40+
protected Map<String, Integer> ruleCweMappings(JSONArray rules) {
41+
Map<String, Integer> mappings = new HashMap<>();
8842

89-
String evidence = result.getJSONObject("message").getString("text");
43+
for (int i = 0; i < rules.length(); i++) {
44+
JSONObject rule = rules.getJSONObject(i);
9045

91-
tcr.setCWE(cwe);
92-
tcr.setCategory(ruleId);
93-
tcr.setEvidence(evidence);
94-
tcr.setConfidence(0);
95-
tcr.setNumber(testNumber(className));
46+
int cwe =
47+
parseInt(
48+
rule.getJSONObject("properties")
49+
.getJSONArray("cwe")
50+
.getString(0)
51+
.substring(4));
9652

97-
return tcr;
98-
}
99-
} catch (Exception ex) {
100-
ex.printStackTrace();
53+
mappings.put(rule.getString("id"), cwe);
10154
}
10255

103-
return null;
104-
}
105-
106-
private Boolean isSnyk(ResultFile resultFile) {
107-
108-
try {
109-
return resultFile
110-
.json()
111-
.getJSONArray("runs")
112-
.getJSONObject(0)
113-
.getJSONObject("tool")
114-
.getJSONObject("driver")
115-
.getString("name")
116-
.equalsIgnoreCase("SnykCode");
117-
} catch (JSONException e) {
118-
return false;
119-
}
56+
return mappings;
12057
}
12158
}
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
package org.owasp.benchmarkutils.score.builder;
2+
3+
import java.util.HashMap;
4+
import java.util.Map;
5+
import org.owasp.benchmarkutils.score.CategoryResults;
6+
import org.owasp.benchmarkutils.score.ToolResults;
7+
8+
public class ToolResultsBuilder {
9+
10+
private Map<String, CategoryResults> categoryResultsMap = new HashMap<>();
11+
12+
private ToolResultsBuilder() {}
13+
14+
public static ToolResultsBuilder builder() {
15+
return new ToolResultsBuilder();
16+
}
17+
18+
public ToolResults build() {
19+
return null;
20+
}
21+
22+
public ToolResultsBuilder setCategoryResults(Map<String, CategoryResults> categoryResultsMap) {
23+
this.categoryResultsMap = categoryResultsMap;
24+
25+
return this;
26+
}
27+
28+
public ToolResultsBuilder setCategoryResult(String key, CategoryResults value) {
29+
this.categoryResultsMap.put(key, value);
30+
31+
return this;
32+
}
33+
}

0 commit comments

Comments
 (0)