Compare commits

..

45 Commits

Author SHA1 Message Date
Jeremy Long
cc2953d6a3 version 1.2.8
Former-commit-id: 8c68d365e0dd05957ad26273a635dbb2c6a8871a
2014-12-28 09:26:14 -05:00
Jeremy Long
c888019068 added link to the documentation on the Central Analyzer
Former-commit-id: dc4553820a6c5907760e100e95379360492cc056
2014-12-28 09:16:01 -05:00
Jeremy Long
56639d3965 updated information about the nexus analyzer and how it relates to the central analyzer
Former-commit-id: 9d3f9b4f3ea30744f6f8f8c2883fc9d8b0be3a0d
2014-12-28 09:15:34 -05:00
Jeremy Long
09ff99823e added information about the central analyzer
Former-commit-id: a01e805f5692b0db9b6260a0385271c60116b7b9
2014-12-28 09:15:07 -05:00
Jeremy Long
5078e32dc7 updated the documentation showing the aggregate goal instead of the aggregate property
Former-commit-id: 81e2b937c98ec3e87a53ed0573885359ff448c2a
2014-12-28 09:14:39 -05:00
Jeremy Long
ecaadff0d8 added documentation regarding disabling the central analyzer and that the aggregate property has been replaced by the aggregate goal
Former-commit-id: 01d67e8ceeae8ab6c0bec54a694cf39d6688a0b7
2014-12-28 09:13:35 -05:00
Jeremy Long
f2ad8cc7d1 added the ability to disable the Central Analyzer (issue #175)
Former-commit-id: e56475fdf3dc94ea60b7acf8badd6a23197881d5
2014-12-28 09:12:22 -05:00
Jeremy Long
c8d77eb213 added documentation about disabling the central analyzer
Former-commit-id: 62ac08aa90599f8c624f4d928bd77528e0676208
2014-12-28 09:11:55 -05:00
Jeremy Long
fe3d9e8bf6 added the ability to disable the Central Analyzer (issue #175)
Former-commit-id: f154f7ab2eec81a90290ee38cb2ecb823f056216
2014-12-28 09:11:30 -05:00
Jeremy Long
6c4171be75 added documentation about disabling the central analyzer
Former-commit-id: b5773b6b4877b16f8b5b92640a55ad96e2ae1295
2014-12-28 09:10:54 -05:00
Jeremy Long
4bbb466e43 added the ability to disable the Central Analyzer (issue #175)
Former-commit-id: f9c25a4f2e7680026d8124623c3f2d2ae316bb67
2014-12-28 09:10:17 -05:00
Jeremy Long
c478415667 initial version
Former-commit-id: cf662ed17ec8b525dcef9826021c3a3be92a0c47
2014-12-28 06:46:39 -05:00
Jeremy Long
fc832b67c5 made BaseTest public
Former-commit-id: d18c65e8485e0c32e15a3b399ffb5f9a3618fb9a
2014-12-28 06:44:08 -05:00
Jeremy Long
943a9ea97e added synchonization to the open method
Former-commit-id: 8be1fcc1b96744dbf4d4f5754f2402be33ed4032
2014-12-28 06:43:45 -05:00
Jeremy Long
2c7ab297d7 removed serialization as Lucene's classes are not serializable
Former-commit-id: 06758ffeca109cb558ca2ac567672153cca71b50
2014-12-28 06:43:11 -05:00
Jeremy Long
d8299f7db1 checkstyle correction
Former-commit-id: a517ce0a86a30e5ffdf1edfa80958d016fe98f56
2014-12-27 07:39:55 -05:00
Jeremy Long
4deeb33f08 added JavaDoc to resetFileTypeAnalzyers()
Former-commit-id: 7feb30ff1750684d60d69a01c76733df0d32b62c
2014-12-27 06:57:21 -05:00
Jeremy Long
3bf4cf8c85 corrected logging statements
Former-commit-id: 55ebf05bbf831c8e87ca8f5b9b74d18e1cfa252c
2014-12-27 06:55:21 -05:00
Jeremy Long
e0217fc6c3 checkstyle correction
Former-commit-id: 0bc46c51151eca7d8b6c0abff3b7b9a47cb0529f
2014-12-27 06:52:37 -05:00
Jeremy Long
62a3efa23a Corrected duplicate code identified by CPD
Former-commit-id: 223a20b4a61a69a6dd0714e1683633dd73eb4302
2014-12-27 06:52:14 -05:00
Jeremy Long
cc7ebe6d52 removed old, unused test cases
Former-commit-id: 57e354d428df6eeed595afddc08359d72bef3067
2014-12-27 06:44:17 -05:00
Jeremy Long
5d920e4b44 added BaseTest to initialize the Settings for tests in the maven-plugin
Former-commit-id: 7da3f4712abcbebf157c8d26174cf0fe2f19f12b
2014-12-27 06:44:03 -05:00
Jeremy Long
1264ea54a1 moved setup to a base test that can be used in other test classes later
Former-commit-id: fe87e1ce9e9230e628bb5b8e90b0c2e85acd8245
2014-12-27 06:42:58 -05:00
Jeremy Long
caa1d77d23 improved error messages to resolve issue #176
Former-commit-id: 57d4e59b50aab93124f321004d05239cd9cd5c3d
2014-12-27 06:23:10 -05:00
Jeremy Long
20a55b3342 added test case
Former-commit-id: 4b24fb1a31b103c56c51f99d1c6e1aaa05c73a4b
2014-12-26 07:11:30 -05:00
Jeremy Long
8bfe67fc60 additional error handling, checkstyle corrections, and added resetFileTypeAnalyzers to enable reuse of the engine as part of resolution to issue #173
Former-commit-id: b964d2fd30a5520abb732a6768b9e89ba3978749
2014-12-26 07:10:22 -05:00
Jeremy Long
d42a1c6ab1 added a scan artifacts method to enable scanning of a MavenProject as part of resolution for issue #173
Former-commit-id: 7db9d35d2b0327ed678502bd8ad3c9050613eefb
2014-12-26 07:09:11 -05:00
Jeremy Long
80a89ef6d1 additional changes to resolve issue #173
Former-commit-id: 30edb64043b45c028aea77ec172d1ed127672a45
2014-12-26 07:07:27 -05:00
Jeremy Long
1a0e605f0c added jmockit for testing
Former-commit-id: 5fe09b31551fac79670505f709c0b0783431d8a8
2014-12-26 07:06:38 -05:00
Jeremy Long
573c8eb509 added a reset() method as part of resolution for issue #173
Former-commit-id: b07e6a477ebd1b008f9be6f249a531fcb911865a
2014-12-26 07:06:16 -05:00
Jeremy Long
e676e3a14b added a reset method to re-enable the file type analyzers so the engine could be reused to scan files as part of resolution for issue #173
Former-commit-id: 4b2cca05cf9724d58e3a8a7970eb2d05bb553346
2014-12-26 07:05:48 -05:00
Jeremy Long
af8c807ee0 added a getter for the FileTypeAnalyzers to resolve a problem while fixing issue #173
Former-commit-id: 359b9e41a03bd2bd0c9c63e437540bf082c7c92d
2014-12-26 07:04:45 -05:00
Jeremy Long
dfaa5df965 re-enabled summary and fail build on CVSS scores
Former-commit-id: f4568c46bfd2933aebf3e8bfe270749846fc4c01
2014-12-24 08:34:05 -05:00
Jeremy Long
32055ecdcc updated error message
Former-commit-id: 1dff15f05f6380565b2df230093bccbeb4cbbe25
2014-12-24 08:07:07 -05:00
Jeremy Long
9db71c5f0c replaced with new classes
Former-commit-id: 2b09e2533af5748b2ff41b551482bef8e012e2fe
2014-12-24 07:59:25 -05:00
Jeremy Long
99856bf285 cleaned up maven report aggregration by removing the aggregate configuration and creating an aggregate goal
Former-commit-id: bba05b6052a2b2347b055884ffdf678d7ed8f17f
2014-12-24 07:58:53 -05:00
Jeremy Long
4d006b3e05 updated to resolve class loading issues with CPEAnalyzer and updated to use execution root instead of root parent project to store context flags
Former-commit-id: 948ce11556e157e3d127be8f04cc2e4abfba2712
2014-12-24 07:47:22 -05:00
Jeremy Long
4e37165ba6 fixed bug that prevented verbose logging when target directory does not exisst
Former-commit-id: 442092011e791576ce629091a6bee4fb45c43b7d
2014-12-24 07:42:24 -05:00
Jeremy Long
38a5834785 added type checking for CPEAnalyzer to avoid exceptions
Former-commit-id: 6f407c839f4c2f74900f46901f4a8452abe83e06
2014-12-17 11:25:16 -05:00
Jeremy Long
d6e1352869 made serializable
Former-commit-id: e826b6b05017739cc35641dcdd882e4c62946a12
2014-12-17 11:24:46 -05:00
Jeremy Long
bf1b7bd7a2 added logging statements
Former-commit-id: 399ad8e258b88b32eecf9082b62bc27c4387c64a
2014-12-17 11:16:13 -05:00
Jeremy Long
2306327057 added logging
Former-commit-id: ab39408750a77fb70d05b7115bf6c6ace4f7ff52
2014-12-17 11:15:32 -05:00
Jeremy Long
2d389ba73f updated to version 1.2.8-SNAPSHOT
Former-commit-id: d8c12eae66b9fa54188ebde2da3323a132a4d9d2
2014-12-09 06:38:26 -05:00
Jeremy Long
ce8d5bc635 hack resolution to issue #172 - more information is needed to fully resolve the issue though
Former-commit-id: 366299924689cca0e277fd82b9f7bd40b9c19490
2014-12-09 06:36:04 -05:00
Jeremy Long
8fdc2007e0 fixed unit test
Former-commit-id: e1571c23fc236d810b60037f9cd8f7a804b69195
2014-12-09 06:35:07 -05:00
37 changed files with 1140 additions and 2215 deletions

View File

@@ -20,7 +20,7 @@ Copyright (c) 2013 - Jeremy Long. All Rights Reserved.
<parent>
<groupId>org.owasp</groupId>
<artifactId>dependency-check-parent</artifactId>
<version>1.2.7</version>
<version>1.2.8</version>
</parent>
<artifactId>dependency-check-ant</artifactId>

View File

@@ -559,6 +559,28 @@ public class DependencyCheckTask extends Task {
public void setNuspecAnalyzerEnabled(boolean nuspecAnalyzerEnabled) {
this.nuspecAnalyzerEnabled = nuspecAnalyzerEnabled;
}
/**
* Whether or not the central analyzer is enabled.
*/
private boolean centralAnalyzerEnabled = false;
/**
* Get the value of centralAnalyzerEnabled
*
* @return the value of centralAnalyzerEnabled
*/
public boolean isCentralAnalyzerEnabled() {
return centralAnalyzerEnabled;
}
/**
* Set the value of centralAnalyzerEnabled
*
* @param centralAnalyzerEnabled new value of centralAnalyzerEnabled
*/
public void setCentralAnalyzerEnabled(boolean centralAnalyzerEnabled) {
this.centralAnalyzerEnabled = centralAnalyzerEnabled;
}
/**
* Whether or not the nexus analyzer is enabled.
@@ -1015,6 +1037,8 @@ public class DependencyCheckTask extends Task {
Settings.setBoolean(Settings.KEYS.ANALYZER_JAR_ENABLED, jarAnalyzerEnabled);
//NUSPEC ANALYZER
Settings.setBoolean(Settings.KEYS.ANALYZER_NUSPEC_ENABLED, nuspecAnalyzerEnabled);
//CENTRAL ANALYZER
Settings.setBoolean(Settings.KEYS.ANALYZER_CENTRAL_ENABLED, centralAnalyzerEnabled);
//NEXUS ANALYZER
Settings.setBoolean(Settings.KEYS.ANALYZER_NEXUS_ENABLED, nexusAnalyzerEnabled);
if (nexusUrl != null && !nexusUrl.isEmpty()) {

View File

@@ -50,8 +50,9 @@ Property | Description
------------------------|---------------------------------------------------------------------------|------------------
archiveAnalyzerEnabled | Sets whether the Archive Analyzer will be used. | true
zipExtensions | A comma-separated list of additional file extensions to be treated like a ZIP file, the contents will be extracted and analyzed. | &nbsp;
jarAnalyzer | Sets whether Jar Analyzer will be used. | true
nexusAnalyzerEnabled | Sets whether Nexus Analyzer will be used. | true
jarAnalyzer | Sets whether the Jar Analyzer will be used. | true
centralAnalyzerEnabled | Sets whether the Central Analyzer will be used. If this analyzer is being disabled there is a good chance you also want to disable the Nexus Analyzer (see below). | true
nexusAnalyzerEnabled | Sets whether Nexus Analyzer will be used. This analyzer is superceded by the Central Analyzer; however, you can configure this to run against a Nexus Pro installation. | true
nexusUrl | Defines the Nexus Pro URL. If not set the Nexus Analyzer will be disabled. | &nbsp;
nexusUsesProxy | Whether or not the defined proxy should be used when connecting to Nexus. | true
nuspecAnalyzerEnabled | Sets whether or not the .NET Nuget Nuspec Analyzer will be used. | true

View File

@@ -20,7 +20,7 @@ Copyright (c) 2012 - Jeremy Long. All Rights Reserved.
<parent>
<groupId>org.owasp</groupId>
<artifactId>dependency-check-parent</artifactId>
<version>1.2.7</version>
<version>1.2.8</version>
</parent>
<artifactId>dependency-check-cli</artifactId>

View File

@@ -233,6 +233,7 @@ public class App {
final boolean archiveDisabled = cli.isArchiveDisabled();
final boolean assemblyDisabled = cli.isAssemblyDisabled();
final boolean nuspecDisabled = cli.isNuspecDisabled();
final boolean centralDisabled = cli.isCentralDisabled();
final boolean nexusDisabled = cli.isNexusDisabled();
final String nexusUrl = cli.getNexusUrl();
final String databaseDriverName = cli.getDatabaseDriverName();
@@ -298,6 +299,7 @@ public class App {
Settings.setBoolean(Settings.KEYS.ANALYZER_NUSPEC_ENABLED, !nuspecDisabled);
Settings.setBoolean(Settings.KEYS.ANALYZER_ASSEMBLY_ENABLED, !assemblyDisabled);
Settings.setBoolean(Settings.KEYS.ANALYZER_CENTRAL_ENABLED, !centralDisabled);
Settings.setBoolean(Settings.KEYS.ANALYZER_NEXUS_ENABLED, !nexusDisabled);
if (nexusUrl != null && !nexusUrl.isEmpty()) {
Settings.setString(Settings.KEYS.ANALYZER_NEXUS_URL, nexusUrl);

View File

@@ -323,6 +323,10 @@ public final class CliParser {
.withDescription("Disable the .NET Assembly Analyzer.")
.create();
final Option disableCentralAnalyzer = OptionBuilder.withLongOpt(ARGUMENT.DISABLE_CENTRAL)
.withDescription("Disable the Central Analyzer. If this analyzer is disabled it is likely you also want to disable the Nexus Analyzer.")
.create();
final Option disableNexusAnalyzer = OptionBuilder.withLongOpt(ARGUMENT.DISABLE_NEXUS)
.withDescription("Disable the Nexus Analyzer.")
.create();
@@ -360,6 +364,7 @@ public final class CliParser {
.addOption(disableArchiveAnalyzer)
.addOption(disableAssemblyAnalyzer)
.addOption(disableNuspecAnalyzer)
.addOption(disableCentralAnalyzer)
.addOption(disableNexusAnalyzer)
.addOption(nexusUrl)
.addOption(nexusUsesProxy)
@@ -456,6 +461,15 @@ public final class CliParser {
return (line != null) && line.hasOption(ARGUMENT.DISABLE_NEXUS);
}
/**
* Returns true if the disableCentral command line argument was specified.
*
* @return true if the disableCentral command line argument was specified; otherwise false
*/
public boolean isCentralDisabled() {
return (line != null) && line.hasOption(ARGUMENT.DISABLE_CENTRAL);
}
/**
* Returns the url to the nexus server if one was specified.
*
@@ -876,6 +890,10 @@ public final class CliParser {
* Disables the Nuspec Analyzer.
*/
public static final String DISABLE_NUSPEC = "disableNuspec";
/**
* Disables the Central Analyzer.
*/
public static final String DISABLE_CENTRAL = "disableCentral";
/**
* Disables the Nexus Analyzer.
*/

View File

@@ -23,8 +23,9 @@ Short | Argument&nbsp;Name&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; | Paramete
-------|-----------------------|-----------------|-----------------------------------------------------------------------------|---------------
| \-\-disableArchive | | Sets whether the Archive Analyzer will be used. | false
| \-\-zipExtensions | \<strings\> | A comma-separated list of additional file extensions to be treated like a ZIP file, the contents will be extracted and analyzed. | &nbsp;
| \-\-disableJar | | Sets whether Jar Analyzer will be used. | false
| \-\-disableNexus | | Sets whether Nexus Analyzer will be used. | false
| \-\-disableJar | | Sets whether the Jar Analyzer will be used. | false
| \-\-disableCentral | | Sets whether the Central Analyzer will be used. If this analyzer is being disabled there is a good chance you also want to disable the Nexus Analyzer. | false
| \-\-disableNexus | | Sets whether the Nexus Analyzer will be used. Note, this has been superceded by the Central Analyzer. However, you can configure the Nexus URL to utilize an internally hosted Nexus Pro server. | false
| \-\-nexus | \<url\> | The url to the Nexus Pro Server. If not set the Nexus Analyzer will be disabled. | &nbsp;
| \-\-nexusUsesProxy | \<true\|false\> | Whether or not the defined proxy should be used when connecting to Nexus. | true
| \-\-disableNuspec | | Sets whether or not the .NET Nuget Nuspec Analyzer will be used. | false

View File

@@ -20,7 +20,7 @@ Copyright (c) 2012 Jeremy Long. All Rights Reserved.
<parent>
<groupId>org.owasp</groupId>
<artifactId>dependency-check-parent</artifactId>
<version>1.2.7</version>
<version>1.2.8</version>
</parent>
<artifactId>dependency-check-core</artifactId>

View File

@@ -153,6 +153,11 @@ public class Engine {
return dependencies;
}
/**
* Sets the dependencies.
*
* @param dependencies the dependencies
*/
public void setDependencies(List<Dependency> dependencies) {
this.dependencies = dependencies;
}
@@ -323,7 +328,7 @@ public class Engine {
}
} else {
final String msg = String.format("No file extension found on file '%s'. The file was not analyzed.", file.toString());
LOGGER.log(Level.FINEST, msg);
LOGGER.log(Level.FINE, msg);
}
return dependency;
}
@@ -513,6 +518,15 @@ public class Engine {
return scan;
}
/**
* Returns the set of file type analyzers.
*
* @return the set of file type analyzers
*/
public Set<FileTypeAnalyzer> getFileTypeAnalyzers() {
return this.fileTypeAnalyzers;
}
/**
* Checks the CPE Index to ensure documents exists. If none exist a NoDataException is thrown.
*

View File

@@ -41,16 +41,7 @@ public abstract class AbstractFileTypeAnalyzer extends AbstractAnalyzer implemen
* enabled.
*/
public AbstractFileTypeAnalyzer() {
final String key = getAnalyzerEnabledSettingKey();
try {
enabled = Settings.getBoolean(key, true);
} catch (InvalidSettingException ex) {
String msg = String.format("Invalid setting for property '%s'", key);
LOGGER.log(Level.WARNING, msg);
LOGGER.log(Level.FINE, "", ex);
msg = String.format("%s has been disabled", getName());
LOGGER.log(Level.WARNING, msg);
}
reset();
}
//</editor-fold>
@@ -164,6 +155,23 @@ public abstract class AbstractFileTypeAnalyzer extends AbstractAnalyzer implemen
}
}
/**
* Resets the enabled flag on the analyzer.
*/
@Override
public final void reset() {
final String key = getAnalyzerEnabledSettingKey();
try {
enabled = Settings.getBoolean(key, true);
} catch (InvalidSettingException ex) {
String msg = String.format("Invalid setting for property '%s'", key);
LOGGER.log(Level.WARNING, msg);
LOGGER.log(Level.FINE, "", ex);
msg = String.format("%s has been disabled", getName());
LOGGER.log(Level.WARNING, msg);
}
}
/**
* Analyzes a given dependency. If the dependency is an archive, such as a WAR or EAR, the contents are extracted,
* scanned, and added to the list of dependencies within the engine.

View File

@@ -31,4 +31,9 @@ public interface FileTypeAnalyzer extends Analyzer {
* @return whether or not the specified file extension is supported by this analyzer.
*/
boolean supportsExtension(String extension);
/**
* Resets the analyzers state.
*/
void reset();
}

