1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 package org.owasp.dependencycheck.analyzer;
19
20 import org.junit.After;
21 import org.junit.Before;
22 import org.junit.Test;
23 import org.owasp.dependencycheck.BaseTest;
24 import org.owasp.dependencycheck.analyzer.exception.AnalysisException;
25 import org.owasp.dependencycheck.dependency.Dependency;
26
27 import java.io.File;
28
29 import static org.hamcrest.CoreMatchers.containsString;
30 import static org.hamcrest.CoreMatchers.is;
31 import static org.hamcrest.MatcherAssert.assertThat;
32 import static org.junit.Assert.*;
33
34 import org.junit.Assume;
35 import org.owasp.dependencycheck.Engine;
36 import org.owasp.dependencycheck.dependency.EvidenceType;
37 import org.owasp.dependencycheck.exception.InitializationException;
38 import org.owasp.dependencycheck.utils.InvalidSettingException;
39 import org.owasp.dependencycheck.utils.Settings;
40
41
42
43
44
45
46 public class NodePackageAnalyzerTest extends BaseTest {
47
48
49
50
51 private NodePackageAnalyzer analyzer;
52
53
54
55 private Engine engine;
56
57
58
59
60
61
62
63 private NodeAuditAnalyzer getNodeAuditAnalyzer(Engine engine) {
64 for (Analyzer a : engine.getAnalyzers()) {
65 if (a instanceof NodeAuditAnalyzer) {
66 return (NodeAuditAnalyzer) a;
67 }
68 }
69 return null;
70 }
71
72
73
74
75
76
77
78 private NodePackageAnalyzer getNodePackageAnalyzer(Engine engine) {
79 for (Analyzer a : engine.getAnalyzers()) {
80 if (a instanceof NodePackageAnalyzer) {
81 return (NodePackageAnalyzer) a;
82 }
83 }
84 return null;
85 }
86
87
88
89
90
91
92 @Before
93 @Override
94 public void setUp() throws Exception {
95 super.setUp();
96 if (getSettings().getBoolean(Settings.KEYS.ANALYZER_NODE_PACKAGE_ENABLED)) {
97 engine = new Engine(this.getSettings());
98 NodeAuditAnalyzer auditAnalyzer = getNodeAuditAnalyzer(engine);
99 auditAnalyzer.setFilesMatched(true);
100 analyzer = getNodePackageAnalyzer(engine);
101 analyzer.setFilesMatched(true);
102 analyzer.initialize(getSettings());
103 try {
104 analyzer.prepare(engine);
105 } catch (InitializationException ex) {
106 if (!ex.getMessage().startsWith("Missing package.lock or npm-shrinkwrap.lock file")) {
107 throw ex;
108 }
109 }
110 }
111 }
112
113
114
115
116
117
118 @After
119 @Override
120 public void tearDown() throws Exception {
121 if (getSettings().getBoolean(Settings.KEYS.ANALYZER_NODE_PACKAGE_ENABLED)) {
122 analyzer.close();
123 engine.close();
124 }
125 super.tearDown();
126
127 }
128
129
130
131
132 @Test
133 public void testGetName() throws InvalidSettingException {
134 Assume.assumeThat(getSettings().getBoolean(Settings.KEYS.ANALYZER_NODE_PACKAGE_ENABLED), is(true));
135 Assume.assumeThat(getSettings().getBoolean(Settings.KEYS.ANALYZER_NODE_AUDIT_ENABLED), is(true));
136 assertThat(analyzer.getName(), is("Node.js Package Analyzer"));
137 }
138
139
140
141
142 @Test
143 public void testSupportsFiles() throws InvalidSettingException {
144 Assume.assumeThat(getSettings().getBoolean(Settings.KEYS.ANALYZER_NODE_PACKAGE_ENABLED), is(true));
145 Assume.assumeThat(getSettings().getBoolean(Settings.KEYS.ANALYZER_NODE_AUDIT_ENABLED), is(true));
146 assertThat(analyzer.accept(new File("package-lock.json")), is(true));
147 assertThat(analyzer.accept(new File("npm-shrinkwrap.json")), is(true));
148 }
149
150
151
152
153
154
155 @Test
156 public void testAnalyzeShrinkwrapJson() throws AnalysisException, InvalidSettingException {
157 Assume.assumeThat(getSettings().getBoolean(Settings.KEYS.ANALYZER_NODE_PACKAGE_ENABLED), is(true));
158 Assume.assumeThat(getSettings().getBoolean(Settings.KEYS.ANALYZER_NODE_AUDIT_ENABLED), is(true));
159 final Dependency toScan = new Dependency(BaseTest.getResourceAsFile(this,
160 "nodejs/npm-shrinkwrap.json"));
161 final Dependency toCombine = new Dependency(BaseTest.getResourceAsFile(this,
162 "nodejs/node_modules/dns-sync/package.json"));
163 engine.addDependency(toScan);
164 engine.addDependency(toCombine);
165 analyzer.analyze(toScan, engine);
166 analyzer.analyze(toCombine, engine);
167
168 testLock();
169 }
170
171 private void testLock() {
172 final boolean isMac = System.getProperty("os.name").toLowerCase().contains("mac");
173
174
175 boolean bracesFound = false;
176 boolean expandRangeFound = false;
177
178 Dependency result = null;
179 for (Dependency dep : engine.getDependencies()) {
180 if (!isMac && "fsevents".equals(dep.getName())) {
181 fail("fsevents need to be skipped on non mac");
182 }
183
184 if ("react-dom".equals(dep.getName())) {
185 fail("react-dom need to be skipped because it's an alias");
186 }
187
188 if ("braces".equals(dep.getName())) {
189 bracesFound = true;
190 }
191
192 if ("expand-range".equals(dep.getName())) {
193 expandRangeFound = true;
194 }
195
196 if ("fake_submodule".equals(dep.getName())) {
197 fail("start with file: need to be skipped because it's a local package");
198 }
199
200 if ("react-dom".equals(dep.getName())) {
201 fail("start with file: need to be skipped because it's a local package");
202 }
203
204 if ("dns-sync".equals(dep.getName())) {
205 result = dep;
206 }
207 }
208
209 assertTrue("need to contain braces", bracesFound);
210
211 assertTrue("need to contain expand-range (dependency of braces)", expandRangeFound);
212
213 final String vendorString = result.getEvidence(EvidenceType.VENDOR).toString();
214 assertThat(vendorString, containsString("Sanjeev Koranga"));
215 assertThat(vendorString, containsString("dns-sync"));
216 assertThat(result.getEvidence(EvidenceType.PRODUCT).toString(), containsString("dns-sync"));
217 assertThat(result.getEvidence(EvidenceType.VERSION).toString(), containsString("0.1.3"));
218 assertEquals(NodePackageAnalyzer.DEPENDENCY_ECOSYSTEM, result.getEcosystem());
219 assertEquals("dns-sync", result.getName());
220 assertEquals("0.1.3", result.getVersion());
221
222
223
224
225
226
227 }
228
229
230
231
232
233
234 @Test
235 public void testAnalyzePackageJsonWithShrinkwrap() throws AnalysisException, InvalidSettingException {
236 Assume.assumeThat(getSettings().getBoolean(Settings.KEYS.ANALYZER_NODE_PACKAGE_ENABLED), is(true));
237 Assume.assumeThat(getSettings().getBoolean(Settings.KEYS.ANALYZER_NODE_AUDIT_ENABLED), is(true));
238 final Dependency packageJson = new Dependency(BaseTest.getResourceAsFile(this,
239 "nodejs/package.json"));
240 final Dependency shrinkwrap = new Dependency(BaseTest.getResourceAsFile(this,
241 "nodejs/npm-shrinkwrap.json"));
242 engine.addDependency(packageJson);
243 engine.addDependency(shrinkwrap);
244 assertEquals(2, engine.getDependencies().length);
245 analyzer.analyze(packageJson, engine);
246 assertEquals(1, engine.getDependencies().length);
247 assertEquals(shrinkwrap, engine.getDependencies()[0]);
248 analyzer.analyze(shrinkwrap, engine);
249
250 testLock();
251 }
252
253
254
255
256
257
258 @Test
259 public void testWithoutLock() throws AnalysisException, InvalidSettingException {
260 Assume.assumeThat(getSettings().getBoolean(Settings.KEYS.ANALYZER_NODE_PACKAGE_ENABLED), is(true));
261 Assume.assumeThat(getSettings().getBoolean(Settings.KEYS.ANALYZER_NODE_AUDIT_ENABLED), is(true));
262 final Dependency packageJson = new Dependency(BaseTest.getResourceAsFile(this,
263 "nodejs/no_lock/package.json"));
264 engine.addDependency(packageJson);
265 analyzer.analyze(packageJson, engine);
266
267
268 assertEquals("Expected 1 dependencies", 1, engine.getDependencies().length);
269 }
270
271
272
273
274
275
276 @Test
277 public void testPackageLockV2() throws AnalysisException, InvalidSettingException {
278 Assume.assumeThat(getSettings().getBoolean(Settings.KEYS.ANALYZER_NODE_PACKAGE_ENABLED), is(true));
279 Assume.assumeThat(getSettings().getBoolean(Settings.KEYS.ANALYZER_NODE_AUDIT_ENABLED), is(true));
280 final Dependency packageJson = new Dependency(BaseTest.getResourceAsFile(this,
281 "nodejs/test_lockv2/package.json"));
282 final Dependency packageLockJson = new Dependency(BaseTest.getResourceAsFile(this,
283 "nodejs/test_lockv2/package-lock.json"));
284 engine.addDependency(packageJson);
285 engine.addDependency(packageLockJson);
286 analyzer.analyze(packageJson, engine);
287 assertEquals("Expected 1 dependencies", 1, engine.getDependencies().length);
288 analyzer.analyze(packageLockJson, engine);
289 assertEquals("Expected 1 dependencies", 6, engine.getDependencies().length);
290 }
291
292
293
294
295
296
297 @Test
298 public void testPackageLockV3() throws AnalysisException, InvalidSettingException {
299 Assume.assumeThat(getSettings().getBoolean(Settings.KEYS.ANALYZER_NODE_PACKAGE_ENABLED), is(true));
300 Assume.assumeThat(getSettings().getBoolean(Settings.KEYS.ANALYZER_NODE_AUDIT_ENABLED), is(true));
301 final Dependency packageJson = new Dependency(BaseTest.getResourceAsFile(this,
302 "nodejs/test_lockv3/package.json"));
303 final Dependency packageLockJson = new Dependency(BaseTest.getResourceAsFile(this,
304 "nodejs/test_lockv3/package-lock.json"));
305 engine.addDependency(packageJson);
306 engine.addDependency(packageLockJson);
307 analyzer.analyze(packageJson, engine);
308 assertEquals("Expected 1 dependencies", 1, engine.getDependencies().length);
309 analyzer.analyze(packageLockJson, engine);
310 assertEquals("Expected 1 dependencies", 6, engine.getDependencies().length);
311 }
312
313
314
315
316
317
318
319
320 @Test
321 public void testLocalPackageDependency() throws AnalysisException, InvalidSettingException {
322 Assume.assumeThat(getSettings().getBoolean(Settings.KEYS.ANALYZER_NODE_PACKAGE_ENABLED), is(true));
323 final Dependency packageJson = new Dependency(BaseTest.getResourceAsFile(this,
324 "nodejs/local_package/package.json"));
325 final Dependency packageLockJson = new Dependency(BaseTest.getResourceAsFile(this,
326 "nodejs/local_package/package-lock.json"));
327 engine.addDependency(packageJson);
328 engine.addDependency(packageLockJson);
329 analyzer.analyze(packageJson, engine);
330 assertEquals("Expected 1 dependencies", 1, engine.getDependencies().length);
331 analyzer.analyze(packageLockJson, engine);
332 assertEquals("Expected 2 dependencies", 2, engine.getDependencies().length);
333 }
334 }