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+ }
0 commit comments