Skip to content

Commit 4f28c77

Browse files
A parser for CFN-Nag JSON output (#1485)
1 parent b145f3f commit 4f28c77

8 files changed

Lines changed: 491 additions & 3 deletions

File tree

src/main/java/edu/hm/hafner/analysis/Severity.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -98,13 +98,13 @@ public static Severity valueOf(@CheckForNull final String severity, final Severi
9898
* @return mapped level.
9999
*/
100100
public static Severity guessFromString(@CheckForNull final String severity) {
101-
if (Strings.CI.containsAny(severity, "error", "severe", "critical", "fatal")) {
101+
if (Strings.CI.containsAny(severity, "error", "severe", "critical", "fatal", "fail")) {
102102
return ERROR;
103103
}
104104
if (Strings.CI.containsAny(severity, "info", "note", "low", "suggestion")) {
105105
return WARNING_LOW;
106106
}
107-
if (Strings.CI.containsAny(severity, "warning", "medium", "moderate")) {
107+
if (Strings.CI.containsAny(severity, "warn", "medium", "moderate")) {
108108
return WARNING_NORMAL;
109109
}
110110
if (Strings.CI.contains(severity, "high")) {
Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
package edu.hm.hafner.analysis.parser;
2+
3+
import org.json.JSONArray;
4+
import org.json.JSONObject;
5+
6+
import edu.hm.hafner.analysis.Issue;
7+
import edu.hm.hafner.analysis.IssueBuilder;
8+
import edu.hm.hafner.analysis.Report;
9+
import edu.umd.cs.findbugs.annotations.CheckForNull;
10+
11+
import java.io.Serial;
12+
13+
/**
14+
* A parser for CFN-Nag JSON output.
15+
*
16+
* @author Akash Manna
17+
* @see <a href="https://github.com/stelligent/cfn_nag">cfn_nag on GitHub</a>
18+
*/
19+
public class CfnNagParser extends JsonIssueParser {
20+
@Serial
21+
private static final long serialVersionUID = -3892714194841984933L;
22+
23+
private static final String FILE_NAME = "filename";
24+
private static final String FILE_RESULTS = "file_results";
25+
private static final String VIOLATIONS = "violations";
26+
private static final String ID = "id";
27+
private static final String TYPE = "type";
28+
private static final String MESSAGE = "message";
29+
private static final String LOGICAL_RESOURCE_IDS = "logical_resource_ids";
30+
private static final String LINE_NUMBERS = "line_numbers";
31+
32+
@Override
33+
protected void parseJsonObject(final Report report, final JSONObject jsonReport, final IssueBuilder issueBuilder) {
34+
addIssues(jsonReport, issueBuilder, report);
35+
}
36+
37+
@Override
38+
protected void parseJsonArray(final Report report, final JSONArray jsonReport, final IssueBuilder issueBuilder) {
39+
for (int i = 0; i < jsonReport.length(); i++) {
40+
var issueContainer = jsonReport.optJSONObject(i);
41+
if (issueContainer != null) {
42+
addIssues(issueContainer, issueBuilder, report);
43+
}
44+
}
45+
}
46+
47+
private void addIssues(final JSONObject issueContainer, final IssueBuilder issueBuilder, final Report report) {
48+
var fileResults = issueContainer.optJSONObject(FILE_RESULTS);
49+
if (fileResults == null) {
50+
return;
51+
}
52+
53+
var violations = fileResults.optJSONArray(VIOLATIONS);
54+
if (violations == null) {
55+
return;
56+
}
57+
58+
var fileName = issueContainer.optString(FILE_NAME);
59+
for (int i = 0; i < violations.length(); i++) {
60+
var violation = violations.optJSONObject(i);
61+
if (violation != null) {
62+
report.add(convertToIssue(violation, fileName, issueBuilder));
63+
}
64+
}
65+
}
66+
67+
private Issue convertToIssue(final JSONObject violation, final String fileName, final IssueBuilder issueBuilder) {
68+
issueBuilder.setFileName(fileName)
69+
.setType(violation.optString(ID, "-"))
70+
.setMessage(violation.optString(MESSAGE))
71+
.guessSeverity(violation.optString(TYPE));
72+
73+
applyLineNumbers(violation.optJSONArray(LINE_NUMBERS), issueBuilder);
74+
applyLogicalResourceIds(violation.optJSONArray(LOGICAL_RESOURCE_IDS), issueBuilder);
75+
76+
return issueBuilder.buildAndClean();
77+
}
78+
79+
private void applyLineNumbers(@CheckForNull final JSONArray lineNumbers, final IssueBuilder issueBuilder) {
80+
if (lineNumbers == null || lineNumbers.isEmpty()) {
81+
return;
82+
}
83+
84+
var lineStart = lineNumbers.optInt(0, 0);
85+
var lineEnd = lineNumbers.optInt(lineNumbers.length() - 1, lineStart);
86+
87+
issueBuilder.setLineStart(lineStart).setLineEnd(lineEnd);
88+
}
89+
90+
private void applyLogicalResourceIds(@CheckForNull final JSONArray logicalResourceIds,
91+
final IssueBuilder issueBuilder) {
92+
if (logicalResourceIds == null || logicalResourceIds.isEmpty()) {
93+
return;
94+
}
95+
96+
var resources = new StringBuilder();
97+
for (int i = 0; i < logicalResourceIds.length(); i++) {
98+
var id = logicalResourceIds.optString(i);
99+
if (id.isBlank()) {
100+
continue;
101+
}
102+
103+
if (!resources.isEmpty()) {
104+
resources.append(", ");
105+
}
106+
resources.append(id);
107+
}
108+
109+
if (!resources.isEmpty()) {
110+
issueBuilder.setDescription("Logical resource ID(s): " + resources);
111+
}
112+
}
113+
}
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
package edu.hm.hafner.analysis.registry;
2+
3+
import edu.hm.hafner.analysis.IssueParser;
4+
import edu.hm.hafner.analysis.parser.CfnNagParser;
5+
6+
/**
7+
* A descriptor for CFN-Nag JSON reports.
8+
*
9+
* @author Akash Manna
10+
*/
11+
class CfnNagDescriptor extends ParserDescriptor {
12+
private static final String ID = "cfn-nag";
13+
private static final String NAME = "CFN-Nag";
14+
15+
CfnNagDescriptor() {
16+
super(ID, NAME);
17+
}
18+
19+
@Override
20+
public IssueParser create(final Option... options) {
21+
return new CfnNagParser();
22+
}
23+
24+
@Override
25+
public String getPattern() {
26+
return "**/cfn-nag-report.json";
27+
}
28+
29+
@Override
30+
public String getHelp() {
31+
return "Use commandline <code>cfn_nag_scan --input-path . --output-format json</code> "
32+
+ "to generate JSON output.<br/>"
33+
+ "See <a href='https://github.com/stelligent/cfn_nag'>cfn_nag on GitHub</a> for usage details.";
34+
}
35+
36+
@Override
37+
public String getUrl() {
38+
return "https://github.com/stelligent/cfn_nag";
39+
}
40+
}

src/main/java/edu/hm/hafner/analysis/registry/ParserRegistry.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ public class ParserRegistry {
5151
new CargoClippyDescriptor(),
5252
new CcmDescriptor(),
5353
new CfnLintDescriptor(),
54+
new CfnNagDescriptor(),
5455
new CheckovDescriptor(),
5556
new CheckStyleDescriptor(),
5657
new ClairDescriptor(),

0 commit comments

Comments
 (0)