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.fs.TextPointer;
32 import org.sonar.api.batch.rule.ActiveRules;
33 import org.sonar.api.batch.sensor.SensorContext;
34 import org.sonar.api.batch.sensor.issue.NewIssue;
35 import org.sonar.api.batch.sensor.issue.NewIssueLocation;
36 import org.sonar.api.rule.RuleKey;
37 import org.sonar.api.scan.filesystem.PathResolver;
38 import org.sonar.api.utils.log.Logger;
39 import org.sonar.api.utils.log.Loggers;
40
41 import com.hack23.sonar.cloudformation.reports.checkov.CheckovPassedCheck;
42 import com.hack23.sonar.cloudformation.reports.checkov.CheckovReport;
43
44
45
46
47 public final class CheckovProcessReports extends AbstractProcessReports {
48
49
50 public static final String SENSOR_NAME = "Cloudformation Check";
51
52
53 private static final Logger LOGGER = Loggers.get(CheckovProcessReports.class);
54
55
56 private final CheckovReportReader checkovReportReader;
57
58
59 private final PathResolver pathResolver;
60
61
62 private final FileSystem fileSystem;
63
64
65
66
67
68
69
70 public CheckovProcessReports(final FileSystem fileSystem,
71 final PathResolver pathResolver) {
72 super();
73 this.checkovReportReader = new CheckovReportReader();
74 this.fileSystem = fileSystem;
75 this.pathResolver = pathResolver;
76 }
77
78
79
80
81
82
83
84
85 public void processCheckovReport(final SensorContext context,final Optional<String> reportFilesProperty) throws IOException {
86 if (reportFilesProperty.isPresent()) {
87
88 final String reports = reportFilesProperty.get();
89 LOGGER.info(CloudformationConstants.CHECKOV_REPORT_FILES_PROPERTY + "=" + reports);
90 final String[] reportFiles = StringUtils.split(reports, ",");
91
92 for (final String report : reportFiles) {
93 LOGGER.info("Processing checkov :" + report);
94 if (pathResolver.relativeFile(fileSystem.baseDir(), report).exists()) {
95 handleCheckovReports(context, report);
96 } else {
97 LOGGER.warn("Processing checkov:" + report + " missing");
98 }
99 }
100 } else {
101 LOGGER.warn("Missing property:{}", CloudformationConstants.CHECKOV_REPORT_FILES_PROPERTY);
102 }
103 }
104
105
106
107
108
109
110
111
112
113 private void handleCheckovReports(final SensorContext context, final String report) throws IOException {
114 LOGGER.info("Reading checkov reports:{}", report);
115
116 final List<CheckovReport> checkovReportList = checkovReportReader
117 .readReport(Files.newInputStream(pathResolver.relativeFile(fileSystem.baseDir(), report).toPath()));
118
119
120 for (final CheckovReport checkovReport : checkovReportList) {
121
122 final ActiveRules activeRules = context.activeRules();
123 for (final CheckovPassedCheck failedChecks : checkovReport.getResults().getFailedChecks()) {
124 final String filename = failedChecks.getFilePath();
125 LOGGER.info("Checkov scanned file :{}", filename);
126
127 final InputFile templateInputFile = findTemplate(fileSystem,
128 filename.substring(filename.lastIndexOf(File.separator) + 1), filename);
129
130 addCheckovIssue(context, activeRules, checkovReport, failedChecks, templateInputFile);
131 }
132 }
133 }
134
135
136
137
138
139
140
141
142
143
144 private static void addCheckovIssue(final SensorContext context, final ActiveRules activeRules, final CheckovReport checkovReport,
145 final CheckovPassedCheck failedChecks, final InputFile templateInputFile) {
146
147 String repoName = "cloudformation-plugin-cfn";
148 if (templateInputFile != null && "terraform".equalsIgnoreCase(templateInputFile.language())) {
149 repoName = "cloudformation-plugin-terraform";
150 }
151
152 final RuleKey ruleKey = RuleKey.of(repoName,checkovReport.getCheckType() + "-" + failedChecks.getCheckId());
153
154 if (activeRules.find(ruleKey) == null) {
155 LOGGER.warn("No active checkov rule detected for:'{}' with key {} detected in {}",failedChecks.getCheckName(), ruleKey,failedChecks.getFilePath());
156 return;
157 }
158
159 if (templateInputFile == null) {
160 LOGGER.warn("File not found {} for rule {} issue not created", failedChecks.getFilePath(), ruleKey);
161 return;
162 }
163
164 final List<Integer> lineNumbers = failedChecks.getFileLineRange();
165 if(!lineNumbers.isEmpty()) {
166 final TextPointer startLine = templateInputFile.selectLine(lineNumbers.get(0)).start();
167 final TextPointer endLine = templateInputFile.selectLine(lineNumbers.get(lineNumbers.size()-1)).end();
168 final NewIssue newIssue = context.newIssue().forRule(ruleKey);
169
170 final NewIssueLocation location = newIssue.newLocation()
171 .on(templateInputFile).at(templateInputFile.newRange(startLine, endLine))
172 .message(failedChecks.getCheckName());
173 newIssue.at(location).save();
174 }
175 }
176
177
178 }