diff --git a/core/pom.xml b/core/pom.xml index ec6ab763cf..ebe8b4232c 100644 --- a/core/pom.xml +++ b/core/pom.xml @@ -100,6 +100,24 @@ Copyright (c) 2012 Jeremy Long. All Rights Reserved. + + io.github.download-maven-plugin + download-maven-plugin + + + download-published-suppressions + generate-resources + + wget + + + https://dependency-check.github.io/DependencyCheck/suppressions/publishedSuppressions.xml + ${project.build.directory}/classes + dependencycheck-hosted-suppression-snapshot.xml + + + + org.jsonschema2pojo jsonschema2pojo-maven-plugin diff --git a/core/src/main/java/org/owasp/dependencycheck/analyzer/AbstractSuppressionAnalyzer.java b/core/src/main/java/org/owasp/dependencycheck/analyzer/AbstractSuppressionAnalyzer.java index f03d2f6157..28ea42e91e 100644 --- a/core/src/main/java/org/owasp/dependencycheck/analyzer/AbstractSuppressionAnalyzer.java +++ b/core/src/main/java/org/owasp/dependencycheck/analyzer/AbstractSuppressionAnalyzer.java @@ -30,6 +30,8 @@ import java.util.Set; import java.util.regex.Pattern; import javax.annotation.concurrent.ThreadSafe; + +import org.jetbrains.annotations.NotNull; import org.owasp.dependencycheck.Engine; import org.owasp.dependencycheck.analyzer.exception.AnalysisException; import org.owasp.dependencycheck.data.update.HostedSuppressionsDataSource; @@ -68,6 +70,10 @@ public abstract class AbstractSuppressionAnalyzer extends AbstractAnalyzer { * The file name of the base suppression XML file. */ private static final String BASE_SUPPRESSION_FILE = "dependencycheck-base-suppression.xml"; + /** + * The file name of the snapshot of the hosted suppression XML file. + */ + private static final String HOSTED_SUPPRESSION_SNAPSHOT_FILE = "dependencycheck-hosted-suppression-snapshot.xml"; /** * The key used to store and retrieve the suppression files. */ @@ -188,7 +194,7 @@ private void loadSuppressionBaseData(final Engine engine) throws SuppressionPars } /** - * Loads the base suppression rules packaged with the application. + * Loads the suppression rules packaged with the application. * * @param parser The suppression parser to use * @param engine a reference the dependency-check engine @@ -196,24 +202,8 @@ private void loadSuppressionBaseData(final Engine engine) throws SuppressionPars */ private void loadPackagedSuppressionBaseData(final SuppressionParser parser, final Engine engine) throws SuppressionParseException { List ruleList = null; - final URL jarLocation = AbstractSuppressionAnalyzer.class.getProtectionDomain().getCodeSource().getLocation(); - String suppressionFileLocation = jarLocation.getFile(); - if (suppressionFileLocation.endsWith(".jar")) { - suppressionFileLocation = "jar:file:" + suppressionFileLocation + "!/" + BASE_SUPPRESSION_FILE; - } else if (suppressionFileLocation.startsWith("nested:") && suppressionFileLocation.endsWith(".jar!/")) { - // suppressionFileLocation -> nested:/app/app.jar/!BOOT-INF/lib/dependency-check-core-.jar!/ - // goal-> jar:nested:/app/app.jar/!BOOT-INF/lib/dependency-check-core-.jar!/dependencycheck-base-suppression.xml - suppressionFileLocation = "jar:" + suppressionFileLocation + BASE_SUPPRESSION_FILE; - } else { - suppressionFileLocation = "file:" + suppressionFileLocation + BASE_SUPPRESSION_FILE; - } - URL baseSuppresssionURL = null; - try { - baseSuppresssionURL = new URL(suppressionFileLocation); - } catch (MalformedURLException e) { - throw new SuppressionParseException("Unable to load the base suppression data file", e); - } - try (InputStream in = baseSuppresssionURL.openStream()) { + URL baseSuppressionURL = getPackagedFile(BASE_SUPPRESSION_FILE); + try (InputStream in = baseSuppressionURL.openStream()) { ruleList = parser.parseSuppressionRules(in); } catch (SAXException | IOException ex) { throw new SuppressionParseException("Unable to parse the base suppression data file", ex); @@ -229,6 +219,27 @@ private void loadPackagedSuppressionBaseData(final SuppressionParser parser, fin } } + private static @NotNull URL getPackagedFile(String packagedFileName) throws SuppressionParseException { + final URL jarLocation = AbstractSuppressionAnalyzer.class.getProtectionDomain().getCodeSource().getLocation(); + String suppressionFileLocation = jarLocation.getFile(); + if (suppressionFileLocation.endsWith(".jar")) { + suppressionFileLocation = "jar:file:" + suppressionFileLocation + "!/" + packagedFileName; + } else if (suppressionFileLocation.startsWith("nested:") && suppressionFileLocation.endsWith(".jar!/")) { + // suppressionFileLocation -> nested:/app/app.jar/!BOOT-INF/lib/dependency-check-core-.jar!/ + // goal-> jar:nested:/app/app.jar/!BOOT-INF/lib/dependency-check-core-.jar!/dependencycheck-base-suppression.xml + suppressionFileLocation = "jar:" + suppressionFileLocation + packagedFileName; + } else { + suppressionFileLocation = "file:" + suppressionFileLocation + packagedFileName; + } + URL baseSuppressionURL = null; + try { + baseSuppressionURL = new URL(suppressionFileLocation); + } catch (MalformedURLException e) { + throw new SuppressionParseException("Unable to load the packaged file: " + packagedFileName, e); + } + return baseSuppressionURL; + } + /** * Loads all the base suppression rules from the hosted suppression file * generated/updated automatically by the FP Suppression GitHub Action for @@ -242,31 +253,28 @@ private void loadPackagedSuppressionBaseData(final SuppressionParser parser, fin * @param parser The suppression parser to use */ private void loadHostedSuppressionBaseData(final SuppressionParser parser, final Engine engine) { - final File repoFile; - boolean repoEmpty = false; final boolean enabled = getSettings().getBoolean(Settings.KEYS.HOSTED_SUPPRESSIONS_ENABLED, true); if (!enabled) { return; } - final boolean autoupdate = getSettings().getBoolean(Settings.KEYS.AUTO_UPDATE, true); - final boolean forceupdate = getSettings().getBoolean(Settings.KEYS.HOSTED_SUPPRESSIONS_FORCEUPDATE, false); try { final String configuredUrl = getSettings().getString(Settings.KEYS.HOSTED_SUPPRESSIONS_URL, HostedSuppressionsDataSource.DEFAULT_SUPPRESSIONS_URL); final URL url = new URL(configuredUrl); final String fileName = new File(url.getPath()).getName(); - repoFile = new File(getSettings().getDataDirectory(), fileName); - if (!repoFile.isFile() || repoFile.length() <= 1L) { - repoEmpty = true; - LOGGER.warn("Hosted Suppressions file is empty or missing - attempting to force the update"); - getSettings().setBoolean(Settings.KEYS.HOSTED_SUPPRESSIONS_FORCEUPDATE, true); - } - if ((!autoupdate && forceupdate) || (autoupdate && repoEmpty)) { - if (engine == null) { - LOGGER.warn("Engine was null, this should only happen in tests - skipping forced update"); - } else { - repoEmpty = forceUpdateHostedSuppressions(engine, repoFile); + final File repoFile = new File(getSettings().getDataDirectory(), fileName); + boolean repoEmpty = !repoFile.isFile() || repoFile.length() <= 1L; + if (repoEmpty) { + // utilize the snapshot hosted suppression file + URL hostedSuppressionSnapshotURL = getPackagedFile(HOSTED_SUPPRESSION_SNAPSHOT_FILE); + try (InputStream in = hostedSuppressionSnapshotURL.openStream()) { + Files.copy(in, repoFile.toPath(), StandardCopyOption.REPLACE_EXISTING); + repoEmpty = false; + LOGGER.debug("Copied hosted suppression snapshot file to {}", repoFile.toPath()); + } catch (IOException ex) { + LOGGER.warn("Unable to copy the hosted suppression snapshot file to {}, results may contain false positives " + + "already resolved by the DependencyCheck project", repoFile.toPath(), ex); } } if (!repoEmpty) { diff --git a/pom.xml b/pom.xml index a90d331fba..0399f7d061 100644 --- a/pom.xml +++ b/pom.xml @@ -187,6 +187,11 @@ Copyright (c) 2012 - Jeremy Long clean install + + io.github.download-maven-plugin + download-maven-plugin + 2.0.0 + org.jsonschema2pojo jsonschema2pojo-maven-plugin