mirror of
https://github.com/ysoftdevs/DependencyCheck.git
synced 2026-01-14 15:53:36 +01:00
overhaul node package and nsp analyzer
This commit is contained in:
@@ -164,6 +164,10 @@ Copyright (c) 2012 Jeremy Long. All Rights Reserved.
|
||||
</plugins>
|
||||
</reporting>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.vdurmont</groupId>
|
||||
<artifactId>semver4j</artifactId>
|
||||
</dependency>
|
||||
<!-- Note, to stay compatible with Jenkins installations only JARs compiled to 1.6 can be used -->
|
||||
<dependency>
|
||||
<groupId>joda-time</groupId>
|
||||
|
||||
@@ -85,6 +85,14 @@ public abstract class AbstractAnalyzer implements Analyzer {
|
||||
@Override
|
||||
public void initialize(Settings settings) {
|
||||
this.settings = settings;
|
||||
final String key = getAnalyzerEnabledSettingKey();
|
||||
try {
|
||||
this.setEnabled(settings.getBoolean(key, true));
|
||||
} catch (InvalidSettingException ex) {
|
||||
final String msg = String.format("Invalid setting for property '%s'", key);
|
||||
LOGGER.warn(msg);
|
||||
LOGGER.debug(msg, ex);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -95,15 +103,6 @@ public abstract class AbstractAnalyzer implements Analyzer {
|
||||
*/
|
||||
@Override
|
||||
public final void prepare(Engine engine) throws InitializationException {
|
||||
final String key = getAnalyzerEnabledSettingKey();
|
||||
try {
|
||||
this.setEnabled(settings.getBoolean(key, true));
|
||||
} catch (InvalidSettingException ex) {
|
||||
final String msg = String.format("Invalid setting for property '%s'", key);
|
||||
LOGGER.warn(msg);
|
||||
LOGGER.debug(msg, ex);
|
||||
}
|
||||
|
||||
if (isEnabled()) {
|
||||
prepareAnalyzer(engine);
|
||||
} else {
|
||||
|
||||
@@ -0,0 +1,289 @@
|
||||
/*
|
||||
* 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) 2017 Steve Springett. All Rights Reserved.
|
||||
*/
|
||||
package org.owasp.dependencycheck.analyzer;
|
||||
|
||||
import org.owasp.dependencycheck.Engine;
|
||||
import org.owasp.dependencycheck.dependency.Confidence;
|
||||
import org.owasp.dependencycheck.dependency.Dependency;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.Map;
|
||||
import javax.annotation.concurrent.ThreadSafe;
|
||||
import javax.json.Json;
|
||||
import javax.json.JsonArray;
|
||||
import javax.json.JsonObject;
|
||||
import javax.json.JsonObjectBuilder;
|
||||
import javax.json.JsonString;
|
||||
import javax.json.JsonValue;
|
||||
import org.owasp.dependencycheck.dependency.EvidenceType;
|
||||
import org.owasp.dependencycheck.utils.Checksum;
|
||||
|
||||
/**
|
||||
* An abstract NPM analyzer that contains common methods for concrete
|
||||
* implementations.
|
||||
*
|
||||
* @author Steve Springett
|
||||
*/
|
||||
@ThreadSafe
|
||||
public abstract class AbstractNpmAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
|
||||
/**
|
||||
* The logger.
|
||||
*/
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(AbstractNpmAnalyzer.class);
|
||||
|
||||
/**
|
||||
* A descriptor for the type of dependencies processed or added by this
|
||||
* analyzer.
|
||||
*/
|
||||
public static final String NPM_DEPENDENCY_ECOSYSTEM = "npm";
|
||||
/**
|
||||
* The file name to scan.
|
||||
*/
|
||||
private static final String PACKAGE_JSON = "package.json";
|
||||
|
||||
/**
|
||||
* Determines if the file can be analyzed by the analyzer.
|
||||
*
|
||||
* @param pathname the path to the file
|
||||
* @return true if the file can be analyzed by the given analyzer; otherwise
|
||||
* false
|
||||
*/
|
||||
@Override
|
||||
public boolean accept(File pathname) {
|
||||
boolean accept = super.accept(pathname);
|
||||
if (accept) {
|
||||
try {
|
||||
// Do not scan the node_modules directory
|
||||
if (pathname.getCanonicalPath().contains(File.separator + "node_modules" + File.separator)) {
|
||||
LOGGER.debug("Skipping analysis of node module: " + pathname.getCanonicalPath());
|
||||
accept = false;
|
||||
}
|
||||
} catch (IOException ex) {
|
||||
throw new RuntimeException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
return accept;
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a dependency object.
|
||||
*
|
||||
* @param dependency the parent dependency
|
||||
* @param name the name of the dependency to create
|
||||
* @param version the version of the dependency to create
|
||||
* @param scope the scope of the dependency being created
|
||||
* @return the generated dependency
|
||||
*/
|
||||
protected Dependency createDependency(Dependency dependency, String name, String version, String scope) {
|
||||
final Dependency nodeModule = new Dependency(new File(dependency.getActualFile() + "?" + name), true);
|
||||
nodeModule.setEcosystem(NPM_DEPENDENCY_ECOSYSTEM);
|
||||
//this is virtual - the sha1 is purely for the hyperlink in the final html report
|
||||
nodeModule.setSha1sum(Checksum.getSHA1Checksum(String.format("%s:%s", name, version)));
|
||||
nodeModule.setMd5sum(Checksum.getMD5Checksum(String.format("%s:%s", name, version)));
|
||||
nodeModule.addEvidence(EvidenceType.PRODUCT, "package.json", "name", name, Confidence.HIGHEST);
|
||||
nodeModule.addEvidence(EvidenceType.VENDOR, "package.json", "name", name, Confidence.HIGH);
|
||||
nodeModule.addEvidence(EvidenceType.VERSION, "package.json", "version", version, Confidence.HIGHEST);
|
||||
nodeModule.addProjectReference(dependency.getName() + ": " + scope);
|
||||
nodeModule.setName(name);
|
||||
nodeModule.setVersion(version);
|
||||
nodeModule.addIdentifier("npm", String.format("%s:%s", name, version), null, Confidence.HIGHEST);
|
||||
return nodeModule;
|
||||
}
|
||||
|
||||
/**
|
||||
* Processes a part of package.json (as defined by JsonArray) and update the
|
||||
* specified dependency with relevant info.
|
||||
*
|
||||
* @param engine the dependency-check engine
|
||||
* @param dependency the Dependency to update
|
||||
* @param jsonArray the jsonArray to parse
|
||||
* @param depType the dependency type
|
||||
*/
|
||||
protected void processPackage(Engine engine, Dependency dependency, JsonArray jsonArray, String depType) {
|
||||
final JsonObjectBuilder builder = Json.createObjectBuilder();
|
||||
for (JsonString str : jsonArray.getValuesAs(JsonString.class)) {
|
||||
builder.add(str.toString(), "");
|
||||
}
|
||||
final JsonObject jsonObject = builder.build();
|
||||
processPackage(engine, dependency, jsonObject, depType);
|
||||
}
|
||||
|
||||
/**
|
||||
* Processes a part of package.json (as defined by JsonObject) and update
|
||||
* the specified dependency with relevant info.
|
||||
*
|
||||
* @param engine the dependency-check engine
|
||||
* @param dependency the Dependency to update
|
||||
* @param jsonObject the jsonObject to parse
|
||||
* @param depType the dependency type
|
||||
*/
|
||||
protected void processPackage(Engine engine, Dependency dependency, JsonObject jsonObject, String depType) {
|
||||
for (int i = 0; i < jsonObject.size(); i++) {
|
||||
for (Map.Entry<String, JsonValue> entry : jsonObject.entrySet()) {
|
||||
|
||||
final String name = entry.getKey();
|
||||
String version = "";
|
||||
if (entry.getValue() != null && entry.getValue().getValueType() == JsonValue.ValueType.STRING) {
|
||||
version = ((JsonString) entry.getValue()).getString();
|
||||
}
|
||||
final Dependency existing = findDependency(engine, name, version);
|
||||
if (existing == null) {
|
||||
final Dependency nodeModule = createDependency(dependency, name, version, depType);
|
||||
engine.addDependency(nodeModule);
|
||||
} else {
|
||||
existing.addProjectReference(dependency.getName() + ": " + depType);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds information to an evidence collection from the node json
|
||||
* configuration.
|
||||
*
|
||||
* @param dep the dependency to add the evidence
|
||||
* @param t the type of evidence to add
|
||||
* @param json information from node.js
|
||||
* @return the actual string set into evidence
|
||||
* @param key the key to obtain the data from the json information
|
||||
*/
|
||||
private static String addToEvidence(Dependency dep, EvidenceType t, JsonObject json, String key) {
|
||||
String evidenceStr = null;
|
||||
if (json.containsKey(key)) {
|
||||
final JsonValue value = json.get(key);
|
||||
if (value instanceof JsonString) {
|
||||
evidenceStr = ((JsonString) value).getString();
|
||||
dep.addEvidence(t, PACKAGE_JSON, key, evidenceStr, Confidence.HIGHEST);
|
||||
} else if (value instanceof JsonObject) {
|
||||
final JsonObject jsonObject = (JsonObject) value;
|
||||
for (final Map.Entry<String, JsonValue> entry : jsonObject.entrySet()) {
|
||||
final String property = entry.getKey();
|
||||
final JsonValue subValue = entry.getValue();
|
||||
if (subValue instanceof JsonString) {
|
||||
evidenceStr = ((JsonString) subValue).getString();
|
||||
dep.addEvidence(t, PACKAGE_JSON,
|
||||
String.format("%s.%s", key, property),
|
||||
evidenceStr,
|
||||
Confidence.HIGHEST);
|
||||
} else {
|
||||
LOGGER.warn("JSON sub-value not string as expected: {}", subValue);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
LOGGER.warn("JSON value not string or JSON object as expected: {}", value);
|
||||
}
|
||||
}
|
||||
return evidenceStr;
|
||||
}
|
||||
|
||||
/**
|
||||
* Locates the dependency from the list of dependencies that have been
|
||||
* scanned by the engine.
|
||||
*
|
||||
* @param engine the dependency-check engine
|
||||
* @param name the name of the dependency to find
|
||||
* @param version the version of the dependency to find
|
||||
* @return the identified dependency; otherwise null
|
||||
*/
|
||||
protected Dependency findDependency(Engine engine, String name, String version) {
|
||||
for (Dependency d : engine.getDependencies()) {
|
||||
if (NPM_DEPENDENCY_ECOSYSTEM.equals(d.getEcosystem()) && name.equals(d.getName()) && version != null && d.getVersion() != null) {
|
||||
String dependencyVersion = d.getVersion();
|
||||
if (DependencyBundlingAnalyzer.npmVersionsMatch(version, dependencyVersion)) {
|
||||
return d;
|
||||
}
|
||||
// if (dependencyVersion.startsWith("^") || dependencyVersion.startsWith("~")) {
|
||||
// dependencyVersion = dependencyVersion.substring(1);
|
||||
// }
|
||||
//
|
||||
// if (version.equals(dependencyVersion)) {
|
||||
// return d;
|
||||
// }
|
||||
// if (version.startsWith("^") || version.startsWith("~") || version.contains("*")) {
|
||||
// String type;
|
||||
// String tmp;
|
||||
// if (version.startsWith("^") || version.startsWith("~")) {
|
||||
// type = version.substring(0, 1);
|
||||
// tmp = version.substring(1);
|
||||
// } else {
|
||||
// type = "*";
|
||||
// tmp = version;
|
||||
// }
|
||||
// final String[] v = tmp.split(" ")[0].split("\\.");
|
||||
// final String[] depVersion = dependencyVersion.split("\\.");
|
||||
//
|
||||
// if ("^".equals(type) && v[0].equals(depVersion[0])) {
|
||||
// return d;
|
||||
// } else if ("~".equals(type) && v.length >= 2 && depVersion.length >= 2
|
||||
// && v[0].equals(depVersion[0]) && v[1].equals(depVersion[1])) {
|
||||
// return d;
|
||||
// } else if (v[0].equals("*")
|
||||
// || (v.length >= 2 && v[0].equals(depVersion[0]) && v[1].equals("*"))
|
||||
// || (v.length >= 3 && depVersion.length >= 2 && v[0].equals(depVersion[0])
|
||||
// && v[1].equals(depVersion[1]) && v[2].equals("*"))) {
|
||||
// return d;
|
||||
// }
|
||||
// }
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Collects evidence from the given JSON for the associated dependency.
|
||||
*
|
||||
* @param json the JSON that contains the evidence to collect
|
||||
* @param dependency the dependency to add the evidence too
|
||||
*/
|
||||
public void gatherEvidence(final JsonObject json, Dependency dependency) {
|
||||
if (json.containsKey("name")) {
|
||||
final Object value = json.get("name");
|
||||
if (value instanceof JsonString) {
|
||||
final String valueString = ((JsonString) value).getString();
|
||||
dependency.setName(valueString);
|
||||
dependency.setPackagePath(valueString);
|
||||
dependency.addEvidence(EvidenceType.PRODUCT, PACKAGE_JSON, "name", valueString, Confidence.HIGHEST);
|
||||
dependency.addEvidence(EvidenceType.VENDOR, PACKAGE_JSON, "name", valueString, Confidence.HIGH);
|
||||
} else {
|
||||
LOGGER.warn("JSON value not string as expected: {}", value);
|
||||
}
|
||||
}
|
||||
final String desc = addToEvidence(dependency, EvidenceType.PRODUCT, json, "description");
|
||||
dependency.setDescription(desc);
|
||||
addToEvidence(dependency, EvidenceType.VENDOR, json, "author");
|
||||
final String version = addToEvidence(dependency, EvidenceType.VERSION, json, "version");
|
||||
if (version != null) {
|
||||
dependency.setVersion(version);
|
||||
dependency.addIdentifier("npm", String.format("%s:%s", dependency.getName(), version), null, Confidence.HIGHEST);
|
||||
}
|
||||
|
||||
// Adds the license if defined in package.json
|
||||
if (json.containsKey("license")) {
|
||||
final Object value = json.get("license");
|
||||
if (value instanceof JsonString) {
|
||||
dependency.setLicense(json.getString("license"));
|
||||
} else {
|
||||
dependency.setLicense(json.getJsonObject("license").getString("type"));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -17,6 +17,9 @@
|
||||
*/
|
||||
package org.owasp.dependencycheck.analyzer;
|
||||
|
||||
import com.vdurmont.semver4j.Semver;
|
||||
import com.vdurmont.semver4j.Semver.SemverType;
|
||||
import com.vdurmont.semver4j.SemverException;
|
||||
import java.io.File;
|
||||
import java.util.Set;
|
||||
import java.util.regex.Matcher;
|
||||
@@ -135,10 +138,11 @@ public class DependencyBundlingAnalyzer extends AbstractDependencyComparingAnaly
|
||||
mergeDependencies(nextDependency, dependency, dependenciesToRemove);
|
||||
return true; //since we merged into the next dependency - skip forward to the next in mainIterator
|
||||
}
|
||||
} else if (ecoSystemIs(NspAnalyzer.DEPENDENCY_ECOSYSTEM, dependency, nextDependency)
|
||||
} else if (ecoSystemIs(AbstractNpmAnalyzer.NPM_DEPENDENCY_ECOSYSTEM, dependency, nextDependency)
|
||||
&& namesAreEqual(dependency, nextDependency)
|
||||
&& versionsAreEqual(dependency, nextDependency)) {
|
||||
if (dependency.isVirtual()) {
|
||||
&& npmVersionsMatch(dependency.getVersion(), nextDependency.getVersion())) {
|
||||
|
||||
if (!dependency.isVirtual()) {
|
||||
DependencyMergingAnalyzer.mergeDependencies(dependency, nextDependency, dependenciesToRemove);
|
||||
} else {
|
||||
DependencyMergingAnalyzer.mergeDependencies(nextDependency, dependency, dependenciesToRemove);
|
||||
@@ -158,7 +162,7 @@ public class DependencyBundlingAnalyzer extends AbstractDependencyComparingAnaly
|
||||
* removed from the main analysis loop, this function adds to this
|
||||
* collection
|
||||
*/
|
||||
private void mergeDependencies(final Dependency dependency, final Dependency relatedDependency, final Set<Dependency> dependenciesToRemove) {
|
||||
public static void mergeDependencies(final Dependency dependency, final Dependency relatedDependency, final Set<Dependency> dependenciesToRemove) {
|
||||
dependency.addRelatedDependency(relatedDependency);
|
||||
for (Dependency d : relatedDependency.getRelatedDependencies()) {
|
||||
dependency.addRelatedDependency(d);
|
||||
@@ -167,7 +171,9 @@ public class DependencyBundlingAnalyzer extends AbstractDependencyComparingAnaly
|
||||
if (dependency.getSha1sum().equals(relatedDependency.getSha1sum())) {
|
||||
dependency.addAllProjectReferences(relatedDependency.getProjectReferences());
|
||||
}
|
||||
dependenciesToRemove.add(relatedDependency);
|
||||
if (dependenciesToRemove != null) {
|
||||
dependenciesToRemove.add(relatedDependency);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -487,14 +493,72 @@ public class DependencyBundlingAnalyzer extends AbstractDependencyComparingAnaly
|
||||
|
||||
/**
|
||||
* Determine if the dependency version is equal in the given dependencies.
|
||||
* This method attempts to evaluate version range checks.
|
||||
*
|
||||
* @param dependency a dependency to compare
|
||||
* @param nextDependency a dependency to compare
|
||||
* @param current a dependency version to compare
|
||||
* @param nextDependency a dependency version to compare
|
||||
* @return true if the version is equal in both dependencies; otherwise
|
||||
* false
|
||||
*/
|
||||
private boolean versionsAreEqual(Dependency dependency, Dependency nextDependency) {
|
||||
return dependency.getVersion() != null && dependency.getVersion().equals(nextDependency.getVersion());
|
||||
public static boolean npmVersionsMatch(String current, String next) {
|
||||
String left = current;
|
||||
String right = next;
|
||||
if (left == null || right == null) {
|
||||
return false;
|
||||
}
|
||||
if (left.equals(right) || "*".equals(left) || "*".equals(right)) {
|
||||
return true;
|
||||
}
|
||||
if (left.contains(" ")) { // we have a version string from package.json
|
||||
if (right.contains(" ")) { // we can't evaluate this ">=1.5.4 <2.0.0" vs "2 || 3"
|
||||
return false;
|
||||
}
|
||||
if (!right.matches("^\\d.*$")) {
|
||||
right = stripLeadingNonNumeric(right);
|
||||
if (right == null) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
try {
|
||||
Semver v = new Semver(right, SemverType.NPM);
|
||||
return v.satisfies(left);
|
||||
} catch (SemverException ex) {
|
||||
LOGGER.trace("ignore", ex);
|
||||
}
|
||||
} else {
|
||||
if (!left.matches("^\\d.*$")) {
|
||||
left = stripLeadingNonNumeric(left);
|
||||
if (left == null) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
try {
|
||||
Semver v = new Semver(left, SemverType.NPM);
|
||||
if (v.satisfies(right)) {
|
||||
return true;
|
||||
}
|
||||
if (!right.contains((" "))) {
|
||||
left = current;
|
||||
right = stripLeadingNonNumeric(right);
|
||||
if (right != null) {
|
||||
v = new Semver(right, SemverType.NPM);
|
||||
return v.satisfies(left);
|
||||
}
|
||||
}
|
||||
} catch (SemverException ex) {
|
||||
LOGGER.trace("ignore", ex);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private static String stripLeadingNonNumeric(String str) {
|
||||
for (int x = 0; x < str.length(); x++) {
|
||||
if (Character.isDigit(str.codePointAt(x))) {
|
||||
return str.substring(x);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -128,4 +128,4 @@ updater.nvdcve.enabled=true
|
||||
updater.versioncheck.enabled=true
|
||||
analyzer.versionfilter.enabled=true
|
||||
|
||||
ecosystem.skip.nvdcve=npm
|
||||
ecosystem.skip.cpeanalyzer=npm
|
||||
@@ -43,6 +43,9 @@ public class NodePackageAnalyzerTest extends BaseTest {
|
||||
* The analyzer to test.
|
||||
*/
|
||||
private NodePackageAnalyzer analyzer;
|
||||
/**
|
||||
* A reference to the engine.
|
||||
*/
|
||||
private Engine engine;
|
||||
|
||||
/**
|
||||
@@ -87,7 +90,8 @@ public class NodePackageAnalyzerTest extends BaseTest {
|
||||
*/
|
||||
@Test
|
||||
public void testSupportsFiles() {
|
||||
assertThat(analyzer.accept(new File("package.json")), is(true));
|
||||
assertThat(analyzer.accept(new File("package-lock.json")), is(true));
|
||||
assertThat(analyzer.accept(new File("shrinkwrap.json")), is(true));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -96,10 +100,12 @@ public class NodePackageAnalyzerTest extends BaseTest {
|
||||
* @throws AnalysisException is thrown when an exception occurs.
|
||||
*/
|
||||
@Test
|
||||
public void testAnalyzePackageJson() throws AnalysisException {
|
||||
final Dependency result = new Dependency(BaseTest.getResourceAsFile(this,
|
||||
"nodejs/node_modules/dns-sync/package.json"));
|
||||
analyzer.analyze(result, null);
|
||||
public void testAnalyzeShrinkwrapJson() throws AnalysisException {
|
||||
final Dependency toScan = new Dependency(BaseTest.getResourceAsFile(this,
|
||||
"nodejs/shrinkwrap.json"));
|
||||
analyzer.analyze(toScan, engine);
|
||||
assertEquals("Expected 1 dependency", engine.getDependencies().length, 1);
|
||||
final Dependency result = engine.getDependencies()[0];
|
||||
final String vendorString = result.getEvidence(EvidenceType.VENDOR).toString();
|
||||
assertThat(vendorString, containsString("Sanjeev Koranga"));
|
||||
assertThat(vendorString, containsString("dns-sync"));
|
||||
@@ -109,4 +115,24 @@ public class NodePackageAnalyzerTest extends BaseTest {
|
||||
assertEquals("dns-sync", result.getName());
|
||||
assertEquals("0.1.0", result.getVersion());
|
||||
}
|
||||
|
||||
/**
|
||||
* Test of inspect method, of class PythonDistributionAnalyzer.
|
||||
*
|
||||
* @throws AnalysisException is thrown when an exception occurs.
|
||||
*/
|
||||
@Test
|
||||
public void testAnalyzePackageJsonWithShrinkwrap() throws AnalysisException {
|
||||
final Dependency packageLock = new Dependency(BaseTest.getResourceAsFile(this,
|
||||
"nodejs/package-lock.json"));
|
||||
final Dependency shrinkwrap = new Dependency(BaseTest.getResourceAsFile(this,
|
||||
"nodejs/shrinkwrap.json"));
|
||||
engine.addDependency(packageLock);
|
||||
engine.addDependency(shrinkwrap);
|
||||
assertEquals(2, engine.getDependencies().length);
|
||||
analyzer.analyze(packageLock, engine);
|
||||
assertEquals(1, engine.getDependencies().length); //package-lock was removed without analysis
|
||||
analyzer.analyze(shrinkwrap, engine);
|
||||
assertEquals(1, engine.getDependencies().length); //shrinkwrap was removed with analysis adding 1 dependency
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
package org.owasp.dependencycheck.analyzer;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.owasp.dependencycheck.BaseTest;
|
||||
import org.owasp.dependencycheck.analyzer.exception.AnalysisException;
|
||||
@@ -36,12 +34,20 @@ public class NspAnalyzerTest extends BaseTest {
|
||||
analyzer.setFilesMatched(true);
|
||||
analyzer.initialize(getSettings());
|
||||
analyzer.prepare(engine);
|
||||
final Dependency result = new Dependency(BaseTest.getResourceAsFile(this, "nsp/package.json"));
|
||||
analyzer.analyze(result, engine);
|
||||
|
||||
assertTrue(result.getEvidence(EvidenceType.VENDOR).toString().contains("owasp-nodejs-goat"));
|
||||
assertTrue(result.getEvidence(EvidenceType.PRODUCT).toString().contains("A tool to learn OWASP Top 10 for node.js developers"));
|
||||
assertTrue(result.getEvidence(EvidenceType.VERSION).toString().contains("1.3.0"));
|
||||
final Dependency toScan = new Dependency(BaseTest.getResourceAsFile(this, "nsp/package.json"));
|
||||
analyzer.analyze(toScan, engine);
|
||||
boolean found = false;
|
||||
assertEquals("4 dependencies should be identified", 4, engine.getDependencies().length);
|
||||
for (Dependency result : engine.getDependencies()) {
|
||||
if ("package.json?uglify-js".equals(result.getFileName())) {
|
||||
found = true;
|
||||
assertTrue(result.getEvidence(EvidenceType.VENDOR).toString().contains("uglify-js"));
|
||||
assertTrue(result.getEvidence(EvidenceType.PRODUCT).toString().contains("uglify-js"));
|
||||
assertTrue(result.getEvidence(EvidenceType.VERSION).toString().contains("2.4.24"));
|
||||
assertTrue(result.isVirtual());
|
||||
}
|
||||
}
|
||||
assertTrue("Uglify was not found", found);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -61,38 +67,6 @@ public class NspAnalyzerTest extends BaseTest {
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAnalyzePackageJsonWithBundledDeps() throws AnalysisException, InitializationException {
|
||||
try (Engine engine = new Engine(getSettings())) {
|
||||
NspAnalyzer analyzer = new NspAnalyzer();
|
||||
analyzer.setFilesMatched(true);
|
||||
analyzer.initialize(getSettings());
|
||||
analyzer.prepare(engine);
|
||||
final Dependency result = new Dependency(BaseTest.getResourceAsFile(this, "nsp/bundled.deps.package.json"));
|
||||
analyzer.analyze(result, engine);
|
||||
|
||||
assertTrue(result.getEvidence(EvidenceType.VENDOR).toString().contains("Philipp Dunkel <pip@pipobscure.com>"));
|
||||
assertTrue(result.getEvidence(EvidenceType.PRODUCT).toString().contains("Native Access to Mac OS-X FSEvents"));
|
||||
assertTrue(result.getEvidence(EvidenceType.VERSION).toString().contains("1.1.1"));
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAnalyzePackageJsonWithLicenseObject() throws AnalysisException, InitializationException {
|
||||
try (Engine engine = new Engine(getSettings())) {
|
||||
NspAnalyzer analyzer = new NspAnalyzer();
|
||||
analyzer.setFilesMatched(true);
|
||||
analyzer.initialize(getSettings());
|
||||
analyzer.prepare(engine);
|
||||
final Dependency result = new Dependency(BaseTest.getResourceAsFile(this, "nsp/license.obj.package.json"));
|
||||
analyzer.analyze(result, engine);
|
||||
|
||||
assertTrue(result.getEvidence(EvidenceType.VENDOR).toString().contains("Twitter, Inc."));
|
||||
assertTrue(result.getEvidence(EvidenceType.PRODUCT).toString().contains("The most popular front-end framework for developing responsive, mobile first projects on the web"));
|
||||
assertTrue(result.getEvidence(EvidenceType.VERSION).toString().contains("3.2.0"));
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAnalyzePackageJsonInNodeModulesDirectory() throws AnalysisException, InitializationException {
|
||||
try (Engine engine = new Engine(getSettings())) {
|
||||
@@ -100,12 +74,10 @@ public class NspAnalyzerTest extends BaseTest {
|
||||
analyzer.setFilesMatched(true);
|
||||
analyzer.initialize(getSettings());
|
||||
analyzer.prepare(engine);
|
||||
final Dependency result = new Dependency(BaseTest.getResourceAsFile(this, "nodejs/node_modules/dns-sync/package.json"));
|
||||
analyzer.analyze(result, engine);
|
||||
// package.json adds 5 bits of evidence
|
||||
assertTrue(result.size() == 5);
|
||||
// but no vulnerabilities were cited
|
||||
assertTrue(result.getVulnerabilities().isEmpty());
|
||||
final Dependency toScan = new Dependency(BaseTest.getResourceAsFile(this, "nodejs/node_modules/dns-sync/package.json"));
|
||||
engine.addDependency(toScan);
|
||||
analyzer.analyze(toScan, engine);
|
||||
assertEquals("No dependencies should exist", 0, engine.getDependencies().length);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -124,4 +124,4 @@ analyzer.vulnerabilitysuppression.enabled=true
|
||||
updater.nvdcve.enabled=true
|
||||
updater.versioncheck.enabled=true
|
||||
|
||||
ecosystem.skip.nvdcve=npm
|
||||
ecosystem.skip.cpeanalyzer=npm
|
||||
@@ -443,9 +443,9 @@ public final class Settings {
|
||||
*/
|
||||
public static final String UPDATE_VERSION_CHECK_ENABLED = "updater.versioncheck.enabled";
|
||||
/**
|
||||
* The key to determine which ecosystems should skip the NVD CVE analysis.
|
||||
* The key to determine which ecosystems should skip the CPE analysis.
|
||||
*/
|
||||
public static final String ECOSYSTEM_SKIP_NVDCVE = "ecosystem.skip.nvdcve";
|
||||
public static final String ECOSYSTEM_SKIP_CPEANALYZER = "ecosystem.skip.cpeanalyzer";
|
||||
|
||||
/**
|
||||
* private constructor because this is a "utility" class containing
|
||||
|
||||
5
pom.xml
5
pom.xml
@@ -625,6 +625,11 @@ Copyright (c) 2012 - Jeremy Long
|
||||
</reporting>
|
||||
<dependencyManagement>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.vdurmont</groupId>
|
||||
<artifactId>semver4j</artifactId>
|
||||
<version>2.1.0</version>
|
||||
</dependency>
|
||||
<!-- analysis core (used by Jenkins) uses 1.6-->
|
||||
<dependency>
|
||||
<groupId>joda-time</groupId>
|
||||
|
||||
Reference in New Issue
Block a user