App.java

  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. import java.io.File;
  20. import java.io.FileNotFoundException;
  21. import java.io.IOException;
  22. import java.util.ArrayList;
  23. import java.util.List;
  24. import java.util.Set;

  25. import java.util.stream.Collectors;
  26. import java.util.stream.Stream;
  27. import org.apache.commons.cli.ParseException;
  28. import org.apache.tools.ant.DirectoryScanner;
  29. import org.owasp.dependencycheck.data.nvdcve.DatabaseException;
  30. import org.owasp.dependencycheck.dependency.Dependency;
  31. import org.owasp.dependencycheck.dependency.Vulnerability;
  32. import org.apache.tools.ant.types.LogLevel;
  33. import org.owasp.dependencycheck.data.update.exception.UpdateException;
  34. import org.owasp.dependencycheck.dependency.naming.Identifier;
  35. import org.owasp.dependencycheck.exception.ExceptionCollection;
  36. import org.owasp.dependencycheck.exception.ReportException;
  37. import org.owasp.dependencycheck.utils.Downloader;
  38. import org.owasp.dependencycheck.utils.InvalidSettingException;
  39. import org.owasp.dependencycheck.utils.Settings;
  40. import org.slf4j.Logger;
  41. import org.slf4j.LoggerFactory;

  42. import ch.qos.logback.core.FileAppender;
  43. import ch.qos.logback.classic.encoder.PatternLayoutEncoder;
  44. import ch.qos.logback.classic.filter.ThresholdFilter;
  45. import ch.qos.logback.classic.spi.ILoggingEvent;
  46. import ch.qos.logback.classic.Level;
  47. import ch.qos.logback.classic.LoggerContext;
  48. import io.github.jeremylong.jcs3.slf4j.Slf4jAdapter;
  49. import java.util.TreeSet;
  50. import org.owasp.dependencycheck.utils.SeverityUtil;

  51. /**
  52.  * The command line interface for the DependencyCheck application.
  53.  *
  54.  * @author Jeremy Long
  55.  */
  56. @SuppressWarnings("squid:S106")
  57. public class App {

  58.     /**
  59.      * The logger.
  60.      */
  61.     private static final Logger LOGGER = LoggerFactory.getLogger(App.class);
  62.     /**
  63.      * Properties file error message.
  64.      */
  65.     private static final String ERROR_LOADING_PROPERTIES_FILE = "Error loading properties file";
  66.     /**
  67.      * System specific new line character.
  68.      */
  69.     private static final String NEW_LINE = System.getProperty("line.separator", "\n");
  70.     /**
  71.      * The configured settings.
  72.      */
  73.     private final Settings settings;

  74.     /**
  75.      * The main method for the application.
  76.      *
  77.      * @param args the command line arguments
  78.      */
  79.     @SuppressWarnings("squid:S4823")
  80.     public static void main(String[] args) {
  81.         System.setProperty("jcs.logSystem", "slf4j");
  82.         if (!LOGGER.isDebugEnabled()) {
  83.             Slf4jAdapter.muteLogging(true);
  84.         }
  85.         final int exitCode;
  86.         final App app = new App();
  87.         exitCode = app.run(args);
  88.         LOGGER.debug("Exit code: {}", exitCode);
  89.         System.exit(exitCode);
  90.     }

  91.     /**
  92.      * Builds the App object.
  93.      */
  94.     public App() {
  95.         settings = new Settings();
  96.     }

  97.     /**
  98.      * Builds the App object; this method is used for testing.
  99.      *
  100.      * @param settings the configured settings
  101.      */
  102.     protected App(Settings settings) {
  103.         this.settings = settings;
  104.     }

  105.     /**
  106.      * Main CLI entry-point into the application.
  107.      *
  108.      * @param args the command line arguments
  109.      * @return the exit code to return
  110.      */
  111.     public int run(String[] args) {
  112.         int exitCode = 0;
  113.         final CliParser cli = new CliParser(settings);

  114.         try {
  115.             cli.parse(args);
  116.         } catch (FileNotFoundException ex) {
  117.             System.err.println(ex.getMessage());
  118.             cli.printHelp();
  119.             return 1;
  120.         } catch (ParseException ex) {
  121.             System.err.println(ex.getMessage());
  122.             cli.printHelp();
  123.             return 2;
  124.         }
  125.         final String verboseLog = cli.getStringArgument(CliParser.ARGUMENT.VERBOSE_LOG);
  126.         if (verboseLog != null) {
  127.             prepareLogger(verboseLog);
  128.         }

  129.         if (cli.isPurge()) {
  130.             final String connStr = cli.getStringArgument(CliParser.ARGUMENT.CONNECTION_STRING);
  131.             if (connStr != null) {
  132.                 LOGGER.error("Unable to purge the database when using a non-default connection string");
  133.                 exitCode = 3;
  134.             } else {
  135.                 try {
  136.                     populateSettings(cli);
  137.                     Downloader.getInstance().configure(settings);
  138.                 } catch (InvalidSettingException ex) {
  139.                     LOGGER.error(ex.getMessage());
  140.                     LOGGER.debug(ERROR_LOADING_PROPERTIES_FILE, ex);
  141.                     exitCode = 4;
  142.                     return exitCode;
  143.                 }
  144.                 try (Engine engine = new Engine(Engine.Mode.EVIDENCE_PROCESSING, settings)) {
  145.                     if (!engine.purge()) {
  146.                         exitCode = 7;
  147.                         return exitCode;
  148.                     }
  149.                 } finally {
  150.                     settings.cleanup();
  151.                 }
  152.             }
  153.         } else if (cli.isGetVersion()) {
  154.             cli.printVersionInfo();
  155.         } else if (cli.isUpdateOnly()) {
  156.             try {
  157.                 populateSettings(cli);
  158.                 settings.setBoolean(Settings.KEYS.AUTO_UPDATE, true);
  159.                 Downloader.getInstance().configure(settings);
  160.             } catch (InvalidSettingException ex) {
  161.                 LOGGER.error(ex.getMessage());
  162.                 LOGGER.debug(ERROR_LOADING_PROPERTIES_FILE, ex);
  163.                 exitCode = 4;
  164.                 return exitCode;
  165.             }
  166.             try {
  167.                 runUpdateOnly();
  168.             } catch (UpdateException ex) {
  169.                 LOGGER.error(ex.getMessage(), ex);
  170.                 exitCode = 8;
  171.             } catch (DatabaseException ex) {
  172.                 LOGGER.error(ex.getMessage(), ex);
  173.                 exitCode = 9;
  174.             } finally {
  175.                 settings.cleanup();
  176.             }
  177.         } else if (cli.isRunScan()) {
  178.             try {
  179.                 populateSettings(cli);
  180.                 Downloader.getInstance().configure(settings);
  181.             } catch (InvalidSettingException ex) {
  182.                 LOGGER.error(ex.getMessage(), ex);
  183.                 LOGGER.debug(ERROR_LOADING_PROPERTIES_FILE, ex);
  184.                 exitCode = 4;
  185.                 return exitCode;
  186.             }
  187.             try {
  188.                 final String[] scanFiles = cli.getScanFiles();
  189.                 if (scanFiles != null) {
  190.                     exitCode = runScan(cli.getReportDirectory(), cli.getReportFormat(), cli.getProjectName(), scanFiles,
  191.                             cli.getExcludeList(), cli.getSymLinkDepth(), cli.getFailOnCVSS());
  192.                 } else {
  193.                     LOGGER.error("No scan files configured");
  194.                 }
  195.             } catch (DatabaseException ex) {
  196.                 LOGGER.error(ex.getMessage());
  197.                 LOGGER.debug("database exception", ex);
  198.                 exitCode = 11;
  199.             } catch (ReportException ex) {
  200.                 LOGGER.error(ex.getMessage());
  201.                 LOGGER.debug("report exception", ex);
  202.                 exitCode = 12;
  203.             } catch (ExceptionCollection ex) {
  204.                 if (ex.isFatal()) {
  205.                     exitCode = 13;
  206.                     LOGGER.error("One or more fatal errors occurred");
  207.                 } else {
  208.                     exitCode = 14;
  209.                 }
  210.                 for (Throwable e : ex.getExceptions()) {
  211.                     if (e.getMessage() != null) {
  212.                         LOGGER.error(e.getMessage());
  213.                         LOGGER.debug("unexpected error", e);
  214.                     }
  215.                 }
  216.             } finally {
  217.                 settings.cleanup();
  218.             }
  219.         } else {
  220.             cli.printHelp();
  221.         }
  222.         return exitCode;
  223.     }

  224.     /**
  225.      * Scans the specified directories and writes the dependency reports to the
  226.      * reportDirectory.
  227.      *
  228.      * @param reportDirectory the path to the directory where the reports will
  229.      * be written
  230.      * @param outputFormats String[] of output formats of the report
  231.      * @param applicationName the application name for the report
  232.      * @param files the files/directories to scan
  233.      * @param excludes the patterns for files/directories to exclude
  234.      * @param symLinkDepth the depth that symbolic links will be followed
  235.      * @param cvssFailScore the score to fail on if a vulnerability is found
  236.      * @return the exit code if there was an error
  237.      * @throws ReportException thrown when the report cannot be generated
  238.      * @throws DatabaseException thrown when there is an error connecting to the
  239.      * database
  240.      * @throws ExceptionCollection thrown when an exception occurs during
  241.      * analysis; there may be multiple exceptions contained within the
  242.      * collection.
  243.      */
  244.     private int runScan(String reportDirectory, String[] outputFormats, String applicationName, String[] files,
  245.             String[] excludes, int symLinkDepth, float cvssFailScore) throws DatabaseException,
  246.             ExceptionCollection, ReportException {
  247.         Engine engine = null;
  248.         try {
  249.             final List<String> antStylePaths = getPaths(files);
  250.             final Set<File> paths = scanAntStylePaths(antStylePaths, symLinkDepth, excludes);

  251.             engine = new Engine(settings);
  252.             engine.scan(paths);

  253.             ExceptionCollection exCol = null;
  254.             try {
  255.                 engine.analyzeDependencies();
  256.             } catch (ExceptionCollection ex) {
  257.                 if (ex.isFatal()) {
  258.                     throw ex;
  259.                 }
  260.                 exCol = ex;
  261.             }

  262.             try {
  263.                 for (String outputFormat : outputFormats) {
  264.                     engine.writeReports(applicationName, new File(reportDirectory), outputFormat, exCol);
  265.                 }
  266.             } catch (ReportException ex) {
  267.                 if (exCol != null) {
  268.                     exCol.addException(ex);
  269.                     throw exCol;
  270.                 } else {
  271.                     throw ex;
  272.                 }
  273.             }
  274.             if (exCol != null && !exCol.getExceptions().isEmpty()) {
  275.                 throw exCol;
  276.             }
  277.             return determineReturnCode(engine, cvssFailScore);
  278.         } finally {
  279.             if (engine != null) {
  280.                 engine.close();
  281.             }
  282.         }
  283.     }

  284.     /**
  285.      * Determines the return code based on if one of the dependencies scanned
  286.      * has a vulnerability with a CVSS score above the cvssFailScore.
  287.      *
  288.      * @param engine the engine used during analysis
  289.      * @param cvssFailScore the max allowed CVSS score
  290.      * @return returns <code>1</code> if a severe enough vulnerability is
  291.      * identified; otherwise <code>0</code>
  292.      */
  293.     private int determineReturnCode(Engine engine, float cvssFailScore) {
  294.         int retCode = 0;
  295.         //Set the exit code based on whether we found a high enough vulnerability
  296.         final StringBuilder ids = new StringBuilder();
  297.         for (Dependency d : engine.getDependencies()) {
  298.             boolean addName = true;
  299.             for (Vulnerability v : d.getVulnerabilities()) {
  300.                 final Double cvssV2 = v.getCvssV2() != null && v.getCvssV2().getCvssData() != null
  301.                         && v.getCvssV2().getCvssData().getBaseScore() != null ? v.getCvssV2().getCvssData().getBaseScore() : -1;
  302.                 final Double cvssV3 = v.getCvssV3() != null && v.getCvssV3().getCvssData() != null
  303.                         && v.getCvssV3().getCvssData().getBaseScore() != null ? v.getCvssV3().getCvssData().getBaseScore() : -1;
  304.                 final Double cvssV4 = v.getCvssV4() != null && v.getCvssV4().getCvssData() != null
  305.                         && v.getCvssV4().getCvssData().getBaseScore() != null ? v.getCvssV4().getCvssData().getBaseScore() : -1;
  306.                 final Double unscoredCvss = v.getUnscoredSeverity() != null ? SeverityUtil.estimateCvssV2(v.getUnscoredSeverity()) : -1;

  307.                 if (cvssV2 >= cvssFailScore
  308.                         || cvssV3 >= cvssFailScore
  309.                         || cvssV4 >= cvssFailScore
  310.                         || unscoredCvss >= cvssFailScore
  311.                         //safety net to fail on any if for some reason the above misses on 0
  312.                         || (cvssFailScore <= 0.0f)) {
  313.                     double score = 0.0;
  314.                     if (cvssV4 >= 0.0) {
  315.                         score = cvssV4;
  316.                     } else if (cvssV3 >= 0.0) {
  317.                         score = cvssV3;
  318.                     } else if (cvssV2 >= 0.0) {
  319.                         score = cvssV2;
  320.                     } else if (unscoredCvss >= 0.0) {
  321.                         score = unscoredCvss;
  322.                     }
  323.                     if (addName) {
  324.                         addName = false;
  325.                         ids.append(NEW_LINE).append(d.getFileName()).append(" (")
  326.                            .append(Stream.concat(d.getSoftwareIdentifiers().stream(), d.getVulnerableSoftwareIdentifiers().stream())
  327.                                          .map(Identifier::getValue)
  328.                                          .collect(Collectors.joining(", ")))
  329.                            .append("): ");
  330.                         ids.append(v.getName()).append('(').append(score).append(')');
  331.                     } else {
  332.                         ids.append(", ").append(v.getName()).append('(').append(score).append(')');
  333.                     }
  334.                 }
  335.             }
  336.         }
  337.         if (ids.length() > 0) {
  338.             LOGGER.error(
  339.                     String.format("%n%nOne or more dependencies were identified with vulnerabilities that have a CVSS score greater than or "
  340.                             + "equal to '%.1f': %n%s%n%nSee the dependency-check report for more details.%n%n", cvssFailScore, ids)
  341.             );

  342.             retCode = 15;
  343.         }

  344.         return retCode;
  345.     }

  346.     /**
  347.      * Scans the give Ant Style paths and collects the actual files.
  348.      *
  349.      * @param antStylePaths a list of ant style paths to scan for actual files
  350.      * @param symLinkDepth the depth to traverse symbolic links
  351.      * @param excludes an array of ant style excludes
  352.      * @return returns the set of identified files
  353.      */
  354.     private Set<File> scanAntStylePaths(List<String> antStylePaths, int symLinkDepth, String[] excludes) {
  355.         final Set<File> paths = new TreeSet<>();
  356.         for (String file : antStylePaths) {
  357.             LOGGER.debug("Scanning {}", file);
  358.             final DirectoryScanner scanner = new DirectoryScanner();
  359.             String include = file.replace('\\', '/');
  360.             final File baseDir;
  361.             final int pos = getLastFileSeparator(include);
  362.             final String tmpBase = include.substring(0, pos);
  363.             final String tmpInclude = include.substring(pos + 1);
  364.             if (tmpInclude.indexOf('*') >= 0 || tmpInclude.indexOf('?') >= 0
  365.                     || new File(include).isFile()) {
  366.                 baseDir = new File(tmpBase);
  367.                 include = tmpInclude;
  368.             } else {
  369.                 baseDir = new File(tmpBase, tmpInclude);
  370.                 include = "**/*";
  371.             }
  372.             LOGGER.debug("BaseDir: " + baseDir);
  373.             LOGGER.debug("Include: " + include);
  374.             scanner.setBasedir(baseDir);
  375.             final String[] includes = {include};
  376.             scanner.setIncludes(includes);
  377.             scanner.setMaxLevelsOfSymlinks(symLinkDepth);
  378.             if (symLinkDepth <= 0) {
  379.                 scanner.setFollowSymlinks(false);
  380.             }
  381.             if (excludes != null && excludes.length > 0) {
  382.                 for (String e : excludes) {
  383.                     LOGGER.debug("Exclude: " + e);
  384.                 }
  385.                 scanner.addExcludes(excludes);
  386.             }
  387.             scanner.scan();
  388.             if (scanner.getIncludedFilesCount() > 0) {
  389.                 for (String s : scanner.getIncludedFiles()) {
  390.                     final File f = new File(baseDir, s);
  391.                     LOGGER.debug("Found file {}", f);
  392.                     paths.add(f);
  393.                 }
  394.             }
  395.         }
  396.         return paths;
  397.     }

  398.     /**
  399.      * Determines the ant style paths from the given array of files.
  400.      *
  401.      * @param files an array of file paths
  402.      * @return a list containing ant style paths
  403.      */
  404.     private List<String> getPaths(String[] files) {
  405.         final List<String> antStylePaths = new ArrayList<>();
  406.         for (String file : files) {
  407.             final String antPath = ensureCanonicalPath(file);
  408.             antStylePaths.add(antPath);
  409.         }
  410.         return antStylePaths;
  411.     }

  412.     /**
  413.      * Only executes the update phase of dependency-check.
  414.      *
  415.      * @throws UpdateException thrown if there is an error updating
  416.      * @throws DatabaseException thrown if a fatal error occurred and a
  417.      * connection to the database could not be established
  418.      */
  419.     private void runUpdateOnly() throws UpdateException, DatabaseException {
  420.         try (Engine engine = new Engine(settings)) {
  421.             engine.doUpdates();
  422.         }
  423.     }

  424.     //CSOFF: MethodLength
  425.     /**
  426.      * Updates the global Settings.
  427.      *
  428.      * @param cli a reference to the CLI Parser that contains the command line
  429.      * arguments used to set the corresponding settings in the core engine.
  430.      * @throws InvalidSettingException thrown when a user defined properties
  431.      * file is unable to be loaded.
  432.      */
  433.     protected void populateSettings(CliParser cli) throws InvalidSettingException {
  434.         final File propertiesFile = cli.getFileArgument(CliParser.ARGUMENT.PROP);
  435.         if (propertiesFile != null) {
  436.             try {
  437.                 settings.mergeProperties(propertiesFile);
  438.             } catch (FileNotFoundException ex) {
  439.                 throw new InvalidSettingException("Unable to find properties file '" + propertiesFile.getPath() + "'", ex);
  440.             } catch (IOException ex) {
  441.                 throw new InvalidSettingException("Error reading properties file '" + propertiesFile.getPath() + "'", ex);
  442.             }
  443.         }
  444.         final String dataDirectory = cli.getStringArgument(CliParser.ARGUMENT.DATA_DIRECTORY);
  445.         if (dataDirectory != null) {
  446.             settings.setString(Settings.KEYS.DATA_DIRECTORY, dataDirectory);
  447.         } else if (System.getProperty("basedir") != null) {
  448.             final File dataDir = new File(System.getProperty("basedir"), "data");
  449.             settings.setString(Settings.KEYS.DATA_DIRECTORY, dataDir.getAbsolutePath());
  450.         } else {
  451.             final File jarPath = new File(App.class
  452.                     .getProtectionDomain().getCodeSource().getLocation().getPath());
  453.             final File base = jarPath.getParentFile();
  454.             final String sub = settings.getString(Settings.KEYS.DATA_DIRECTORY);
  455.             final File dataDir = new File(base, sub);
  456.             settings.setString(Settings.KEYS.DATA_DIRECTORY, dataDir.getAbsolutePath());
  457.         }
  458.         final Boolean autoUpdate = cli.hasOption(CliParser.ARGUMENT.DISABLE_AUTO_UPDATE) != null ? false : null;
  459.         settings.setBooleanIfNotNull(Settings.KEYS.AUTO_UPDATE, autoUpdate);
  460.         settings.setStringIfNotEmpty(Settings.KEYS.PROXY_SERVER,
  461.                 cli.getStringArgument(CliParser.ARGUMENT.PROXY_SERVER));
  462.         settings.setStringIfNotEmpty(Settings.KEYS.PROXY_PORT,
  463.                 cli.getStringArgument(CliParser.ARGUMENT.PROXY_PORT));
  464.         settings.setStringIfNotEmpty(Settings.KEYS.PROXY_USERNAME,
  465.                 cli.getStringArgument(CliParser.ARGUMENT.PROXY_USERNAME));
  466.         settings.setStringIfNotEmpty(Settings.KEYS.PROXY_PASSWORD,
  467.                 cli.getStringArgument(CliParser.ARGUMENT.PROXY_PASSWORD, Settings.KEYS.PROXY_PASSWORD));
  468.         settings.setStringIfNotEmpty(Settings.KEYS.PROXY_NON_PROXY_HOSTS,
  469.                 cli.getStringArgument(CliParser.ARGUMENT.NON_PROXY_HOSTS));
  470.         settings.setStringIfNotEmpty(Settings.KEYS.CONNECTION_TIMEOUT,
  471.                 cli.getStringArgument(CliParser.ARGUMENT.CONNECTION_TIMEOUT));
  472.         settings.setStringIfNotEmpty(Settings.KEYS.CONNECTION_READ_TIMEOUT,
  473.                 cli.getStringArgument(CliParser.ARGUMENT.CONNECTION_READ_TIMEOUT));
  474.         settings.setStringIfNotEmpty(Settings.KEYS.HINTS_FILE,
  475.                 cli.getStringArgument(CliParser.ARGUMENT.HINTS_FILE));
  476.         settings.setArrayIfNotEmpty(Settings.KEYS.SUPPRESSION_FILE,
  477.                 cli.getStringArguments(CliParser.ARGUMENT.SUPPRESSION_FILES));
  478.         settings.setStringIfNotEmpty(Settings.KEYS.SUPPRESSION_FILE_USER,
  479.                 cli.getStringArgument(CliParser.ARGUMENT.SUPPRESSION_FILE_USER));
  480.         settings.setStringIfNotEmpty(Settings.KEYS.SUPPRESSION_FILE_PASSWORD,
  481.                 cli.getStringArgument(CliParser.ARGUMENT.SUPPRESSION_FILE_PASSWORD));
  482.         settings.setStringIfNotEmpty(Settings.KEYS.SUPPRESSION_FILE_BEARER_TOKEN,
  483.                 cli.getStringArgument(CliParser.ARGUMENT.SUPPRESSION_FILE_BEARER_TOKEN));
  484.         //File Type Analyzer Settings
  485.         settings.setBooleanIfNotNull(Settings.KEYS.ANALYZER_EXPERIMENTAL_ENABLED,
  486.                 cli.hasOption(CliParser.ARGUMENT.EXPERIMENTAL));
  487.         settings.setBooleanIfNotNull(Settings.KEYS.ANALYZER_RETIRED_ENABLED,
  488.                 cli.hasOption(CliParser.ARGUMENT.RETIRED));
  489.         settings.setStringIfNotNull(Settings.KEYS.ANALYZER_GOLANG_PATH,
  490.                 cli.getStringArgument(CliParser.ARGUMENT.PATH_TO_GO));
  491.         settings.setStringIfNotNull(Settings.KEYS.ANALYZER_YARN_PATH,
  492.                 cli.getStringArgument(CliParser.ARGUMENT.PATH_TO_YARN));
  493.         settings.setStringIfNotNull(Settings.KEYS.ANALYZER_PNPM_PATH,
  494.                 cli.getStringArgument(CliParser.ARGUMENT.PATH_TO_PNPM));
  495.         settings.setBooleanIfNotNull(Settings.KEYS.PRETTY_PRINT,
  496.                 cli.hasOption(CliParser.ARGUMENT.PRETTY_PRINT));
  497.         settings.setStringIfNotNull(Settings.KEYS.ANALYZER_RETIREJS_REPO_JS_URL,
  498.                 cli.getStringArgument(CliParser.ARGUMENT.RETIREJS_URL));
  499.         settings.setStringIfNotNull(Settings.KEYS.ANALYZER_RETIREJS_REPO_JS_USER,
  500.                 cli.getStringArgument(CliParser.ARGUMENT.RETIREJS_URL_USER));
  501.         settings.setStringIfNotNull(Settings.KEYS.ANALYZER_RETIREJS_REPO_JS_PASSWORD,
  502.                 cli.getStringArgument(CliParser.ARGUMENT.RETIREJS_URL_PASSWORD));
  503.         settings.setStringIfNotNull(Settings.KEYS.ANALYZER_RETIREJS_REPO_JS_BEARER_TOKEN,
  504.                 cli.getStringArgument(CliParser.ARGUMENT.RETIREJS_URL_BEARER_TOKEN));
  505.         settings.setBooleanIfNotNull(Settings.KEYS.ANALYZER_RETIREJS_FORCEUPDATE,
  506.                 cli.hasOption(CliParser.ARGUMENT.RETIRE_JS_FORCEUPDATE));
  507.         settings.setStringIfNotNull(Settings.KEYS.ANALYZER_RETIREJS_FILTERS,
  508.                 cli.getStringArgument(CliParser.ARGUMENT.RETIREJS_FILTERS));
  509.         settings.setBooleanIfNotNull(Settings.KEYS.ANALYZER_RETIREJS_FILTER_NON_VULNERABLE,
  510.                 cli.hasOption(CliParser.ARGUMENT.RETIREJS_FILTER_NON_VULNERABLE));
  511.         settings.setBoolean(Settings.KEYS.ANALYZER_JAR_ENABLED,
  512.                 !cli.isDisabled(CliParser.ARGUMENT.DISABLE_JAR, Settings.KEYS.ANALYZER_JAR_ENABLED));
  513.         settings.setBoolean(Settings.KEYS.UPDATE_VERSION_CHECK_ENABLED,
  514.                 !cli.isDisabled(CliParser.ARGUMENT.DISABLE_VERSION_CHECK, Settings.KEYS.UPDATE_VERSION_CHECK_ENABLED));
  515.         settings.setBoolean(Settings.KEYS.ANALYZER_MSBUILD_PROJECT_ENABLED,
  516.                 !cli.isDisabled(CliParser.ARGUMENT.DISABLE_MSBUILD, Settings.KEYS.ANALYZER_MSBUILD_PROJECT_ENABLED));
  517.         settings.setBoolean(Settings.KEYS.ANALYZER_ARCHIVE_ENABLED,
  518.                 !cli.isDisabled(CliParser.ARGUMENT.DISABLE_ARCHIVE, Settings.KEYS.ANALYZER_ARCHIVE_ENABLED));
  519.         settings.setBoolean(Settings.KEYS.ANALYZER_KNOWN_EXPLOITED_ENABLED,
  520.                 !cli.isDisabled(CliParser.ARGUMENT.DISABLE_KEV, Settings.KEYS.ANALYZER_KNOWN_EXPLOITED_ENABLED));
  521.         settings.setStringIfNotNull(Settings.KEYS.KEV_URL,
  522.                 cli.getStringArgument(CliParser.ARGUMENT.KEV_URL));
  523.         settings.setStringIfNotNull(Settings.KEYS.KEV_USER,
  524.                 cli.getStringArgument(CliParser.ARGUMENT.KEV_USER));
  525.         settings.setStringIfNotNull(Settings.KEYS.KEV_PASSWORD,
  526.                 cli.getStringArgument(CliParser.ARGUMENT.KEV_PASSWORD));
  527.         settings.setStringIfNotNull(Settings.KEYS.KEV_BEARER_TOKEN,
  528.                 cli.getStringArgument(CliParser.ARGUMENT.KEV_BEARER_TOKEN));
  529.         settings.setBoolean(Settings.KEYS.ANALYZER_PYTHON_DISTRIBUTION_ENABLED,
  530.                 !cli.isDisabled(CliParser.ARGUMENT.DISABLE_PY_DIST, Settings.KEYS.ANALYZER_PYTHON_DISTRIBUTION_ENABLED));
  531.         settings.setBoolean(Settings.KEYS.ANALYZER_PYTHON_PACKAGE_ENABLED,
  532.                 !cli.isDisabled(CliParser.ARGUMENT.DISABLE_PY_PKG, Settings.KEYS.ANALYZER_PYTHON_PACKAGE_ENABLED));
  533.         settings.setBoolean(Settings.KEYS.ANALYZER_AUTOCONF_ENABLED,
  534.                 !cli.isDisabled(CliParser.ARGUMENT.DISABLE_AUTOCONF, Settings.KEYS.ANALYZER_AUTOCONF_ENABLED));
  535.         settings.setBoolean(Settings.KEYS.ANALYZER_MAVEN_INSTALL_ENABLED,
  536.                 !cli.isDisabled(CliParser.ARGUMENT.DISABLE_MAVEN_INSTALL, Settings.KEYS.ANALYZER_MAVEN_INSTALL_ENABLED));
  537.         settings.setBoolean(Settings.KEYS.ANALYZER_PIP_ENABLED,
  538.                 !cli.isDisabled(CliParser.ARGUMENT.DISABLE_PIP, Settings.KEYS.ANALYZER_PIP_ENABLED));
  539.         settings.setBoolean(Settings.KEYS.ANALYZER_PIPFILE_ENABLED,
  540.                 !cli.isDisabled(CliParser.ARGUMENT.DISABLE_PIPFILE, Settings.KEYS.ANALYZER_PIPFILE_ENABLED));
  541.         settings.setBoolean(Settings.KEYS.ANALYZER_POETRY_ENABLED,
  542.                 !cli.isDisabled(CliParser.ARGUMENT.DISABLE_POETRY, Settings.KEYS.ANALYZER_POETRY_ENABLED));
  543.         settings.setBoolean(Settings.KEYS.ANALYZER_CMAKE_ENABLED,
  544.                 !cli.isDisabled(CliParser.ARGUMENT.DISABLE_CMAKE, Settings.KEYS.ANALYZER_CMAKE_ENABLED));
  545.         settings.setBoolean(Settings.KEYS.ANALYZER_NUSPEC_ENABLED,
  546.                 !cli.isDisabled(CliParser.ARGUMENT.DISABLE_NUSPEC, Settings.KEYS.ANALYZER_NUSPEC_ENABLED));
  547.         settings.setBoolean(Settings.KEYS.ANALYZER_NUGETCONF_ENABLED,
  548.                 !cli.isDisabled(CliParser.ARGUMENT.DISABLE_NUGETCONF, Settings.KEYS.ANALYZER_NUGETCONF_ENABLED));
  549.         settings.setBoolean(Settings.KEYS.ANALYZER_ASSEMBLY_ENABLED,
  550.                 !cli.isDisabled(CliParser.ARGUMENT.DISABLE_ASSEMBLY, Settings.KEYS.ANALYZER_ASSEMBLY_ENABLED));
  551.         settings.setBoolean(Settings.KEYS.ANALYZER_BUNDLE_AUDIT_ENABLED,
  552.                 !cli.isDisabled(CliParser.ARGUMENT.DISABLE_BUNDLE_AUDIT, Settings.KEYS.ANALYZER_BUNDLE_AUDIT_ENABLED));
  553.         settings.setBoolean(Settings.KEYS.ANALYZER_FILE_NAME_ENABLED,
  554.                 !cli.isDisabled(CliParser.ARGUMENT.DISABLE_FILENAME, Settings.KEYS.ANALYZER_FILE_NAME_ENABLED));
  555.         settings.setBoolean(Settings.KEYS.ANALYZER_MIX_AUDIT_ENABLED,
  556.                 !cli.isDisabled(CliParser.ARGUMENT.DISABLE_MIX_AUDIT, Settings.KEYS.ANALYZER_MIX_AUDIT_ENABLED));
  557.         settings.setBoolean(Settings.KEYS.ANALYZER_OPENSSL_ENABLED,
  558.                 !cli.isDisabled(CliParser.ARGUMENT.DISABLE_OPENSSL, Settings.KEYS.ANALYZER_OPENSSL_ENABLED));
  559.         settings.setBoolean(Settings.KEYS.ANALYZER_COMPOSER_LOCK_ENABLED,
  560.                 !cli.isDisabled(CliParser.ARGUMENT.DISABLE_COMPOSER, Settings.KEYS.ANALYZER_COMPOSER_LOCK_ENABLED));
  561.         settings.setBooleanIfNotNull(Settings.KEYS.ANALYZER_COMPOSER_LOCK_SKIP_DEV,
  562.                 cli.hasOption(CliParser.ARGUMENT.COMPOSER_LOCK_SKIP_DEV));
  563.         settings.setBoolean(Settings.KEYS.ANALYZER_CPANFILE_ENABLED,
  564.                 !cli.isDisabled(CliParser.ARGUMENT.DISABLE_CPAN, Settings.KEYS.ANALYZER_CPANFILE_ENABLED));
  565.         settings.setBoolean(Settings.KEYS.ANALYZER_GOLANG_DEP_ENABLED,
  566.                 !cli.isDisabled(CliParser.ARGUMENT.DISABLE_GO_DEP, Settings.KEYS.ANALYZER_GOLANG_DEP_ENABLED));
  567.         settings.setBoolean(Settings.KEYS.ANALYZER_GOLANG_MOD_ENABLED,
  568.                 !cli.isDisabled(CliParser.ARGUMENT.DISABLE_GOLANG_MOD, Settings.KEYS.ANALYZER_GOLANG_MOD_ENABLED));
  569.         settings.setBoolean(Settings.KEYS.ANALYZER_DART_ENABLED,
  570.                 !cli.isDisabled(CliParser.ARGUMENT.DISABLE_DART, Settings.KEYS.ANALYZER_DART_ENABLED));
  571.         settings.setBoolean(Settings.KEYS.ANALYZER_NODE_PACKAGE_ENABLED,
  572.                 !cli.isDisabled(CliParser.ARGUMENT.DISABLE_NODE_JS, Settings.KEYS.ANALYZER_NODE_PACKAGE_ENABLED));
  573.         settings.setBoolean(Settings.KEYS.ANALYZER_NODE_AUDIT_ENABLED,
  574.                 !cli.isNodeAuditDisabled());
  575.         settings.setBoolean(Settings.KEYS.ANALYZER_YARN_AUDIT_ENABLED,
  576.                 !cli.isYarnAuditDisabled());
  577.         settings.setBoolean(Settings.KEYS.ANALYZER_PNPM_AUDIT_ENABLED,
  578.                 !cli.isPnpmAuditDisabled());
  579.         settings.setBoolean(Settings.KEYS.ANALYZER_NODE_AUDIT_USE_CACHE,
  580.                 !cli.isDisabled(CliParser.ARGUMENT.DISABLE_NODE_AUDIT_CACHE, Settings.KEYS.ANALYZER_NODE_AUDIT_USE_CACHE));
  581.         settings.setBoolean(Settings.KEYS.ANALYZER_RETIREJS_ENABLED,
  582.                 !cli.isDisabled(CliParser.ARGUMENT.DISABLE_RETIRE_JS, Settings.KEYS.ANALYZER_RETIREJS_ENABLED));
  583.         settings.setBoolean(Settings.KEYS.ANALYZER_SWIFT_PACKAGE_MANAGER_ENABLED,
  584.                 !cli.isDisabled(CliParser.ARGUMENT.DISABLE_SWIFT, Settings.KEYS.ANALYZER_SWIFT_PACKAGE_MANAGER_ENABLED));
  585.         settings.setBoolean(Settings.KEYS.ANALYZER_SWIFT_PACKAGE_RESOLVED_ENABLED,
  586.                 !cli.isDisabled(CliParser.ARGUMENT.DISABLE_SWIFT_RESOLVED, Settings.KEYS.ANALYZER_SWIFT_PACKAGE_RESOLVED_ENABLED));
  587.         settings.setBoolean(Settings.KEYS.ANALYZER_COCOAPODS_ENABLED,
  588.                 !cli.isDisabled(CliParser.ARGUMENT.DISABLE_COCOAPODS, Settings.KEYS.ANALYZER_COCOAPODS_ENABLED));
  589.         settings.setBoolean(Settings.KEYS.ANALYZER_CARTHAGE_ENABLED,
  590.                 !cli.isDisabled(CliParser.ARGUMENT.DISABLE_CARTHAGE, Settings.KEYS.ANALYZER_CARTHAGE_ENABLED));
  591.         settings.setBoolean(Settings.KEYS.ANALYZER_RUBY_GEMSPEC_ENABLED,
  592.                 !cli.isDisabled(CliParser.ARGUMENT.DISABLE_RUBYGEMS, Settings.KEYS.ANALYZER_RUBY_GEMSPEC_ENABLED));
  593.         settings.setBoolean(Settings.KEYS.ANALYZER_CENTRAL_ENABLED,
  594.                 !cli.isDisabled(CliParser.ARGUMENT.DISABLE_CENTRAL, Settings.KEYS.ANALYZER_CENTRAL_ENABLED));
  595.         settings.setBoolean(Settings.KEYS.ANALYZER_CENTRAL_USE_CACHE,
  596.                 !cli.isDisabled(CliParser.ARGUMENT.DISABLE_CENTRAL_CACHE, Settings.KEYS.ANALYZER_CENTRAL_USE_CACHE));
  597.         settings.setBoolean(Settings.KEYS.ANALYZER_OSSINDEX_ENABLED,
  598.                 !cli.isDisabled(CliParser.ARGUMENT.DISABLE_OSSINDEX, Settings.KEYS.ANALYZER_OSSINDEX_ENABLED));
  599.         settings.setBoolean(Settings.KEYS.ANALYZER_OSSINDEX_USE_CACHE,
  600.                 !cli.isDisabled(CliParser.ARGUMENT.DISABLE_OSSINDEX_CACHE, Settings.KEYS.ANALYZER_OSSINDEX_USE_CACHE));

  601.         settings.setBooleanIfNotNull(Settings.KEYS.ANALYZER_NODE_PACKAGE_SKIPDEV,
  602.                 cli.hasOption(CliParser.ARGUMENT.NODE_PACKAGE_SKIP_DEV_DEPENDENCIES));
  603.         settings.setBooleanIfNotNull(Settings.KEYS.ANALYZER_NODE_AUDIT_SKIPDEV,
  604.                 cli.hasOption(CliParser.ARGUMENT.DISABLE_NODE_AUDIT_SKIPDEV));
  605.         settings.setBooleanIfNotNull(Settings.KEYS.ANALYZER_NEXUS_ENABLED,
  606.                 cli.hasOption(CliParser.ARGUMENT.ENABLE_NEXUS));
  607.         settings.setStringIfNotEmpty(Settings.KEYS.ANALYZER_CENTRAL_URL,
  608.                 cli.getStringArgument(CliParser.ARGUMENT.CENTRAL_URL));
  609.         settings.setStringIfNotEmpty(Settings.KEYS.ANALYZER_CENTRAL_USER,
  610.                 cli.getStringArgument(CliParser.ARGUMENT.CENTRAL_USERNAME));
  611.         settings.setStringIfNotEmpty(Settings.KEYS.ANALYZER_CENTRAL_PASSWORD,
  612.                 cli.getStringArgument(CliParser.ARGUMENT.CENTRAL_PASSWORD));
  613.         settings.setStringIfNotEmpty(Settings.KEYS.ANALYZER_CENTRAL_BEARER_TOKEN,
  614.                 cli.getStringArgument(CliParser.ARGUMENT.CENTRAL_BEARER_TOKEN));
  615.         settings.setStringIfNotEmpty(Settings.KEYS.ANALYZER_OSSINDEX_URL,
  616.                 cli.getStringArgument(CliParser.ARGUMENT.OSSINDEX_URL));
  617.         settings.setStringIfNotEmpty(Settings.KEYS.ANALYZER_OSSINDEX_USER,
  618.                 cli.getStringArgument(CliParser.ARGUMENT.OSSINDEX_USERNAME));
  619.         settings.setStringIfNotEmpty(Settings.KEYS.ANALYZER_OSSINDEX_PASSWORD,
  620.                 cli.getStringArgument(CliParser.ARGUMENT.OSSINDEX_PASSWORD, Settings.KEYS.ANALYZER_OSSINDEX_PASSWORD));
  621.         settings.setStringIfNotEmpty(Settings.KEYS.ANALYZER_OSSINDEX_WARN_ONLY_ON_REMOTE_ERRORS,
  622.                 cli.getStringArgument(CliParser.ARGUMENT.OSSINDEX_WARN_ONLY_ON_REMOTE_ERRORS,
  623.                         Settings.KEYS.ANALYZER_OSSINDEX_WARN_ONLY_ON_REMOTE_ERRORS));
  624.         settings.setFloat(Settings.KEYS.JUNIT_FAIL_ON_CVSS,
  625.                 cli.getFloatArgument(CliParser.ARGUMENT.FAIL_JUNIT_ON_CVSS, 0));
  626.         settings.setBooleanIfNotNull(Settings.KEYS.ANALYZER_ARTIFACTORY_ENABLED,
  627.                 cli.hasOption(CliParser.ARGUMENT.ARTIFACTORY_ENABLED));
  628.         settings.setBooleanIfNotNull(Settings.KEYS.ANALYZER_ARTIFACTORY_PARALLEL_ANALYSIS,
  629.                 cli.getBooleanArgument(CliParser.ARGUMENT.ARTIFACTORY_PARALLEL_ANALYSIS));
  630.         settings.setBooleanIfNotNull(Settings.KEYS.ANALYZER_ARTIFACTORY_USES_PROXY,
  631.                 cli.getBooleanArgument(CliParser.ARGUMENT.ARTIFACTORY_USES_PROXY));
  632.         settings.setStringIfNotEmpty(Settings.KEYS.ANALYZER_ARTIFACTORY_URL,
  633.                 cli.getStringArgument(CliParser.ARGUMENT.ARTIFACTORY_URL));
  634.         settings.setStringIfNotEmpty(Settings.KEYS.ANALYZER_ARTIFACTORY_API_USERNAME,
  635.                 cli.getStringArgument(CliParser.ARGUMENT.ARTIFACTORY_USERNAME));
  636.         settings.setStringIfNotEmpty(Settings.KEYS.ANALYZER_ARTIFACTORY_API_TOKEN,
  637.                 cli.getStringArgument(CliParser.ARGUMENT.ARTIFACTORY_API_TOKEN));
  638.         settings.setStringIfNotEmpty(Settings.KEYS.ANALYZER_ARTIFACTORY_BEARER_TOKEN,
  639.                 cli.getStringArgument(CliParser.ARGUMENT.ARTIFACTORY_BEARER_TOKEN));
  640.         settings.setStringIfNotEmpty(Settings.KEYS.ANALYZER_MIX_AUDIT_PATH,
  641.                 cli.getStringArgument(CliParser.ARGUMENT.PATH_TO_MIX_AUDIT));
  642.         settings.setStringIfNotEmpty(Settings.KEYS.ANALYZER_BUNDLE_AUDIT_PATH,
  643.                 cli.getStringArgument(CliParser.ARGUMENT.PATH_TO_BUNDLE_AUDIT));
  644.         settings.setStringIfNotEmpty(Settings.KEYS.ANALYZER_BUNDLE_AUDIT_WORKING_DIRECTORY,
  645.                 cli.getStringArgument(CliParser.ARGUMENT.PATH_TO_BUNDLE_AUDIT_WORKING_DIRECTORY));
  646.         settings.setStringIfNotEmpty(Settings.KEYS.ANALYZER_NEXUS_URL,
  647.                 cli.getStringArgument(CliParser.ARGUMENT.NEXUS_URL));
  648.         settings.setStringIfNotEmpty(Settings.KEYS.ANALYZER_NEXUS_USER,
  649.                 cli.getStringArgument(CliParser.ARGUMENT.NEXUS_USERNAME));
  650.         settings.setStringIfNotEmpty(Settings.KEYS.ANALYZER_NEXUS_PASSWORD,
  651.                 cli.getStringArgument(CliParser.ARGUMENT.NEXUS_PASSWORD, Settings.KEYS.ANALYZER_NEXUS_PASSWORD));
  652.         //TODO deprecate this in favor of non-proxy host
  653.         final boolean nexusUsesProxy = cli.isNexusUsesProxy();
  654.         settings.setBoolean(Settings.KEYS.ANALYZER_NEXUS_USES_PROXY, nexusUsesProxy);
  655.         settings.setStringIfNotEmpty(Settings.KEYS.DB_DRIVER_NAME,
  656.                 cli.getStringArgument(CliParser.ARGUMENT.DB_DRIVER));
  657.         settings.setStringIfNotEmpty(Settings.KEYS.DB_DRIVER_PATH,
  658.                 cli.getStringArgument(CliParser.ARGUMENT.DB_DRIVER_PATH));
  659.         settings.setStringIfNotEmpty(Settings.KEYS.DB_CONNECTION_STRING,
  660.                 cli.getStringArgument(CliParser.ARGUMENT.CONNECTION_STRING));
  661.         settings.setStringIfNotEmpty(Settings.KEYS.DB_USER,
  662.                 cli.getStringArgument(CliParser.ARGUMENT.DB_NAME));
  663.         settings.setStringIfNotEmpty(Settings.KEYS.DB_PASSWORD,
  664.                 cli.getStringArgument(CliParser.ARGUMENT.DB_PASSWORD, Settings.KEYS.DB_PASSWORD));
  665.         settings.setStringIfNotEmpty(Settings.KEYS.ADDITIONAL_ZIP_EXTENSIONS,
  666.                 cli.getStringArgument(CliParser.ARGUMENT.ADDITIONAL_ZIP_EXTENSIONS));
  667.         settings.setStringIfNotEmpty(Settings.KEYS.ANALYZER_ASSEMBLY_DOTNET_PATH,
  668.                 cli.getStringArgument(CliParser.ARGUMENT.PATH_TO_CORE));

  669.         String key = cli.getStringArgument(CliParser.ARGUMENT.NVD_API_KEY);
  670.         if (key != null) {
  671.             if ((key.startsWith("\"") && key.endsWith("\"") || (key.startsWith("'") && key.endsWith("'")))) {
  672.                 key = key.substring(1, key.length() - 1);
  673.             }
  674.             settings.setStringIfNotEmpty(Settings.KEYS.NVD_API_KEY, key);
  675.         }
  676.         settings.setStringIfNotEmpty(Settings.KEYS.NVD_API_ENDPOINT,
  677.                 cli.getStringArgument(CliParser.ARGUMENT.NVD_API_ENDPOINT));
  678.         settings.setIntIfNotNull(Settings.KEYS.NVD_API_DELAY, cli.getIntegerValue(CliParser.ARGUMENT.NVD_API_DELAY));
  679.         settings.setIntIfNotNull(Settings.KEYS.NVD_API_RESULTS_PER_PAGE, cli.getIntegerValue(CliParser.ARGUMENT.NVD_API_RESULTS_PER_PAGE));
  680.         settings.setStringIfNotEmpty(Settings.KEYS.NVD_API_DATAFEED_URL, cli.getStringArgument(CliParser.ARGUMENT.NVD_API_DATAFEED_URL));
  681.         settings.setStringIfNotEmpty(Settings.KEYS.NVD_API_DATAFEED_USER, cli.getStringArgument(CliParser.ARGUMENT.NVD_API_DATAFEED_USER));
  682.         settings.setStringIfNotEmpty(Settings.KEYS.NVD_API_DATAFEED_PASSWORD, cli.getStringArgument(CliParser.ARGUMENT.NVD_API_DATAFEED_PASSWORD));
  683.         settings.setStringIfNotEmpty(Settings.KEYS.NVD_API_DATAFEED_BEARER_TOKEN, cli.getStringArgument(CliParser.ARGUMENT.NVD_API_DATAFEED_BEARER_TOKEN));
  684.         settings.setIntIfNotNull(Settings.KEYS.NVD_API_MAX_RETRY_COUNT, cli.getIntegerValue(CliParser.ARGUMENT.NVD_API_MAX_RETRY_COUNT));
  685.         settings.setIntIfNotNull(Settings.KEYS.NVD_API_VALID_FOR_HOURS, cli.getIntegerValue(CliParser.ARGUMENT.NVD_API_VALID_FOR_HOURS));

  686.         settings.setStringIfNotNull(Settings.KEYS.HOSTED_SUPPRESSIONS_URL,
  687.                 cli.getStringArgument(CliParser.ARGUMENT.HOSTED_SUPPRESSIONS_URL));
  688.         settings.setStringIfNotNull(Settings.KEYS.HOSTED_SUPPRESSIONS_USER,
  689.                 cli.getStringArgument(CliParser.ARGUMENT.HOSTED_SUPPRESSIONS_USER));
  690.         settings.setStringIfNotNull(Settings.KEYS.HOSTED_SUPPRESSIONS_PASSWORD,
  691.                 cli.getStringArgument(CliParser.ARGUMENT.HOSTED_SUPPRESSIONS_PASSWORD));
  692.         settings.setStringIfNotNull(Settings.KEYS.HOSTED_SUPPRESSIONS_BEARER_TOKEN,
  693.                 cli.getStringArgument(CliParser.ARGUMENT.HOSTED_SUPPRESSIONS_BEARER_TOKEN));
  694.         settings.setBoolean(Settings.KEYS.HOSTED_SUPPRESSIONS_ENABLED,
  695.                 !cli.isDisabled(CliParser.ARGUMENT.DISABLE_HOSTED_SUPPRESSIONS, Settings.KEYS.HOSTED_SUPPRESSIONS_ENABLED));
  696.         settings.setBooleanIfNotNull(Settings.KEYS.HOSTED_SUPPRESSIONS_FORCEUPDATE,
  697.                 cli.hasOption(CliParser.ARGUMENT.HOSTED_SUPPRESSIONS_FORCEUPDATE));
  698.         settings.setIntIfNotNull(Settings.KEYS.HOSTED_SUPPRESSIONS_VALID_FOR_HOURS,
  699.                 cli.getIntegerValue(CliParser.ARGUMENT.HOSTED_SUPPRESSIONS_VALID_FOR_HOURS));
  700.     }

  701.     //CSON: MethodLength
  702.     /**
  703.      * Creates a file appender and adds it to logback.
  704.      *
  705.      * @param verboseLog the path to the verbose log file
  706.      */
  707.     private void prepareLogger(String verboseLog) {
  708.         final LoggerContext context = (LoggerContext) LoggerFactory.getILoggerFactory();
  709.         final PatternLayoutEncoder encoder = new PatternLayoutEncoder();
  710.         encoder.setPattern("%d %C:%L%n%-5level - %msg%n");
  711.         encoder.setContext(context);
  712.         encoder.start();
  713.         final FileAppender<ILoggingEvent> fa = new FileAppender<>();
  714.         fa.setAppend(true);
  715.         fa.setEncoder(encoder);
  716.         fa.setContext(context);
  717.         fa.setFile(verboseLog);
  718.         final File f = new File(verboseLog);
  719.         String name = f.getName();
  720.         final int i = name.lastIndexOf('.');
  721.         if (i > 1) {
  722.             name = name.substring(0, i);
  723.         }
  724.         fa.setName(name);
  725.         fa.start();
  726.         final ch.qos.logback.classic.Logger rootLogger = context.getLogger(ch.qos.logback.classic.Logger.ROOT_LOGGER_NAME);
  727.         rootLogger.setLevel(Level.DEBUG);
  728.         final ThresholdFilter filter = new ThresholdFilter();
  729.         filter.setLevel(LogLevel.INFO.getValue());
  730.         filter.setContext(context);
  731.         filter.start();
  732.         rootLogger.iteratorForAppenders().forEachRemaining(action -> action.addFilter(filter));
  733.         rootLogger.addAppender(fa);
  734.     }

  735.     /**
  736.      * Takes a path and resolves it to be a canonical &amp; absolute path. The
  737.      * caveats are that this method will take an Ant style file selector path
  738.      * (../someDir/**\/*.jar) and convert it to an absolute/canonical path (at
  739.      * least to the left of the first * or ?).
  740.      *
  741.      * @param path the path to canonicalize
  742.      * @return the canonical path
  743.      */
  744.     protected String ensureCanonicalPath(String path) {
  745.         final String basePath;
  746.         String wildCards = null;
  747.         final String file = path.replace('\\', '/');
  748.         if (file.contains("*") || file.contains("?")) {

  749.             int pos = getLastFileSeparator(file);
  750.             if (pos < 0) {
  751.                 return file;
  752.             }
  753.             pos += 1;
  754.             basePath = file.substring(0, pos);
  755.             wildCards = file.substring(pos);
  756.         } else {
  757.             basePath = file;
  758.         }

  759.         File f = new File(basePath);
  760.         try {
  761.             f = f.getCanonicalFile();
  762.             if (wildCards != null) {
  763.                 f = new File(f, wildCards);
  764.             }
  765.         } catch (IOException ex) {
  766.             LOGGER.warn("Invalid path '{}' was provided.", path);
  767.             LOGGER.debug("Invalid path provided", ex);
  768.         }
  769.         return f.getAbsolutePath().replace('\\', '/');
  770.     }

  771.     /**
  772.      * Returns the position of the last file separator.
  773.      *
  774.      * @param file a file path
  775.      * @return the position of the last file separator
  776.      */
  777.     @SuppressWarnings("ManualMinMaxCalculation")
  778.     private int getLastFileSeparator(String file) {
  779.         if (file.contains("*") || file.contains("?")) {
  780.             int p1 = file.indexOf('*');
  781.             int p2 = file.indexOf('?');
  782.             p1 = p1 > 0 ? p1 : file.length();
  783.             p2 = p2 > 0 ? p2 : file.length();
  784.             int pos = p1 < p2 ? p1 : p2;
  785.             pos = file.lastIndexOf('/', pos);
  786.             return pos;
  787.         } else {
  788.             return file.lastIndexOf('/');
  789.         }
  790.     }
  791. }