View File

@@ -62,7 +62,7 @@ public final class CpeMemoryIndex {
/**
* singleton instance.
*/
private static CpeMemoryIndex instance = new CpeMemoryIndex();
private static final CpeMemoryIndex INSTANCE = new CpeMemoryIndex();
/**
* private constructor for singleton.
@@ -76,7 +76,7 @@ public final class CpeMemoryIndex {
* @return the instance of the CpeMemoryIndex
*/
public static CpeMemoryIndex getInstance() {
return instance;
return INSTANCE;
}
/**
* The in memory Lucene index.
@@ -114,18 +114,20 @@ public final class CpeMemoryIndex {
* @throws IndexException thrown if there is an error creating the index
*/
public void open(CveDB cve) throws IndexException {
if (!openState) {
index = new RAMDirectory();
buildIndex(cve);
try {
indexReader = DirectoryReader.open(index);
} catch (IOException ex) {
throw new IndexException(ex);
synchronized (INSTANCE) {
if (!openState) {
index = new RAMDirectory();
buildIndex(cve);
try {
indexReader = DirectoryReader.open(index);
} catch (IOException ex) {
throw new IndexException(ex);
}
indexSearcher = new IndexSearcher(indexReader);
searchingAnalyzer = createSearchingAnalyzer();
queryParser = new QueryParser(LuceneUtils.CURRENT_VERSION, Fields.DOCUMENT_KEY, searchingAnalyzer);
openState = true;
}
indexSearcher = new IndexSearcher(indexReader);
searchingAnalyzer = createSearchingAnalyzer();
queryParser = new QueryParser(LuceneUtils.CURRENT_VERSION, Fields.DOCUMENT_KEY, searchingAnalyzer);
openState = true;
}
}
/**

View File

@@ -261,7 +261,7 @@ public class DownloadTask implements Callable<Future<ProcessTask>> {
*/
private void extractGzip(File file) throws FileNotFoundException, IOException {
final String originalPath = file.getPath();
File gzip = new File(originalPath + ".gz");
final File gzip = new File(originalPath + ".gz");
if (gzip.isFile() && !gzip.delete()) {
gzip.deleteOnExit();
}

View File

@@ -610,7 +610,14 @@ public class Dependency implements Serializable, Comparable<Dependency> {
* @param dependency a reference to the related dependency
*/
public void addRelatedDependency(Dependency dependency) {
relatedDependencies.add(dependency);
if (this == dependency) {
LOGGER.warning("Attempted to add a circular reference - please post the log file to issue #172 here "
+ "https://github.com/jeremylong/DependencyCheck/issues/172 ");
LOGGER.log(Level.FINE, "this: {0}", this.toString());
LOGGER.log(Level.FINE, "dependency: {0}", dependency.toString());
} else {
relatedDependencies.add(dependency);
}
}
/**

View File

@@ -21,6 +21,7 @@ import java.util.Properties;
import mockit.Mock;
import mockit.MockUp;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import org.junit.Test;
import org.owasp.dependencycheck.BaseTest;
import org.owasp.dependencycheck.data.nvdcve.DatabaseProperties;
@@ -136,9 +137,9 @@ public class EngineVersionCheckTest extends BaseTest {
@Test
public void testGetCurrentReleaseVersion() {
EngineVersionCheck instance = new EngineVersionCheck();
DependencyVersion expResult = new DependencyVersion("1.2.6");
DependencyVersion minExpResult = new DependencyVersion("1.2.6");
String release = instance.getCurrentReleaseVersion();
DependencyVersion result = new DependencyVersion(release);
assertEquals(expResult, result);
assertTrue(minExpResult.compareTo(result) <= 0);
}
}

View File

@@ -3,7 +3,7 @@
<parent>
<groupId>org.owasp</groupId>
<artifactId>dependency-check-parent</artifactId>
<version>1.2.7</version>
<version>1.2.8</version>
</parent>
<groupId>org.owasp</groupId>
<artifactId>dependency-check-jenkins</artifactId>

View File

@@ -22,7 +22,7 @@ Copyright (c) 2013 Jeremy Long. All Rights Reserved.
<parent>
<groupId>org.owasp</groupId>
<artifactId>dependency-check-parent</artifactId>
<version>1.2.7</version>
<version>1.2.8</version>
</parent>
<artifactId>dependency-check-maven</artifactId>
@@ -86,6 +86,23 @@ Copyright (c) 2013 Jeremy Long. All Rights Reserved.
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.16</version>
<configuration>
<systemProperties>
<property>
<name>data.directory</name>
<value>${project.build.directory}/dependency-check-data</value>
</property>
<property>
<name>temp.directory</name>
<value>${project.build.directory}/temp</value>
</property>
</systemProperties>
</configuration>
</plugin>
<plugin>
<inherited>true</inherited>
<groupId>org.apache.maven.plugins</groupId>
@@ -315,6 +332,12 @@ Copyright (c) 2013 Jeremy Long. All Rights Reserved.
<artifactId>maven-reporting-api</artifactId>
<version>3.0</version>
</dependency>
<dependency>
<groupId>org.jmockit</groupId>
<artifactId>jmockit</artifactId>
<version>1.12</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>

View File

@@ -0,0 +1,231 @@
/*
* This file is part of dependency-check-maven.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright (c) 2013 Jeremy Long. All Rights Reserved.
*/
package org.owasp.dependencycheck.maven;
import java.io.File;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugin.MojoFailureException;
import org.apache.maven.plugins.annotations.LifecyclePhase;
import org.apache.maven.plugins.annotations.Mojo;
import org.apache.maven.plugins.annotations.ResolutionScope;
import org.apache.maven.project.MavenProject;
import org.owasp.dependencycheck.analyzer.DependencyBundlingAnalyzer;
import org.owasp.dependencycheck.analyzer.exception.AnalysisException;
import org.owasp.dependencycheck.data.nvdcve.DatabaseException;
import org.owasp.dependencycheck.dependency.Dependency;
import org.owasp.dependencycheck.utils.Settings;
/**
* Maven Plugin that checks project dependencies and the dependencies of all child modules to see if they have any known
* published vulnerabilities.
*
* @author Jeremy Long <jeremy.long@owasp.org>
*/
@Mojo(
name = "aggregate",
defaultPhase = LifecyclePhase.SITE,
aggregator = true,
threadSafe = true,
requiresDependencyResolution = ResolutionScope.COMPILE_PLUS_RUNTIME,
requiresOnline = true
)
public class AggregateMojo extends BaseDependencyCheckMojo {
/**
* Logger field reference.
*/
private static final Logger LOGGER = Logger.getLogger(AggregateMojo.class.getName());
/**
* Executes the aggregate dependency-check goal. This runs dependency-check and generates the subsequent reports.
*
* @throws MojoExecutionException thrown if there is ane exception running the mojo
* @throws MojoFailureException thrown if dependency-check is configured to fail the build
*/
@Override
public void runCheck() throws MojoExecutionException, MojoFailureException {
final Engine engine = generateDataFile();
if (getProject() == getReactorProjects().get(getReactorProjects().size() - 1)) {
final Map<MavenProject, Set<MavenProject>> children = buildAggregateInfo();
boolean hasOrchestration = false;
for (MavenProject current : getReactorProjects()) {
final List<Dependency> dependencies = readDataFile(current);
final List<MavenProject> childProjects = getAllChildren(current, children);
//check for orchestration build - execution root with no children or dependencies
if ((dependencies == null || dependencies.isEmpty()) && childProjects.isEmpty() && current.isExecutionRoot()) {
hasOrchestration = true;
}
}
for (MavenProject current : getReactorProjects()) {
List<Dependency> dependencies = readDataFile(current);
final List<MavenProject> childProjects = getAllChildren(current, children);
//check for orchestration build - execution root with no children or dependencies
if ((dependencies == null || dependencies.isEmpty()) && childProjects.isEmpty() && current.isExecutionRoot()) {
engine.resetFileTypeAnalyzers();
for (MavenProject mod : getReactorProjects()) {
scanArtifacts(mod, engine);
}
engine.analyzeDependencies();
} else {
if (dependencies == null) {
dependencies = new ArrayList<Dependency>();
}
for (MavenProject reportOn : childProjects) {
final List<Dependency> childDeps = readDataFile(reportOn);
if (childDeps != null && !childDeps.isEmpty()) {
dependencies.addAll(childDeps);
}
}
engine.getDependencies().clear();
engine.getDependencies().addAll(dependencies);
final DependencyBundlingAnalyzer bundler = new DependencyBundlingAnalyzer();
try {
bundler.analyze(null, engine);
} catch (AnalysisException ex) {
LOGGER.log(Level.WARNING, "An error occured grouping the dependencies; duplicate entries may exist in the report", ex);
LOGGER.log(Level.FINE, "Bundling Exception", ex);
}
}
try {
final File outputDir = getCorrectOutputDirectory(current);
writeReports(engine, current, outputDir);
} catch (MojoExecutionException ex) {
if (!hasOrchestration) {
throw ex;
} // else ignore this
}
}
}
engine.cleanup();
Settings.cleanup();
}
/**
* Returns a list containing all the recursive, non-pom children of the given project, never <code>null</code>.
*
* @param project the parent project to collect the child project references
* @param childMap a map of the parent-child relationships
* @return a list of child projects
*/
protected List<MavenProject> getAllChildren(MavenProject project, Map<MavenProject, Set<MavenProject>> childMap) {
final Set<MavenProject> children = childMap.get(project);
if (children == null) {
return Collections.emptyList();
}
final List<MavenProject> result = new ArrayList<MavenProject>();
for (MavenProject child : children) {
if (isMultiModule(child)) {
result.addAll(getAllChildren(child, childMap));
} else {
result.add(child);
}
}
return result;
}
/**
* Test if the project has pom packaging
*
* @param mavenProject Project to test
* @return <code>true</code> if it has a pom packaging; otherwise <code>false</code>
*/
protected boolean isMultiModule(MavenProject mavenProject) {
return "pom".equals(mavenProject.getPackaging());
}
/**
* Builds the parent-child map.
*
* @return a map of the parent/child relationships
*/
private Map<MavenProject, Set<MavenProject>> buildAggregateInfo() {
final Map<MavenProject, Set<MavenProject>> parentChildMap = new HashMap<MavenProject, Set<MavenProject>>();
for (MavenProject proj : getReactorProjects()) {
Set<MavenProject> depList = parentChildMap.get(proj.getParent());
if (depList == null) {
depList = new HashSet<MavenProject>();
parentChildMap.put(proj.getParent(), depList);
}
depList.add(proj);
}
return parentChildMap;
}
/**
* Runs dependency-check's Engine and writes the serialized dependencies to disk.
*
* @return the Engine used to execute dependency-check
* @throws MojoExecutionException thrown if there is an exception running the mojo
* @throws MojoFailureException thrown if dependency-check is configured to fail the build if severe CVEs are
* identified.
*/
protected Engine generateDataFile() throws MojoExecutionException, MojoFailureException {
final Engine engine;
try {
engine = initializeEngine();
} catch (DatabaseException ex) {
LOGGER.log(Level.FINE, "Database connection error", ex);
throw new MojoExecutionException("An exception occured connecting to the local database. Please see the log file for more details.", ex);
}
scanArtifacts(getProject(), engine);
engine.analyzeDependencies();
writeDataFile(engine.getDependencies());
showSummary(engine.getDependencies());
checkForFailure(engine.getDependencies());
return engine;
}
@Override
public boolean canGenerateReport() {
return true; //aggregate always returns true for now - we can look at a more complicated/acurate solution later
}
/**
* Returns the report name.
*
* @param locale the location
* @return the report name
*/
public String getName(Locale locale) {
return "dependency-check:aggregate";
}
/**
* Gets the description of the Dependency-Check report to be displayed in the Maven Generated Reports page.
*
* @param locale The Locale to get the description for
* @return the description
*/
public String getDescription(Locale locale) {
return "Generates an aggregate report of all child Maven projects providing details on any "
+ "published vulnerabilities within project dependencies. This report is a best "
+ "effort and may contain false positives and false negatives.";
}
}

View File

@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright (c) 2013 Jeremy Long. All Rights Reserved.
* Copyright (c) 2014 Jeremy Long. All Rights Reserved.
*/
package org.owasp.dependencycheck.maven;
@@ -29,50 +29,42 @@ import java.io.ObjectOutputStream;
import java.io.OutputStream;
import java.util.List;
import java.util.Locale;
import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.apache.maven.artifact.Artifact;
import org.apache.maven.doxia.sink.Sink;
import org.apache.maven.plugin.AbstractMojo;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugin.MojoFailureException;
import org.apache.maven.plugins.annotations.LifecyclePhase;
import org.apache.maven.plugins.annotations.Mojo;
import org.apache.maven.plugins.annotations.Component;
import org.apache.maven.plugins.annotations.Parameter;
import org.apache.maven.plugins.annotations.ResolutionScope;
import org.apache.maven.project.MavenProject;
import org.apache.maven.reporting.MavenReport;
import org.apache.maven.reporting.MavenReportException;
import org.apache.maven.settings.Proxy;
import org.owasp.dependencycheck.analyzer.DependencyBundlingAnalyzer;
import org.owasp.dependencycheck.analyzer.exception.AnalysisException;
import org.owasp.dependencycheck.data.nexus.MavenArtifact;
import org.owasp.dependencycheck.data.nvdcve.CveDB;
import org.owasp.dependencycheck.data.nvdcve.DatabaseException;
import org.owasp.dependencycheck.data.nvdcve.DatabaseProperties;
import org.owasp.dependencycheck.dependency.Confidence;
import org.owasp.dependencycheck.dependency.Dependency;
import org.owasp.dependencycheck.dependency.Identifier;
import org.owasp.dependencycheck.dependency.Vulnerability;
import org.owasp.dependencycheck.reporting.ReportGenerator;
import org.owasp.dependencycheck.utils.LogUtils;
import org.owasp.dependencycheck.utils.Settings;
/**
* Maven Plugin that checks project dependencies to see if they have any known published vulnerabilities.
*
* @author Jeremy Long <jeremy.long@owasp.org>
*/
@Mojo(
name = "check",
defaultPhase = LifecyclePhase.COMPILE,
threadSafe = true,
requiresDependencyResolution = ResolutionScope.RUNTIME_PLUS_SYSTEM,
requiresOnline = true
)
public class DependencyCheckMojo extends ReportAggregationMojo {
public abstract class BaseDependencyCheckMojo extends AbstractMojo implements MavenReport {
//<editor-fold defaultstate="collapsed" desc="Private fields">
/**
* Logger field reference.
*/
private static final Logger LOGGER = Logger.getLogger(DependencyCheckMojo.class.getName());
private static final Logger LOGGER = Logger.getLogger(BaseDependencyCheckMojo.class.getName());
/**
* The properties file location.
*/
@@ -86,12 +78,23 @@ public class DependencyCheckMojo extends ReportAggregationMojo {
*/
private static final String NEW_LINE = System.getProperty("line.separator", "\n").intern();
/**
* The dependency-check engine used to scan the project.
* Sets whether or not the external report format should be used.
*/
private Engine engine = null;
//</editor-fold>
@Parameter(property = "metaFileName", defaultValue = "dependency-check.ser", required = true)
private String dataFileName;
//</editor-fold>
// <editor-fold defaultstate="collapsed" desc="Maven bound parameters and components">
/**
* The Maven Project Object.
*/
@Component
private MavenProject project;
/**
* List of Maven project of the current build
*/
@Parameter(readonly = true, required = true, property = "reactorProjects")
private List<MavenProject> reactorProjects;
/**
* The path to the verbose log.
*/
@@ -117,6 +120,14 @@ public class DependencyCheckMojo extends ReportAggregationMojo {
@SuppressWarnings("CanBeFinal")
@Parameter(property = "autoupdate", defaultValue = "true", required = true)
private boolean autoUpdate = true;
/**
* Generate aggregate reports in multi-module projects.
*
* @deprecated use the aggregate goal instead
*/
@Parameter(property = "aggregate", defaultValue = "false")
@Deprecated
private boolean aggregate;
/**
* The report format to be generated (HTML, XML, VULN, ALL). This configuration option has no affect if using this
* within the Site plug-in unless the externalReport is set to true. Default is HTML.
@@ -184,14 +195,22 @@ public class DependencyCheckMojo extends ReportAggregationMojo {
@Parameter(property = "nuspecAnalyzerEnabled", defaultValue = "true", required = false)
private boolean nuspecAnalyzerEnabled = true;
/**
* Whether or not the Central Analyzer is enabled.
*/
@SuppressWarnings("CanBeFinal")
@Parameter(property = "centralAnalyzerEnabled", defaultValue = "true", required = false)
private boolean centralAnalyzerEnabled = true;
/**
* Whether or not the Nexus Analyzer is enabled.
*/
@SuppressWarnings("CanBeFinal")
@Parameter(property = "nexusAnalyzerEnabled", defaultValue = "true", required = false)
private boolean nexusAnalyzerEnabled = true;
/**
* Whether or not the Nexus Analyzer is enabled.
* The URL of a Nexus Pro server.
*/
@Parameter(property = "nexusUrl", defaultValue = "", required = false)
private String nexusUrl;
@@ -299,38 +318,116 @@ public class DependencyCheckMojo extends ReportAggregationMojo {
@Deprecated
private String externalReport = null;
// </editor-fold>
/**
* Executes the Dependency-Check on the dependent libraries.
*
* @return the Engine used to scan the dependencies.
* @throws DatabaseException thrown if there is an exception connecting to the database
* Specifies the destination directory for the generated Dependency-Check report. This generally maps to
* "target/site".
*/
private Engine executeDependencyCheck() throws DatabaseException {
return executeDependencyCheck(getProject());
@Parameter(property = "reportOutputDirectory", defaultValue = "${project.reporting.outputDirectory}", required = true)
private File reportOutputDirectory;
// </editor-fold>
//<editor-fold defaultstate="collapsed" desc="Base Maven implementation">
/**
* Executes dependency-check.
*
* @throws MojoExecutionException thrown if there is an exception executing the mojo
* @throws MojoFailureException thrown if dependency-check failed the build
*/
@Override
public void execute() throws MojoExecutionException, MojoFailureException {
validateAggregate();
project.setContextValue(getOutputDirectoryContextKey(), this.outputDirectory);
runCheck();
}
/**
* Executes the Dependency-Check on the dependent libraries.
* Checks if the aggregate configuration parameter has been set to true. If it has a MojoExecutionException is
* thrown because the aggregate configuration parameter is no longer supported.
*
* @param project the project to run dependency-check on
* @return the Engine used to scan the dependencies.
* @throws DatabaseException thrown if there is an exception connecting to the database
* @throws MojoExecutionException thrown if aggregate is set to true
*/
private Engine executeDependencyCheck(MavenProject project) throws DatabaseException {
final Engine localEngine;
if (engine == null) {
localEngine = initializeEngine(project);
} else {
localEngine = engine;
private void validateAggregate() throws MojoExecutionException {
if (aggregate) {
final String msg = "Aggregate configuration detected - as of dependency-check 1.2.8 this no longer supported. "
+ "Please use the aggregate goal instead.";
throw new MojoExecutionException(msg);
}
}
final Set<Artifact> artifacts = project.getArtifacts();
for (Artifact a : artifacts) {
/**
* Generates the Dependency-Check Site Report.
*
* @param sink the sink to write the report to
* @param locale the locale to use when generating the report
* @throws MavenReportException if a maven report exception occurs
* @deprecated use {@link #generate(org.apache.maven.doxia.sink.Sink, java.util.Locale) instead.
*/
@Deprecated
public final void generate(@SuppressWarnings("deprecation") org.codehaus.doxia.sink.Sink sink, Locale locale) throws MavenReportException {
generate((Sink) sink, locale);
}
/**
* Generates the Dependency-Check Site Report.
*
* @param sink the sink to write the report to
* @param locale the locale to use when generating the report
* @throws MavenReportException if a maven report exception occurs
*/
public void generate(Sink sink, Locale locale) throws MavenReportException {
try {
validateAggregate();
} catch (MojoExecutionException ex) {
throw new MavenReportException(ex.getMessage());
}
project.setContextValue(getOutputDirectoryContextKey(), getReportOutputDirectory());
try {
runCheck();
} catch (MojoExecutionException ex) {
throw new MavenReportException(ex.getMessage(), ex);
} catch (MojoFailureException ex) {
LOGGER.warning("Vulnerabilities were identifies that exceed the CVSS threshold for failing the build");
}
}
/**
* Returns the correct output directory depending on if a site is being executed or not.
*
* @return the directory to write the report(s)
* @throws MojoExecutionException thrown if there is an error loading the file path
*/
protected File getCorrectOutputDirectory() throws MojoExecutionException {
return getCorrectOutputDirectory(this.project);
}
/**
* Returns the correct output directory depending on if a site is being executed or not.
*
* @param current the Maven project to get the output directory from
* @return the directory to write the report(s)
* @throws MojoExecutionException thrown if there is an error loading the file path
*/
protected File getCorrectOutputDirectory(MavenProject current) throws MojoExecutionException {
final Object obj = current.getContextValue(getOutputDirectoryContextKey());
if (obj != null && obj instanceof File) {
return (File) obj;
} else {
throw new MojoExecutionException(String.format("Unable to determine output directory for '%s'", current.getName()));
}
}
/**
* Scans the project's artifacts and adds them to the engine's dependency list.
*
* @param project the project to scan the dependencies of
* @param engine the engine to use to scan the dependencies
*/
protected void scanArtifacts(MavenProject project, Engine engine) {
for (Artifact a : project.getArtifacts()) {
if (excludeFromScan(a)) {
continue;
}
final List<Dependency> deps = localEngine.scan(a.getFile().getAbsoluteFile());
final List<Dependency> deps = engine.scan(a.getFile().getAbsoluteFile());
if (deps != null) {
if (deps.size() == 1) {
final Dependency d = deps.get(0);
@@ -345,44 +442,96 @@ public class DependencyCheckMojo extends ReportAggregationMojo {
}
}
}
localEngine.analyzeDependencies();
return localEngine;
}
/**
* Executes the dependency-check scan and generates the necassary report.
*
* @throws MojoExecutionException thrown if there is an exception running the scan
* @throws MojoFailureException thrown if dependency-check is configured to fail the build
*/
public abstract void runCheck() throws MojoExecutionException, MojoFailureException;
/**
* Sets the Reporting output directory.
*
* @param directory the output directory
*/
@Override
public void setReportOutputDirectory(File directory) {
reportOutputDirectory = directory;
}
/**
* Returns the report output directory.
*
* @return the report output directory
*/
@Override
public File getReportOutputDirectory() {
return reportOutputDirectory;
}
/**
* Returns the output directory.
*
* @return the output directory
*/
public File getOutputDirectory() {
return outputDirectory;
}
/**
* Returns whether this is an external report. This method always returns true.
*
* @return <code>true</code>
*/
@Override
public final boolean isExternalReport() {
return true;
}
/**
* Returns the output name.
*
* @return the output name
*/
public String getOutputName() {
if ("HTML".equalsIgnoreCase(this.format) || "ALL".equalsIgnoreCase(this.format)) {
return "dependency-check-report";
} else if ("XML".equalsIgnoreCase(this.format)) {
return "dependency-check-report.xml#";
} else if ("VULN".equalsIgnoreCase(this.format)) {
return "dependency-check-vulnerability";
} else {
LOGGER.log(Level.WARNING, "Unknown report format used during site generation.");
return "dependency-check-report";
}
}
/**
* Returns the category name.
*
* @return the category name
*/
public String getCategoryName() {
return MavenReport.CATEGORY_PROJECT_REPORTS;
}
//</editor-fold>
/**
* Initializes a new <code>Engine</code> that can be used for scanning.
*
* @param project the current MavenProject
* @return a newly instantiated <code>Engine</code>
* @throws DatabaseException thrown if there is a database exception
*/
private Engine initializeEngine(MavenProject project) throws DatabaseException {
protected Engine initializeEngine() throws DatabaseException {
final InputStream in = BaseDependencyCheckMojo.class.getClassLoader().getResourceAsStream(LOG_PROPERTIES_FILE);
LogUtils.prepareLogger(in, logFile);
populateSettings();
final Engine localEngine = new Engine(project);
return localEngine;
return new Engine(this.project, this.reactorProjects);
}
/**
* Tests is the artifact should be included in the scan (i.e. is the dependency in a scope that is being scanned).
*
* @param a the Artifact to test
* @return <code>true</code> if the artifact is in an excluded scope; otherwise <code>false</code>
*/
private boolean excludeFromScan(Artifact a) {
if (skipTestScope && Artifact.SCOPE_TEST.equals(a.getScope())) {
return true;
}
if (skipProvidedScope && Artifact.SCOPE_PROVIDED.equals(a.getScope())) {
return true;
}
if (skipRuntimeScope && !Artifact.SCOPE_RUNTIME.equals(a.getScope())) {
return true;
}
return false;
}
//<editor-fold defaultstate="collapsed" desc="Methods to populate global settings">
/**
* Takes the properties supplied and updates the dependency-check settings. Additionally, this sets the system
* properties required to change the proxy url, port, and connection timeout.
@@ -443,6 +592,8 @@ public class DependencyCheckMojo extends ReportAggregationMojo {
//NUSPEC ANALYZER
Settings.setBoolean(Settings.KEYS.ANALYZER_NUSPEC_ENABLED, nuspecAnalyzerEnabled);
//NEXUS ANALYZER
Settings.setBoolean(Settings.KEYS.ANALYZER_CENTRAL_ENABLED, centralAnalyzerEnabled);
//NEXUS ANALYZER
Settings.setBoolean(Settings.KEYS.ANALYZER_NEXUS_ENABLED, nexusAnalyzerEnabled);
if (nexusUrl != null && !nexusUrl.isEmpty()) {
Settings.setString(Settings.KEYS.ANALYZER_NEXUS_URL, nexusUrl);
@@ -527,248 +678,90 @@ public class DependencyCheckMojo extends ReportAggregationMojo {
return null;
}
//</editor-fold>
/**
* Initialize the mojo.
*/
@Override
protected void initialize() {
final InputStream in = DependencyCheckMojo.class.getClassLoader().getResourceAsStream(LOG_PROPERTIES_FILE);
LogUtils.prepareLogger(in, logFile);
}
/**
* Executes the dependency-check and generates the report.
* Tests is the artifact should be included in the scan (i.e. is the dependency in a scope that is being scanned).
*
* @throws MojoExecutionException if a maven exception occurs
* @throws MojoFailureException thrown if a CVSS score is found that is higher then the configured level
* @param a the Artifact to test
* @return <code>true</code> if the artifact is in an excluded scope; otherwise <code>false</code>
*/
@Override
protected void performExecute() throws MojoExecutionException, MojoFailureException {
try {
engine = executeDependencyCheck();
ReportingUtil.generateExternalReports(engine, outputDirectory, getProject().getName(), format);
if (this.showSummary) {
showSummary(engine.getDependencies());
}
if (this.failBuildOnCVSS <= 10) {
checkForFailure(engine.getDependencies());
}
} catch (DatabaseException ex) {
LOGGER.log(Level.SEVERE, "Unable to connect to the dependency-check database; analysis has stopped");
LOGGER.log(Level.FINE, "", ex);
}
}
@Override
protected void postExecute() throws MojoExecutionException, MojoFailureException {
try {
super.postExecute();
} finally {
cleanupEngine();
}
}
@Override
protected void postGenerate() throws MavenReportException {
try {
super.postGenerate();
} finally {
cleanupEngine();
}
}
/**
* Calls <code>engine.cleanup()</code> to release resources.
*/
private void cleanupEngine() {
if (engine != null) {
engine.cleanup();
engine = null;
}
Settings.cleanup(true);
}
/**
* Generates the Dependency-Check Site Report.
*
* @param locale the locale to use when generating the report
* @throws MavenReportException if a maven report exception occurs
*/
@Override
protected void executeNonAggregateReport(Locale locale) throws MavenReportException {
final List<Dependency> deps = readDataFile();
if (deps != null) {
try {
if (engine != null) {
engine = initializeEngine(getProject());
}
engine.getDependencies().addAll(deps);
} catch (DatabaseException ex) {
final String msg = String.format("An unrecoverable exception with the dependency-check initialization occured while scanning %s",
getProject().getName());
throw new MavenReportException(msg, ex);
}
} else {
try {
engine = executeDependencyCheck();
} catch (DatabaseException ex) {
final String msg = String.format("An unrecoverable exception with the dependency-check scan occured while scanning %s",
getProject().getName());
throw new MavenReportException(msg, ex);
}
}
ReportingUtil.generateExternalReports(engine, getReportOutputDirectory(), getProject().getName(), format);
}
@Override
protected void executeAggregateReport(MavenProject project, Locale locale) throws MavenReportException {
List<Dependency> deps = readDataFile(project);
if (deps != null) {
try {
if (engine != null) {
engine = initializeEngine(project);
}
engine.getDependencies().addAll(deps);
} catch (DatabaseException ex) {
final String msg = String.format("An unrecoverable exception with the dependency-check initialization occured while scanning %s",
project.getName());
throw new MavenReportException(msg, ex);
}
} else {
try {
engine = executeDependencyCheck(project);
} catch (DatabaseException ex) {
final String msg = String.format("An unrecoverable exception with the dependency-check scan occured while scanning %s",
project.getName());
throw new MavenReportException(msg, ex);
}
}
for (MavenProject child : getAllChildren(project)) {
deps = readDataFile(child);
if (deps == null) {
final String msg = String.format("Unable to include information on %s in the dependency-check aggregate report",
child.getName());
LOGGER.severe(msg);
} else {
engine.getDependencies().addAll(deps);
}
}
final DependencyBundlingAnalyzer bundler = new DependencyBundlingAnalyzer();
try {
bundler.analyze(null, engine);
} catch (AnalysisException ex) {
LOGGER.log(Level.WARNING, "An error occured grouping the dependencies; duplicate entries may exist in the report", ex);
LOGGER.log(Level.FINE, "Bundling Exception", ex);
}
final File outputDir = getReportOutputDirectory(project);
if (outputDir != null) {
ReportingUtil.generateExternalReports(engine, outputDir, project.getName(), format);
}
}
// <editor-fold defaultstate="collapsed" desc="Mojo interface/abstract required setter/getter methods">
/**
* Returns the output name.
*
* @return the output name
*/
public String getOutputName() {
if ("HTML".equalsIgnoreCase(this.format) || "ALL".equalsIgnoreCase(this.format)) {
return "dependency-check-report";
} else if ("XML".equalsIgnoreCase(this.format)) {
return "dependency-check-report.xml#";
} else if ("VULN".equalsIgnoreCase(this.format)) {
return "dependency-check-vulnerability";
} else {
LOGGER.log(Level.WARNING, "Unknown report format used during site generation.");
return "dependency-check-report";
}
}
/**
* Returns the category name.
*
* @return the category name
*/
public String getCategoryName() {
return MavenReport.CATEGORY_PROJECT_REPORTS;
}
/**
* Returns the report name.
*
* @param locale the location
* @return the report name
*/
public String getName(Locale locale) {
return "dependency-check";
}
/**
* Gets the description of the Dependency-Check report to be displayed in the Maven Generated Reports page.
*
* @param locale The Locale to get the description for
* @return the description
*/
public String getDescription(Locale locale) {
return "A report providing details on any published "
+ "vulnerabilities within project dependencies. This report is a best effort but may contain "
+ "false positives and false negatives.";
}
/**
* Returns whether or not a report can be generated.
*
* @return <code>true</code> if a report can be generated; otherwise <code>false</code>
*/
public boolean canGenerateReport() {
if (canGenerateAggregateReport() || (isAggregate() && isMultiModule())) {
protected boolean excludeFromScan(Artifact a) {
if (skipTestScope && Artifact.SCOPE_TEST.equals(a.getScope())) {
return true;
}
if (canGenerateNonAggregateReport()) {
if (skipProvidedScope && Artifact.SCOPE_PROVIDED.equals(a.getScope())) {
return true;
}
if (skipRuntimeScope && !Artifact.SCOPE_RUNTIME.equals(a.getScope())) {
return true;
} else {
final String msg;
if (getProject().getArtifacts().size() > 0) {
msg = "No project dependencies exist in the included scope - dependency-check:check is unable to generate a report.";
} else {
msg = "No project dependencies exist - dependency-check:check is unable to generate a report.";
}
LOGGER.warning(msg);
}
return false;
}
/**
* Returns whether or not a non-aggregate report can be generated.
* Returns a reference to the current project. This method is used instead of auto-binding the project via component
* annotation in concrete implementations of this. If the child has a <code>@Component MavenProject project;</code>
* defined then the abstract class (i.e. this class) will not have access to the current project (just the way Maven
* works with the binding).
*
* @return <code>true</code> if a non-aggregate report can be generated; otherwise <code>false</code>
* @return returns a reference to the current project
*/
@Override
protected boolean canGenerateNonAggregateReport() {
boolean ability = false;
for (Artifact a : getProject().getArtifacts()) {
if (!excludeFromScan(a)) {
ability = true;
break;
}
}
return ability;
protected MavenProject getProject() {
return project;
}
/**
* Returns whether or not an aggregate report can be generated.
* Returns the list of Maven Projects in this build.
*
* @return <code>true</code> if an aggregate report can be generated; otherwise <code>false</code>
* @return the list of Maven Projects in this build
*/
@Override
protected boolean canGenerateAggregateReport() {
return isAggregate() && isLastProject();
protected List<MavenProject> getReactorProjects() {
return reactorProjects;
}
/**
* Returns the report format.
*
* @return the report format
*/
protected String getFormat() {
return format;
}
/**
* Generates the reports for a given dependency-check engine.
*
* @param engine a dependency-check engine
* @param p the maven project
* @param outputDir the directory path to write the report(s).
*/
protected void writeReports(Engine engine, MavenProject p, File outputDir) {
DatabaseProperties prop = null;
CveDB cve = null;
try {
cve = new CveDB();
cve.open();
prop = cve.getDatabaseProperties();
} catch (DatabaseException ex) {
LOGGER.log(Level.FINE, "Unable to retrieve DB Properties", ex);
} finally {
if (cve != null) {
cve.close();
}
}
final ReportGenerator r = new ReportGenerator(p.getName(), engine.getDependencies(), engine.getAnalyzers(), prop);
try {
r.generateReports(outputDir.getAbsolutePath(), format);
} catch (IOException ex) {
LOGGER.log(Level.SEVERE,
"Unexpected exception occurred during analysis; please see the verbose error log for more details.");
LOGGER.log(Level.FINE, null, ex);
} catch (Throwable ex) {
LOGGER.log(Level.SEVERE,
"Unexpected exception occurred during analysis; please see the verbose error log for more details.");
LOGGER.log(Level.FINE, null, ex);
}
}
// </editor-fold>
//<editor-fold defaultstate="collapsed" desc="Methods to fail build or show summary">
/**
* Checks to see if a vulnerability has been identified with a CVSS score that is above the threshold set in the
@@ -777,27 +770,29 @@ public class DependencyCheckMojo extends ReportAggregationMojo {
* @param dependencies the list of dependency objects
* @throws MojoFailureException thrown if a CVSS score is found that is higher then the threshold set
*/
private void checkForFailure(List<Dependency> dependencies) throws MojoFailureException {
final StringBuilder ids = new StringBuilder();
for (Dependency d : dependencies) {
boolean addName = true;
for (Vulnerability v : d.getVulnerabilities()) {
if (v.getCvssScore() >= failBuildOnCVSS) {
if (addName) {
addName = false;
ids.append(NEW_LINE).append(d.getFileName()).append(": ");
ids.append(v.getName());
} else {
ids.append(", ").append(v.getName());
protected void checkForFailure(List<Dependency> dependencies) throws MojoFailureException {
if (failBuildOnCVSS <= 10) {
final StringBuilder ids = new StringBuilder();
for (Dependency d : dependencies) {
boolean addName = true;
for (Vulnerability v : d.getVulnerabilities()) {
if (v.getCvssScore() >= failBuildOnCVSS) {
if (addName) {
addName = false;
ids.append(NEW_LINE).append(d.getFileName()).append(": ");
ids.append(v.getName());
} else {
ids.append(", ").append(v.getName());
}
}
}
}
}
if (ids.length() > 0) {
final String msg = String.format("%n%nDependency-Check Failure:%n"
+ "One or more dependencies were identified with vulnerabilities that have a CVSS score greater then '%.1f': %s%n"
+ "See the dependency-check report for more details.%n%n", failBuildOnCVSS, ids.toString());
throw new MojoFailureException(msg);
if (ids.length() > 0) {
final String msg = String.format("%n%nDependency-Check Failure:%n"
+ "One or more dependencies were identified with vulnerabilities that have a CVSS score greater then '%.1f': %s%n"
+ "See the dependency-check report for more details.%n%n", failBuildOnCVSS, ids.toString());
throw new MojoFailureException(msg);
}
}
}
@@ -806,52 +801,73 @@ public class DependencyCheckMojo extends ReportAggregationMojo {
*
* @param dependencies a list of dependency objects
*/
private void showSummary(List<Dependency> dependencies) {
final StringBuilder summary = new StringBuilder();
for (Dependency d : dependencies) {
boolean firstEntry = true;
final StringBuilder ids = new StringBuilder();
for (Vulnerability v : d.getVulnerabilities()) {
if (firstEntry) {
firstEntry = false;
} else {
ids.append(", ");
}
ids.append(v.getName());
}
if (ids.length() > 0) {
summary.append(d.getFileName()).append(" (");
firstEntry = true;
for (Identifier id : d.getIdentifiers()) {
protected void showSummary(List<Dependency> dependencies) {
if (showSummary) {
final StringBuilder summary = new StringBuilder();
for (Dependency d : dependencies) {
boolean firstEntry = true;
final StringBuilder ids = new StringBuilder();
for (Vulnerability v : d.getVulnerabilities()) {
if (firstEntry) {
firstEntry = false;
} else {
summary.append(", ");
ids.append(", ");
}
summary.append(id.getValue());
ids.append(v.getName());
}
if (ids.length() > 0) {
summary.append(d.getFileName()).append(" (");
firstEntry = true;
for (Identifier id : d.getIdentifiers()) {
if (firstEntry) {
firstEntry = false;
} else {
summary.append(", ");
}
summary.append(id.getValue());
}
summary.append(") : ").append(ids).append(NEW_LINE);
}
summary.append(") : ").append(ids).append(NEW_LINE);
}
}
if (summary.length() > 0) {
final String msg = String.format("%n%n" + "One or more dependencies were identified with known vulnerabilities:%n%n%s"
+ "%n%nSee the dependency-check report for more details.%n%n", summary.toString());
LOGGER.log(Level.WARNING, msg);
if (summary.length() > 0) {
final String msg = String.format("%n%n" + "One or more dependencies were identified with known vulnerabilities:%n%n%s"
+ "%n%nSee the dependency-check report for more details.%n%n", summary.toString());
LOGGER.log(Level.WARNING, msg);
}
}
}
//</editor-fold>
//<editor-fold defaultstate="collapsed" desc="Methods to read/write the serialized data file">
/**
* Returns the key used to store the path to the data file that is saved by <code>writeDataFile()</code>. This key
* is used in the <code>MavenProject.(set|get)ContextValue</code>.
*
* @return the key used to store the path to the data file
*/
protected String getDataFileContextKey() {
return "dependency-check-path-" + dataFileName;
}
/**
* Returns the key used to store the path to the output directory. When generating the report in the
* <code>executeAggregateReport()</code> the output directory should be obtained by using this key.
*
* @return the key used to store the path to the output directory
*/
protected String getOutputDirectoryContextKey() {
return "dependency-output-dir-" + dataFileName;
}
/**
* Writes the scan data to disk. This is used to serialize the scan data between the "check" and "aggregate" phase.
*
* @return the File object referencing the data file that was written
* @param dependencies the list of dependencies to serialize
*/
@Override
protected File writeDataFile() {
protected void writeDataFile(List<Dependency> dependencies) {
File file = null;
if (engine != null && getProject().getContextValue(this.getDataFileContextKey()) == null) {
file = new File(getProject().getBuild().getDirectory(), getDataFileName());
if (dependencies != null && project.getContextValue(this.getDataFileContextKey()) == null) {
file = new File(project.getBuild().getDirectory(), dataFileName);
OutputStream os = null;
OutputStream bos = null;
ObjectOutputStream out = null;
@@ -859,13 +875,14 @@ public class DependencyCheckMojo extends ReportAggregationMojo {
os = new FileOutputStream(file);
bos = new BufferedOutputStream(os);
out = new ObjectOutputStream(bos);
out.writeObject(engine.getDependencies());
out.writeObject(dependencies);
out.flush();
//call reset to prevent resource leaks per
//https://www.securecoding.cert.org/confluence/display/java/SER10-J.+Avoid+memory+and+resource+leaks+during+serialization
out.reset();
project.setContextValue(this.getDataFileContextKey(), file.getAbsolutePath());
LOGGER.fine(String.format("Serialized data file written to '%s'", file.getAbsolutePath()));
} catch (IOException ex) {
LOGGER.log(Level.WARNING, "Unable to create data file used for report aggregation; "
+ "if report aggregation is being used the results may be incomplete.");
@@ -894,18 +911,6 @@ public class DependencyCheckMojo extends ReportAggregationMojo {
}
}
}
return file;
}
/**
* Reads the serialized scan data from disk. This is used to serialize the scan data between the "check" and
* "aggregate" phase.
*
* @return a <code>Engine</code> object populated with dependencies if the serialized data file exists; otherwise
* <code>null</code> is returned
*/
protected List<Dependency> readDataFile() {
return readDataFile(getProject());
}
/**
@@ -946,5 +951,4 @@ public class DependencyCheckMojo extends ReportAggregationMojo {
return ret;
}
//</editor-fold>
}

View File

@@ -0,0 +1,118 @@
/*
* This file is part of dependency-check-maven.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright (c) 2013 Jeremy Long. All Rights Reserved.
*/
package org.owasp.dependencycheck.maven;
import java.util.Locale;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.apache.maven.artifact.Artifact;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugin.MojoFailureException;
import org.apache.maven.plugins.annotations.LifecyclePhase;
import org.apache.maven.plugins.annotations.Mojo;
import org.apache.maven.plugins.annotations.ResolutionScope;
import org.owasp.dependencycheck.data.nvdcve.DatabaseException;
import org.owasp.dependencycheck.utils.Settings;
/**
* Maven Plugin that checks the project dependencies to see if they have any known published vulnerabilities.
*
* @author Jeremy Long <jeremy.long@owasp.org>
*/
@Mojo(
name = "check",
defaultPhase = LifecyclePhase.COMPILE,
threadSafe = true,
requiresDependencyResolution = ResolutionScope.COMPILE_PLUS_RUNTIME,
requiresOnline = true
)
public class CheckMojo extends BaseDependencyCheckMojo {
/**
* Logger field reference.
*/
private static final Logger LOGGER = Logger.getLogger(CheckMojo.class.getName());
/**
* Returns whether or not a the report can be generated.
*
* @return <code>true</code> if the report can be generated; otherwise <code>false</code>
*/
@Override
public boolean canGenerateReport() {
boolean isCapable = false;
for (Artifact a : getProject().getArtifacts()) {
if (!excludeFromScan(a)) {
isCapable = true;
break;
}
}
return isCapable;
}
/**
* Executes the dependency-check engine on the project's dependencies and generates the report.
*
* @throws MojoExecutionException thrown if there is an exception executing the goal
* @throws MojoFailureException thrown if dependency-check is configured to fail the build
*/
@Override
public void runCheck() throws MojoExecutionException, MojoFailureException {
final Engine engine;
try {
engine = initializeEngine();
} catch (DatabaseException ex) {
LOGGER.log(Level.FINE, "Database connection error", ex);
throw new MojoExecutionException("An exception occured connecting to the local database. Please see the log file for more details.", ex);
}
scanArtifacts(getProject(), engine);
if (engine.getDependencies().isEmpty()) {
LOGGER.info("No dependencies were identified that could be analyzed by dependency-check");
} else {
engine.analyzeDependencies();
writeReports(engine, getProject(), getCorrectOutputDirectory());
writeDataFile(engine.getDependencies());
showSummary(engine.getDependencies());
checkForFailure(engine.getDependencies());
}
engine.cleanup();
Settings.cleanup();
}
/**
* Returns the report name.
*
* @param locale the location
* @return the report name
*/
public String getName(Locale locale) {
return "dependency-check";
}
/**
* Gets the description of the Dependency-Check report to be displayed in the Maven Generated Reports page.
*
* @param locale The Locale to get the description for
* @return the description
*/
public String getDescription(Locale locale) {
return "Generates a report providing details on any published vulnerabilities within project dependencies. "
+ "This report is a best effort and may contain false positives and false negatives.";
}
}

View File

@@ -17,10 +17,12 @@
*/
package org.owasp.dependencycheck.maven;
import java.util.List;
import java.util.logging.Logger;
import org.apache.maven.project.MavenProject;
import org.owasp.dependencycheck.analyzer.Analyzer;
import org.owasp.dependencycheck.analyzer.CPEAnalyzer;
import org.owasp.dependencycheck.analyzer.FileTypeAnalyzer;
import org.owasp.dependencycheck.data.nvdcve.DatabaseException;
import org.owasp.dependencycheck.utils.Settings;
@@ -44,22 +46,37 @@ public class Engine extends org.owasp.dependencycheck.Engine {
* The current MavenProject.
*/
private MavenProject currentProject;
/**
* The list of MavenProjects that are part of the current build.
*/
private List<MavenProject> reactorProjects;
/**
* Key used in the MavenProject context values to note whether or not an update has been executed.
*/
public static final String UPDATE_EXECUTED_FLAG = "dependency-check-update-executed";
/**
* Creates a new Engine to perform anyalsis on dependencies.
*
* @param project the current Maven project
* @param reactorProjects the reactor projects for the current Maven execution
* @throws DatabaseException thrown if there is an issue connecting to the database
*/
public Engine(MavenProject project) throws DatabaseException {
public Engine(MavenProject project, List<MavenProject> reactorProjects) throws DatabaseException {
this.currentProject = project;
final MavenProject parent = getRootParent();
if (parent != null && parent.getContextValue("dependency-check-data-was-updated") != null) {
this.reactorProjects = reactorProjects;
final MavenProject root = getExecutionRoot();
if (root != null) {
LOGGER.fine(String.format("Checking root project, %s, if updates have already been completed", root.getArtifactId()));
} else {
LOGGER.fine("Checking root project, null, if updates have already been completed");
}
if (root != null && root.getContextValue(UPDATE_EXECUTED_FLAG) != null) {
System.setProperty(Settings.KEYS.AUTO_UPDATE, Boolean.FALSE.toString());
}
initializeEngine();
if (parent != null) {
parent.setContextValue("dependency-check-data-was-updated", Boolean.valueOf(true));
if (root != null) {
root.setContextValue(UPDATE_EXECUTED_FLAG, Boolean.TRUE);
}
}
@@ -81,7 +98,7 @@ public class Engine extends org.owasp.dependencycheck.Engine {
@Override
protected Analyzer initializeAnalyzer(Analyzer analyzer) {
if ((analyzer instanceof CPEAnalyzer)) {
CPEAnalyzer cpe = getPreviouslyLoadedAnalyzer();
CPEAnalyzer cpe = getPreviouslyLoadedCPEAnalyzer();
if (cpe != null) {
return cpe;
}
@@ -91,6 +108,23 @@ public class Engine extends org.owasp.dependencycheck.Engine {
return super.initializeAnalyzer(analyzer);
}
/**
* Releases resources used by the analyzers by calling close() on each analyzer.
*/
@Override
public void cleanup() {
super.cleanup();
if (currentProject == null || reactorProjects == null) {
return;
}
if (this.currentProject == reactorProjects.get(reactorProjects.size() - 1)) {
final CPEAnalyzer cpe = getPreviouslyLoadedCPEAnalyzer();
if (cpe != null) {
cpe.close();
}
}
}
/**
* Closes the given analyzer. This skips closing the CPEAnalyzer.
*
@@ -99,7 +133,7 @@ public class Engine extends org.owasp.dependencycheck.Engine {
@Override
protected void closeAnalyzer(Analyzer analyzer) {
if ((analyzer instanceof CPEAnalyzer)) {
if (getPreviouslyLoadedAnalyzer() == null) {
if (getPreviouslyLoadedCPEAnalyzer() == null) {
super.closeAnalyzer(analyzer);
}
} else {
@@ -107,26 +141,19 @@ public class Engine extends org.owasp.dependencycheck.Engine {
}
}
/**
* Closes the CPEAnalyzer if it has been created and persisted in the root parent MavenProject context.
*/
public void cleanupFinal() {
final CPEAnalyzer cpe = getPreviouslyLoadedAnalyzer();
if (cpe != null) {
cpe.close();
}
}
/**
* Gets the CPEAnalyzer from the root Maven Project.
*
* @return an initialized CPEAnalyzer
*/
private CPEAnalyzer getPreviouslyLoadedAnalyzer() {
private CPEAnalyzer getPreviouslyLoadedCPEAnalyzer() {
CPEAnalyzer cpe = null;
final MavenProject project = getRootParent();
final MavenProject project = getExecutionRoot();
if (project != null) {
cpe = (CPEAnalyzer) project.getContextValue(CPE_ANALYZER_KEY);
final Object obj = project.getContextValue(CPE_ANALYZER_KEY);
if (obj != null && obj instanceof CPEAnalyzer) {
cpe = (CPEAnalyzer) project.getContextValue(CPE_ANALYZER_KEY);
}
}
return cpe;
}
@@ -137,7 +164,7 @@ public class Engine extends org.owasp.dependencycheck.Engine {
* @param cpe the CPEAnalyzer to store
*/
private void storeCPEAnalyzer(CPEAnalyzer cpe) {
final MavenProject p = getRootParent();
final MavenProject p = getExecutionRoot();
if (p != null) {
p.setContextValue(CPE_ANALYZER_KEY, cpe);
}
@@ -148,7 +175,16 @@ public class Engine extends org.owasp.dependencycheck.Engine {
*
* @return the root Maven Project
*/
private MavenProject getRootParent() {
private MavenProject getExecutionRoot() {
if (reactorProjects == null) {
return null;
}
for (MavenProject p : reactorProjects) {
if (p.isExecutionRoot()) {
return p;
}
}
//the following should never run, but leaving it as a failsafe.
if (this.currentProject == null) {
return null;
}
@@ -158,4 +194,15 @@ public class Engine extends org.owasp.dependencycheck.Engine {
}
return p;
}
/**
* Resets the file type analyzers so that they can be re-used to scan additional directories. Without the reset the
* analyzer might be disabled because the first scan/analyze did not identify any files that could be processed by
* the analyzer.
*/
public void resetFileTypeAnalyzers() {
for (FileTypeAnalyzer a : getFileTypeAnalyzers()) {
a.reset();
}
}
}

View File

@@ -1,468 +0,0 @@
/*
* This file is part of dependency-check-maven.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright (c) 2014 Jeremy Long. All Rights Reserved.
*/
package org.owasp.dependencycheck.maven;
import java.io.File;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import java.util.logging.Logger;
import org.apache.maven.doxia.sink.Sink;
import org.apache.maven.plugin.AbstractMojo;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugin.MojoFailureException;
import org.apache.maven.plugins.annotations.Component;
import org.apache.maven.plugins.annotations.Parameter;
import org.apache.maven.project.MavenProject;
import org.apache.maven.reporting.MavenReport;
import org.apache.maven.reporting.MavenReportException;
/**
* <p>
* This is an abstract reporting mojo that enables report aggregation. Some of the code in the this class was copied
* from the CoberturaReportMojo (http://mojo.codehaus.org/cobertura-maven-plugin/, version 2.6). The authors of the
* CoberturaReportMojo were <a href="will.gwaltney@sas.com">Will Gwaltney</a> and
* <a href="mailto:joakim@erdfelt.com">Joakim Erdfelt</a>. There working example of how to do report aggregation was
* invaluable.</p>
* <p>
* An important point about using this abstract class is that it is intended for one to write some form of serialized
* data (via the {@link org.owasp.dependencycheck.maven.ReportAggregationMojo#writeDataFile() }; note that the
* <code>writeDataFile()</code> function is called automatically after either {@link org.owasp.dependencycheck.maven.ReportAggregationMojo#executeNonAggregateReport(org.apache.maven.doxia.sink.Sink,
* org.apache.maven.doxia.sink.SinkFactory, java.util.Locale)
* } or {@link org.owasp.dependencycheck.maven.ReportAggregationMojo#executeAggregateReport(org.apache.maven.doxia.sink.Sink,
* org.apache.maven.doxia.sink.SinkFactory, java.util.Locale)
* } are called. When <code>executeAggregateReport()</code> is implemented, one can call {@link org.owasp.dependencycheck.maven.ReportAggregationMojo#getChildDataFiles()
* } to obtain a list of the data files to aggregate.</p>
*
*
* @author Jeremy Long <jeremy.long@owasp.org>
*/
public abstract class ReportAggregationMojo extends AbstractMojo implements MavenReport {
/**
* The Maven Project Object.
*/
@Component
private MavenProject project;
/**
* Logger field reference.
*/
private static final Logger LOGGER = Logger.getLogger(ReportAggregationMojo.class.getName());
/**
* List of Maven project of the current build
*/
@Parameter(readonly = true, required = true, property = "reactorProjects")
private List<MavenProject> reactorProjects;
/**
* Generate aggregate reports in multi-module projects.
*/
@Parameter(property = "aggregate", defaultValue = "false")
private boolean aggregate;
/**
* Sets whether or not the external report format should be used.
*/
@Parameter(property = "metaFileName", defaultValue = "dependency-check.ser", required = true)
private String dataFileName;
/**
* Specifies the destination directory for the generated Dependency-Check report. This generally maps to
* "target/site".
*/
@Parameter(property = "reportOutputDirectory", defaultValue = "${project.reporting.outputDirectory}", required = true)
private File reportOutputDirectory;
/**
* Sets the Reporting output directory.
*
* @param directory the output directory
*/
@Override
public void setReportOutputDirectory(File directory) {
reportOutputDirectory = directory;
}
/**
* Returns the output directory.
*
* @return the output directory
*/
@Override
public File getReportOutputDirectory() {
return reportOutputDirectory;
}
/**
* Returns the output directory for the given project.
*
* @param project the Maven project to get the output directory for
* @return the output directory for the given project
*/
public File getReportOutputDirectory(MavenProject project) {
final Object o = project.getContextValue(getOutputDirectoryContextKey());
if (o != null && o instanceof File) {
return (File) o;
}
return null;
}
/**
* Returns whether this is an external report. This method always returns true.
*
* @return <code>true</code>
*/
@Override
public final boolean isExternalReport() {
return true;
}
/**
* Initializes the mojo.
*/
protected abstract void initialize();
/**
* The collection of child projects.
*/
private final Map<MavenProject, Set<MavenProject>> projectChildren = new HashMap<MavenProject, Set<MavenProject>>();
/**
* Called before execute; allows for any setup that is needed. If this is overridden you must call
* </code>super.preExecute()</code>.
*
* @throws MojoExecutionException thrown if there is an issue executing the mojo
* @throws MojoFailureException thrown if there is an issue executing the mojo
*/
protected void preExecute() throws MojoExecutionException, MojoFailureException {
buildAggregateInfo();
}
/**
* Called when the mojo is being executed.
*
* @throws MojoExecutionException thrown if there is an issue executing the mojo
* @throws MojoFailureException thrown if there is an issue executing the mojo
*/
protected abstract void performExecute() throws MojoExecutionException, MojoFailureException;
/**
* Runs after the mojo has executed. This implementation will call <code>writeDataFile()</code>. As such, it is
* important that if this method is overriden that <code>super.postExecute()</code> is called.
*
* @throws MojoExecutionException thrown if there is an issue executing the mojo
* @throws MojoFailureException thrown if there is an issue executing the mojo
*/
protected void postExecute() throws MojoExecutionException, MojoFailureException {
final File written = writeDataFile();
if (written != null) {
project.setContextValue(getDataFileContextKey(), written.getAbsolutePath());
}
}
/**
* Returns the key used to store the path to the data file that is saved by <code>writeDataFile()</code>. This key
* is used in the <code>MavenProject.(set|get)ContextValue</code>.
*
* @return the key used to store the path to the data file
*/
protected String getDataFileContextKey() {
return "dependency-check-path-" + this.getDataFileName();
}
/**
* Returns the key used to store the path to the output directory. When generating the report in the
* <code>executeAggregateReport()</code> the output directory should be obtained by using this key.
*
* @return the key used to store the path to the output directory
*/
protected String getOutputDirectoryContextKey() {
return "dependency-output-dir-" + this.getDataFileName();
}
/**
* Is called by Maven to execute the mojo.
*
* @throws MojoExecutionException thrown if there is an issue executing the mojo
* @throws MojoFailureException thrown if there is an issue executing the mojo
*/
public final void execute() throws MojoExecutionException, MojoFailureException {
try {
initialize();
preExecute();
performExecute();
} finally {
postExecute();
}
}
/**
* Runs prior to the site report generation.
*
* @throws MavenReportException if a maven report exception occurs
*/
protected void preGenerate() throws MavenReportException {
buildAggregateInfo();
project.setContextValue(getOutputDirectoryContextKey(), getReportOutputDirectory());
}
/**
* Executes after the site report has been generated.
*
* @throws MavenReportException if a maven report exception occurs
*/
protected void postGenerate() throws MavenReportException {
final File written = writeDataFile();
if (written != null) {
project.setContextValue(getDataFileContextKey(), written.getAbsolutePath());
}
}
/**
* Generates the non aggregate report.
*
* @param locale the locale to use when generating the report
* @throws MavenReportException if a maven report exception occurs
*/
protected abstract void executeNonAggregateReport(Locale locale) throws MavenReportException;
/**
* Generates the aggregate Site Report.
*
* @param project the maven project used to generate the aggregate report
* @param locale the locale to use when generating the report
* @throws MavenReportException if a maven report exception occurs
*/
protected abstract void executeAggregateReport(MavenProject project, Locale locale) throws MavenReportException;
/**
* Generates the Dependency-Check Site Report.
*
* @param sink the sink to write the report to
* @param locale the locale to use when generating the report
* @throws MavenReportException if a maven report exception occurs
* @deprecated use {@link #generate(org.apache.maven.doxia.sink.Sink, java.util.Locale) instead.
*/
@Deprecated
public final void generate(@SuppressWarnings("deprecation") org.codehaus.doxia.sink.Sink sink, Locale locale) throws MavenReportException {
generate((Sink) sink, locale);
}
/**
* Generates the Dependency-Check Site Report.
*
* @param sink the sink to write the report to
* @param locale the locale to use when generating the report
* @throws MavenReportException if a maven report exception occurs
*/
public final void generate(Sink sink, Locale locale) throws MavenReportException {
try {
initialize();
preGenerate();
if (canGenerateNonAggregateReport()) {
executeNonAggregateReport(locale);
}
} finally {
postGenerate();
}
if (canGenerateAggregateReport()) {
for (MavenProject proj : reactorProjects) {
if (!isMultiModule(proj)) {
continue;
}
executeAggregateReport(proj, locale);
}
}
}
/**
* Returns whether or not the mojo can generate a non-aggregate report for this project.
*
* @return <code>true</code> if a non-aggregate report can be generated, otherwise <code>false</code>
*/
protected abstract boolean canGenerateNonAggregateReport();
/**
* Returns whether or not we can generate any aggregate reports at this time.
*
* @return <code>true</code> if an aggregate report can be generated, otherwise <code>false</code>
*/
protected abstract boolean canGenerateAggregateReport();
/**
* Returns the name of the data file that contains the serialized data.
*
* @return the name of the data file that contains the serialized data
*/
protected String getDataFileName() {
return dataFileName;
}
/**
* Writes the data file to disk in the target directory.
*
* @return the File object referencing the data file that was written
*/
protected abstract File writeDataFile();
/**
* Collects the information needed for building aggregate reports.
*/
private void buildAggregateInfo() {
// build parent-child map
for (MavenProject proj : reactorProjects) {
Set<MavenProject> depList = projectChildren.get(proj.getParent());
if (depList == null) {
depList = new HashSet<MavenProject>();
projectChildren.put(proj.getParent(), depList);
}
depList.add(proj);
}
}
/**
* Returns a list containing all the recursive, non-pom children of the given project, never <code>null</code>.
*
* @return a list of child projects
*/
protected List<MavenProject> getAllChildren() {
return getAllChildren(project);
}
/**
* Returns a list containing all the recursive, non-pom children of the given project, never <code>null</code>.
*
* @param parentProject the parent project to collect the child project references
* @return a list of child projects
*/
protected List<MavenProject> getAllChildren(MavenProject parentProject) {
final Set<MavenProject> children = projectChildren.get(parentProject);
if (children == null) {
return Collections.emptyList();
}
final List<MavenProject> result = new ArrayList<MavenProject>();
for (MavenProject child : children) {
if (isMultiModule(child)) {
result.addAll(getAllChildren(child));
} else {
result.add(child);
}
}
return result;
}
/**
* Returns a list of data files that were produced by the direct children of the given MavenProject.
*
* @param project the Maven project to obtain the child data files from
* @return a list of the data files
*/
protected List<File> getAllChildDataFiles(MavenProject project) {
final List<MavenProject> children = getAllChildren(project);
return getDataFiles(children);
}
/**
* Returns any existing output files from the given list of projects.
*
* @param projects the list of projects to obtain the output files from
* @return a list of output files
*/
protected List<File> getDataFiles(List<MavenProject> projects) {
final List<File> files = new ArrayList<File>();
for (MavenProject proj : projects) {
final Object path = project.getContextValue(getDataFileContextKey());
if (path == null) {
final String msg = String.format("Unable to aggregate data for '%s' - aggregate data file was not generated",
proj.getName());
LOGGER.warning(msg);
} else {
final File outputFile = new File((String) path);
if (outputFile.exists()) {
files.add(outputFile);
} else {
if (!isMultiModule(project)) {
final String msg = String.format("Unable to aggregate data for '%s' - missing data file '%s'",
proj.getName(), outputFile.getPath());
LOGGER.warning(msg);
}
}
}
}
return files;
}
/**
* Test if the project has pom packaging
*
* @param mavenProject Project to test
* @return <code>true</code> if it has a pom packaging; otherwise <code>false</code>
*/
protected boolean isMultiModule(MavenProject mavenProject) {
return "pom".equals(mavenProject.getPackaging());
}
/**
* Test if the current project has pom packaging
*
* @return <code>true</code> if it has a pom packaging; otherwise <code>false</code>
*/
protected boolean isMultiModule() {
return isMultiModule(project);
}
/**
* Check whether the current project is the last project in a multi-module build. If the maven build is not a
* multi-module project then this will always return true.
*
* @return <code>true</code> if the current project is the last project in a multi-module build; otherwise
* <code>false</code>
*/
protected boolean isLastProject() {
return project.equals(reactorProjects.get(reactorProjects.size() - 1));
}
/**
* Returns whether or not the mojo is configured to perform report aggregation.
*
* @return <code>true</code> if report aggregation is enabled; otherwise <code>false</code>
*/
public boolean isAggregate() {
return aggregate;
}
/**
* Returns a reference to the current project. This method is used instead of auto-binding the project via component
* annotation in concrete implementations of this. If the child has a <code>@Component MavenProject project;</code>
* defined then the abstract class (i.e. this class) will not have access to the current project (just the way Maven
* works with the binding).
*
* @return returns a reference to the current project
*/
protected MavenProject getProject() {
return project;
}
}

View File

@@ -1,455 +0,0 @@
/*
* This file is part of dependency-check-maven.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright (c) 2014 Jeremy Long. All Rights Reserved.
*/
package org.owasp.dependencycheck.maven;
import java.io.File;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.text.DateFormat;
import java.util.Date;
import java.util.List;
import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.apache.maven.doxia.sink.Sink;
import org.owasp.dependencycheck.data.nvdcve.CveDB;
import org.owasp.dependencycheck.data.nvdcve.DatabaseException;
import org.owasp.dependencycheck.data.nvdcve.DatabaseProperties;
import org.owasp.dependencycheck.dependency.Dependency;
import org.owasp.dependencycheck.dependency.Evidence;
import org.owasp.dependencycheck.dependency.Identifier;
import org.owasp.dependencycheck.dependency.Reference;
import org.owasp.dependencycheck.dependency.Vulnerability;
import org.owasp.dependencycheck.dependency.VulnerableSoftware;
import org.owasp.dependencycheck.reporting.ReportGenerator;
/**
* A utility class that encapsulates the report generation for dependency-check-maven.
*
* @author Jeremy Long <jeremy.long@owasp.org>
*/
final class ReportingUtil {
/**
* Logger field reference.
*/
private static final Logger LOGGER = Logger.getLogger(ReportingUtil.class.getName());
/**
* Empty private constructor for this utility class.
*/
private ReportingUtil() {
}
/**
* Generates the reports for a given dependency-check engine.
*
* @param engine a dependency-check engine
* @param outDirectory the directory to write the reports to
* @param projectName the name of the project that a report is being generated for
* @param format the format of the report to generate
*/
static void generateExternalReports(Engine engine, File outDirectory, String projectName, String format) {
DatabaseProperties prop = null;
CveDB cve = null;
try {
cve = new CveDB();
cve.open();
prop = cve.getDatabaseProperties();
} catch (DatabaseException ex) {
LOGGER.log(Level.FINE, "Unable to retrieve DB Properties", ex);
} finally {
if (cve != null) {
cve.close();
}
}
final ReportGenerator r = new ReportGenerator(projectName, engine.getDependencies(), engine.getAnalyzers(), prop);
try {
r.generateReports(outDirectory.getCanonicalPath(), format);
} catch (IOException ex) {
LOGGER.log(Level.SEVERE,
"Unexpected exception occurred during analysis; please see the verbose error log for more details.");
LOGGER.log(Level.FINE, null, ex);
} catch (Throwable ex) {
LOGGER.log(Level.SEVERE,
"Unexpected exception occurred during analysis; please see the verbose error log for more details.");
LOGGER.log(Level.FINE, null, ex);
}
}
/**
* Generates a dependency-check report using the Maven Site format.
*
* @param engine the engine used to scan the dependencies
* @param sink the sink to write the data to
* @param projectName the name of the project
*/
static void generateMavenSiteReport(final Engine engine, Sink sink, String projectName) {
final List<Dependency> dependencies = engine.getDependencies();
writeSiteReportHeader(sink, projectName);
writeSiteReportTOC(sink, dependencies);
int cnt = 0;
for (Dependency d : dependencies) {
writeSiteReportDependencyHeader(sink, d);
cnt = writeSiteReportDependencyEvidenceUsed(d, cnt, sink);
cnt = writeSiteReportDependencyRelatedDependencies(d, cnt, sink);
writeSiteReportDependencyIdentifiers(d, sink);
writeSiteReportDependencyVulnerabilities(d, sink, cnt);
}
sink.body_();
}
// <editor-fold defaultstate="collapsed" desc="various writeXXXXX methods to generate the Site Report">
/**
* Writes the vulnerabilities to the site report.
*
* @param d the dependency
* @param sink the sink to write the data to
* @param collapsibleHeaderCount the collapsible header count
*/
private static void writeSiteReportDependencyVulnerabilities(Dependency d, Sink sink, int collapsibleHeaderCount) {
int cnt = collapsibleHeaderCount;
if (d.getVulnerabilities() != null && !d.getVulnerabilities().isEmpty()) {
for (Vulnerability v : d.getVulnerabilities()) {
sink.paragraph();
sink.bold();
try {
sink.link("http://web.nvd.nist.gov/view/vuln/detail?vulnId=" + URLEncoder.encode(v.getName(), "US-ASCII"));
sink.text(v.getName());
sink.link_();
sink.bold_();
} catch (UnsupportedEncodingException ex) {
sink.text(v.getName());
sink.bold_();
sink.lineBreak();
sink.text("http://web.nvd.nist.gov/view/vuln/detail?vulnId=" + v.getName());
}
sink.paragraph_();
sink.paragraph();
sink.text("Severity: ");
if (v.getCvssScore() < 4.0) {
sink.text("Low");
} else {
if (v.getCvssScore() >= 7.0) {
sink.text("High");
} else {
sink.text("Medium");
}
}
sink.lineBreak();
sink.text("CVSS Score: " + v.getCvssScore());
if (v.getCwe() != null && !v.getCwe().isEmpty()) {
sink.lineBreak();
sink.text("CWE: ");
sink.text(v.getCwe());
}
sink.paragraph_();
sink.paragraph();
sink.text(v.getDescription());
if (v.getReferences() != null && !v.getReferences().isEmpty()) {
sink.list();
for (Reference ref : v.getReferences()) {
sink.listItem();
sink.text(ref.getSource());
sink.text(" - ");
sink.link(ref.getUrl());
sink.text(ref.getName());
sink.link_();
sink.listItem_();
}
sink.list_();
}
sink.paragraph_();
if (v.getVulnerableSoftware() != null && !v.getVulnerableSoftware().isEmpty()) {
sink.paragraph();
cnt += 1;
sink.rawText("Vulnerable Software <a href=\"javascript:toggleElement(this, 'vulnSoft" + cnt + "')\">[-]</a>");
sink.rawText("<div id=\"vulnSoft" + cnt + "\" style=\"display:block\">");
sink.list();
for (VulnerableSoftware vs : v.getVulnerableSoftware()) {
sink.listItem();
try {
sink.link("http://web.nvd.nist.gov/view/vuln/search-results?cpe=" + URLEncoder.encode(vs.getName(), "US-ASCII"));
sink.text(vs.getName());
sink.link_();
if (vs.hasPreviousVersion()) {
sink.text(" and all previous versions.");
}
} catch (UnsupportedEncodingException ex) {
sink.text(vs.getName());
if (vs.hasPreviousVersion()) {
sink.text(" and all previous versions.");
}
sink.text(" (http://web.nvd.nist.gov/view/vuln/search-results?cpe=" + vs.getName() + ")");
}
sink.listItem_();
}
sink.list_();
sink.rawText("</div>");
sink.paragraph_();
}
}
}
}
/**
* Writes the identifiers to the site report.
*
* @param d the dependency
* @param sink the sink to write the data to
*/
private static void writeSiteReportDependencyIdentifiers(Dependency d, Sink sink) {
if (d.getIdentifiers() != null && !d.getIdentifiers().isEmpty()) {
sink.sectionTitle4();
sink.text("Identifiers");
sink.sectionTitle4_();
sink.list();
for (Identifier i : d.getIdentifiers()) {
sink.listItem();
sink.text(i.getType());
sink.text(": ");
if (i.getUrl() != null && i.getUrl().length() > 0) {
sink.link(i.getUrl());
sink.text(i.getValue());
sink.link_();
} else {
sink.text(i.getValue());
}
if (i.getDescription() != null && i.getDescription().length() > 0) {
sink.lineBreak();
sink.text(i.getDescription());
}
sink.listItem_();
}
sink.list_();
}
}
/**
* Writes the related dependencies to the site report.
*
* @param d the dependency
* @param sink the sink to write the data to
* @param collapsibleHeaderCount the collapsible header count
* @return the collapsible header count
*/
private static int writeSiteReportDependencyRelatedDependencies(Dependency d, int collapsibleHeaderCount, Sink sink) {
int cnt = collapsibleHeaderCount;
if (d.getRelatedDependencies() != null && !d.getRelatedDependencies().isEmpty()) {
cnt += 1;
sink.sectionTitle4();
sink.rawText("Related Dependencies <a href=\"javascript:toggleElement(this, 'related" + cnt + "')\">[+]</a>");
sink.sectionTitle4_();
sink.rawText("<div id=\"related" + cnt + "\" style=\"display:none\">");
sink.list();
for (Dependency r : d.getRelatedDependencies()) {
sink.listItem();
sink.text(r.getFileName());
sink.list();
writeListItem(sink, "File Path: " + r.getFilePath());
writeListItem(sink, "SHA1: " + r.getSha1sum());
writeListItem(sink, "MD5: " + r.getMd5sum());
sink.list_();
sink.listItem_();
}
sink.list_();
sink.rawText("</div>");
}
return cnt;
}
/**
* Writes the evidence used to the site report.
*
* @param d the dependency
* @param sink the sink to write the data to
* @param collapsibleHeaderCount the collapsible header count
* @return the collapsible header count
*/
private static int writeSiteReportDependencyEvidenceUsed(Dependency d, int collapsibleHeaderCount, Sink sink) {
int cnt = collapsibleHeaderCount;
final Set<Evidence> evidence = d.getEvidenceForDisplay();
if (evidence != null && evidence.size() > 0) {
cnt += 1;
sink.sectionTitle4();
sink.rawText("Evidence Collected <a href=\"javascript:toggleElement(this, 'evidence" + cnt + "')\">[+]</a>");
sink.sectionTitle4_();
sink.rawText("<div id=\"evidence" + cnt + "\" style=\"display:none\">");
sink.table();
sink.tableRow();
writeTableHeaderCell(sink, "Source");
writeTableHeaderCell(sink, "Name");
writeTableHeaderCell(sink, "Value");
sink.tableRow_();
for (Evidence e : evidence) {
sink.tableRow();
writeTableCell(sink, e.getSource());
writeTableCell(sink, e.getName());
writeTableCell(sink, e.getValue());
sink.tableRow_();
}
sink.table_();
sink.rawText("</div>");
}
return cnt;
}
/**
* Writes the dependency header to the site report.
*
* @param d the dependency
* @param sink the sink to write the data to
*/
private static void writeSiteReportDependencyHeader(Sink sink, Dependency d) {
sink.sectionTitle2();
sink.anchor("sha1" + d.getSha1sum());
sink.text(d.getFileName());
sink.anchor_();
sink.sectionTitle2_();
if (d.getDescription() != null && d.getDescription().length() > 0) {
sink.paragraph();
sink.bold();
sink.text("Description: ");
sink.bold_();
sink.text(d.getDescription());
sink.paragraph_();
}
if (d.getLicense() != null && d.getLicense().length() > 0) {
sink.paragraph();
sink.bold();
sink.text("License: ");
sink.bold_();
if (d.getLicense().startsWith("http://") && !d.getLicense().contains(" ")) {
sink.link(d.getLicense());
sink.text(d.getLicense());
sink.link_();
} else {
sink.text(d.getLicense());
}
sink.paragraph_();
}
}
/**
* Adds a list item to the site report.
*
* @param sink the sink to write the data to
* @param text the text to write
*/
private static void writeListItem(Sink sink, String text) {
sink.listItem();
sink.text(text);
sink.listItem_();
}
/**
* Adds a table cell to the site report.
*
* @param sink the sink to write the data to
* @param text the text to write
*/
private static void writeTableCell(Sink sink, String text) {
sink.tableCell();
sink.text(text);
sink.tableCell_();
}
/**
* Adds a table header cell to the site report.
*
* @param sink the sink to write the data to
* @param text the text to write
*/
private static void writeTableHeaderCell(Sink sink, String text) {
sink.tableHeaderCell();
sink.text(text);
sink.tableHeaderCell_();
}
/**
* Writes the TOC for the site report.
*
* @param sink the sink to write the data to
* @param dependencies the dependencies that are being reported on
*/
private static void writeSiteReportTOC(Sink sink, final List<Dependency> dependencies) {
sink.list();
for (Dependency d : dependencies) {
sink.listItem();
sink.link("#sha1" + d.getSha1sum());
sink.text(d.getFileName());
sink.link_();
if (!d.getVulnerabilities().isEmpty()) {
sink.rawText(" <font style=\"color:red\">•</font>");
}
if (!d.getRelatedDependencies().isEmpty()) {
sink.list();
for (Dependency r : d.getRelatedDependencies()) {
writeListItem(sink, r.getFileName());
}
sink.list_();
}
sink.listItem_();
}
sink.list_();
}
/**
* Writes the site report header.
*
* @param sink the sink to write the data to
* @param projectName the name of the project
*/
private static void writeSiteReportHeader(Sink sink, String projectName) {
sink.head();
sink.title();
sink.text("Dependency-Check Report: " + projectName);
sink.title_();
sink.head_();
sink.body();
sink.rawText("<script type=\"text/javascript\">");
sink.rawText("function toggleElement(el, targetId) {");
sink.rawText("if (el.innerText == '[+]') {");
sink.rawText(" el.innerText = '[-]';");
sink.rawText(" document.getElementById(targetId).style.display='block';");
sink.rawText("} else {");
sink.rawText(" el.innerText = '[+]';");
sink.rawText(" document.getElementById(targetId).style.display='none';");
sink.rawText("}");
sink.rawText("}");
sink.rawText("</script>");
sink.section1();
sink.sectionTitle1();
sink.text("Project: " + projectName);
sink.sectionTitle1_();
sink.date();
final Date now = new Date();
sink.text(DateFormat.getDateTimeInstance().format(now));
sink.date_();
sink.section1_();
}
// </editor-fold>
}

View File

@@ -1,10 +1,18 @@
Goals
====================
Goal | Description
-----------|-----------------------
aggregate | Runs dependency-check against the child projects and aggregates the results into a single report.
check | Runs dependency-check against the project and generates a report.
Configuration
====================
The following properties can be set on the dependency-check-maven plugin.
Property | Description | Default Value
---------------------|------------------------------------|------------------
aggregate | Sets whether report aggregation will be performed for multi-module site reports. This option only affects the report generation when configured within the reporting section. | false
aggregate | Deprecated - use the aggregate goal instead. | &nbsp;
autoUpdate | Sets whether auto-updating of the NVD CVE/CPE data is enabled. It is not recommended that this be turned to false. | true
outputDirectory | The location to write the report(s). Note, this is not used if generating the report as part of a `mvn site` build | 'target'
failBuildOnCVSS | Specifies if the build should be failed if a CVSS score above a specified level is identified. The default is 11 which means since the CVSS scores are 0-10, by default the build will never fail. | 11
@@ -28,7 +36,8 @@ Property | Description
archiveAnalyzerEnabled | Sets whether the Archive Analyzer will be used. | true
zipExtensions | A comma-separated list of additional file extensions to be treated like a ZIP file, the contents will be extracted and analyzed. | &nbsp;
jarAnalyzer | Sets whether Jar Analyzer will be used. | true
nexusAnalyzerEnabled | Sets whether Nexus Analyzer will be used. | true
centralAnalyzerEnabled | Sets whether Central Analyzer will be used. If this analyzer is being disabled there is a good chance you also want to disable the Nexus Analyzer (see below). | true
nexusAnalyzerEnabled | Sets whether Nexus Analyzer will be used. This analyzer is superceded by the Central Analyzer; however, you can configure this to run against a Nexus Pro installation. | true
nexusUrl | Defines the Nexus Pro Server URL. If not set the Nexus Analyzer will be disabled. | &nbsp;
nexusUsesProxy | Whether or not the defined proxy should be used when connecting to Nexus. | true
nuspecAnalyzerEnabled | Sets whether or not the .NET Nuget Nuspec Analyzer will be used. | true

View File

@@ -13,7 +13,7 @@ seven days the update will only take a few seconds.
#set( $H = '#' )
$H$H$H Example 1:
Create the DependencyCheck-report.html in the target directory
Create the DependencyCheck-report.html in the target directory.
```xml
<project>
@@ -43,7 +43,7 @@ Create the DependencyCheck-report.html in the target directory
```
$H$H$H Example 2:
Create an aggregated dependency-check report within the site
Create an aggregated dependency-check report within the site.
```xml
<project>
@@ -57,13 +57,10 @@ Create an aggregated dependency-check report within the site
<groupId>org.owasp</groupId>
<artifactId>dependency-check-maven</artifactId>
<version>${project.version}</version>
<configuration>
<aggregate>true</aggregate>
</configuration>
<reportSets>
<reportSet>
<reports>
<report>check</report>
<report>aggregate</report>
</reports>
</reportSet>
</reportSets>
@@ -78,7 +75,7 @@ Create an aggregated dependency-check report within the site
```
$H$H$H Example 3:
Create the DependencyCheck-report.html and fail the build for CVSS greater then 8
Create the DependencyCheck-report.html and fail the build for CVSS greater then 8.
```xml
<project>
@@ -111,7 +108,7 @@ Create the DependencyCheck-report.html and fail the build for CVSS greater then
```
$H$H$H Example 4:
Create the DependencyCheck-report.html and skip artifacts not bundled in distribution (Provided and Runtime scope)
Create the DependencyCheck-report.html and skip artifacts not bundled in distribution (Provided and Runtime scope).
```xml
<project>
@@ -145,7 +142,7 @@ Create the DependencyCheck-report.html and skip artifacts not bundled in distrib
```
$H$H$H Example 5:
Create the DependencyCheck-report.html and use internal mirroring of CVE contents
Create the DependencyCheck-report.html and use internal mirroring of CVE contents.
```xml
<project>

View File

@@ -0,0 +1,106 @@
/*
* This file is part of dependency-check-maven.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright (c) 2014 Jeremy Long. All Rights Reserved.
*/
package org.owasp.dependencycheck.maven;
import java.io.File;
import java.net.URISyntaxException;
import java.util.HashSet;
import java.util.Locale;
import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;
import mockit.Mock;
import mockit.MockUp;
import org.apache.maven.artifact.Artifact;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugin.MojoFailureException;
import org.apache.maven.plugin.testing.stubs.ArtifactStub;
import org.apache.maven.project.MavenProject;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import org.junit.Test;
import org.owasp.dependencycheck.data.nvdcve.DatabaseException;
import org.owasp.dependencycheck.utils.InvalidSettingException;
import org.owasp.dependencycheck.utils.Settings;
/**
*
* @author Jeremy Long <jeremy.long@owasp.org>
*/
public class BaseDependencyCheckMojoTest extends BaseTest {
/**
* Test of scanArtifacts method, of class BaseDependencyCheckMojo.
*/
@Test
public void testScanArtifacts() throws DatabaseException, InvalidSettingException {
MavenProject project = new MockUp<MavenProject>() {
@Mock
public Set<Artifact> getArtifacts() {
Set<Artifact> artifacts = new HashSet<Artifact>();
Artifact a = new ArtifactStub();
try {
File file = new File(Test.class.getProtectionDomain().getCodeSource().getLocation().toURI());
a.setFile(file);
artifacts.add(a);
} catch (URISyntaxException ex) {
Logger.getLogger(BaseDependencyCheckMojoTest.class.getName()).log(Level.SEVERE, null, ex);
}
//File file = new File(this.getClass().getClassLoader().getResource("daytrader-ear-2.1.7.ear").getPath());
return artifacts;
}
}.getMockInstance();
boolean autoUpdate = Settings.getBoolean(Settings.KEYS.AUTO_UPDATE);
Settings.setBoolean(Settings.KEYS.AUTO_UPDATE, false);
Engine engine = new Engine(null, null);
Settings.setBoolean(Settings.KEYS.AUTO_UPDATE, autoUpdate);
assertTrue(engine.getDependencies().isEmpty());
BaseDependencyCheckMojoImpl instance = new BaseDependencyCheckMojoImpl();
instance.scanArtifacts(project, engine);
assertFalse(engine.getDependencies().isEmpty());
engine.cleanup();
}
public class BaseDependencyCheckMojoImpl extends BaseDependencyCheckMojo {
@Override
public void runCheck() throws MojoExecutionException, MojoFailureException {
throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
}
@Override
public String getName(Locale locale) {
return "test implementation";
}
@Override
public String getDescription(Locale locale) {
return "test implementation";
}
@Override
public boolean canGenerateReport() {
throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
}
}
}

View File

@@ -0,0 +1,47 @@
/*
* This file is part of dependency-check-maven.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright (c) 2014 Jeremy Long. All Rights Reserved.
*/
package org.owasp.dependencycheck.maven;
import java.io.InputStream;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.owasp.dependencycheck.utils.Settings;
/**
*
* @author Jeremy Long <jeremy.long@owasp.org>
*/
public class BaseTest {
/**
* The properties file location.
*/
public static final String PROPERTIES_FILE = "mojo.properties";
@BeforeClass
public static void setUpClass() throws Exception {
Settings.initialize();
InputStream mojoProperties = BaseTest.class.getClassLoader().getResourceAsStream(BaseTest.PROPERTIES_FILE);
Settings.mergeProperties(mojoProperties);
}
@AfterClass
public static void tearDownClass() throws Exception {
Settings.cleanup(true);
}
}

View File

@@ -1,210 +0,0 @@
/*
* This file is part of dependency-check-maven.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright (c) 2013 Jeremy Long. All Rights Reserved.
*/
package org.owasp.dependencycheck.maven;
import org.apache.maven.plugin.testing.AbstractMojoTestCase;
import org.junit.After;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
/**
* TODO - figure out how to get the test harness to work. ATM no tests are running.
*
* @author Jeremy Long <jeremy.long@owasp.org>
*/
public class DependencyCheckMojoTest extends AbstractMojoTestCase {
public DependencyCheckMojoTest() {
}
@BeforeClass
public static void setUpClass() throws Exception {
}
@AfterClass
public static void tearDownClass() throws Exception {
}
@Before
public void setUp() {
}
@After
public void tearDown() {
}
//
// /**
// * Test of execute method, of class DependencyCheckMojo.
// */
// @Test
// public void testExecute() throws Exception {
// System.out.println("execute");
// DependencyCheckMojo instance = new DependencyCheckMojo();
// instance.execute();
// // TODO review the generated test code and remove the default call to fail.
// fail("The test case is a prototype.");
// }
//
// /**
// * Test of generate method, of class DependencyCheckMojo.
// */
// @Test
// public void testGenerate_Sink_Locale() throws Exception {
// System.out.println("generate");
// org.codehaus.doxia.sink.Sink sink = null;
// Locale locale = null;
// DependencyCheckMojo instance = new DependencyCheckMojo();
// instance.generate(sink, locale);
// // TODO review the generated test code and remove the default call to fail.
// fail("The test case is a prototype.");
// }
/**
* Test of generate method, of class DependencyCheckMojo.
*/
@Test
public void testGenerate_Sink_SinkFactory_Locale() throws Exception {
//can't get the test-harness to work.
// File samplePom = new File(this.getClass().getClassLoader().getResource("sample.xml").toURI());
// DependencyCheckMojo mojo = (DependencyCheckMojo) lookupMojo("check", samplePom);
// assertNotNull("Unable to load mojo", mojo);
//
// File out = mojo.getReportOutputDirectory();
// OutputStream os = new FileOutputStream(out);
// MySink sink = new MySink(os);
// Locale locale = new Locale("en");
//
//
// mojo.generate(sink, null, locale);
// sink.close();
}
// /**
// * Test of getOutputName method, of class DependencyCheckMojo.
// */
// @Test
// public void testGetOutputName() {
// System.out.println("getOutputName");
// DependencyCheckMojo instance = new DependencyCheckMojo();
// String expResult = "";
// String result = instance.getOutputName();
// assertEquals(expResult, result);
// // TODO review the generated test code and remove the default call to fail.
// fail("The test case is a prototype.");
// }
//
// /**
// * Test of getCategoryName method, of class DependencyCheckMojo.
// */
// @Test
// public void testGetCategoryName() {
// System.out.println("getCategoryName");
// DependencyCheckMojo instance = new DependencyCheckMojo();
// String expResult = "";
// String result = instance.getCategoryName();
// assertEquals(expResult, result);
// // TODO review the generated test code and remove the default call to fail.
// fail("The test case is a prototype.");
// }
//
// /**
// * Test of getName method, of class DependencyCheckMojo.
// */
// @Test
// public void testGetName() {
// System.out.println("getName");
// Locale locale = null;
// DependencyCheckMojo instance = new DependencyCheckMojo();
// String expResult = "";
// String result = instance.getName(locale);
// assertEquals(expResult, result);
// // TODO review the generated test code and remove the default call to fail.
// fail("The test case is a prototype.");
// }
//
// /**
// * Test of setReportOutputDirectory method, of class DependencyCheckMojo.
// */
// @Test
// public void testSetReportOutputDirectory() {
// System.out.println("setReportOutputDirectory");
// File directory = null;
// DependencyCheckMojo instance = new DependencyCheckMojo();
// instance.setReportOutputDirectory(directory);
// // TODO review the generated test code and remove the default call to fail.
// fail("The test case is a prototype.");
// }
//
// /**
// * Test of getReportOutputDirectory method, of class DependencyCheckMojo.
// */
// @Test
// public void testGetReportOutputDirectory() {
// System.out.println("getReportOutputDirectory");
// DependencyCheckMojo instance = new DependencyCheckMojo();
// File expResult = null;
// File result = instance.getReportOutputDirectory();
// assertEquals(expResult, result);
// // TODO review the generated test code and remove the default call to fail.
// fail("The test case is a prototype.");
// }
//
// /**
// * Test of getDescription method, of class DependencyCheckMojo.
// */
// @Test
// public void testGetDescription() {
// System.out.println("getDescription");
// Locale locale = null;
// DependencyCheckMojo instance = new DependencyCheckMojo();
// String expResult = "";
// String result = instance.getDescription(locale);
// assertEquals(expResult, result);
// // TODO review the generated test code and remove the default call to fail.
// fail("The test case is a prototype.");
// }
//
// /**
// * Test of isExternalReport method, of class DependencyCheckMojo.
// */
// @Test
// public void testIsExternalReport() {
// System.out.println("isExternalReport");
// DependencyCheckMojo instance = new DependencyCheckMojo();
// boolean expResult = false;
// boolean result = instance.isExternalReport();
// assertEquals(expResult, result);
// // TODO review the generated test code and remove the default call to fail.
// fail("The test case is a prototype.");
// }
//
// /**
// * Test of canGenerateReport method, of class DependencyCheckMojo.
// */
// @Test
// public void testCanGenerateReport() {
// System.out.println("canGenerateReport");
// DependencyCheckMojo instance = new DependencyCheckMojo();
// boolean expResult = false;
// boolean result = instance.canGenerateReport();
// assertEquals(expResult, result);
// // TODO review the generated test code and remove the default call to fail.
// fail("The test case is a prototype.");
// }
}

View File

@@ -1,601 +0,0 @@
/*
* This file is part of dependency-check-maven.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright (c) 2013 Jeremy Long. All Rights Reserved.
*/
package org.owasp.dependencycheck.maven;
import java.io.IOException;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.apache.maven.doxia.logging.Log;
import org.apache.maven.doxia.sink.Sink;
import org.apache.maven.doxia.sink.SinkEventAttributes;
/**
*
* @author Jeremy Long <jeremy.long@owasp.org>
*/
public class MySink implements Sink {
private OutputStreamWriter out = null;
public MySink(OutputStream os) {
out = new OutputStreamWriter(os);
}
private void writeTag(String tag) {
try {
out.write(tag);
} catch (IOException ex) {
Logger.getLogger(MySink.class.getName()).log(Level.SEVERE, "Error writing a tag; unable to generate the report");
Logger.getLogger(MySink.class.getName()).log(Level.FINE, null, ex);
}
}
public void head() {
writeTag("<head>");
}
public void head_() {
writeTag("</head>");
}
public void title() {
writeTag("<title>");
}
public void title_() {
writeTag("</title>");
}
public void author() {
writeTag("<author>");
}
public void author_() {
writeTag("</author>");
}
public void date() {
writeTag("<time>");
}
public void date_() {
writeTag("</time>");
}
public void body() {
writeTag("<body>");
}
public void body_() {
writeTag("</body>");
}
public void sectionTitle() {
writeTag("<h1>");
}
public void sectionTitle_() {
writeTag("</h1>");
}
public void section1() {
writeTag("<div>");
}
public void section1_() {
writeTag("</div>");
}
public void sectionTitle1() {
writeTag("<h2>");
}
public void sectionTitle1_() {
writeTag("</h2>");
}
public void section2() {
writeTag("<div>");
}
public void section2_() {
writeTag("</div>");
}
public void sectionTitle2() {
writeTag("<h3>");
}
public void sectionTitle2_() {
writeTag("</h3>");
}
public void section3() {
writeTag("<div>");
}
public void section3_() {
writeTag("</div>");
}
public void sectionTitle3() {
writeTag("<h4>");
}
public void sectionTitle3_() {
writeTag("</h4>");
}
public void section4() {
writeTag("<div>");
}
public void section4_() {
writeTag("</div>");
}
public void sectionTitle4() {
writeTag("<h5>");
}
public void sectionTitle4_() {
writeTag("</h5>");
}
public void section5() {
writeTag("<div>");
}
public void section5_() {
writeTag("</div>");
}
public void sectionTitle5() {
writeTag("<h6>");
}
public void sectionTitle5_() {
writeTag("</h6>");
}
public void list() {
writeTag("<ul>");
}
public void list_() {
writeTag("</ul>");
}
public void listItem() {
writeTag("<li>");
}
public void listItem_() {
writeTag("</li>");
}
public void numberedList(int numbering) {
writeTag("<ol>");
}
public void numberedList_() {
writeTag("</ol>");
}
public void numberedListItem() {
writeTag("<li>");
}
public void numberedListItem_() {
writeTag("</li>");
}
public void definitionList() {
writeTag("<dl>");
}
public void definitionList_() {
writeTag("</dl>");
}
public void definitionListItem() {
writeTag("<dt>");
}
public void definitionListItem_() {
writeTag("</dt>");
}
public void definition() {
writeTag("<dd>");
}
public void definition_() {
writeTag("</dd>");
}
public void definedTerm() {
writeTag("<dt>");
}
public void definedTerm_() {
writeTag("</dt>");
}
public void figure() {
throw new UnsupportedOperationException("Not supported yet.");
}
public void figure_() {
throw new UnsupportedOperationException("Not supported yet.");
}
public void figureCaption() {
throw new UnsupportedOperationException("Not supported yet.");
}
public void figureCaption_() {
throw new UnsupportedOperationException("Not supported yet.");
}
public void figureGraphics(String name) {
throw new UnsupportedOperationException("Not supported yet.");
}
public void table() {
writeTag("<table>");
}
public void table_() {
writeTag("</table>");
}
public void tableRows(int[] justification, boolean grid) {
writeTag("<tr>");
}
public void tableRows_() {
writeTag("</tr>");
}
public void tableRow() {
writeTag("<tr>");
}
public void tableRow_() {
writeTag("</tr>");
}
public void tableCell() {
writeTag("<td>");
}
public void tableCell(String width) {
writeTag("<td>");
}
public void tableCell_() {
writeTag("</td>");
}
public void tableHeaderCell() {
writeTag("<th>");
}
public void tableHeaderCell(String width) {
writeTag("<th>");
}
public void tableHeaderCell_() {
writeTag("</th>");
}
public void tableCaption() {
writeTag("<caption>");
}
public void tableCaption_() {
writeTag("</caption>");
}
public void paragraph() {
writeTag("<p>");
}
public void paragraph_() {
writeTag("</p>");
}
public void verbatim(boolean boxed) {
writeTag("<pre>");
}
public void verbatim_() {
writeTag("</pre>");
}
public void horizontalRule() {
writeTag("<hr/>");
}
public void pageBreak() {
writeTag("<br/>");
}
public void anchor(String name) {
writeTag("<a href=\"" + name + "\">");
}
public void anchor_() {
writeTag("</a>");
}
public void link(String name) {
writeTag("<link href=\"" + name + "\">");
}
public void link_() {
writeTag("</link>");
}
public void italic() {
writeTag("<i>");
}
public void italic_() {
writeTag("</i>");
}
public void bold() {
writeTag("<b>");
}
public void bold_() {
writeTag("</b>");
}
public void monospaced() {
writeTag("<pre>");
}
public void monospaced_() {
writeTag("</pre>");
}
public void lineBreak() {
writeTag("<br>");
}
public void nonBreakingSpace() {
writeTag("&nbsp;");
}
public void text(String text) {
try {
//TODO add HTML Encoding - or figure out how to get the doxia xhtmlsink to work.
out.write(text);
} catch (IOException ex) {
Logger.getLogger(MySink.class.getName()).log(Level.SEVERE, "Error writing a text; unable to generate the report");
Logger.getLogger(MySink.class.getName()).log(Level.FINE, null, ex);
}
}
public void rawText(String text) {
try {
out.write(text);
} catch (IOException ex) {
Logger.getLogger(MySink.class.getName()).log(Level.SEVERE, "Error writing raw text; unable to generate the report");
Logger.getLogger(MySink.class.getName()).log(Level.FINE, null, ex);
}
}
public void flush() {
try {
out.flush();
} catch (IOException ex) {
Logger.getLogger(MySink.class.getName()).log(Level.FINEST, null, ex);
}
}
public void close() {
flush();
try {
out.close();
} catch (IOException ex) {
Logger.getLogger(MySink.class.getName()).log(Level.FINEST, null, ex);
}
}
@Override
public void head(SinkEventAttributes sea) {
throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
}
@Override
public void title(SinkEventAttributes sea) {
throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
}
@Override
public void author(SinkEventAttributes sea) {
throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
}
@Override
public void date(SinkEventAttributes sea) {
throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
}
@Override
public void body(SinkEventAttributes sea) {
throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
}
@Override
public void section(int i, SinkEventAttributes sea) {
throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
}
@Override
public void section_(int i) {
throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
}
@Override
public void sectionTitle(int i, SinkEventAttributes sea) {
throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
}
@Override
public void sectionTitle_(int i) {
throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
}
@Override
public void list(SinkEventAttributes sea) {
throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
}
@Override
public void listItem(SinkEventAttributes sea) {
throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
}
@Override
public void numberedList(int i, SinkEventAttributes sea) {
throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
}
@Override
public void numberedListItem(SinkEventAttributes sea) {
throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
}
@Override
public void definitionList(SinkEventAttributes sea) {
throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
}
@Override
public void definitionListItem(SinkEventAttributes sea) {
throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
}
@Override
public void definition(SinkEventAttributes sea) {
throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
}
@Override
public void definedTerm(SinkEventAttributes sea) {
throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
}
@Override
public void figure(SinkEventAttributes sea) {
throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
}
@Override
public void figureCaption(SinkEventAttributes sea) {
throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
}
@Override
public void figureGraphics(String string, SinkEventAttributes sea) {
throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
}
@Override
public void table(SinkEventAttributes sea) {
throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
}
@Override
public void tableRow(SinkEventAttributes sea) {
throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
}
@Override
public void tableCell(SinkEventAttributes sea) {
throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
}
@Override
public void tableHeaderCell(SinkEventAttributes sea) {
throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
}
@Override
public void tableCaption(SinkEventAttributes sea) {
throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
}
@Override
public void paragraph(SinkEventAttributes sea) {
throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
}
@Override
public void verbatim(SinkEventAttributes sea) {
throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
}
@Override
public void horizontalRule(SinkEventAttributes sea) {
throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
}
@Override
public void anchor(String string, SinkEventAttributes sea) {
throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
}
@Override
public void link(String string, SinkEventAttributes sea) {
throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
}
@Override
public void lineBreak(SinkEventAttributes sea) {
throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
}
@Override
public void text(String string, SinkEventAttributes sea) {
throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
}
@Override
public void comment(String string) {
throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
}
@Override
public void unknown(String string, Object[] os, SinkEventAttributes sea) {
throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
}
@Override
public void enableLogging(Log log) {
throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
}
}

View File

@@ -0,0 +1,2 @@
# the path to the data directory
data.directory=[JAR]/dependency-check-data

View File

@@ -21,7 +21,7 @@ Copyright (c) 2014 - Jeremy Long. All Rights Reserved.
<parent>
<groupId>org.owasp</groupId>
<artifactId>dependency-check-parent</artifactId>
<version>1.2.7</version>
<version>1.2.8</version>
</parent>
<artifactId>dependency-check-utils</artifactId>

View File

@@ -80,11 +80,11 @@ public final class Downloader {
try {
org.apache.commons.io.FileUtils.copyFile(file, outputPath);
} catch (IOException ex) {
final String msg = String.format("Download failed, unable to copy '%s'", url.toString());
final String msg = String.format("Download failed, unable to copy '%s' to '%s'", url.toString(), outputPath.getAbsolutePath());
throw new DownloadFailedException(msg);
}
} else {
final String msg = String.format("Download failed, file does not exist '%s'", url.toString());
final String msg = String.format("Download failed, file ('%s') does not exist", url.toString());
throw new DownloadFailedException(msg);
}
} else {
@@ -101,7 +101,8 @@ public final class Downloader {
} finally {
conn = null;
}
throw new DownloadFailedException("Error downloading file.", ex);
final String msg = String.format("Error downloading file %s; unable to connect.", url.toString());
throw new DownloadFailedException(msg, ex);
}
final String encoding = conn.getContentEncoding();
@@ -122,13 +123,19 @@ public final class Downloader {
while ((bytesRead = reader.read(buffer)) > 0) {
writer.write(buffer, 0, bytesRead);
}
} catch (IOException ex) {
final String msg = String.format("Error saving '%s' to file '%s'%nConnection Timeout: %d%nEncoding: %s%n",
url.toString(), outputPath.getAbsolutePath(), conn.getConnectTimeout(), encoding);
throw new DownloadFailedException(msg, ex);
} catch (Throwable ex) {
throw new DownloadFailedException("Error saving downloaded file.", ex);
final String msg = String.format("Unexpected exception saving '%s' to file '%s'%nConnection Timeout: %d%nEncoding: %s%n",
url.toString(), outputPath.getAbsolutePath(), conn.getConnectTimeout(), encoding);
throw new DownloadFailedException(msg, ex);
} finally {
if (writer != null) {
try {
writer.close();
} catch (Throwable ex) {
} catch (IOException ex) {
LOGGER.log(Level.FINEST,
"Error closing the writer in Downloader.", ex);
}
@@ -136,7 +143,7 @@ public final class Downloader {
if (reader != null) {
try {
reader.close();
} catch (Throwable ex) {
} catch (IOException ex) {
LOGGER.log(Level.FINEST,
"Error closing the reader in Downloader.", ex);
}

View File

@@ -17,6 +17,7 @@
*/
package org.owasp.dependencycheck.utils;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.util.logging.FileHandler;
@@ -57,6 +58,13 @@ public final class LogUtils {
if (verboseLogFile != null && !verboseLogFile.isEmpty()) {
verboseLoggingEnabled = true;
final Logger logger = Logger.getLogger("");
final File logFile = new File(verboseLogFile);
final File logDir = logFile.getParentFile();
if (logDir != null && !logDir.isDirectory() && !logDir.mkdirs()) {
final String msg = String.format("Unable to create directory '%s', verbose logging will be disabled.",
logDir.getAbsolutePath());
throw new IOException(msg);
}
final FileHandler fileHandler = new FileHandler(verboseLogFile, true);
fileHandler.setFormatter(new SimpleFormatter());
fileHandler.setLevel(Level.FINE);

View File

@@ -20,7 +20,7 @@ Copyright (c) 2012 - Jeremy Long
<groupId>org.owasp</groupId>
<artifactId>dependency-check-parent</artifactId>
<version>1.2.7</version>
<version>1.2.8</version>
<packaging>pom</packaging>
<modules>

View File

@@ -0,0 +1,11 @@
Central Analyzer
==============
Dependency-check includes an analyzer that will check for the Maven GAV
(Group/Artifact/Version) information for artifacts in the scanned area. By
default the information comes from [Maven Central][1]. If the artifact's hash
is found in the configured Nexus repository, its GAV is recorded as an Identifier
and the Group is collected as Vendor evidence, the Artifact is collected as Product
evidence, and the Version is collected as Version evidence.
[1]: http://search.maven.org/ "Maven Central"

View File

@@ -1,54 +1,17 @@
Nexus Analyzer
==============
Dependency-check includes an analyzer that will check for the Maven GAV
(Group/Artifact/Version) information for artifacts in the scanned area. By
default the information comes from [Maven Central][1], but can be configured to
use a local repository if necessary. If the artifact's hash is found in the
configured Nexus repository, its GAV is recorded as an Identifier and the Group
is collected as Vendor evidence, the Artifact is collected as Product evidence,
and the Version is collected as Version evidence.
The Nexus Analyzer has been superceded by the Central Analyzer. If both the
Central Analyzer and Nexus Analyzer are enabled and the Nexus URL has not
been configured to point to an instance of Nexus Pro the Nexus Analyzer will
disable itself.
Default Configuration
---------------------
By default, the Nexus analyzer uses the [Sonatype Nexus Repository][2] to search
for SHA-1 hashes of dependencies. If the proxy is configured for Dependency
Check, that proxy is used in order to connect to the Nexus Central repository.
So if you're using `--proxyurl` on the command-line, the `proxyUrl` setting in
the Maven plugin, or the `proxyUrl` attribute in the Ant task, that proxy will
be used by default. Also, the proxy port, user, and password configured globally
are used as well.
Overriding Defaults
-------------------
If you have an internal Nexus repository you want to use, Dependency Check can
be configured to use this repository rather than Sonatype. This needs to be a
Nexus repository (support for Artifactory is planned). For a normal installation
of Nexus, you would append `/service/local/` to the root of the URL to your
Nexus repository. This URL can be set as:
* `analyzer.nexus.url` in `dependencycheck.properties`
* `--nexus <url>` in the CLI
* The `nexusUrl` property in the Maven plugin
* The `nexusUrl` attribute in the Ant task
If this repository is internal and should not use the proxy, you can disable the
proxy for just the Nexus analyzer. Setting this makes no difference if a proxy
is not configured.
* `analyzer.nexus.proxy=false` in `dependencycheck.properties`
* `--nexusUsesProxy false` in the CLI
* The `nexusUsesProxy` property in the Maven plugin
* The `nexusUsesProxy` attribute in the Ant task
Finally, the Nexus analyzer can be disabled altogether.
* `analyzer.nexus.enabled=false` in `dependencycheck.properties`
* `--disableNexus` in the CLI
* `nexusAnalyzerEnabled` property in the Maven plugin
* `nexusAnalyzerEnabled` attribute in the Ant task
The Nexus Analyzer will check for the Maven GAV (Group/Artifact/Version) information
for artifacts in the scanned area. This is done by determining if an artifact exists
in a Nexus Pro installation using the SHA-1 hash of the artifact scanned. If the
artifact's hash is found in the configured Nexus repository, its GAV is recorded as
an Identifier and the Group is collected as Vendor evidence, the Artifact is
collected as Product evidence, and the Version is collected as Version evidence.
Logging
-------
@@ -60,9 +23,9 @@ You may see a log message similar to the following during analysis:
At the beginning of analysis, a check is made by the Nexus analyzer to see if it
is able to reach the configured Nexus service, and if it cannot be reached, the
analyzer will be disabled. If you see this message, you can use the
configuration settings described above to resolve the issue, or disable the
analyzer altogether.
analyzer will be disabled. If you see this message, you can use the configuration
settings described in either the CLI, Ant, Maven, or Jenkins plugins to resolve
the issue, or disable the analyzer altogether.
[1]: http://search.maven.org/ "Maven Central"
[2]: https://repository.sonatype.org/ "Sonatype Nexus Repository"

View File

@@ -98,6 +98,9 @@ Copyright (c) 2013 Jeremy Long. All Rights Reserved.
<item name="Jar Analyzer" href="./jar-analyzer.html">
<description>Jar Analyzer</description>
</item>
<item name="Central Analyzer" href="./central-analyzer.html">
<description>Central Analyzer</description>
</item>
<item name="Nexus Analyzer" href="./nexus-analyzer.html">
<description>Nexus Analyzer</description>
</item>