forked from jenkinsci/analysis-model
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathClairParser.java
128 lines (114 loc) · 4.62 KB
/
ClairParser.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
package edu.hm.hafner.analysis.parser;
import java.io.IOException;
import java.io.Reader;
import java.util.Locale;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import org.json.JSONTokener;
import edu.hm.hafner.analysis.Issue;
import edu.hm.hafner.analysis.IssueBuilder;
import edu.hm.hafner.analysis.IssueParser;
import edu.hm.hafner.analysis.ParsingException;
import edu.hm.hafner.analysis.ReaderFactory;
import edu.hm.hafner.analysis.Report;
import edu.hm.hafner.analysis.Severity;
import edu.umd.cs.findbugs.annotations.Nullable;
/**
* A parser for clair scanner json output.
* <p>
* See <a href='https://github.com/arminc/clair-scanner'>clair-scanner</a> for project details.
*
* @author Andreas Mandel
*/
public class ClairParser extends IssueParser {
private static final long serialVersionUID = 42L;
@Override
public boolean accepts(final ReaderFactory readerFactory) {
return readerFactory.getFileName().endsWith(".json");
}
@Override
public Report parse(final ReaderFactory readerFactory) throws ParsingException {
final Report report = new Report();
try (Reader reader = readerFactory.create()) {
final JSONObject jsonReport = (JSONObject) new JSONTokener(reader).nextValue();
final String image = optStringIgnoreCase(jsonReport, "image");
final JSONArray vulnerabilities = optJsonArrayIgnoreCase(jsonReport, "vulnerabilities");
for (Object vulnerability : vulnerabilities) {
if (vulnerability instanceof JSONObject) {
report.add(convertToIssue((JSONObject) vulnerability, image));
}
}
}
catch (IOException | JSONException | ClassCastException e) {
throw new ParsingException(e);
}
return report;
}
private Issue convertToIssue(final JSONObject jsonIssue, @Nullable final String image) {
final StringBuilder message = new StringBuilder();
appendIfNotEmpty(jsonIssue, message, "featurename", "");
appendIfNotEmpty(jsonIssue, message, "featureversion", ":");
appendIfNotEmpty(jsonIssue, message, "description", "");
appendIfNotEmpty(jsonIssue, message, "fixedby", "Fixed by ");
appendIfNotEmpty(jsonIssue, message, "link", "see ");
return new IssueBuilder()
.setMessage(message.toString())
.setCategory(optStringIgnoreCase(jsonIssue, "vulnerability"))
.setSeverity(toSeverity(optStringIgnoreCase(jsonIssue, "severity")))
.setType(optStringIgnoreCase(jsonIssue, "namespace"))
.setFileName(image).build();
}
private void appendIfNotEmpty(final JSONObject issue, final StringBuilder message, final String key,
final String head) {
final String text = optStringIgnoreCase(issue, key);
if (text != null && !text.isEmpty()) {
if (message.length() > 0 && !":".equals(head)) {
message.append(' ');
}
message.append(head).append(text);
}
}
private Severity toSeverity(@Nullable final String level) {
switch (String.valueOf(level).toLowerCase(Locale.ENGLISH)) {
case "defcon1":
return Severity.ERROR;
case "critical":
return Severity.WARNING_HIGH;
case "high":
return Severity.WARNING_NORMAL;
default:
return Severity.WARNING_LOW;
}
}
private JSONArray optJsonArrayIgnoreCase(final JSONObject json, final String searchKey) {
final Object result = optIgnoreCase(json, searchKey);
return result instanceof JSONArray ? (JSONArray) result : new JSONArray();
}
@Nullable
private String optStringIgnoreCase(final JSONObject json, final String searchKey) {
final Object result = optIgnoreCase(json, searchKey);
return result instanceof String ? (String) result : null;
}
@Nullable
private Object optIgnoreCase(final JSONObject json, final String searchKey) {
Object result = json.opt(searchKey);
if (result == null) {
result = searchIgnoreCase(json, searchKey);
}
return result;
}
@Nullable
private Object searchIgnoreCase(final JSONObject json, final String searchKey) {
Object result = null;
for (String key : json.keySet()) {
if (key.equalsIgnoreCase(searchKey)) {
result = json.opt(key);
if (result != null) {
break;
}
}
}
return result;
}
}