Skip to content

Commit

Permalink
Add test for NistMirrorTask
Browse files Browse the repository at this point in the history
Signed-off-by: nscuro <[email protected]>
  • Loading branch information
nscuro authored and rkg-mm committed May 5, 2024
1 parent be034e1 commit fd5f52c
Show file tree
Hide file tree
Showing 5 changed files with 16,867 additions and 4 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ public class NvdMirrorServlet extends FileSystemResourceServlet {
public void init(final ServletConfig config) throws ServletException {
LOGGER.info("Initializing NVD mirror");
super.init(config);
super.setDirectory(NistMirrorTask.NVD_MIRROR_DIR);
super.setDirectory(NistMirrorTask.DEFAULT_NVD_MIRROR_DIR.toString());
super.setAbsolute(true);
}

Expand Down
14 changes: 11 additions & 3 deletions src/main/java/org/dependencytrack/tasks/NistMirrorTask.java
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@
import java.net.SocketTimeoutException;
import java.net.URL;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.StandardCopyOption;
import java.time.Duration;
import java.util.Calendar;
Expand Down Expand Up @@ -98,7 +99,7 @@ private enum ResourceType {
NONE // DO NOT PARSE THIS TYPE
}

public static final String NVD_MIRROR_DIR = Config.getInstance().getDataDirectorty().getAbsolutePath() + File.separator + "nist";
public static final Path DEFAULT_NVD_MIRROR_DIR = Config.getInstance().getDataDirectorty().toPath().resolve("nist").toAbsolutePath();
private static final String CVE_JSON_11_MODIFIED_URL = "/json/cve/1.1/nvdcve-1.1-modified.json.gz";
private static final String CVE_JSON_11_BASE_URL = "/json/cve/1.1/nvdcve-1.1-%d.json.gz";
private static final String CVE_JSON_11_MODIFIED_META = "/json/cve/1.1/nvdcve-1.1-modified.meta";
Expand Down Expand Up @@ -142,9 +143,16 @@ private enum ResourceType {
.bindTo(Metrics.getRegistry());
}

private final Path mirrorDirPath;
private boolean mirroredWithoutErrors = true;

public NistMirrorTask() {
this(DEFAULT_NVD_MIRROR_DIR);
}

NistMirrorTask(final Path mirrorDirPath) {
this.mirrorDirPath = mirrorDirPath;

try (final QueryManager qm = new QueryManager()) {
this.isEnabled = qm.isEnabled(VULNERABILITY_SOURCE_NVD_ENABLED);
this.isApiEnabled = qm.isEnabled(VULNERABILITY_SOURCE_NVD_API_ENABLED);
Expand All @@ -156,7 +164,7 @@ public NistMirrorTask() {
if (this.nvdFeedsUrl.endsWith("/")) {
this.nvdFeedsUrl = this.nvdFeedsUrl.substring(0, this.nvdFeedsUrl.length()-1);
}
}
}
}

/**
Expand All @@ -183,7 +191,7 @@ public void inform(final Event e) {

final long start = System.currentTimeMillis();
LOGGER.info("Starting NIST mirroring task");
final File mirrorPath = new File(NVD_MIRROR_DIR);
final File mirrorPath = mirrorDirPath.toFile();
setOutputDir(mirrorPath.getAbsolutePath());
getAllFiles();
final long end = System.currentTimeMillis();
Expand Down
175 changes: 175 additions & 0 deletions src/test/java/org/dependencytrack/tasks/NistMirrorTaskTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,175 @@
/*
* This file is part of Dependency-Track.
*
* 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.
*
* SPDX-License-Identifier: Apache-2.0
* Copyright (c) OWASP Foundation. All Rights Reserved.
*/
package org.dependencytrack.tasks;

import com.github.tomakehurst.wiremock.junit.WireMockRule;
import org.dependencytrack.PersistenceCapableTest;
import org.dependencytrack.event.NistMirrorEvent;
import org.dependencytrack.model.Severity;
import org.dependencytrack.model.Vulnerability;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;

import java.io.ByteArrayOutputStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.List;
import java.util.zip.GZIPOutputStream;

import static com.github.tomakehurst.wiremock.client.WireMock.aResponse;
import static com.github.tomakehurst.wiremock.client.WireMock.anyUrl;
import static com.github.tomakehurst.wiremock.client.WireMock.get;
import static com.github.tomakehurst.wiremock.client.WireMock.urlPathEqualTo;
import static com.github.tomakehurst.wiremock.core.WireMockConfiguration.options;
import static org.apache.commons.io.IOUtils.resourceToByteArray;
import static org.assertj.core.api.Assertions.assertThat;
import static org.dependencytrack.model.ConfigPropertyConstants.VULNERABILITY_SOURCE_NVD_ENABLED;
import static org.dependencytrack.model.ConfigPropertyConstants.VULNERABILITY_SOURCE_NVD_FEEDS_URL;

public class NistMirrorTaskTest extends PersistenceCapableTest {

@Rule
public WireMockRule wireMock = new WireMockRule(options().dynamicPort());

@Before
public void setUp() {
qm.createConfigProperty(
VULNERABILITY_SOURCE_NVD_ENABLED.getGroupName(),
VULNERABILITY_SOURCE_NVD_ENABLED.getPropertyName(),
"true",
VULNERABILITY_SOURCE_NVD_ENABLED.getPropertyType(),
VULNERABILITY_SOURCE_NVD_ENABLED.getDescription()
);
qm.createConfigProperty(
VULNERABILITY_SOURCE_NVD_FEEDS_URL.getGroupName(),
VULNERABILITY_SOURCE_NVD_FEEDS_URL.getPropertyName(),
wireMock.baseUrl(),
VULNERABILITY_SOURCE_NVD_FEEDS_URL.getPropertyType(),
VULNERABILITY_SOURCE_NVD_FEEDS_URL.getDescription()
);
}

@Test
public void test() throws Exception {
// Gzip the JSON feed file to match the format returned by the NVD.
// NB: The file is a truncated version of an actual feed file.
// It only contains the first three CVEs. Truncation was done with jq:
// jq 'del(.CVE_Items[3:])' ~/.dependency-track/nist/nvdcve-1.1-2022.json > nvdcve-1.1-2022.json
final var byteArrayOutputStream = new ByteArrayOutputStream();
try (final var gzipOutputStream = new GZIPOutputStream(byteArrayOutputStream)) {
gzipOutputStream.write(resourceToByteArray("/unit/nvd/feed/nvdcve-1.1-2022.json"));
}

wireMock.stubFor(get(anyUrl())
.willReturn(aResponse()
.withStatus(404)));
wireMock.stubFor(get(urlPathEqualTo("/json/cve/1.1/nvdcve-1.1-2022.json.gz"))
.willReturn(aResponse()
.withBody(byteArrayOutputStream.toByteArray())));
wireMock.stubFor(get(urlPathEqualTo("/json/cve/1.1/nvdcve-1.1-2022.meta"))
.willReturn(aResponse()
.withBody(resourceToByteArray("/unit/nvd/feed/nvdcve-1.1-2022.meta"))));

final Path mirrorDirPath = Files.createTempDirectory(null);
mirrorDirPath.toFile().deleteOnExit();

new NistMirrorTask(mirrorDirPath).inform(new NistMirrorEvent());

assertThat(mirrorDirPath.resolve("nvdcve-1.1-2022.json.gz")).exists();
assertThat(mirrorDirPath.resolve("nvdcve-1.1-2022.json")).exists();
assertThat(mirrorDirPath.resolve("nvdcve-1.1-2022.meta")).exists();

final List<Vulnerability> vulns = qm.getVulnerabilities().getList(Vulnerability.class);
assertThat(vulns).satisfiesExactlyInAnyOrder(
vuln -> {
assertThat(vuln.getVulnId()).isEqualTo("CVE-2022-0001");
assertThat(vuln.getSource()).isEqualTo("NVD");
assertThat(vuln.getDescription()).isEqualTo("""
Non-transparent sharing of branch predictor selectors between contexts \
in some Intel(R) Processors may allow an authorized user to potentially \
enable information disclosure via local access.""");
assertThat(vuln.getReferences()).isEqualTo("""
* [https://www.intel.com/content/www/us/en/security-center/advisory/intel-sa-00598.html](https://www.intel.com/content/www/us/en/security-center/advisory/intel-sa-00598.html)
* [http://www.openwall.com/lists/oss-security/2022/03/18/2](http://www.openwall.com/lists/oss-security/2022/03/18/2)
* [https://www.oracle.com/security-alerts/cpujul2022.html](https://www.oracle.com/security-alerts/cpujul2022.html)
* [https://security.netapp.com/advisory/ntap-20220818-0004/](https://security.netapp.com/advisory/ntap-20220818-0004/)
* [https://www.kb.cert.org/vuls/id/155143](https://www.kb.cert.org/vuls/id/155143)""");
assertThat(vuln.getPublished()).isInSameMinuteAs("2022-03-11T18:15:00Z");
assertThat(vuln.getUpdated()).isInSameMinuteAs("2024-04-09T15:15:00Z");
assertThat(vuln.getCvssV2BaseScore()).isEqualByComparingTo("2.1");
assertThat(vuln.getCvssV2ExploitabilitySubScore()).isEqualByComparingTo("3.9");
assertThat(vuln.getCvssV2ImpactSubScore()).isEqualByComparingTo("2.9");
assertThat(vuln.getCvssV2Vector()).isEqualTo("(AV:L/AC:L/Au:N/C:P/I:N/A:N)");
assertThat(vuln.getCvssV3BaseScore()).isEqualByComparingTo("6.5");
assertThat(vuln.getCvssV3ExploitabilitySubScore()).isEqualByComparingTo("2.0");
assertThat(vuln.getCvssV3ImpactSubScore()).isEqualByComparingTo("4.0");
assertThat(vuln.getCvssV3Vector()).isEqualTo("CVSS:3.0/AV:L/AC:L/PR:L/UI:N/S:C/C:H/I:N/A:N");
assertThat(vuln.getSeverity()).isEqualTo(Severity.MEDIUM);
},
vuln -> {
assertThat(vuln.getVulnId()).isEqualTo("CVE-2022-0002");
assertThat(vuln.getSource()).isEqualTo("NVD");
assertThat(vuln.getDescription()).isEqualTo("""
Non-transparent sharing of branch predictor within a context in some \
Intel(R) Processors may allow an authorized user to potentially enable \
information disclosure via local access.""");
assertThat(vuln.getReferences()).isEqualTo("""
* [https://www.intel.com/content/www/us/en/security-center/advisory/intel-sa-00598.html](https://www.intel.com/content/www/us/en/security-center/advisory/intel-sa-00598.html)
* [http://www.openwall.com/lists/oss-security/2022/03/18/2](http://www.openwall.com/lists/oss-security/2022/03/18/2)
* [https://www.oracle.com/security-alerts/cpujul2022.html](https://www.oracle.com/security-alerts/cpujul2022.html)
* [https://security.netapp.com/advisory/ntap-20220818-0004/](https://security.netapp.com/advisory/ntap-20220818-0004/)""");
assertThat(vuln.getPublished()).isInSameMinuteAs("2022-03-11T18:15:00Z");
assertThat(vuln.getUpdated()).isInSameMinuteAs("2022-08-19T12:28:00Z");
assertThat(vuln.getCvssV2BaseScore()).isEqualByComparingTo("2.1");
assertThat(vuln.getCvssV2ExploitabilitySubScore()).isEqualByComparingTo("3.9");
assertThat(vuln.getCvssV2ImpactSubScore()).isEqualByComparingTo("2.9");
assertThat(vuln.getCvssV2Vector()).isEqualTo("(AV:L/AC:L/Au:N/C:P/I:N/A:N)");
assertThat(vuln.getCvssV3BaseScore()).isEqualByComparingTo("6.5");
assertThat(vuln.getCvssV3ExploitabilitySubScore()).isEqualByComparingTo("2.0");
assertThat(vuln.getCvssV3ImpactSubScore()).isEqualByComparingTo("4.0");
assertThat(vuln.getCvssV3Vector()).isEqualTo("CVSS:3.0/AV:L/AC:L/PR:L/UI:N/S:C/C:H/I:N/A:N");
assertThat(vuln.getSeverity()).isEqualTo(Severity.MEDIUM);
},
vuln -> {
assertThat(vuln.getVulnId()).isEqualTo("CVE-2022-0004");
assertThat(vuln.getSource()).isEqualTo("NVD");
assertThat(vuln.getDescription()).isEqualTo("""
Hardware debug modes and processor INIT setting that allow override of \
locks for some Intel(R) Processors in Intel(R) Boot Guard and Intel(R) \
TXT may allow an unauthenticated user to potentially enable escalation \
of privilege via physical access.""");
assertThat(vuln.getReferences()).isEqualTo("""
* [https://www.intel.com/content/www/us/en/security-center/advisory/intel-sa-00613.html](https://www.intel.com/content/www/us/en/security-center/advisory/intel-sa-00613.html)""");
assertThat(vuln.getPublished()).isInSameMinuteAs("2022-05-12T17:15:00Z");
assertThat(vuln.getUpdated()).isInSameMinuteAs("2022-06-10T20:52:00Z");
assertThat(vuln.getCvssV2BaseScore()).isEqualByComparingTo("7.2");
assertThat(vuln.getCvssV2ExploitabilitySubScore()).isEqualByComparingTo("3.9");
assertThat(vuln.getCvssV2ImpactSubScore()).isEqualByComparingTo("10.0");
assertThat(vuln.getCvssV2Vector()).isEqualTo("(AV:L/AC:L/Au:N/C:C/I:C/A:C)");
assertThat(vuln.getCvssV3BaseScore()).isEqualByComparingTo("6.8");
assertThat(vuln.getCvssV3ExploitabilitySubScore()).isEqualByComparingTo("0.9");
assertThat(vuln.getCvssV3ImpactSubScore()).isEqualByComparingTo("5.9");
assertThat(vuln.getCvssV3Vector()).isEqualTo("CVSS:3.0/AV:P/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H");
assertThat(vuln.getSeverity()).isEqualTo(Severity.MEDIUM);
}
);
}

}
Loading

0 comments on commit fd5f52c

Please sign in to comment.