View Javadoc
1   /*
2    * This file is part of dependency-check-cli.
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    *     http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   *
16   * Copyright (c) 2012 Jeremy Long. All Rights Reserved.
17   */
18  package org.owasp.dependencycheck;
19  
20  import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
21  import org.apache.commons.cli.CommandLine;
22  import org.apache.commons.cli.CommandLineParser;
23  import org.apache.commons.cli.DefaultParser;
24  import org.apache.commons.cli.Option;
25  import org.apache.commons.cli.OptionGroup;
26  import org.apache.commons.cli.Options;
27  import org.apache.commons.cli.ParseException;
28  import org.apache.commons.cli.help.HelpFormatter;
29  import org.apache.commons.cli.help.TextHelpAppendable;
30  import org.owasp.dependencycheck.reporting.ReportGenerator.Format;
31  import org.owasp.dependencycheck.utils.InvalidSettingException;
32  import org.owasp.dependencycheck.utils.Settings;
33  import org.slf4j.Logger;
34  import org.slf4j.LoggerFactory;
35  
36  import java.io.File;
37  import java.io.FileNotFoundException;
38  import java.io.IOException;
39  import java.io.UncheckedIOException;
40  import java.util.Comparator;
41  
42  /**
43   * A utility to parse command line arguments for the DependencyCheck.
44   *
45   * @author Jeremy Long
46   */
47  //suppress hard-coded password rule
48  @SuppressWarnings("squid:S2068")
49  public final class CliParser {
50  
51      /**
52       * The logger.
53       */
54      private static final Logger LOGGER = LoggerFactory.getLogger(CliParser.class);
55      /**
56       * The command line.
57       */
58      private CommandLine line;
59      /**
60       * Indicates whether the arguments are valid.
61       */
62      private boolean isValid = true;
63      /**
64       * The configured settings.
65       */
66      private final Settings settings;
67      /**
68       * The supported reported formats.
69       */
70      private static final String SUPPORTED_FORMATS = "HTML, XML, CSV, JSON, JUNIT, SARIF, JENKINS, GITLAB or ALL";
71  
72      private static final String HELP_MSG = String.format(
73              "Dependency-Check can be used to identify if there are any known CVE vulnerabilities in libraries " +
74                      "utilized by an application. Dependency-Check will automatically update required data from the " +
75                      "Internet, such as the CVE and CPE data files from nvd.nist.gov.%n"
76      );
77  
78      /**
79       * Constructs a new CLI Parser object with the configured settings.
80       *
81       * @param settings the configured settings
82       */
83      public CliParser(Settings settings) {
84          this.settings = settings;
85      }
86  
87      /**
88       * Parses the arguments passed in and captures the results for later use.
89       *
90       * @param args the command line arguments
91       * @throws FileNotFoundException is thrown when a 'file' argument does not
92       * point to a file that exists.
93       * @throws ParseException is thrown when a Parse Exception occurs.
94       */
95      public void parse(String... args) throws FileNotFoundException, ParseException {
96          line = parseArgs(args);
97  
98          if (line != null) {
99              validateArgs();
100         }
101     }
102 
103     /**
104      * Parses the command line arguments.
105      *
106      * @param args the command line arguments
107      * @return the results of parsing the command line arguments
108      * @throws ParseException if the arguments are invalid
109      */
110     private CommandLine parseArgs(String... args) throws ParseException {
111         final CommandLineParser parser = new DefaultParser();
112         final Options options = createCommandLineOptions();
113         return parser.parse(options, args);
114     }
115 
116     /**
117      * Validates that the command line arguments are valid.
118      *
119      * @throws FileNotFoundException if there is a file specified by either the
120      * SCAN or CPE command line arguments that does not exist.
121      * @throws ParseException is thrown if there is an exception parsing the
122      * command line.
123      */
124     private void validateArgs() throws FileNotFoundException, ParseException {
125         if (isUpdateOnly() || isRunScan()) {
126 
127             String value = line.getOptionValue(ARGUMENT.NVD_API_VALID_FOR_HOURS);
128             if (value != null) {
129                 try {
130                     final int i = Integer.parseInt(value);
131                     if (i < 0) {
132                         throw new ParseException("Invalid Setting: nvdValidForHours must be a number greater than or equal to 0.");
133                     }
134                 } catch (NumberFormatException ex) {
135                     throw new ParseException("Invalid Setting: nvdValidForHours must be a number greater than or equal to 0.");
136                 }
137             }
138             value = line.getOptionValue(ARGUMENT.NVD_API_MAX_RETRY_COUNT);
139             if (value != null) {
140                 try {
141                     final int i = Integer.parseInt(value);
142                     if (i <= 0) {
143                         throw new ParseException("Invalid Setting: nvdMaxRetryCount must be a number greater than 0.");
144                     }
145                 } catch (NumberFormatException ex) {
146                     throw new ParseException("Invalid Setting: nvdMaxRetryCount must be a number greater than 0.");
147                 }
148             }
149             value = line.getOptionValue(ARGUMENT.NVD_API_DELAY);
150             if (value != null) {
151                 try {
152                     final int i = Integer.parseInt(value);
153                     if (i < 0) {
154                         throw new ParseException("Invalid Setting: nvdApiDelay must be a number greater than or equal to 0.");
155                     }
156                 } catch (NumberFormatException ex) {
157                     throw new ParseException("Invalid Setting: nvdApiDelay must be a number greater than or equal to 0.");
158                 }
159             }
160             value = line.getOptionValue(ARGUMENT.NVD_API_RESULTS_PER_PAGE);
161             if (value != null) {
162                 try {
163                     final int i = Integer.parseInt(value);
164                     if (i <= 0 || i > 2000) {
165                         throw new ParseException("Invalid Setting: nvdApiResultsPerPage must be a number in the range [1, 2000].");
166                     }
167                 } catch (NumberFormatException ex) {
168                     throw new ParseException("Invalid Setting: nvdApiResultsPerPage must be a number in the range [1, 2000].");
169                 }
170             }
171         }
172         if (isRunScan()) {
173             validatePathExists(getScanFiles(), ARGUMENT.SCAN);
174             validatePathExists(getReportDirectory(), ARGUMENT.OUT);
175             final String pathToCore = getStringArgument(ARGUMENT.PATH_TO_CORE);
176             if (pathToCore != null) {
177                 validatePathExists(pathToCore, ARGUMENT.PATH_TO_CORE);
178             }
179             if (line.hasOption(ARGUMENT.OUTPUT_FORMAT)) {
180                 for (String validating : getReportFormat()) {
181                     if (!isValidFormat(validating)
182                             && !isValidFilePath(validating, "format")) {
183                         final String msg = String.format("An invalid 'format' of '%s' was specified. "
184                                         + "Supported output formats are %s, and custom template files.",
185                                 validating, SUPPORTED_FORMATS);
186                         throw new ParseException(msg);
187                     }
188                 }
189             }
190             if (line.hasOption(ARGUMENT.SYM_LINK_DEPTH)) {
191                 try {
192                     final int i = Integer.parseInt(line.getOptionValue(ARGUMENT.SYM_LINK_DEPTH));
193                     if (i < 0) {
194                         throw new ParseException("Symbolic Link Depth (symLink) must be greater than zero.");
195                     }
196                 } catch (NumberFormatException ex) {
197                     throw new ParseException("Symbolic Link Depth (symLink) is not a number.");
198                 }
199             }
200         }
201     }
202 
203     /**
204      * Validates the format to be one of the known Formats.
205      *
206      * @param format the format to validate
207      * @return true, if format is known in Format; false otherwise
208      * @see Format
209      */
210     private boolean isValidFormat(String format) {
211         try {
212             Format.valueOf(format);
213             return true;
214         } catch (IllegalArgumentException ex) {
215             return false;
216         }
217     }
218 
219     /**
220      * Validates the path to point at an existing file.
221      *
222      * @param path the path to validate if it exists
223      * @param argumentName the argument being validated (e.g. scan, out, etc.)
224      * @return true, if path exists; false otherwise
225      */
226     private boolean isValidFilePath(String path, @SuppressWarnings("SameParameterValue") String argumentName) {
227         try {
228             validatePathExists(path, argumentName);
229             return true;
230         } catch (FileNotFoundException ex) {
231             return false;
232         }
233     }
234 
235     /**
236      * Validates whether or not the path(s) points at a file that exists; if the
237      * path(s) does not point to an existing file a FileNotFoundException is
238      * thrown.
239      *
240      * @param paths the paths to validate if they exists
241      * @param optType the option being validated (e.g. scan, out, etc.)
242      * @throws FileNotFoundException is thrown if one of the paths being
243      * validated does not exist.
244      */
245     private void validatePathExists(String[] paths, @SuppressWarnings("SameParameterValue") String optType) throws FileNotFoundException {
246         for (String path : paths) {
247             validatePathExists(path, optType);
248         }
249     }
250 
251     /**
252      * Validates whether or not the path points at a file that exists; if the
253      * path does not point to an existing file a FileNotFoundException is
254      * thrown.
255      *
256      * @param path the paths to validate if they exists
257      * @param argumentName the argument being validated (e.g. scan, out, etc.)
258      * @throws FileNotFoundException is thrown if the path being validated does
259      * not exist.
260      */
261     private void validatePathExists(String path, String argumentName) throws FileNotFoundException {
262         if (path == null) {
263             isValid = false;
264             final String msg = String.format("Invalid '%s' argument: null", argumentName);
265             throw new FileNotFoundException(msg);
266         } else if (!path.contains("*") && !path.contains("?")) {
267             File f = new File(path);
268             final String[] formats = this.getReportFormat();
269             if ("o".equalsIgnoreCase(argumentName.substring(0, 1)) && formats.length == 1 && !"ALL".equalsIgnoreCase(formats[0])) {
270                 final String checkPath = path.toLowerCase();
271                 if (checkPath.endsWith(".html") || checkPath.endsWith(".xml") || checkPath.endsWith(".htm")
272                         || checkPath.endsWith(".csv") || checkPath.endsWith(".json")) {
273                     if (f.getParentFile() == null) {
274                         f = new File(".", path);
275                     }
276                     if (!f.getParentFile().isDirectory()) {
277                         isValid = false;
278                         final String msg = String.format("Invalid '%s' argument: '%s' - directory path does not exist", argumentName, path);
279                         throw new FileNotFoundException(msg);
280                     }
281                 }
282             } else if ("o".equalsIgnoreCase(argumentName.substring(0, 1)) && !f.isDirectory()) {
283                 if (f.getParentFile() != null && f.getParentFile().isDirectory() && !f.mkdir()) {
284                     isValid = false;
285                     final String msg = String.format("Invalid '%s' argument: '%s' - unable to create the output directory", argumentName, path);
286                     throw new FileNotFoundException(msg);
287                 }
288                 if (!f.isDirectory()) {
289                     isValid = false;
290                     final String msg = String.format("Invalid '%s' argument: '%s' - path does not exist", argumentName, path);
291                     throw new FileNotFoundException(msg);
292                 }
293             } else if (!f.exists()) {
294                 isValid = false;
295                 final String msg = String.format("Invalid '%s' argument: '%s' - path does not exist", argumentName, path);
296                 throw new FileNotFoundException(msg);
297             }
298 //        } else if (path.startsWith("//") || path.startsWith("\\\\")) {
299 //            isValid = false;
300 //            final String msg = String.format("Invalid '%s' argument: '%s'%nUnable to scan paths that start with '//'.", argumentName, path);
301 //            throw new FileNotFoundException(msg);
302         } else if ((path.endsWith("/*") && !path.endsWith("**/*")) || (path.endsWith("\\*") && path.endsWith("**\\*"))) {
303             LOGGER.warn("Possibly incorrect path '{}' from argument '{}' because it ends with a slash star; "
304                     + "dependency-check uses ant-style paths", path, argumentName);
305         }
306     }
307 
308     /**
309      * Generates an Options collection that is used to parse the command line
310      * and to display the help message.
311      *
312      * @return the command line options used for parsing the command line
313      */
314     private Options createCommandLineOptions() {
315         final Options options = new Options();
316         addStandardOptions(options);
317         addAdvancedOptions(options);
318         addDeprecatedOptions(options);
319         return options;
320     }
321 
322     /**
323      * Adds the standard command line options to the given options collection.
324      *
325      * @param options a collection of command line arguments
326      */
327     private void addStandardOptions(final Options options) {
328         //This is an option group because it can be specified more than once.
329         options.addOptionGroup(newOptionGroup(newOptionWithArg(ARGUMENT.SCAN_SHORT, ARGUMENT.SCAN, "path",
330                         "The path to scan - this option can be specified multiple times. Ant style paths are supported (e.g. 'path/**/*.jar'); "
331                                 + "if using Ant style paths it is highly recommended to quote the argument value.")))
332                 .addOptionGroup(newOptionGroup(newOptionWithArg(ARGUMENT.EXCLUDE, "pattern", "Specify an exclusion pattern. This option "
333                         + "can be specified multiple times and it accepts Ant style exclusions.")))
334                 .addOption(newOptionWithArg(ARGUMENT.PROJECT, "name", "The name of the project being scanned."))
335                 .addOption(newOptionWithArg(ARGUMENT.OUT_SHORT, ARGUMENT.OUT, "path",
336                         "The folder to write reports to. This defaults to the current directory. It is possible to set this to a specific "
337                                 + "file name if the format argument is not set to ALL."))
338                 .addOption(newOptionWithArg(ARGUMENT.OUTPUT_FORMAT_SHORT, ARGUMENT.OUTPUT_FORMAT, "format",
339                         "The report format (" + SUPPORTED_FORMATS + "). The default is HTML. Multiple format parameters can be specified."))
340                 .addOption(newOption(ARGUMENT.PRETTY_PRINT, "When specified the JSON and XML report formats will be pretty printed."))
341                 .addOption(newOption(ARGUMENT.VERSION_SHORT, ARGUMENT.VERSION, "Print the version information."))
342                 .addOption(newOption(ARGUMENT.HELP_SHORT, ARGUMENT.HELP, "Print this message."))
343                 .addOption(newOption(ARGUMENT.ADVANCED_HELP, "Print the advanced help message."))
344                 .addOption(newOption(ARGUMENT.DISABLE_AUTO_UPDATE_SHORT, ARGUMENT.DISABLE_AUTO_UPDATE,
345                         "Disables the automatic updating of the NVD-CVE, hosted-suppressions and RetireJS data."))
346                 .addOption(newOptionWithArg(ARGUMENT.VERBOSE_LOG_SHORT, ARGUMENT.VERBOSE_LOG, "file",
347                         "The file path to write verbose logging information."))
348                 .addOptionGroup(newOptionGroup(newOptionWithArg(ARGUMENT.SUPPRESSION_FILES, "file",
349                         "The file path to the suppression XML file. This can be specified more then once to utilize multiple suppression files")))
350                 .addOption(newOption(ARGUMENT.DISABLE_VERSION_CHECK, "Disables the dependency-check version check"))
351                 .addOption(newOption(ARGUMENT.EXPERIMENTAL, "Enables the experimental analyzers."))
352                 .addOption(newOptionWithArg(ARGUMENT.NVD_API_KEY, "apiKey", "The API Key to access the NVD API."))
353                 .addOption(newOptionWithArg(ARGUMENT.FAIL_ON_CVSS, "score",
354                         "Specifies if the build should be failed if a CVSS score above a specified level is identified. The default is 11; "
355                                 + "since the CVSS scores are 0-10, by default the build will never fail."))
356                 .addOption(newOptionWithArg(ARGUMENT.FAIL_JUNIT_ON_CVSS, "score",
357                         "Specifies the CVSS score that is considered a failure when generating the junit report. The default is 0."));
358     }
359 
360     /**
361      * Adds the advanced command line options to the given options collection.
362      * These are split out for purposes of being able to display two different
363      * help messages.
364      *
365      * @param options a collection of command line arguments
366      */
367     private void addAdvancedOptions(final Options options) {
368         options
369                 .addOption(newOption(ARGUMENT.UPDATE_ONLY,
370                         "Only update the local NVD data cache; no scan will be executed."))
371                 .addOption(newOptionWithArg(ARGUMENT.NVD_API_DELAY, "milliseconds",
372                         "Time in milliseconds to wait between downloading from the NVD."))
373                 .addOption(newOptionWithArg(ARGUMENT.NVD_API_RESULTS_PER_PAGE, "count",
374                         "The number records for a single page from NVD API (must be <=2000)."))
375                 .addOption(newOptionWithArg(ARGUMENT.NVD_API_ENDPOINT, "endpoint",
376                         "The NVD API Endpoint - setting this is rare."))
377                 .addOption(newOptionWithArg(ARGUMENT.NVD_API_DATAFEED_URL, "url",
378                         "The URL to the NVD API Datafeed."))
379                 .addOption(newOptionWithArg(ARGUMENT.NVD_API_DATAFEED_USER, "user",
380                         "Credentials for basic authentication to the NVD API Datafeed."))
381                 .addOption(newOptionWithArg(ARGUMENT.NVD_API_DATAFEED_PASSWORD, "password",
382                         "Credentials for basic authentication to the NVD API Datafeed."))
383                 .addOption(newOptionWithArg(ARGUMENT.NVD_API_DATAFEED_BEARER_TOKEN, "token",
384                         "Credentials for bearer authentication to the NVD API Datafeed."))
385                 .addOption(newOptionWithArg(ARGUMENT.SUPPRESSION_FILE_USER, "user",
386                         "Credentials for basic authentication to web-hosted suppression files."))
387                 .addOption(newOptionWithArg(ARGUMENT.SUPPRESSION_FILE_PASSWORD, "password",
388                         "Credentials for basic authentication to web-hosted suppression files."))
389                 .addOption(newOptionWithArg(ARGUMENT.SUPPRESSION_FILE_BEARER_TOKEN, "token",
390                         "Credentials for bearer authentication to web-hosted suppression files."))
391                 .addOption(newOptionWithArg(ARGUMENT.NVD_API_MAX_RETRY_COUNT, "count",
392                         "The maximum number of retry requests for a single call to the NVD API."))
393                 .addOption(newOptionWithArg(ARGUMENT.NVD_API_VALID_FOR_HOURS, "hours",
394                         "The number of hours to wait before checking for new updates from the NVD."))
395                 .addOption(newOptionWithArg(ARGUMENT.PROXY_PORT, "port",
396                         "The proxy port to use when downloading resources."))
397                 .addOption(newOptionWithArg(ARGUMENT.PROXY_SERVER, "server",
398                         "The proxy server to use when downloading resources."))
399                 .addOption(newOptionWithArg(ARGUMENT.PROXY_USERNAME, "user",
400                         "The proxy username to use when downloading resources."))
401                 .addOption(newOptionWithArg(ARGUMENT.PROXY_PASSWORD, "pass",
402                         "The proxy password to use when downloading resources."))
403                 .addOption(newOptionWithArg(ARGUMENT.NON_PROXY_HOSTS, "list",
404                         "The proxy exclusion list: hostnames (or patterns) for which proxy should not be used. "
405                                 + "Use pipe, comma or colon as list separator."))
406                 .addOption(newOptionWithArg(ARGUMENT.CONNECTION_TIMEOUT_SHORT, ARGUMENT.CONNECTION_TIMEOUT, "timeout",
407                         "The connection timeout (in milliseconds) to use when downloading resources."))
408                 .addOption(newOptionWithArg(ARGUMENT.CONNECTION_READ_TIMEOUT, "timeout",
409                         "The read timeout (in milliseconds) to use when downloading resources."))
410                 .addOption(newOptionWithArg(ARGUMENT.CONNECTION_STRING, "connStr",
411                         "The connection string to the database."))
412                 .addOption(newOptionWithArg(ARGUMENT.DB_NAME, "user",
413                         "The username used to connect to the database."))
414                 .addOption(newOptionWithArg(ARGUMENT.DATA_DIRECTORY_SHORT, ARGUMENT.DATA_DIRECTORY, "path",
415                         "The location of the H2 Database file. This option should generally not be set."))
416                 .addOption(newOptionWithArg(ARGUMENT.DB_PASSWORD, "password",
417                         "The password for connecting to the database."))
418                 .addOption(newOptionWithArg(ARGUMENT.DB_DRIVER, "driver",
419                         "The database driver name."))
420                 .addOption(newOptionWithArg(ARGUMENT.DB_DRIVER_PATH, "path",
421                         "The path to the database driver; note, this does not need to be set unless the JAR is "
422                                 + "outside of the classpath."))
423                 .addOption(newOptionWithArg(ARGUMENT.SYM_LINK_DEPTH, "depth",
424                         "Sets how deep nested symbolic links will be followed; 0 indicates symbolic links will not be followed."))
425                 .addOption(newOptionWithArg(ARGUMENT.PATH_TO_BUNDLE_AUDIT, "path",
426                         "The path to bundle-audit for Gem bundle analysis."))
427                 .addOption(newOptionWithArg(ARGUMENT.PATH_TO_BUNDLE_AUDIT_WORKING_DIRECTORY, "path",
428                         "The path to working directory that the bundle-audit command should be executed from when "
429                                 + "doing Gem bundle analysis."))
430                 .addOption(newOptionWithArg(ARGUMENT.CENTRAL_URL, "url",
431                         "Alternative URL for Maven Central Search. If not set the public Sonatype Maven Central will be used."))
432                 .addOption(newOptionWithArg(ARGUMENT.CENTRAL_USERNAME, "username",
433                         "Credentials for basic auth towards the --centralUrl."))
434                 .addOption(newOptionWithArg(ARGUMENT.CENTRAL_PASSWORD, "password",
435                         "Credentials for basic auth towards the --centralUrl"))
436                 .addOption(newOptionWithArg(ARGUMENT.CENTRAL_BEARER_TOKEN, "token",
437                         "Token for bearer auth towards the --centralUrl"))
438                 .addOption(newOptionWithArg(ARGUMENT.OSSINDEX_CACHE_VALID_FOR_HOURS, "hours",
439                         "The number of hours to wait before checking for new updates on individual packages/components from Sonatype OSS Index. The default is 24 hours."))
440                 .addOption(newOptionWithArg(ARGUMENT.OSSINDEX_URL, "url",
441                         "Alternative base URL for the OSS Index API. If not set the public Sonatype OSS Index API on Sonatype Guide will be used."))
442                 .addOption(newOptionWithArg(ARGUMENT.OSSINDEX_USERNAME, "username",
443                         "(deprecated) Sets the OSS Index API username for use with legacy OSS Index API tokens. " +
444                                 "Username is not required after migration to using Sonatype Guide personal access token as password."))
445                 .addOption(newOptionWithArg(ARGUMENT.OSSINDEX_PASSWORD, "password", "Sets the Sonatype Guide personal " +
446                         "access token or (deprecated) legacy OSS Index API token to authenticate with."))
447                 .addOption(newOptionWithArg(ARGUMENT.OSSINDEX_WARN_ONLY_ON_REMOTE_ERRORS, "true/false",
448                         "Whether a Sonatype OSS Index remote error should result in a warning only or a failure."))
449                 .addOption(newOption(ARGUMENT.RETIRE_JS_FORCEUPDATE, "Force the RetireJS Analyzer to update "
450                         + "even if autoupdate is disabled"))
451                 .addOption(newOptionWithArg(ARGUMENT.RETIREJS_URL, "url",
452                         "The Retire JS Repository URL"))
453                 .addOption(newOptionWithArg(ARGUMENT.RETIREJS_URL_USER, "username",
454                         "Credentials for basic auth towards the Retire JS Repository URL"))
455                 .addOption(newOptionWithArg(ARGUMENT.RETIREJS_URL_PASSWORD, "password",
456                         "Credentials for basic auth towards the Retire JS Repository URL"))
457                 .addOption(newOptionWithArg(ARGUMENT.RETIREJS_URL_BEARER_TOKEN, "token",
458                         "Token for bearer auth towards the Retire JS Repository URL"))
459                 .addOption(newOption(ARGUMENT.RETIRE_JS_FILTER_NON_VULNERABLE, "Specifies that the Retire JS "
460                         + "Analyzer should filter out non-vulnerable JS files from the report."))
461                 .addOption(newOptionWithArg(ARGUMENT.ARTIFACTORY_PARALLEL_ANALYSIS, "true/false",
462                         "Whether the Artifactory Analyzer should use parallel analysis."))
463                 .addOption(newOptionWithArg(ARGUMENT.ARTIFACTORY_USES_PROXY, "true/false",
464                         "Whether the Artifactory Analyzer should use the proxy."))
465                 .addOption(newOptionWithArg(ARGUMENT.ARTIFACTORY_USERNAME, "username",
466                         "The Artifactory username for authentication."))
467                 .addOption(newOptionWithArg(ARGUMENT.ARTIFACTORY_API_TOKEN, "token",
468                         "The Artifactory API token."))
469                 .addOption(newOptionWithArg(ARGUMENT.ARTIFACTORY_BEARER_TOKEN, "token",
470                         "The Artifactory bearer token."))
471                 .addOption(newOptionWithArg(ARGUMENT.ARTIFACTORY_URL, "url",
472                         "The Artifactory URL."))
473                 .addOption(newOptionWithArg(ARGUMENT.PATH_TO_GO, "path",
474                         "The path to the `go` executable."))
475                 .addOption(newOptionWithArg(ARGUMENT.PATH_TO_YARN, "path",
476                         "The path to the `yarn` executable."))
477                 .addOption(newOptionWithArg(ARGUMENT.PATH_TO_PNPM, "path",
478                         "The path to the `pnpm` executable."))
479                 .addOption(newOptionWithArg(ARGUMENT.RETIRE_JS_FILTERS, "pattern",
480                         "Specify Retire JS content filter used to exclude files from analysis based on their content; "
481                                 + "most commonly used to exclude based on your applications own copyright line. This "
482                                 + "option can be specified multiple times."))
483                 .addOption(newOptionWithArg(ARGUMENT.NEXUS_URL, "url",
484                         "Sets the Nexus Repository v3 API base URL (example https://domain.enterprise/nexus/). If not "
485                                 + "set the Nexus Analyzer will be disabled."))
486                 .addOption(newOptionWithArg(ARGUMENT.NEXUS_USERNAME, "username",
487                         "The username to authenticate to the Nexus Server's REST API Endpoint. If not set the Nexus "
488                                 + "Analyzer will use an unauthenticated connection."))
489                 .addOption(newOptionWithArg(ARGUMENT.NEXUS_PASSWORD, "password",
490                         "The password to authenticate to the Nexus Server's REST API Endpoint. If not set the Nexus "
491                                 + "Analyzer will use an unauthenticated connection."))
492                 //TODO remove as this should be covered by non-proxy hosts
493                 .addOption(newOptionWithArg(ARGUMENT.NEXUS_USES_PROXY, "true/false",
494                         "Whether or not the configured proxy should be used when connecting to Nexus."))
495                 .addOption(newOptionWithArg(ARGUMENT.ADDITIONAL_ZIP_EXTENSIONS, "extensions",
496                         "A comma separated list of additional extensions to be scanned as ZIP files (ZIP, EAR, WAR "
497                                 + "are already treated as zip files)"))
498                 .addOption(newOptionWithArg(ARGUMENT.PROP_SHORT, ARGUMENT.PROP, "file", "A property file to load."))
499                 .addOption(newOptionWithArg(ARGUMENT.PATH_TO_CORE, "path", "The path to dotnet core."))
500                 .addOption(newOptionWithArg(ARGUMENT.HINTS_FILE, "file", "The file path to the hints XML file."))
501                 .addOption(newOption(ARGUMENT.RETIRED, "Enables the retired analyzers."))
502                 .addOption(newOption(ARGUMENT.DISABLE_MSBUILD, "Disable the MS Build Analyzer."))
503                 .addOption(newOption(ARGUMENT.DISABLE_JAR, "Disable the Jar Analyzer."))
504                 .addOption(newOption(ARGUMENT.DISABLE_ARCHIVE, "Disable the Archive Analyzer."))
505                 .addOption(newOption(ARGUMENT.DISABLE_KEV, "Disable the Known Exploited Vulnerability Analyzer."))
506                 .addOption(newOptionWithArg(ARGUMENT.KEV_URL, "url", "The url to the CISA Known Exploited Vulnerabilities JSON data feed"))
507                 .addOption(newOptionWithArg(ARGUMENT.KEV_USER, "user", "The user for basic authentication towards the CISA Known Exploited "
508                         + "Vulnerabilities JSON data feed"))
509                 .addOption(newOptionWithArg(ARGUMENT.KEV_PASSWORD, "password", "The password for basic authentication towards the CISA Known "
510                         + "Exploited Vulnerabilities JSON data feed"))
511                 .addOption(newOptionWithArg(ARGUMENT.KEV_BEARER_TOKEN, "token", "The token for bearer authentication towards the CISA Known "
512                         + "Exploited Vulnerabilities JSON data feed"))
513                 .addOption(newOption(ARGUMENT.DISABLE_ASSEMBLY, "Disable the .NET Assembly Analyzer."))
514                 .addOption(newOption(ARGUMENT.DISABLE_PY_DIST, "Disable the Python Distribution Analyzer."))
515                 .addOption(newOption(ARGUMENT.DISABLE_CMAKE, "Disable the Cmake Analyzer."))
516                 .addOption(newOption(ARGUMENT.DISABLE_PY_PKG, "Disable the Python Package Analyzer."))
517                 .addOption(newOption(ARGUMENT.DISABLE_MIX_AUDIT, "Disable the Elixir mix_audit Analyzer."))
518                 .addOption(newOption(ARGUMENT.DISABLE_RUBYGEMS, "Disable the Ruby Gemspec Analyzer."))
519                 .addOption(newOption(ARGUMENT.DISABLE_BUNDLE_AUDIT, "Disable the Ruby Bundler-Audit Analyzer."))
520                 .addOption(newOption(ARGUMENT.DISABLE_FILENAME, "Disable the File Name Analyzer."))
521                 .addOption(newOption(ARGUMENT.DISABLE_AUTOCONF, "Disable the Autoconf Analyzer."))
522                 .addOption(newOption(ARGUMENT.DISABLE_MAVEN_INSTALL, "Disable the Maven install Analyzer."))
523                 .addOption(newOption(ARGUMENT.DISABLE_PE, "Disable the PE Analyzer."))
524                 .addOption(newOption(ARGUMENT.DISABLE_PIP, "Disable the pip Analyzer."))
525                 .addOption(newOption(ARGUMENT.DISABLE_PIPFILE, "Disable the Pipfile Analyzer."))
526                 .addOption(newOption(ARGUMENT.DISABLE_COMPOSER, "Disable the PHP Composer Analyzer."))
527                 .addOption(newOption(ARGUMENT.COMPOSER_LOCK_SKIP_DEV, "Configures the PHP Composer Analyzer to skip packages-dev"))
528                 .addOption(newOption(ARGUMENT.DISABLE_CPAN, "Disable the Perl CPAN file Analyzer."))
529                 .addOption(newOption(ARGUMENT.DISABLE_POETRY, "Disable the Poetry Analyzer."))
530                 .addOption(newOption(ARGUMENT.DISABLE_GOLANG_MOD, "Disable the Golang Mod Analyzer."))
531                 .addOption(newOption(ARGUMENT.DISABLE_DART, "Disable the Dart Analyzer."))
532                 .addOption(newOption(ARGUMENT.DISABLE_OPENSSL, "Disable the OpenSSL Analyzer."))
533                 .addOption(newOption(ARGUMENT.DISABLE_NUSPEC, "Disable the Nuspec Analyzer."))
534                 .addOption(newOption(ARGUMENT.DISABLE_NUGETCONF, "Disable the Nuget packages.config Analyzer."))
535                 .addOption(newOption(ARGUMENT.DISABLE_CENTRAL, "Disable the Central Analyzer. If this analyzer "
536                         + "is disabled it is likely you also want to disable the Nexus Analyzer."))
537                 .addOption(newOption(ARGUMENT.DISABLE_CENTRAL_CACHE, "Disallow the Central Analyzer from caching results"))
538                 .addOption(newOption(ARGUMENT.DISABLE_OSSINDEX, "Disable the Sonatype OSS Index Analyzer."))
539                 .addOption(newOption(ARGUMENT.DISABLE_OSSINDEX_CACHE, "Disallow the OSS Index Analyzer from caching results"))
540                 .addOption(newOption(ARGUMENT.DISABLE_COCOAPODS, "Disable the CocoaPods Analyzer."))
541                 .addOption(newOption(ARGUMENT.DISABLE_CARTHAGE, "Disable the Carthage Analyzer."))
542                 .addOption(newOption(ARGUMENT.DISABLE_SWIFT, "Disable the swift package Analyzer."))
543                 .addOption(newOption(ARGUMENT.DISABLE_SWIFT_RESOLVED, "Disable the swift package resolved Analyzer."))
544                 .addOption(newOption(ARGUMENT.DISABLE_GO_DEP, "Disable the Golang Package Analyzer."))
545                 .addOption(newOption(ARGUMENT.DISABLE_NODE_JS, "Disable the Node Package Analyzer."))
546                 .addOption(newOption(ARGUMENT.NODE_PACKAGE_SKIP_DEV_DEPENDENCIES, "Configures the Node Package Analyzer to skip devDependencies"))
547                 .addOption(newOption(ARGUMENT.DISABLE_NODE_AUDIT, "Disable the Node Audit Analyzer."))
548                 .addOption(newOption(ARGUMENT.DISABLE_PNPM_AUDIT, "Disable the Pnpm Audit Analyzer."))
549                 .addOption(newOption(ARGUMENT.DISABLE_YARN_AUDIT, "Disable the Yarn Audit Analyzer."))
550                 .addOption(newOption(ARGUMENT.DISABLE_NODE_AUDIT_CACHE, "Disallow the Node Audit Analyzer from caching results"))
551                 .addOption(newOption(ARGUMENT.DISABLE_NODE_AUDIT_SKIPDEV, "Configures the Node Audit Analyzer to skip devDependencies"))
552                 .addOption(newOption(ARGUMENT.DISABLE_RETIRE_JS, "Disable the RetireJS Analyzer."))
553                 .addOption(newOption(ARGUMENT.ENABLE_NEXUS, "Enable the Nexus Analyzer."))
554                 .addOption(newOption(ARGUMENT.ARTIFACTORY_ENABLED, "Whether the Artifactory Analyzer should be enabled."))
555                 .addOption(newOption(ARGUMENT.PURGE_NVD, "Purges the local NVD data cache"))
556                 .addOption(newOption(ARGUMENT.DISABLE_HOSTED_SUPPRESSIONS, "Disable retrieval of the hosted suppressions from the configured URL."))
557                 .addOption(newOption(ARGUMENT.HOSTED_SUPPRESSIONS_FORCEUPDATE, "Force the hosted suppressions file to update even"
558                         + " if autoupdate is disabled"))
559                 .addOption(newOptionWithArg(ARGUMENT.HOSTED_SUPPRESSIONS_VALID_FOR_HOURS, "hours",
560                         "The number of hours to wait before checking for new updates of the the hosted suppressions file."))
561                 .addOption(newOptionWithArg(ARGUMENT.HOSTED_SUPPRESSIONS_URL, "url",
562                         "The URL for a mirrored hosted suppressions file"))
563                 .addOption(newOptionWithArg(ARGUMENT.HOSTED_SUPPRESSIONS_USER, "user",
564                         "The user for basic auth to a mirrored hosted suppressions file"))
565                 .addOption(newOptionWithArg(ARGUMENT.HOSTED_SUPPRESSIONS_PASSWORD, "password",
566                         "The password for basic auth to a mirrored hosted suppressions file"))
567                 .addOption(newOptionWithArg(ARGUMENT.HOSTED_SUPPRESSIONS_BEARER_TOKEN, "token",
568                         "The token for bearer auth to  a mirrored hosted suppressions file"));
569 
570     }
571 
572     /**
573      * Adds the deprecated command line options to the given options collection.
574      * These are split out for purposes of not including them in the help
575      * message. We need to add the deprecated options so as not to break
576      * existing scripts.
577      *
578      * @param options a collection of command line arguments
579      */
580     private void addDeprecatedOptions(final Options options) {
581         //not a real option - but enables java debugging via the shell script
582         options.addOption(newOption("debug",
583                 "Used to enable java debugging of the cli via dependency-check.sh."));
584     }
585 
586     /**
587      * Determines if the 'version' command line argument was passed in.
588      *
589      * @return whether or not the 'version' command line argument was passed in
590      */
591     public boolean isGetVersion() {
592         return (line != null) && line.hasOption(ARGUMENT.VERSION);
593     }
594 
595     /**
596      * Determines if the 'help' command line argument was passed in.
597      *
598      * @return whether or not the 'help' command line argument was passed in
599      */
600     public boolean isGetHelp() {
601         return (line != null) && line.hasOption(ARGUMENT.HELP);
602     }
603 
604     /**
605      * Determines if the 'scan' command line argument was passed in.
606      *
607      * @return whether or not the 'scan' command line argument was passed in
608      */
609     public boolean isRunScan() {
610         return (line != null) && isValid && line.hasOption(ARGUMENT.SCAN);
611     }
612 
613     /**
614      * Returns the symbolic link depth (how deeply symbolic links will be
615      * followed).
616      *
617      * @return the symbolic link depth
618      */
619     public int getSymLinkDepth() {
620         int value = 0;
621         try {
622             value = Integer.parseInt(line.getOptionValue(ARGUMENT.SYM_LINK_DEPTH, "0"));
623             if (value < 0) {
624                 value = 0;
625             }
626         } catch (NumberFormatException ex) {
627             LOGGER.debug("Symbolic link was not a number");
628         }
629         return value;
630     }
631 
632     /**
633      * Utility method to determine if one of the disable options has been set.
634      * If not set, this method will check the currently configured settings for
635      * the current value to return.
636      * <p>
637      * Example given `--disableArchive` on the command line would cause this
638      * method to return true for the disable archive setting.
639      *
640      * @param disableFlag the command line disable option
641      * @param setting the corresponding settings key
642      * @return true if the disable option was set, if not set the currently
643      * configured value will be returned
644      */
645     public boolean isDisabled(String disableFlag, String setting) {
646         if (line == null || !line.hasOption(disableFlag)) {
647             try {
648                 return !settings.getBoolean(setting);
649             } catch (InvalidSettingException ise) {
650                 LOGGER.warn("Invalid property setting '{}' defaulting to false", setting);
651                 return false;
652             }
653         } else {
654             return true;
655         }
656     }
657 
658     /**
659      * Returns true if the disableNodeAudit command line argument was specified.
660      *
661      * @return true if the disableNodeAudit command line argument was specified;
662      * otherwise false
663      */
664     public boolean isNodeAuditDisabled() {
665         return isDisabled(ARGUMENT.DISABLE_NODE_AUDIT, Settings.KEYS.ANALYZER_NODE_AUDIT_ENABLED);
666     }
667 
668     /**
669      * Returns true if the disableYarnAudit command line argument was specified.
670      *
671      * @return true if the disableYarnAudit command line argument was specified;
672      * otherwise false
673      */
674     public boolean isYarnAuditDisabled() {
675         return isDisabled(ARGUMENT.DISABLE_YARN_AUDIT, Settings.KEYS.ANALYZER_YARN_AUDIT_ENABLED);
676     }
677 
678     /**
679      * Returns true if the disablePnpmAudit command line argument was specified.
680      *
681      * @return true if the disablePnpmAudit command line argument was specified;
682      * otherwise false
683      */
684     public boolean isPnpmAuditDisabled() {
685         return isDisabled(ARGUMENT.DISABLE_PNPM_AUDIT, Settings.KEYS.ANALYZER_PNPM_AUDIT_ENABLED);
686     }
687 
688     /**
689      * Returns true if the Nexus Analyzer should use the configured proxy to
690      * connect to Nexus; otherwise false is returned.
691      *
692      * @return true if the Nexus Analyzer should use the configured proxy to
693      * connect to Nexus; otherwise false
694      */
695     public boolean isNexusUsesProxy() {
696         // If they didn't specify whether Nexus needs to use the proxy, we should
697         // still honor the property if it's set.
698         if (line == null || !line.hasOption(ARGUMENT.NEXUS_USES_PROXY)) {
699             try {
700                 return settings.getBoolean(Settings.KEYS.ANALYZER_NEXUS_USES_PROXY);
701             } catch (InvalidSettingException ise) {
702                 return true;
703             }
704         } else {
705             return Boolean.parseBoolean(line.getOptionValue(ARGUMENT.NEXUS_USES_PROXY));
706         }
707     }
708 
709     /**
710      * Returns the argument boolean value.
711      *
712      * @param argument the argument
713      * @return the argument boolean value
714      */
715     @SuppressFBWarnings(justification = "Accepting that this is a bad practice - used a Boolean as we needed three states",
716             value = {"NP_BOOLEAN_RETURN_NULL"})
717     public Boolean getBooleanArgument(String argument) {
718         if (line != null && line.hasOption(argument)) {
719             final String value = line.getOptionValue(argument);
720             if (value != null) {
721                 return Boolean.parseBoolean(value);
722             }
723         }
724         return null;
725     }
726 
727     /**
728      * Returns the argument value for the given option.
729      *
730      * @param option the option
731      * @return the value of the argument
732      */
733     public String getStringArgument(String option) {
734         return getStringArgument(option, null);
735     }
736 
737     /**
738      * Returns the argument value for the given option.
739      *
740      * @param option the option
741      * @param key the dependency-check settings key for the option.
742      * @return the value of the argument
743      */
744     public String getStringArgument(String option, String key) {
745         if (line != null && line.hasOption(option)) {
746             if (key != null && (option.toLowerCase().endsWith("password")
747                     || option.toLowerCase().endsWith("pass"))) {
748                 LOGGER.warn("{} used on the command line, consider moving the password "
749                         + "to a properties file using the key `{}` and using the "
750                         + "--propertyfile argument instead", option, key);
751             }
752             return line.getOptionValue(option);
753         }
754         return null;
755     }
756 
757     /**
758      * Returns the argument value for the given option.
759      *
760      * @param option the option
761      * @return the value of the argument
762      */
763     public String[] getStringArguments(String option) {
764         if (line != null && line.hasOption(option)) {
765             return line.getOptionValues(option);
766         }
767         return null;
768     }
769 
770     /**
771      * Returns the argument value for the given option.
772      *
773      * @param option the option
774      * @return the value of the argument
775      */
776     public File getFileArgument(String option) {
777         final String path = line.getOptionValue(option);
778         if (path != null) {
779             return new File(path);
780         }
781         return null;
782     }
783 
784     /**
785      * Appends the command line help message to the passed appendable
786      */
787     void printHelp(Appendable appendable) {
788         TextHelpAppendable helpAppendable = new TextHelpAppendable(appendable);
789         helpAppendable.setMaxWidth(100);
790         HelpFormatter formatter = HelpFormatter.builder()
791                 .setShowSince(false)
792                 .setComparator(Comparator.comparing(Option::getKey, String::compareToIgnoreCase))
793                 .setHelpAppendable(helpAppendable)
794                 .get();
795 
796         final Options options = new Options();
797         addStandardOptions(options);
798         if (line != null && line.hasOption(ARGUMENT.ADVANCED_HELP)) {
799             addAdvancedOptions(options);
800         }
801 
802         try {
803             formatter.printHelp("dependency-check", HELP_MSG, formatter.sort(options), "", true);
804         } catch (IOException e) {
805             throw new UncheckedIOException(e);
806         }
807     }
808 
809     /**
810      * Retrieves the file command line parameter(s) specified for the 'scan'
811      * argument.
812      *
813      * @return the file paths specified on the command line for scan
814      */
815     public String[] getScanFiles() {
816         return line.getOptionValues(ARGUMENT.SCAN);
817     }
818 
819     /**
820      * Retrieves the list of excluded file patterns specified by the 'exclude'
821      * argument.
822      *
823      * @return the excluded file patterns
824      */
825     public String[] getExcludeList() {
826         return line.getOptionValues(ARGUMENT.EXCLUDE);
827     }
828 
829     /**
830      * Retrieves the list of retire JS content filters used to exclude JS files
831      * by content.
832      *
833      * @return the retireJS filters
834      */
835     public String[] getRetireJsFilters() {
836         return line.getOptionValues(ARGUMENT.RETIRE_JS_FILTERS);
837     }
838 
839     /**
840      * Returns whether or not the retireJS analyzer should exclude
841      * non-vulnerable JS from the report.
842      *
843      * @return <code>true</code> if non-vulnerable JS should be filtered in the
844      * RetireJS Analyzer; otherwise <code>null</code>
845      */
846     @SuppressFBWarnings(justification = "Accepting that this is a bad practice - but made more sense in this use case",
847             value = {"NP_BOOLEAN_RETURN_NULL"})
848     public Boolean isRetireJsFilterNonVulnerable() {
849         return line != null && line.hasOption(ARGUMENT.RETIRE_JS_FILTER_NON_VULNERABLE) ? true : null;
850     }
851 
852     /**
853      * Returns the directory to write the reports to specified on the command
854      * line.
855      *
856      * @return the path to the reports directory.
857      */
858     public String getReportDirectory() {
859         return line.getOptionValue(ARGUMENT.OUT, ".");
860     }
861 
862     /**
863      * Returns the output format specified on the command line. Defaults to HTML
864      * if no format was specified.
865      *
866      * @return the output format name.
867      */
868     public String[] getReportFormat() {
869         if (line.hasOption(ARGUMENT.OUTPUT_FORMAT)) {
870             return line.getOptionValues(ARGUMENT.OUTPUT_FORMAT);
871         }
872         return new String[]{"HTML"};
873     }
874 
875     /**
876      * Returns the application name specified on the command line.
877      *
878      * @return the application name.
879      */
880     public String getProjectName() {
881         String name = line.getOptionValue(ARGUMENT.PROJECT);
882         if (name == null) {
883             name = "";
884         }
885         return name;
886     }
887 
888     /**
889      * <p>
890      * Prints the manifest information to standard output.</p>
891      * <ul><li>Implementation-Title: ${pom.name}</li>
892      * <li>Implementation-Version: ${pom.version}</li></ul>
893      */
894     public void printVersionInfo() {
895         final String version = String.format("%s version %s",
896                 settings.getString(Settings.KEYS.APPLICATION_NAME, "dependency-check"),
897                 settings.getString(Settings.KEYS.APPLICATION_VERSION, "Unknown"));
898         System.out.println(version);
899     }
900 
901     /**
902      * Checks if the update only flag has been set.
903      *
904      * @return <code>true</code> if the update only flag has been set; otherwise
905      * <code>false</code>.
906      */
907     public boolean isUpdateOnly() {
908         return line != null && line.hasOption(ARGUMENT.UPDATE_ONLY);
909     }
910 
911     /**
912      * Checks if the purge NVD flag has been set.
913      *
914      * @return <code>true</code> if the purge nvd flag has been set; otherwise
915      * <code>false</code>.
916      */
917     public boolean isPurge() {
918         return line != null && line.hasOption(ARGUMENT.PURGE_NVD);
919     }
920 
921     /**
922      * Returns the database driver name if specified; otherwise null is
923      * returned.
924      *
925      * @return the database driver name if specified; otherwise null is returned
926      */
927     public String getDatabaseDriverName() {
928         return line.getOptionValue(ARGUMENT.DB_DRIVER);
929     }
930 
931     /**
932      * Returns the argument value.
933      *
934      * @param argument the argument
935      * @return the value of the argument
936      */
937     public Integer getIntegerValue(String argument) {
938         final String v = line.getOptionValue(argument);
939         if (v != null) {
940             return Integer.parseInt(v);
941         }
942         return null;
943     }
944 
945     /**
946      * Checks if the option is present. If present it will return
947      * <code>true</code>; otherwise <code>false</code>.
948      *
949      * @param option the option to check
950      * @return <code>true</code> if auto-update is allowed; otherwise
951      * <code>null</code>
952      */
953     @SuppressFBWarnings(justification = "Accepting that this is a bad practice - but made more sense in this use case",
954             value = {"NP_BOOLEAN_RETURN_NULL"})
955     public Boolean hasOption(String option) {
956         return (line != null && line.hasOption(option)) ? true : null;
957     }
958 
959     /**
960      * Returns the CVSS value to fail on.
961      *
962      * @return 11 if nothing is set. Otherwise it returns the int passed from
963      * the command line arg
964      */
965     public float getFailOnCVSS() {
966         if (line.hasOption(ARGUMENT.FAIL_ON_CVSS)) {
967             final String value = line.getOptionValue(ARGUMENT.FAIL_ON_CVSS);
968             try {
969                 return Float.parseFloat(value);
970             } catch (NumberFormatException nfe) {
971                 return 11;
972             }
973         } else {
974             return 11;
975         }
976     }
977 
978     /**
979      * Returns the float argument for the given option.
980      *
981      * @param option the option
982      * @param defaultValue the value if the option is not present
983      * @return the value of the argument if present; otherwise the defaultValue
984      */
985     public float getFloatArgument(String option, float defaultValue) {
986         if (line.hasOption(option)) {
987             final String value = line.getOptionValue(option);
988             try {
989                 return Integer.parseInt(value);
990             } catch (NumberFormatException nfe) {
991                 return defaultValue;
992             }
993         } else {
994             return defaultValue;
995         }
996     }
997 
998     /**
999      * Builds a new option.
1000      *
1001      * @param name the long name
1002      * @param description the description
1003      * @return a new option
1004      */
1005     private Option newOption(String name, String description) {
1006         return Option.builder().longOpt(name).desc(description).get();
1007     }
1008 
1009     /**
1010      * Builds a new option.
1011      *
1012      * @param shortName the short name
1013      * @param name the long name
1014      * @param description the description
1015      * @return a new option
1016      */
1017     private Option newOption(String shortName, String name, String description) {
1018         return Option.builder(shortName).longOpt(name).desc(description).get();
1019     }
1020 
1021     /**
1022      * Builds a new option.
1023      *
1024      * @param name the long name
1025      * @param arg the argument name
1026      * @param description the description
1027      * @return a new option
1028      */
1029     private Option newOptionWithArg(String name, String arg, String description) {
1030         return Option.builder().longOpt(name).argName(arg).hasArg().desc(description).get();
1031     }
1032 
1033     /**
1034      * Builds a new option.
1035      *
1036      * @param shortName the short name
1037      * @param name the long name
1038      * @param arg the argument name
1039      * @param description the description
1040      * @return a new option
1041      */
1042     private Option newOptionWithArg(String shortName, String name, String arg, String description) {
1043         return Option.builder(shortName).longOpt(name).argName(arg).hasArg().desc(description).get();
1044     }
1045 
1046     /**
1047      * Builds a new option group so that an option can be specified multiple
1048      * times on the command line.
1049      *
1050      * @param option the option to add to the group
1051      * @return a new option group
1052      */
1053     private OptionGroup newOptionGroup(Option option) {
1054         final OptionGroup group = new OptionGroup();
1055         group.addOption(option);
1056         return group;
1057     }
1058 
1059     /**
1060      * A collection of static final strings that represent the possible command
1061      * line arguments.
1062      */
1063     public static class ARGUMENT {
1064 
1065         /**
1066          * The long CLI argument name specifying the directory/file to scan.
1067          */
1068         public static final String SCAN = "scan";
1069         /**
1070          * The short CLI argument name specifying the directory/file to scan.
1071          */
1072         public static final String SCAN_SHORT = "s";
1073         /**
1074          * The long CLI argument name specifying that the CPE/CVE/etc. data
1075          * should not be automatically updated.
1076          */
1077         public static final String DISABLE_AUTO_UPDATE = "noupdate";
1078         /**
1079          * The long CLI argument name specifying that the version check should
1080          * not be performed.
1081          */
1082         public static final String DISABLE_VERSION_CHECK = "disableVersionCheck";
1083         /**
1084          * The short CLI argument name specifying that the CPE/CVE/etc. data
1085          * should not be automatically updated.
1086          */
1087         public static final String DISABLE_AUTO_UPDATE_SHORT = "n";
1088         /**
1089          * The long CLI argument name specifying that only the update phase
1090          * should be executed; no scan should be run.
1091          */
1092         public static final String UPDATE_ONLY = "updateonly";
1093         /**
1094          * The long CLI argument name specifying that only the update phase
1095          * should be executed; no scan should be run.
1096          */
1097         public static final String PURGE_NVD = "purge";
1098         /**
1099          * The long CLI argument name specifying the directory to write the
1100          * reports to.
1101          */
1102         public static final String OUT = "out";
1103         /**
1104          * The short CLI argument name specifying the directory to write the
1105          * reports to.
1106          */
1107         public static final String OUT_SHORT = "o";
1108         /**
1109          * The long CLI argument name specifying the output format to write the
1110          * reports to.
1111          */
1112         public static final String OUTPUT_FORMAT = "format";
1113         /**
1114          * The short CLI argument name specifying the output format to write the
1115          * reports to.
1116          */
1117         public static final String OUTPUT_FORMAT_SHORT = "f";
1118         /**
1119          * The long CLI argument name specifying the name of the project to be
1120          * scanned.
1121          */
1122         public static final String PROJECT = "project";
1123         /**
1124          * The long CLI argument name asking for help.
1125          */
1126         public static final String HELP = "help";
1127         /**
1128          * The long CLI argument name asking for advanced help.
1129          */
1130         public static final String ADVANCED_HELP = "advancedHelp";
1131         /**
1132          * The short CLI argument name asking for help.
1133          */
1134         public static final String HELP_SHORT = "h";
1135         /**
1136          * The long CLI argument name asking for the version.
1137          */
1138         public static final String VERSION_SHORT = "v";
1139         /**
1140          * The short CLI argument name asking for the version.
1141          */
1142         public static final String VERSION = "version";
1143         /**
1144          * The CLI argument name indicating the proxy port.
1145          */
1146         public static final String PROXY_PORT = "proxyport";
1147         /**
1148          * The CLI argument name indicating the proxy server.
1149          */
1150         public static final String PROXY_SERVER = "proxyserver";
1151         /**
1152          * The CLI argument name indicating the proxy username.
1153          */
1154         public static final String PROXY_USERNAME = "proxyuser";
1155         /**
1156          * The CLI argument name indicating the proxy password.
1157          */
1158         public static final String PROXY_PASSWORD = "proxypass";
1159         /**
1160          * The CLI argument name indicating the proxy proxy exclusion list.
1161          */
1162         public static final String NON_PROXY_HOSTS = "nonProxyHosts";
1163         /**
1164          * The short CLI argument name indicating the connection timeout.
1165          */
1166         public static final String CONNECTION_TIMEOUT_SHORT = "c";
1167         /**
1168          * The CLI argument name indicating the connection timeout.
1169          */
1170         public static final String CONNECTION_TIMEOUT = "connectiontimeout";
1171         /**
1172          * The CLI argument name indicating the connection read timeout.
1173          */
1174         public static final String CONNECTION_READ_TIMEOUT = "readtimeout";
1175         /**
1176          * The short CLI argument name for setting the location of an additional
1177          * properties file.
1178          */
1179         public static final String PROP_SHORT = "P";
1180         /**
1181          * The CLI argument name for setting the location of an additional
1182          * properties file.
1183          */
1184         public static final String PROP = "propertyfile";
1185         /**
1186          * The CLI argument name for setting the location of the data directory.
1187          */
1188         public static final String DATA_DIRECTORY = "data";
1189         /**
1190          * The CLI argument name for setting the URL for the NVD API Endpoint.
1191          */
1192         public static final String NVD_API_ENDPOINT = "nvdApiEndpoint";
1193         /**
1194          * The CLI argument name for setting the URL for the NVD API Key.
1195          */
1196         public static final String NVD_API_KEY = "nvdApiKey";
1197         /**
1198          * The CLI argument name for setting the maximum number of retry
1199          * requests for a single call to the NVD API.
1200          */
1201         public static final String NVD_API_MAX_RETRY_COUNT = "nvdMaxRetryCount";
1202         /**
1203          * The CLI argument name for setting the number of hours to wait before
1204          * checking for new updates from the NVD.
1205          */
1206         public static final String NVD_API_VALID_FOR_HOURS = "nvdValidForHours";
1207         /**
1208          * The CLI argument name for the NVD API Data Feed URL.
1209          */
1210         public static final String NVD_API_DATAFEED_URL = "nvdDatafeed";
1211         /**
1212          * The username for basic auth to the CVE data.
1213          */
1214         public static final String NVD_API_DATAFEED_USER = "nvdUser";
1215         /**
1216          * The password for basic auth to the CVE data.
1217          */
1218         public static final String NVD_API_DATAFEED_PASSWORD = "nvdPassword";
1219         /**
1220          * The token for bearer auth to the CVE data.
1221          */
1222         public static final String NVD_API_DATAFEED_BEARER_TOKEN = "nvdBearerToken";
1223         /**
1224          * The username for basic auth to web-hosted suppression files.
1225          */
1226         public static final String SUPPRESSION_FILE_USER = "suppressionUser";
1227         /**
1228          * The passwored for basic auth to web-hosted suppression files.
1229          */
1230         public static final String SUPPRESSION_FILE_PASSWORD = "suppressionPassword";
1231         /**
1232          * The toke for bearer auth to web-hosted suppression files.
1233          */
1234         public static final String SUPPRESSION_FILE_BEARER_TOKEN = "suppressionBearerToken";
1235         /**
1236          * The time in milliseconds to wait between downloading NVD API data.
1237          */
1238         public static final String NVD_API_DELAY = "nvdApiDelay";
1239         /**
1240          * The number records for a single page from NVD API.
1241          */
1242         public static final String NVD_API_RESULTS_PER_PAGE = "nvdApiResultsPerPage";
1243         /**
1244          * The short CLI argument name for setting the location of the data
1245          * directory.
1246          */
1247         public static final String DATA_DIRECTORY_SHORT = "d";
1248         /**
1249          * The CLI argument name for setting the location of the data directory.
1250          */
1251         public static final String VERBOSE_LOG = "log";
1252         /**
1253          * The short CLI argument name for setting the location of the data
1254          * directory.
1255          */
1256         public static final String VERBOSE_LOG_SHORT = "l";
1257         /**
1258          * The CLI argument name for setting the depth of symbolic links that
1259          * will be followed.
1260          */
1261         public static final String SYM_LINK_DEPTH = "symLink";
1262         /**
1263          * The CLI argument name for setting the location of the suppression
1264          * file(s).
1265          */
1266         public static final String SUPPRESSION_FILES = "suppression";
1267         /**
1268          * The CLI argument name for setting the location of the hint file.
1269          */
1270         public static final String HINTS_FILE = "hints";
1271         /**
1272          * Disables the Jar Analyzer.
1273          */
1274         public static final String DISABLE_JAR = "disableJar";
1275         /**
1276          * Disable the MS Build Analyzer.
1277          */
1278         public static final String DISABLE_MSBUILD = "disableMSBuild";
1279         /**
1280          * Disables the Archive Analyzer.
1281          */
1282         public static final String DISABLE_ARCHIVE = "disableArchive";
1283         /**
1284          * Disables the Known Exploited Analyzer.
1285          */
1286         public static final String DISABLE_KEV = "disableKnownExploited";
1287         /**
1288          * The URL to the CISA Known Exploited Vulnerability JSON datafeed.
1289          */
1290         public static final String KEV_URL = "kevURL";
1291         /**
1292          * The user for basic auth towards a CISA Known Exploited Vulnerability JSON datafeed mirror.
1293          */
1294         public static final String KEV_USER = "kevUser";
1295         /**
1296          * The password for basic auth towards a CISA Known Exploited Vulnerability JSON datafeed mirror.
1297          */
1298         public static final String KEV_PASSWORD = "kevPassword";
1299         /**
1300          * The token for bearer auth towards a CISA Known Exploited Vulnerability JSON datafeed mirror.
1301          */
1302         public static final String KEV_BEARER_TOKEN = "kevBearerToken";
1303         /**
1304          * Disables the Python Distribution Analyzer.
1305          */
1306         public static final String DISABLE_PY_DIST = "disablePyDist";
1307         /**
1308          * Disables the Python Package Analyzer.
1309          */
1310         public static final String DISABLE_PY_PKG = "disablePyPkg";
1311         /**
1312          * Disables the Elixir mix audit Analyzer.
1313          */
1314         public static final String DISABLE_MIX_AUDIT = "disableMixAudit";
1315         /**
1316          * Disables the Golang Dependency Analyzer.
1317          */
1318         public static final String DISABLE_GO_DEP = "disableGolangDep";
1319         /**
1320          * Disables the PHP Composer Analyzer.
1321          */
1322         public static final String DISABLE_COMPOSER = "disableComposer";
1323         /**
1324          * Whether the PHP Composer Analyzer skips dev packages.
1325          */
1326         public static final String COMPOSER_LOCK_SKIP_DEV = "composerSkipDev";
1327         /**
1328          * Disables the Perl CPAN File Analyzer.
1329          */
1330         public static final String DISABLE_CPAN = "disableCpan";
1331         /**
1332          * Disables the Golang Mod Analyzer.
1333          */
1334         public static final String DISABLE_GOLANG_MOD = "disableGolangMod";
1335         /**
1336          * Disables the Dart Analyzer.
1337          */
1338         public static final String DISABLE_DART = "disableDart";
1339         /**
1340          * The CLI argument name for setting the path to `go`.
1341          */
1342         public static final String PATH_TO_GO = "go";
1343         /**
1344          * The CLI argument name for setting the path to `yarn`.
1345          */
1346         public static final String PATH_TO_YARN = "yarn";
1347         /**
1348          * The CLI argument name for setting the path to `pnpm`.
1349          */
1350         public static final String PATH_TO_PNPM = "pnpm";
1351         /**
1352          * Disables the Ruby Gemspec Analyzer.
1353          */
1354         public static final String DISABLE_RUBYGEMS = "disableRubygems";
1355         /**
1356          * Disables the Autoconf Analyzer.
1357          */
1358         public static final String DISABLE_AUTOCONF = "disableAutoconf";
1359         /**
1360          * Disables the Maven install Analyzer.
1361          */
1362         public static final String DISABLE_MAVEN_INSTALL = "disableMavenInstall";
1363         /**
1364          * Disables the pip Analyzer.
1365          */
1366         public static final String DISABLE_PIP = "disablePip";
1367         /**
1368          * Disables the Pipfile Analyzer.
1369          */
1370         public static final String DISABLE_PIPFILE = "disablePipfile";
1371         /**
1372          * Disables the Poetry Analyzer.
1373          */
1374         public static final String DISABLE_POETRY = "disablePoetry";
1375         /**
1376          * Disables the Cmake Analyzer.
1377          */
1378         public static final String DISABLE_CMAKE = "disableCmake";
1379         /**
1380          * Disables the cocoapods analyzer.
1381          */
1382         public static final String DISABLE_COCOAPODS = "disableCocoapodsAnalyzer";
1383         /**
1384          * Disables the Carthage analyzer.
1385          */
1386         public static final String DISABLE_CARTHAGE = "disableCarthageAnalyzer";
1387         /**
1388          * Disables the swift package manager analyzer.
1389          */
1390         public static final String DISABLE_SWIFT = "disableSwiftPackageManagerAnalyzer";
1391         /**
1392          * Disables the swift package resolved analyzer.
1393          */
1394         public static final String DISABLE_SWIFT_RESOLVED = "disableSwiftPackageResolvedAnalyzer";
1395         /**
1396          * Disables the Assembly Analyzer.
1397          */
1398         public static final String DISABLE_ASSEMBLY = "disableAssembly";
1399         /**
1400          * Disables the PE Analyzer.
1401          */
1402         public static final String DISABLE_PE = "disablePE";
1403         /**
1404          * Disables the Ruby Bundler Audit Analyzer.
1405          */
1406         public static final String DISABLE_BUNDLE_AUDIT = "disableBundleAudit";
1407         /**
1408          * Disables the File Name Analyzer.
1409          */
1410         public static final String DISABLE_FILENAME = "disableFileName";
1411         /**
1412          * Disables the Nuspec Analyzer.
1413          */
1414         public static final String DISABLE_NUSPEC = "disableNuspec";
1415         /**
1416          * Disables the Nuget packages.config Analyzer.
1417          */
1418         public static final String DISABLE_NUGETCONF = "disableNugetconf";
1419         /**
1420          * Disables the Central Analyzer.
1421          */
1422         public static final String DISABLE_CENTRAL = "disableCentral";
1423         /**
1424          * Disables the Central Analyzer's ability to cache results locally.
1425          */
1426         public static final String DISABLE_CENTRAL_CACHE = "disableCentralCache";
1427         /**
1428          * The alternative URL for Maven Central Search.
1429          */
1430         public static final String CENTRAL_URL = "centralUrl";
1431         /**
1432          * The username for basic authentication to the alternative Maven Central Search.
1433          */
1434         public static final String CENTRAL_USERNAME = "centralUsername";
1435         /**
1436          * The password for basic authentication to the alternative Maven Central Search.
1437          */
1438         public static final String CENTRAL_PASSWORD = "centralPassword";
1439         /**
1440          * The token for bearer authentication to the alternative Maven Central Search.
1441          */
1442         public static final String CENTRAL_BEARER_TOKEN = "centralBearerToken";
1443         /**
1444          * Disables the Nexus Analyzer.
1445          */
1446         public static final String ENABLE_NEXUS = "enableNexus";
1447         /**
1448          * Disables the Sonatype OSS Index Analyzer.
1449          */
1450         public static final String DISABLE_OSSINDEX = "disableOssIndex";
1451         /**
1452          * Disables the Sonatype OSS Index Analyzer's ability to cache results
1453          * locally.
1454          */
1455         public static final String DISABLE_OSSINDEX_CACHE = "disableOssIndexCache";
1456         /**
1457          * The number of hours to wait before checking for new updates on individual packages/components from Sonatype OSS Index
1458          */
1459         public static final String OSSINDEX_CACHE_VALID_FOR_HOURS = "ossIndexCacheValidForHours";
1460         /**
1461          * The alternative URL for the Sonatype OSS Index.
1462          */
1463         public static final String OSSINDEX_URL = "ossIndexUrl";
1464         /**
1465          * The username for the Sonatype OSS Index.
1466          */
1467         public static final String OSSINDEX_USERNAME = "ossIndexUsername";
1468         /**
1469          * The password for the Sonatype OSS Index.
1470          */
1471         public static final String OSSINDEX_PASSWORD = "ossIndexPassword";
1472         /**
1473          * The password for the Sonatype OSS Index.
1474          */
1475         public static final String OSSINDEX_WARN_ONLY_ON_REMOTE_ERRORS = "ossIndexRemoteErrorWarnOnly";
1476         /**
1477          * Disables the OpenSSL Analyzer.
1478          */
1479         public static final String DISABLE_OPENSSL = "disableOpenSSL";
1480         /**
1481          * Disables the Node Package Analyzer.
1482          */
1483         public static final String DISABLE_NODE_JS = "disableNodeJS";
1484         /**
1485          * Skips dev dependencies in Node Package Analyzer.
1486          */
1487         public static final String NODE_PACKAGE_SKIP_DEV_DEPENDENCIES = "nodePackageSkipDevDependencies";
1488         /**
1489          * Disables the Node Audit Analyzer.
1490          */
1491         public static final String DISABLE_NODE_AUDIT = "disableNodeAudit";
1492         /**
1493          * Disables the Yarn Audit Analyzer.
1494          */
1495         public static final String DISABLE_YARN_AUDIT = "disableYarnAudit";
1496         /**
1497          * Disables the Pnpm Audit Analyzer.
1498          */
1499         public static final String DISABLE_PNPM_AUDIT = "disablePnpmAudit";
1500         /**
1501          * Disables the Node Audit Analyzer's ability to cache results locally.
1502          */
1503         public static final String DISABLE_NODE_AUDIT_CACHE = "disableNodeAuditCache";
1504         /**
1505          * Configures the Node Audit Analyzer to skip the dev dependencies.
1506          */
1507         public static final String DISABLE_NODE_AUDIT_SKIPDEV = "nodeAuditSkipDevDependencies";
1508         /**
1509          * Disables the RetireJS Analyzer.
1510          */
1511         public static final String DISABLE_RETIRE_JS = "disableRetireJs";
1512         /**
1513          * Whether the RetireJS Analyzer will update regardless of the
1514          * `autoupdate` setting.
1515          */
1516         public static final String RETIRE_JS_FORCEUPDATE = "retireJsForceUpdate";
1517         /**
1518          * The URL to the retire JS repository.
1519          */
1520         public static final String RETIREJS_URL = "retireJsUrl";
1521         /**
1522          * The username for basic auth to the retire JS repository.
1523          */
1524         public static final String RETIREJS_URL_USER = "retireJsUrlUser";
1525         /**
1526          * The password for basic auth to the retire JS repository.
1527          */
1528         public static final String RETIREJS_URL_PASSWORD = "retireJsUrlPass";
1529         /**
1530          * The token for bearer auth to the retire JS repository.
1531          */
1532         public static final String RETIREJS_URL_BEARER_TOKEN = "retireJsUrlBearerToken";
1533         /**
1534          * The URL of the nexus server.
1535          */
1536         public static final String NEXUS_URL = "nexus";
1537         /**
1538          * The username for the nexus server.
1539          */
1540         public static final String NEXUS_USERNAME = "nexusUser";
1541         /**
1542          * The password for the nexus server.
1543          */
1544         public static final String NEXUS_PASSWORD = "nexusPass";
1545         /**
1546          * Whether or not the defined proxy should be used when connecting to
1547          * Nexus.
1548          */
1549         public static final String NEXUS_USES_PROXY = "nexusUsesProxy";
1550         /**
1551          * The CLI argument name for setting the connection string.
1552          */
1553         public static final String CONNECTION_STRING = "connectionString";
1554         /**
1555          * The CLI argument name for setting the database user name.
1556          */
1557         public static final String DB_NAME = "dbUser";
1558         /**
1559          * The CLI argument name for setting the database password.
1560          */
1561         public static final String DB_PASSWORD = "dbPassword";
1562         /**
1563          * The CLI argument name for setting the database driver name.
1564          */
1565         public static final String DB_DRIVER = "dbDriverName";
1566         /**
1567          * The CLI argument name for setting the path to the database driver; in
1568          * case it is not on the class path.
1569          */
1570         public static final String DB_DRIVER_PATH = "dbDriverPath";
1571         /**
1572          * The CLI argument name for setting the path to dotnet core.
1573          */
1574         public static final String PATH_TO_CORE = "dotnet";
1575         /**
1576          * The CLI argument name for setting extra extensions.
1577          */
1578         public static final String ADDITIONAL_ZIP_EXTENSIONS = "zipExtensions";
1579         /**
1580          * Exclude path argument.
1581          */
1582         public static final String EXCLUDE = "exclude";
1583         /**
1584          * The CLI argument name for setting the path to bundle-audit for Ruby
1585          * bundle analysis.
1586          */
1587         public static final String PATH_TO_BUNDLE_AUDIT = "bundleAudit";
1588         /**
1589          * The CLI argument name for setting the path that should be used as the
1590          * working directory that the bundle-audit command used for Ruby bundle
1591          * analysis should be executed from. This will allow for the usage of
1592          * rbenv
1593          */
1594         public static final String PATH_TO_BUNDLE_AUDIT_WORKING_DIRECTORY = "bundleAuditWorkingDirectory";
1595         /**
1596          * The CLI argument name for setting the path to mix_audit for Elixir
1597          * analysis.
1598          */
1599         public static final String PATH_TO_MIX_AUDIT = "mixAudit";
1600         /**
1601          * The CLI argument to enable the experimental analyzers.
1602          */
1603         public static final String EXPERIMENTAL = "enableExperimental";
1604         /**
1605          * The CLI argument to enable the retired analyzers.
1606          */
1607         public static final String RETIRED = "enableRetired";
1608         /**
1609          * The CLI argument for the retire JS content filters.
1610          */
1611         public static final String RETIRE_JS_FILTERS = "retireJsFilter";
1612         /**
1613          * The CLI argument for the retire JS content filter for non-vulnerable.
1614          */
1615         public static final String RETIRE_JS_FILTER_NON_VULNERABLE = "retireJsFilterNonVulnerable";
1616         /**
1617          * The CLI argument for indicating if the Artifactory analyzer should be
1618          * enabled.
1619          */
1620         public static final String ARTIFACTORY_ENABLED = "enableArtifactory";
1621         /**
1622          * The CLI argument for indicating if the Artifactory analyzer should
1623          * use the proxy.
1624          */
1625         public static final String ARTIFACTORY_URL = "artifactoryUrl";
1626         /**
1627          * The CLI argument for indicating the Artifactory username.
1628          */
1629         public static final String ARTIFACTORY_USERNAME = "artifactoryUsername";
1630         /**
1631          * The CLI argument for indicating the Artifactory API token.
1632          */
1633         public static final String ARTIFACTORY_API_TOKEN = "artifactoryApiToken";
1634         /**
1635          * The CLI argument for indicating the Artifactory bearer token.
1636          */
1637         public static final String ARTIFACTORY_BEARER_TOKEN = "artifactoryBearerToken";
1638         /**
1639          * The CLI argument for indicating if the Artifactory analyzer should
1640          * use the proxy.
1641          */
1642         public static final String ARTIFACTORY_USES_PROXY = "artifactoryUseProxy";
1643         /**
1644          * The CLI argument for indicating if the Artifactory analyzer should
1645          * use the parallel analysis.
1646          */
1647         public static final String ARTIFACTORY_PARALLEL_ANALYSIS = "artifactoryParallelAnalysis";
1648         /**
1649          * The CLI argument to configure when the execution should be considered
1650          * a failure.
1651          */
1652         public static final String FAIL_ON_CVSS = "failOnCVSS";
1653         /**
1654          * The CLI argument to configure if the XML and JSON reports should be
1655          * pretty printed.
1656          */
1657         public static final String PRETTY_PRINT = "prettyPrint";
1658         /**
1659          * The CLI argument to set the threshold that is considered a failure
1660          * when generating the JUNIT report format.
1661          */
1662         public static final String FAIL_JUNIT_ON_CVSS = "junitFailOnCVSS";
1663         /**
1664          * The CLI argument to set the number of hours to wait before
1665          * re-checking hosted suppressions file for updates.
1666          */
1667         public static final String DISABLE_HOSTED_SUPPRESSIONS = "disableHostedSuppressions";
1668         /**
1669          * The CLI argument to set the number of hours to wait before
1670          * re-checking hosted suppressions file for updates.
1671          */
1672         public static final String HOSTED_SUPPRESSIONS_VALID_FOR_HOURS = "hostedSuppressionsValidForHours";
1673         /**
1674          * The CLI argument to set Whether the hosted suppressions file will
1675          * update regardless of the `noupdate` argument.
1676          */
1677         public static final String HOSTED_SUPPRESSIONS_FORCEUPDATE = "hostedSuppressionsForceUpdate";
1678         /**
1679          * The CLI argument to set the location of a mirrored hosted
1680          * suppressions file .
1681          */
1682         public static final String HOSTED_SUPPRESSIONS_URL = "hostedSuppressionsUrl";
1683         /**
1684          * The username for basic auth to a mirrored hosted suppressions file.
1685          */
1686         public static final String HOSTED_SUPPRESSIONS_USER = "hostedSuppressionsUser";
1687         /**
1688          * The passwored for basic auth to a mirrored hosted suppressions file.
1689          */
1690         public static final String HOSTED_SUPPRESSIONS_PASSWORD = "hostedSuppressionsPassword";
1691         /**
1692          * The toke for bearer auth to  a mirrored hosted suppressions file.
1693          */
1694         public static final String HOSTED_SUPPRESSIONS_BEARER_TOKEN = "hostedSuppressionsBearerToken";
1695     }
1696 }