renamed modules and fixed errors with various lifecycle stages

This commit is contained in:
Jeremy Long
2018-01-25 06:54:01 -05:00
parent 3736161e39
commit 62a5db6b8b
740 changed files with 40 additions and 12 deletions

View File

@@ -0,0 +1,15 @@
Copyright (c) 2012-2013 Jeremy Long. All rights reserved.
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.
----------------------------------------------------------------------------

View File

@@ -0,0 +1,63 @@
<?xml version="1.0" encoding="UTF-8"?>
<assembly
xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2
http://maven.apache.org/xsd/assembly-1.1.2.xsd">
<id>release</id>
<formats>
<format>zip</format>
</formats>
<includeBaseDirectory>false</includeBaseDirectory>
<fileSets>
<fileSet>
<outputDirectory>dependency-check/bin</outputDirectory>
<directory>${project.build.directory}/release/bin</directory>
<includes>
<include>*.sh</include>
</includes>
<fileMode>0755</fileMode>
</fileSet>
<fileSet>
<outputDirectory>dependency-check/bin</outputDirectory>
<directory>${project.build.directory}/release/bin</directory>
<includes>
<include>*.bat</include>
</includes>
</fileSet>
<fileSet>
<outputDirectory>dependency-check/repo</outputDirectory>
<directory>${project.build.directory}/release/repo</directory>
</fileSet>
<fileSet>
<directory>.</directory>
<outputDirectory>dependency-check/plugins</outputDirectory>
<excludes>
<exclude>*/**</exclude>
</excludes>
</fileSet>
<fileSet>
<outputDirectory>dependency-check</outputDirectory>
<includes>
<include>LICENSE*</include>
<include>NOTICE*</include>
</includes>
</fileSet>
<fileSet>
<outputDirectory>dependency-check/licenses</outputDirectory>
<directory>${basedir}/src/main/resources/META-INF/licenses</directory>
</fileSet>
<fileSet>
<outputDirectory>dependency-check/licenses</outputDirectory>
<directory>${basedir}/../dependency-check-core/src/main/resources/META-INF/licenses</directory>
</fileSet>
<fileSet>
<outputDirectory>dependency-check</outputDirectory>
<directory>${basedir}</directory>
<includes>
<include>README.md</include>
<include>LICENSE.txt</include>
</includes>
</fileSet>
</fileSets>
</assembly>

View File

@@ -0,0 +1,593 @@
/*
* This file is part of dependency-check-cli.
*
* 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) 2012 Jeremy Long. All Rights Reserved.
*/
package org.owasp.dependencycheck;
import ch.qos.logback.classic.LoggerContext;
import ch.qos.logback.classic.encoder.PatternLayoutEncoder;
import ch.qos.logback.classic.spi.ILoggingEvent;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import org.apache.commons.cli.ParseException;
import org.owasp.dependencycheck.data.nvdcve.DatabaseException;
import org.owasp.dependencycheck.dependency.Dependency;
import org.apache.tools.ant.DirectoryScanner;
import org.owasp.dependencycheck.dependency.Vulnerability;
import org.owasp.dependencycheck.utils.Settings;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import ch.qos.logback.core.FileAppender;
import org.owasp.dependencycheck.data.update.exception.UpdateException;
import org.owasp.dependencycheck.exception.ExceptionCollection;
import org.owasp.dependencycheck.exception.ReportException;
import org.owasp.dependencycheck.utils.InvalidSettingException;
import org.slf4j.impl.StaticLoggerBinder;
/**
* The command line interface for the DependencyCheck application.
*
* @author Jeremy Long
*/
public class App {
/**
* The logger.
*/
private static final Logger LOGGER = LoggerFactory.getLogger(App.class);
/**
* The configured settings.
*/
private Settings settings = null;
/**
* The main method for the application.
*
* @param args the command line arguments
*/
public static void main(String[] args) {
int exitCode = 0;
final App app = new App();
exitCode = app.run(args);
LOGGER.debug("Exit code: {}", exitCode);
System.exit(exitCode);
}
/**
* Builds the App object.
*/
public App() {
settings = new Settings();
}
/**
* Builds the App object; this method is used for testing.
*
* @param settings the configured settings
*/
protected App(Settings settings) {
this.settings = settings;
}
/**
* Main CLI entry-point into the application.
*
* @param args the command line arguments
* @return the exit code to return
*/
public int run(String[] args) {
int exitCode = 0;
final CliParser cli = new CliParser(settings);
try {
cli.parse(args);
} catch (FileNotFoundException ex) {
System.err.println(ex.getMessage());
cli.printHelp();
return -1;
} catch (ParseException ex) {
System.err.println(ex.getMessage());
cli.printHelp();
return -2;
}
if (cli.getVerboseLog() != null) {
prepareLogger(cli.getVerboseLog());
}
if (cli.isPurge()) {
if (cli.getConnectionString() != null) {
LOGGER.error("Unable to purge the database when using a non-default connection string");
exitCode = -3;
} else {
try {
populateSettings(cli);
} catch (InvalidSettingException ex) {
LOGGER.error(ex.getMessage());
LOGGER.debug("Error loading properties file", ex);
exitCode = -4;
return exitCode;
}
File db;
try {
db = new File(settings.getDataDirectory(), settings.getString(Settings.KEYS.DB_FILE_NAME, "dc.h2.db"));
if (db.exists()) {
if (db.delete()) {
LOGGER.info("Database file purged; local copy of the NVD has been removed");
} else {
LOGGER.error("Unable to delete '{}'; please delete the file manually", db.getAbsolutePath());
exitCode = -5;
}
} else {
LOGGER.error("Unable to purge database; the database file does not exist: {}", db.getAbsolutePath());
exitCode = -6;
}
} catch (IOException ex) {
LOGGER.error("Unable to delete the database");
exitCode = -7;
} finally {
settings.cleanup();
}
}
} else if (cli.isGetVersion()) {
cli.printVersionInfo();
} else if (cli.isUpdateOnly()) {
try {
populateSettings(cli);
} catch (InvalidSettingException ex) {
LOGGER.error(ex.getMessage());
LOGGER.debug("Error loading properties file", ex);
exitCode = -4;
return exitCode;
}
try {
runUpdateOnly();
} catch (UpdateException ex) {
LOGGER.error(ex.getMessage());
exitCode = -8;
} catch (DatabaseException ex) {
LOGGER.error(ex.getMessage());
exitCode = -9;
} finally {
settings.cleanup();
}
} else if (cli.isRunScan()) {
try {
populateSettings(cli);
} catch (InvalidSettingException ex) {
LOGGER.error(ex.getMessage());
LOGGER.debug("Error loading properties file", ex);
exitCode = -4;
return exitCode;
}
try {
final String[] scanFiles = cli.getScanFiles();
if (scanFiles != null) {
exitCode = runScan(cli.getReportDirectory(), cli.getReportFormat(), cli.getProjectName(), scanFiles,
cli.getExcludeList(), cli.getSymLinkDepth(), cli.getFailOnCVSS());
} else {
LOGGER.error("No scan files configured");
}
} catch (InvalidScanPathException ex) {
LOGGER.error("An invalid scan path was detected; unable to scan '//*' paths");
exitCode = -10;
} catch (DatabaseException ex) {
LOGGER.error(ex.getMessage());
exitCode = -11;
} catch (ReportException ex) {
LOGGER.error(ex.getMessage());
exitCode = -12;
} catch (ExceptionCollection ex) {
if (ex.isFatal()) {
exitCode = -13;
LOGGER.error("One or more fatal errors occurred");
} else {
exitCode = -14;
}
for (Throwable e : ex.getExceptions()) {
if (e.getMessage() != null) {
LOGGER.error(e.getMessage());
}
}
} finally {
settings.cleanup();
}
} else {
cli.printHelp();
}
return exitCode;
}
/**
* Scans the specified directories and writes the dependency reports to the
* reportDirectory.
*
* @param reportDirectory the path to the directory where the reports will
* be written
* @param outputFormat the output format of the report
* @param applicationName the application name for the report
* @param files the files/directories to scan
* @param excludes the patterns for files/directories to exclude
* @param symLinkDepth the depth that symbolic links will be followed
* @param cvssFailScore the score to fail on if a vulnerability is found
* @return the exit code if there was an error
*
* @throws InvalidScanPathException thrown if the path to scan starts with
* "//"
* @throws ReportException thrown when the report cannot be generated
* @throws DatabaseException thrown when there is an error connecting to the
* database
* @throws ExceptionCollection thrown when an exception occurs during
* analysis; there may be multiple exceptions contained within the
* collection.
*/
private int runScan(String reportDirectory, String outputFormat, String applicationName, String[] files,
String[] excludes, int symLinkDepth, int cvssFailScore) throws InvalidScanPathException, DatabaseException,
ExceptionCollection, ReportException {
Engine engine = null;
try {
final List<String> antStylePaths = getPaths(files);
final Set<File> paths = scanAntStylePaths(antStylePaths, symLinkDepth, excludes);
engine = new Engine(settings);
engine.scan(paths);
ExceptionCollection exCol = null;
try {
engine.analyzeDependencies();
} catch (ExceptionCollection ex) {
if (ex.isFatal()) {
throw ex;
}
exCol = ex;
}
try {
engine.writeReports(applicationName, new File(reportDirectory), outputFormat);
} catch (ReportException ex) {
if (exCol != null) {
exCol.addException(ex);
throw exCol;
} else {
throw ex;
}
}
if (exCol != null && !exCol.getExceptions().isEmpty()) {
throw exCol;
}
return determineReturnCode(engine, cvssFailScore);
} finally {
if (engine != null) {
engine.close();
}
}
}
/**
* Determines the return code based on if one of the dependencies scanned
* has a vulnerability with a CVSS score above the cvssFailScore.
*
* @param engine the engine used during analysis
* @param cvssFailScore the max allowed CVSS score
* @return returns <code>1</code> if a severe enough vulnerability is
* identified; otherwise <code>0</code>
*/
private int determineReturnCode(Engine engine, int cvssFailScore) {
int retCode = 0;
//Set the exit code based on whether we found a high enough vulnerability
for (Dependency dep : engine.getDependencies()) {
if (!dep.getVulnerabilities().isEmpty()) {
for (Vulnerability vuln : dep.getVulnerabilities()) {
LOGGER.debug("VULNERABILITY FOUND {}", dep.getDisplayFileName());
if (vuln.getCvssScore() > cvssFailScore) {
retCode = 1;
}
}
}
}
return retCode;
}
/**
* Scans the give Ant Style paths and collects the actual files.
*
* @param antStylePaths a list of ant style paths to scan for actual files
* @param symLinkDepth the depth to traverse symbolic links
* @param excludes an array of ant style excludes
* @return returns the set of identified files
* @throws InvalidScanPathException thrown when the scan path is invalid
*/
private Set<File> scanAntStylePaths(List<String> antStylePaths, int symLinkDepth, String[] excludes)
throws InvalidScanPathException {
final Set<File> paths = new HashSet<>();
for (String file : antStylePaths) {
LOGGER.debug("Scanning {}", file);
final DirectoryScanner scanner = new DirectoryScanner();
String include = file.replace('\\', '/');
File baseDir;
if (include.startsWith("//")) {
throw new InvalidScanPathException("Unable to scan paths specified by //");
} else {
final int pos = getLastFileSeparator(include);
final String tmpBase = include.substring(0, pos);
final String tmpInclude = include.substring(pos + 1);
if (tmpInclude.indexOf('*') >= 0 || tmpInclude.indexOf('?') >= 0
|| (new File(include)).isFile()) {
baseDir = new File(tmpBase);
include = tmpInclude;
} else {
baseDir = new File(tmpBase, tmpInclude);
include = "**/*";
}
}
scanner.setBasedir(baseDir);
final String[] includes = {include};
scanner.setIncludes(includes);
scanner.setMaxLevelsOfSymlinks(symLinkDepth);
if (symLinkDepth <= 0) {
scanner.setFollowSymlinks(false);
}
if (excludes != null && excludes.length > 0) {
scanner.addExcludes(excludes);
}
scanner.scan();
if (scanner.getIncludedFilesCount() > 0) {
for (String s : scanner.getIncludedFiles()) {
final File f = new File(baseDir, s);
LOGGER.debug("Found file {}", f.toString());
paths.add(f);
}
}
}
return paths;
}
/**
* Determines the ant style paths from the given array of files.
*
* @param files an array of file paths
* @return a list containing ant style paths
*/
private List<String> getPaths(String[] files) {
final List<String> antStylePaths = new ArrayList<>();
for (String file : files) {
final String antPath = ensureCanonicalPath(file);
antStylePaths.add(antPath);
}
return antStylePaths;
}
/**
* Only executes the update phase of dependency-check.
*
* @throws UpdateException thrown if there is an error updating
* @throws DatabaseException thrown if a fatal error occurred and a
* connection to the database could not be established
*/
private void runUpdateOnly() throws UpdateException, DatabaseException {
try (Engine engine = new Engine(settings)) {
engine.doUpdates();
}
}
/**
* Updates the global Settings.
*
* @param cli a reference to the CLI Parser that contains the command line
* arguments used to set the corresponding settings in the core engine.
*
* @throws InvalidSettingException thrown when a user defined properties
* file is unable to be loaded.
*/
protected void populateSettings(CliParser cli) throws InvalidSettingException {
final String connectionTimeout = cli.getConnectionTimeout();
final String proxyServer = cli.getProxyServer();
final String proxyPort = cli.getProxyPort();
final String proxyUser = cli.getProxyUsername();
final String proxyPass = cli.getProxyPassword();
final String dataDirectory = cli.getDataDirectory();
final File propertiesFile = cli.getPropertiesFile();
final String[] suppressionFiles = cli.getSuppressionFiles();
final String hintsFile = cli.getHintsFile();
final String nexusUrl = cli.getNexusUrl();
final String databaseDriverName = cli.getDatabaseDriverName();
final String databaseDriverPath = cli.getDatabaseDriverPath();
final String connectionString = cli.getConnectionString();
final String databaseUser = cli.getDatabaseUser();
final String databasePassword = cli.getDatabasePassword();
final String additionalZipExtensions = cli.getAdditionalZipExtensions();
final String pathToMono = cli.getPathToMono();
final String cveMod12 = cli.getModifiedCve12Url();
final String cveMod20 = cli.getModifiedCve20Url();
final String cveBase12 = cli.getBaseCve12Url();
final String cveBase20 = cli.getBaseCve20Url();
final Integer cveValidForHours = cli.getCveValidForHours();
final Boolean autoUpdate = cli.isAutoUpdate();
final Boolean experimentalEnabled = cli.isExperimentalEnabled();
final Boolean retiredEnabled = cli.isRetiredEnabled();
if (propertiesFile != null) {
try {
settings.mergeProperties(propertiesFile);
} catch (FileNotFoundException ex) {
throw new InvalidSettingException("Unable to find properties file '" + propertiesFile.getPath() + "'", ex);
} catch (IOException ex) {
throw new InvalidSettingException("Error reading properties file '" + propertiesFile.getPath() + "'", ex);
}
}
// We have to wait until we've merged the properties before attempting to set whether we use
// the proxy for Nexus since it could be disabled in the properties, but not explicitly stated
// on the command line. This is true of other boolean values set below not using the setBooleanIfNotNull.
final boolean nexusUsesProxy = cli.isNexusUsesProxy();
if (dataDirectory != null) {
settings.setString(Settings.KEYS.DATA_DIRECTORY, dataDirectory);
} else if (System.getProperty("basedir") != null) {
final File dataDir = new File(System.getProperty("basedir"), "data");
settings.setString(Settings.KEYS.DATA_DIRECTORY, dataDir.getAbsolutePath());
} else {
final File jarPath = new File(App.class.getProtectionDomain().getCodeSource().getLocation().getPath());
final File base = jarPath.getParentFile();
final String sub = settings.getString(Settings.KEYS.DATA_DIRECTORY);
final File dataDir = new File(base, sub);
settings.setString(Settings.KEYS.DATA_DIRECTORY, dataDir.getAbsolutePath());
}
settings.setBooleanIfNotNull(Settings.KEYS.AUTO_UPDATE, autoUpdate);
settings.setStringIfNotEmpty(Settings.KEYS.PROXY_SERVER, proxyServer);
settings.setStringIfNotEmpty(Settings.KEYS.PROXY_PORT, proxyPort);
settings.setStringIfNotEmpty(Settings.KEYS.PROXY_USERNAME, proxyUser);
settings.setStringIfNotEmpty(Settings.KEYS.PROXY_PASSWORD, proxyPass);
settings.setStringIfNotEmpty(Settings.KEYS.CONNECTION_TIMEOUT, connectionTimeout);
settings.setStringIfNotEmpty(Settings.KEYS.HINTS_FILE, hintsFile);
settings.setIntIfNotNull(Settings.KEYS.CVE_CHECK_VALID_FOR_HOURS, cveValidForHours);
settings.setArrayIfNotEmpty(Settings.KEYS.SUPPRESSION_FILE, suppressionFiles);
//File Type Analyzer Settings
settings.setBooleanIfNotNull(Settings.KEYS.ANALYZER_EXPERIMENTAL_ENABLED, experimentalEnabled);
settings.setBooleanIfNotNull(Settings.KEYS.ANALYZER_RETIRED_ENABLED, retiredEnabled);
settings.setBoolean(Settings.KEYS.ANALYZER_JAR_ENABLED, !cli.isJarDisabled());
settings.setBoolean(Settings.KEYS.ANALYZER_ARCHIVE_ENABLED, !cli.isArchiveDisabled());
settings.setBoolean(Settings.KEYS.ANALYZER_PYTHON_DISTRIBUTION_ENABLED, !cli.isPythonDistributionDisabled());
settings.setBoolean(Settings.KEYS.ANALYZER_PYTHON_PACKAGE_ENABLED, !cli.isPythonPackageDisabled());
settings.setBoolean(Settings.KEYS.ANALYZER_AUTOCONF_ENABLED, !cli.isAutoconfDisabled());
settings.setBoolean(Settings.KEYS.ANALYZER_CMAKE_ENABLED, !cli.isCmakeDisabled());
settings.setBoolean(Settings.KEYS.ANALYZER_NUSPEC_ENABLED, !cli.isNuspecDisabled());
settings.setBoolean(Settings.KEYS.ANALYZER_ASSEMBLY_ENABLED, !cli.isAssemblyDisabled());
settings.setBoolean(Settings.KEYS.ANALYZER_BUNDLE_AUDIT_ENABLED, !cli.isBundleAuditDisabled());
settings.setBoolean(Settings.KEYS.ANALYZER_OPENSSL_ENABLED, !cli.isOpenSSLDisabled());
settings.setBoolean(Settings.KEYS.ANALYZER_COMPOSER_LOCK_ENABLED, !cli.isComposerDisabled());
settings.setBoolean(Settings.KEYS.ANALYZER_NODE_PACKAGE_ENABLED, !cli.isNodeJsDisabled());
settings.setBoolean(Settings.KEYS.ANALYZER_NSP_PACKAGE_ENABLED, !cli.isNspDisabled());
settings.setBoolean(Settings.KEYS.ANALYZER_SWIFT_PACKAGE_MANAGER_ENABLED, !cli.isSwiftPackageAnalyzerDisabled());
settings.setBoolean(Settings.KEYS.ANALYZER_COCOAPODS_ENABLED, !cli.isCocoapodsAnalyzerDisabled());
settings.setBoolean(Settings.KEYS.ANALYZER_RUBY_GEMSPEC_ENABLED, !cli.isRubyGemspecDisabled());
settings.setBoolean(Settings.KEYS.ANALYZER_CENTRAL_ENABLED, !cli.isCentralDisabled());
settings.setBoolean(Settings.KEYS.ANALYZER_NEXUS_ENABLED, !cli.isNexusDisabled());
settings.setStringIfNotEmpty(Settings.KEYS.ANALYZER_BUNDLE_AUDIT_PATH, cli.getPathToBundleAudit());
settings.setStringIfNotEmpty(Settings.KEYS.ANALYZER_NEXUS_URL, nexusUrl);
settings.setBoolean(Settings.KEYS.ANALYZER_NEXUS_USES_PROXY, nexusUsesProxy);
settings.setStringIfNotEmpty(Settings.KEYS.DB_DRIVER_NAME, databaseDriverName);
settings.setStringIfNotEmpty(Settings.KEYS.DB_DRIVER_PATH, databaseDriverPath);
settings.setStringIfNotEmpty(Settings.KEYS.DB_CONNECTION_STRING, connectionString);
settings.setStringIfNotEmpty(Settings.KEYS.DB_USER, databaseUser);
settings.setStringIfNotEmpty(Settings.KEYS.DB_PASSWORD, databasePassword);
settings.setStringIfNotEmpty(Settings.KEYS.ADDITIONAL_ZIP_EXTENSIONS, additionalZipExtensions);
settings.setStringIfNotEmpty(Settings.KEYS.ANALYZER_ASSEMBLY_MONO_PATH, pathToMono);
if (cveBase12 != null && !cveBase12.isEmpty()) {
settings.setString(Settings.KEYS.CVE_SCHEMA_1_2, cveBase12);
settings.setString(Settings.KEYS.CVE_SCHEMA_2_0, cveBase20);
settings.setString(Settings.KEYS.CVE_MODIFIED_12_URL, cveMod12);
settings.setString(Settings.KEYS.CVE_MODIFIED_20_URL, cveMod20);
}
}
/**
* Creates a file appender and adds it to logback.
*
* @param verboseLog the path to the verbose log file
*/
private void prepareLogger(String verboseLog) {
final StaticLoggerBinder loggerBinder = StaticLoggerBinder.getSingleton();
final LoggerContext context = (LoggerContext) loggerBinder.getLoggerFactory();
final PatternLayoutEncoder encoder = new PatternLayoutEncoder();
encoder.setPattern("%d %C:%L%n%-5level - %msg%n");
encoder.setContext(context);
encoder.start();
final FileAppender<ILoggingEvent> fa = new FileAppender<>();
fa.setAppend(true);
fa.setEncoder(encoder);
fa.setContext(context);
fa.setFile(verboseLog);
final File f = new File(verboseLog);
String name = f.getName();
final int i = name.lastIndexOf('.');
if (i > 1) {
name = name.substring(0, i);
}
fa.setName(name);
fa.start();
final ch.qos.logback.classic.Logger rootLogger = context.getLogger(ch.qos.logback.classic.Logger.ROOT_LOGGER_NAME);
rootLogger.addAppender(fa);
}
/**
* Takes a path and resolves it to be a canonical &amp; absolute path. The
* caveats are that this method will take an Ant style file selector path
* (../someDir/**\/*.jar) and convert it to an absolute/canonical path (at
* least to the left of the first * or ?).
*
* @param path the path to canonicalize
* @return the canonical path
*/
protected String ensureCanonicalPath(String path) {
String basePath;
String wildCards = null;
final String file = path.replace('\\', '/');
if (file.contains("*") || file.contains("?")) {
int pos = getLastFileSeparator(file);
if (pos < 0) {
return file;
}
pos += 1;
basePath = file.substring(0, pos);
wildCards = file.substring(pos);
} else {
basePath = file;
}
File f = new File(basePath);
try {
f = f.getCanonicalFile();
if (wildCards != null) {
f = new File(f, wildCards);
}
} catch (IOException ex) {
LOGGER.warn("Invalid path '{}' was provided.", path);
LOGGER.debug("Invalid path provided", ex);
}
return f.getAbsolutePath().replace('\\', '/');
}
/**
* Returns the position of the last file separator.
*
* @param file a file path
* @return the position of the last file separator
*/
private int getLastFileSeparator(String file) {
if (file.contains("*") || file.contains("?")) {
int p1 = file.indexOf('*');
int p2 = file.indexOf('?');
p1 = p1 > 0 ? p1 : file.length();
p2 = p2 > 0 ? p2 : file.length();
int pos = p1 < p2 ? p1 : p2;
pos = file.lastIndexOf('/', pos);
return pos;
} else {
return file.lastIndexOf('/');
}
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,66 @@
/*
* This file is part of dependency-check-cli.
*
* 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;
/**
* Thrown if an invalid path is encountered.
*
* @author Jeremy Long
*/
public class InvalidScanPathException extends Exception {
/**
* The serial version UID for serialization.
*/
private static final long serialVersionUID = 1L;
/**
* Creates a new InvalidScanPathException.
*/
public InvalidScanPathException() {
super();
}
/**
* Creates a new InvalidScanPathException.
*
* @param msg a message for the exception
*/
public InvalidScanPathException(String msg) {
super(msg);
}
/**
* Creates a new InvalidScanPathException.
*
* @param ex the cause of the exception
*/
public InvalidScanPathException(Throwable ex) {
super(ex);
}
/**
* Creates a new InvalidScanPathException.
*
* @param msg a message for the exception
* @param ex the cause of the exception
*/
public InvalidScanPathException(String msg, Throwable ex) {
super(msg, ex);
}
}

View File

@@ -0,0 +1,4 @@
/**
* Includes the main entry point for the DependencyChecker.
*/
package org.owasp.dependencycheck;

View File

@@ -0,0 +1,202 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
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.

View File

@@ -0,0 +1,16 @@
<configuration>
<contextName>dependency-check</contextName>
<!-- Logging configuration -->
<appender name="console" class="ch.qos.logback.core.ConsoleAppender">
<Target>System.out</Target>
<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
<level>INFO</level>
</filter>
<encoder>
<pattern>[%level] %msg%n</pattern>
</encoder>
</appender>
<root level="DEBUG">
<appender-ref ref="console"/>
</root>
</configuration>

View File

@@ -0,0 +1,69 @@
Command Line Arguments
======================
The following table lists the command line arguments:
Short | Argument&nbsp;Name&nbsp;&nbsp; | Parameter | Description | Requirement
-------|------------------------|-----------------|-------------|------------
| \-\-project | \<name\> | The name of the project being scanned. | Required
\-s | \-\-scan | \<path\> | The path to scan \- this option can be specified multiple times. It is also possible to specify Ant style paths (e.g. directory/**/*.jar). | Required
| \-\-exclude | \<pattern\> | The path patterns to exclude from the scan \- this option can be specified multiple times. This accepts Ant style path patterns (e.g. **/exclude/**). | Optional
| \-\-symLink | \<depth\> | The depth that symbolic links will be followed; the default is 0 meaning symbolic links will not be followed. | Optional
\-o | \-\-out | \<path\> | The folder to write reports to. This defaults to the current directory. If the format is not set to ALL one could specify a specific file name. | Optional
\-f | \-\-format | \<format\> | The output format to write to (XML, HTML, CSV, JSON, VULN, ALL). The default is HTML. | Required
| \-\-failOnCVSS | \<score\> | If the score set between 0 and 10 the exit code from dependency-check will indicate if a vulnerability with a CVSS score equal to or higher was identified. | Optional
\-l | \-\-log | \<file\> | The file path to write verbose logging information. | Optional
\-n | \-\-noupdate | | Disables the automatic updating of the CPE data. | Optional
| \-\-suppression | \<files\> | The file paths to the suppression XML files; used to suppress [false positives](../general/suppression.html). This can be specified more than once to utilize multiple suppression files. | Optional
\-h | \-\-help | | Print the help message. | Optional
| \-\-advancedHelp | | Print the advanced help message. | Optional
\-v | \-\-version | | Print the version information. | Optional
| \-\-cveValidForHours | \<hours\> | The number of hours to wait before checking for new updates from the NVD. The default is 4 hours. | Optional
| \-\-enableExperimental | | Enable the [experimental analyzers](../analyzers/index.html). If not set the analyzers marked as experimental below will not be loaded or used. | Optional
| \-\-enableRetired | | Enable the [retired analyzers](../analyzers/index.html). If not set the analyzers marked as retired below will not be loaded or used. | Optional
Advanced Options
================
Short | Argument&nbsp;Name&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; | Parameter | Description | Default&nbsp;Value
-------|------------------------|-----------------|----------------------------------------------------------------------------------|-------------------
| \-\-cveUrl12Modified | \<url\> | URL for the modified CVE 1.2 | https://nvd.nist.gov/download/nvdcve-Modified.xml.gz
| \-\-cveUrl20Modified | \<url\> | URL for the modified CVE 2.0 | https://nvd.nist.gov/feeds/xml/cve/nvdcve-2.0-Modified.xml.gz
| \-\-cveUrl12Base | \<url\> | Base URL for each year's CVE 1.2, the %d will be replaced with the year | https://nvd.nist.gov/download/nvdcve-%d.xml.gz
| \-\-cveUrl20Base | \<url\> | Base URL for each year's CVE 2.0, the %d will be replaced with the year | https://nvd.nist.gov/feeds/xml/cve/nvdcve-2.0-%d.xml.gz
\-P | \-\-propertyfile | \<file\> | Specifies a file that contains properties to use instead of applicaion defaults. | &nbsp;
| \-\-updateonly | | If set only the update phase of dependency-check will be executed; no scan will be executed and no report will be generated. | &nbsp;
| \-\-disablePyDist | | Sets whether the [experimental](../analyzers/index.html) Python Distribution Analyzer will be used. | false
| \-\-disablePyPkg | | Sets whether the [experimental](../analyzers/index.html) Python Package Analyzer will be used. | false
| \-\-disableNodeJS | | Sets whether the [retired](../analyzers/index.html) Node.js Package Analyzer will be used. | false
| \-\-disableNSP | | Sets whether the NSP Analyzer will be used. | false
| \-\-disableRubygems | | Sets whether the [experimental](../analyzers/index.html) Ruby Gemspec Analyzer will be used. | false
| \-\-disableBundleAudit | | Sets whether the [experimental](../analyzers/index.html) Ruby Bundler Audit Analyzer will be used. | false
| \-\-disableCocoapodsAnalyzer | | Sets whether the [experimental](../analyzers/index.html) Cocoapods Analyzer will be used. | false
| \-\-disableSwiftPackageManagerAnalyzer | | Sets whether the [experimental](../analyzers/index.html) Swift Package Manager Analyzer will be used. | false
| \-\-disableAutoconf | | Sets whether the [experimental](../analyzers/index.html) Autoconf Analyzer will be used. | false
| \-\-disableOpenSSL | | Sets whether the OpenSSL Analyzer will be used. | false
| \-\-disableCmake | | Sets whether the [experimental](../analyzers/index.html) Cmake Analyzer will be disabled. | false
| \-\-disableArchive | | Sets whether the Archive Analyzer will be disabled. | 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 the Jar Analyzer will be disabled. | false
| \-\-disableComposer | | Sets whether the [experimental](../analyzers/index.html) PHP Composer Lock File Analyzer will be disabled. | false
| \-\-disableCentral | | Sets whether the Central Analyzer will be used. **Disabling this analyzer is not recommended as it could lead to false negatives (e.g. libraries that have vulnerabilities may not be reported correctly).** 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 (requires Nexus Pro). 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 Server's web service end point (example: http://domain.enterprise/nexus/service/local/). 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
| \-\-disableAssembly | | Sets whether or not the .NET Assembly Analyzer should be used. | false
| \-\-mono | \<path\> | The path to Mono for .NET Assembly analysis on non-windows systems. | &nbsp;
| \-\-bundleAudit | | The path to the bundle-audit executable. | &nbsp;
| \-\-proxyserver | \<server\> | The proxy server to use when downloading resources; see the [proxy configuration](../data/proxy.html) page for more information. | &nbsp;
| \-\-proxyport | \<port\> | The proxy port to use when downloading resources. | &nbsp;
| \-\-connectiontimeout | \<timeout\> | The connection timeout (in milliseconds) to use when downloading resources. | &nbsp;
| \-\-proxypass | \<pass\> | The proxy password to use when downloading resources. | &nbsp;
| \-\-proxyuser | \<user\> | The proxy username to use when downloading resources. | &nbsp;
| \-\-connectionString | \<connStr\> | The connection string to the database. | &nbsp;
| \-\-dbDriverName | \<driver\> | The database driver name. | &nbsp;
| \-\-dbDriverPath | \<path\> | The path to the database driver; note, this does not need to be set unless the JAR is outside of the class path. | &nbsp;
| \-\-dbPassword | \<password\> | The password for connecting to the database. | &nbsp;
| \-\-dbUser | \<user\> | The username used to connect to the database. | &nbsp;
\-d | \-\-data | \<path\> | The location of the data directory used to store persistent data. This option should generally not be set. | &nbsp;
| \-\-purge | | Delete the local copy of the NVD. This is used to force a refresh of the data. | &nbsp;

View File

@@ -0,0 +1,36 @@
About
====================
OWASP dependency-check-cli is an command line tool that uses dependency-check-core to detect
publicly disclosed vulnerabilities associated with the scanned project dependencies. The tool
will generate a report listing the dependency, any identified Common Platform Enumeration (CPE)
identifiers, and the associated Common Vulnerability and Exposure (CVE) entries.
Installation & Usage
====================
Download the dependency-check command line tool [here](http://dl.bintray.com/jeremy-long/owasp/dependency-check-${project.version}-release.zip).
Extract the zip file to a location on your computer and put the 'bin' directory into the
path environment variable.
#set( $H = '#' )
$H$H$H Homebrew
$ brew install dependency-check
This puts an executable `dependency-check` script in the `/bin` directory of
your homebrew installation.
To scan a folder on the system you can run:
$H$H$H Windows
dependency-check.bat --project "My App Name" --scan "c:\java\application\lib"
$H$H$H *nix
dependency-check.sh --project "My App Name" --scan "/java/application/lib"
To view the command line arguments, see the <a href="arguments.html">arguments page</a>, or you can run:
$H$H$H Windows
dependency-check.bat --help
$H$H$H *nix
dependency-check.sh --help

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 10 KiB

35
cli/src/site/site.xml Normal file
View File

@@ -0,0 +1,35 @@
<?xml version="1.0" encoding="ISO-8859-1"?>
<!--
This file is part of dependency-check-cli.
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.
-->
<project name="dependency-check-cli">
<bannerLeft>
<name>OWASP dependency-check-cli</name>
<alt>OWASP dependency-check-cli</alt>
<src>./images/dc-cli.svg</src>
</bannerLeft>
<body>
<breadcrumbs>
<item name="dependency-check" href="../index.html"/>
</breadcrumbs>
<menu name="Getting Started">
<item name="Installation" href="index.html"/>
<item name="Configuration" href="arguments.html"/>
</menu>
<menu ref="reports" />
</body>
</project>

View File

@@ -0,0 +1,194 @@
/*
* This file is part of dependency-check-core.
*
* 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) 2017 The OWASP Foundation. All Rights Reserved.
*/
package org.owasp.dependencycheck;
import static org.hamcrest.core.Is.is;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;
import java.io.File;
import java.io.FileNotFoundException;
import java.net.URISyntaxException;
import java.util.HashMap;
import java.util.Map;
import org.apache.commons.cli.ParseException;
import org.apache.commons.cli.UnrecognizedOptionException;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.owasp.dependencycheck.utils.InvalidSettingException;
import org.owasp.dependencycheck.utils.Settings;
import org.owasp.dependencycheck.utils.Settings.KEYS;
/**
* Tests for the {@link AppTest} class.
*/
public class AppTest extends BaseTest {
/**
* Test rule for asserting exceptions and their contents.
*/
@Rule
public ExpectedException expectedException = ExpectedException.none();
/**
* Test of ensureCanonicalPath method, of class App.
*/
@Test
public void testEnsureCanonicalPath() {
String file = "../*.jar";
App instance = new App(getSettings());
String result = instance.ensureCanonicalPath(file);
assertFalse(result.contains(".."));
assertTrue(result.endsWith("*.jar"));
file = "../some/skip/../path/file.txt";
String expResult = "/some/path/file.txt";
result = instance.ensureCanonicalPath(file);
assertTrue("result=" + result, result.endsWith(expResult));
}
/**
* Assert that boolean properties can be set on the CLI and parsed into the
* {@link Settings}.
*
* @throws Exception the unexpected {@link Exception}.
*/
@Test
public void testPopulateSettings() throws Exception {
File prop = new File(this.getClass().getClassLoader().getResource("sample.properties").toURI().getPath());
String[] args = {"-P", prop.getAbsolutePath()};
Map<String, Boolean> expected = new HashMap<>();
expected.put(Settings.KEYS.AUTO_UPDATE, Boolean.FALSE);
expected.put(Settings.KEYS.ANALYZER_ARCHIVE_ENABLED, Boolean.TRUE);
assertTrue(testBooleanProperties(args, expected));
String[] args2 = {"-n"};
expected.put(Settings.KEYS.AUTO_UPDATE, Boolean.FALSE);
expected.put(Settings.KEYS.ANALYZER_ARCHIVE_ENABLED, Boolean.TRUE);
assertTrue(testBooleanProperties(args2, expected));
String[] args3 = {"-h"};
expected.put(Settings.KEYS.AUTO_UPDATE, Boolean.TRUE);
expected.put(Settings.KEYS.ANALYZER_ARCHIVE_ENABLED, Boolean.TRUE);
assertTrue(testBooleanProperties(args3, expected));
String[] args4 = {"--disableArchive"};
expected.put(Settings.KEYS.AUTO_UPDATE, Boolean.TRUE);
expected.put(Settings.KEYS.ANALYZER_ARCHIVE_ENABLED, Boolean.FALSE);
assertTrue(testBooleanProperties(args4, expected));
String[] args5 = {"-P", prop.getAbsolutePath(), "--disableArchive"};
expected.put(Settings.KEYS.AUTO_UPDATE, Boolean.FALSE);
expected.put(Settings.KEYS.ANALYZER_ARCHIVE_ENABLED, Boolean.FALSE);
assertTrue(testBooleanProperties(args5, expected));
prop = new File(this.getClass().getClassLoader().getResource("sample2.properties").toURI().getPath());
String[] args6 = {"-P", prop.getAbsolutePath(), "--disableArchive"};
expected.put(Settings.KEYS.AUTO_UPDATE, Boolean.TRUE);
expected.put(Settings.KEYS.ANALYZER_ARCHIVE_ENABLED, Boolean.FALSE);
assertTrue(testBooleanProperties(args6, expected));
String[] args7 = {"-P", prop.getAbsolutePath(), "--noupdate"};
expected.put(Settings.KEYS.AUTO_UPDATE, Boolean.FALSE);
expected.put(Settings.KEYS.ANALYZER_ARCHIVE_ENABLED, Boolean.FALSE);
assertTrue(testBooleanProperties(args7, expected));
String[] args8 = {"-P", prop.getAbsolutePath(), "--noupdate", "--disableArchive"};
expected.put(Settings.KEYS.AUTO_UPDATE, Boolean.FALSE);
expected.put(Settings.KEYS.ANALYZER_ARCHIVE_ENABLED, Boolean.FALSE);
assertTrue(testBooleanProperties(args8, expected));
}
/**
* Assert that an {@link UnrecognizedOptionException} is thrown when a
* property that is not supported is specified on the CLI.
*
* @throws Exception the unexpected {@link Exception}.
*/
@Test
public void testPopulateSettingsException() throws Exception {
String[] args = {"-invalidPROPERTY"};
expectedException.expect(UnrecognizedOptionException.class);
expectedException.expectMessage("Unrecognized option: -invalidPROPERTY");
testBooleanProperties(args, null);
}
/**
* Assert that a single suppression file can be set using the CLI.
*
* @throws Exception the unexpected {@link Exception}.
*/
@Test
public void testPopulatingSuppressionSettingsWithASingleFile() throws Exception {
// GIVEN CLI properties with the mandatory arguments
File prop = new File(this.getClass().getClassLoader().getResource("sample.properties").toURI().getPath());
// AND a single suppression file
String[] args = {"-P", prop.getAbsolutePath(), "--suppression", "another-file.xml"};
// WHEN parsing the CLI arguments
final CliParser cli = new CliParser(getSettings());
cli.parse(args);
final App classUnderTest = new App(getSettings());
classUnderTest.populateSettings(cli);
// THEN the suppression file is set in the settings for use in the application core
assertThat("Expected the suppression file to be set in the Settings", getSettings().getString(KEYS.SUPPRESSION_FILE), is("another-file.xml"));
}
/**
* Assert that multiple suppression files can be set using the CLI.
*
* @throws Exception the unexpected {@link Exception}.
*/
@Test
public void testPopulatingSuppressionSettingsWithMultipleFiles() throws Exception {
// GIVEN CLI properties with the mandatory arguments
File prop = new File(this.getClass().getClassLoader().getResource("sample.properties").toURI().getPath());
// AND a single suppression file
String[] args = {"-P", prop.getAbsolutePath(), "--suppression", "first-file.xml", "another-file.xml"};
// WHEN parsing the CLI arguments
final CliParser cli = new CliParser(getSettings());
cli.parse(args);
final App classUnderTest = new App(getSettings());
classUnderTest.populateSettings(cli);
// THEN the suppression file is set in the settings for use in the application core
assertThat("Expected the suppression files to be set in the Settings with a separator", getSettings().getString(KEYS.SUPPRESSION_FILE), is("first-file.xml,another-file.xml"));
}
private boolean testBooleanProperties(String[] args, Map<String, Boolean> expected) throws URISyntaxException, FileNotFoundException, ParseException, InvalidSettingException {
this.reloadSettings();
final CliParser cli = new CliParser(getSettings());
cli.parse(args);
App instance = new App(getSettings());
instance.populateSettings(cli);
boolean results = true;
for (Map.Entry<String, Boolean> entry : expected.entrySet()) {
results &= getSettings().getBoolean(entry.getKey()) == entry.getValue();
}
return results;
}
}

View File

@@ -0,0 +1,62 @@
/*
* Copyright 2014 OWASP.
*
* 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.
*/
package org.owasp.dependencycheck;
import org.junit.After;
import org.junit.Before;
import org.owasp.dependencycheck.utils.Settings;
/**
*
* @author Jeremy Long
*/
public class BaseTest {
/**
* The configured settings.
*/
private Settings settings;
/**
* Initialize the {@link Settings}.
*/
@Before
public void setUp() {
settings = new Settings();
}
/**
* Clean the {@link Settings}.
*/
@After
public void tearDown() {
settings.cleanup(true);
}
/**
* Returns the settings for the test cases.
*
* @return
*/
protected Settings getSettings() {
return settings;
}
protected void reloadSettings() {
tearDown();
setUp();
}
}

View File

@@ -0,0 +1,309 @@
/*
* This file is part of Dependency-Check.
*
* 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) 2012 Jeremy Long. All Rights Reserved.
*/
package org.owasp.dependencycheck;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.PrintStream;
import org.apache.commons.cli.ParseException;
import org.junit.AfterClass;
import org.junit.Assert;
import org.junit.BeforeClass;
import org.junit.Test;
import org.owasp.dependencycheck.utils.Settings;
/**
*
* @author Jeremy Long
*/
public class CliParserTest extends BaseTest {
/**
* Test of parse method, of class CliParser.
*
* @throws Exception thrown when an exception occurs.
*/
@Test
public void testParse() throws Exception {
String[] args = {};
PrintStream out = System.out;
ByteArrayOutputStream baos = new ByteArrayOutputStream();
System.setOut(new PrintStream(baos));
CliParser instance = new CliParser(getSettings());
instance.parse(args);
Assert.assertFalse(instance.isGetVersion());
Assert.assertFalse(instance.isGetHelp());
Assert.assertFalse(instance.isRunScan());
}
/**
* Test of parse method with help arg, of class CliParser.
*
* @throws Exception thrown when an exception occurs.
*/
@Test
public void testParse_help() throws Exception {
String[] args = {"-help"};
PrintStream out = System.out;
CliParser instance = new CliParser(getSettings());
instance.parse(args);
Assert.assertFalse(instance.isGetVersion());
Assert.assertTrue(instance.isGetHelp());
Assert.assertFalse(instance.isRunScan());
}
/**
* Test of parse method with version arg, of class CliParser.
*
* @throws Exception thrown when an exception occurs.
*/
@Test
public void testParse_version() throws Exception {
String[] args = {"-version"};
CliParser instance = new CliParser(getSettings());
instance.parse(args);
Assert.assertTrue(instance.isGetVersion());
Assert.assertFalse(instance.isGetHelp());
Assert.assertFalse(instance.isRunScan());
}
/**
* Test of parse method with failOnCVSS without an argument
*
* @throws Exception thrown when an exception occurs.
*/
@Test
public void testParse_failOnCVSSNoArg() throws Exception {
String[] args = {"--failOnCVSS"};
CliParser instance = new CliParser(getSettings());
try {
instance.parse(args);
} catch (ParseException ex) {
Assert.assertTrue(ex.getMessage().contains("Missing argument"));
}
Assert.assertFalse(instance.isGetVersion());
Assert.assertFalse(instance.isGetHelp());
Assert.assertFalse(instance.isRunScan());
}
/**
* Test of parse method with failOnCVSS invalid argument. It should default to 11
*
* @throws Exception thrown when an exception occurs.
*/
@Test
public void testParse_failOnCVSSInvalidArgument() throws Exception {
String[] args = {"--failOnCVSS","bad"};
CliParser instance = new CliParser(getSettings());
instance.parse(args);
Assert.assertEquals("Default should be 11", 11, instance.getFailOnCVSS());
Assert.assertFalse(instance.isGetVersion());
Assert.assertFalse(instance.isGetHelp());
Assert.assertFalse(instance.isRunScan());
}
/**
* Test of parse method with failOnCVSS invalid argument. It should default to 11
*
* @throws Exception thrown when an exception occurs.
*/
@Test
public void testParse_failOnCVSSValidArgument() throws Exception {
String[] args = {"--failOnCVSS","6"};
CliParser instance = new CliParser(getSettings());
instance.parse(args);
Assert.assertEquals(6, instance.getFailOnCVSS());
Assert.assertFalse(instance.isGetVersion());
Assert.assertFalse(instance.isGetHelp());
Assert.assertFalse(instance.isRunScan());
}
/**
* Test of parse method with jar and cpe args, of class CliParser.
*
* @throws Exception thrown when an exception occurs.
*/
@Test
public void testParse_unknown() throws Exception {
String[] args = {"-unknown"};
PrintStream out = System.out;
PrintStream err = System.err;
ByteArrayOutputStream baos_out = new ByteArrayOutputStream();
ByteArrayOutputStream baos_err = new ByteArrayOutputStream();
System.setOut(new PrintStream(baos_out));
System.setErr(new PrintStream(baos_err));
CliParser instance = new CliParser(getSettings());
try {
instance.parse(args);
} catch (ParseException ex) {
Assert.assertTrue(ex.getMessage().contains("Unrecognized option"));
}
Assert.assertFalse(instance.isGetVersion());
Assert.assertFalse(instance.isGetHelp());
Assert.assertFalse(instance.isRunScan());
}
/**
* Test of parse method with scan arg, of class CliParser.
*
* @throws Exception thrown when an exception occurs.
*/
@Test
public void testParse_scan() throws Exception {
String[] args = {"-scan"};
CliParser instance = new CliParser(getSettings());
try {
instance.parse(args);
} catch (ParseException ex) {
Assert.assertTrue(ex.getMessage().contains("Missing argument"));
}
Assert.assertFalse(instance.isGetVersion());
Assert.assertFalse(instance.isGetHelp());
Assert.assertFalse(instance.isRunScan());
}
/**
* Test of parse method with jar arg, of class CliParser.
*
* @throws Exception thrown when an exception occurs.
*/
@Test
public void testParse_scan_unknownFile() throws Exception {
String[] args = {"-scan", "jar.that.does.not.exist", "-app", "test"};
CliParser instance = new CliParser(getSettings());
try {
instance.parse(args);
} catch (FileNotFoundException ex) {
Assert.assertTrue(ex.getMessage().contains("Invalid 'scan' argument"));
}
Assert.assertFalse(instance.isGetVersion());
Assert.assertFalse(instance.isGetHelp());
Assert.assertFalse(instance.isRunScan());
}
/**
* Test of parse method with jar arg, of class CliParser.
*
* @throws Exception thrown when an exception occurs.
*/
@Test
public void testParse_scan_withFileExists() throws Exception {
File path = new File(this.getClass().getClassLoader().getResource("checkSumTest.file").toURI().getPath());
String[] args = {"-scan", path.getCanonicalPath(), "-out", "./", "-app", "test"};
CliParser instance = new CliParser(getSettings());
instance.parse(args);
Assert.assertEquals(path.getCanonicalPath(), instance.getScanFiles()[0]);
Assert.assertFalse(instance.isGetVersion());
Assert.assertFalse(instance.isGetHelp());
Assert.assertTrue(instance.isRunScan());
}
/**
* Test of printVersionInfo, of class CliParser.
*
* @throws Exception thrown when an exception occurs.
*/
@Test
public void testParse_printVersionInfo() throws Exception {
PrintStream out = System.out;
ByteArrayOutputStream baos = new ByteArrayOutputStream();
System.setOut(new PrintStream(baos));
CliParser instance = new CliParser(getSettings());
instance.printVersionInfo();
try {
baos.flush();
String text = (new String(baos.toByteArray())).toLowerCase();
String[] lines = text.split(System.getProperty("line.separator"));
Assert.assertEquals(1, lines.length);
Assert.assertTrue(text.contains("version"));
Assert.assertTrue(!text.contains("unknown"));
} catch (IOException ex) {
System.setOut(out);
Assert.fail("CliParser.printVersionInfo did not write anything to system.out.");
} finally {
System.setOut(out);
}
}
/**
* Test of printHelp, of class CliParser.
*
* @throws Exception thrown when an exception occurs.
*/
@Test
public void testParse_printHelp() throws Exception {
PrintStream out = System.out;
ByteArrayOutputStream baos = new ByteArrayOutputStream();
System.setOut(new PrintStream(baos));
CliParser instance = new CliParser(getSettings());
String[] args = {"-h"};
instance.parse(args);
instance.printHelp();
args[0] = "-ah";
instance.parse(args);
instance.printHelp();
try {
baos.flush();
String text = (new String(baos.toByteArray()));
String[] lines = text.split(System.getProperty("line.separator"));
Assert.assertTrue(lines[0].startsWith("usage: "));
Assert.assertTrue((lines.length > 2));
} catch (IOException ex) {
System.setOut(out);
Assert.fail("CliParser.printVersionInfo did not write anything to system.out.");
} finally {
System.setOut(out);
}
}
}

View File

@@ -0,0 +1 @@
this is a test file used to check the checksums.

View File

@@ -0,0 +1,33 @@
autoupdate=false
somethingmadeup=test
analyzer.experimental.enabled=false
analyzer.jar.enabled=true
analyzer.archive.enabled=true
analyzer.node.package.enabled=true
analyzer.composer.lock.enabled=true
analyzer.python.distribution.enabled=true
analyzer.python.package.enabled=true
analyzer.ruby.gemspec.enabled=true
analyzer.autoconf.enabled=true
analyzer.cmake.enabled=true
analyzer.assembly.enabled=true
analyzer.nuspec.enabled=true
analyzer.openssl.enabled=true
analyzer.central.enabled=true
analyzer.nexus.enabled=false
analyzer.cocoapods.enabled=true
analyzer.swift.package.manager.enabled=true
#whether the nexus analyzer uses the proxy
analyzer.nexus.proxy=true
analyzer.cpe.enabled=true
analyzer.cpesuppression.enabled=true
analyzer.dependencybundling.enabled=true
analyzer.dependencymerging.enabled=true
analyzer.falsepositive.enabled=true
analyzer.filename.enabled=true
analyzer.hint.enabled=true
analyzer.nvdcve.enabled=true
analyzer.vulnerabilitysuppression.enabled=true
updater.nvdcve.enabled=true
updater.versioncheck.enabled=true
analyzer.versionfilter.enabled=true

View File

@@ -0,0 +1,33 @@
autoupdate=true
analyzer.experimental.enabled=true
analyzer.jar.enabled=false
analyzer.archive.enabled=false
analyzer.node.package.enabled=false
analyzer.composer.lock.enabled=false
analyzer.python.distribution.enabled=false
analyzer.python.package.enabled=false
analyzer.ruby.gemspec.enabled=false
analyzer.autoconf.enabled=false
analyzer.cmake.enabled=false
analyzer.assembly.enabled=false
analyzer.nuspec.enabled=false
analyzer.openssl.enabled=false
analyzer.central.enabled=false
analyzer.nexus.enabled=true
analyzer.cocoapods.enabled=false
analyzer.swift.package.manager.enabled=false
#whether the nexus analyzer uses the proxy
analyzer.nexus.proxy=false
analyzer.cpe.enabled=false
analyzer.cpesuppression.enabled=false
analyzer.dependencybundling.enabled=false
analyzer.dependencymerging.enabled=false
analyzer.falsepositive.enabled=false
analyzer.filename.enabled=false
analyzer.hint.enabled=false
analyzer.nvdcve.enabled=false
analyzer.vulnerabilitysuppression.enabled=false
updater.nvdcve.enabled=false
updater.versioncheck.enabled=false
analyzer.versionfilter.enabled=false