Issue #730: Allow multiple args for CLI suppresion

The core has not been extended but the CLI is able to parse and pass to the Settings singleton
This change to the CLI is backwards compatible
This commit is contained in:
Phillip Whittlesea
2017-06-11 15:05:24 +01:00
parent 869c9c0114
commit 76218da8d1
6 changed files with 165 additions and 12 deletions

View File

@@ -387,7 +387,7 @@ public class App {
final String proxyPass = cli.getProxyPassword();
final String dataDirectory = cli.getDataDirectory();
final File propertiesFile = cli.getPropertiesFile();
final String suppressionFile = cli.getSuppressionFile();
final String[] suppressionFiles = cli.getSuppressionFiles();
final String hintsFile = cli.getHintsFile();
final String nexusUrl = cli.getNexusUrl();
final String databaseDriverName = cli.getDatabaseDriverName();
@@ -436,10 +436,11 @@ public class App {
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.SUPPRESSION_FILE, suppressionFile);
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);

View File

@@ -273,7 +273,7 @@ public final class CliParser {
.desc("Sets how deep nested symbolic links will be followed; 0 indicates symbolic links will not be followed.")
.build();
final Option suppressionFile = Option.builder().argName("file").hasArg().longOpt(ARGUMENT.SUPPRESSION_FILE)
final Option suppressionFile = Option.builder().argName("file").hasArgs().longOpt(ARGUMENT.SUPPRESSION_FILES)
.desc("The file path to the suppression XML file.")
.build();
@@ -1020,12 +1020,12 @@ public final class CliParser {
}
/**
* Returns the path to the suppression file.
* Returns the paths to the suppression files.
*
* @return the path to the suppression file
* @return the paths to the suppression files.
*/
public String getSuppressionFile() {
return line.getOptionValue(ARGUMENT.SUPPRESSION_FILE);
public String[] getSuppressionFiles() {
return line.getOptionValues(ARGUMENT.SUPPRESSION_FILES);
}
/**
@@ -1363,9 +1363,9 @@ public final class CliParser {
public static final String SYM_LINK_DEPTH = "symLink";
/**
* The CLI argument name for setting the location of the suppression
* file.
* file(s).
*/
public static final String SUPPRESSION_FILE = "suppression";
public static final String SUPPRESSION_FILES = "suppression";
/**
* The CLI argument name for setting the location of the hint file.
*/

View File

@@ -14,7 +14,7 @@ Short | Argument Name   | Parameter | Description | Requir
| \-\-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 | \<file\> | The file path to the suppression XML file; used to suppress [false positives](../general/suppression.html). | Optional
| \-\-suppression | \<files\> | The file paths to the suppression XML files; used to suppress [false positives](../general/suppression.html). | Optional
\-h | \-\-help | | Print the help message. | Optional
| \-\-advancedHelp | | Print the advanced help message. | Optional
\-v | \-\-version | | Print the version information. | Optional
@@ -64,4 +64,4 @@ Short | Argument&nbsp;Name&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; | Paramete
| \-\-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;
| \-\-purge | | Delete the local copy of the NVD. This is used to force a refresh of the data. | &nbsp;

View File

@@ -153,7 +153,7 @@ public class AppTest {
* @throws Exception the unexpected {@link Exception}.
*/
@Test
public void testPopulatingSuppressionSettings() throws Exception {
public void testPopulatingSuppressionSettingsWithASingleFile() throws Exception {
// GIVEN CLI properties with the mandatory arguments
File prop = new File(this.getClass().getClassLoader().getResource("sample.properties").toURI().getPath());
@@ -170,6 +170,29 @@ public class AppTest {
assertThat("Expected the suppression file to be set in the Settings singleton", Settings.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();
cli.parse(args);
final App classUnderTest = new App();
classUnderTest.populateSettings(cli);
// THEN the suppression file is set in the settings singleton for use in the application core
assertThat("Expected the suppression files to be set in the Settings singleton with a separator", Settings.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 {
Settings.initialize();
try {

View File

@@ -32,6 +32,8 @@ import java.net.URLDecoder;
import java.util.Enumeration;
import java.util.Properties;
import org.apache.commons.lang3.StringUtils;
/**
* A simple settings container that wraps the dependencycheck.properties file.
*
@@ -47,6 +49,10 @@ public final class Settings {
* The properties file location.
*/
private static final String PROPERTIES_FILE = "dependencycheck.properties";
/**
* Array separator.
*/
private static final String ARRAY_SEP = ",";
/**
* Thread local settings.
*/
@@ -558,6 +564,18 @@ public final class Settings {
LOGGER.debug("Setting: {}='{}'", key, value);
}
/**
* Sets a property value from an array.
* <p>
* Note: each value of the array will be joined by the delimiter {@link Settings#ARRAY_SEP}.
*
* @param key the key for the property
* @param value the value for the property
*/
static void setArray(String key, String[] value) {
setString(key, StringUtils.join(value, ARRAY_SEP));
}
/**
* Sets a property value only if the value is not null.
*
@@ -582,6 +600,18 @@ public final class Settings {
}
}
/**
* Sets a property value only if the array value is not null and not empty.
*
* @param key the key for the property
* @param value the value for the property
*/
public static void setArrayIfNotEmpty(String key, String[] value) {
if (null != value && value.length > 0) {
setArray(key, value);
}
}
/**
* Sets a property value.
*

View File

@@ -17,10 +17,17 @@
*/
package org.owasp.dependencycheck.utils;
import static org.hamcrest.core.Is.is;
import static org.hamcrest.core.IsNull.nullValue;
import static org.junit.Assert.assertThat;
import java.io.File;
import java.io.IOException;
import java.net.URISyntaxException;
import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
/**
@@ -29,6 +36,22 @@ import org.junit.Test;
*/
public class SettingsTest extends BaseTest {
/**
* Initialize the {@link Settings} singleton.
*/
@Before
public void setUp() {
Settings.initialize();
}
/**
* Clean the {@link Settings} singleton.
*/
@After
public void tearDown() {
Settings.cleanup();
}
/**
* Test of getString method, of class Settings.
*/
@@ -220,4 +243,80 @@ public class SettingsTest extends BaseTest {
File tmp = Settings.getTempDirectory();
Assert.assertTrue(tmp.exists());
}
/**
* Assert {@link Settings#setArrayIfNotEmpty(String, String[])} with an empty array is ignored.
*/
@Test
public void testSetArrayNotEmptyIgnoresAnEmptyArray() {
// GIVEN an empty array
final String[] array = {};
// WHEN setting the array
Settings.setArrayIfNotEmpty("key", array);
// THEN the property was not set
assertThat("Expected the property to not be set", Settings.getString("key"), nullValue());
}
/**
* Assert {@link Settings#setArrayIfNotEmpty(String, String[])} with a null array is ignored.
*/
@Test
public void testSetArrayNotEmptyIgnoresAnNullArray() {
// GIVEN a null array
final String[] array = null;
// WHEN setting the array
Settings.setArrayIfNotEmpty("key", array);
// THEN the property was not set
assertThat("Expected the property to not be set", Settings.getString("key"), nullValue());
}
/**
* Assert {@link Settings#setArrayIfNotEmpty(String, String[])} with multiple values sets a delimited string.
*/
@Test
public void testSetArrayNotEmptySetsADelimitedString() {
// GIVEN an array with values
final String[] array = { "value1", "value2" };
// WHEN setting the array
Settings.setArrayIfNotEmpty("key", array);
// THEN the property is set
assertThat("Expected the property to be set", Settings.getString("key"), is("value1,value2"));
}
/**
* Assert {@link Settings#setArrayIfNotEmpty(String, String[])} with a single values sets a string.
*/
@Test
public void testSetArrayNotEmptyWithSingleValueSetsAString() {
// GIVEN an array with a value
final String[] array = { "value1" };
// WHEN setting the array
Settings.setArrayIfNotEmpty("key", array);
// THEN the property is set
assertThat("Expected the property to be set", Settings.getString("key"), is("value1"));
}
/**
* Assert {@link Settings#setArray(String, String[])} with multiple values sets a delimited string.
*/
@Test
public void testSetArraySetsADelimitedString() {
// GIVEN an array with values
final String[] array = { "value1", "value2" };
// WHEN setting the array
Settings.setArray("key", array);
// THEN the property is set
assertThat("Expected the property to be set", Settings.getString("key"), is("value1,value2"));
}
}