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 dd377f6ff65..ebadbf75edf 100644 --- a/core/src/main/java/org/owasp/dependencycheck/analyzer/NodePackageAnalyzer.java +++ b/core/src/main/java/org/owasp/dependencycheck/analyzer/NodePackageAnalyzer.java @@ -386,6 +386,14 @@ private void processDependencies(JsonObject json, File baseDir, File rootFile, if (entry.getValue() instanceof JsonObject) { jo = (JsonObject) entry.getValue(); + + // Ignore/skip linked entries (as they don't have "version" and + // later logic will crash) + if (jo.getBoolean("link", false)) { + LOGGER.warn("Skipping `" + name + "` because it is a link dependency"); + continue; + } + version = jo.getString("version"); optional = jo.getBoolean("optional", false); isDev = jo.getBoolean("dev", false); diff --git a/core/src/test/java/org/owasp/dependencycheck/analyzer/NodePackageAnalyzerTest.java b/core/src/test/java/org/owasp/dependencycheck/analyzer/NodePackageAnalyzerTest.java index e4c5f20cac7..c05193b80f4 100644 --- a/core/src/test/java/org/owasp/dependencycheck/analyzer/NodePackageAnalyzerTest.java +++ b/core/src/test/java/org/owasp/dependencycheck/analyzer/NodePackageAnalyzerTest.java @@ -309,4 +309,26 @@ public void testPackageLockV3() throws AnalysisException, InvalidSettingExceptio analyzer.analyze(packageLockJson, engine); assertEquals("Expected 1 dependencies", 6, engine.getDependencies().length); } + + /** + * Test of analysis of package with a local package as a dependency. + * + * This test crashes with an NPE if issue #1947 isn't resolved. + * + * @throws AnalysisException if there was a problem with the analysis + */ + @Test + public void testLocalPackageDependency() throws AnalysisException, InvalidSettingException { + Assume.assumeThat(getSettings().getBoolean(Settings.KEYS.ANALYZER_NODE_PACKAGE_ENABLED), is(true)); + final Dependency packageJson = new Dependency(BaseTest.getResourceAsFile(this, + "nodejs/local_package/package.json")); + final Dependency packageLockJson = new Dependency(BaseTest.getResourceAsFile(this, + "nodejs/local_package/package-lock.json")); + engine.addDependency(packageJson); + engine.addDependency(packageLockJson); + analyzer.analyze(packageJson, engine); + assertEquals("Expected 1 dependencies", 1, engine.getDependencies().length); + analyzer.analyze(packageLockJson, engine); + assertEquals("Expected 2 dependencies", 2, engine.getDependencies().length); + } } diff --git a/core/src/test/resources/nodejs/local_package/mypackage/package.json b/core/src/test/resources/nodejs/local_package/mypackage/package.json new file mode 100644 index 00000000000..3dfb1c7e95a --- /dev/null +++ b/core/src/test/resources/nodejs/local_package/mypackage/package.json @@ -0,0 +1,14 @@ +{ + "name": "mypackage", + "version": "1.0.0", + "description": "", + "main": "index.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "keywords": [], + "author": "", + "license": "ISC", + "dependencies": { + } +} diff --git a/core/src/test/resources/nodejs/local_package/node_modules/.package-lock.json b/core/src/test/resources/nodejs/local_package/node_modules/.package-lock.json new file mode 100644 index 00000000000..47664dd2836 --- /dev/null +++ b/core/src/test/resources/nodejs/local_package/node_modules/.package-lock.json @@ -0,0 +1,16 @@ +{ + "name": "local_package", + "version": "1.0.0", + "lockfileVersion": 2, + "requires": true, + "packages": { + "mypackage": { + "version": "1.0.0", + "license": "ISC" + }, + "node_modules/mypackage": { + "resolved": "mypackage", + "link": true + } + } +} diff --git a/core/src/test/resources/nodejs/local_package/node_modules/mypackage b/core/src/test/resources/nodejs/local_package/node_modules/mypackage new file mode 120000 index 00000000000..5b433629f81 --- /dev/null +++ b/core/src/test/resources/nodejs/local_package/node_modules/mypackage @@ -0,0 +1 @@ +../mypackage \ No newline at end of file diff --git a/core/src/test/resources/nodejs/local_package/package-lock.json b/core/src/test/resources/nodejs/local_package/package-lock.json new file mode 100644 index 00000000000..e18b5b4414c --- /dev/null +++ b/core/src/test/resources/nodejs/local_package/package-lock.json @@ -0,0 +1,29 @@ +{ + "name": "local_package", + "version": "1.0.0", + "lockfileVersion": 2, + "requires": true, + "packages": { + "": { + "name": "local_package", + "version": "1.0.0", + "license": "ISC", + "dependencies": { + "mypackage": "file:./mypackage" + } + }, + "mypackage": { + "version": "1.0.0", + "license": "ISC" + }, + "node_modules/mypackage": { + "resolved": "mypackage", + "link": true + } + }, + "dependencies": { + "mypackage": { + "version": "file:mypackage" + } + } +} diff --git a/core/src/test/resources/nodejs/local_package/package.json b/core/src/test/resources/nodejs/local_package/package.json new file mode 100644 index 00000000000..e443de05b71 --- /dev/null +++ b/core/src/test/resources/nodejs/local_package/package.json @@ -0,0 +1,15 @@ +{ + "name": "local_package", + "version": "1.0.0", + "description": "", + "main": "index.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "keywords": [], + "author": "", + "license": "ISC", + "dependencies": { + "mypackage": "file:./mypackage" + } +}