1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 package com.hack23.sonar.cloudformation.reports.process;
21
22 import java.io.File;
23 import java.io.IOException;
24 import java.nio.file.Files;
25 import java.util.List;
26 import java.util.Optional;
27
28 import org.apache.commons.lang3.StringUtils;
29 import org.sonar.api.batch.fs.FileSystem;
30 import org.sonar.api.batch.fs.InputFile;
31 import org.sonar.api.batch.rule.ActiveRules;
32 import org.sonar.api.batch.sensor.SensorContext;
33 import org.sonar.api.batch.sensor.issue.NewIssue;
34 import org.sonar.api.batch.sensor.issue.NewIssueLocation;
35 import org.sonar.api.rule.RuleKey;
36 import org.sonar.api.scan.filesystem.PathResolver;
37 import org.sonar.api.utils.log.Logger;
38 import org.sonar.api.utils.log.Loggers;
39
40 import com.hack23.sonar.cloudformation.reports.cfnnag.CfnNagScanReport;
41 import com.hack23.sonar.cloudformation.reports.cfnnag.CfnNagViolation;
42
43
44
45
46 public final class CfnNagProcessReports extends AbstractProcessReports {
47
48
49 public static final String UNDEFINED_FAILURE = "FUNDEFINED";
50
51
52 public static final String UNDEFINED_WARNING = "WUNDEFINED";
53
54
55 private static final Logger LOGGER = Loggers.get(CfnNagProcessReports.class);
56
57
58 private final CfnNagScanReportReader cfnNagScanReportReader;
59
60
61 private final PathResolver pathResolver;
62
63
64 private final FileSystem fileSystem;
65
66
67
68
69
70
71
72
73 public CfnNagProcessReports(final FileSystem fileSystem, final PathResolver pathResolver) {
74 super();
75 this.cfnNagScanReportReader = new CfnNagScanReportReader();
76 this.fileSystem = fileSystem;
77 this.pathResolver = pathResolver;
78 }
79
80
81
82
83
84
85
86
87 public void processCfnNagReport(final SensorContext context, final Optional<String> reportFilesProperty)
88 throws IOException {
89 if (reportFilesProperty.isPresent()) {
90
91 final String reports = reportFilesProperty.get();
92 final String[] reportFiles = StringUtils.split(reports, ",");
93
94 for (final String report : reportFiles) {
95 LOGGER.info("Processing cfn-nag :" + report);
96 if (pathResolver.relativeFile(fileSystem.baseDir(), report).exists()) {
97
98 handleCfnNagScanReports(context, report);
99 } else {
100 LOGGER.warn("Processing cfn-nag:" + report + " missing");
101 }
102 }
103 } else {
104 LOGGER.warn("Missing property:{}", CloudformationConstants.CFN_NAG_REPORT_FILES_PROPERTY);
105 }
106 }
107
108
109
110
111
112
113
114
115 private void handleCfnNagScanReports(final SensorContext context, final String report)
116 throws IOException {
117 LOGGER.info("Reading cfn-nag reports:{}", report);
118 final List<CfnNagScanReport> cfnNagscanReports = cfnNagScanReportReader
119 .readReport(Files.newInputStream(pathResolver.relativeFile(fileSystem.baseDir(), report).toPath()));
120
121 for (final CfnNagScanReport nagScanReport : cfnNagscanReports) {
122
123 final String filename = nagScanReport.getFilename();
124 LOGGER.info("Cfn-nag scanned file :{}", filename);
125
126 final InputFile templateInputFile = findTemplate(fileSystem,
127 filename.substring(filename.lastIndexOf(File.separator) + 1), filename);
128
129 final List<CfnNagViolation> violations = nagScanReport.getFileResults().getViolations();
130 for (final CfnNagViolation cfnNagViolation : violations) {
131 addIssue(context, cfnNagViolation, templateInputFile);
132 }
133 }
134 }
135
136
137
138
139
140
141
142
143 private static void addIssue(final SensorContext context, final CfnNagViolation violation,
144 final InputFile templateInputFile) {
145 final ActiveRules activeRules = context.activeRules();
146
147 if (templateInputFile != null) {
148
149 if (violation.getLineNumbers().isEmpty()) {
150 final NewIssue newIssue = context.newIssue().forRule(RuleKey.of("cloudformation-plugin-cfn", findRuleId(activeRules, violation)));
151 final NewIssueLocation location = newIssue.newLocation()
152 .on(templateInputFile)
153 .message(violation.getMessage());
154 newIssue.at(location).save();
155
156 } else {
157 final List<Integer> lineNumbers = violation.getLineNumbers();
158 for (final Integer line : lineNumbers) {
159 if (line != null && line >= 0) {
160 final NewIssue newIssue = context.newIssue().forRule(RuleKey.of("cloudformation-plugin-cfn", findRuleId(activeRules, violation)));
161 final NewIssueLocation location = newIssue.newLocation()
162 .on(templateInputFile).at(templateInputFile.selectLine(line))
163 .message(violation.getMessage());
164 newIssue.at(location).save();
165
166 } else {
167 final NewIssue newIssue = context.newIssue().forRule(RuleKey.of("cloudformation-plugin-cfn", findRuleId(activeRules, violation)));
168 final NewIssueLocation location = newIssue.newLocation()
169 .on(templateInputFile)
170 .message(violation.getMessage());
171 newIssue.at(location).save();
172 }
173 }
174 }
175 } else {
176 final NewIssue newIssue = context.newIssue().forRule(RuleKey.of("cloudformation-plugin-cfn", findRuleId(activeRules, violation)));
177 final NewIssueLocation location = newIssue.newLocation()
178 .on(context.project())
179 .message(violation.getMessage());
180 newIssue.at(location).save();
181 }
182 }
183
184
185
186
187
188
189
190
191 private static String findRuleId(final ActiveRules activeRules, final CfnNagViolation violation) {
192 final RuleKey ruleKey = RuleKey.of("cloudformation-plugin-cfn", violation.getId());
193
194 if (activeRules.find(ruleKey) != null) {
195 return violation.getId();
196 } else {
197 if (violation.getId().startsWith("W")) {
198 return UNDEFINED_WARNING;
199 } else {
200 return UNDEFINED_FAILURE;
201 }
202 }
203 }
204
205 }