diff --git a/.github/workflows/false-positive-ops.yml b/.github/workflows/false-positive-ops.yml
index 2ecfa1b1068..ceb70fdfa3e 100644
--- a/.github/workflows/false-positive-ops.yml
+++ b/.github/workflows/false-positive-ops.yml
@@ -171,11 +171,11 @@ jobs:
}
purl += '@.*$';
var cpe = process.env.CPE.trim().replaceAll(/^`|`$/g,'').split(':');
- var matchCpe;
+ var cpe22UriPrefix;
if (cpe[1] == '2.3') {
- matchcpe = 'cpe:/a:' + cpe[3] + ':' + cpe[4];
+ cpe22UriPrefix = 'cpe:/a:' + cpe[3] + ':' + cpe[4] + ':';
} else {
- matchcpe = 'cpe:/a:' + cpe[2] + ':' + cpe[3];
+ cpe22UriPrefix = 'cpe:/a:' + cpe[2] + ':' + cpe[3] + ':';
}
await github.rest.issues.createComment({
@@ -189,7 +189,7 @@ jobs:
' FP per issue #' + context.issue.number + '\n' +
' ]]>\n' +
' ' + purl + '\n' +
- ' ' + matchcpe + '\n' +
+ ' ' + cpe22UriPrefix + '\n' +
'\n```\n\n' +
'Link to test results: ' + context.serverUrl + '/' + context.repo.owner + '/' + context.repo.repo + '/actions/runs/' + context.runId
})
@@ -218,11 +218,11 @@ jobs:
purl += '@.*$';
var cpe = process.env.CPE.trim().replaceAll(/^`|`$/g,'').split(':');
console.log(cpe);
- var matchCpe;
+ var cpe22UriPrefix;
if (cpe[1] == '2.3') {
- matchcpe = 'cpe:/a:' + cpe[3] + ':' + cpe[4];
+ cpe22UriPrefix = 'cpe:/a:' + cpe[3] + ':' + cpe[4] + ':';
} else {
- matchcpe = 'cpe:/a:' + cpe[2] + ':' + cpe[3];
+ cpe22UriPrefix = 'cpe:/a:' + cpe[2] + ':' + cpe[3] + ':';
}
await github.rest.issues.createComment({
@@ -236,7 +236,7 @@ jobs:
' FP per issue #' + context.issue.number + '\n' +
' ]]>\n' +
' ' + purl + '\n' +
- ' ' + matchcpe + '\n' +
+ ' ' + cpe22UriPrefix + '\n' +
'\n```\n\n' +
'Link to test results: ' + context.serverUrl + '/' + context.repo.owner + '/' + context.repo.repo + '/actions/runs/' + context.runId
})
@@ -264,11 +264,11 @@ jobs:
}
purl += '@.*$';
var cpe = process.env.CPE.trim().replaceAll(/^`|`$/g,'').split(':');
- var matchCpe;
+ var cpe22UriPrefix;
if (cpe[1] == '2.3') {
- matchcpe = 'cpe:/a:' + cpe[3] + ':' + cpe[4];
+ cpe22UriPrefix = 'cpe:/a:' + cpe[3] + ':' + cpe[4] + ':';
} else {
- matchcpe = 'cpe:/a:' + cpe[2] + ':' + cpe[3];
+ cpe22UriPrefix = 'cpe:/a:' + cpe[2] + ':' + cpe[3] + ':';
}
await github.rest.issues.createComment({
@@ -282,7 +282,7 @@ jobs:
' FP per issue #' + context.issue.number + '\n' +
' ]]>\n' +
' ' + purl + '\n' +
- ' ' + matchcpe + '\n' +
+ ' ' + cpe22UriPrefix + '\n' +
'\n```\n\n' +
'Link to test results: ' + context.serverUrl + '/' + context.repo.owner + '/' + context.repo.repo + '/actions/runs/' + context.runId
})
diff --git a/.github/workflows/publish-suppressions.yml b/.github/workflows/publish-suppressions.yml
index 87030db6127..2d5d7d2963a 100644
--- a/.github/workflows/publish-suppressions.yml
+++ b/.github/workflows/publish-suppressions.yml
@@ -2,6 +2,9 @@ name: Publish Suppressions
on:
workflow_dispatch:
+ push:
+ branches:
+ - generatedSuppressions
permissions: {}
jobs:
diff --git a/ant/src/main/java/org/owasp/dependencycheck/taskdefs/Update.java b/ant/src/main/java/org/owasp/dependencycheck/taskdefs/Update.java
index 9736dfc277e..6019a193964 100644
--- a/ant/src/main/java/org/owasp/dependencycheck/taskdefs/Update.java
+++ b/ant/src/main/java/org/owasp/dependencycheck/taskdefs/Update.java
@@ -20,12 +20,12 @@
import org.apache.tools.ant.BuildException;
import org.apache.tools.ant.Project;
import org.owasp.dependencycheck.Engine;
+import org.owasp.dependencycheck.ant.logging.AntTaskHolder;
import org.owasp.dependencycheck.data.nvdcve.DatabaseException;
import org.owasp.dependencycheck.data.update.exception.UpdateException;
import org.owasp.dependencycheck.utils.Downloader;
import org.owasp.dependencycheck.utils.InvalidSettingException;
import org.owasp.dependencycheck.utils.Settings;
-import org.owasp.dependencycheck.ant.logging.AntTaskHolder;
/**
* An Ant task definition to execute dependency-check update. This will download
@@ -203,7 +203,7 @@ public class Update extends Purge {
*/
private Boolean hostedSuppressionsForceUpdate;
/**
- * Whether the hosted suppressions file will be used. Defaults to true.
+ * Whether the hosted suppressions will be updated from the configured URL. Defaults to true.
*/
private Boolean hostedSuppressionsEnabled;
/**
diff --git a/ant/src/site/markdown/config-update.md b/ant/src/site/markdown/config-update.md
index b310bc48788..aff1d4d2519 100644
--- a/ant/src/site/markdown/config-update.md
+++ b/ant/src/site/markdown/config-update.md
@@ -50,7 +50,7 @@ The following properties can be configured in the plugin. However, they are less
| connectionString | The connection string used to connect to the database. See using a [database server](../data/database.html). | |
| databaseUser | The username used when connecting to the database. | |
| databasePassword | The password used when connecting to the database. | |
-| hostedSuppressionsEnabled | Whether the hosted suppression file will be used. | true |
+| hostedSuppressionsEnabled | Whether the hosted suppressions will be updated from the configured URL. | true |
| hostedSuppressionsUrl | The URL to a mirrored copy of the hosted suppressions file for internet-constrained environments | https://dependency-check.github.io/DependencyCheck/suppressions/publishedSuppressions.xml |
| hostedSuppressionsUser | The user for a Basic-auth-protected mirrored copy of the hosted suppressions file for internet-constrained environments | |
| hostedSuppressionsPassword | The password/token for a Basic-auth-protected mirrored copy of the hosted suppressions file for internet-constrained environments | |
diff --git a/ant/src/site/markdown/configuration.md b/ant/src/site/markdown/configuration.md
index 0556f752ad6..874214f4ec0 100644
--- a/ant/src/site/markdown/configuration.md
+++ b/ant/src/site/markdown/configuration.md
@@ -166,7 +166,7 @@ The following properties can be configured in the plugin. However, they are less
| connectionString | The connection string used to connect to the database. See using a [database server](../data/database.html). | |
| databaseUser | The username used when connecting to the database. | |
| databasePassword | The password used when connecting to the database. | |
-| hostedSuppressionsEnabled | Whether the hosted suppression file will be used. | true |
+| hostedSuppressionsEnabled | Whether the hosted suppressions will be updated from the configured URL. | true |
| hostedSuppressionsUrl | The URL to a mirrored copy of the hosted suppressions file for internet-constrained environments | https://dependency-check.github.io/DependencyCheck/suppressions/publishedSuppressions.xml |
| hostedSuppressionsUser | The user for a Basic-auth-protected mirrored copy of the hosted suppressions file for internet-constrained environments | |
| hostedSuppressionsPassword | The password/token for a Basic-auth-protected mirrored copy of the hosted suppressions file for internet-constrained environments | |
diff --git a/cli/src/main/java/org/owasp/dependencycheck/App.java b/cli/src/main/java/org/owasp/dependencycheck/App.java
index 5bccba7218c..672e74dbb24 100644
--- a/cli/src/main/java/org/owasp/dependencycheck/App.java
+++ b/cli/src/main/java/org/owasp/dependencycheck/App.java
@@ -24,6 +24,7 @@
import ch.qos.logback.classic.spi.ILoggingEvent;
import ch.qos.logback.core.FileAppender;
import org.apache.commons.cli.ParseException;
+import org.apache.commons.lang3.StringUtils;
import org.apache.tools.ant.DirectoryScanner;
import org.apache.tools.ant.types.LogLevel;
import org.owasp.dependencycheck.data.nvdcve.DatabaseException;
@@ -46,6 +47,7 @@
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
+import java.util.Optional;
import java.util.Set;
import java.util.TreeSet;
import java.util.stream.Collectors;
@@ -95,6 +97,14 @@ public static void main(String[] args) {
*/
public App() {
settings = new Settings();
+ settings.setString(Settings.KEYS.APPLICATION_NAME, determineName());
+ }
+
+ private static String determineName() {
+ return Optional.ofNullable(System.getenv("ODC_NAME"))
+ .filter(StringUtils::isNotBlank)
+ .map(n -> n.replace('/', '-').replace(' ', '_'))
+ .orElse("dependency-check-cli");
}
/**
@@ -120,11 +130,11 @@ public int run(String[] args) {
cli.parse(args);
} catch (FileNotFoundException ex) {
System.err.println(ex.getMessage());
- cli.printHelp();
+ cli.printHelp(System.out);
return 1;
} catch (ParseException ex) {
System.err.println(ex.getMessage());
- cli.printHelp();
+ cli.printHelp(System.out);
return 2;
}
final String verboseLog = cli.getStringArgument(CliParser.ARGUMENT.VERBOSE_LOG);
@@ -224,7 +234,7 @@ public int run(String[] args) {
settings.cleanup();
}
} else {
- cli.printHelp();
+ cli.printHelp(System.out);
}
return exitCode;
}
@@ -456,12 +466,6 @@ private void runUpdateOnly() throws UpdateException, DatabaseException {
* file is unable to be loaded.
*/
protected void populateSettings(CliParser cli) throws InvalidSettingException {
- String name = System.getenv("ODC_NAME") != null ? System.getenv("ODC_NAME") : "dependency-check-cli";
- if (name.isBlank()) {
- name = "dependency-check-cli";
- }
- name = name.replace("/", "-").replace(" ", "_");
- settings.setString(Settings.KEYS.APPLICATION_NAME, name);
final File propertiesFile = cli.getFileArgument(CliParser.ARGUMENT.PROP);
if (propertiesFile != null) {
try {
diff --git a/cli/src/main/java/org/owasp/dependencycheck/CliParser.java b/cli/src/main/java/org/owasp/dependencycheck/CliParser.java
index 2db9e05aa88..6260c10e040 100644
--- a/cli/src/main/java/org/owasp/dependencycheck/CliParser.java
+++ b/cli/src/main/java/org/owasp/dependencycheck/CliParser.java
@@ -21,11 +21,12 @@
import org.apache.commons.cli.CommandLine;
import org.apache.commons.cli.CommandLineParser;
import org.apache.commons.cli.DefaultParser;
-import org.apache.commons.cli.HelpFormatter;
import org.apache.commons.cli.Option;
import org.apache.commons.cli.OptionGroup;
import org.apache.commons.cli.Options;
import org.apache.commons.cli.ParseException;
+import org.apache.commons.cli.help.HelpFormatter;
+import org.apache.commons.cli.help.TextHelpAppendable;
import org.owasp.dependencycheck.reporting.ReportGenerator.Format;
import org.owasp.dependencycheck.utils.InvalidSettingException;
import org.owasp.dependencycheck.utils.Settings;
@@ -34,6 +35,9 @@
import java.io.File;
import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.UncheckedIOException;
+import java.util.Comparator;
/**
* A utility to parse command line arguments for the DependencyCheck.
@@ -65,6 +69,12 @@ public final class CliParser {
*/
private static final String SUPPORTED_FORMATS = "HTML, XML, CSV, JSON, JUNIT, SARIF, JENKINS, GITLAB or ALL";
+ private static final String HELP_MSG = String.format(
+ "Dependency-Check can be used to identify if there are any known CVE vulnerabilities in libraries " +
+ "utilized by an application. Dependency-Check will automatically update required data from the " +
+ "Internet, such as the CVE and CPE data files from nvd.nist.gov.%n"
+ );
+
/**
* Constructs a new CLI Parser object with the configured settings.
*
@@ -82,7 +92,7 @@ public CliParser(Settings settings) {
* point to a file that exists.
* @throws ParseException is thrown when a Parse Exception occurs.
*/
- public void parse(String[] args) throws FileNotFoundException, ParseException {
+ public void parse(String... args) throws FileNotFoundException, ParseException {
line = parseArgs(args);
if (line != null) {
@@ -97,7 +107,7 @@ public void parse(String[] args) throws FileNotFoundException, ParseException {
* @return the results of parsing the command line arguments
* @throws ParseException if the arguments are invalid
*/
- private CommandLine parseArgs(String[] args) throws ParseException {
+ private CommandLine parseArgs(String... args) throws ParseException {
final CommandLineParser parser = new DefaultParser();
final Options options = createCommandLineOptions();
return parser.parse(options, args);
@@ -213,7 +223,7 @@ private boolean isValidFormat(String format) {
* @param argumentName the argument being validated (e.g. scan, out, etc.)
* @return true, if path exists; false otherwise
*/
- private boolean isValidFilePath(String path, String argumentName) {
+ private boolean isValidFilePath(String path, @SuppressWarnings("SameParameterValue") String argumentName) {
try {
validatePathExists(path, argumentName);
return true;
@@ -232,7 +242,7 @@ private boolean isValidFilePath(String path, String argumentName) {
* @throws FileNotFoundException is thrown if one of the paths being
* validated does not exist.
*/
- private void validatePathExists(String[] paths, String optType) throws FileNotFoundException {
+ private void validatePathExists(String[] paths, @SuppressWarnings("SameParameterValue") String optType) throws FileNotFoundException {
for (String path : paths) {
validatePathExists(path, optType);
}
@@ -301,7 +311,6 @@ private void validatePathExists(String path, String argumentName) throws FileNot
*
* @return the command line options used for parsing the command line
*/
- @SuppressWarnings("static-access")
private Options createCommandLineOptions() {
final Options options = new Options();
addStandardOptions(options);
@@ -315,10 +324,8 @@ private Options createCommandLineOptions() {
*
* @param options a collection of command line arguments
*/
- @SuppressWarnings("static-access")
private void addStandardOptions(final Options options) {
- //This is an option group because it can be specified more then once.
-
+ //This is an option group because it can be specified more than once.
options.addOptionGroup(newOptionGroup(newOptionWithArg(ARGUMENT.SCAN_SHORT, ARGUMENT.SCAN, "path",
"The path to scan - this option can be specified multiple times. Ant style paths are supported (e.g. 'path/**/*.jar'); "
+ "if using Ant style paths it is highly recommended to quote the argument value.")))
@@ -357,7 +364,6 @@ private void addStandardOptions(final Options options) {
*
* @param options a collection of command line arguments
*/
- @SuppressWarnings("static-access")
private void addAdvancedOptions(final Options options) {
options
.addOption(newOption(ARGUMENT.UPDATE_ONLY,
@@ -445,11 +451,11 @@ private void addAdvancedOptions(final Options options) {
.addOption(newOptionWithArg(ARGUMENT.RETIREJS_URL, "url",
"The Retire JS Repository URL"))
.addOption(newOptionWithArg(ARGUMENT.RETIREJS_URL_USER, "username",
- "The password to authenticate to Retire JS Repository URL"))
+ "Credentials for basic auth towards the Retire JS Repository URL"))
.addOption(newOptionWithArg(ARGUMENT.RETIREJS_URL_PASSWORD, "password",
- "The password to authenticate to Retire JS Repository URL"))
+ "Credentials for basic auth towards the Retire JS Repository URL"))
.addOption(newOptionWithArg(ARGUMENT.RETIREJS_URL_BEARER_TOKEN, "token",
- "The password to authenticate to Retire JS Repository URL"))
+ "Token for bearer auth towards the Retire JS Repository URL"))
.addOption(newOption(ARGUMENT.RETIRE_JS_FILTER_NON_VULNERABLE, "Specifies that the Retire JS "
+ "Analyzer should filter out non-vulnerable JS files from the report."))
.addOption(newOptionWithArg(ARGUMENT.ARTIFACTORY_PARALLEL_ANALYSIS, "true/false",
@@ -547,7 +553,7 @@ private void addAdvancedOptions(final Options options) {
.addOption(newOption(ARGUMENT.ENABLE_NEXUS, "Enable the Nexus Analyzer."))
.addOption(newOption(ARGUMENT.ARTIFACTORY_ENABLED, "Whether the Artifactory Analyzer should be enabled."))
.addOption(newOption(ARGUMENT.PURGE_NVD, "Purges the local NVD data cache"))
- .addOption(newOption(ARGUMENT.DISABLE_HOSTED_SUPPRESSIONS, "Disable the usage of the hosted suppressions file"))
+ .addOption(newOption(ARGUMENT.DISABLE_HOSTED_SUPPRESSIONS, "Disable retrieval of the hosted suppressions from the configured URL."))
.addOption(newOption(ARGUMENT.HOSTED_SUPPRESSIONS_FORCEUPDATE, "Force the hosted suppressions file to update even"
+ " if autoupdate is disabled"))
.addOption(newOptionWithArg(ARGUMENT.HOSTED_SUPPRESSIONS_VALID_FOR_HOURS, "hours",
@@ -571,7 +577,6 @@ private void addAdvancedOptions(final Options options) {
*
* @param options a collection of command line arguments
*/
- @SuppressWarnings({"static-access", "deprecation"})
private void addDeprecatedOptions(final Options options) {
//not a real option - but enables java debugging via the shell script
options.addOption(newOption("debug",
@@ -784,26 +789,28 @@ public File getFileArgument(String option) {
}
/**
- * Displays the command line help message to the standard output.
+ * Appends the command line help message to the passed appendable
*/
- public void printHelp() {
- final HelpFormatter formatter = new HelpFormatter();
+ void printHelp(Appendable appendable) {
+ TextHelpAppendable helpAppendable = new TextHelpAppendable(appendable);
+ helpAppendable.setMaxWidth(100);
+ HelpFormatter formatter = HelpFormatter.builder()
+ .setShowSince(false)
+ .setComparator(Comparator.comparing(Option::getKey, String::compareToIgnoreCase))
+ .setHelpAppendable(helpAppendable)
+ .get();
+
final Options options = new Options();
addStandardOptions(options);
if (line != null && line.hasOption(ARGUMENT.ADVANCED_HELP)) {
addAdvancedOptions(options);
}
- final String helpMsg = String.format("%n%s"
- + " can be used to identify if there are any known CVE vulnerabilities in libraries utilized by an application. "
- + "%s will automatically update required data from the Internet, such as the CVE and CPE data files from nvd.nist.gov.%n%n",
- settings.getString(Settings.KEYS.APPLICATION_NAME, "DependencyCheck"),
- settings.getString(Settings.KEYS.APPLICATION_NAME, "DependencyCheck"));
- formatter.printHelp(settings.getString(Settings.KEYS.APPLICATION_NAME, "DependencyCheck"),
- helpMsg,
- options,
- "",
- true);
+ try {
+ formatter.printHelp("dependency-check", HELP_MSG, formatter.sort(options), "", true);
+ } catch (IOException e) {
+ throw new UncheckedIOException(e);
+ }
}
/**
@@ -1005,7 +1012,7 @@ public float getFloatArgument(String option, float defaultValue) {
* @return a new option
*/
private Option newOption(String name, String description) {
- return Option.builder().longOpt(name).desc(description).build();
+ return Option.builder().longOpt(name).desc(description).get();
}
/**
@@ -1017,7 +1024,7 @@ private Option newOption(String name, String description) {
* @return a new option
*/
private Option newOption(String shortName, String name, String description) {
- return Option.builder(shortName).longOpt(name).desc(description).build();
+ return Option.builder(shortName).longOpt(name).desc(description).get();
}
/**
@@ -1029,7 +1036,7 @@ private Option newOption(String shortName, String name, String description) {
* @return a new option
*/
private Option newOptionWithArg(String name, String arg, String description) {
- return Option.builder().longOpt(name).argName(arg).hasArg().desc(description).build();
+ return Option.builder().longOpt(name).argName(arg).hasArg().desc(description).get();
}
/**
@@ -1042,7 +1049,7 @@ private Option newOptionWithArg(String name, String arg, String description) {
* @return a new option
*/
private Option newOptionWithArg(String shortName, String name, String arg, String description) {
- return Option.builder(shortName).longOpt(name).argName(arg).hasArg().desc(description).build();
+ return Option.builder(shortName).longOpt(name).argName(arg).hasArg().desc(description).get();
}
/**
diff --git a/cli/src/site/markdown/arguments.md b/cli/src/site/markdown/arguments.md
index 74340343e3d..e081b4109d5 100644
--- a/cli/src/site/markdown/arguments.md
+++ b/cli/src/site/markdown/arguments.md
@@ -134,7 +134,7 @@ Advanced Options
| | \-\-dbUser | \ | The username used to connect to the database. | |
| \-d | \-\-data | \ | The location of the data directory used to store persistent data. | /usr/local/var/dependencycheck if installed through brew (→ [formula](https://github.com/Homebrew/homebrew-core/blob/master/Formula/d/dependency-check.rb#L29)). Otherwise, the data directory is created inside the install directory i.e. as a sibling to the `/bin`, `/lib` directories. |
| | \-\-purge | | Delete the local copy of the NVD. This is used to force a refresh of the data. | |
-| | \-\-disableHostedSuppressions | | Whether the usage of the hosted suppressions file will be disabled. | false |
+| | \-\-disableHostedSuppressions | | Disable retrieval of the hosted suppressions from the configured URL. | false |
| | \-\-hostedSuppressionsForceUpdate | | Whether the hosted suppressions file will update regardless of the `noupdate` argument. | false |
| | \-\-hostedSuppressionsValidForHours | \ | The number of hours to wait before checking for new updates of the hosted suppressions file | 2 |
| | \-\-hostedSuppressionsUrl | \ | The URL to a mirrored copy of the hosted suppressions file for internet-constrained environments | https://dependency-check.github.io/DependencyCheck/suppressions/publishedSuppressions.xml |
diff --git a/cli/src/test/java/org/owasp/dependencycheck/CliParserTest.java b/cli/src/test/java/org/owasp/dependencycheck/CliParserTest.java
index aba771547d2..d63337316dc 100644
--- a/cli/src/test/java/org/owasp/dependencycheck/CliParserTest.java
+++ b/cli/src/test/java/org/owasp/dependencycheck/CliParserTest.java
@@ -24,14 +24,21 @@
import java.io.File;
import java.io.FileNotFoundException;
import java.io.PrintStream;
+import java.io.StringWriter;
+import java.util.List;
import static java.nio.charset.StandardCharsets.UTF_8;
+import static java.util.stream.Collectors.toList;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.containsInRelativeOrder;
+import static org.hamcrest.Matchers.greaterThan;
+import static org.hamcrest.Matchers.matchesPattern;
+import static org.hamcrest.Matchers.startsWith;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertNull;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.assertTrue;
-import static org.junit.jupiter.api.Assertions.fail;
/**
*
@@ -47,13 +54,8 @@ class CliParserTest extends BaseTest {
@Test
void testParse() throws Exception {
- String[] args = {};
-
- ByteArrayOutputStream baos = new ByteArrayOutputStream();
- System.setOut(new PrintStream(baos, true, UTF_8));
-
CliParser instance = new CliParser(getSettings());
- instance.parse(args);
+ instance.parse();
assertFalse(instance.isGetVersion());
assertFalse(instance.isGetHelp());
@@ -160,16 +162,9 @@ void testParse_failOnCVSSValidArgument() throws Exception {
@Test
void testParse_unknown() {
- String[] args = {"-unknown"};
-
- ByteArrayOutputStream baos_out = new ByteArrayOutputStream();
- ByteArrayOutputStream baos_err = new ByteArrayOutputStream();
- System.setOut(new PrintStream(baos_out, true, UTF_8));
- System.setErr(new PrintStream(baos_err, true, UTF_8));
-
CliParser instance = new CliParser(getSettings());
- ParseException ex = assertThrows(ParseException.class, () -> instance.parse(args) ,
+ ParseException ex = assertThrows(ParseException.class, () -> instance.parse("-unknown"),
"Unrecognized option should have caused an exception");
assertTrue(ex.getMessage().contains("Unrecognized option"));
@@ -243,7 +238,6 @@ void testParse_scan_withFileExists() throws Exception {
*
*/
@Test
- @SuppressWarnings("StringSplitter")
void testParse_printVersionInfo() {
PrintStream out = System.out;
@@ -253,11 +247,7 @@ void testParse_printVersionInfo() {
CliParser instance = new CliParser(getSettings());
instance.printVersionInfo();
try {
- String text = baos.toString(UTF_8).toLowerCase();
- String[] lines = text.split(System.lineSeparator());
- assertTrue(lines.length >= 1);
- assertTrue(text.contains("version"));
- assertFalse(text.contains("unknown"));
+ assertThat(baos.toString(UTF_8), matchesPattern("(?mi)dependency-check.*version [0-9]+.*\n"));
} finally {
System.setOut(out);
}
@@ -269,28 +259,32 @@ void testParse_printVersionInfo() {
* @throws Exception thrown when an exception occurs.
*/
@Test
- @SuppressWarnings("StringSplitter")
void testParse_printHelp() throws Exception {
+ CliParser instance = new CliParser(getSettings());
+ instance.parse("-h");
+ StringWriter text = new StringWriter();
+ instance.printHelp(text);
- PrintStream out = System.out;
- ByteArrayOutputStream baos = new ByteArrayOutputStream();
- System.setOut(new PrintStream(baos, true, UTF_8));
+ List lines = text.toString().lines().collect(toList());
+ assertThat(lines, containsInRelativeOrder(startsWith(" usage: dependency-check"), startsWith(" -v, --version")));
+ assertThat(lines.size(), greaterThan(10));
+ }
+ /**
+ * Test of printHelp, of class CliParser.
+ *
+ * @throws Exception thrown when an exception occurs.
+ */
+ @Test
+ void testParse_printHelpAdvanced() throws Exception {
CliParser instance = new CliParser(getSettings());
- String[] args = {"-h"};
- instance.parse(args);
- instance.printHelp();
- args[0] = "--advancedHelp";
- instance.parse(args);
- instance.printHelp();
- try {
- String text = (baos.toString(UTF_8));
- String[] lines = text.split(System.lineSeparator());
- assertTrue(lines[0].startsWith("usage: "));
- assertTrue((lines.length > 2));
- } finally {
- System.setOut(out);
- }
+ instance.parse("--advancedHelp");
+ StringWriter text = new StringWriter();
+ instance.printHelp(text);
+
+ List lines = text.toString().lines().collect(toList());
+ assertThat(lines, containsInRelativeOrder(startsWith(" usage: dependency-check"), startsWith(" -c, --connectiontimeout"), startsWith(" -v, --version")));
+ assertThat(lines.size(), greaterThan(60));
}
/**
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 a8635751162..a9069c9eb27 100644
--- a/core/src/main/java/org/owasp/dependencycheck/analyzer/AbstractSuppressionAnalyzer.java
+++ b/core/src/main/java/org/owasp/dependencycheck/analyzer/AbstractSuppressionAnalyzer.java
@@ -17,41 +17,45 @@
*/
package org.owasp.dependencycheck.analyzer;
-import java.io.File;
-import java.io.IOException;
-import java.io.InputStream;
-import java.net.MalformedURLException;
-import java.net.URL;
-import java.nio.file.Files;
-import java.nio.file.Path;
-import java.nio.file.StandardCopyOption;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Set;
-import java.util.regex.Pattern;
-import javax.annotation.concurrent.ThreadSafe;
-
+import com.google.common.annotations.VisibleForTesting;
import org.jspecify.annotations.NonNull;
import org.owasp.dependencycheck.Engine;
import org.owasp.dependencycheck.analyzer.exception.AnalysisException;
import org.owasp.dependencycheck.data.update.HostedSuppressionsDataSource;
+import org.owasp.dependencycheck.data.update.exception.UpdateException;
import org.owasp.dependencycheck.dependency.Dependency;
import org.owasp.dependencycheck.exception.InitializationException;
import org.owasp.dependencycheck.exception.WriteLockException;
-import org.owasp.dependencycheck.utils.WriteLock;
-import org.owasp.dependencycheck.xml.suppression.SuppressionParseException;
-import org.owasp.dependencycheck.xml.suppression.SuppressionParser;
-import org.owasp.dependencycheck.xml.suppression.SuppressionRule;
import org.owasp.dependencycheck.utils.DownloadFailedException;
import org.owasp.dependencycheck.utils.Downloader;
import org.owasp.dependencycheck.utils.FileUtils;
import org.owasp.dependencycheck.utils.ResourceNotFoundException;
import org.owasp.dependencycheck.utils.Settings;
import org.owasp.dependencycheck.utils.TooManyRequestsException;
+import org.owasp.dependencycheck.utils.WriteLock;
+import org.owasp.dependencycheck.xml.suppression.SuppressionParseException;
+import org.owasp.dependencycheck.xml.suppression.SuppressionParser;
+import org.owasp.dependencycheck.xml.suppression.SuppressionRule;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.xml.sax.SAXException;
+import javax.annotation.concurrent.ThreadSafe;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.StandardCopyOption;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.regex.Pattern;
+
+import static org.owasp.dependencycheck.data.update.HostedSuppressionsDataSource.falsePositivesDueTo;
+import static org.owasp.dependencycheck.utils.FileUtils.existsWithContent;
+
/**
* Abstract base suppression analyzer that contains methods for parsing the
* suppression XML file.
@@ -78,16 +82,6 @@ public abstract class AbstractSuppressionAnalyzer extends AbstractAnalyzer {
*/
public static final String SUPPRESSION_OBJECT_KEY = "suppression.rules";
- /**
- * Returns a list of file EXTENSIONS supported by this analyzer.
- *
- * @return a list of file EXTENSIONS supported by this analyzer.
- */
- @SuppressWarnings("SameReturnValue")
- public Set getSupportedExtensions() {
- return null;
- }
-
/**
* The prepare method loads the suppression XML file.
*
@@ -102,13 +96,13 @@ public synchronized void prepareAnalyzer(Engine engine) throws InitializationExc
try {
loadSuppressionBaseData(engine);
} catch (SuppressionParseException ex) {
- throw new InitializationException("Error initializing the suppression analyzer: " + ex.getLocalizedMessage(), ex, true);
+ throw new InitializationException("Error initializing the suppression analyzer base data: " + ex, ex, true);
}
try {
- loadSuppressionData(engine);
+ loadSuppressionUserData(engine);
} catch (SuppressionParseException ex) {
- throw new InitializationException("Warn initializing the suppression analyzer: " + ex.getLocalizedMessage(), ex, false);
+ throw new InitializationException("Warn initializing the suppression analyzer user data: " + ex, ex, false);
}
}
@@ -145,12 +139,12 @@ protected void analyzeDependency(Dependency dependency, Engine engine) throws An
* @param engine a reference to the ODC engine.
* @throws SuppressionParseException thrown if the XML cannot be parsed.
*/
- private void loadSuppressionData(Engine engine) throws SuppressionParseException {
- final List ruleList = new ArrayList<>();
+ private void loadSuppressionUserData(Engine engine) throws SuppressionParseException {
final SuppressionParser parser = new SuppressionParser();
final String[] suppressionFilePaths = getSettings().getArray(Settings.KEYS.SUPPRESSION_FILE);
final List failedLoadingFiles = new ArrayList<>();
if (suppressionFilePaths != null && suppressionFilePaths.length > 0) {
+ final List ruleList = new ArrayList<>();
// Load all the suppression file paths
for (final String suppressionFilePath : suppressionFilePaths) {
try {
@@ -160,20 +154,12 @@ private void loadSuppressionData(Engine engine) throws SuppressionParseException
failedLoadingFiles.add(msg);
}
}
+ LOGGER.debug("{} user suppression rules were loaded from {} sources.", ruleList.size(), suppressionFilePaths.length - failedLoadingFiles.size());
+ appendRules(engine, ruleList);
}
- LOGGER.debug("{} suppression rules were loaded.", ruleList.size());
- if (!ruleList.isEmpty()) {
- if (engine.hasObject(SUPPRESSION_OBJECT_KEY)) {
- @SuppressWarnings("unchecked")
- final List rules = (List) engine.getObject(SUPPRESSION_OBJECT_KEY);
- rules.addAll(ruleList);
- } else {
- engine.putObject(SUPPRESSION_OBJECT_KEY, ruleList);
- }
- }
if (!failedLoadingFiles.isEmpty()) {
- LOGGER.debug("{} suppression files failed to load.", failedLoadingFiles.size());
+ LOGGER.debug("{} user suppression files failed to load.", failedLoadingFiles.size());
final StringBuilder sb = new StringBuilder();
failedLoadingFiles.forEach(sb::append);
throw new SuppressionParseException(sb.toString());
@@ -187,35 +173,27 @@ private void loadSuppressionData(Engine engine) throws SuppressionParseException
* @throws SuppressionParseException thrown if the XML cannot be parsed.
*/
private void loadSuppressionBaseData(final Engine engine) throws SuppressionParseException {
- final SuppressionParser parser = new SuppressionParser();
- loadPackagedSuppressionBaseData(parser, engine);
- loadHostedSuppressionBaseData(parser, engine);
+ loadPackagedBaseSuppressionData(engine);
+ loadHostedSuppressionBaseData(engine);
}
/**
* Loads the suppression rules packaged with the application.
*
- * @param parser The suppression parser to use
* @param engine a reference the dependency-check engine
* @throws SuppressionParseException thrown if the XML cannot be parsed.
*/
- private void loadPackagedSuppressionBaseData(final SuppressionParser parser, final Engine engine) throws SuppressionParseException {
- List ruleList = null;
+ @VisibleForTesting
+ void loadPackagedBaseSuppressionData(final Engine engine) throws SuppressionParseException {
+ List ruleList;
URL baseSuppressionURL = getPackagedFile(BASE_SUPPRESSION_FILE);
try (InputStream in = baseSuppressionURL.openStream()) {
- ruleList = parser.parseSuppressionRules(in);
+ ruleList = new SuppressionParser().parseSuppressionRules(in);
+ LOGGER.debug("{} base suppression rules were loaded.", ruleList.size());
+ appendRules(engine, ruleList);
} catch (SAXException | IOException ex) {
throw new SuppressionParseException("Unable to parse the base suppression data file", ex);
}
- if (ruleList != null && !ruleList.isEmpty()) {
- if (engine.hasObject(SUPPRESSION_OBJECT_KEY)) {
- @SuppressWarnings("unchecked")
- final List rules = (List) engine.getObject(SUPPRESSION_OBJECT_KEY);
- rules.addAll(ruleList);
- } else {
- engine.putObject(SUPPRESSION_OBJECT_KEY, ruleList);
- }
- }
}
private static @NonNull URL getPackagedFile(String packagedFileName) throws SuppressionParseException {
@@ -230,13 +208,11 @@ private void loadPackagedSuppressionBaseData(final SuppressionParser parser, fin
} else {
suppressionFileLocation = "file:" + suppressionFileLocation + packagedFileName;
}
- URL baseSuppressionURL = null;
try {
- baseSuppressionURL = new URL(suppressionFileLocation);
+ return new URL(suppressionFileLocation);
} catch (MalformedURLException e) {
throw new SuppressionParseException("Unable to load the packaged file: " + packagedFileName, e);
}
- return baseSuppressionURL;
}
/**
@@ -249,62 +225,62 @@ private void loadPackagedSuppressionBaseData(final SuppressionParser parser, fin
* already been resolved by the dependency-check project.
*
* @param engine a reference the dependency-check engine
- * @param parser The suppression parser to use
*/
- private void loadHostedSuppressionBaseData(final SuppressionParser parser, final Engine engine) {
- final boolean enabled = getSettings().getBoolean(Settings.KEYS.HOSTED_SUPPRESSIONS_ENABLED, true);
- if (!enabled) {
- return;
- }
-
+ @VisibleForTesting
+ void loadHostedSuppressionBaseData(final Engine engine) {
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();
- if (fileName.isBlank()) {
- throw new IOException("Hosted Suppression URL must imply a filename");
- }
- final File repoFile = new File(getSettings().getDataDirectory(), fileName);
- boolean repoEmpty = !repoFile.isFile() || repoFile.length() <= 1L;
- if (repoEmpty) {
- // utilize the snapshot hosted suppression file
+ // Try remote update if enabled and stale or forced by user
+ File repoFile = tryRemoteHostedSuppressionsFetchIfConfigured(engine);
+
+ // If still empty after update attempt; utilize the snapshot hosted suppression file
+ //
+ // Note that this local fallback will run regardless of whether hosted suppressions are "enabled" or the
+ // value of autoUpdate, forceupdate etc since this is an offline operation similar to regular "base" suppressions.
+ if (!existsWithContent(repoFile)) {
+ LOGGER.debug("Hosted suppressions not found locally; attempting fallback to store packaged snapshot from this Dependency-Check release at {}...", repoFile.toPath());
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);
}
+ LOGGER.info(falsePositivesDueTo("Hosted suppressions using snapshot as of this Dependency-Check release"));
}
- if (!repoEmpty) {
- loadCachedHostedSuppressionsRules(parser, repoFile, engine);
- } else {
- LOGGER.warn("Empty Hosted Suppression file after update, results may contain false positives "
- + "already resolved by the DependencyCheck project due to failed download of the hosted suppression file");
- }
+
+ loadCachedHostedSuppressionsRules(repoFile, engine);
+
} catch (IOException | InitializationException ex) {
- LOGGER.warn("Unable to load hosted suppressions", ex);
+ LOGGER.warn(falsePositivesDueTo("Unable to load hosted suppressions from either remote source or packaged snapshot"), ex);
}
}
+ /**
+ * If configured to do so, try fetching hosted suppressions from the configured remote source.
+ * @return The local cached repoFile the suppressions are to be loaded from. Note that on return this may still not be created.
+ * @throws IOException only if settings are invalid to handle hosted suppressions either remotely or locally
+ */
+ private File tryRemoteHostedSuppressionsFetchIfConfigured(Engine engine) throws IOException {
+ HostedSuppressionsDataSource ds = new HostedSuppressionsDataSource();
+ try {
+ ds.updateUnhandled(engine);
+ } catch (UpdateException ex) {
+ LOGGER.warn(falsePositivesDueTo("Failed to update hosted suppressions file from remote source"), ex);
+ }
+ return ds.validatedRepoFile();
+ }
+
/**
* Load the hosted suppression file from the web resource
*
- * @param parser The suppressionParser to use for loading
* @param repoFile The cached web resource
* @param engine a reference the dependency-check engine
*
* @throws InitializationException When errors occur trying to create a
* defensive copy of the web resource before loading
*/
- private void loadCachedHostedSuppressionsRules(final SuppressionParser parser, final File repoFile, final Engine engine)
+ private void loadCachedHostedSuppressionsRules(final File repoFile, final Engine engine)
throws InitializationException {
// take a defensive copy to avoid a risk of corrupted file by a competing parallel new download.
final Path defensiveCopy;
- try (WriteLock lock = new WriteLock(getSettings(), true, repoFile.getName() + ".lock")) {
+ try (WriteLock ignored = new WriteLock(getSettings(), true, repoFile.getName() + ".lock")) {
defensiveCopy = Files.createTempFile("dc-basesuppressions", ".xml");
LOGGER.debug("copying hosted suppressions file {} to {}", repoFile.toPath(), defensiveCopy);
Files.copy(repoFile.toPath(), defensiveCopy, StandardCopyOption.REPLACE_EXISTING);
@@ -314,19 +290,12 @@ private void loadCachedHostedSuppressionsRules(final SuppressionParser parser, f
try (InputStream in = Files.newInputStream(defensiveCopy)) {
final List ruleList;
- ruleList = parser.parseSuppressionRules(in);
- if (!ruleList.isEmpty()) {
- if (engine.hasObject(SUPPRESSION_OBJECT_KEY)) {
- @SuppressWarnings("unchecked")
- final List rules = (List) engine.getObject(SUPPRESSION_OBJECT_KEY);
- rules.addAll(ruleList);
- } else {
- engine.putObject(SUPPRESSION_OBJECT_KEY, ruleList);
- }
- }
+ ruleList = new SuppressionParser().parseSuppressionRules(in);
+ LOGGER.debug("{} hosted suppression rules were loaded.", ruleList.size());
+ appendRules(engine, ruleList);
+
} catch (SAXException | IOException ex) {
- LOGGER.warn("Unable to parse the hosted suppressions data file, results may contain false positives already resolved "
- + "by the DependencyCheck project", ex);
+ LOGGER.warn(falsePositivesDueTo("Unable to parse the hosted suppressions data file at {}"), repoFile.getPath(), ex);
}
try {
Files.delete(defensiveCopy);
@@ -335,6 +304,18 @@ private void loadCachedHostedSuppressionsRules(final SuppressionParser parser, f
}
}
+ private void appendRules(Engine engine, List ruleList) {
+ if (!ruleList.isEmpty()) {
+ if (engine.hasObject(SUPPRESSION_OBJECT_KEY)) {
+ @SuppressWarnings("unchecked")
+ final List rules = (List) engine.getObject(SUPPRESSION_OBJECT_KEY);
+ rules.addAll(ruleList);
+ } else {
+ engine.putObject(SUPPRESSION_OBJECT_KEY, ruleList);
+ }
+ }
+ }
+
/**
* Load a single suppression rules file from the path provided using the
* parser provided.
@@ -367,20 +348,20 @@ private List loadSuppressionFile(final SuppressionParser parser
Downloader.getInstance().fetchFile(url, file, true, Settings.KEYS.SUPPRESSION_FILE_USER,
Settings.KEYS.SUPPRESSION_FILE_PASSWORD, Settings.KEYS.SUPPRESSION_FILE_BEARER_TOKEN);
} catch (TooManyRequestsException ex1) {
- throw new SuppressionParseException("Unable to download supression file `" + file
+ throw new SuppressionParseException("Unable to download suppression file `" + file
+ "`; received 429 - too many requests", ex1);
} catch (ResourceNotFoundException ex1) {
- throw new SuppressionParseException("Unable to download supression file `" + file
+ throw new SuppressionParseException("Unable to download suppression file `" + file
+ "`; received 404 - resource not found", ex1);
} catch (InterruptedException ex1) {
Thread.currentThread().interrupt();
- throw new SuppressionParseException("Unable to download supression file `" + file + "`", ex1);
+ throw new SuppressionParseException("Unable to download suppression file `" + file + "`", ex1);
}
} catch (TooManyRequestsException ex) {
- throw new SuppressionParseException("Unable to download supression file `" + file
+ throw new SuppressionParseException("Unable to download suppression file `" + file
+ "`; received 429 - too many requests", ex);
} catch (ResourceNotFoundException ex) {
- throw new SuppressionParseException("Unable to download supression file `" + file + "`; received 404 - resource not found", ex);
+ throw new SuppressionParseException("Unable to download suppression file `" + file + "`; received 404 - resource not found", ex);
}
} else {
file = new File(suppressionFilePath);
@@ -435,7 +416,7 @@ private List loadSuppressionFile(final SuppressionParser parser
* SuppressionParseException
*/
private void throwSuppressionParseException(String message, Exception exception, String suppressionFilePath) throws SuppressionParseException {
- LOGGER.warn(String.format(message + " '%s'", suppressionFilePath));
+ LOGGER.warn("{} [{}]", message, suppressionFilePath);
LOGGER.debug("", exception);
throw new SuppressionParseException(message, exception);
}
diff --git a/core/src/main/java/org/owasp/dependencycheck/analyzer/LibmanAnalyzer.java b/core/src/main/java/org/owasp/dependencycheck/analyzer/LibmanAnalyzer.java
index 8013e704239..1c946194494 100644
--- a/core/src/main/java/org/owasp/dependencycheck/analyzer/LibmanAnalyzer.java
+++ b/core/src/main/java/org/owasp/dependencycheck/analyzer/LibmanAnalyzer.java
@@ -47,6 +47,8 @@
import java.util.regex.Matcher;
import java.util.regex.Pattern;
+import static org.owasp.dependencycheck.utils.FileUtils.existsWithContent;
+
/**
* Analyzer which parses a libman.json file to gather module information.
*
@@ -161,7 +163,7 @@ public void analyzeDependency(Dependency dependency, Engine engine) throws Analy
final File dependencyFile = dependency.getActualFile();
- if (!dependencyFile.isFile() || dependencyFile.length() == 0) {
+ if (!existsWithContent(dependencyFile)) {
return;
}
diff --git a/core/src/main/java/org/owasp/dependencycheck/analyzer/NodeAuditAnalyzer.java b/core/src/main/java/org/owasp/dependencycheck/analyzer/NodeAuditAnalyzer.java
index c6de926ed56..51307bbf5ac 100644
--- a/core/src/main/java/org/owasp/dependencycheck/analyzer/NodeAuditAnalyzer.java
+++ b/core/src/main/java/org/owasp/dependencycheck/analyzer/NodeAuditAnalyzer.java
@@ -45,6 +45,8 @@
import java.nio.file.Files;
import java.util.List;
+import static org.owasp.dependencycheck.utils.FileUtils.existsWithContent;
+
/**
* Used to analyze Node Package Manager (npm) package-lock.json and
* npm-shrinkwrap.json files via NPM Audit API.
@@ -135,7 +137,7 @@ protected void analyzeDependency(Dependency dependency, Engine engine) throws An
LOGGER.debug("Skipping {} because shrinkwrap lock file exists", dependency.getFilePath());
return;
}
- if (!packageLock.isFile() || packageLock.length() == 0 || !shouldProcess(packageLock)) {
+ if (!existsWithContent(packageLock) || !shouldProcess(packageLock)) {
return;
}
final File packageJson = new File(packageLock.getParentFile(), "package.json");
diff --git a/core/src/main/java/org/owasp/dependencycheck/analyzer/NodePackageAnalyzer.java b/core/src/main/java/org/owasp/dependencycheck/analyzer/NodePackageAnalyzer.java
index 5b29f43e5e3..7c5da572d00 100644
--- a/core/src/main/java/org/owasp/dependencycheck/analyzer/NodePackageAnalyzer.java
+++ b/core/src/main/java/org/owasp/dependencycheck/analyzer/NodePackageAnalyzer.java
@@ -54,6 +54,8 @@
import java.util.Map;
import java.util.Objects;
+import static org.owasp.dependencycheck.utils.FileUtils.existsWithContent;
+
/**
* Used to analyze Node Package Manager (npm) package.json files, and collect
* information that can be used to determine the associated CPE.
@@ -223,7 +225,7 @@ private boolean noLockFileExists(File dependencyFile) {
@Override
protected void analyzeDependency(Dependency dependency, Engine engine) throws AnalysisException {
final File dependencyFile = dependency.getActualFile();
- if (!dependencyFile.isFile() || dependencyFile.length() == 0 || !shouldProcess(dependencyFile)) {
+ if (!existsWithContent(dependencyFile) || !shouldProcess(dependencyFile)) {
return;
}
if (isNodeAuditEnabled(engine)
diff --git a/core/src/main/java/org/owasp/dependencycheck/analyzer/PinnedMavenInstallAnalyzer.java b/core/src/main/java/org/owasp/dependencycheck/analyzer/PinnedMavenInstallAnalyzer.java
index 0be4239329f..cc156eba679 100644
--- a/core/src/main/java/org/owasp/dependencycheck/analyzer/PinnedMavenInstallAnalyzer.java
+++ b/core/src/main/java/org/owasp/dependencycheck/analyzer/PinnedMavenInstallAnalyzer.java
@@ -25,8 +25,6 @@
import com.github.packageurl.MalformedPackageURLException;
import com.github.packageurl.PackageURL;
import com.github.packageurl.PackageURLBuilder;
-import java.util.Map;
-import java.util.stream.Collectors;
import org.owasp.dependencycheck.Engine;
import org.owasp.dependencycheck.analyzer.exception.AnalysisException;
import org.owasp.dependencycheck.data.nvd.ecosystem.Ecosystem;
@@ -45,8 +43,12 @@
import java.io.IOException;
import java.util.Collections;
import java.util.List;
+import java.util.Map;
import java.util.Objects;
import java.util.regex.Pattern;
+import java.util.stream.Collectors;
+
+import static org.owasp.dependencycheck.utils.FileUtils.existsWithContent;
/**
* Used to analyze Maven pinned dependency files named {@code *install*.json}, a
@@ -116,7 +118,7 @@ protected void analyzeDependency(Dependency dependency, Engine engine) throws An
LOGGER.debug("Checking file {}", dependency.getActualFilePath());
final File dependencyFile = dependency.getActualFile();
- if (!dependencyFile.isFile() || dependencyFile.length() == 0) {
+ if (!existsWithContent(dependencyFile)) {
return;
}
diff --git a/core/src/main/java/org/owasp/dependencycheck/analyzer/PipAnalyzer.java b/core/src/main/java/org/owasp/dependencycheck/analyzer/PipAnalyzer.java
index e4ceb68bf25..bf7b88e8f7f 100644
--- a/core/src/main/java/org/owasp/dependencycheck/analyzer/PipAnalyzer.java
+++ b/core/src/main/java/org/owasp/dependencycheck/analyzer/PipAnalyzer.java
@@ -44,6 +44,8 @@
import java.util.regex.Pattern;
import java.util.stream.Collectors;
+import static org.owasp.dependencycheck.utils.FileUtils.existsWithContent;
+
/**
* Used to analyze pip dependency files named requirements.txt.
*
@@ -131,7 +133,7 @@ protected void analyzeDependency(Dependency dependency, Engine engine) throws An
engine.removeDependency(dependency);
}
final File dependencyFile = dependency.getActualFile();
- if (!dependencyFile.isFile() || dependencyFile.length() == 0) {
+ if (!existsWithContent(dependencyFile)) {
return;
}
diff --git a/core/src/main/java/org/owasp/dependencycheck/analyzer/PipfileAnalyzer.java b/core/src/main/java/org/owasp/dependencycheck/analyzer/PipfileAnalyzer.java
index bb5c66fc75e..318bc003ebe 100644
--- a/core/src/main/java/org/owasp/dependencycheck/analyzer/PipfileAnalyzer.java
+++ b/core/src/main/java/org/owasp/dependencycheck/analyzer/PipfileAnalyzer.java
@@ -43,6 +43,8 @@
import java.util.regex.Matcher;
import java.util.regex.Pattern;
+import static org.owasp.dependencycheck.utils.FileUtils.existsWithContent;
+
/**
* Used to analyze dependencies defined in Pipfile. This analyzer works in
* tandem with the `PipfilelockAnalyzer` - and both analyzers use the same key
@@ -141,7 +143,7 @@ protected void analyzeDependency(Dependency dependency, Engine engine) throws An
}
final File dependencyFile = dependency.getActualFile();
- if (!dependencyFile.isFile() || dependencyFile.length() == 0) {
+ if (!existsWithContent(dependencyFile)) {
return;
}
diff --git a/core/src/main/java/org/owasp/dependencycheck/analyzer/PipfilelockAnalyzer.java b/core/src/main/java/org/owasp/dependencycheck/analyzer/PipfilelockAnalyzer.java
index d2a3f8f4719..993c2b302d9 100644
--- a/core/src/main/java/org/owasp/dependencycheck/analyzer/PipfilelockAnalyzer.java
+++ b/core/src/main/java/org/owasp/dependencycheck/analyzer/PipfilelockAnalyzer.java
@@ -50,6 +50,8 @@
import java.nio.file.Files;
import java.util.Set;
+import static org.owasp.dependencycheck.utils.FileUtils.existsWithContent;
+
/**
* Used to analyze dependencies defined in Pipfile.lock. This analyzer works in
* tandem with the `PipfileAnalyzer` - and both analyzers use the same key to
@@ -134,7 +136,7 @@ protected void analyzeDependency(Dependency dependency, Engine engine) throws An
engine.removeDependency(dependency);
final File dependencyFile = dependency.getActualFile();
- if (!dependencyFile.isFile() || dependencyFile.length() == 0) {
+ if (!existsWithContent(dependencyFile)) {
return;
}
diff --git a/core/src/main/java/org/owasp/dependencycheck/analyzer/PnpmAuditAnalyzer.java b/core/src/main/java/org/owasp/dependencycheck/analyzer/PnpmAuditAnalyzer.java
index a9a88c78835..ac42f445006 100644
--- a/core/src/main/java/org/owasp/dependencycheck/analyzer/PnpmAuditAnalyzer.java
+++ b/core/src/main/java/org/owasp/dependencycheck/analyzer/PnpmAuditAnalyzer.java
@@ -47,6 +47,8 @@
import java.util.ArrayList;
import java.util.List;
+import static org.owasp.dependencycheck.utils.FileUtils.existsWithContent;
+
@ThreadSafe
public class PnpmAuditAnalyzer extends AbstractNpmAnalyzer {
@@ -90,7 +92,7 @@ protected void analyzeDependency(Dependency dependency, Engine engine) throws An
engine.removeDependency(dependency);
}
final File packageLock = dependency.getActualFile();
- if (!packageLock.isFile() || packageLock.length() == 0 || !shouldProcess(packageLock)) {
+ if (!existsWithContent(packageLock) || !shouldProcess(packageLock)) {
return;
}
final List advisories;
diff --git a/core/src/main/java/org/owasp/dependencycheck/analyzer/RetireJsAnalyzer.java b/core/src/main/java/org/owasp/dependencycheck/analyzer/RetireJsAnalyzer.java
index af9319a4c4d..d73fd3e7201 100644
--- a/core/src/main/java/org/owasp/dependencycheck/analyzer/RetireJsAnalyzer.java
+++ b/core/src/main/java/org/owasp/dependencycheck/analyzer/RetireJsAnalyzer.java
@@ -20,10 +20,12 @@
import com.esotericsoftware.minlog.Log;
import com.github.packageurl.MalformedPackageURLException;
import com.github.packageurl.PackageURLBuilder;
+import com.google.common.annotations.VisibleForTesting;
import com.h3xstream.retirejs.repo.JsLibraryResult;
import com.h3xstream.retirejs.repo.ScannerFacade;
import com.h3xstream.retirejs.repo.VulnerabilitiesRepository;
import com.h3xstream.retirejs.repo.VulnerabilitiesRepositoryLoader;
+import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.validator.routines.UrlValidator;
import org.json.JSONException;
@@ -58,19 +60,18 @@
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
-import java.net.URL;
import java.nio.file.Files;
+import java.nio.file.StandardCopyOption;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
+import java.util.OptionalInt;
import java.util.Set;
import java.util.stream.Collectors;
-import org.apache.commons.io.IOUtils;
-
import static org.owasp.dependencycheck.analyzer.RetireJsLibrary.KnownIdentifierTypes.CVE;
import static org.owasp.dependencycheck.analyzer.RetireJsLibrary.KnownIdentifierTypes.GITHUB_SECURITY_ADVISORY;
import static org.owasp.dependencycheck.analyzer.RetireJsLibrary.KnownIdentifierTypes.SECONDARY_NAME_TYPES;
@@ -193,40 +194,13 @@ protected void prepareFileTypeAnalyzer(Engine engine) throws InitializationExcep
// it aligns with other analyzers that don't log such information.
Log.set(Log.LEVEL_WARN);
- File repoFile = null;
- boolean repoEmpty = false;
- try {
- final String configuredUrl = getSettings().getString(Settings.KEYS.ANALYZER_RETIREJS_REPO_JS_URL, RetireJSDataSource.DEFAULT_JS_URL);
- final URL url = new URL(configuredUrl);
- final File filepath = new File(url.getPath());
- repoFile = new File(getSettings().getDataDirectory(), filepath.getName());
- if (!repoFile.isFile() || repoFile.length() <= 1L) {
- LOGGER.warn("Retire JS repository is empty or missing - attempting to force the update");
- repoEmpty = true;
- getSettings().setBoolean(Settings.KEYS.ANALYZER_RETIREJS_FORCEUPDATE, true);
- }
- } catch (IOException ex) {
- this.setEnabled(false);
- throw new InitializationException("Failed to initialize the RetireJS", ex);
- }
+ File repoFile = tryRemoteFetchIfConfigured(engine);
- final boolean autoupdate = getSettings().getBoolean(Settings.KEYS.AUTO_UPDATE, true);
- final boolean forceupdate = getSettings().getBoolean(Settings.KEYS.ANALYZER_RETIREJS_FORCEUPDATE, false);
- if ((!autoupdate && forceupdate) || (autoupdate && repoEmpty)) {
- final RetireJSDataSource ds = new RetireJSDataSource();
- try {
- ds.update(engine);
- } catch (UpdateException ex) {
- throw new InitializationException("Unable to initialize the Retire JS repository", ex);
- }
- }
-
- //several users are reporting that the retire js repository is getting corrupted.
try (WriteLock ignored = new WriteLock(getSettings(), true, repoFile.getName() + ".lock")) {
final File temp = getSettings().getTempDirectory();
final File tempRepo = new File(temp, repoFile.getName());
- LOGGER.debug("copying retireJs repo {} to {}", repoFile.toPath(), tempRepo.toPath());
- Files.copy(repoFile.toPath(), tempRepo.toPath());
+ LOGGER.debug("copying RetireJS repo {} to {}", repoFile.toPath(), tempRepo.toPath());
+ Files.copy(repoFile.toPath(), tempRepo.toPath(), StandardCopyOption.REPLACE_EXISTING);
repoFile = tempRepo;
} catch (WriteLockException | IOException ex) {
this.setEnabled(false);
@@ -245,6 +219,17 @@ protected void prepareFileTypeAnalyzer(Engine engine) throws InitializationExcep
}
}
+ private File tryRemoteFetchIfConfigured(Engine engine) throws InitializationException {
+ RetireJSDataSource ds = new RetireJSDataSource();
+ try {
+ ds.update(engine);
+ return ds.validatedRepoFile();
+ } catch (UpdateException ex) {
+ this.setEnabled(false);
+ throw new InitializationException("Failed to initialize the RetireJS repo", ex);
+ }
+ }
+
/**
* Returns the name of the analyzer.
*
@@ -324,6 +309,12 @@ public void analyzeDependency(Dependency dependency, Engine engine) throws Analy
protected void closeAnalyzer() throws Exception {
Log.set(Log.LEVEL_INFO);
}
+
+ @SuppressWarnings("SameParameterValue")
+ @VisibleForTesting
+ OptionalInt knownLibraryCountFor(String fileName) {
+ return jsRepository == null ? OptionalInt.empty() : OptionalInt.of(jsRepository.findByFilename(fileName).size());
+ }
}
class RetireJsLibrary {
diff --git a/core/src/main/java/org/owasp/dependencycheck/analyzer/YarnAuditAnalyzer.java b/core/src/main/java/org/owasp/dependencycheck/analyzer/YarnAuditAnalyzer.java
index 8a17a1077b4..a8a9f8d94fe 100644
--- a/core/src/main/java/org/owasp/dependencycheck/analyzer/YarnAuditAnalyzer.java
+++ b/core/src/main/java/org/owasp/dependencycheck/analyzer/YarnAuditAnalyzer.java
@@ -41,12 +41,11 @@
import org.slf4j.LoggerFactory;
import us.springett.parsers.cpe.exceptions.CpeValidationException;
+import javax.annotation.concurrent.ThreadSafe;
import jakarta.json.Json;
import jakarta.json.JsonException;
import jakarta.json.JsonObject;
import jakarta.json.JsonReader;
-
-import javax.annotation.concurrent.ThreadSafe;
import java.io.File;
import java.io.FileFilter;
import java.io.IOException;
@@ -57,6 +56,8 @@
import java.util.List;
import java.util.stream.Stream;
+import static org.owasp.dependencycheck.utils.FileUtils.existsWithContent;
+
@ThreadSafe
public class YarnAuditAnalyzer extends AbstractNpmAnalyzer {
@@ -233,7 +234,7 @@ protected void analyzeDependency(Dependency dependency, Engine engine) throws An
engine.removeDependency(dependency);
}
final File packageLock = dependency.getActualFile();
- if (!packageLock.isFile() || packageLock.length() == 0 || !shouldProcess(packageLock)) {
+ if (!existsWithContent(packageLock) || !shouldProcess(packageLock)) {
return;
}
File dependencyDirectory = getDependencyDirectory(packageLock);
diff --git a/core/src/main/java/org/owasp/dependencycheck/data/update/HostedSuppressionsDataSource.java b/core/src/main/java/org/owasp/dependencycheck/data/update/HostedSuppressionsDataSource.java
index 09d7627b7b2..70c9d94f8a9 100644
--- a/core/src/main/java/org/owasp/dependencycheck/data/update/HostedSuppressionsDataSource.java
+++ b/core/src/main/java/org/owasp/dependencycheck/data/update/HostedSuppressionsDataSource.java
@@ -17,10 +17,12 @@
*/
package org.owasp.dependencycheck.data.update;
+import org.jspecify.annotations.NonNull;
import org.owasp.dependencycheck.Engine;
import org.owasp.dependencycheck.data.update.exception.UpdateException;
import org.owasp.dependencycheck.exception.WriteLockException;
import org.owasp.dependencycheck.utils.Downloader;
+import org.owasp.dependencycheck.utils.InvalidSettingException;
import org.owasp.dependencycheck.utils.ResourceNotFoundException;
import org.owasp.dependencycheck.utils.Settings;
import org.owasp.dependencycheck.utils.TooManyRequestsException;
@@ -33,8 +35,13 @@
import java.net.MalformedURLException;
import java.net.URL;
import java.nio.file.Files;
+import java.time.Duration;
public class HostedSuppressionsDataSource extends LocalDataSource {
+ /**
+ * The default URL to the Hosted Suppressions file.
+ */
+ public static final String DEFAULT_SUPPRESSIONS_URL = "https://dependency-check.github.io/DependencyCheck/suppressions/publishedSuppressions.xml";
/**
* Static logger.
@@ -45,81 +52,89 @@ public class HostedSuppressionsDataSource extends LocalDataSource {
* The configured settings.
*/
private Settings settings;
- /**
- * The default URL to the Hosted Suppressions file.
- */
- public static final String DEFAULT_SUPPRESSIONS_URL = "https://dependency-check.github.io/DependencyCheck/suppressions/publishedSuppressions.xml";
/**
- * Downloads the current Hosted suppressions file.
+ * Makes a best effort to download the current Hosted suppressions file if configured to do so.
*
* @param engine a reference to the ODC Engine
* @return returns false as no updates are made to the database, just web
* resources cached locally
- * @throws UpdateException thrown if the update encountered fatal errors
+ * @throws UpdateException thrown only if the update encountered fatal configuration errors
*/
@Override
public boolean update(Engine engine) throws UpdateException {
- this.settings = engine.getSettings();
- final String configuredUrl = settings.getString(Settings.KEYS.HOSTED_SUPPRESSIONS_URL, DEFAULT_SUPPRESSIONS_URL);
- final boolean autoupdate = settings.getBoolean(Settings.KEYS.AUTO_UPDATE, true);
- final boolean forceupdate = settings.getBoolean(Settings.KEYS.HOSTED_SUPPRESSIONS_FORCEUPDATE, false);
- final boolean cpeSuppressionEnabled = settings.getBoolean(Settings.KEYS.ANALYZER_CPE_SUPPRESSION_ENABLED, true);
- final boolean vulnSuppressionEnabled = settings.getBoolean(Settings.KEYS.ANALYZER_VULNERABILITY_SUPPRESSION_ENABLED, true);
- boolean enabled = settings.getBoolean(Settings.KEYS.HOSTED_SUPPRESSIONS_ENABLED, true);
- enabled = enabled && (cpeSuppressionEnabled || vulnSuppressionEnabled);
try {
- final URL url = new URL(configuredUrl);
- final File filepath = new File(url.getPath());
- final File repoFile = new File(settings.getDataDirectory(), filepath.getName());
- final boolean proceed = enabled && (forceupdate || (autoupdate && shouldUpdate(repoFile)));
- if (proceed) {
- LOGGER.debug("Begin Hosted Suppressions file update");
- fetchHostedSuppressions(settings, url, repoFile);
- saveLastUpdated(repoFile, System.currentTimeMillis() / 1000);
- }
+ updateUnhandled(engine);
} catch (UpdateException ex) {
// only emit a warning, DependencyCheck will continue without taking the latest hosted suppressions into account.
- LOGGER.warn("Failed to update hosted suppressions file, results may contain false positives already resolved by the "
- + "DependencyCheck project", ex);
- } catch (MalformedURLException ex) {
- throw new UpdateException(String.format("Invalid URL for Hosted Suppressions file (%s)", configuredUrl), ex);
+ LOGGER.warn(falsePositivesDueTo("Failed to update hosted suppressions file from remote source"), ex);
} catch (IOException ex) {
- throw new UpdateException("Unable to get the data directory", ex);
+ // Unhandled IOExceptions are fatal configuration errors of a sort
+ throw new UpdateException("Unable to determine the local location to cache hosted suppressions", ex);
}
return false;
}
+ public static @NonNull String falsePositivesDueTo(String reason) {
+ return reason + ", results may contain false positives already resolved by the DependencyCheck project";
+ }
+
/**
- * Determines if the we should update the Hosted Suppressions file.
+ * Updates the current Hosted Suppressions file if configured to do so; failing if it cannot be done
*
- * @param repo the Hosted Suppressions file.
- * @return true if an update to the Hosted Suppressions file
- * should be performed; otherwise false
- * @throws NumberFormatException thrown if an invalid value is contained in
- * the database properties
+ * @param engine a reference to the ODC Engine
+ * @throws IOException if there is an error determining the local location to cache hosted suppressions
+ * @throws UpdateException if the remote update failed for any reason
*/
- protected boolean shouldUpdate(File repo) throws NumberFormatException {
- boolean proceed = true;
- if (repo != null && repo.isFile()) {
- final int validForHours = settings.getInt(Settings.KEYS.HOSTED_SUPPRESSIONS_VALID_FOR_HOURS, 2);
- final long lastUpdatedOn = getLastUpdated(repo);
- final long now = System.currentTimeMillis();
- LOGGER.debug("Last updated: {}", lastUpdatedOn);
- LOGGER.debug("Now: {}", now);
- final long msValid = validForHours * 60L * 60L * 1000L;
- proceed = (now - lastUpdatedOn) > msValid;
- if (!proceed) {
- LOGGER.info("Skipping Hosted Suppressions file update since last update was within {} hours.", validForHours);
- }
+ public void updateUnhandled(Engine engine) throws IOException, UpdateException {
+ this.settings = engine.getSettings();
+ final URL url = validatedUrl();
+ final File repoFile = validatedRepoFileFrom(url);
+
+ if (isEnabled() && shouldUpdateFromRemote(repoFile)) {
+ LOGGER.debug("Begin Hosted Suppressions file update from remote source");
+ fetchHostedSuppressions(url, repoFile);
+ saveLastUpdated(repoFile);
}
- return proceed;
+ }
+
+ private @NonNull URL validatedUrl() throws InvalidSettingException {
+ final String configuredUrl = settings.getString(Settings.KEYS.HOSTED_SUPPRESSIONS_URL, DEFAULT_SUPPRESSIONS_URL);
+ try {
+ return new URL(configuredUrl);
+ } catch (MalformedURLException ex) {
+ throw new InvalidSettingException(String.format("Invalid URL for Hosted Suppressions file (%s)", configuredUrl), ex);
+ }
+ }
+
+ public @NonNull File validatedRepoFile() throws IOException {
+ return validatedRepoFileFrom(validatedUrl());
+ }
+
+ private @NonNull File validatedRepoFileFrom(URL url) throws IOException {
+ String fileName = new File(url.getPath()).getName();
+ if (fileName.isBlank()) {
+ throw new InvalidSettingException("Hosted Suppression URL must imply a filename; even if disabled.");
+ }
+ return new File(settings.getDataDirectory(), fileName);
+ }
+
+ private boolean isEnabled() {
+ return settings.getBoolean(Settings.KEYS.HOSTED_SUPPRESSIONS_ENABLED, true) && (
+ settings.getBoolean(Settings.KEYS.ANALYZER_CPE_SUPPRESSION_ENABLED, true) ||
+ settings.getBoolean(Settings.KEYS.ANALYZER_VULNERABILITY_SUPPRESSION_ENABLED, true));
+ }
+
+ private boolean shouldUpdateFromRemote(File repoFile) {
+ boolean forceupdate = settings.getBoolean(Settings.KEYS.HOSTED_SUPPRESSIONS_FORCEUPDATE, false);
+ boolean autoupdate = settings.getBoolean(Settings.KEYS.AUTO_UPDATE, true);
+ Duration validFor = Duration.ofHours(settings.getInt(Settings.KEYS.HOSTED_SUPPRESSIONS_VALID_FOR_HOURS, 2));
+ return forceupdate || (autoupdate && isStale(repoFile, validFor));
}
/**
* Fetches the hosted suppressions file
*
- * @param settings a reference to the dependency-check settings
* @param repoUrl the URL to the hosted suppressions file to use
* @param repoFile the local file where the hosted suppressions file is to
* be placed
@@ -127,7 +142,7 @@ protected boolean shouldUpdate(File repo) throws NumberFormatException {
* initialization
*/
@SuppressWarnings("try")
- private void fetchHostedSuppressions(Settings settings, URL repoUrl, File repoFile) throws UpdateException {
+ private void fetchHostedSuppressions(URL repoUrl, File repoFile) throws UpdateException {
try (WriteLock ignored = new WriteLock(settings, true, repoFile.getName() + ".lock")) {
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("Hosted Suppressions URL: {}", repoUrl.toExternalForm());
@@ -144,17 +159,14 @@ public boolean purge(Engine engine) {
this.settings = engine.getSettings();
boolean result = true;
try {
- final URL repoUrl = new URL(settings.getString(Settings.KEYS.HOSTED_SUPPRESSIONS_URL,
- DEFAULT_SUPPRESSIONS_URL));
- final String filename = new File(repoUrl.getPath()).getName();
- final File repo = new File(settings.getDataDirectory(), filename);
+ final File repo = validatedRepoFile();
if (repo.exists()) {
- try (WriteLock ignored = new WriteLock(settings, true, filename + ".lock")) {
+ try (WriteLock ignored = new WriteLock(settings, true, repo.getName() + ".lock")) {
result = deleteCachedFile(repo);
}
}
} catch (WriteLockException | IOException ex) {
- LOGGER.error("Unable to delete the Hosted suppression file - invalid configuration");
+ LOGGER.error("Unable to delete the Hosted suppression file - invalid configuration: {}", ex.toString());
result = false;
}
return result;
@@ -163,8 +175,9 @@ public boolean purge(Engine engine) {
private boolean deleteCachedFile(final File repo) {
boolean deleted = true;
try {
- Files.delete(repo.toPath());
- LOGGER.info("Hosted suppression file removed successfully");
+ if (Files.deleteIfExists(repo.toPath())) {
+ LOGGER.info("Hosted suppression file removed successfully");
+ }
} catch (IOException ex) {
LOGGER.error("Unable to delete '{}'; please delete the file manually", repo.getAbsolutePath(), ex);
deleted = false;
diff --git a/core/src/main/java/org/owasp/dependencycheck/data/update/LocalDataSource.java b/core/src/main/java/org/owasp/dependencycheck/data/update/LocalDataSource.java
index 88d51840668..78c8a24dc83 100644
--- a/core/src/main/java/org/owasp/dependencycheck/data/update/LocalDataSource.java
+++ b/core/src/main/java/org/owasp/dependencycheck/data/update/LocalDataSource.java
@@ -17,15 +17,21 @@
*/
package org.owasp.dependencycheck.data.update;
+import org.jspecify.annotations.NonNull;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
+import java.time.Duration;
+import java.time.Instant;
import java.util.Properties;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
+
+import static org.owasp.dependencycheck.utils.FileUtils.existsWithContent;
/**
*
@@ -39,16 +45,15 @@ public abstract class LocalDataSource implements CachedWebDataSource {
private static final Logger LOGGER = LoggerFactory.getLogger(LocalDataSource.class);
/**
- * Saves the timestamp in a properties file next to the provided repo file
+ * Saves the timestamp in a properties file adjacent to the provided repo file
*
* @param repo the local file data source
- * @param timestamp the epoch timestamp to store
*/
- protected void saveLastUpdated(File repo, long timestamp) {
+ protected void saveLastUpdated(@NonNull File repo) {
final File timestampFile = new File(repo + ".properties");
try (OutputStream out = new FileOutputStream(timestampFile)) {
final Properties prop = new Properties();
- prop.setProperty("LAST_UPDATED", String.valueOf(timestamp));
+ prop.setProperty("LAST_UPDATED", String.valueOf(System.currentTimeMillis()));
prop.store(out, null);
} catch (IOException ex) {
throw new RuntimeException(ex);
@@ -60,24 +65,46 @@ protected void saveLastUpdated(File repo, long timestamp) {
* next to the repo file).
*
* @param repo the local file data source
- * @return the epoch timestamp of the last updated date/time
+ * @return the instant of the last updated date/time
*/
- protected long getLastUpdated(File repo) {
+ protected Instant getLastUpdated(@NonNull File repo) {
long lastUpdatedOn = 0;
final File timestampFile = new File(repo + ".properties");
if (timestampFile.isFile()) {
try (InputStream is = new FileInputStream(timestampFile)) {
final Properties props = new Properties();
props.load(is);
- lastUpdatedOn = Integer.parseInt(props.getProperty("LAST_UPDATED", "0"));
+ lastUpdatedOn = Long.parseLong(props.getProperty("LAST_UPDATED", "0"));
} catch (IOException | NumberFormatException ex) {
LOGGER.debug("error reading timestamp file", ex);
}
if (lastUpdatedOn <= 0) {
- //fall back on conversion from file last modified to storing in the db.
+ //fall back on conversion from file last modified
lastUpdatedOn = repo.lastModified();
}
}
- return lastUpdatedOn;
+ return Instant.ofEpochMilli(lastUpdatedOn);
+ }
+
+ /**
+ * Determines if we should update the local data source.
+ *
+ * @param repo the local file data source
+ * @param validFor the duration for which the local data source should be considered valid
+ * @return true if an update to the data source should be performed; otherwise false.
+ * If the repo does not exist, or is an empty file, it is considered stale.
+ */
+ protected boolean isStale(@NonNull File repo, @NonNull Duration validFor) {
+ boolean stale = true;
+ if (existsWithContent(repo)) {
+ final Instant lastUpdatedOn = getLastUpdated(repo);
+ final Instant now = Instant.now();
+ LOGGER.debug("{} last updated: {}, now: {}", getClass().getSimpleName(), lastUpdatedOn, now);
+ stale = lastUpdatedOn.plus(validFor).isBefore(now);
+ if (!stale) {
+ LOGGER.info("Should skip {} update since last update was within period {}.", getClass().getSimpleName(), validFor);
+ }
+ }
+ return stale;
}
}
diff --git a/core/src/main/java/org/owasp/dependencycheck/data/update/RetireJSDataSource.java b/core/src/main/java/org/owasp/dependencycheck/data/update/RetireJSDataSource.java
index 7dcbf994b0d..74280d08224 100644
--- a/core/src/main/java/org/owasp/dependencycheck/data/update/RetireJSDataSource.java
+++ b/core/src/main/java/org/owasp/dependencycheck/data/update/RetireJSDataSource.java
@@ -17,16 +17,12 @@
*/
package org.owasp.dependencycheck.data.update;
-import java.io.File;
-import java.io.IOException;
-import java.net.MalformedURLException;
-import java.net.URL;
-import javax.annotation.concurrent.ThreadSafe;
-
+import org.jspecify.annotations.NonNull;
import org.owasp.dependencycheck.Engine;
import org.owasp.dependencycheck.data.update.exception.UpdateException;
import org.owasp.dependencycheck.exception.WriteLockException;
import org.owasp.dependencycheck.utils.Downloader;
+import org.owasp.dependencycheck.utils.InvalidSettingException;
import org.owasp.dependencycheck.utils.ResourceNotFoundException;
import org.owasp.dependencycheck.utils.Settings;
import org.owasp.dependencycheck.utils.TooManyRequestsException;
@@ -34,6 +30,15 @@
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import javax.annotation.concurrent.ThreadSafe;
+import java.io.File;
+import java.io.IOException;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.time.Duration;
+
+import static org.owasp.dependencycheck.utils.FileUtils.existsWithContent;
+
/**
* Downloads a local copy of the RetireJS repository.
*
@@ -41,23 +46,18 @@
*/
@ThreadSafe
public class RetireJSDataSource extends LocalDataSource {
-
/**
- * Static logger.
+ * The default URL to the RetireJS JavaScript repository.
*/
- private static final Logger LOGGER = LoggerFactory.getLogger(RetireJSDataSource.class);
+ private static final String DEFAULT_JS_URL = "https://raw.githubusercontent.com/Retirejs/retire.js/master/repository/jsrepository.json";
/**
- * The property key indicating when the last update occurred.
+ * Static logger.
*/
- public static final String RETIREJS_UPDATED_ON = "RetireJSUpdatedOn";
+ private static final Logger LOGGER = LoggerFactory.getLogger(RetireJSDataSource.class);
/**
* The configured settings.
*/
private Settings settings;
- /**
- * The default URL to the RetireJS JavaScript repository.
- */
- public static final String DEFAULT_JS_URL = "https://raw.githubusercontent.com/Retirejs/retire.js/master/repository/jsrepository.json";
/**
* Constructs a new engine version check utility.
@@ -75,54 +75,51 @@ public RetireJSDataSource() {
@Override
public boolean update(Engine engine) throws UpdateException {
this.settings = engine.getSettings();
+ final URL url = validatedUrl();
+ final File repoFile = validatedRepoFileFrom(url);
+ if (isEnabled() && shouldUpdateFromRemote(repoFile)) {
+ LOGGER.debug("Begin RetireJS Update");
+ initializeRetireJsRepo(settings, url, repoFile);
+ saveLastUpdated(repoFile);
+ }
+ return false;
+ }
+
+ private @NonNull URL validatedUrl() throws UpdateException {
final String configuredUrl = settings.getString(Settings.KEYS.ANALYZER_RETIREJS_REPO_JS_URL, DEFAULT_JS_URL);
- final boolean autoupdate = settings.getBoolean(Settings.KEYS.AUTO_UPDATE, true);
- final boolean forceupdate = settings.getBoolean(Settings.KEYS.ANALYZER_RETIREJS_FORCEUPDATE, false);
- final boolean enabled = settings.getBoolean(Settings.KEYS.ANALYZER_RETIREJS_ENABLED, true);
try {
- final URL url = new URL(configuredUrl);
- final File filepath = new File(url.getPath());
- final File repoFile = new File(settings.getDataDirectory(), filepath.getName());
- final boolean proceed = enabled && (forceupdate || (autoupdate && shouldUpdate(repoFile)));
- if (proceed) {
- LOGGER.debug("Begin RetireJS Update");
- initializeRetireJsRepo(settings, url, repoFile);
- saveLastUpdated(repoFile, System.currentTimeMillis() / 1000);
- }
+ return new URL(configuredUrl);
} catch (MalformedURLException ex) {
throw new UpdateException(String.format("Invalid URL for RetireJS repository (%s)", configuredUrl), ex);
- } catch (IOException ex) {
- throw new UpdateException("Unable to get the data directory", ex);
}
- return false;
}
- /**
- * Determines if the we should update the RetireJS database.
- *
- * @param repo the retire JS repository.
- * @return true if an updated to the RetireJS database should
- * be performed; otherwise false
- * @throws NumberFormatException thrown if an invalid value is contained in
- * the database properties
- */
- protected boolean shouldUpdate(File repo) throws NumberFormatException {
- boolean proceed = true;
- if (repo != null && repo.isFile()) {
- final int validForHours = settings.getInt(Settings.KEYS.ANALYZER_RETIREJS_REPO_VALID_FOR_HOURS, 0);
- final long lastUpdatedOn = getLastUpdated(repo);
- final long now = System.currentTimeMillis();
- LOGGER.debug("Last updated: {}", lastUpdatedOn);
- LOGGER.debug("Now: {}", now);
- final long msValid = validForHours * 60L * 60L * 1000L;
- proceed = (now - lastUpdatedOn) > msValid;
- if (!proceed) {
- LOGGER.info("Skipping RetireJS update since last update was within {} hours.", validForHours);
+ public @NonNull File validatedRepoFile() throws UpdateException {
+ return validatedRepoFileFrom(validatedUrl());
+ }
+
+ private @NonNull File validatedRepoFileFrom(URL url) throws UpdateException {
+ try {
+ String fileName = new File(url.getPath()).getName();
+ if (fileName.isBlank()) {
+ throw new InvalidSettingException("RetireJS URL must imply a filename.");
}
+ return new File(settings.getDataDirectory(), fileName);
+ } catch (IOException ex) {
+ throw new UpdateException("Unable to determine the local location to cache RetireJS repo", ex);
}
- return proceed;
}
+ private boolean isEnabled() {
+ return settings.getBoolean(Settings.KEYS.ANALYZER_RETIREJS_ENABLED, true);
+ }
+
+ private boolean shouldUpdateFromRemote(File repoFile) {
+ boolean forceupdate = settings.getBoolean(Settings.KEYS.ANALYZER_RETIREJS_FORCEUPDATE, false);
+ boolean autoupdate = settings.getBoolean(Settings.KEYS.AUTO_UPDATE, true);
+ Duration validFor = Duration.ofHours(settings.getInt(Settings.KEYS.ANALYZER_RETIREJS_REPO_VALID_FOR_HOURS, 24));
+ return forceupdate || !existsWithContent(repoFile) || (autoupdate && isStale(repoFile, validFor));
+ }
/**
* Initializes the local RetireJS repository
@@ -130,8 +127,7 @@ protected boolean shouldUpdate(File repo) throws NumberFormatException {
* @param settings a reference to the dependency-check settings
* @param repoUrl the URL to the RetireJS repository to use
* @param repoFile the filename to use for the RetireJS repository
- * @throws UpdateException thrown if there is an exception during
- * initialization
+ * @throws UpdateException thrown if there is an exception during initialization
*/
@SuppressWarnings("try")
private void initializeRetireJsRepo(Settings settings, URL repoUrl, File repoFile) throws UpdateException {
diff --git a/core/src/main/resources/dependencycheck-base-suppression.xml b/core/src/main/resources/dependencycheck-base-suppression.xml
index 5fb964bc377..01d0a2b944b 100644
--- a/core/src/main/resources/dependencycheck-base-suppression.xml
+++ b/core/src/main/resources/dependencycheck-base-suppression.xml
@@ -8,14 +8,14 @@
obvious fp - currently not returning any CVEs
]]>
^pkg:maven/commons\-cli/commons\-cli@.*$
- cpe:/a:spirit-project:spirit
+ cpe:/a:spirit-project:spirit:
^pkg:maven/javax\.xml\.bind/jaxb\-api@.*$
- cpe:/a:oracle:java_se
+ cpe:/a:oracle:java_se:
^pkg:maven/javax\.ws\.rs/javax\.ws\.rs\-api@.*$
- cpe:/a:oracle:web_services
+ cpe:/a:oracle:web_services:
^pkg:maven/org\.sonarsource\.scanner\.gradle/sonarqube-gradle-plugin@.*$
- cpe:/a:sonarsource:sonarqube
+ cpe:/a:sonarsource:sonarqube:
^pkg:maven/io\.quarkus/quarkus\-fs\-util@.*$
- cpe:/a:quarkus:quarkus
+ cpe:/a:quarkus:quarkus:
^pkg:maven/org\.apache\.james/apache\-mime4j\-storage@.*$
cpe:/a:storage(_project)?:storage.*
- cpe:/a:apache:james
+ cpe:/a:apache:james:
^pkg:maven/io\.quarkus/quarkus\-hibernate\-orm.*$
- cpe:/a:hibernate:hibernate_orm
+ cpe:/a:hibernate:hibernate_orm:
^pkg:maven/io\.quarkus/quarkus\-hibernate\-validator@.*$
- cpe:/a:redhat:hibernate_validator
+ cpe:/a:redhat:hibernate_validator:
.*unicode.*$
- cpe:/a:unicode:unicode
+ cpe:/a:unicode:unicode:
^pkg:maven/com\.typesafe\.akka/akka\-stream\-contrib_2\.13@.*$
- cpe:/a:akka:akka
+ cpe:/a:akka:akka:
^pkg:maven/org\.zalando/spring\-boot\-etcd@.*$
- cpe:/a:etcd:etcd
-
-
-
- ^pkg:maven/com\.salesforce\.servicelibs/reactive\-grpc.*$
- cpe:/a:grpc:grpc
+ cpe:/a:etcd:etcd:
^pkg:maven/org\.apache\.geronimo\.config/geronimo\-config\-impl@.*$
- cpe:/a:apache:geronimo
+ cpe:/a:apache:geronimo:
^pkg:maven/io\.reactivex/rxjava@.*$
- cpe:/a:travis-ci:travis_ci
+ cpe:/a:travis-ci:travis_ci:
^pkg:maven/org\.seleniumhq\.selenium/selenium\-chromium\-driver@.*$
- cpe:/a:chromium:chromium
+ cpe:/a:chromium:chromium:
cpe:/a:chromium(_project)?:chromium.*
@@ -136,7 +129,7 @@
FP per #3572
]]>
^pkg:maven/org\.spark\-project\.spark/unused@.*$
- cpe:/a:apache:spark
+ cpe:/a:apache:spark:
^pkg:swift/swift\-log@.*$
- cpe:/a:apple:swift
+ cpe:/a:apple:swift:
^io\.awspring\.cloud:spring-cloud-.*$
- cpe:/a:pivotal_software:spring_framework
- cpe:/a:pivotal_software:spring_framework
+ cpe:/a:pivotal_software:spring_framework:
+ cpe:/a:pivotal_software:spring_framework:
cpe:/a:context(_project)?:context.*
@@ -181,68 +174,60 @@
]]>
^pkg:maven/io\.github\.x\-stream/mxparser@.*$
cpe:/a:xstream(_project)?:xstream.*
- cpe:/a:oracle:jdk
+ cpe:/a:oracle:jdk:
^pkg:maven/io\.pivotal\.cfenv/java\-cfenv\-boot\-pivotal\-scs@.*$
- cpe:/a:pivotal_software:spring_boot
- cpe:/a:pivotal_software:spring_framework
+ cpe:/a:pivotal_software:spring_boot:
+ cpe:/a:pivotal_software:spring_framework:
^pkg:maven/org\.seleniumhq\.selenium/selenium\-opera\-driver@.*$
- cpe:/a:opera:opera
- cpe:/a:opera_software:opera
+ cpe:/a:opera:opera:
+ cpe:/a:opera_software:opera:
^pkg:(generic|nuget)/(ProcessSnapshotCleanup|QTAgent.{0,10}|QTDCAgent|QTDCAgent32|TDEnvCleanup|UiaComWrapper|VSTestVideoRecorder|VisualStudioDatastoreConfigurationProvider|msdia140typelib_clr0200)@.*$
- cpe:/a:microsoft:visual_studio
+ cpe:/a:microsoft:visual_studio:
^pkg:(generic|nuget)/(Microsoft\.)?(IntelliTrace|TestPlatform|VisualStudio\.).*$
- cpe:/a:microsoft:visual_studio
- cpe:/a:microsoft:ie
+ cpe:/a:microsoft:visual_studio:
+ cpe:/a:microsoft:ie:
.*\.TestTools\..*\.dll
- cpe:/a:microsoft:visual_studio
- cpe:/a:microsoft:ie
+ cpe:/a:microsoft:visual_studio:
+ cpe:/a:microsoft:ie:
^pkg:(generic|nuget)/Microsoft\.Dia.*$
- cpe:/a:dia:dia
+ cpe:/a:dia:dia:
^pkg:maven/io\.helidon\.microprofile\.server/helidon\-microprofile\-server@.*$
- cpe:/a:oracle:http_server
-
-
-
- ^pkg:maven/co\.elastic\.apm/apm\-.*$
- cpe:/a:grpc:grpc
- cpe:/a:apache:httpclient
+ cpe:/a:oracle:http_server:
^pkg:maven/io\.r2dbc/r2dbc\-postgresql@.*$
- cpe:/a:postgresql:postgresql
+ cpe:/a:postgresql:postgresql:
^pkg:maven/.*vertx-pg-client@.*$
- cpe:/a:postgresql:postgresql
-
-
-
- ^pkg:maven/io\.opencensus/opencensus\-contrib\-grpc\-metrics@.*$
- cpe:/a:grpc:grpc
-
-
- https://nvd.nist.gov/vuln/search#/nvd/home?sortOrder=1&sortDirection=1&cpeFilterMode=applicability&cpeName=cpe:2.3:a:grpc:grpc:*:*:*:*:*:*:*:*&resultType=records
- ]]>
- ^pkg:maven/io\.grpc/grpc\-.*$
- CVE-2017-7860
- CVE-2017-7861
- CVE-2017-8359
- CVE-2017-9431
- CVE-2020-7768
- CVE-2023-1428
- CVE-2023-32731
- CVE-2023-32732
- CVE-2023-33953
- CVE-2023-4785
- CVE-2024-11407
- CVE-2024-7246
-
-
-
- ^pkg:maven/com\.google\.api\.grpc/grpc\-google\-common\-protos@.*$
- cpe:/a:grpc:grpc
-
-
-
- ^pkg:maven/com\.lightstep\.tracer/.*$
- cpe:/a:grpc:grpc
+ cpe:/a:postgresql:postgresql:
^pkg:maven/com\.google\.http\-client/google\-http\-client@.*$
- cpe:/a:apache:httpclient
+ cpe:/a:apache:httpclient:
^pkg:maven/org\.mybatis/mybatis\-spring@.*$
- cpe:/a:mybatis:mybatis
+ cpe:/a:mybatis:mybatis:
^pkg:(generic|nuget)/Microsoft\.IdentityModel\.Protocols\.OpenIdConnect@.*$
- cpe:/a:microsoft:identitymodel
- cpe:/a:openid:openid
- cpe:/a:openid:openid_connect
+ cpe:/a:microsoft:identitymodel:
+ cpe:/a:openid:openid:
+ cpe:/a:openid:openid_connect:
^pkg:composer/[^/]+/[^/]+@.*$
- cpe:/a:php:php
+ cpe:/a:php:php:
^pkg:composer/symfony/(polyfill-|ux-|panther|webpack-encore-bundle|mercure@|mercure-bundle|monolog-bundle).*$
- cpe:/a:sensiolabs:symfony
+ cpe:/a:sensiolabs:symfony:
^pkg:composer/symfony/.*(contracts|-pack)@.*$
- cpe:/a:sensiolabs:symfony
+ cpe:/a:sensiolabs:symfony:
^pkg:composer/(?!pimcore/pimcore@).*$
- cpe:/a:pimcore:pimcore
+ cpe:/a:pimcore:pimcore:
^pkg:composer/(?!pear/pear@|pear/pear-core-minimal@).*$
- cpe:/a:pear:pear
+ cpe:/a:pear:pear:
^pkg:composer/(?!laravel/framework@|laravel/laravel@).*$
- cpe:/a:laravel:laravel
- cpe:/a:laravel:framework
+ cpe:/a:laravel:laravel:
+ cpe:/a:laravel:framework:
^pkg:composer/(?!drupal/services@).*$
- cpe:/a:services_project:services
+ cpe:/a:services_project:services:
^pkg:composer/(?!doctrine/orm@).*$
- cpe:/a:doctrine-project:doctrine
+ cpe:/a:doctrine-project:doctrine:
^pkg:maven/org\.jboss\.resteasy/resteasy\-spring\-boot\-starter@.*$
- cpe:/a:redhat:resteasy
+ cpe:/a:redhat:resteasy:
^pkg:maven/com\.github\.docker\-java/docker\-java.*$
- cpe:/a:docker:docker
+ cpe:/a:docker:docker:
^pkg:maven/io\.micrometer/micrometer\-core@.*$
- cpe:/a:vmware:ace
- cpe:/a:vmware:vmware_ace
+ cpe:/a:vmware:ace:
+ cpe:/a:vmware:vmware_ace:
^pkg:maven/ch\.qos\.logback\.contrib/.*$
- cpe:/a:logback:logback
- cpe:/a:qos:logback
+ cpe:/a:logback:logback:
+ cpe:/a:qos:logback:
^pkg:maven/be\.sysa\.log\-sanitizer/log\-sanitizer\-logback@.*$
- cpe:/a:logback:logback
- cpe:/a:qos:logback
+ cpe:/a:logback:logback:
+ cpe:/a:qos:logback:
^pkg:maven/org\.graalvm.*$
- cpe:/a:oracle:openjdk
- cpe:/a:sun:openjdk
+ cpe:/a:oracle:openjdk:
+ cpe:/a:sun:openjdk:
^pkg:maven/org\.graalvm\..*$
- cpe:/a:oracle:graalvm
+ cpe:/a:oracle:graalvm:
^pkg:maven/org\.graalvm/graal\-sdk@.*$
- cpe:/a:oracle:graalvm
+ cpe:/a:oracle:graalvm:
^pkg:maven/org\.graalvm/launcher\-common@.*$
- cpe:/a:oracle:graalvm
+ cpe:/a:oracle:graalvm:
^pkg:maven/org\.graalvm/polyglot\-tck@.*$
- cpe:/a:oracle:graalvm
+ cpe:/a:oracle:graalvm:
^pkg:maven/org\.netbeans\.external/.*$
- cpe:/a:apache:netbeans
+ cpe:/a:apache:netbeans:
^pkg:maven/com\.itextpdf\.tool/xfa\-.*$
- cpe:/a:itextpdf:itext
+ cpe:/a:itextpdf:itext:
^pkg:maven/com\.itextpdf/xfa\-.*$
- cpe:/a:itextpdf:itext
+ cpe:/a:itextpdf:itext:
^pkg:maven/com\.itextpdf/typography@.*$
- cpe:/a:itextpdf:itext
+ cpe:/a:itextpdf:itext:
^pkg:maven/com\.itextpdf/itext\-licensekey\-volume@.*$
- cpe:/a:itextpdf:itext
+ cpe:/a:itextpdf:itext:
^pkg:maven/org\.testcontainers/postgresql@.*$
- cpe:/a:postgresql:postgresql
+ cpe:/a:postgresql:postgresql:
^pkg:maven/org\.msgpack/msgpack@.*$
- cpe:/a:messagepack:messagepack
+ cpe:/a:messagepack:messagepack:
^pkg:maven/io\.dropwizard\.logback/logback\-throttling\-appender@.*$
- cpe:/a:logback:logback
- cpe:/a:qos:logback
+ cpe:/a:logback:logback:
+ cpe:/a:qos:logback:
.*EntityFramework\.SqlServer*\.dll
- cpe:/a:microsoft:server:6.0.0.0
- cpe:/a:microsoft:sql_server:6.0
+ cpe:/a:microsoft:server:6.0.0.0:
+ cpe:/a:microsoft:sql_server:6.0:
^pkg:maven/org\.bouncycastle.*$
- cpe:/a:oracle:jdk
+ cpe:/a:oracle:jdk:
.*spring-security-[^\\/]*\.jar$
- cpe:/a:mod_security:mod_security
- cpe:/a:springsource:spring_framework
- cpe:/a:vmware:springsource_spring_framework
- cpe:/a:pivotal:spring_framework
- cpe:/a:pivotal_software:spring_framework
+ cpe:/a:mod_security:mod_security:
+ cpe:/a:springsource:spring_framework:
+ cpe:/a:vmware:springsource_spring_framework:
+ cpe:/a:pivotal:spring_framework:
+ cpe:/a:pivotal_software:spring_framework:
com\.thoughtworks\.xstream:xstream:.*
- cpe:/a:springsource:spring_framework
+ cpe:/a:springsource:spring_framework:
org\.apache\.velocity:velocity-tools:.*
- cpe:/a:apache:struts
+ cpe:/a:apache:struts:
cpe:/a:json-jwt_project:json-jwt is a ruby lib #1791
- 39. cpe:/a:zip_project:zip is an etherium related project #1788
- 40. cpe:/a:echo_project:echo is a php media wiki project #1786
- 41. cpe:/a:util-linux_project:util-linux c util on linux #2069
- 42. cpe:/a:bitmap_project:bitmap is a C library #1961
- 43. cpe:/a:security-framework_project:security-framework is a rust library
- 44. cpe:/a:next:next is NeXT system.
- 45. cpe:/a:property_pro:property_pro is classic ASP
+ 38. cpe:/a:json-jwt_project:json-jwt: is a ruby lib #1791
+ 39. cpe:/a:zip_project:zip: is an etherium related project #1788
+ 40. cpe:/a:echo_project:echo: is a php media wiki project #1786
+ 41. cpe:/a:util-linux_project:util-linux: c util on linux #2069
+ 42. cpe:/a:bitmap_project:bitmap: is a C library #1961
+ 43. cpe:/a:security-framework_project:security-framework: is a rust library
+ 44. cpe:/a:next:next: is NeXT system.
+ 45. cpe:/a:property_pro:property_pro: is classic ASP
46. CVE-2020-10663 is a ruby vulnerability
47. Facebook is not a dependency
48. gitlab is not a depenency #2567 and is built using ruby
@@ -654,41 +598,41 @@
65. cpe:/a:web_project:web is a Web Server library in Go
]]>
.*(\.(dll|jar|ear|war|pom|nupkg|nuspec|aar)|pom\.xml|package.json|packages.config)$
- cpe:/a:sandbox:sandbox
- cpe:/a:openmedia:openmedia
- cpe:/a:file_project:file
- cpe:/a:file:file
- cpe:/a:shim:shim
+ cpe:/a:sandbox:sandbox:
+ cpe:/a:openmedia:openmedia:
+ cpe:/a:file_project:file:
+ cpe:/a:file:file:
+ cpe:/a:shim:shim:
cpe:/a:shim(_project)?:shim.*
cpe:/a:date(_project)?:date.*
- cpe:/a:net_dns:net_dns
- cpe:/a:nodejs:node.js
- cpe:/a:nodejs:nodejs
+ cpe:/a:net_dns:net_dns:
+ cpe:/a:nodejs:node.js:
+ cpe:/a:nodejs:nodejs:
cpe:/a:context(_project)?:context.*
cpe:/a:mail(_project)?:mail.*
cpe:/a:ldap(_project)?:ldap.*
cpe:/a:user_import(_project)?:user_import.*
- cpe:/a:root:root
+ cpe:/a:root:root:
cpe:/a:xmlsec(_project)?:xmlsec.*
cpe:/a:rest-client(_project)?:rest-client.*
cpe:/a:hub(_project)?:hub.*
cpe:/a:views(_project)?:views.*
cpe:/a:restful_web_services(_project)?:restful_web_services.*
- cpe:/a:php:php
+ cpe:/a:php:php:
cpe:/a:font(_project)?:font.*
cpe:/a:amazon_aws(_project)?:amazon_aws.*
- cpe:/a:google:android
+ cpe:/a:google:android:
cpe:/a:first(_project)?:first.*
- cpe:/a:interact:interact
+ cpe:/a:interact:interact:
cpe:/a:finder(_project)?:finder.*
cpe:/a:archiver(_project)?:archiver.*
cpe:/a:r(_project)?:r.*
cpe:/a:jwt(_project)?:jwt.*
cpe:/a:git(_project)?:git.*
- cpe:/a:git:git
+ cpe:/a:git:git:
cpe:/a:git_for_windows(_project)?:git_for_windows.*
- cpe:/a:mono-project:mono
- cpe:/a:mono:mono
+ cpe:/a:mono-project:mono:
+ cpe:/a:mono:mono:
cpe:/a:mono(_project)?:mono.*
cpe:/a:app(_project)?:app.*
cpe:/a:json-jwt(_project)?:json-jwt.*
@@ -697,25 +641,25 @@
cpe:/a:util-linux(_project)?:util-linux.*
cpe:/a:bitmap(_project)?:bitmap.*
cpe:/a:security-framework(_project)?:security-framework.*
- cpe:/a:next:next
- cpe:/a:property_pro:property_pro
+ cpe:/a:next:next:
+ cpe:/a:property_pro:property_pro:
CVE-2020-10663
- cpe:/a:facebook:facebook
- cpe:/a:gitlab:gitlab
- cpe:/a:delegate:delegate
+ cpe:/a:facebook:facebook:
+ cpe:/a:gitlab:gitlab:
+ cpe:/a:delegate:delegate:
cpe:/a:thread(_project)?:thread.*
cpe:/a:data_tools(_project)?:data_tools.*
cpe:/a:tag(_project)?:tag.*
- cpe:/a:kubernetes:kubernetes
+ cpe:/a:kubernetes:kubernetes:
cpe:/a:websockets(_project)?:websockets.*
cpe:/a:cron(_project)?:cron.*
cpe:/a:html2pdf(_project)?:html2pdf.*
cpe:/a:shadow(_project)?:shadow.*
- cpe:/a:cde:cde
- cpe:/a:docker:docker
- cpe:/a:travis-ci:travis_ci
+ cpe:/a:cde:cde:
+ cpe:/a:docker:docker:
+ cpe:/a:travis-ci:travis_ci:
cpe:/a:storage(_project)?:storage.*
- cpe:/a:pivotal_software:rabbitmq
+ cpe:/a:pivotal_software:rabbitmq:
cpe:/a:saml(_project)?:saml.*
cpe:/a:yaml(_project)?:yaml.*
cpe:/a:web(_project)?:web.*
@@ -736,7 +680,7 @@
11. sqlserver_project is a node js module (#1388)
12. auth0 is a javascript library (#1925)
13. JAR files should not be identified as github
- 14. cpe:/a:data-tools_project:data_tools is a python project #1961
+ 14. cpe:/a:data-tools_project:data_tools: is a python project #1961
15. flow_project reports an Ethereum token issue
16. ghost CMS is a node.js package (#3203)
17. ws_project is a node websocket client (#1535)
@@ -745,26 +689,26 @@
20. perl:perl is a C project #4254
]]>
.*(\.(jar|ear|war|pom)|pom\.xml)$
- cpe:/a:dash:dash
+ cpe:/a:dash:dash:
cpe:/a:mustache.js(_project)?:mustache.js
- cpe:/a:microsoft:active_directory
- cpe:/a:microsoft:active_directory_federation_services
- cpe:/a:microsoft:active_directory_services
- cpe:/a:snmp:snmp
- cpe:/a:net-snmp:net-snmp
- cpe:/a:python:python
- cpe:/a:python_software_foundation:python
+ cpe:/a:microsoft:active_directory:
+ cpe:/a:microsoft:active_directory_federation_services:
+ cpe:/a:microsoft:active_directory_services:
+ cpe:/a:snmp:snmp:
+ cpe:/a:net-snmp:net-snmp:
+ cpe:/a:python:python:
+ cpe:/a:python_software_foundation:python:
CVE-2017-16046
cpe:/a:sqlserver(_project)?:sqlserver
- cpe:/a:auth0:auth0
- cpe:/a:github:github
+ cpe:/a:auth0:auth0:
+ cpe:/a:github:github:
cpe:/a:data-tools(_project)?:data_tools.*
cpe:/a:flow(_project)?:flow.*
- cpe:/a:ghost:ghost
+ cpe:/a:ghost:ghost:
cpe:/a:ws(_project)?:ws.*
cpe:/a:i18n(_project)?:i18n.*
- cpe:/a:redis:redis
- cpe:/a:perl:perl
+ cpe:/a:redis:redis:
+ cpe:/a:perl:perl:
^pkg:maven/org\.apache\.poi/ooxml\-schemas@.*$
- cpe:/a:apache:poi
+ cpe:/a:apache:poi:
^pkg:maven/org\.jboss\.eap/wildfly\-client\-properties@.*$
- cpe:/a:redhat:wildfly
+ cpe:/a:redhat:wildfly:
^pkg:(generic|nuget)/(microsoft\.)?jQuery[\.-].*$
- cpe:/a:jquery:jquery
+ cpe:/a:jquery:jquery:
^pkg:(generic|nuget)/System\.Security\.Cryptography\.OpenSsl@.*$
- cpe:/a:openssl:openssl
+ cpe:/a:openssl:openssl:
^pkg:(generic|nuget)/Microsoft\.Bcl\.AsyncInterfaces@.*$
- cpe:/a:microsoft:.net_core
+ cpe:/a:microsoft:.net_core:
^pkg:(generic|nuget)/Microsoft\.DiaSymReader\.Native\.arm@.*$
- cpe:/a:microsoft:visual_studio
- cpe:/a:microsoft:visual_studio_2017
+ cpe:/a:microsoft:visual_studio:
+ cpe:/a:microsoft:visual_studio_2017:
^pkg:(generic|nuget)/Microsoft\.DiaSymReader\.Native@.*$
- cpe:/a:dia:dia
+ cpe:/a:dia:dia:
^pkg:maven/(io\.quarkus/quarkus\-|io\.smallrye).*mutiny.*@.*$
- cpe:/a:mutiny:mutiny
+ cpe:/a:mutiny:mutiny:
^org\.mitre:openid-connect-client:.*$
- cpe:/a:openid:openid_connect
+ cpe:/a:openid:openid_connect:
^de\.siegmar:logback-gelf:.*$
- cpe:/a:logback:logback
- cpe:/a:qos:logback
-
-
-
- ^pkg:maven/io\.prometheus\.jmx/.*$
- CVE-2019-3826
-
-
-
- ^io\.prometheus:simple.*$
- CVE-2019-3826
+ cpe:/a:logback:logback:
+ cpe:/a:qos:logback:
^pkg:maven/io\.prometheus/simpleclient_logback@.*$
- cpe:/a:logback:logback
- cpe:/a:qos:logback
+ cpe:/a:logback:logback:
+ cpe:/a:qos:logback:
(com\.sun\.jersey|org\.glassfish\.jersey\.core):jersey-(client|common):.*
- cpe:/a:oracle:glassfish
- cpe:/a:oracle:oracle_client
+ cpe:/a:oracle:glassfish:
+ cpe:/a:oracle:oracle_client:
^pkg:maven/org\.ehcache/ehcache@.*$
- cpe:/a:gradle:gradle
+ cpe:/a:gradle:gradle:
^com\.atlassian\.http:atlassian-http:.*$
- cpe:/a:atlassian:bitbucket
+ cpe:/a:atlassian:bitbucket:
^com\.cybersource:flex-server-sdk:.*$
cpe:/a:flex(_project)?:flex.*
- cpe:/a:id:id-software
+ cpe:/a:id:id-software:
^pkg:maven/com\.atlassian\.httpclient/atlassian\-httpclient\-library@.*$
- cpe:/a:apache:httpclient
+ cpe:/a:apache:httpclient:
^pkg:maven/io\.scanbot/scanbot\-sdk\-imageprocessing@.*$
- cpe:/a:image_processing_software:image_processing_software
+ cpe:/a:image_processing_software:image_processing_software:
^pkg:maven/co\.elastic\.apm/apm\-grails\-plugin@.*$
- cpe:/a:grails:grails
+ cpe:/a:grails:grails:
^pkg:maven/org\.apache\.geronimo/geronimo\-(health|metrics(-common)?)@.*$
- cpe:/a:apache:geronimo
+ cpe:/a:apache:geronimo:
^pkg:maven/co\.elastic\.logging/logback\-ecs\-encoder@.*$
- cpe:/a:logback:logback
- cpe:/a:qos:logback
+ cpe:/a:logback:logback:
+ cpe:/a:qos:logback:
^pkg:maven/com\.typesafe\.play/shaded\-oauth@.*$
- cpe:/a:playframework:play_framework
+ cpe:/a:playframework:play_framework:
^pkg:maven/com\.typesafe\.play/cachecontrol_2\.13@.*$
- cpe:/a:playframework:play_framework
+ cpe:/a:playframework:play_framework:
^pkg:maven/org\.apache\.camel/camel\-servicenow(\-starter)?@.*$
- cpe:/a:apache:camel
- cpe:/a:servicenow:servicenow
+ cpe:/a:apache:camel:
+ cpe:/a:servicenow:servicenow:
^pkg:maven/org\.apache\.camel/json\-simple\-ordered@.*$
- cpe:/a:apache:camel
+ cpe:/a:apache:camel:
^pkg:maven/org\.apache\.camel/camel\-cxf@.*$
- cpe:/a:apache:cxf
+ cpe:/a:apache:cxf:
^pkg:maven/org\.apache\.camel/camel\-cxf\-transport@.*$
- cpe:/a:apache:cxf
+ cpe:/a:apache:cxf:
^pkg:maven/com\.atlassian\.jira/jira\-rest\-java\-client\-api@.*$
- cpe:/a:atlassian:jira
- cpe:/a:atlassian:jira_core
+ cpe:/a:atlassian:jira:
+ cpe:/a:atlassian:jira_core:
^pkg:maven/com\.atlassian\.jira/jira\-rest\-java\-client\-core@.*$
- cpe:/a:atlassian:jira
- cpe:/a:atlassian:jira_core
+ cpe:/a:atlassian:jira:
+ cpe:/a:atlassian:jira_core:
^pkg:maven/com\.atlassian\.jira/jira\-rest\-java\-client\-app@.*$
- cpe:/a:atlassian:jira
- cpe:/a:atlassian:jira_core
+ cpe:/a:atlassian:jira:
+ cpe:/a:atlassian:jira_core:
^pkg:maven/com\.github\.docker\-java/docker\-java@.*$
- cpe:/a:docker:docker
+ cpe:/a:docker:docker:
^pkg:maven/com\.itextpdf/itext\-licensekey@.*$
- cpe:/a:itextpdf:itext
+ cpe:/a:itextpdf:itext:
^pkg:maven/com\.datomic/(?!datomic-free).*$
- cpe:/a:cognitect:datomic
+ cpe:/a:cognitect:datomic:
^pkg:maven/com\.liferay\.portal/com\.liferay\.util\.slf4j@.*$
- cpe:/a:liferay:liferay
- cpe:/a:liferay:liferay_portal
- cpe:/a:liferay:portal
+ cpe:/a:liferay:liferay:
+ cpe:/a:liferay:liferay_portal:
+ cpe:/a:liferay:portal:
^pkg:maven/com\.liferay\.portal/com\.liferay\.portal\.impl@.*$
- cpe:/a:liferay:liferay
- cpe:/a:liferay:liferay_portal
- cpe:/a:liferay:portal
+ cpe:/a:liferay:liferay:
+ cpe:/a:liferay:liferay_portal:
+ cpe:/a:liferay:portal:
^pkg:maven/com\.liferay\.portal/com\.liferay\.support\.tomcat@.*$
- cpe:/a:liferay:liferay
- cpe:/a:liferay:liferay_portal
- cpe:/a:liferay:portal
+ cpe:/a:liferay:liferay:
+ cpe:/a:liferay:liferay_portal:
+ cpe:/a:liferay:portal:
^pkg:maven/com\.liferay\.portal/com\.liferay\.util\.bridges@.*$
- cpe:/a:liferay:liferay
- cpe:/a:liferay:liferay_portal
- cpe:/a:liferay:portal
+ cpe:/a:liferay:liferay:
+ cpe:/a:liferay:liferay_portal:
+ cpe:/a:liferay:portal:
^pkg:maven/com\.liferay\.portal/com\.liferay\.util\.java@.*$
- cpe:/a:liferay:liferay
- cpe:/a:liferay:liferay_portal
- cpe:/a:liferay:portal
+ cpe:/a:liferay:liferay:
+ cpe:/a:liferay:liferay_portal:
+ cpe:/a:liferay:portal:
^pkg:maven/com\.liferay\.portal/com\.liferay\.util\.taglib@.*$
- cpe:/a:liferay:liferay
- cpe:/a:liferay:liferay_portal
- cpe:/a:liferay:portal
+ cpe:/a:liferay:liferay:
+ cpe:/a:liferay:liferay_portal:
+ cpe:/a:liferay:portal:
^pkg:maven/com\.liferay\.portal/com\.liferay\.portal\.test@.*$
- cpe:/a:liferay:liferay
- cpe:/a:liferay:liferay_portal
- cpe:/a:liferay:portal
+ cpe:/a:liferay:liferay:
+ cpe:/a:liferay:liferay_portal:
+ cpe:/a:liferay:portal:
^pkg:maven/com\.liferay\.portal/com\.liferay\.portal\.kernel@.*$
- cpe:/a:liferay:liferay
- cpe:/a:liferay:liferay_portal
- cpe:/a:liferay:portal
+ cpe:/a:liferay:liferay:
+ cpe:/a:liferay:liferay_portal:
+ cpe:/a:liferay:portal:
^pkg:maven/com\.liferay\.portletmvc4spring/com\.liferay\.portletmvc4spring\.test@.*$
- cpe:/a:liferay:liferay
- cpe:/a:liferay:liferay_portal
- cpe:/a:liferay:portal
+ cpe:/a:liferay:liferay:
+ cpe:/a:liferay:liferay_portal:
+ cpe:/a:liferay:portal:
^pkg:maven/com\.liferay/biz\.aQute\.bnd\.annotation@.*$
- cpe:/a:liferay:liferay
- cpe:/a:liferay:liferay_portal
- cpe:/a:liferay:portal
+ cpe:/a:liferay:liferay:
+ cpe:/a:liferay:liferay_portal:
+ cpe:/a:liferay:portal:
^org\.apache\.geronimo\.javamail:geronimo-javamail_1\.4_mail:.*$
- cpe:/a:apache:geronimo
+ cpe:/a:apache:geronimo:
^geronimo-spec:geronimo-spec-javamail:.*$
- cpe:/a:apache:geronimo
+ cpe:/a:apache:geronimo:
^org\.apache\.geronimo\.javamail:geronimo-javamail_1\.4_provider:.*$
- cpe:/a:apache:geronimo
+ cpe:/a:apache:geronimo:
^pkg:maven/com\.nimbusds/oauth2\-oidc\-sdk@.*$
- cpe:/a:openid:openid
- cpe:/a:openid:openid_connect
+ cpe:/a:openid:openid:
+ cpe:/a:openid:openid_connect:
^pkg:maven/com\.azure/azure\-core\-http\-netty@.*$
- cpe:/a:netty:netty
+ cpe:/a:netty:netty:
^pkg:(nuget|generic)/Azure\.Core(_sdk)?@.*$
- cpe:/a:microsoft:.net_core
+ cpe:/a:microsoft:.net_core:
^pkg:maven/com\.nimbusds/oauth2\-oidc\-sdk@.*$
- cpe:/a:openid:openid
- cpe:/a:openid:openid_connect
+ cpe:/a:openid:openid:
+ cpe:/a:openid:openid_connect:
^org\.apache\.activemq:artemis.*$
- cpe:/a:apache:apache_http_server
- cpe:/a:apache:http_server
- cpe:/a:apache:activemq
+ cpe:/a:apache:apache_http_server:
+ cpe:/a:apache:http_server:
+ cpe:/a:apache:activemq:
com\.sun\.jersey\.contribs:jersey-apache-client.*
- cpe:/a:apache:httpclient
+ cpe:/a:apache:httpclient:
org\.glassfish(\.(web|grizzly)):.*(json|faces|jstl|grizzly).*
- cpe:/a:oracle:glassfish
- cpe:/a:oracle:glassfish_server
+ cpe:/a:oracle:glassfish:
+ cpe:/a:oracle:glassfish_server:
^pkg:maven/io\.kamon/kamon\-akka.*$
- cpe:/a:akka:akka
+ cpe:/a:akka:akka:
^pkg:maven/io\.undertow\..*$
- cpe:/a:redhat:undertow
- cpe:/a:oracle:jsp
+ cpe:/a:redhat:undertow:
+ cpe:/a:oracle:jsp:
^pkg:(generic|nuget)/Microsoft\.AspNetCore\..*$
- cpe:/a:microsoft:aspnetcore
- cpe:/a:microsoft:asp.net_core
- cpe:/a:microsoft:asp.net
+ cpe:/a:microsoft:aspnetcore:
+ cpe:/a:microsoft:asp.net_core:
+ cpe:/a:microsoft:asp.net:
^pkg:(generic|nuget)/Microsoft\.Net\..*$
- cpe:/a:microsoft:aspnetcore
- cpe:/a:microsoft:asp.net_core
- cpe:/a:microsoft:asp.net
+ cpe:/a:microsoft:aspnetcore:
+ cpe:/a:microsoft:asp.net_core:
+ cpe:/a:microsoft:asp.net:
^pkg:(generic|nuget)/Microsoft\.Extensions\..*$
- cpe:/a:microsoft:aspnetcore
- cpe:/a:microsoft:asp.net_core
- cpe:/a:microsoft:asp.net
+ cpe:/a:microsoft:aspnetcore:
+ cpe:/a:microsoft:asp.net_core:
+ cpe:/a:microsoft:asp.net:
^pkg:(generic|nuget)/Swashbuckle\..*$
- cpe:/a:asp-project:asp-project
+ cpe:/a:asp-project:asp-project:
^pkg:(generic|nuget)/Microsoft\.VisualStudio\.Web\.CodeGenerat.*$
- cpe:/a:microsoft:visual_studio_code
+ cpe:/a:microsoft:visual_studio_code:
^pkg:(generic|nuget)/Microsoft\.Win32\.Registry\.AccessControl@.*$
- cpe:/a:microsoft:access
+ cpe:/a:microsoft:access:
^com\.github\.danielwegener:logback-kafka-appender:.*$
- cpe:/a:logback:logback
- cpe:/a:qos:logback
+ cpe:/a:logback:logback:
+ cpe:/a:qos:logback:
^org\.apache\.httpcomponents:httpmime:.*$
- cpe:/a:apache:httpclient
+ cpe:/a:apache:httpclient:
^pkg:maven/org\.eclipse\.jetty/jetty\-reactive\-httpclient@.*$
- cpe:/a:mortbay_jetty:jetty
- cpe:/a:mortbay:jetty
- cpe:/a:jetty:jetty
- cpe:/a:eclipse:jetty
+ cpe:/a:mortbay_jetty:jetty:
+ cpe:/a:mortbay:jetty:
+ cpe:/a:jetty:jetty:
+ cpe:/a:eclipse:jetty:
^pkg:maven/org\.eclipse\.jetty\.websocket/websocket-api@.*$
- cpe:/a:mortbay_jetty:jetty
- cpe:/a:mortbay:jetty
- cpe:/a:jetty:jetty
- cpe:/a:eclipse:jetty
+ cpe:/a:mortbay_jetty:jetty:
+ cpe:/a:mortbay:jetty:
+ cpe:/a:jetty:jetty:
+ cpe:/a:eclipse:jetty:
^com\.facebook\.android:facebook-android-sdk:.*$
- cpe:/a:facebook:facebook
+ cpe:/a:facebook:facebook:
^com\.amazonaws:aws-android-sdk-cognitoidentityprovider-asf:.*$
- cpe:/a:android:android_sdk
+ cpe:/a:android:android_sdk:
^pkg:maven/com\.hazelcast/hazelcast\-aws@.*$
- cpe:/a:hazelcast:hazelcast
+ cpe:/a:hazelcast:hazelcast:
^pkg:maven/com\.hazelcast/hazelcast\-kubernetes@.*$
- cpe:/a:hazelcast:hazelcast
+ cpe:/a:hazelcast:hazelcast:
^pkg:maven/com\.hazelcast/hazelcast\-client\-protocol@.*$
- cpe:/a:hazelcast:hazelcast
+ cpe:/a:hazelcast:hazelcast:
^pkg:maven/com\.rabbitmq/amqp\-client@.*$
- cpe:/a:pivotal_software:rabbitmq
+ cpe:/a:pivotal_software:rabbitmq:
^pkg:maven/io\.zipkin\.reporter2/zipkin\-sender\-activemq\-client@.*$
- cpe:/a:apache:activemq
+ cpe:/a:apache:activemq:
^pkg:maven/com\.lightbend\.akka\.management/akka\-management_2\.12@.*$
- cpe:/a:akka:akka
+ cpe:/a:akka:akka:
^pkg:maven/com\.github\.romix\.akka/akka\-kryo\-serialization_2\.12@.*$
- cpe:/a:akka:akka
+ cpe:/a:akka:akka:
^pkg:maven/io\.kamon/kamon\-prometheus_2\.12@.*$
- cpe:/a:prometheus:prometheus
+ cpe:/a:prometheus:prometheus:
^pkg:maven/org\.jetbrains\.kotlinx/.*$
- cpe:/a:jetbrains:kotlin
+ cpe:/a:jetbrains:kotlin:
^org\.jetbrains:annotations:.*$
- cpe:/a:jetbrains:intellij_idea
+ cpe:/a:jetbrains:intellij_idea:
^pkg:maven/org\.openapitools/jackson\-databind\-nullable@.*$
- cpe:/a:fasterxml:jackson
- cpe:/a:fasterxml:jackson-databind
+ cpe:/a:fasterxml:jackson:
+ cpe:/a:fasterxml:jackson-databind:
org\.opensaml:xmltooling:.*
- cpe:/a:shibboleth:opensaml
- cpe:/a:internet2:opensaml
+ cpe:/a:shibboleth:opensaml:
+ cpe:/a:internet2:opensaml:
CVE-2015-0851
CVE-2019-9628
@@ -1599,62 +1529,62 @@
Suppresses false positives on the org.opensaml:openws
]]>
org\.opensaml:openws:.*
- cpe:/a:internet2:opensaml
+ cpe:/a:internet2:opensaml:
.*(\.(whl|egg)|\b(site|dist)-packages\b.*)
- cpe:/a:python:python
- cpe:/a:python_software_foundation:python
- cpe:/a:class:class
- cpe:/a:file:file
- cpe:/a:gnupg:gnupg
- cpe:/a:mongodb:mongodb
- cpe:/a:mozilla:mozilla
- cpe:/a:openssl:openssl
- cpe:/a:sendfile:sendfile
- cpe:/a:sendmail:sendmail
- cpe:/a:yacc:yacc
+ cpe:/a:python:python:
+ cpe:/a:python_software_foundation:python:
+ cpe:/a:class:class:
+ cpe:/a:file:file:
+ cpe:/a:gnupg:gnupg:
+ cpe:/a:mongodb:mongodb:
+ cpe:/a:mozilla:mozilla:
+ cpe:/a:openssl:openssl:
+ cpe:/a:sendfile:sendfile:
+ cpe:/a:sendmail:sendmail:
+ cpe:/a:yacc:yacc:
com\.google(\.[a-zA-Z0-9_-]+)?:.*:.*
- cpe:/a:google:desktop
+ cpe:/a:google:desktop:
com\.google\.((?!android).)*:.*
- cpe:/a:google:android
- cpe:/a:google:android_api
+ cpe:/a:google:android:
+ cpe:/a:google:android_api:
com\.google\.android\..*:.*
- cpe:/a:google:android
- cpe:/a:google:android_api
- cpe:/a:google:google
+ cpe:/a:google:android:
+ cpe:/a:google:android_api:
+ cpe:/a:google:google:
^pkg:maven/com\.google\.guava/failureaccess@.*$
- cpe:/a:google:guava
+ cpe:/a:google:guava:
^pkg:maven/com\.google\.guava/listenablefuture@.*$
- cpe:/a:google:guava
+ cpe:/a:google:guava:
com.microsoft.bingads:microsoft.bingads:.*
- cpe:/a:microsoft:bing
+ cpe:/a:microsoft:bing:
.*jersey.*
- cpe:/a:oracle:glassfish_server
- cpe:/a:oracle:glassfish
+ cpe:/a:oracle:glassfish_server:
+ cpe:/a:oracle:glassfish:
.*\bhk2\b.*
- cpe:/a:oracle:glassfish
+ cpe:/a:oracle:glassfish:
.*\bhk2-utils.*\.jar
- cpe:/a:oracle:glassfish
+ cpe:/a:oracle:glassfish:
org.ow2.petals:petals-se-camel:.*
- cpe:/a:apache:camel
+ cpe:/a:apache:camel:
org.apache.mina:mina.*
- cpe:/a:apache-ssl:apache-ssl
+ cpe:/a:apache-ssl:apache-ssl:
org.apache.woden:woden.*
- cpe:/a:apache-ssl:apache-ssl
+ cpe:/a:apache-ssl:apache-ssl:
org.apache.geronimo.specs:.*
- cpe:/a:apache:geronimo
+ cpe:/a:apache:geronimo:
^pkg:maven/dev\.miku/r2dbc\-mysql@.*$
- cpe:/a:mysql:mysql
+ cpe:/a:mysql:mysql:
^pkg:maven/org\.apache\.tomcat/tomcat\-jni@.*$
- cpe:/a:apache:tomcat
- cpe:/a:apache_tomcat:apache_tomcat
- cpe:/a:apache_software_foundation:tomcat
+ cpe:/a:apache:tomcat:
+ cpe:/a:apache_tomcat:apache_tomcat:
+ cpe:/a:apache_software_foundation:tomcat:
org\.apache\.tomcat\.embed:tomcat-embed-el:.*
- cpe:/a:apache:tomcat
- cpe:/a:apache_tomcat:apache_tomcat
- cpe:/a:apache_software_foundation:tomcat
+ cpe:/a:apache:tomcat:
+ cpe:/a:apache_tomcat:apache_tomcat:
+ cpe:/a:apache_software_foundation:tomcat:
^org\.apache\.tomcat:tomcat-(servlet|el)-api:.*$
- cpe:/a:apache:tomcat
- cpe:/a:apache_tomcat:apache_tomcat
- cpe:/a:apache_software_foundation:tomcat
+ cpe:/a:apache:tomcat:
+ cpe:/a:apache_tomcat:apache_tomcat:
+ cpe:/a:apache_software_foundation:tomcat:
org\.apache\.tomcat:tomcat-jdbc:.*
- cpe:/a:apache:tomcat
- cpe:/a:apache_tomcat:apache_tomcat
+ cpe:/a:apache:tomcat:
+ cpe:/a:apache_tomcat:apache_tomcat:
org\.apache\.tomcat:tomcat-juli:.*
- cpe:/a:apache:tomcat
- cpe:/a:apache_tomcat:apache_tomcat
+ cpe:/a:apache:tomcat:
+ cpe:/a:apache_tomcat:apache_tomcat:
com\.google\.javascript:closure-compiler:.*
- cpe:/a:google:google_apps:-
+ cpe:/a:google:google_apps:-:
.*mongodb.*:.*:.*
- cpe:/a:mongodb:mongodb
+ cpe:/a:mongodb:mongodb:
^org\.apache\.xbean:xbean.*$
- cpe:/a:apache:geronimo
+ cpe:/a:apache:geronimo:
^org\.openjdk\.jmh:jmh-core:.*$
- cpe:/a:sun:openjdk
- cpe:/a:oracle:openjdk
+ cpe:/a:sun:openjdk:
+ cpe:/a:oracle:openjdk:
^org\.apache\.geronimo\.components:geronimo-transaction:.*$
- cpe:/a:apache:geronimo
+ cpe:/a:apache:geronimo:
info\.ganglia\.gmetric4j:gmetric4j:.*
- cpe:/a:ganglia:ganglia
+ cpe:/a:ganglia:ganglia:
io\.dropwizard\.metrics:metrics-ganglia:.*
- cpe:/a:ganglia:ganglia
+ cpe:/a:ganglia:ganglia:
^pkg:maven/io\.dropwizard/dropwizard-jetty@.*$
- cpe:/a:mortbay_jetty:jetty
- cpe:/a:mortbay:jetty
- cpe:/a:jetty:jetty
- cpe:/a:eclipse:jetty
+ cpe:/a:mortbay_jetty:jetty:
+ cpe:/a:mortbay:jetty:
+ cpe:/a:jetty:jetty:
+ cpe:/a:eclipse:jetty:
^pkg:maven/org\.gagravarr/vorbis\-java\-tika@.*$
- cpe:/a:apache:tika
+ cpe:/a:apache:tika:
cpe:/a:flac(_project)?:flac.*
@@ -1859,53 +1789,53 @@
false positive per issue #1961
]]>
^pkg:maven/edu\.usc\.ir/sentiment\-analysis\-parser@.*$
- cpe:/a:apache:opennlp
- cpe:/a:apache:tika
+ cpe:/a:apache:opennlp:
+ cpe:/a:apache:tika:
^pkg:maven/org\.apache\.avro/avro\-mapred@.*$
- cpe:/a:apache:hadoop
+ cpe:/a:apache:hadoop:
^pkg:maven/org\.scala\-lang/scalap@.*$
- cpe:/a:scala-lang:scala
+ cpe:/a:scala-lang:scala:
^pkg:maven/org\.apache\.spark/spark\-sketch_2\.\d+@.*$
- cpe:/a:sketch:sketch
+ cpe:/a:sketch:sketch:
^pkg:maven/org\.apache\.parquet/parquet\-hadoop@.*$
- cpe:/a:apache:hadoop
+ cpe:/a:apache:hadoop:
^pkg:maven/com\.intellij/annotations@.*$
- cpe:/a:jetbrains:intellij_idea
+ cpe:/a:jetbrains:intellij_idea:
^pkg:maven/org\.ops4j\.pax\.web/pax\-web\-jetty\-bundle@.*$
- cpe:/a:mortbay_jetty:jetty
- cpe:/a:mortbay:jetty
- cpe:/a:jetty:jetty
- cpe:/a:eclipse:jetty
+ cpe:/a:mortbay_jetty:jetty:
+ cpe:/a:mortbay:jetty:
+ cpe:/a:jetty:jetty:
+ cpe:/a:eclipse:jetty:
^pkg:maven/org\.drizzle\.jdbc/drizzle\-jdbc@.*$
- cpe:/a:mysql:mysql
+ cpe:/a:mysql:mysql:
^pkg:maven/org\.apache\.kerby/mysql\-backend@.*$
- cpe:/a:mysql:mysql
+ cpe:/a:mysql:mysql:
^pkg:maven/com\.alibaba/druid@.*$
- cpe:/a:alibaba:alibaba
+ cpe:/a:alibaba:alibaba:
io\.dropwizard\.metrics:metrics-httpclient:.*
- cpe:/a:apache:httpclient
+ cpe:/a:apache:httpclient:
javax\.(annotation|transaction):javax\.(annotation|transaction)-api:.*
- cpe:/a:oracle:glassfish
+ cpe:/a:oracle:glassfish:
^org\.apache\.directory\.api:api-ldap.*$
- cpe:/a:apache:apache_http_server
- cpe:/a:apache:directory_studio
- cpe:/a:apache:ldap_studio
+ cpe:/a:apache:apache_http_server:
+ cpe:/a:apache:directory_studio:
+ cpe:/a:apache:ldap_studio:
cpe:/a:net-ldap(_project)?:net-ldap.*
@@ -1964,64 +1894,63 @@
FP per #2029
]]>
^pkg:maven/org\.opensaml/openws@.*$
- cpe:/a:shibboleth:opensaml
+ cpe:/a:shibboleth:opensaml:
^org\.apache\.servicemix\.bundles:org\.apache\.servicemix\.bundles\.not-yet-commons-ssl:.*$
- cpe:/a:apache-ssl:apache-ssl
+ cpe:/a:apache-ssl:apache-ssl:
^org\.apache\.cxf\.fediz:fediz-core:.*$
- cpe:/a:apache:cxf
+ cpe:/a:apache:cxf:
.*(\.(jar|ear|war|pom)|pom\.xml)
- cpe:/a:tiger:tiger
+ cpe:/a:tiger:tiger:
.*(\.(dll|jar|ear|war|pom)|pom\.xml)
- cpe:/a:class:class
+ cpe:/a:class:class:
.*(\.(jar|ear|war|pom)|pom\.xml)
- cpe:/a:pam:pam
- cpe:/a:pam_ssh:pam_ssh
- cpe:/a:sun:linux
- cpe:/a:sun:sunos
- cpe:/a:oracle:linux
+ cpe:/a:pam:pam:
+ cpe:/a:pam_ssh:pam_ssh:
+ cpe:/a:sun:linux:
+ cpe:/a:sun:sunos:
+ cpe:/a:oracle:linux:
.*(\.(jar|ear|war|pom)|pom\.xml)
- cpe:/a:sun:java
- cpe:/a:sun:jdk
- cpe:/a:sun:j2se
- cpe:/a:sun:j_se
- cpe:/a:sun:j_se
+ cpe:/a:sun:java:
+ cpe:/a:sun:jdk:
+ cpe:/a:sun:j2se:
+ cpe:/a:sun:j_se:
^org\.apache\.pdfbox:fontbox:.*$
- cpe:/a:apache:pdfbox
+ cpe:/a:apache:pdfbox:
^(javax\.json|org\.glassfish):javax\.json(-api)?:.*$
- cpe:/a:processing:processing
+ cpe:/a:processing:processing:
^pkg:maven/org\.glassfish.*$
- cpe:/a:processing:processing
+ cpe:/a:processing:processing:
^pkg:maven/jakarta\.json/jakarta\.json\-api@.*$
- cpe:/a:processing:processing
+ cpe:/a:processing:processing:
^org\.ojai:ojai:.*$
- cpe:/a:mapr:mapr
+ cpe:/a:mapr:mapr:
^org\.jenkins-ci\.plugins:dependency-track:.*$
- cpe:/a:track%2b:track%2b
+ cpe:/a:track%2b:track%2b:
^org\.jenkins-ci\.plugins:.*$
- cpe:/a:jenkins:jenkins
+ cpe:/a:jenkins:jenkins:
^org\.jenkins-ci\.tools:maven-hpi-plugin:.*$
- cpe:/a:jenkins:jenkins
- cpe:/a:jenkins:maven
+ cpe:/a:jenkins:jenkins:
+ cpe:/a:jenkins:maven:
^org\.owasp:dependency-check-gradle:.*$
- cpe:/a:gradle:gradle
+ cpe:/a:gradle:gradle:
^pkg:maven/com\.android\.tools\.build/gradle\-api@.*$
- cpe:/a:gradle:gradle
+ cpe:/a:gradle:gradle:
^io\.springfox:springfox-.+:.*$
- cpe:/a:gradle:gradle
-
-
-
- ^io\.micrometer:micrometer-registry-prometheus:.*$
- CVE-2019-3826
+ cpe:/a:gradle:gradle:
^pkg:maven/io\.micrometer/micrometer\-spring\-legacy@.*$
- cpe:/a:pivotal_software:spring_framework
+ cpe:/a:pivotal_software:spring_framework:
^pkg:maven/com\.squareup\.retrofit2?/(?!retrofit).*$
- cpe:/a:squareup:retrofit
-
-
-
- ^io\.prometheus:simpleclient_common:.*$
- CVE-2019-3826
-
-
-
- ^io\.prometheus:simpleclient:.*$
- CVE-2019-3826
+ cpe:/a:squareup:retrofit:
^(?!org\.jenkins-ci\.main:jenkins-war).*$
- cpe:/a:jenkins:jenkins
+ cpe:/a:jenkins:jenkins:
^(?!org\.glassfish\.main\.core:glassfish).*$
- cpe:/a:oracle:glassfish
+ cpe:/a:oracle:glassfish:
^org\.scala-lang\.modules:.*$
- cpe:/a:scala-lang:scala
+ cpe:/a:scala-lang:scala:
^(?!org\.jenkins-ci\.main:maven-plugin):.*$
- cpe:/a:jenkins:maven
+ cpe:/a:jenkins:maven:
^org\.jruby\.ext.*$
- cpe:/a:jruby:jruby
+ cpe:/a:jruby:jruby:
org\.elasticsearch:securesm:.*
- cpe:/a:elasticsearch:elasticsearch
+ cpe:/a:elasticsearch:elasticsearch:
^org\.apache\.wink:wink-json4j:.*$
- cpe:/a:wink:wink
+ cpe:/a:wink:wink:
^javax\.(jws|servlet):javax\.(jws|servlet)-api:.*$
- cpe:/a:oracle:glassfish
+ cpe:/a:oracle:glassfish:
org\.glassfish:javax.el:.*
- cpe:/a:oracle:glassfish
+ cpe:/a:oracle:glassfish:
^pkg:maven/javax\.portlet/portlet\-api@.*$
- cpe:/a:apache:pluto
+ cpe:/a:apache:pluto:
^org\.pac4j:pac4j-oidc:.*$
- cpe:/a:openid:openid
+ cpe:/a:openid:openid:
sslext:sslext:.*
- cpe:/a:apache:struts
+ cpe:/a:apache:struts:
org\.apache\.activemq:activemq(-jms)?-pool.*
- cpe:/a:apache:activemq
+ cpe:/a:apache:activemq:
^pkg:maven/org\.apache\.activemq/activemq-(openwire-legacy|spring)@.*$
- cpe:/a:apache:activemq
+ cpe:/a:apache:activemq:
^pkg:maven/org\.apache\.activemq\.protobuf/activemq\-protobuf@.*$
- cpe:/a:apache:activemq
+ cpe:/a:apache:activemq:
.*(?!gradle).*
- cpe:/a:gradle:gradle
+ cpe:/a:gradle:gradle:
^pkg:maven/de\.ahus1\.keycloak\.dropwizard/keycloak\-dropwizard@.*$
- cpe:/a:keycloak:keycloak
+ cpe:/a:keycloak:keycloak:
^pkg:maven/org\.keycloak/keycloak\-jetty\-core@.*$
- cpe:/a:mortbay_jetty:jetty
- cpe:/a:mortbay:jetty
- cpe:/a:jetty:jetty
- cpe:/a:eclipse:jetty
+ cpe:/a:mortbay_jetty:jetty:
+ cpe:/a:mortbay:jetty:
+ cpe:/a:jetty:jetty:
+ cpe:/a:eclipse:jetty:
com\.offbytwo\.jenkins:jenkins-client:.*
- cpe:/a:jenkins:jenkins
+ cpe:/a:jenkins:jenkins:
^(?!com.thoughtworks).*xstream.*$
- cpe:/a:x-stream:xstream
+ cpe:/a:x-stream:xstream:
^org\.glassfish\.jersey\.ext:jersey-proxy-client:.*$
- cpe:/a:oracle:oracle_client
+ cpe:/a:oracle:oracle_client:
^org\.mitre\.dsmiley\.httpproxy:smiley-http-proxy-servlet:.*$
- cpe:/a:shttp:shttp
+ cpe:/a:shttp:shttp:
^pkg:maven/com\.fasterxml\.jackson\.dataformat/jackson\-dataformat\-(ion|cbor|avro|protobuf|smile)@.*$
- cpe:/a:fasterxml:jackson-dataformat-xml
+ cpe:/a:fasterxml:jackson-dataformat-xml:
.*package\.json$
cpe:/a:file(_project)?:file.*
- cpe:/a:file:file
- cpe:/a:shim:shim
+ cpe:/a:file:file:
+ cpe:/a:shim:shim:
cpe:/a:shim(_project)?:shim.*
@@ -2427,67 +2335,67 @@
False positives on python.
]]>
.*__init__\.py$
- cpe:/a:shim:shim
- cpe:/a:python:python
+ cpe:/a:shim:shim:
+ cpe:/a:python:python:
.*PKG-INFO$
- cpe:/a:nodejs:nodejs
- cpe:/a:nodejs:node.js
+ cpe:/a:nodejs:nodejs:
+ cpe:/a:nodejs:node.js:
.*
- cpe:/a:checkpoint:check_point
+ cpe:/a:checkpoint:check_point:
^org\.bouncycastle:bctsp.*$
- cpe:/a:openpgp:openpgp
- cpe:/a:pgp:openpgp
- cpe:/a:pgp:pgp
+ cpe:/a:openpgp:openpgp:
+ cpe:/a:pgp:openpgp:
+ cpe:/a:pgp:pgp:
^org\.apache\.xmlgraphics:xmlgraphics-commons:.*$
- cpe:/a:apache:batik
+ cpe:/a:apache:batik:
^io\.jsonwebtoken:jjwt:.*$
- cpe:/a:sonatype:nexus
+ cpe:/a:sonatype:nexus:
^pkg:maven/io\.vertx/vertx\-auth\-common@.*$
- cpe:/a:sonatype:nexus
+ cpe:/a:sonatype:nexus:
^org\.apache\.james:apache-mime4j-core:.*$
- cpe:/a:jcore:jcore
+ cpe:/a:jcore:jcore:
^javax\.servlet:servlet-api:.*$
- cpe:/a:sun:one_application_server
+ cpe:/a:sun:one_application_server:
^com\.splunk:splunk:.*$
- cpe:/a:splunk:splunk
+ cpe:/a:splunk:splunk:
^org\.openid4java:openid4java:.*$
- cpe:/a:openid:openid
- cpe:/a:openid:openid4java
+ cpe:/a:openid:openid:
+ cpe:/a:openid:openid4java:
^com\.artofsolving:jodconverter:.*$
- cpe:/a:openoffice:openoffice.org
- cpe:/a:openoffice:openoffice
+ cpe:/a:openoffice:openoffice.org:
+ cpe:/a:openoffice:openoffice:
^io\.swagger:.*$
- cpe:/a:sonatype:nexus
+ cpe:/a:sonatype:nexus:
CVE-2020-21913
CVE-2025-5222
- cpe:/a:apple:java
+ cpe:/a:apple:java:
cpe:/a:unicode:unicode:
@@ -2587,22 +2495,22 @@
False positive per issue #854
]]>
^com\.vaadin\.external\.google:android-json:.*$
- cpe:/a:google:android
+ cpe:/a:google:android:
^org\.glassfish:javax\.json:.*$
- cpe:/a:oracle:glassfish
+ cpe:/a:oracle:glassfish:
.*activerecord.*oracle.*\.gemspec
- cpe:/a:ruby-i18n:i18n
- cpe:/a:mikel_lindsaar:mail
+ cpe:/a:ruby-i18n:i18n:
+ cpe:/a:mikel_lindsaar:mail:
cpe:/a:rest-client(_project)?:rest-client.*
@@ -2611,21 +2519,21 @@
]]>
^net\.thisptr:jackson-jq:.*$
cpe:/a:jq(_project)?:jq.*
- cpe:/a:id:id-software
+ cpe:/a:id:id-software:
^org\.jruby\.jcodings:jcodings:.*$
- cpe:/a:jruby:jruby
+ cpe:/a:jruby:jruby:
^org\.jruby\.joni:joni:.*$
- cpe:/a:jruby:jruby
+ cpe:/a:jruby:jruby:
^org\.apache\.cxf\.xjc-utils:.*:.*$
- cpe:/a:apache:cxf
+ cpe:/a:apache:cxf:
^org\.apache\.cxf\.xjcplugins:.*:.*$
- cpe:/a:apache:cxf
+ cpe:/a:apache:cxf:
^org\.apache\.struts\.xwork:xwork-core:.*$
- cpe:/a:apache:struts
+ cpe:/a:apache:struts:
^org\.apache\.cassandra:cassandra-thrift:.*$
- cpe:/a:apache:thrift
- cpe:/a:apache:cassandra
+ cpe:/a:apache:thrift:
+ cpe:/a:apache:cassandra:
^org\.apache\.xbean:xbean-bundleutils:.*$
- cpe:/a:apache:geronimo
+ cpe:/a:apache:geronimo:
^org\.jenkins-ci:annotation-indexer:.*$
- cpe:/a:jenkins:jenkins
+ cpe:/a:jenkins:jenkins:
^org\.apache\.cassandra\.deps:avro:.*$
- cpe:/a:apache:cassandra
+ cpe:/a:apache:cassandra:
^com\.netflix\.hystrix:hystrix-request-servlet:.*$
- cpe:/a:request_it:request_it
+ cpe:/a:request_it:request_it:
^com\.unboundid:unboundid-ldapsdk:.*$
- cpe:/a:id:id-software
+ cpe:/a:id:id-software:
^activesoap:jaxb-xercesImpl:[01].*$
- cpe:/a:apache:xerces2_java
+ cpe:/a:apache:xerces2_java:
73a51faadb407dccdbd77234e0d5a0a648665692
- cpe:/a:apache:xerces2_java
+ cpe:/a:apache:xerces2_java:
^pkg:maven/com\.lightbend\.akka/akka\-stream\-alpakka\-xml_2\.12@.*$
- cpe:/a:akka:akka
+ cpe:/a:akka:akka:
^pkg:maven/com\.vaadin\.(addon|external|flow\.ai).*$
- cpe:/a:vaadin:vaadin
+ cpe:/a:vaadin:vaadin:
^pkg:maven/com\.vaadin\.flow\.ai.*$
- cpe:/a:vaadin:flow
+ cpe:/a:vaadin:flow:
^(?!pkg:maven/com\.vaadin/vaadin(-core)?@).*$
- cpe:/a:vaadin:vaadin
+ cpe:/a:vaadin:vaadin:
^pkg:maven/com\.vaadin/sso-kit-starter@.*$
- cpe:/a:vaadin:flow
+ cpe:/a:vaadin:flow:
^pkg:maven/org\.webjars\.(bower|bowergithub|npm).*$
- cpe:/a:vaadin:vaadin
+ cpe:/a:vaadin:vaadin:
^pkg:maven/com\.lightbend\.akka/akka\-stream\-alpakka\-xml_2\.12@.*$
- cpe:/a:lightbend:akka
+ cpe:/a:lightbend:akka:
^com\.typesafe\.play:play-akka-http-server_2\.\d+:.*$
- cpe:/a:akka:akka
- cpe:/a:akka:http_server
+ cpe:/a:akka:akka:
+ cpe:/a:akka:http_server:
^com\.typesafe\.akka:akka-stream-kafka_2\.12:.*$
- cpe:/a:akka:akka
+ cpe:/a:akka:akka:
^com\.lightbend\.akka:akka-stream-alpakka-jms_2\.12:.*$
- cpe:/a:akka:akka
+ cpe:/a:akka:akka:
^com\.typesafe\.akka:akka-persistence-cassandra:.*$
- cpe:/a:akka:akka
-
-
-
- ^pkg:maven/io\.opencensus/opencensus\-contrib\-grpc\-util@.*$
- cpe:/a:grpc:grpc
-
-
-
- ^com\.google\.api\.grpc:proto-.*$
- cpe:/a:grpc:grpc
+ cpe:/a:akka:akka:
^org\.apache\.chemistry\.opencmis:chemistry-opencmis.*$
- cpe:/a:apache:apache_http_server
- cpe:/a:apache:http_server
+ cpe:/a:apache:apache_http_server:
+ cpe:/a:apache:http_server:
^pkg:maven/org\.apache\.directory\.server/apacheds.*$
- cpe:/a:apache:http_server
+ cpe:/a:apache:http_server:
^org\.alfresco\.cmis\.client:alfresco-opencmis-extension:.*$
- cpe:/a:alfresco:alfresco
+ cpe:/a:alfresco:alfresco:
^org\.apache\.portals\.pluto:pluto-portal-driver:.*$
- cpe:/a:in-portal:in-portal
+ cpe:/a:in-portal:in-portal:
^org\.apache\.directory\.api:api-ldap.*$
- cpe:/a:apache:apache_ldap_studio
+ cpe:/a:apache:apache_ldap_studio:
^org\.apache\.tomcat:tomcat-annotations-api:.*$
- cpe:/a:apache:tomcat
- cpe:/a:apache_tomcat:apache_tomcat
- cpe:/a:apache_software_foundation:tomcat
+ cpe:/a:apache:tomcat:
+ cpe:/a:apache_tomcat:apache_tomcat:
+ cpe:/a:apache_software_foundation:tomcat:
.*winstone-?(\d*\.?){0,3}\.jar
- cpe:/a:mortbay_jetty:jetty
- cpe:/a:mortbay:jetty
- cpe:/a:jetty:jetty
- cpe:/a:eclipse:jetty
+ cpe:/a:mortbay_jetty:jetty:
+ cpe:/a:mortbay:jetty:
+ cpe:/a:jetty:jetty:
+ cpe:/a:eclipse:jetty:
^org\.apache\.maven\.wagon:wagon-webdav-jackrabbit:.*$
- cpe:/a:apache:jackrabbit
+ cpe:/a:apache:jackrabbit:
^org\.apache\.xbean:xbean-reflect:.*$
- cpe:/a:apache:geronimo
+ cpe:/a:apache:geronimo:
^pkg:maven/org\.apache\.aries\.transaction/org\.apache\.aries\.transaction\.manager@.*$
- cpe:/a:apache:geronimo
+ cpe:/a:apache:geronimo:
^org\.apache\.curator:curator-recipes:.*$
- cpe:/a:apache:zookeeper
+ cpe:/a:apache:zookeeper:
^pkg:maven/org\.linguafranca\.pwdb/database@.*$
- cpe:/a:keepass:keepass
+ cpe:/a:keepass:keepass:
^pkg:maven/org\.linguafranca\.pwdb/KeePass.*$
- cpe:/a:keepass:keepass
+ cpe:/a:keepass:keepass:
^pkg:maven/org\.apache\.zookeeper/zookeeper.*@.*$
- cpe:/a:apache:hadoop
+ cpe:/a:apache:hadoop:
CVE-2021-21295
@@ -3075,35 +2969,35 @@
FP per #2650
]]>
^pkg:maven/org\.sonatype\.nexus\.plugins/nexus\-restore\-helm@.*$
- cpe:/a:sonatype:nexus
+ cpe:/a:sonatype:nexus:
^pkg:maven/io\.vertx.*$
- cpe:/a:sonatype:nexus
+ cpe:/a:sonatype:nexus:
^org\.apache\.ant:ant-testutil:.*$
- cpe:/a:apache:apache_test
+ cpe:/a:apache:apache_test:
^org\.apache\.maven\.scm:maven-scm-provider-git-commons:.*$
- cpe:/a:git-scm:git
+ cpe:/a:git-scm:git:
^org\.samba\.jcifs:jcifs:.*$
- cpe:/a:samba:samba
+ cpe:/a:samba:samba:
^org\.webjars\.npm:.*$
- cpe:/a:npm:npm
+ cpe:/a:npm:npm:
^pkg:maven/(mysql/mysql\-connector\-java|com\.mysql/mysql\-connector\-j)@.*$
- cpe:/a:oracle:connector%2fj
- cpe:/a:oracle:jdbc
+ cpe:/a:oracle:connector%2fj:
+ cpe:/a:oracle:jdbc:
^net\.sourceforge\.jtds:jtds:.*$
- cpe:/a:microsoft:sql_server
+ cpe:/a:microsoft:sql_server:
^cn\.guoyukun\.jdbc:db2jcc_license_cu:.*$
- cpe:/a:ibm:db2
+ cpe:/a:ibm:db2:
^io\.gitlab\.arturbosch\.detekt:detekt-.+:.*$
- cpe:/a:gitlab:gitlab
+ cpe:/a:gitlab:gitlab:
^org\.bouncycastle:bcpg-jdk15on:.*$
- cpe:/a:openpgp:openpgp
- cpe:/a:pgp:openpgp
- cpe:/a:pgp:pgp
+ cpe:/a:openpgp:openpgp:
+ cpe:/a:pgp:openpgp:
+ cpe:/a:pgp:pgp:
^name\.neuhalfen\.projects\.crypto\.bouncycastle\.openpgp:bouncy-gpg:.*$
cpe:/a:gpg-pgp(_project)?::gpg-pgp.*
- cpe:/a:openpgp:openpgp
+ cpe:/a:openpgp:openpgp:
^pkg:maven/com\.jcraft/jsch\.agentproxy.*$
- cpe:/a:jcraft:jsch
+ cpe:/a:jcraft:jsch:
^pkg:maven/org\.infinispan\.protostream/protostream.*$
- cpe:/a:infinispan:infinispan
+ cpe:/a:infinispan:infinispan:
^pkg:maven/io\.hawt/hawtio\-wildfly@.*$
- cpe:/a:hawt:hawtio
- cpe:/a:hawt.io:hawtio
- cpe:/a:redhat:wildfly
+ cpe:/a:hawt:hawtio:
+ cpe:/a:hawt.io:hawtio:
+ cpe:/a:redhat:wildfly:
^pkg:maven/ant\-contrib/ant\-contrib@.*$
- cpe:/a:tasks:tasks
+ cpe:/a:tasks:tasks:
^pkg:maven/org\.apache\.camel/camel\-hazelcast@.*$
- cpe:/a:hazelcast:hazelcast
+ cpe:/a:hazelcast:hazelcast:
^pkg:maven/com\.spotify/docker\-client@.*$
- cpe:/a:docker:docker
- cpe:/a:spotify:spotify
+ cpe:/a:docker:docker:
+ cpe:/a:spotify:spotify:
^pkg:maven/com\.typesafe\.play/play\-.*ws\-standalone.*@.*$
- cpe:/a:playframework:play_framework
+ cpe:/a:playframework:play_framework:
^pkg:maven/org\.mybatis\.spring\.boot/mybatis\-spring\-boot.*$
- cpe:/a:mybatis:mybatis
+ cpe:/a:mybatis:mybatis:
^pkg:maven/(?!io.kubernetes).*/.*@.*$
- cpe:/a:kubernetes:java
+ cpe:/a:kubernetes:java:
^pkg:maven/io\.fabric8/openshift\-model\-clusterautoscaling@.*$
- cpe:/a:redhat:cluster_project
- cpe:/a:redhat:mod_cluster
+ cpe:/a:redhat:cluster_project:
+ cpe:/a:redhat:mod_cluster:
^pkg:maven/io\.fabric8/openshift\-model\-machineconfig@.*$
- cpe:/a:redhat:machine-config-operator
+ cpe:/a:redhat:machine-config-operator:
^pkg:maven/com\.amazonaws/aws\-java\-sdk\-sagemakerruntime@.*$
- cpe:/a:sage:sage
+ cpe:/a:sage:sage:
^pkg:maven/org\.mybatis\.generator/mybatis\-generator\-core@.*$
- cpe:/a:mybatis:mybatis
+ cpe:/a:mybatis:mybatis:
^pkg:maven/org\.wildfly\.core/wildfly\-protocol@.*$
- cpe:/a:redhat:wildfly
- cpe:/a:redhat:wildfly_core
- cpe:/a:wildfly:wildfly
+ cpe:/a:redhat:wildfly:
+ cpe:/a:redhat:wildfly_core:
+ cpe:/a:wildfly:wildfly:
^pkg:maven/org\.hibernate/quarkus\-local\-cache@.*$
- cpe:/a:hibernate:hibernate_orm
+ cpe:/a:hibernate:hibernate_orm:
^pkg:maven/org\.owasp/csrfguard\-.*$
- cpe:/a:php:com_extensions
+ cpe:/a:php:com_extensions:
^pkg:maven/io\.quarkus\.(security|gizmo|http)/.*$
- cpe:/a:quarkus:quarkus
+ cpe:/a:quarkus:quarkus:
^(?!(io\.quarkus)).*:.*quarkus.*$
- cpe:/a:quarkus:quarkus
+ cpe:/a:quarkus:quarkus:
^pkg:maven/io\.quarkus/quarkus-jdbc-.*$
- cpe:/a:mysql:mysql
- cpe:/a:oracle:jdbc
- cpe:/a:postgresql:postgresql
+ cpe:/a:mysql:mysql:
+ cpe:/a:oracle:jdbc:
+ cpe:/a:postgresql:postgresql:
^pkg:maven/io\.quarkus.*/.*resteasy.*@.*$
- cpe:/a:redhat:resteasy
+ cpe:/a:redhat:resteasy:
^pkg:maven/org\.apache\.xmlgraphics/batik\-i18n@.*$
- cpe:/a:apache:batik
+ cpe:/a:apache:batik:
^pkg:maven\/com\.github\.anti-social[.\/]prometheus-kt.*$
- cpe:/a:prometheus:prometheus
+ cpe:/a:prometheus:prometheus:
^pkg:maven/com\.oracle\.database\.jdbc/.*@.*$
- cpe:/a:oracle:database
- cpe:/a:oracle:oracle_database
+ cpe:/a:oracle:database:
+ cpe:/a:oracle:oracle_database:
^pkg:maven/com\.oracle\.database\.security/.*@.*$
- cpe:/a:oracle:database
- cpe:/a:oracle:oracle_database
+ cpe:/a:oracle:database:
+ cpe:/a:oracle:oracle_database:
^pkg:maven/com\.oracle\.database\.ha/.*@.*$
- cpe:/a:oracle:database
- cpe:/a:oracle:oracle_database
+ cpe:/a:oracle:database:
+ cpe:/a:oracle:oracle_database:
^pkg:maven/io\.pivotal\.cfenv/.*@.*$
- cpe:/a:pivotal_software:spring_boot
- cpe:/a:pivotal_software:spring_framework
+ cpe:/a:pivotal_software:spring_boot:
+ cpe:/a:pivotal_software:spring_framework:
^pkg:maven/io\.qameta\.allure/allure\-httpclient@.*$
- cpe:/a:apache:httpclient
+ cpe:/a:apache:httpclient:
^pkg:maven/com\.google\.http\-client/google\-http\-client\-apache\-v2@.*$
- cpe:/a:apache:httpclient
+ cpe:/a:apache:httpclient:
^pkg:maven/com\.adobe\.aem/uber\-jar@.*$
- cpe:/a:adobe:experience_manager_forms
+ cpe:/a:adobe:experience_manager_forms:
^pkg:maven/com\.internetitem/logback\-elasticsearch\-appender@.*$
- cpe:/a:elasticsearch:elasticsearch
+ cpe:/a:elasticsearch:elasticsearch:
^pkg:maven/org\.exist\-db\.thirdparty\.xerces/xercesImpl@.*$
- cpe:/a:exist-db:exist
+ cpe:/a:exist-db:exist:
^pkg:pypi/.*python.*$
- cpe:/a:python:python
- cpe:/a:python_software_foundation:python
+ cpe:/a:python:python:
+ cpe:/a:python_software_foundation:python:
^pkg:pypi/python\-keycloak@.*$
- cpe:/a:keycloak:keycloak
+ cpe:/a:keycloak:keycloak:
^pkg:maven/org\.sonarsource\.java/.*$
- cpe:/a:sonarsource:sonarqube
+ cpe:/a:sonarsource:sonarqube:
^pkg:maven/org\.apache\.struts/struts\-annotations@.*$
- cpe:/a:apache:struts
+ cpe:/a:apache:struts:
@@ -3803,23 +3697,23 @@
broad suppressions for all cpan
]]>
^pkg:cpan/.*$
- cpe:/a:mysql:mysql
- cpe:/a:next:next
+ cpe:/a:mysql:mysql:
+ cpe:/a:next:next:
^pkg:cpan/(?!perl@).*$
- cpe:/a:perl:perl
+ cpe:/a:perl:perl:
^pkg:cpan/Catmandu%3A%3AStore/ElasticSearch@.*$
- cpe:/a:elastic:elasticsearch
- cpe:/a:elasticsearch:elasticsearch
+ cpe:/a:elastic:elasticsearch:
+ cpe:/a:elasticsearch:elasticsearch:
^pkg:cpan/Net/SSH2@.*$
- cpe:/a:ssh:ssh
+ cpe:/a:ssh:ssh:
^pkg:maven/com\.nimbusds/lang\-tag@.*$
- cpe:/a:nim-lang:nim-lang
+ cpe:/a:nim-lang:nim-lang:
^pkg:maven/org\.apache\.logging\.log4j/log4j\-api\-kotlin@.*$
- cpe:/a:apache:log4j
+ cpe:/a:apache:log4j:
^pkg:maven/javax\.xml\.crypto/jsr105-api@.*$
- cpe:/a:apache:xml_security_for_java
+ cpe:/a:apache:xml_security_for_java:
^pkg:maven/nginx\-clojure/nginx\-clojure@.*$
- cpe:/a:nginx:nginx
+ cpe:/a:nginx:nginx:
^pkg:maven/io\.netty/netty\-tcnative\-classes@.*$
- cpe:/a:netty:netty
+ cpe:/a:netty:netty:
^pkg:maven/io\.netty\.incubator/.*$
- cpe:/a:netty:netty
+ cpe:/a:netty:netty:
^pkg:maven/io\.projectreactor\.kafka/reactor\-kafka@[1-9]+?[\.]+(((([4-9]+)|[0-9]{2,3}?)+[\.]+[0-9]{1,3}?)|([3\.]+([2-9]|[1-9]+[0-9]+?)))+(.*)$
- cpe:/a:apache:kafka
+ cpe:/a:apache:kafka:
^pkg:maven/com\.itextpdf/pdfrender@.*$
- cpe:/a:itextpdf:itext
+ cpe:/a:itextpdf:itext:
^pkg:maven/org\.apache\.tomcat/annotations\-api@.*$
- cpe:/a:apache:tomcat
- cpe:/a:apache_tomcat:apache_tomcat
+ cpe:/a:apache:tomcat:
+ cpe:/a:apache_tomcat:apache_tomcat:
^pkg:maven/jakarta\.ws\.rs/jakarta\.ws\.rs-api@.*$
- cpe:/a:oracle:java_se
- cpe:/a:oracle:web_services
+ cpe:/a:oracle:java_se:
+ cpe:/a:oracle:web_services:
^pkg:maven/org\.graylog2/gelfclient@.*$
- cpe:/a:graylog:graylog
+ cpe:/a:graylog:graylog:
^pkg:maven/org\.mariadb\.jdbc/mariadb-java-client@.*$
- cpe:/a:mariadb:mariadb
+ cpe:/a:mariadb:mariadb:
^pkg:maven/org\.eclipse/yasson@.*$
- cpe:/a:oracle:projects
+ cpe:/a:oracle:projects:
^pkg:maven/org\.aspectj/aspectj.*@.*$
- cpe:/a:vmware:tools
+ cpe:/a:vmware:tools:
^pkg:maven/org\.apache\.kafka/kafka-log4j-appender@.*$
- cpe:/a:apache:log4j
- cpe:/a:apache:kafka
+ cpe:/a:apache:log4j:
+ cpe:/a:apache:kafka:
^pkg:maven/com\.lightbend\.akka\.management/akka-management-cluster-bootstrap_2\.13@.*$
- cpe:/a:akka:akka
+ cpe:/a:akka:akka:
^pkg:maven/io\.netty/netty-tcnative-boringssl-static@.*$
- cpe:/a:chromium:chromium
+ cpe:/a:chromium:chromium:
cpe:/a:chromium(_project)?:chromium.*
@@ -4018,35 +3912,35 @@
#4123, #4128, #4132, #4136, #4137, #4138, #4145, #4146
]]>
^pkg:maven/(?!org\.apache\.james/).*$
- cpe:/a:apache:james
+ cpe:/a:apache:james:
^pkg:maven/com\.ibm\.etcd/etcd\-java@.*$
- cpe:/a:etcd:etcd
+ cpe:/a:etcd:etcd:
^pkg:maven/org\.cryptomator/(?!cryptomator).*$
- cpe:/a:cryptomator:cryptomator
+ cpe:/a:cryptomator:cryptomator:
^pkg:maven/io\.quarkus/quarkus\-apache\-httpclient@.*$
- cpe:/a:apache:httpclient
+ cpe:/a:apache:httpclient:
^pkg:maven/com\.github\.blagerweij/liquibase-sessionlock@.*$
- cpe:/a:liquibase:liquibase
+ cpe:/a:liquibase:liquibase:
^pkg:maven/org\.typelevel/log4cats\-core_2\.13@.*$
- cpe:/a:davenport:davenport
- cpe:/a:protonmail:protonmail
+ cpe:/a:davenport:davenport:
+ cpe:/a:protonmail:protonmail:
^pkg:maven/org\.codehaus\.jackson/jackson-jaxrs@.*$
- cpe:/a:fasterxml:jackson-databind
+ cpe:/a:fasterxml:jackson-databind:
^pkg:maven/io\.minio/minio@.*$
- cpe:/a:minio:minio
+ cpe:/a:minio:minio:
^pkg:maven/ch\.qos\.reload4j/reload4j@.*$
- cpe:/a:apache:log4j
+ cpe:/a:apache:log4j:
^pkg:maven/com\.mattbertolini/liquibase-slf4j@.*$
- cpe:/a:liquibase:liquibase
+ cpe:/a:liquibase:liquibase:
^pkg:maven/com\.pinterest\.ktlint/ktlint-reporter-checkstyle@.*$
- cpe:/a:checkstyle:checkstyle
+ cpe:/a:checkstyle:checkstyle:
^pkg:maven/org\.apache\.james/apache\-mime4j\-dom@.*$
- cpe:/a:jdom:jdom
+ cpe:/a:jdom:jdom:
^pkg:maven/pl\.allegro\..*$
- cpe:/a:allegro:allegro
+ cpe:/a:allegro:allegro:
^pkg:maven/struts/struts-legacy@.*$
- cpe:/a:apache:struts
+ cpe:/a:apache:struts:
^pkg:maven/(org\.apache\.)?ant/ant\-apache\-log4j@.*$
- cpe:/a:apache:ant
- cpe:/a:apache:log4j
+ cpe:/a:apache:ant:
+ cpe:/a:apache:log4j:
^pkg:maven/io\.swagger\.codegen\.v3/swagger-codegen-generators@.*$
- cpe:/a:swagger:swagger-codegen
+ cpe:/a:swagger:swagger-codegen:
^pkg:maven/org\.flywaydb/.*$
- cpe:/a:mysql:mysql
- cpe:/a:firebird:firebird
+ cpe:/a:mysql:mysql:
+ cpe:/a:firebird:firebird:
^pkg:maven/org\.pac4j/ratpack\-pac4j@.*$
- cpe:/a:pac4j:pac4j
- cpe:/a:ratpack:ratpack
+ cpe:/a:pac4j:pac4j:
+ cpe:/a:ratpack:ratpack:
cpe:/a:ratpack(_project)?:ratpack.*
@@ -4201,102 +4095,102 @@
FP per issue #4440
]]>
^pkg:maven/org\.apache\.activemq/activeio\-core@.*$
- cpe:/a:apache:activemq
+ cpe:/a:apache:activemq:
^pkg:maven/org\.rxtx/rxtx@.*$
- cpe:/a:gnu:parallel
+ cpe:/a:gnu:parallel:
^pkg:maven/org\.iq80\.snappy/snappy@.*$
- cpe:/a:electrum:electrum
+ cpe:/a:electrum:electrum:
^pkg:maven/com\.lightbend\.akka\.management/akka\-.*@.*$
- cpe:/a:akka:akka
- cpe:/a:lightbend:akka
- cpe:/a:lightbend:akka-http
- cpe:/a:lightbend:akka_http
+ cpe:/a:akka:akka:
+ cpe:/a:lightbend:akka:
+ cpe:/a:lightbend:akka-http:
+ cpe:/a:lightbend:akka_http:
^pkg:maven/com\.lightbend\.akka\.discovery/akka\-.*@.*$
- cpe:/a:akka:akka
- cpe:/a:lightbend:akka
+ cpe:/a:akka:akka:
+ cpe:/a:lightbend:akka:
^pkg:maven/com\.google\.cloud/spring-cloud-gcp-starter-sql-postgresql@.*$
- cpe:/a:postgresql:postgresql
+ cpe:/a:postgresql:postgresql:
^pkg:maven/io\.github\.detekt\.sarif4k/sarif4k@.*$
- cpe:/a:detekt:detekt
+ cpe:/a:detekt:detekt:
^pkg:maven/com\.princexml/prince-java-wrapper@.*$
- cpe:/a:princexml:princexml
+ cpe:/a:princexml:princexml:
^pkg:maven/com\.google\.(?!code\.gson).*/.*gson.*$
- cpe:/a:google:gson
+ cpe:/a:google:gson:
^pkg:maven/com\.datastax\.cassandra/cassandra-driver-core@.*$
- cpe:/a:apache:cassandra
+ cpe:/a:apache:cassandra:
^pkg\:maven/io\.quarkus.*/quarkus\-liquibase(-[a-z]+)?@.*
- cpe:/a:liquibase:liquibase
+ cpe:/a:liquibase:liquibase:
^pkg\:maven/io\.quarkus/quarkus\-container\-image\-docker@.*
- cpe:/a:docker:docker
+ cpe:/a:docker:docker:
^pkg:maven/io\.quarkus/quarkus\-spring\-boot\-orm\-api@.*$
- cpe:/a:quarkus:quarkus
+ cpe:/a:quarkus:quarkus:
^pkg:maven/io\.quarkus/quarkus\-spring\-data\-(commons|jpa)\-api@.*$
- cpe:/a:quarkus:quarkus
+ cpe:/a:quarkus:quarkus:
^(?!(org\.)springframework).*:.*spring.*$
- cpe:/a:pivotal_software:spring_framework
- cpe:/a:springsource:spring_framework
- cpe:/a:vmware:spring_framework
- cpe:/a:vmware:springsource_spring_framework
+ cpe:/a:pivotal_software:spring_framework:
+ cpe:/a:springsource:spring_framework:
+ cpe:/a:vmware:spring_framework:
+ cpe:/a:vmware:springsource_spring_framework:
^pkg:maven/org\.apache\.axis2/axis2-xmlbeans@.*$
- cpe:/a:apache:xmlbeans
+ cpe:/a:apache:xmlbeans:
^pkg:maven/org\.apache\.tomcat/jakartaee-migration@.*$
- cpe:/a:apache:tomcat
+ cpe:/a:apache:tomcat:
^pkg:maven/tyrex/tyrex@.*$
- cpe:/a:sun:j2ee
+ cpe:/a:sun:j2ee:
^pkg:maven/io\.zipkin\.aws/brave-propagation-aws@.*$
- cpe:/a:brave:brave
+ cpe:/a:brave:brave:
^pkg:maven/io\.quarkus/quarkus-micrometer-registry-prometheus@.*$
- cpe:/a:prometheus:prometheus
+ cpe:/a:prometheus:prometheus:
^pkg:maven/org\.apache\.activemq/activemq\-artemis\-native@.*$
- cpe:/a:apache:activemq
- cpe:/a:apache:activemq_artemis
+ cpe:/a:apache:activemq:
+ cpe:/a:apache:activemq_artemis:
^pkg:maven/org\.springframework\..*$
- cpe:/a:springsource:spring_framework
- cpe:/a:pivotal:spring_framework
- cpe:/a:pivotal_software:spring_framework
- cpe:/a:vmware:springsource_spring_framework
- cpe:/a:vmware:spring_framework
+ cpe:/a:springsource:spring_framework:
+ cpe:/a:pivotal:spring_framework:
+ cpe:/a:pivotal_software:spring_framework:
+ cpe:/a:vmware:springsource_spring_framework:
+ cpe:/a:vmware:spring_framework:
@@ -4388,20 +4282,20 @@
False positive per #3622, #4561. Spring-boot-starter-oauth2-client gets flagged with wrong spring CPEs.
]]>
^pkg:maven/org\.springframework\.boot/spring\-boot\-starter\-oauth2\-client@.*$
- cpe:/a:pivotal:spring_security_oauth
- cpe:/a:pivotal:spring_security
- cpe:/a:pivotal_software:spring_security_oauth
- cpe:/a:pivotal_software:spring_security
- cpe:/a:vmware:spring_security
+ cpe:/a:pivotal:spring_security_oauth:
+ cpe:/a:pivotal:spring_security:
+ cpe:/a:pivotal_software:spring_security_oauth:
+ cpe:/a:pivotal_software:spring_security:
+ cpe:/a:vmware:spring_security:
^pkg:maven/org\.springframework\.boot/spring-boot-starter-security@.*$
- cpe:/a:pivotal_software:spring_security
- cpe:/a:vmware:spring_security
- cpe:/a:vmware:springsource_spring_security
+ cpe:/a:pivotal_software:spring_security:
+ cpe:/a:vmware:spring_security:
+ cpe:/a:vmware:springsource_spring_security:
@@ -4409,8 +4303,8 @@
Suppress false positives per #3400 and #4597
]]>
^pkg:maven/org\.springframework\.cloud/spring\-cloud\-(common\-)?security.*$
- cpe:/a:pivotal_software:spring_security
- cpe:/a:vmware:spring_security
+ cpe:/a:pivotal_software:spring_security:
+ cpe:/a:vmware:spring_security:
@@ -4418,10 +4312,10 @@
Suppresses false positives per issue #1665, #3219, #4562.
]]>
^pkg:maven/org\.springframework\.security/spring-security-rsa.*$
- cpe:/a:pivotal:spring_security_oauth
- cpe:/a:pivotal_software:spring_security
- cpe:/a:vmware:spring_security
- cpe:/a:vmware:springsource_spring_security
+ cpe:/a:pivotal:spring_security_oauth:
+ cpe:/a:pivotal_software:spring_security:
+ cpe:/a:vmware:spring_security:
+ cpe:/a:vmware:springsource_spring_security:
cpe:/a:security-framework(_project)?:security-framework.*
@@ -4429,9 +4323,9 @@
Spring Security JWT false positive.
]]>
^pkg:maven/org\.springframework\.security/spring-security-jwt.*$
- cpe:/a:vmware:springsource_spring_security
- cpe:/a:vmware:spring_security
- cpe:/a:pivotal_software:spring_security
+ cpe:/a:vmware:springsource_spring_security:
+ cpe:/a:vmware:spring_security:
+ cpe:/a:pivotal_software:spring_security:
cpe:/a:security-framework(_project)?:security-framework.*
@@ -4439,8 +4333,8 @@
Suppresses false positives per issue #1595
]]>
^pkg:maven/org\.springframework\.security/spring-security-jwt@.*$
- cpe:/a:pivotal:spring_security_oauth
- cpe:/a:pivotal_software:spring_security_oauth
+ cpe:/a:pivotal:spring_security_oauth:
+ cpe:/a:pivotal_software:spring_security_oauth:
cpe:/a:jwt(_project)?:jwt.*
@@ -4450,16 +4344,16 @@
]]>
^pkg:maven/org\.springframework\.security\.extensions/spring-security-saml2-core@.*$
cpe:/a:saml(_project)?:saml.*
- cpe:/a:vmware:spring_security
+ cpe:/a:vmware:spring_security:
^pkg:maven/org\.springframework\.security\.extensions/spring-security-saml.*$
- cpe:/a:pivotal_software:spring_security
- cpe:/a:vmware:springsource_spring_security
- cpe:/a:vmware:spring_security
+ cpe:/a:pivotal_software:spring_security:
+ cpe:/a:vmware:springsource_spring_security:
+ cpe:/a:vmware:spring_security:
cpe:/a:security-framework(_project)?:security-framework.*
@@ -4467,9 +4361,9 @@
Suppresses false positives per issue #2235, #4596, #4601
]]>
^pkg:maven/org\.springframework\.security\.kerberos/spring-security-kerberos.*$
- cpe:/a:pivotal_software:spring_security
- cpe:/a:vmware:springsource_spring_security
- cpe:/a:vmware:spring_security
+ cpe:/a:pivotal_software:spring_security:
+ cpe:/a:vmware:springsource_spring_security:
+ cpe:/a:vmware:spring_security:
cpe:/a:security-framework(_project)?:security-framework.*
@@ -4478,25 +4372,25 @@
Supress false positives per issue #1872, #4577
]]>
^pkg:maven/org\.springframework\.security\.oauth/spring-security-oauth2@.*$
- cpe:/a:pivotal_software:spring_security
- cpe:/a:vmware:spring_security
+ cpe:/a:pivotal_software:spring_security:
+ cpe:/a:vmware:spring_security:
^pkg:maven/org\.springframework\.security\.oauth\.boot/spring-security-oauth2-autoconfigure@.*$
- cpe:/a:pivotal_software:spring_boot
- cpe:/a:pivotal_software:spring_security
- cpe:/a:vmware:spring_security
+ cpe:/a:pivotal_software:spring_boot:
+ cpe:/a:pivotal_software:spring_security:
+ cpe:/a:vmware:spring_security:
^pkg:maven/org\.springframework\.security\.oauth\.boot/spring-security-oauth2-autoconfigure@.*$
- cpe:/a:pivotal_software:spring_security_oauth
- cpe:/a:pivotal:spring_security_oauth
+ cpe:/a:pivotal_software:spring_security_oauth:
+ cpe:/a:pivotal:spring_security_oauth:
@@ -4504,25 +4398,25 @@
spring-session has a different version numbering than spring-core. See #1399
]]>
^pkg:maven/org\.springframework\.session/spring-session-(core|data-).*$
- cpe:/a:pivotal_software:spring_security
- cpe:/a:vmware:spring_security
+ cpe:/a:pivotal_software:spring_security:
+ cpe:/a:vmware:spring_security:
^pkg:maven/org\.springframework\.session/spring\-session\-hazelcast@.*$
- cpe:/a:hazelcast:hazelcast
- cpe:/a:pivotal_software:spring_security
- cpe:/a:vmware:spring_security
+ cpe:/a:hazelcast:hazelcast:
+ cpe:/a:pivotal_software:spring_security:
+ cpe:/a:vmware:spring_security:
^pkg:maven/org\.springframework\.ws/spring\-ws\-security@.*$
- cpe:/a:vmware:spring_security
- cpe:/a:pivotal_software:spring_security
+ cpe:/a:vmware:spring_security:
+ cpe:/a:pivotal_software:spring_security:
@@ -4531,36 +4425,36 @@
FP per issues #4581, #4582
]]>
^pkg:maven/org\.springframework\.cloud/spring-cloud-dataflow-rest-.*$
- cpe:/a:vmware:spring_data_rest
- cpe:/a:pivotal_software:spring_data_rest
+ cpe:/a:vmware:spring_data_rest:
+ cpe:/a:pivotal_software:spring_data_rest:
^pkg:maven/org\.springframework\.cloud/spring\-cloud\-.*$
- cpe:/a:vmware:cloud_foundation
+ cpe:/a:vmware:cloud_foundation:
^pkg:maven/org\.springframework\.batch/spring\-batch\-infrastructure@.*$
- cpe:/a:vmware:infrastructure
+ cpe:/a:vmware:infrastructure:
^pkg:maven/org\.springframework\.boot/spring\-boot\-loader\-tools@.*$
- cpe:/a:vmware:tools
+ cpe:/a:vmware:tools:
^pkg:maven/org\.springframework\.security/spring.*$
- cpe:/a:mod_security:mod_security
+ cpe:/a:mod_security:mod_security:
CVE-2018-1258
@@ -4570,33 +4464,33 @@
being flagged as spring-data-rest with the wrong version number)
]]>
^pkg:maven/org\.springframework\.boot/spring-boot-starter-data-rest@.*$
- cpe:/a:pivotal_software:spring_data_rest
- cpe:/a:pivotal_software:spring_boot
+ cpe:/a:pivotal_software:spring_data_rest:
+ cpe:/a:pivotal_software:spring_boot:
^pkg:maven/org\.springframework\.boot/.*$
- cpe:/a:vmware:spring_integration
- cpe:/a:pivotal:spring_security_oauth
- cpe:/a:pivotal_software:spring_security
- cpe:/a:vmware:server
- cpe:/a:vmware:spring_security
+ cpe:/a:vmware:spring_integration:
+ cpe:/a:pivotal:spring_security_oauth:
+ cpe:/a:pivotal_software:spring_security:
+ cpe:/a:vmware:server:
+ cpe:/a:vmware:spring_security:
^pkg:maven/org\.springframework\.batch/spring\-batch\-integration@.*$
- cpe:/a:vmware:spring_integration
+ cpe:/a:vmware:spring_integration:
^pkg:maven/org\.springframework\.boot/spring\-boot\-starter\-web\-services@.*$
- cpe:/a:pivotal_software:spring_web_services
+ cpe:/a:pivotal_software:spring_web_services:
^pkg:maven/org\.springframework\.data/spring-data-mongodb.*$
- cpe:/a:mongodb:mongodb
+ cpe:/a:mongodb:mongodb:
^pkg:maven/org\.springframework\.(data|boot)/spring-(boot-starter-)?data-neo4j@.*$
- cpe:/a:neo4j:neo4j
+ cpe:/a:neo4j:neo4j:
^pkg:maven/org\.springframework\.data/spring-data-solr@.*$
- cpe:/a:apache:solr
+ cpe:/a:apache:solr:
^pkg:maven/org\.springframework\.social/spring-social-facebook@.*$
- cpe:/a:facebook:facebook
+ cpe:/a:facebook:facebook:
^pkg:maven/org\.springframework\.boot/spring\-boot\-starter\-batch@.*$
- cpe:/a:pivotal_software:spring_batch
+ cpe:/a:pivotal_software:spring_batch:
^pkg:maven/org\.springframework\.cloud/spring-cloud-.*$
cpe:/a:context(_project)?:context.*
- cpe:/a:pivotal_software:spring_batch
+ cpe:/a:pivotal_software:spring_batch:
^pkg:maven/org\.springframework\.boot/.*$
- cpe:/a:pivotal_software:spring_data_jpa
+ cpe:/a:pivotal_software:spring_data_jpa:
^pkg:maven/org\.springframework\.boot/spring-boot-starter-data-mongodb.*@.*$
- cpe:/a:mongodb:mongodb
- cpe:/a:vmware:spring_data_mongodb
+ cpe:/a:mongodb:mongodb:
+ cpe:/a:vmware:spring_data_mongodb:
^pkg:maven/org\.springframework\.boot/spring\-boot\-starter\-amqp@.*$
- cpe:/a:pivotal_software:rabbitmq
- cpe:/a:pivotal_software:spring_boot
- cpe:/a:vmware:rabbitmq
+ cpe:/a:pivotal_software:rabbitmq:
+ cpe:/a:pivotal_software:spring_boot:
+ cpe:/a:vmware:rabbitmq:
^pkg:maven/org\.springframework\.cloud/spring\-cloud\-(starter\-)?kubernetes\-fabric8\-(auto)?config@.*$
- cpe:/a:vmware:spring_cloud_config
+ cpe:/a:vmware:spring_cloud_config:
^pkg:maven/org\.springframework\.cloud/spring\-cloud\-deployer\-.*$
- cpe:/a:vmware:spring_cloud_config
- cpe:/a:vmware:spring_cloud_data_flow
+ cpe:/a:vmware:spring_cloud_config:
+ cpe:/a:vmware:spring_cloud_data_flow:
^pkg:maven/org\.springframework\.cloud/spring-cloud-kubernetes-fabric8-config@.*$
- cpe:/a:vmware:spring_cloud_config
+ cpe:/a:vmware:spring_cloud_config:
^pkg:maven/rubygems/jruby\-.*@.*$
- cpe:/a:jruby:jruby
+ cpe:/a:jruby:jruby:
^pkg:maven/rubygems/jruby\-openssl@.*$
- cpe:/a:openssl:openssl
+ cpe:/a:openssl:openssl:
^pkg:maven/io\.opentracing\.contrib/opentracing\-elasticsearch.*@.*$
- cpe:/a:elasticsearch:elasticsearch
+ cpe:/a:elasticsearch:elasticsearch:
^pkg:maven/com\.otaliastudios/zoomlayout@.*$
- cpe:/a:zoom:zoom
+ cpe:/a:zoom:zoom:
^pkg:maven/org\.apache\.hive/.*spark\-client@.*$
- cpe:/a:apache:spark
+ cpe:/a:apache:spark:
^pkg:maven/org\.apache\.twill/twill\-yarn@.*$
- cpe:/a:apache:hadoop
+ cpe:/a:apache:hadoop:
^pkg:maven/org\.apache\.ranger/ranger\-hive\-plugin@.*$
- cpe:/a:apache:hive
+ cpe:/a:apache:hive:
^pkg:maven/org\.apache\.hive/hive\-hbase\-handler@.*$
- cpe:/a:apache:hbase
+ cpe:/a:apache:hbase:
^pkg:maven/org\.apache\.hbase/hbase\-server@.*$
- cpe:/a:apache:http_server
+ cpe:/a:apache:http_server:
^pkg:cocoapods/GoogleUtilities%2FAppDelegateSwizzler@.*$
cpe:/a:app(_project)?:app.*
- cpe:/a:delegate:delegate
+ cpe:/a:delegate:delegate:
^pkg:maven/org\.springframework\.security/spring\-security\-oauth2\-authorization\-server@.*$
- cpe:/a:pivotal:spring_security_oauth
- cpe:/a:pivotal_software:spring_security
- cpe:/a:pivotal_software:spring_security_oauth
- cpe:/a:vmware:spring_security
- cpe:/a:vmware:server
- cpe:/a:vmware:vmware_server
+ cpe:/a:pivotal:spring_security_oauth:
+ cpe:/a:pivotal_software:spring_security:
+ cpe:/a:pivotal_software:spring_security_oauth:
+ cpe:/a:vmware:spring_security:
+ cpe:/a:vmware:server:
+ cpe:/a:vmware:vmware_server:
^pkg:maven/tailrecursion/cljs\-priority\-map@.*$
- cpe:/a:priority-software:priority
+ cpe:/a:priority-software:priority:
^pkg:maven/org\.clojure/data\.priority\-map@.*$
- cpe:/a:priority-software:priority
+ cpe:/a:priority-software:priority:
^pkg:maven/io\.quarkus/quarkus\-keycloak\-authorization@.*$
- cpe:/a:keycloak:keycloak
- cpe:/a:redhat:keycloak
+ cpe:/a:keycloak:keycloak:
+ cpe:/a:redhat:keycloak:
^(?!pkg:maven/commons-net/commons-net).*$
- cpe:/a:apache:commons_net
+ cpe:/a:apache:commons_net:
^pkg:maven/com\.google\.flatbuffers/flatbuffers-java@.*$
cpe:/a:flat(_project)?:flat.*
-
-
- ^pkg:maven/me\.dinowernli/java\-grpc\-prometheus@.*$
- cpe:/a:grpc:grpc
- cpe:/a:prometheus:prometheus
-
^pkg:pypi/.*docker.*$
- cpe:/a:docker:docker
+ cpe:/a:docker:docker:
^(?!pkg:maven/org.eclipse.platform).+$
- cpe:/a:eclipse:eclipse_ide
+ cpe:/a:eclipse:eclipse_ide:
^pkg:maven/cloud\.localstack/localstack-utils@.*$
- cpe:/a:utils(_project)?:utils
+ cpe:/a:utils(_project)?:utils:
^pkg:pypi/zabbix-utils@.*$
- cpe:/a:zabbix:zabbix
+ cpe:/a:zabbix:zabbix:
diff --git a/core/src/test/java/org/owasp/dependencycheck/BaseDBTestCase.java b/core/src/test/java/org/owasp/dependencycheck/BaseDBTestCase.java
index 4c0b7b10ebb..6a29dd07627 100644
--- a/core/src/test/java/org/owasp/dependencycheck/BaseDBTestCase.java
+++ b/core/src/test/java/org/owasp/dependencycheck/BaseDBTestCase.java
@@ -68,7 +68,7 @@ public void ensureDBExists() throws Exception {
if (!dataPath.exists() || !dataFile.exists()) {
LOGGER.trace("Extracting database to {}", dataPath);
dataPath.mkdirs();
- File path = new File(BaseDBTestCase.class.getClassLoader().getResource("data.zip").toURI().getPath());
+ File path = BaseTest.getResourceAsFile(this, "data.zip");
try (FileInputStream fis = new FileInputStream(path);
ZipInputStream zin = new ZipInputStream(new BufferedInputStream(fis))) {
ZipEntry entry;
diff --git a/core/src/test/java/org/owasp/dependencycheck/BaseTest.java b/core/src/test/java/org/owasp/dependencycheck/BaseTest.java
index daffc98c6da..a7b283a11dc 100644
--- a/core/src/test/java/org/owasp/dependencycheck/BaseTest.java
+++ b/core/src/test/java/org/owasp/dependencycheck/BaseTest.java
@@ -15,14 +15,19 @@
*/
package org.owasp.dependencycheck;
+import org.jspecify.annotations.NonNull;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.owasp.dependencycheck.utils.Settings;
import java.io.File;
+import java.io.IOException;
import java.io.InputStream;
+import java.net.MalformedURLException;
+import java.net.URI;
import java.net.URISyntaxException;
+import java.nio.charset.StandardCharsets;
import java.util.Objects;
/**
@@ -67,29 +72,70 @@ public static void tearDownClass() {
/**
* Returns the given resource as an InputStream using the object's class loader.
*
- * @param o the object used to obtain a reference to the class loader
+ * @param o the object used to obtain a reference to the class loader
* @param resource the name of the resource to load
* @return the resource as an InputStream
*/
- public static InputStream getResourceAsStream(Object o, String resource) {
+ public static @NonNull InputStream getResourceAsStream(Object o, String resource) {
return Objects.requireNonNull(o.getClass().getClassLoader().getResourceAsStream(resource), resource + " not found on classpath");
}
/**
* Returns the given resource as a File using the object's class loader.
*
- * @param o the object used to obtain a reference to the class loader
+ * @param o the object used to obtain a reference to the class loader
* @param resource the name of the resource to load
- * @return the resource as an File
+ * @return the resource as a File
*/
- public static File getResourceAsFile(Object o, String resource) {
+ public static @NonNull File getResourceAsFile(Object o, String resource) {
+ return new File(getResourceAsURI(o, resource).getPath());
+ }
+
+ /**
+ * Returns the given resource as a URI using the object's class loader.
+ *
+ * @param o the object used to obtain a reference to the class loader
+ * @param resource the name of the resource to load
+ * @return the resource as a URI
+ */
+ public static @NonNull URI getResourceAsURI(Object o, String resource) {
try {
- return new File(Objects.requireNonNull(o.getClass().getClassLoader().getResource(resource), resource + " not found on classpath").toURI().getPath());
+ return Objects.requireNonNull(o.getClass().getClassLoader().getResource(resource), resource + " not found on classpath").toURI();
} catch (URISyntaxException e) {
throw new UnsupportedOperationException(e);
}
}
+ /**
+ * Returns the given resource as a URL string using the object's class loader.
+ *
+ * @param o the object used to obtain a reference to the class loader
+ * @param resource the name of the resource to load
+ * @return the resource as a URL string
+ */
+ public static @NonNull String getResourceAsUrlString(Object o, String resource) {
+ try {
+ return getResourceAsURI(o, resource).toURL().toString();
+ } catch (MalformedURLException e) {
+ throw new UnsupportedOperationException(e);
+ }
+ }
+
+ /**
+ * Returns the given resource content using the object's class loader.
+ *
+ * @param o the object used to obtain a reference to the class loader
+ * @param resource the name of the resource to load
+ * @return the resource as a String
+ */
+ public static @NonNull String getResourceAsContentString(Object o, String resource) {
+ try (InputStream is = getResourceAsStream(o, resource)) {
+ return new String(is.readAllBytes(), StandardCharsets.UTF_8);
+ } catch (IOException e) {
+ throw new UnsupportedOperationException(e);
+ }
+ }
+
/**
* @return the settings for the test cases.
*/
diff --git a/core/src/test/java/org/owasp/dependencycheck/analyzer/AbstractSuppressionAnalyzerTest.java b/core/src/test/java/org/owasp/dependencycheck/analyzer/AbstractSuppressionAnalyzerTest.java
index 619a54cbe7b..88677f9cd9d 100644
--- a/core/src/test/java/org/owasp/dependencycheck/analyzer/AbstractSuppressionAnalyzerTest.java
+++ b/core/src/test/java/org/owasp/dependencycheck/analyzer/AbstractSuppressionAnalyzerTest.java
@@ -18,30 +18,33 @@
package org.owasp.dependencycheck.analyzer;
import org.jspecify.annotations.NonNull;
-import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.ValueSource;
import org.owasp.dependencycheck.BaseTest;
import org.owasp.dependencycheck.Engine;
import org.owasp.dependencycheck.Engine.Mode;
+import org.owasp.dependencycheck.data.update.HostedSuppressionsDataSource;
import org.owasp.dependencycheck.dependency.Dependency;
import org.owasp.dependencycheck.exception.InitializationException;
import org.owasp.dependencycheck.utils.Downloader;
import org.owasp.dependencycheck.utils.InvalidSettingException;
import org.owasp.dependencycheck.utils.Settings;
import org.owasp.dependencycheck.utils.Settings.KEYS;
+import org.owasp.dependencycheck.xml.suppression.SuppressionParseException;
import org.owasp.dependencycheck.xml.suppression.SuppressionRule;
import java.util.List;
-import java.util.Set;
import java.util.stream.Collectors;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.empty;
+import static org.hamcrest.Matchers.greaterThan;
import static org.hamcrest.Matchers.not;
import static org.junit.jupiter.api.Assertions.assertEquals;
-import static org.junit.jupiter.api.Assertions.assertNull;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.owasp.dependencycheck.analyzer.AbstractSuppressionAnalyzer.SUPPRESSION_OBJECT_KEY;
@@ -53,84 +56,154 @@ class AbstractSuppressionAnalyzerTest extends BaseTest {
/**
* A second suppression file to test with.
*/
- private static final String OTHER_SUPPRESSIONS_FILE = "other-suppressions.xml";
+ private static final String OTHER_TEST_SUPPRESSIONS_FILE = "other-suppressions.xml";
/**
* Suppression file to test with.
*/
- private static final String SUPPRESSIONS_FILE = "suppressions.xml";
+ private static final String TEST_SUPPRESSIONS_FILE = "suppressions.xml";
+ private static final int TEST_SUPPRESSIONS_EXPECTED_COUNT = 5;
- private AbstractSuppressionAnalyzer instance;
+ private Engine engine;
- @BeforeEach
- void createObjectUnderTest() {
- instance = new AbstractSuppressionAnalyzerImpl();
+ @AfterEach
+ void cleanUp() {
+ if (engine != null) {
+ new HostedSuppressionsDataSource().purge(engine);
+ engine.close();
+ }
}
- /**
- * Test of getSupportedExtensions method, of class
- * AbstractSuppressionAnalyzer.
- */
- @Test
- void testGetSupportedExtensions() {
- Set result = instance.getSupportedExtensions();
- assertNull(result);
+ private String testSuppressionsFileUrl() {
+ return BaseTest.getResourceAsUrlString(this, TEST_SUPPRESSIONS_FILE);
}
- /**
- * Test of getRules method, of class AbstractSuppressionAnalyzer for
- * suppression file declared as URL.
- */
- @Test
- void testGetRulesFromSuppressionFileFromURL() throws Exception {
- final String fileUrl = getClass().getClassLoader().getResource(SUPPRESSIONS_FILE).toURI().toURL().toString();
- final int numberOfExtraLoadedRules = getNumberOfRulesLoadedFromPath(fileUrl) - getNumberOfRulesLoadedInCoreFile();
- assertEquals(5, numberOfExtraLoadedRules, "Expected 5 extra rules in the given path");
+ @Nested
+ class BasePackagedSuppressionsLoading {
+ @Test
+ void packagedBaseSuppressions() throws Exception {
+ prepareBaseSuppressionsOnly();
+ @SuppressWarnings("unchecked") List rules = (List) engine.getObject(SUPPRESSION_OBJECT_KEY);
+ assertThat(rules, not(empty()));
+ assertThat("Expected all suppressions in base file to be marked as base", allRulesNotMarkedAsBase(rules), empty());
+ }
}
- /**
- * Test of getRules method, of class AbstractSuppressionAnalyzer for
- * suppression file on the class path.
- */
- @Test
- void testGetRulesFromSuppressionFileInClasspath() throws Exception {
- final int numberOfExtraLoadedRules = getNumberOfRulesLoadedFromPath(SUPPRESSIONS_FILE) - getNumberOfRulesLoadedInCoreFile();
- assertEquals(5, numberOfExtraLoadedRules, "Expected 5 extra rules in the given file");
- }
+ @Nested
+ class HostedSuppressionsLoading {
+ @Test
+ void packagedSnapshotHostedSuppressionsLoadedEvenIfRemoteHostedSuppressionsDisabled() throws Exception {
+ getSettings().setBoolean(KEYS.HOSTED_SUPPRESSIONS_ENABLED, false);
+ prepareHostedSuppressionsOnly();
+ @SuppressWarnings("unchecked") List rules = (List) engine.getObject(SUPPRESSION_OBJECT_KEY);
+ assertThat(rules, not(empty()));
+ assertThat("Expected all suppressions in hosted suppressions snapshot file to be marked as base", allRulesNotMarkedAsBase(rules), empty());
+ }
- /**
- * Assert that rules are loaded from multiple files if multiple files are
- * defined in the {@link Settings}.
- */
- @Test
- void testGetRulesFromMultipleSuppressionFiles() throws Exception {
- final int rulesInCoreFile = getNumberOfRulesLoadedInCoreFile();
-
- // GIVEN suppression rules from one file
- final int rulesInFirstFile = getNumberOfRulesLoadedFromPath(SUPPRESSIONS_FILE) - rulesInCoreFile;
-
- // AND suppression rules from another file
- final int rulesInSecondFile = getNumberOfRulesLoadedFromPath(OTHER_SUPPRESSIONS_FILE) - rulesInCoreFile;
-
- // WHEN initializing with both suppression files
- final String[] suppressionFiles = {SUPPRESSIONS_FILE, OTHER_SUPPRESSIONS_FILE};
- getSettings().setArrayIfNotEmpty(KEYS.SUPPRESSION_FILE, suppressionFiles);
- instance.initialize(getSettings());
- Engine engine = new Engine(getSettings());
- instance.prepare(engine);
-
- // THEN rules from both files were loaded
- final int expectedSize = rulesInFirstFile + rulesInSecondFile + rulesInCoreFile;
- assertThat("Expected suppressions from both files", instance.getRuleCount(engine), is(expectedSize));
+ @Test
+ void packagedSnapshotHostedSuppressionsLoadedIfAutoUpdateDisabled() throws Exception {
+ getSettings().setBoolean(KEYS.HOSTED_SUPPRESSIONS_ENABLED, true);
+ getSettings().setBoolean(KEYS.AUTO_UPDATE, false);
+ prepareHostedSuppressionsOnly();
+ assertThat(AbstractSuppressionAnalyzer.getRuleCount(engine), greaterThan(0));
+ }
+ @Test
+ void packagedSnapshotHostedSuppressionsLoadedIfRemoteHostedSuppressionsFail() throws Exception {
+ getSettings().setBoolean(KEYS.HOSTED_SUPPRESSIONS_ENABLED, true);
+ getSettings().setBoolean(KEYS.AUTO_UPDATE, true);
+ getSettings().setString(KEYS.HOSTED_SUPPRESSIONS_URL, "file:///does-not-exist.xml");
+ prepareHostedSuppressionsOnly();
+ assertThat(AbstractSuppressionAnalyzer.getRuleCount(engine), greaterThan(0));
+ }
+
+ @ParameterizedTest
+ @ValueSource(booleans = {true, false})
+ void ignoresHostedSuppressionsIfUrlDoesntIncludeAFileNameRegardlessOfEnabledState(boolean hostedSuppressionsEnabled) throws Exception {
+ getSettings().setBoolean(KEYS.HOSTED_SUPPRESSIONS_ENABLED, hostedSuppressionsEnabled);
+ getSettings().setString(KEYS.HOSTED_SUPPRESSIONS_URL, "https://valid.url.but.no.file/");
+ prepareHostedSuppressionsOnly();
+ assertThat(AbstractSuppressionAnalyzer.getRuleCount(engine), is(0));
+ }
+
+ @Test
+ void ignoresHostedSuppressionsIfCannotBeParsedFromRemote() throws Exception {
+ getSettings().setBoolean(KEYS.HOSTED_SUPPRESSIONS_ENABLED, true);
+ getSettings().setString(KEYS.HOSTED_SUPPRESSIONS_URL, BaseTest.getResourceAsUrlString(this, "suppressions-invalid.xml"));
+ prepareHostedSuppressionsOnly();
+ assertThat(AbstractSuppressionAnalyzer.getRuleCount(engine), is(0));
+ }
+
+ @Test
+ void prefersRemoteHostedSuppressionsIfEnabled() throws Exception {
+ getSettings().setBoolean(KEYS.HOSTED_SUPPRESSIONS_ENABLED, true);
+ getSettings().setBoolean(KEYS.AUTO_UPDATE, true);
+ getSettings().setString(KEYS.HOSTED_SUPPRESSIONS_URL, testSuppressionsFileUrl());
+ prepareHostedSuppressionsOnly();
+ assertThat(AbstractSuppressionAnalyzer.getRuleCount(engine), is(TEST_SUPPRESSIONS_EXPECTED_COUNT));
+ }
+
+ @Test
+ void prefersRemoteHostedSuppressionsIfEnabledAndForced() throws Exception {
+ getSettings().setBoolean(KEYS.HOSTED_SUPPRESSIONS_ENABLED, true);
+ getSettings().setBoolean(KEYS.AUTO_UPDATE, false);
+ getSettings().setBoolean(KEYS.HOSTED_SUPPRESSIONS_FORCEUPDATE, true);
+ getSettings().setString(KEYS.HOSTED_SUPPRESSIONS_URL, testSuppressionsFileUrl());
+ prepareHostedSuppressionsOnly();
+ assertThat(AbstractSuppressionAnalyzer.getRuleCount(engine), is(TEST_SUPPRESSIONS_EXPECTED_COUNT));
+ }
}
- @Test
- void testFailureToLocateSuppressionFileAnywhere() {
- getSettings().setString(Settings.KEYS.SUPPRESSION_FILE, "doesnotexist.xml");
- instance.initialize(getSettings());
- Engine engine = new Engine(Mode.EVIDENCE_COLLECTION, getSettings());
- assertThrows(InitializationException.class, () ->
- instance.prepare(engine));
+ @Nested
+ class UserSuppressionsLoading {
+ /**
+ * Test of getRules method, of class AbstractSuppressionAnalyzer for
+ * suppression file declared as URL.
+ */
+ @Test
+ void testGetRulesFromSuppressionFileFromURL() throws Exception {
+ final int numberOfExtraLoadedRules = getNumberOfRulesLoadedFromPath(testSuppressionsFileUrl()) - getNumberOfRulesLoadedInCoreFile();
+ assertEquals(TEST_SUPPRESSIONS_EXPECTED_COUNT, numberOfExtraLoadedRules, "Wrong # of expected extra user suppression rules");
+ }
+
+ /**
+ * Test of getRules method, of class AbstractSuppressionAnalyzer for
+ * suppression file on the class path.
+ */
+ @Test
+ void testGetRulesFromSuppressionFileInClasspath() throws Exception {
+ final int numberOfExtraLoadedRules = getNumberOfRulesLoadedFromPath(TEST_SUPPRESSIONS_FILE) - getNumberOfRulesLoadedInCoreFile();
+ assertEquals(TEST_SUPPRESSIONS_EXPECTED_COUNT, numberOfExtraLoadedRules, "Wrong # of expected extra user suppression rules");
+ }
+
+ /**
+ * Assert that rules are loaded from multiple files if multiple files are
+ * defined in the {@link Settings}.
+ */
+ @Test
+ void testGetRulesFromMultipleSuppressionFiles() throws Exception {
+ final int rulesInCoreFile = getNumberOfRulesLoadedInCoreFile();
+
+ // GIVEN suppression rules from one file
+ final int rulesInFirstFile = getNumberOfRulesLoadedFromPath(TEST_SUPPRESSIONS_FILE) - rulesInCoreFile;
+
+ // AND suppression rules from another file
+ final int rulesInSecondFile = getNumberOfRulesLoadedFromPath(OTHER_TEST_SUPPRESSIONS_FILE) - rulesInCoreFile;
+
+ // WHEN initializing with both suppression files
+ final String[] suppressionFiles = {TEST_SUPPRESSIONS_FILE, OTHER_TEST_SUPPRESSIONS_FILE};
+ getSettings().setArrayIfNotEmpty(KEYS.SUPPRESSION_FILE, suppressionFiles);
+ prepareSuppressions();
+
+ // THEN rules from both files were loaded
+ final int expectedSize = rulesInFirstFile + rulesInSecondFile + rulesInCoreFile;
+ assertThat("Expected suppressions from both files", AbstractSuppressionAnalyzer.getRuleCount(engine), is(expectedSize));
+ }
+
+ @Test
+ void testFailureToLocateSuppressionFileAnywhere() {
+ getSettings().setString(Settings.KEYS.SUPPRESSION_FILE, "doesnotexist.xml");
+ assertThrows(InitializationException.class, AbstractSuppressionAnalyzerTest.this::prepareSuppressions);
+ }
}
/**
@@ -142,7 +215,7 @@ void testFailureToLocateSuppressionFileAnywhere() {
*/
private int getNumberOfRulesLoadedInCoreFile() throws Exception {
getSettings().removeProperty(KEYS.SUPPRESSION_FILE);
- Engine engine = prepareSuppressions();
+ prepareSuppressions();
return AbstractSuppressionAnalyzer.getRuleCount(engine);
}
@@ -156,70 +229,51 @@ private int getNumberOfRulesLoadedInCoreFile() throws Exception {
*/
private int getNumberOfRulesLoadedFromPath(final String path) throws Exception {
getSettings().setString(KEYS.SUPPRESSION_FILE, path);
- Engine engine = prepareSuppressions();
+ prepareSuppressions();
return AbstractSuppressionAnalyzer.getRuleCount(engine);
}
- private @NonNull Engine prepareSuppressions() throws InvalidSettingException, InitializationException {
- final AbstractSuppressionAnalyzerImpl fileAnalyzer = new AbstractSuppressionAnalyzerImpl();
- fileAnalyzer.initialize(getSettings());
- Downloader.getInstance().configure(getSettings());
- Engine engine = new Engine(Mode.EVIDENCE_COLLECTION, getSettings());
- fileAnalyzer.prepare(engine);
- return engine;
+ private void prepareSuppressions() throws InvalidSettingException, InitializationException {
+ engine = new Engine(Mode.EVIDENCE_COLLECTION, getSettings());
+ newAnalyzer().prepare(engine);
}
- @Nested
- class CoreSuppressionsLoading {
- @Test
- void testLoadCorePackagedSuppressions() throws Exception {
- List baseRules = assertAllBaseSuppressionRulesAreMarkedCorrectly();
-
- assertAllHostedSnapshotSuppressionsAreMarkedAsBase(baseRules);
- }
-
- private @NonNull List assertAllBaseSuppressionRulesAreMarkedCorrectly() throws InvalidSettingException, InitializationException {
- getSettings().setBoolean(KEYS.HOSTED_SUPPRESSIONS_ENABLED, false);
- Engine engine = prepareSuppressions();
-
- @SuppressWarnings("unchecked") List baseRules = (List) engine.getObject(SUPPRESSION_OBJECT_KEY);
- assertThat(baseRules, not(empty()));
- assertThat("Expected all suppressions in base file to be marked as base", allRulesNotMarkedAsBase(baseRules), empty());
- return baseRules;
- }
-
- private void assertAllHostedSnapshotSuppressionsAreMarkedAsBase(List baseRules) throws InvalidSettingException, InitializationException {
- getSettings().setBoolean(KEYS.HOSTED_SUPPRESSIONS_ENABLED, true);
- getSettings().setString(KEYS.HOSTED_SUPPRESSIONS_URL, "https://intentionally-bad-url/hosted-suppressions.xml");
- Engine engine = prepareSuppressions();
+ private void prepareBaseSuppressionsOnly() throws InvalidSettingException, SuppressionParseException {
+ engine = new Engine(Mode.EVIDENCE_COLLECTION, getSettings());
+ newAnalyzer().loadPackagedBaseSuppressionData(engine);
+ }
- @SuppressWarnings("unchecked") List allRules = (List) engine.getObject(SUPPRESSION_OBJECT_KEY);
+ private void prepareHostedSuppressionsOnly() throws InvalidSettingException {
+ engine = new Engine(Mode.EVIDENCE_COLLECTION, getSettings());
+ newAnalyzer().loadHostedSuppressionBaseData(engine);
+ }
- List hostedSnapshotRules = allRules.stream().filter(r -> !baseRules.contains(r)).collect(Collectors.toList());
- assertThat(hostedSnapshotRules, not(empty()));
- assertThat("Expected all suppressions in hosted suppressions snapshot file to be marked as base", allRulesNotMarkedAsBase(hostedSnapshotRules), empty());
- }
+ private @NonNull AbstractSuppressionAnalyzerImpl newAnalyzer() throws InvalidSettingException {
+ final AbstractSuppressionAnalyzerImpl fileAnalyzer = new AbstractSuppressionAnalyzerImpl();
+ fileAnalyzer.initialize(getSettings());
+ Downloader.getInstance().configure(getSettings());
+ return fileAnalyzer;
+ }
- private @NonNull List allRulesNotMarkedAsBase(List baseRules) {
- return baseRules.stream().filter(r -> !r.isBase()).collect(Collectors.toList());
- }
+ private @NonNull List allRulesNotMarkedAsBase(List baseRules) {
+ return baseRules.stream().filter(r -> !r.isBase()).collect(Collectors.toList());
}
public static class AbstractSuppressionAnalyzerImpl extends AbstractSuppressionAnalyzer {
@Override
public void analyzeDependency(Dependency dependency, Engine engine) {
- throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
+ throw new UnsupportedOperationException("Not supported yet.");
}
@Override
public String getName() {
- throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
+ throw new UnsupportedOperationException("Not supported yet.");
}
@Override
public AnalysisPhase getAnalysisPhase() {
- throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
+ throw new UnsupportedOperationException("Not supported yet.");
}
@Override
diff --git a/core/src/test/java/org/owasp/dependencycheck/analyzer/RetireJsAnalyzerIT.java b/core/src/test/java/org/owasp/dependencycheck/analyzer/RetireJsAnalyzerIT.java
index d750ce04fcd..bd7e9edd7ec 100644
--- a/core/src/test/java/org/owasp/dependencycheck/analyzer/RetireJsAnalyzerIT.java
+++ b/core/src/test/java/org/owasp/dependencycheck/analyzer/RetireJsAnalyzerIT.java
@@ -151,7 +151,6 @@ void testAngular() throws Exception {
"CVE-2022-25869",
"CVE-2024-8373",
"CVE-2025-0716",
- "CVE-2025-2336",
"DOS in $sanitize",
"GHSA-28hp-fgcr-2r4h",
"GHSA-5cp4-xmrw-59wf",
diff --git a/core/src/test/java/org/owasp/dependencycheck/analyzer/RetireJsAnalyzerTest.java b/core/src/test/java/org/owasp/dependencycheck/analyzer/RetireJsAnalyzerTest.java
new file mode 100644
index 00000000000..ca3bc5e3388
--- /dev/null
+++ b/core/src/test/java/org/owasp/dependencycheck/analyzer/RetireJsAnalyzerTest.java
@@ -0,0 +1,143 @@
+/*
+ * This file is part of dependency-check-core.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * Copyright (c) 2026 Chad Wilson. All Rights Reserved.
+ */
+package org.owasp.dependencycheck.analyzer;
+
+import org.apache.commons.lang3.exception.ExceptionUtils;
+import org.json.JSONException;
+import org.jspecify.annotations.NonNull;
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Nested;
+import org.junit.jupiter.api.Test;
+import org.owasp.dependencycheck.BaseTest;
+import org.owasp.dependencycheck.Engine;
+import org.owasp.dependencycheck.data.update.RetireJSDataSource;
+import org.owasp.dependencycheck.exception.InitializationException;
+import org.owasp.dependencycheck.utils.Downloader;
+import org.owasp.dependencycheck.utils.InvalidSettingException;
+import org.owasp.dependencycheck.utils.Settings;
+
+import java.nio.file.NoSuchFileException;
+
+import static org.hamcrest.CoreMatchers.is;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.containsString;
+import static org.hamcrest.Matchers.instanceOf;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+
+class RetireJsAnalyzerTest extends BaseTest {
+ private static final String TEST_RETIRE_JS_REPOSITORY_FILE = "retirejs/jsrepository.json";
+
+ private RetireJsAnalyzer analyzer;
+ private Engine engine;
+
+ @BeforeEach
+ void settings() {
+ getSettings().setBoolean(Settings.KEYS.ANALYZER_RETIREJS_ENABLED, true);
+ getSettings().setBoolean(Settings.KEYS.ANALYZER_RETIREJS_FORCEUPDATE, false);
+ getSettings().setString(Settings.KEYS.ANALYZER_RETIREJS_REPO_JS_URL, testRepositoryFileUrl());
+ }
+
+ @AfterEach
+ void cleanUp() {
+ if (engine != null) {
+ new RetireJSDataSource().purge(engine);
+ engine.close();
+ }
+ }
+
+ private String testRepositoryFileUrl() {
+ return BaseTest.getResourceAsUrlString(this, TEST_RETIRE_JS_REPOSITORY_FILE);
+ }
+
+ @Nested
+ class RepositoryLoading {
+
+ @Test
+ void loadsRemoteIfEmptyWithAutoUpdateDisabled() throws Exception {
+ getSettings().setBoolean(Settings.KEYS.AUTO_UPDATE, false);
+ prepareRetireJs();
+ assertThat(analyzer.knownLibraryCountFor("retire-example-0.0.1.js").orElseThrow(), is(1));
+ }
+
+ @Test
+ void loadsRemoteIfPresentAndForced() throws Exception {
+ prepareRetireJs();
+
+ // try again with repo present; but with a URL that will fail when invoked so we know it tried
+ getSettings().setBoolean(Settings.KEYS.ANALYZER_RETIREJS_FORCEUPDATE, true);
+ getSettings().setString(Settings.KEYS.ANALYZER_RETIREJS_REPO_JS_URL, testRepositoryFileUrl().replace(TEST_RETIRE_JS_REPOSITORY_FILE, "doesnt-exist/" + TEST_RETIRE_JS_REPOSITORY_FILE));
+
+ var ex = assertThrows(InitializationException.class, RetireJsAnalyzerTest.this::prepareRetireJs);
+ assertThat(ex.getMessage(), containsString("Failed to initialize the RetireJS repo"));
+ assertThat(ExceptionUtils.getRootCause(ex), instanceOf(NoSuchFileException.class));
+ }
+
+ @Test
+ void doesNothingIfPresentAndAutoUpdateDisabled() throws Exception {
+ prepareRetireJs();
+
+ getSettings().setBoolean(Settings.KEYS.AUTO_UPDATE, false);
+ getSettings().setBoolean(Settings.KEYS.ANALYZER_RETIREJS_FORCEUPDATE, false);
+
+ // try again with repo present; but with a URL that would fail if invoked
+ getSettings().setString(Settings.KEYS.ANALYZER_RETIREJS_REPO_JS_URL, testRepositoryFileUrl().replace(TEST_RETIRE_JS_REPOSITORY_FILE, "doesnt-exist/" + TEST_RETIRE_JS_REPOSITORY_FILE));
+ prepareRetireJs();
+ }
+
+ @Test
+ void failsIfRemoteRetireJsRepoNotFound() {
+ getSettings().setBoolean(Settings.KEYS.AUTO_UPDATE, true);
+ getSettings().setString(Settings.KEYS.ANALYZER_RETIREJS_REPO_JS_URL, "file:///does-not-exist.xml");
+ var ex = assertThrows(InitializationException.class, RetireJsAnalyzerTest.this::prepareRetireJs);
+ assertThat(ex.getMessage(), containsString("Failed to initialize the RetireJS repo"));
+ assertThat(ExceptionUtils.getRootCause(ex), instanceOf(NoSuchFileException.class));
+ assertThat(analyzer.isEnabled(), is(false));
+ }
+
+ @Test
+ void failsIfRemoteRetireJsCannotBeParsed() {
+ getSettings().setString(Settings.KEYS.ANALYZER_RETIREJS_REPO_JS_URL, BaseTest.getResourceAsUrlString(this, "retirejs/jsrepository-invalid.json"));
+ var ex = assertThrows(InitializationException.class, RetireJsAnalyzerTest.this::prepareRetireJs);
+ assertThat(ex.getMessage(), containsString("Failed to initialize the RetireJS repo"));
+ assertThat(ExceptionUtils.getRootCause(ex), instanceOf(JSONException.class));
+ assertThat(analyzer.isEnabled(), is(false));
+ }
+
+ @Test
+ void prefersRemoteRetireJsIfEnabled() throws Exception {
+ getSettings().setBoolean(Settings.KEYS.AUTO_UPDATE, true);
+ getSettings().setString(Settings.KEYS.ANALYZER_RETIREJS_REPO_JS_URL, testRepositoryFileUrl());
+ prepareRetireJs();
+ assertThat(analyzer.knownLibraryCountFor("retire-example-0.0.1.js").orElseThrow(), is(1));
+ }
+ }
+
+ private void prepareRetireJs() throws InvalidSettingException, InitializationException {
+ engine = new Engine(Engine.Mode.EVIDENCE_COLLECTION, getSettings());
+ analyzer = newAnalyzer();
+ analyzer.prepareFileTypeAnalyzer(engine);
+ }
+
+ private @NonNull RetireJsAnalyzer newAnalyzer() throws InvalidSettingException {
+ final RetireJsAnalyzer fileAnalyzer = new RetireJsAnalyzer();
+ fileAnalyzer.initialize(getSettings());
+ Downloader.getInstance().configure(getSettings());
+ return fileAnalyzer;
+ }
+}
\ No newline at end of file
diff --git a/core/src/test/java/org/owasp/dependencycheck/analyzer/YarnAuditAnalyzerIT.java b/core/src/test/java/org/owasp/dependencycheck/analyzer/YarnAuditAnalyzerIT.java
index 32b1c1a6439..c3474e96086 100644
--- a/core/src/test/java/org/owasp/dependencycheck/analyzer/YarnAuditAnalyzerIT.java
+++ b/core/src/test/java/org/owasp/dependencycheck/analyzer/YarnAuditAnalyzerIT.java
@@ -63,7 +63,6 @@ void testAnalyzePackageYarnClassic() throws Exception {
testAnalyzeForUglifyJs("yarn/yarn-classic-audit/yarn.lock");
}
- @Disabled("broken test case on my local machine - needs further investigation")
@Test
void testAnalyzePackageYarnClassicOnYarnBerryLockfile() {
AnalysisException exception = assertThrows(AnalysisException.class, () -> testAnalyzeForUglifyJs("yarn/yarn-classic-audit-bad-berry-lockfile/yarn.lock"));
diff --git a/core/src/test/java/org/owasp/dependencycheck/data/update/HostedSuppressionsDataSourceTest.java b/core/src/test/java/org/owasp/dependencycheck/data/update/HostedSuppressionsDataSourceTest.java
new file mode 100644
index 00000000000..530e112df46
--- /dev/null
+++ b/core/src/test/java/org/owasp/dependencycheck/data/update/HostedSuppressionsDataSourceTest.java
@@ -0,0 +1,223 @@
+/*
+ * This file is part of dependency-check-core.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * Copyright (c) 2026 Chad Wilson. All Rights Reserved.
+ */
+package org.owasp.dependencycheck.data.update;
+
+import org.jspecify.annotations.NonNull;
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Nested;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.ValueSource;
+import org.owasp.dependencycheck.BaseTest;
+import org.owasp.dependencycheck.Engine;
+import org.owasp.dependencycheck.data.update.exception.UpdateException;
+import org.owasp.dependencycheck.utils.InvalidSettingException;
+import org.owasp.dependencycheck.utils.Settings;
+
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.attribute.FileTime;
+
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.containsString;
+import static org.hamcrest.Matchers.instanceOf;
+import static org.hamcrest.Matchers.is;
+import static org.hamcrest.Matchers.not;
+import static org.junit.jupiter.api.Assertions.assertThrowsExactly;
+
+class HostedSuppressionsDataSourceTest extends BaseTest {
+
+ private static final String TEST_SUPPRESSIONS_FILE = "suppressions.xml";
+
+ private HostedSuppressionsDataSource dataSource;
+ private Engine engine;
+
+ @BeforeEach
+ public void createEngine() {
+ dataSource = new HostedSuppressionsDataSource();
+ engine = new Engine(Engine.Mode.EVIDENCE_COLLECTION, getSettings());
+ }
+
+ @AfterEach
+ void closeEngine() {
+ if (engine != null) {
+ dataSource.purge(engine);
+ engine.close();
+ }
+ }
+
+ @Nested
+ class Update {
+ @Test
+ void doesNothingIfRemoteHostedSuppressionsDisabled() throws Exception {
+ getSettings().setBoolean(Settings.KEYS.HOSTED_SUPPRESSIONS_ENABLED, false);
+ dataSource.update(engine);
+ assertNoCachedHostedSuppressions();
+ }
+
+ @Test
+ void doesNothingIfNoSuppressionAnalyzersEnabled() throws Exception {
+ getSettings().setBoolean(Settings.KEYS.HOSTED_SUPPRESSIONS_ENABLED, true);
+ getSettings().setBoolean(Settings.KEYS.ANALYZER_VULNERABILITY_SUPPRESSION_ENABLED, false);
+ getSettings().setBoolean(Settings.KEYS.ANALYZER_CPE_SUPPRESSION_ENABLED, false);
+ dataSource.update(engine);
+ assertNoCachedHostedSuppressions();
+ }
+
+ @Test
+ void doesNothingIfAutoUpdateDisabled() throws Exception {
+ getSettings().setBoolean(Settings.KEYS.HOSTED_SUPPRESSIONS_ENABLED, true);
+ getSettings().setBoolean(Settings.KEYS.AUTO_UPDATE, false);
+ getSettings().setBoolean(Settings.KEYS.HOSTED_SUPPRESSIONS_FORCEUPDATE, false);
+ dataSource.update(engine);
+ assertNoCachedHostedSuppressions();
+ }
+
+ @Test
+ void ignoresHostedSuppressionsIfRemoteHostedSuppressionsFail() throws Exception {
+ getSettings().setBoolean(Settings.KEYS.HOSTED_SUPPRESSIONS_ENABLED, true);
+ getSettings().setBoolean(Settings.KEYS.AUTO_UPDATE, true);
+ getSettings().setString(Settings.KEYS.HOSTED_SUPPRESSIONS_URL, "file:///does-not-exist.xml");
+ dataSource.update(engine);
+ assertNoCachedHostedSuppressions();
+ }
+
+ @ParameterizedTest
+ @ValueSource(booleans = {true, false})
+ void failsIfSuppressionsUrlDoesntIncludeAFileNameRegardlessOfEnabledState(boolean hostedSuppressionsEnabled) throws Exception {
+ getSettings().setBoolean(Settings.KEYS.HOSTED_SUPPRESSIONS_ENABLED, hostedSuppressionsEnabled);
+ getSettings().setString(Settings.KEYS.HOSTED_SUPPRESSIONS_URL, "https://valid.url.but.no.file/");
+ var ex = assertThrowsExactly(UpdateException.class, () -> dataSource.update(engine));
+ assertThat(ex.getMessage(), containsString("Unable to determine the local location to cache hosted suppressions"));
+ assertThat(ex.getCause(), instanceOf(InvalidSettingException.class));
+ assertThat(ex.getCause().getMessage(), containsString("Hosted Suppression URL must imply a filename"));
+ }
+
+ @Test
+ void failsIfSuppressionsUrlIsMalformed() {
+ getSettings().setBoolean(Settings.KEYS.HOSTED_SUPPRESSIONS_ENABLED, true);
+ getSettings().setString(Settings.KEYS.HOSTED_SUPPRESSIONS_URL, "bad-url");
+ var ex = assertThrowsExactly(UpdateException.class, () -> dataSource.update(engine));
+ assertThat(ex.getMessage(), containsString("Unable to determine the local location to cache hosted suppressions"));
+ assertThat(ex.getCause(), instanceOf(InvalidSettingException.class));
+ assertThat(ex.getCause().getMessage(), containsString("Invalid URL for Hosted Suppressions"));
+ }
+
+ @Test
+ void loadsRemoteHostedSuppressionsIfEnabledAndForced() throws Exception {
+ getSettings().setBoolean(Settings.KEYS.HOSTED_SUPPRESSIONS_ENABLED, true);
+ getSettings().setBoolean(Settings.KEYS.AUTO_UPDATE, false);
+ getSettings().setBoolean(Settings.KEYS.HOSTED_SUPPRESSIONS_FORCEUPDATE, true);
+ getSettings().setString(Settings.KEYS.HOSTED_SUPPRESSIONS_URL, testSuppressionsFileUrl());
+ dataSource.update(engine);
+ assertThat(Files.readString(cachedRepoFile()), is(testSuppressionsFileContent()));
+ assertThat(Files.exists(cachedRepoFileProperties()), is(true));
+ }
+
+ @Test
+ void loadsRemoteHostedSuppressionsIfEnabledWithAutoUpdate() throws Exception {
+ getSettings().setBoolean(Settings.KEYS.HOSTED_SUPPRESSIONS_ENABLED, true);
+ getSettings().setBoolean(Settings.KEYS.AUTO_UPDATE, true);
+ getSettings().setString(Settings.KEYS.HOSTED_SUPPRESSIONS_URL, testSuppressionsFileUrl());
+ dataSource.update(engine);
+ assertThat(Files.readString(cachedRepoFile()), is(testSuppressionsFileContent()));
+ assertThat(Files.exists(cachedRepoFileProperties()), is(true));
+ }
+
+ @Test
+ void doesNothingIfRemoteHostedSuppressionsIsNotStale() throws Exception {
+ getSettings().setBoolean(Settings.KEYS.HOSTED_SUPPRESSIONS_ENABLED, true);
+ getSettings().setBoolean(Settings.KEYS.AUTO_UPDATE, true);
+ getSettings().setString(Settings.KEYS.HOSTED_SUPPRESSIONS_URL, testSuppressionsFileUrl());
+ getSettings().setInt(Settings.KEYS.HOSTED_SUPPRESSIONS_VALID_FOR_HOURS, 1);
+ dataSource.update(engine);
+
+ // Update again immediately
+ String firstUpdateProperties = Files.readString(cachedRepoFileProperties());
+ FileTime firstUpdatePropertiesModified = Files.getLastModifiedTime(cachedRepoFileProperties());
+ dataSource.update(engine);
+
+ assertThat(Files.readString(cachedRepoFileProperties()), is(firstUpdateProperties));
+ assertThat(Files.getLastModifiedTime(cachedRepoFileProperties()), is(firstUpdatePropertiesModified));
+ }
+
+ @Test
+ void reloadsRemoteHostedSuppressionsIfStale() throws Exception {
+ getSettings().setBoolean(Settings.KEYS.HOSTED_SUPPRESSIONS_ENABLED, true);
+ getSettings().setBoolean(Settings.KEYS.AUTO_UPDATE, true);
+ getSettings().setString(Settings.KEYS.HOSTED_SUPPRESSIONS_URL, testSuppressionsFileUrl());
+ getSettings().setInt(Settings.KEYS.HOSTED_SUPPRESSIONS_VALID_FOR_HOURS, 0);
+ dataSource.update(engine);
+
+ // Reset to force an update
+ Files.writeString(cachedRepoFile(), "stale content");
+
+ dataSource.update(engine);
+ assertThat(Files.readString(cachedRepoFile()), not("stale content"));
+ }
+ }
+
+ @Nested
+ class Purge {
+ @Test
+ void purgeRemovesCachedFiles() throws Exception {
+ getSettings().setBoolean(Settings.KEYS.HOSTED_SUPPRESSIONS_ENABLED, true);
+ getSettings().setBoolean(Settings.KEYS.AUTO_UPDATE, true);
+ getSettings().setString(Settings.KEYS.HOSTED_SUPPRESSIONS_URL, testSuppressionsFileUrl());
+ dataSource.update(engine);
+
+ assertThat(Files.exists(cachedRepoFile()), is(true));
+ dataSource.purge(engine);
+ assertThat(Files.exists(cachedRepoFile()), is(false));
+ }
+
+ @Test
+ void doesNothingIfNoCachedFile() throws Exception {
+ dataSource.purge(engine);
+ assertThat(Files.exists(cachedRepoFile()), is(false));
+ }
+
+ @Test
+ void doesNothingIfSuppressionsUrlIsMalformed() {
+ getSettings().setString(Settings.KEYS.HOSTED_SUPPRESSIONS_URL, "bad-url");
+ dataSource.purge(engine);
+ }
+ }
+
+ private @NonNull Path cachedRepoFile() throws IOException {
+ return dataSource.validatedRepoFile().toPath();
+ }
+
+ private @NonNull Path cachedRepoFileProperties() throws IOException {
+ return Path.of(cachedRepoFile() + ".properties");
+ }
+
+ private @NonNull String testSuppressionsFileUrl() {
+ return BaseTest.getResourceAsUrlString(this, TEST_SUPPRESSIONS_FILE);
+ }
+
+ private @NonNull String testSuppressionsFileContent() {
+ return BaseTest.getResourceAsContentString(this, TEST_SUPPRESSIONS_FILE);
+ }
+
+ private void assertNoCachedHostedSuppressions() throws IOException {
+ assertThat("hosted suppression repo file should not exist", dataSource.validatedRepoFile().exists(), is(false));
+ }
+}
diff --git a/core/src/test/java/org/owasp/dependencycheck/data/update/RetireJSDataSourceTest.java b/core/src/test/java/org/owasp/dependencycheck/data/update/RetireJSDataSourceTest.java
new file mode 100644
index 00000000000..e9f07856f8f
--- /dev/null
+++ b/core/src/test/java/org/owasp/dependencycheck/data/update/RetireJSDataSourceTest.java
@@ -0,0 +1,233 @@
+/*
+ * This file is part of dependency-check-core.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * Copyright (c) 2026 Chad Wilson. All Rights Reserved.
+ */
+package org.owasp.dependencycheck.data.update;
+
+import org.apache.commons.lang3.exception.ExceptionUtils;
+import org.jspecify.annotations.NonNull;
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Nested;
+import org.junit.jupiter.api.Test;
+import org.owasp.dependencycheck.BaseTest;
+import org.owasp.dependencycheck.Engine;
+import org.owasp.dependencycheck.data.update.exception.UpdateException;
+import org.owasp.dependencycheck.utils.InvalidSettingException;
+import org.owasp.dependencycheck.utils.Settings;
+
+import java.net.MalformedURLException;
+import java.nio.file.Files;
+import java.nio.file.NoSuchFileException;
+import java.nio.file.Path;
+import java.nio.file.attribute.FileTime;
+
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.containsString;
+import static org.hamcrest.Matchers.instanceOf;
+import static org.hamcrest.Matchers.is;
+import static org.hamcrest.Matchers.not;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.junit.jupiter.api.Assertions.assertThrowsExactly;
+
+class RetireJSDataSourceTest extends BaseTest {
+ private static final String TEST_RETIRE_JS_REPOSITORY_FILE = "retirejs/jsrepository.json";
+
+ private RetireJSDataSource dataSource;
+ private Engine engine;
+
+ @BeforeEach
+ public void createEngine() {
+ dataSource = new RetireJSDataSource();
+ engine = new Engine(Engine.Mode.EVIDENCE_COLLECTION, getSettings());
+ }
+
+ @AfterEach
+ void closeEngine() {
+ if (engine != null) {
+ dataSource.purge(engine);
+ engine.close();
+ }
+ }
+
+ @Nested
+ class Update {
+ @Test
+ void doesNothingIfRetireJsDisabled() throws Exception {
+ getSettings().setBoolean(Settings.KEYS.ANALYZER_RETIREJS_ENABLED, false);
+ dataSource.update(engine);
+ assertNoCachedRetireJs();
+ }
+
+ @Test
+ void loadsRemoteIfEmptyWithAutoUpdateDisabled() throws Exception {
+ getSettings().setBoolean(Settings.KEYS.ANALYZER_RETIREJS_ENABLED, true);
+ getSettings().setBoolean(Settings.KEYS.AUTO_UPDATE, false);
+ dataSource.update(engine);
+ assertCachedRetireJs();
+ }
+
+ @Test
+ void doesNothingIfPresentAndAutoUpdateDisabled() throws Exception {
+ dataSource.update(engine);
+
+ getSettings().setBoolean(Settings.KEYS.ANALYZER_RETIREJS_ENABLED, true);
+ getSettings().setBoolean(Settings.KEYS.AUTO_UPDATE, false);
+ getSettings().setBoolean(Settings.KEYS.ANALYZER_RETIREJS_FORCEUPDATE, false);
+
+ // try again with repo present; but with a URL that would fail if invoked
+ getSettings().setString(Settings.KEYS.ANALYZER_RETIREJS_REPO_JS_URL, testRepositoryFileUrl().replace(TEST_RETIRE_JS_REPOSITORY_FILE, "doesnt-exist/" + TEST_RETIRE_JS_REPOSITORY_FILE));
+ dataSource.update(engine);
+ }
+
+ @Test
+ void failsIfRemoteRetireJsRepoNotFound() throws Exception {
+ getSettings().setBoolean(Settings.KEYS.ANALYZER_RETIREJS_ENABLED, true);
+ getSettings().setBoolean(Settings.KEYS.AUTO_UPDATE, true);
+ getSettings().setString(Settings.KEYS.ANALYZER_RETIREJS_REPO_JS_URL, "file:///does-not-exist.xml");
+ var ex = assertThrows(UpdateException.class, () -> dataSource.update(engine));
+ assertThat(ex.getMessage(), containsString("Failed to initialize the RetireJS repo"));
+ assertThat(ExceptionUtils.getRootCause(ex), instanceOf(NoSuchFileException.class));
+ assertNoCachedRetireJs();
+ }
+
+ @Test
+ void failsIfUrlDoesntIncludeAFileName() {
+ getSettings().setBoolean(Settings.KEYS.ANALYZER_RETIREJS_ENABLED, true);
+ getSettings().setString(Settings.KEYS.ANALYZER_RETIREJS_REPO_JS_URL, "https://valid.url.but.no.file/");
+ var ex = assertThrowsExactly(UpdateException.class, () -> dataSource.update(engine));
+ assertThat(ex.getMessage(), containsString("Unable to determine the local location to cache"));
+ assertThat(ex.getCause(), instanceOf(InvalidSettingException.class));
+ assertThat(ex.getCause().getMessage(), containsString("RetireJS URL must imply a filename"));
+ }
+
+ @Test
+ void failsIfUrlIsMalformed() {
+ getSettings().setBoolean(Settings.KEYS.ANALYZER_RETIREJS_ENABLED, true);
+ getSettings().setString(Settings.KEYS.ANALYZER_RETIREJS_REPO_JS_URL, "bad-url");
+ var ex = assertThrowsExactly(UpdateException.class, () -> dataSource.update(engine));
+ assertThat(ex.getMessage(), containsString("Invalid URL for RetireJS repository (bad-url)"));
+ assertThat(ex.getCause(), instanceOf(MalformedURLException.class));
+ }
+
+ @Test
+ void loadsRemoteRetireJsIfEnabledAndForced() throws Exception {
+ getSettings().setBoolean(Settings.KEYS.ANALYZER_RETIREJS_ENABLED, true);
+ getSettings().setBoolean(Settings.KEYS.AUTO_UPDATE, false);
+ getSettings().setBoolean(Settings.KEYS.ANALYZER_RETIREJS_FORCEUPDATE, true);
+ getSettings().setString(Settings.KEYS.ANALYZER_RETIREJS_REPO_JS_URL, testRepositoryFileUrl());
+ dataSource.update(engine);
+
+ // try again with repo present; but with a URL that fails when invoked
+ getSettings().setString(Settings.KEYS.ANALYZER_RETIREJS_REPO_JS_URL, testRepositoryFileUrl().replace(TEST_RETIRE_JS_REPOSITORY_FILE, "doesnt-exist/" + TEST_RETIRE_JS_REPOSITORY_FILE));
+ var ex = assertThrowsExactly(UpdateException.class, () -> dataSource.update(engine));
+ assertThat(ExceptionUtils.getRootCause(ex), instanceOf(NoSuchFileException.class));
+ }
+
+ @Test
+ void loadsRemoteRetireJsIfEnabledWithAutoUpdate() throws Exception {
+ getSettings().setBoolean(Settings.KEYS.ANALYZER_RETIREJS_ENABLED, true);
+ getSettings().setBoolean(Settings.KEYS.AUTO_UPDATE, true);
+ getSettings().setString(Settings.KEYS.ANALYZER_RETIREJS_REPO_JS_URL, testRepositoryFileUrl());
+ dataSource.update(engine);
+ assertThat(Files.readString(cachedRepoFile()), is(testRepositoryFileContent()));
+ assertThat(Files.exists(cachedRepoFileProperties()), is(true));
+ }
+
+ @Test
+ void doesNothingIfRemoteRetireJsIsNotStale() throws Exception {
+ getSettings().setBoolean(Settings.KEYS.ANALYZER_RETIREJS_ENABLED, true);
+ getSettings().setBoolean(Settings.KEYS.AUTO_UPDATE, true);
+ getSettings().setString(Settings.KEYS.ANALYZER_RETIREJS_REPO_JS_URL, testRepositoryFileUrl());
+ getSettings().setInt(Settings.KEYS.ANALYZER_RETIREJS_REPO_VALID_FOR_HOURS, 1);
+ dataSource.update(engine);
+
+ // Update again immediately
+ String firstUpdateProperties = Files.readString(cachedRepoFileProperties());
+ FileTime firstUpdatePropertiesModified = Files.getLastModifiedTime(cachedRepoFileProperties());
+ dataSource.update(engine);
+
+ assertThat(Files.readString(cachedRepoFileProperties()), is(firstUpdateProperties));
+ assertThat(Files.getLastModifiedTime(cachedRepoFileProperties()), is(firstUpdatePropertiesModified));
+ }
+
+ @Test
+ void reloadsRemoteRetireJsIfStale() throws Exception {
+ getSettings().setBoolean(Settings.KEYS.ANALYZER_RETIREJS_ENABLED, true);
+ getSettings().setBoolean(Settings.KEYS.AUTO_UPDATE, true);
+ getSettings().setString(Settings.KEYS.ANALYZER_RETIREJS_REPO_JS_URL, testRepositoryFileUrl());
+ getSettings().setInt(Settings.KEYS.ANALYZER_RETIREJS_REPO_VALID_FOR_HOURS, 0);
+ dataSource.update(engine);
+
+ // Reset to force an update
+ Files.writeString(cachedRepoFile(), "stale content");
+
+ dataSource.update(engine);
+ assertThat(Files.readString(cachedRepoFile()), not("stale content"));
+ }
+ }
+
+ @Nested
+ class Purge {
+ @Test
+ void purgeRemovesCachedFiles() throws Exception {
+ getSettings().setBoolean(Settings.KEYS.ANALYZER_RETIREJS_ENABLED, true);
+ getSettings().setBoolean(Settings.KEYS.AUTO_UPDATE, true);
+ getSettings().setString(Settings.KEYS.ANALYZER_RETIREJS_REPO_JS_URL, testRepositoryFileUrl());
+ dataSource.update(engine);
+
+ assertThat(Files.exists(cachedRepoFile()), is(true));
+ dataSource.purge(engine);
+ assertThat(Files.exists(cachedRepoFile()), is(false));
+ }
+
+ @Test
+ void doesNothingIfNoCachedFile() throws Exception {
+ dataSource.purge(engine);
+ assertThat(Files.exists(cachedRepoFile()), is(false));
+ }
+
+ @Test
+ void doesNothingIfUrlIsMalformed() {
+ getSettings().setString(Settings.KEYS.ANALYZER_RETIREJS_REPO_JS_URL, "bad-url");
+ dataSource.purge(engine);
+ }
+ }
+
+ private @NonNull Path cachedRepoFile() throws UpdateException {
+ return dataSource.validatedRepoFile().toPath();
+ }
+
+ private @NonNull Path cachedRepoFileProperties() throws UpdateException {
+ return Path.of(cachedRepoFile() + ".properties");
+ }
+
+ private @NonNull String testRepositoryFileUrl() {
+ return BaseTest.getResourceAsUrlString(this, TEST_RETIRE_JS_REPOSITORY_FILE);
+ }
+
+ private @NonNull String testRepositoryFileContent() {
+ return BaseTest.getResourceAsContentString(this, TEST_RETIRE_JS_REPOSITORY_FILE);
+ }
+
+ private void assertNoCachedRetireJs() throws UpdateException {
+ assertThat("RetireJS repo file should not exist", dataSource.validatedRepoFile().exists(), is(false));
+ }
+
+ private void assertCachedRetireJs() throws UpdateException {
+ assertThat("RetireJS repo file should exist", dataSource.validatedRepoFile().exists(), is(true));
+ }
+}
diff --git a/core/src/test/resources/retirejs/jsrepository-invalid.json b/core/src/test/resources/retirejs/jsrepository-invalid.json
new file mode 100644
index 00000000000..e076eea9296
--- /dev/null
+++ b/core/src/test/resources/retirejs/jsrepository-invalid.json
@@ -0,0 +1,3 @@
+{
+ "bad": "syntax"
+}
diff --git a/core/src/test/resources/retirejs/jsrepository.json b/core/src/test/resources/retirejs/jsrepository.json
new file mode 100644
index 00000000000..1dcaf60ee7f
--- /dev/null
+++ b/core/src/test/resources/retirejs/jsrepository.json
@@ -0,0 +1,37 @@
+{
+ "retire-example": {
+ "vulnerabilities": [
+ {
+ "below": "0.0.2",
+ "severity": "low",
+ "cwe": [
+ "CWE-477"
+ ],
+ "identifiers": {
+ "summary": "bug summary",
+ "CVE": [
+ "CVE-XXXX-XXXX"
+ ],
+ "bug": "1234"
+ },
+ "info": [
+ "http://github.com/eoftedal/retire.js/"
+ ]
+ }
+ ],
+ "extractors": {
+ "func": [
+ "retire.VERSION"
+ ],
+ "filename": [
+ "retire-example-(§§version§§)(.min)?\\.js"
+ ],
+ "filecontent": [
+ "/\\*!? Retire-example v(§§version§§)"
+ ],
+ "hashes": {
+ "07f8b94c8d601a24a1914a1a92bec0e4fafda964": "0.0.1"
+ }
+ }
+ }
+}
diff --git a/core/src/test/resources/suppressions-invalid.xml b/core/src/test/resources/suppressions-invalid.xml
new file mode 100644
index 00000000000..efd7b9ead1e
--- /dev/null
+++ b/core/src/test/resources/suppressions-invalid.xml
@@ -0,0 +1,7 @@
+
+
+
+
\ No newline at end of file
diff --git a/core/src/test/resources/yarn/yarn-classic-audit-bad-berry-lockfile/package.json b/core/src/test/resources/yarn/yarn-classic-audit-bad-berry-lockfile/package.json
index d46b8308f70..fb923d5d14d 100644
--- a/core/src/test/resources/yarn/yarn-classic-audit-bad-berry-lockfile/package.json
+++ b/core/src/test/resources/yarn/yarn-classic-audit-bad-berry-lockfile/package.json
@@ -5,7 +5,7 @@
"description": "A tool to learn OWASP Top 10 for node.js developers",
"main": "server.js",
"dependencies": {
- "mime-db": "^1.52.0"
+ "does-not-exist": "file:../does-not-exist"
},
"scripts": {
"start": "node server.js",
@@ -14,5 +14,6 @@
"precommit": "grunt precommit"
},
"repository": "https://github.com/OWASP/NodejsGoat",
- "license": "Apache 2.0"
+ "license": "Apache 2.0",
+ "packageManager": "yarn@1.22.22"
}
diff --git a/core/src/test/resources/yarn/yarn-classic-audit/package.json b/core/src/test/resources/yarn/yarn-classic-audit/package.json
index b2fc8eaf8f0..ba0bfadbfed 100644
--- a/core/src/test/resources/yarn/yarn-classic-audit/package.json
+++ b/core/src/test/resources/yarn/yarn-classic-audit/package.json
@@ -57,5 +57,6 @@
"zaproxy": "^0.2.0"
},
"repository": "https://github.com/OWASP/NodejsGoat",
- "license": "Apache 2.0"
+ "license": "Apache 2.0",
+ "packageManager": "yarn@1.22.22"
}
diff --git a/maven/src/main/java/org/owasp/dependencycheck/maven/BaseDependencyCheckMojo.java b/maven/src/main/java/org/owasp/dependencycheck/maven/BaseDependencyCheckMojo.java
index dc9d19085b2..f45828eb5fd 100644
--- a/maven/src/main/java/org/owasp/dependencycheck/maven/BaseDependencyCheckMojo.java
+++ b/maven/src/main/java/org/owasp/dependencycheck/maven/BaseDependencyCheckMojo.java
@@ -1158,7 +1158,7 @@ public abstract class BaseDependencyCheckMojo extends AbstractMojo implements Ma
@Parameter(property = "hostedSuppressionsForceUpdate")
private Boolean hostedSuppressionsForceUpdate;
/**
- * Whether the hosted suppressions file will be used.
+ * Whether the hosted suppressions will be updated from the configured URL.
*/
@SuppressWarnings("CanBeFinal")
@Parameter(property = "hostedSuppressionsEnabled")
diff --git a/maven/src/site/markdown/configuration.md b/maven/src/site/markdown/configuration.md
index e750b170b93..68a79397c11 100644
--- a/maven/src/site/markdown/configuration.md
+++ b/maven/src/site/markdown/configuration.md
@@ -175,7 +175,7 @@ Note that any passwords in the below configuration could be exposed if you use `
| serverId | The id of a server defined in the settings.xml; this can be used to encrypt the database password. See [password encryption](http://maven.apache.org/guides/mini/guide-encryption.html) for more information. | |
| databaseUser | The username used when connecting to the database. | |
| databasePassword | The password used when connecting to the database. | |
-| hostedSuppressionsEnabled | Whether the hosted suppressions file will be used. | true |
+| hostedSuppressionsEnabled | Whether the hosted suppressions will be updated from the configured URL. | true |
| hostedSuppressionsForceUpdate | Whether the hosted suppressions file will update regardless of the `autoupdate` setting. | false |
| hostedSuppressionsUrl | The URL to a mirrored copy of the hosted suppressions file for internet-constrained environments. | https://dependency-check.github.io/DependencyCheck/suppressions/publishedSuppressions.xml |
| hostedSuppressionsValidForHours | Sets the number of hours to wait before checking for new updates of the hosted suppressions file. | 2 |
diff --git a/pom.xml b/pom.xml
index be6afa2003e..f30ee01530a 100644
--- a/pom.xml
+++ b/pom.xml
@@ -434,9 +434,9 @@ Copyright (c) 2012 - Jeremy Long
- pl.project13.maven
- git-commit-id-plugin
- 4.9.10
+ io.github.git-commit-id
+ git-commit-id-maven-plugin
+ 10.0.0
git-info
diff --git a/src/site/markdown/dependency-check-gradle/configuration-aggregate.md b/src/site/markdown/dependency-check-gradle/configuration-aggregate.md
index 9776a6003a5..a93d5ec9592 100644
--- a/src/site/markdown/dependency-check-gradle/configuration-aggregate.md
+++ b/src/site/markdown/dependency-check-gradle/configuration-aggregate.md
@@ -90,7 +90,7 @@ The following properties can be configured in the dependencyCheck task. However,
| data | password | The password used when connecting to the database. | |
| slack | enabled | Whether or not slack notifications are enabled. | false |
| slack | webhookUrl | The custom incoming webhook URL to receive notifications. Note that the current implementation only notifies about build failures so this should be used in combination with failBuildOnCVSS. | |
-| hostedSuppressions | enabled | Whether the hosted suppressions file will be used. | true |
+| hostedSuppressions | enabled | Whether the hosted suppressions will be updated from the configured URL. | true |
| hostedSuppressions | forceupdate | Sets whether hosted suppressions file will update regardless of the `autoupdate` setting. | false |
| hostedSuppressions | url | The URL to a mirrored copy of the hosted suppressions file for internet-constrained environments. | https://dependency-check.github.io/DependencyCheck/suppressions/publishedSuppressions.xml |
| hostedSuppressions | user | Credentials used for basic authentication for the hosted suppressions file. | |
diff --git a/src/site/markdown/dependency-check-gradle/configuration-update.md b/src/site/markdown/dependency-check-gradle/configuration-update.md
index 17d6fc9ca42..2406e3123c7 100644
--- a/src/site/markdown/dependency-check-gradle/configuration-update.md
+++ b/src/site/markdown/dependency-check-gradle/configuration-update.md
@@ -62,7 +62,7 @@ The following properties can be configured in the dependencyCheck task. However,
| data | connectionString | The connection string used to connect to the database. See using a [database server](../data/database.html). | |
| data | username | The username used when connecting to the database. | |
| data | password | The password used when connecting to the database. | |
-| hostedSuppressions | enabled | Whether the hosted suppressions file will be used. | true |
+| hostedSuppressions | enabled | Whether the hosted suppressions will be updated from the configured URL. | true |
| hostedSuppressions | forceupdate | Sets whether hosted suppressions file will update regardless of the `autoupdate` setting. | false |
| hostedSuppressions | url | The URL to (a mirror of) the hosted suppressions file. | https://dependency-check.github.io/DependencyCheck/suppressions/publishedSuppressions.xml |
| hostedSuppressions | user | Credentials used for basic authentication for the hosted suppressions file. | |
diff --git a/src/site/markdown/dependency-check-gradle/configuration.md b/src/site/markdown/dependency-check-gradle/configuration.md
index dbc8495dc1a..8e0d4bdd781 100644
--- a/src/site/markdown/dependency-check-gradle/configuration.md
+++ b/src/site/markdown/dependency-check-gradle/configuration.md
@@ -90,7 +90,7 @@ The following properties can be configured in the dependencyCheck task. However,
| data | password | The password used when connecting to the database. | |
| slack | enabled | Whether or not slack notifications are enabled. | false |
| slack | webhookUrl | The custom incoming webhook URL to receive notifications. Note that the current implementation only notifies about build failures so this should be used in combination with failBuildOnCVSS. | |
-| hostedSuppressions | enabled | Whether the hosted suppressions file will be used. | true |
+| hostedSuppressions | enabled | Whether the hosted suppressions will be updated from the configured URL. | true |
| hostedSuppressions | forceupdate | Sets whether hosted suppressions file will update regardless of the `autoupdate` setting. | false |
| hostedSuppressions | url | The URL to a mirrored copy of the hosted suppressions file for internet-constrained environments. | https://dependency-check.github.io/DependencyCheck/suppressions/publishedSuppressions.xml |
| hostedSuppressions | user | Credentials used for basic authentication for the hosted suppressions file. | |
diff --git a/utils/src/main/java/org/owasp/dependencycheck/utils/FileUtils.java b/utils/src/main/java/org/owasp/dependencycheck/utils/FileUtils.java
index 88428dee453..5a55f16ad72 100644
--- a/utils/src/main/java/org/owasp/dependencycheck/utils/FileUtils.java
+++ b/utils/src/main/java/org/owasp/dependencycheck/utils/FileUtils.java
@@ -17,6 +17,14 @@
*/
package org.owasp.dependencycheck.utils;
+import org.apache.commons.io.FilenameUtils;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.commons.lang3.SystemUtils;
+import org.jspecify.annotations.NonNull;
+import org.jspecify.annotations.Nullable;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
import java.io.Closeable;
import java.io.File;
import java.io.FileInputStream;
@@ -30,14 +38,6 @@
import java.util.UUID;
import java.util.stream.Stream;
-import org.apache.commons.io.FilenameUtils;
-import org.apache.commons.lang3.StringUtils;
-import org.apache.commons.lang3.SystemUtils;
-import org.jspecify.annotations.NonNull;
-import org.jspecify.annotations.Nullable;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
/**
* A collection of utilities for processing information about files.
*
@@ -195,4 +195,12 @@ public static File getResourceAsFile(final String resource) {
}
return new File(path);
}
+
+ /**
+ * @param file the file to check
+ * @return true if the passed file is a file with more than 1 byte of content
+ */
+ public static boolean existsWithContent(@NonNull File file) {
+ return file.isFile() && file.length() > 1;
+ }
}
diff --git a/utils/src/test/java/org/owasp/dependencycheck/utils/FileUtilsTest.java b/utils/src/test/java/org/owasp/dependencycheck/utils/FileUtilsTest.java
index 5c63b668099..35918b7fe56 100644
--- a/utils/src/test/java/org/owasp/dependencycheck/utils/FileUtilsTest.java
+++ b/utils/src/test/java/org/owasp/dependencycheck/utils/FileUtilsTest.java
@@ -18,12 +18,17 @@
package org.owasp.dependencycheck.utils;
import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.io.TempDir;
import java.io.File;
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.owasp.dependencycheck.utils.FileUtils.existsWithContent;
/**
*
@@ -31,6 +36,9 @@
*/
class FileUtilsTest extends BaseTest {
+ @TempDir
+ Path tempDir;
+
/**
* Test of getFileExtension method, of class FileUtils.
*/
@@ -74,4 +82,17 @@ void testDeleteWithSubDirectories() throws Exception {
assertTrue(status, "delete returned a failed status");
assertFalse(file.exists(), "Temporary file exists after attempting deletion");
}
+
+ @Test
+ void testExistsWithContent() throws IOException {
+ assertFalse(existsWithContent(new File("doesnt-exist")));
+ assertFalse(existsWithContent(new File(".")), "directory shouldn't be considered as existing with content");
+
+ Path tempFile = Files.createTempFile(tempDir, "", "");
+ assertFalse(existsWithContent(tempFile.toFile()), "empty file shouldn't be considered as existing with content");
+ Files.writeString(tempFile, " ");
+ assertFalse(existsWithContent(tempFile.toFile()), "1 byte file shouldn't be considered as existing with content");
+ Files.writeString(tempFile, " ");
+ assertTrue(existsWithContent(tempFile.toFile()));
+ }
}