1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 package org.owasp.dependencycheck.maven;
19
20 import java.io.File;
21 import java.util.ArrayList;
22 import java.util.Collections;
23 import java.util.HashMap;
24 import java.util.HashSet;
25 import java.util.List;
26 import java.util.Locale;
27 import java.util.Map;
28 import java.util.Set;
29 import java.util.logging.Level;
30 import java.util.logging.Logger;
31 import org.apache.maven.plugin.MojoExecutionException;
32 import org.apache.maven.plugin.MojoFailureException;
33 import org.apache.maven.plugins.annotations.LifecyclePhase;
34 import org.apache.maven.plugins.annotations.Mojo;
35 import org.apache.maven.plugins.annotations.ResolutionScope;
36 import org.apache.maven.project.MavenProject;
37 import org.owasp.dependencycheck.analyzer.DependencyBundlingAnalyzer;
38 import org.owasp.dependencycheck.analyzer.exception.AnalysisException;
39 import org.owasp.dependencycheck.data.nvdcve.DatabaseException;
40 import org.owasp.dependencycheck.dependency.Dependency;
41 import org.owasp.dependencycheck.utils.Settings;
42
43
44
45
46
47
48
49 @Mojo(
50 name = "aggregate",
51 defaultPhase = LifecyclePhase.SITE,
52 aggregator = true,
53 threadSafe = true,
54 requiresDependencyResolution = ResolutionScope.COMPILE_PLUS_RUNTIME,
55 requiresOnline = true
56 )
57 public class AggregateMojo extends BaseDependencyCheckMojo {
58
59
60
61
62 private static final Logger LOGGER = Logger.getLogger(AggregateMojo.class.getName());
63
64
65
66
67
68
69
70 @Override
71 public void runCheck() throws MojoExecutionException, MojoFailureException {
72 final Engine engine = generateDataFile();
73
74 if (getProject() == getReactorProjects().get(getReactorProjects().size() - 1)) {
75 final Map<MavenProject, Set<MavenProject>> children = buildAggregateInfo();
76 boolean hasOrchestration = false;
77 for (MavenProject current : getReactorProjects()) {
78 final List<Dependency> dependencies = readDataFile(current);
79 final List<MavenProject> childProjects = getAllChildren(current, children);
80
81 if ((dependencies == null || dependencies.isEmpty()) && childProjects.isEmpty() && current.isExecutionRoot()) {
82 hasOrchestration = true;
83 }
84 }
85
86 for (MavenProject current : getReactorProjects()) {
87 List<Dependency> dependencies = readDataFile(current);
88 final List<MavenProject> childProjects = getAllChildren(current, children);
89
90 if ((dependencies == null || dependencies.isEmpty()) && childProjects.isEmpty() && current.isExecutionRoot()) {
91 engine.resetFileTypeAnalyzers();
92 for (MavenProject mod : getReactorProjects()) {
93 scanArtifacts(mod, engine);
94 }
95 engine.analyzeDependencies();
96 } else {
97 if (dependencies == null) {
98 dependencies = new ArrayList<Dependency>();
99 }
100 for (MavenProject reportOn : childProjects) {
101 final List<Dependency> childDeps = readDataFile(reportOn);
102 if (childDeps != null && !childDeps.isEmpty()) {
103 dependencies.addAll(childDeps);
104 }
105 }
106 engine.getDependencies().clear();
107 engine.getDependencies().addAll(dependencies);
108 final DependencyBundlingAnalyzer bundler = new DependencyBundlingAnalyzer();
109 try {
110 bundler.analyze(null, engine);
111 } catch (AnalysisException ex) {
112 LOGGER.log(Level.WARNING, "An error occured grouping the dependencies; duplicate entries may exist in the report", ex);
113 LOGGER.log(Level.FINE, "Bundling Exception", ex);
114 }
115 }
116 try {
117 final File outputDir = getCorrectOutputDirectory(current);
118 writeReports(engine, current, outputDir);
119 } catch (MojoExecutionException ex) {
120 if (!hasOrchestration) {
121 throw ex;
122 }
123 }
124 }
125 }
126 engine.cleanup();
127 Settings.cleanup();
128 }
129
130
131
132
133
134
135
136
137 protected List<MavenProject> getAllChildren(MavenProject project, Map<MavenProject, Set<MavenProject>> childMap) {
138 final Set<MavenProject> children = childMap.get(project);
139 if (children == null) {
140 return Collections.emptyList();
141 }
142 final List<MavenProject> result = new ArrayList<MavenProject>();
143 for (MavenProject child : children) {
144 if (isMultiModule(child)) {
145 result.addAll(getAllChildren(child, childMap));
146 } else {
147 result.add(child);
148 }
149 }
150 return result;
151 }
152
153
154
155
156
157
158
159 protected boolean isMultiModule(MavenProject mavenProject) {
160 return "pom".equals(mavenProject.getPackaging());
161 }
162
163
164
165
166
167
168 private Map<MavenProject, Set<MavenProject>> buildAggregateInfo() {
169 final Map<MavenProject, Set<MavenProject>> parentChildMap = new HashMap<MavenProject, Set<MavenProject>>();
170 for (MavenProject proj : getReactorProjects()) {
171 Set<MavenProject> depList = parentChildMap.get(proj.getParent());
172 if (depList == null) {
173 depList = new HashSet<MavenProject>();
174 parentChildMap.put(proj.getParent(), depList);
175 }
176 depList.add(proj);
177 }
178 return parentChildMap;
179 }
180
181
182
183
184
185
186
187
188
189 protected Engine generateDataFile() throws MojoExecutionException, MojoFailureException {
190 final Engine engine;
191 try {
192 engine = initializeEngine();
193 } catch (DatabaseException ex) {
194 LOGGER.log(Level.FINE, "Database connection error", ex);
195 throw new MojoExecutionException("An exception occured connecting to the local database. Please see the log file for more details.", ex);
196 }
197 scanArtifacts(getProject(), engine);
198 engine.analyzeDependencies();
199 writeDataFile(engine.getDependencies());
200 showSummary(engine.getDependencies());
201 checkForFailure(engine.getDependencies());
202 return engine;
203 }
204
205 @Override
206 public boolean canGenerateReport() {
207 return true;
208 }
209
210
211
212
213
214
215
216 public String getName(Locale locale) {
217 return "dependency-check:aggregate";
218 }
219
220
221
222
223
224
225
226 public String getDescription(Locale locale) {
227 return "Generates an aggregate report of all child Maven projects providing details on any "
228 + "published vulnerabilities within project dependencies. This report is a best "
229 + "effort and may contain false positives and false negatives.";
230 }
231 }