github.com/anchore/syft@v1.38.2/syft/pkg/cataloger/javascript/parse_yarn_lock_test.go (about) 1 package javascript 2 3 import ( 4 "context" 5 "io" 6 "net/http" 7 "net/http/httptest" 8 "os" 9 "testing" 10 11 "github.com/stretchr/testify/assert" 12 13 "github.com/anchore/syft/syft/artifact" 14 "github.com/anchore/syft/syft/file" 15 "github.com/anchore/syft/syft/pkg" 16 "github.com/anchore/syft/syft/pkg/cataloger/internal/pkgtest" 17 ) 18 19 func TestParseYarnBerry(t *testing.T) { 20 fixture := "test-fixtures/yarn-berry/yarn.lock" 21 locations := file.NewLocationSet(file.NewLocation(fixture)) 22 23 expectedPkgs := []pkg.Package{ 24 { 25 Name: "@babel/code-frame", 26 Version: "7.10.4", 27 Locations: locations, 28 PURL: "pkg:npm/%40babel/code-frame@7.10.4", 29 Language: pkg.JavaScript, 30 Type: pkg.NpmPkg, 31 Metadata: pkg.YarnLockEntry{ 32 Resolved: "@babel/code-frame@npm:7.10.4", 33 Integrity: "feb4543c8a509fe30f0f6e8d7aa84f82b41148b963b826cd330e34986f649a85cb63b2f13dd4effdf434ac555d16f14940b8ea5f4433297c2f5ff85486ded019", 34 Dependencies: map[string]string{ 35 "@babel/highlight": "^7.10.4", 36 }, 37 }, 38 }, 39 { 40 Name: "@types/minimatch", 41 Version: "3.0.3", 42 Locations: locations, 43 PURL: "pkg:npm/%40types/minimatch@3.0.3", 44 Language: pkg.JavaScript, 45 Type: pkg.NpmPkg, 46 Metadata: pkg.YarnLockEntry{ 47 Resolved: "@types/minimatch@npm:3.0.3", 48 Integrity: "b80259d55b96ef24cb3bb961b6dc18b943f2bb8838b4d8e7bead204f3173e551a416ffa49f9aaf1dc431277fffe36214118628eacf4aea20119df8835229901b", 49 }, 50 }, 51 { 52 Name: "@types/qs", 53 Version: "6.9.4", 54 Locations: locations, 55 PURL: "pkg:npm/%40types/qs@6.9.4", 56 Language: pkg.JavaScript, 57 Type: pkg.NpmPkg, 58 Metadata: pkg.YarnLockEntry{ 59 Resolved: "@types/qs@npm:6.9.4", 60 Integrity: "77e509ed213f7694ae35f84a58b88da8744aad019e93556af6aeab4289287abbe71836c051d00649dbac0289ea199e408442590cfb1785009de11c3c8d0cbbea", 61 }, 62 }, 63 { 64 Name: "ajv", 65 Version: "6.12.3", 66 Locations: locations, 67 PURL: "pkg:npm/ajv@6.12.3", 68 Language: pkg.JavaScript, 69 Type: pkg.NpmPkg, 70 Metadata: pkg.YarnLockEntry{ 71 Resolved: "ajv@npm:6.12.3", 72 Integrity: "ca559d34710e6969d33bc1316282e1ece4d4d99ff5fdca4bfe31947740f8f90e7824238cdc2954e499cf75b2432e3e6c56b32814ebe04fccf8abcc3fbf36b348", 73 Dependencies: map[string]string{ 74 "fast-deep-equal": "^3.1.1", 75 "fast-json-stable-stringify": "^2.0.0", 76 "json-schema-traverse": "^0.4.1", 77 "uri-js": "^4.2.2", 78 }, 79 }, 80 }, 81 { 82 Name: "asn1.js", 83 Version: "4.10.1", 84 Locations: locations, 85 PURL: "pkg:npm/asn1.js@4.10.1", 86 Language: pkg.JavaScript, 87 Type: pkg.NpmPkg, 88 Metadata: pkg.YarnLockEntry{ 89 Resolved: "asn1.js@npm:4.10.1", 90 Integrity: "9289a1a55401238755e3142511d7b8f6fc32f08c86ff68bd7100da8b6c186179dd6b14234fba2f7f6099afcd6758a816708485efe44bc5b2a6ec87d9ceeddbb5", 91 Dependencies: map[string]string{ 92 "bn.js": "^4.0.0", 93 "inherits": "^2.0.1", 94 "minimalistic-assert": "^1.0.0", 95 }, 96 }, 97 }, 98 { 99 Name: "atob", 100 Version: "2.1.2", 101 Locations: locations, 102 PURL: "pkg:npm/atob@2.1.2", 103 Language: pkg.JavaScript, 104 Type: pkg.NpmPkg, 105 Metadata: pkg.YarnLockEntry{ 106 Resolved: "atob@npm:2.1.2", 107 Integrity: "dfeeeb70090c5ebea7be4b9f787f866686c645d9f39a0d184c817252d0cf08455ed25267d79c03254d3be1f03ac399992a792edcd5ffb9c91e097ab5ef42833a", 108 }, 109 }, 110 { 111 Name: "aws-sdk", 112 Version: "2.706.0", 113 PURL: "pkg:npm/aws-sdk@2.706.0", 114 Locations: locations, 115 Language: pkg.JavaScript, 116 Type: pkg.NpmPkg, 117 Metadata: pkg.YarnLockEntry{ 118 Resolved: "aws-sdk@npm:2.706.0", 119 Integrity: "bf8ca2fc4f758bdebd04051ec15729affad3eb0e18eed4ae41db5b7d6ff2aed2cf3a12ae082c11b955df0125378c57b8406e1f91006e48f0c162fdbe4ee4e330", 120 Dependencies: map[string]string{ 121 "buffer": "4.9.2", 122 "events": "1.1.1", 123 "ieee754": "1.1.13", 124 "jmespath": "0.15.0", 125 "querystring": "0.2.0", 126 "sax": "1.2.1", 127 "url": "0.10.3", 128 "uuid": "3.3.2", 129 "xml2js": "0.4.19", 130 }, 131 }, 132 }, 133 { 134 Name: "c0n-fab_u.laTION", 135 Version: "7.7.7", 136 Locations: locations, 137 PURL: "pkg:npm/c0n-fab_u.laTION@7.7.7", 138 Language: pkg.JavaScript, 139 Type: pkg.NpmPkg, 140 Metadata: pkg.YarnLockEntry{ 141 Resolved: "newtest@workspace:.", 142 Dependencies: map[string]string{ 143 "@babel/code-frame": "7.10.4", 144 "@types/minimatch": "3.0.3", 145 "@types/qs": "6.9.4", 146 "ajv": "6.12.3", 147 "asn1.js": "4.10.1", 148 "atob": "2.1.2", 149 }}, 150 }, 151 { 152 Name: "jhipster-core", 153 Version: "7.3.4", 154 Locations: locations, 155 PURL: "pkg:npm/jhipster-core@7.3.4", 156 Language: pkg.JavaScript, 157 Type: pkg.NpmPkg, 158 Metadata: pkg.YarnLockEntry{ 159 Resolved: "jhipster-core@npm:7.3.4", 160 Integrity: "6a97741d574a42a138f98596c668370b41ec8870335bcd758b6b890e279ba30d4d2be447f8cecbf416286f2c53636b406a63a773c7b00709c95af0a9a3f9b397", 161 Dependencies: map[string]string{ 162 "chevrotain": "7.0.1", 163 "fs-extra": "8.1.0", 164 "lodash": "4.17.15", 165 "winston": "3.2.1", 166 }, 167 }, 168 }, 169 } 170 expectedRelationships := []artifact.Relationship{ 171 { 172 From: expectedPkgs[0], 173 To: expectedPkgs[7], 174 Type: artifact.DependencyOfRelationship, 175 }, 176 { 177 From: expectedPkgs[1], 178 To: expectedPkgs[7], 179 Type: artifact.DependencyOfRelationship, 180 }, 181 { 182 From: expectedPkgs[2], 183 To: expectedPkgs[7], 184 Type: artifact.DependencyOfRelationship, 185 }, 186 { 187 From: expectedPkgs[3], 188 To: expectedPkgs[7], 189 Type: artifact.DependencyOfRelationship, 190 }, 191 { 192 From: expectedPkgs[4], 193 To: expectedPkgs[7], 194 Type: artifact.DependencyOfRelationship, 195 }, 196 { 197 From: expectedPkgs[5], 198 To: expectedPkgs[7], 199 Type: artifact.DependencyOfRelationship, 200 }, 201 } 202 203 adapter := newGenericYarnLockAdapter(CatalogerConfig{}) 204 pkgtest.TestFileParser(t, fixture, adapter.parseYarnLock, expectedPkgs, expectedRelationships) 205 } 206 207 func TestParseYarnLock(t *testing.T) { 208 var expectedRelationships []artifact.Relationship 209 fixture := "test-fixtures/yarn/yarn.lock" 210 locations := file.NewLocationSet(file.NewLocation(fixture)) 211 212 expectedPkgs := []pkg.Package{ 213 { 214 Name: "@babel/code-frame", 215 Version: "7.10.4", 216 Locations: locations, 217 PURL: "pkg:npm/%40babel/code-frame@7.10.4", 218 Language: pkg.JavaScript, 219 Type: pkg.NpmPkg, 220 Metadata: pkg.YarnLockEntry{ 221 Resolved: "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.10.4.tgz#168da1a36e90da68ae8d49c0f1b48c7c6249213a", 222 Integrity: "sha512-vG6SvB6oYEhvgisZNFRmRCUkLz11c7rp+tbNTynGqc6mS1d5ATd/sGyV6W0KZZnXRKMTzZDRgQT3Ou9jhpAfUg==", 223 Dependencies: map[string]string{ 224 "@babel/highlight": "^7.10.4", 225 }, 226 }, 227 }, 228 { 229 Name: "@types/minimatch", 230 Version: "3.0.3", 231 Locations: locations, 232 PURL: "pkg:npm/%40types/minimatch@3.0.3", 233 Language: pkg.JavaScript, 234 Type: pkg.NpmPkg, 235 Metadata: pkg.YarnLockEntry{ 236 Resolved: "https://registry.yarnpkg.com/@types/minimatch/-/minimatch-3.0.3.tgz#3dca0e3f33b200fc7d1139c0cd96c1268cadfd9d", 237 Integrity: "sha512-tHq6qdbT9U1IRSGf14CL0pUlULksvY9OZ+5eEgl1N7t+OA3tGvNpxJCzuKQlsNgCVwbAs670L1vcVQi8j9HjnA==", 238 Dependencies: map[string]string{}, 239 }, 240 }, 241 { 242 Name: "@types/qs", 243 Version: "6.9.4", 244 Locations: locations, 245 PURL: "pkg:npm/%40types/qs@6.9.4", 246 Language: pkg.JavaScript, 247 Type: pkg.NpmPkg, 248 Metadata: pkg.YarnLockEntry{ 249 Resolved: "https://registry.yarnpkg.com/@types/qs/-/qs-6.9.4.tgz#a59e851c1ba16c0513ea123830dd639a0a15cb6a", 250 Integrity: "sha512-+wYo+L6ZF6BMoEjtf8zB2esQsqdV6WsjRK/GP9WOgLPrq87PbNWgIxS76dS5uvl/QXtHGakZmwTznIfcPXcKlQ==", 251 Dependencies: map[string]string{}, 252 }, 253 }, 254 { 255 Name: "ajv", 256 Version: "6.12.3", 257 Locations: locations, 258 PURL: "pkg:npm/ajv@6.12.3", 259 Language: pkg.JavaScript, 260 Type: pkg.NpmPkg, 261 Metadata: pkg.YarnLockEntry{ 262 Resolved: "https://registry.yarnpkg.com/ajv/-/ajv-6.12.3.tgz#18c5af38a111ddeb4f2697bd78d68abc1cabd706", 263 Integrity: "sha512-4K0cK3L1hsqk9xIb2z9vs/XU+PGJZ9PNpJRDS9YLzmNdX6jmVPfamLvTJr0aDAusnHyCHO6MjzlkAsgtqp9teA==", 264 Dependencies: map[string]string{ 265 "fast-deep-equal": "^3.1.1", 266 "fast-json-stable-stringify": "^2.0.0", 267 "json-schema-traverse": "^0.4.1", 268 "uri-js": "^4.2.2", 269 }, 270 }, 271 }, 272 { 273 Name: "asn1.js", 274 Version: "4.10.1", 275 Locations: locations, 276 PURL: "pkg:npm/asn1.js@4.10.1", 277 Language: pkg.JavaScript, 278 Type: pkg.NpmPkg, 279 Metadata: pkg.YarnLockEntry{ 280 Resolved: "https://registry.yarnpkg.com/asn1.js/-/asn1.js-4.10.1.tgz#b9c2bf5805f1e64aadeed6df3a2bfafb5a73f5a0", 281 Integrity: "sha512-p32cOF5q0Zqs9uBiONKYLm6BClCoBCM5O9JfeUSlnQLBTxYdTK+pW+nXflm8UkKd2UYlEbYz5qEi0JuZR9ckSw==", 282 Dependencies: map[string]string{ 283 "bn.js": "^4.0.0", 284 "inherits": "^2.0.1", 285 "minimalistic-assert": "^1.0.0", 286 }, 287 }, 288 }, 289 { 290 Name: "atob", 291 Version: "2.1.2", 292 Locations: locations, 293 294 PURL: "pkg:npm/atob@2.1.2", 295 Language: pkg.JavaScript, 296 Type: pkg.NpmPkg, 297 Metadata: pkg.YarnLockEntry{ 298 Resolved: "https://registry.yarnpkg.com/atob/-/atob-2.1.2.tgz#6d9517eb9e030d2436666651e86bd9f6f13533c9", 299 Integrity: "sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==", 300 Dependencies: map[string]string{}, 301 }, 302 }, 303 { 304 Name: "aws-sdk", 305 Version: "2.706.0", 306 Locations: locations, 307 PURL: "pkg:npm/aws-sdk@2.706.0", 308 Language: pkg.JavaScript, 309 Type: pkg.NpmPkg, 310 Metadata: pkg.YarnLockEntry{ 311 Resolved: "https://registry.yarnpkg.com/aws-sdk/-/aws-sdk-2.706.0.tgz#09f65e9a91ecac5a635daf934082abae30eca953", 312 Integrity: "sha512-7GT+yrB5Wb/zOReRdv/Pzkb2Qt+hz6B/8FGMVaoysX3NryHvQUdz7EQWi5yhg9CxOjKxdw5lFwYSs69YlSp1KA==", 313 Dependencies: map[string]string{ 314 "buffer": "4.9.2", 315 "events": "1.1.1", 316 "ieee754": "1.1.13", 317 "jmespath": "0.15.0", 318 "querystring": "0.2.0", 319 "sax": "1.2.1", 320 "url": "0.10.3", 321 "uuid": "3.3.2", 322 "xml2js": "0.4.19", 323 }, 324 }, 325 }, 326 { 327 Name: "jhipster-core", 328 Version: "7.3.4", 329 Locations: locations, 330 PURL: "pkg:npm/jhipster-core@7.3.4", 331 Language: pkg.JavaScript, 332 Type: pkg.NpmPkg, 333 Metadata: pkg.YarnLockEntry{ 334 Resolved: "https://registry.yarnpkg.com/jhipster-core/-/jhipster-core-7.3.4.tgz#c34b8c97c7f4e8b7518dae015517e2112c73cc80", 335 Integrity: "sha512-AUhT69kNkqppaJZVfan/xnKG4Gs9Ggj7YLtTZFVe+xg+THrbMb5Ng7PL07PDlDw4KAEA33GMCwuAf65E8EpC4g==", 336 Dependencies: map[string]string{ 337 "chevrotain": "7.0.1", 338 "fs-extra": "8.1.0", 339 "lodash": "4.17.15", 340 "winston": "3.2.1", 341 }, 342 }, 343 }, 344 { 345 Name: "something-i-made-up", 346 Version: "7.7.7", 347 Locations: locations, 348 PURL: "pkg:npm/something-i-made-up@7.7.7", 349 Language: pkg.JavaScript, 350 Type: pkg.NpmPkg, 351 Metadata: pkg.YarnLockEntry{ 352 Resolved: "https://registry.yarnpkg.com/something-i-made-up/-/c0n-fab_u.laTION-7.7.7.tgz#b9c2bf5805f1e64aadeed6df3a2bfafb5a73f5a0", 353 Integrity: "sha512-p32cOF5q0Zqs9uBiONKYLm6BClCoBCM5O9JfeUSlnQLBTxYdTK+pW+nXflm8UkKd2UYlEbYz5qEi0JuZR9ckSw==", 354 Dependencies: map[string]string{}, 355 }, 356 }, 357 } 358 359 adapter := newGenericYarnLockAdapter(CatalogerConfig{}) 360 pkgtest.TestFileParser(t, fixture, adapter.parseYarnLock, expectedPkgs, expectedRelationships) 361 } 362 363 func TestParseYarnLockWithRelationships(t *testing.T) { 364 fixture := "test-fixtures/yarn-v1-deps/yarn.lock" 365 locations := file.NewLocationSet(file.NewLocation(fixture)) 366 367 expectedPkgs := []pkg.Package{ 368 { 369 Name: "@babel/code-frame", 370 Version: "7.10.4", 371 Locations: locations, 372 PURL: "pkg:npm/%40babel/code-frame@7.10.4", 373 Language: pkg.JavaScript, 374 Type: pkg.NpmPkg, 375 Metadata: pkg.YarnLockEntry{ 376 Resolved: "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.10.4.tgz#168da1a36e90da68ae8d49c0f1b48c7c6249213a", 377 Integrity: "sha512-vG6SvB6oYEhvgisZNFRmRCUkLz11c7rp+tbNTynGqc6mS1d5ATd/sGyV6W0KZZnXRKMTzZDRgQT3Ou9jhpAfUg==", 378 Dependencies: map[string]string{ 379 "@babel/highlight": "^7.10.4", 380 }, 381 }, 382 }, 383 { 384 Name: "@types/minimatch", 385 Version: "3.0.3", 386 Locations: locations, 387 PURL: "pkg:npm/%40types/minimatch@3.0.3", 388 Language: pkg.JavaScript, 389 Type: pkg.NpmPkg, 390 Metadata: pkg.YarnLockEntry{ 391 Resolved: "https://registry.yarnpkg.com/@types/minimatch/-/minimatch-3.0.3.tgz#3dca0e3f33b200fc7d1139c0cd96c1268cadfd9d", 392 Integrity: "sha512-tHq6qdbT9U1IRSGf14CL0pUlULksvY9OZ+5eEgl1N7t+OA3tGvNpxJCzuKQlsNgCVwbAs670L1vcVQi8j9HjnA==", 393 Dependencies: map[string]string{}, 394 }, 395 }, 396 { 397 Name: "@types/qs", 398 Version: "6.9.4", 399 Locations: locations, 400 PURL: "pkg:npm/%40types/qs@6.9.4", 401 Language: pkg.JavaScript, 402 Type: pkg.NpmPkg, 403 Metadata: pkg.YarnLockEntry{ 404 Resolved: "https://registry.yarnpkg.com/@types/qs/-/qs-6.9.4.tgz#a59e851c1ba16c0513ea123830dd639a0a15cb6a", 405 Integrity: "sha512-+wYo+L6ZF6BMoEjtf8zB2esQsqdV6WsjRK/GP9WOgLPrq87PbNWgIxS76dS5uvl/QXtHGakZmwTznIfcPXcKlQ==", 406 Dependencies: map[string]string{}, 407 }, 408 }, 409 { 410 Name: "ajv", 411 Version: "6.12.3", 412 Locations: locations, 413 PURL: "pkg:npm/ajv@6.12.3", 414 Language: pkg.JavaScript, 415 Type: pkg.NpmPkg, 416 Metadata: pkg.YarnLockEntry{ 417 Resolved: "https://registry.yarnpkg.com/ajv/-/ajv-6.12.3.tgz#18c5af38a111ddeb4f2697bd78d68abc1cabd706", 418 Integrity: "sha512-4K0cK3L1hsqk9xIb2z9vs/XU+PGJZ9PNpJRDS9YLzmNdX6jmVPfamLvTJr0aDAusnHyCHO6MjzlkAsgtqp9teA==", 419 Dependencies: map[string]string{ 420 "fast-deep-equal": "^3.1.1", 421 "fast-json-stable-stringify": "^2.0.0", 422 "json-schema-traverse": "^0.4.1", 423 "uri-js": "^4.2.2", 424 }, 425 }, 426 }, 427 { 428 Name: "asn1.js", 429 Version: "4.10.1", 430 Locations: locations, 431 PURL: "pkg:npm/asn1.js@4.10.1", 432 Language: pkg.JavaScript, 433 Type: pkg.NpmPkg, 434 Metadata: pkg.YarnLockEntry{ 435 Resolved: "https://registry.yarnpkg.com/asn1.js/-/asn1.js-4.10.1.tgz#b9c2bf5805f1e64aadeed6df3a2bfafb5a73f5a0", 436 Integrity: "sha512-p32cOF5q0Zqs9uBiONKYLm6BClCoBCM5O9JfeUSlnQLBTxYdTK+pW+nXflm8UkKd2UYlEbYz5qEi0JuZR9ckSw==", 437 Dependencies: map[string]string{ 438 "atob": "^2.1.2", 439 "bn.js": "^4.0.0", 440 "inherits": "^2.0.1", 441 "minimalistic-assert": "^1.0.0", 442 }, 443 }, 444 }, 445 { 446 Name: "atob", 447 Version: "2.1.2", 448 Locations: locations, 449 450 PURL: "pkg:npm/atob@2.1.2", 451 Language: pkg.JavaScript, 452 Type: pkg.NpmPkg, 453 Metadata: pkg.YarnLockEntry{ 454 Resolved: "https://registry.yarnpkg.com/atob/-/atob-2.1.2.tgz#6d9517eb9e030d2436666651e86bd9f6f13533c9", 455 Integrity: "sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==", 456 Dependencies: map[string]string{}, 457 }, 458 }, 459 { 460 Name: "aws-sdk", 461 Version: "2.706.0", 462 Locations: locations, 463 PURL: "pkg:npm/aws-sdk@2.706.0", 464 Language: pkg.JavaScript, 465 Type: pkg.NpmPkg, 466 Metadata: pkg.YarnLockEntry{ 467 Resolved: "https://registry.yarnpkg.com/aws-sdk/-/aws-sdk-2.706.0.tgz#09f65e9a91ecac5a635daf934082abae30eca953", 468 Integrity: "sha512-7GT+yrB5Wb/zOReRdv/Pzkb2Qt+hz6B/8FGMVaoysX3NryHvQUdz7EQWi5yhg9CxOjKxdw5lFwYSs69YlSp1KA==", 469 Dependencies: map[string]string{ 470 "asn1.js": "4.10.1", 471 "buffer": "4.9.2", 472 "events": "1.1.1", 473 "ieee754": "1.1.13", 474 "jmespath": "0.15.0", 475 "querystring": "0.2.0", 476 "sax": "1.2.1", 477 "url": "0.10.3", 478 "uuid": "3.3.2", 479 "xml2js": "0.4.19", 480 }, 481 }, 482 }, 483 { 484 Name: "jhipster-core", 485 Version: "7.3.4", 486 Locations: locations, 487 PURL: "pkg:npm/jhipster-core@7.3.4", 488 Language: pkg.JavaScript, 489 Type: pkg.NpmPkg, 490 Metadata: pkg.YarnLockEntry{ 491 Resolved: "https://registry.yarnpkg.com/jhipster-core/-/jhipster-core-7.3.4.tgz#c34b8c97c7f4e8b7518dae015517e2112c73cc80", 492 Integrity: "sha512-AUhT69kNkqppaJZVfan/xnKG4Gs9Ggj7YLtTZFVe+xg+THrbMb5Ng7PL07PDlDw4KAEA33GMCwuAf65E8EpC4g==", 493 Dependencies: map[string]string{ 494 "chevrotain": "7.0.1", 495 "fs-extra": "8.1.0", 496 "lodash": "4.17.15", 497 "winston": "3.2.1", 498 }, 499 }, 500 }, 501 { 502 Name: "something-i-made-up", 503 Version: "7.7.7", 504 Locations: locations, 505 PURL: "pkg:npm/something-i-made-up@7.7.7", 506 Language: pkg.JavaScript, 507 Type: pkg.NpmPkg, 508 Metadata: pkg.YarnLockEntry{ 509 Resolved: "https://registry.yarnpkg.com/something-i-made-up/-/c0n-fab_u.laTION-7.7.7.tgz#b9c2bf5805f1e64aadeed6df3a2bfafb5a73f5a0", 510 Integrity: "sha512-p32cOF5q0Zqs9uBiONKYLm6BClCoBCM5O9JfeUSlnQLBTxYdTK+pW+nXflm8UkKd2UYlEbYz5qEi0JuZR9ckSw==", 511 Dependencies: map[string]string{}, 512 }, 513 }, 514 } 515 516 expectedRelationships := []artifact.Relationship{ 517 { 518 From: expectedPkgs[4], 519 To: expectedPkgs[6], 520 Type: artifact.DependencyOfRelationship, 521 }, 522 { 523 From: expectedPkgs[5], 524 To: expectedPkgs[4], 525 Type: artifact.DependencyOfRelationship, 526 }, 527 } 528 adapter := newGenericYarnLockAdapter(CatalogerConfig{}) 529 pkgtest.TestFileParser(t, fixture, adapter.parseYarnLock, expectedPkgs, expectedRelationships) 530 } 531 func TestParseYarnLockWithDuplicates(t *testing.T) { 532 var expectedRelationships []artifact.Relationship 533 fixture := "test-fixtures/yarn-dups/yarn.lock" 534 locations := file.NewLocationSet(file.NewLocation(fixture)) 535 536 expectedPkgs := []pkg.Package{ 537 { 538 Name: "async", 539 Version: "0.9.2", 540 Locations: locations, 541 PURL: "pkg:npm/async@0.9.2", 542 Language: pkg.JavaScript, 543 Type: pkg.NpmPkg, 544 Metadata: pkg.YarnLockEntry{ 545 Resolved: "https://registry.yarnpkg.com/async/-/async-0.9.2.tgz#aea74d5e61c1f899613bf64bda66d4c78f2fd17d", 546 Integrity: "sha1-rqdNXmHB+JlhO/ZL2mbUx48v0X0=", 547 Dependencies: map[string]string{}, 548 }, 549 }, 550 { 551 Name: "async", 552 Version: "3.2.3", 553 Locations: locations, 554 PURL: "pkg:npm/async@3.2.3", 555 Language: pkg.JavaScript, 556 Type: pkg.NpmPkg, 557 Metadata: pkg.YarnLockEntry{ 558 Resolved: "https://registry.yarnpkg.com/async/-/async-3.2.3.tgz#ac53dafd3f4720ee9e8a160628f18ea91df196c9", 559 Integrity: "sha512-spZRyzKL5l5BZQrr/6m/SqFdBN0q3OCI0f9rjfBzCMBIP4p75P620rR3gTmaksNOhmzgdxcaxdNfMy6anrbM0g==", 560 Dependencies: map[string]string{}, 561 }, 562 }, 563 { 564 Name: "merge-objects", 565 Version: "1.0.5", 566 Locations: locations, 567 PURL: "pkg:npm/merge-objects@1.0.5", 568 Language: pkg.JavaScript, 569 Type: pkg.NpmPkg, 570 Metadata: pkg.YarnLockEntry{ 571 Resolved: "https://registry.yarnpkg.com/merge-objects/-/merge-objects-1.0.5.tgz#ad923ff3910091acc1438f53eb75b8f37d862a86", 572 Integrity: "sha1-rZI/85EAkazBQ49T63W4832GKoY=", 573 Dependencies: map[string]string{}, 574 }, 575 }, 576 { 577 Name: "@4lolo/resize-observer-polyfill", 578 Version: "1.5.2", 579 Locations: locations, 580 PURL: "pkg:npm/%404lolo/resize-observer-polyfill@1.5.2", 581 Language: pkg.JavaScript, 582 Type: pkg.NpmPkg, 583 Metadata: pkg.YarnLockEntry{ 584 Resolved: "https://registry.yarnpkg.com/@4lolo/resize-observer-polyfill/-/resize-observer-polyfill-1.5.2.tgz#58868fc7224506236b5550d0c68357f0a874b84b", 585 Integrity: "sha512-HY4JYLITsWBOdeqCF/x3q7Aa2PVl/BmfkPv4H/Qzplc4Lrn9cKmWz6jHyAREH9tFuD0xELjJVgX3JaEmdcXu3g==", 586 Dependencies: map[string]string{}, 587 }, 588 }, 589 { 590 Name: "should-type", 591 Version: "1.3.0", 592 Locations: locations, 593 PURL: "pkg:npm/should-type@1.3.0", 594 Language: pkg.JavaScript, 595 Type: pkg.NpmPkg, 596 Metadata: pkg.YarnLockEntry{ 597 Resolved: "https://github.com/shouldjs/type.git#31d26945cb3b4ad21d2308776e4442c461666390", 598 Integrity: "", 599 Dependencies: map[string]string{}, 600 }, 601 }, 602 } 603 604 adapter := newGenericYarnLockAdapter(CatalogerConfig{}) 605 pkgtest.TestFileParser(t, fixture, adapter.parseYarnLock, expectedPkgs, expectedRelationships) 606 } 607 608 type handlerPath struct { 609 path string 610 handler func(w http.ResponseWriter, r *http.Request) 611 } 612 613 func TestSearchYarnForLicenses(t *testing.T) { 614 ctx := context.TODO() 615 fixture := "test-fixtures/yarn-remote/yarn.lock" 616 locations := file.NewLocationSet(file.NewLocation(fixture)) 617 mux, url, teardown := setupYarnRegistry() 618 defer teardown() 619 tests := []struct { 620 name string 621 fixture string 622 config CatalogerConfig 623 requestHandlers []handlerPath 624 expectedPackages []pkg.Package 625 }{ 626 { 627 name: "search remote licenses returns the expected licenses when search is set to true", 628 config: CatalogerConfig{SearchRemoteLicenses: true}, 629 requestHandlers: []handlerPath{ 630 { 631 // https://registry.yarnpkg.com/@babel/code-frame/7.10.4 632 path: "/@babel/code-frame/7.10.4", 633 handler: generateMockYarnRegistryHandler("test-fixtures/yarn-remote/registry_response.json"), 634 }, 635 }, 636 expectedPackages: []pkg.Package{ 637 { 638 Name: "@babel/code-frame", 639 Version: "7.10.4", 640 Locations: locations, 641 PURL: "pkg:npm/%40babel/code-frame@7.10.4", 642 Licenses: pkg.NewLicenseSet(pkg.NewLicenseWithContext(ctx, "MIT")), 643 Language: pkg.JavaScript, 644 Type: pkg.NpmPkg, 645 Metadata: pkg.YarnLockEntry{ 646 Resolved: "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.10.4.tgz#168da1a36e90da68ae8d49c0f1b48c7c6249213a", 647 Integrity: "sha512-vG6SvB6oYEhvgisZNFRmRCUkLz11c7rp+tbNTynGqc6mS1d5ATd/sGyV6W0KZZnXRKMTzZDRgQT3Ou9jhpAfUg==", 648 Dependencies: map[string]string{ 649 "@babel/highlight": "^7.10.4", 650 }, 651 }, 652 }, 653 }, 654 }, 655 } 656 657 for _, tc := range tests { 658 t.Run(tc.name, func(t *testing.T) { 659 // set up the mock server 660 for _, handler := range tc.requestHandlers { 661 mux.HandleFunc(handler.path, handler.handler) 662 } 663 tc.config.NPMBaseURL = url 664 adapter := newGenericYarnLockAdapter(tc.config) 665 pkgtest.NewCatalogTester(). 666 FromFile(t, fixture). 667 Expects(tc.expectedPackages, nil). 668 WithoutTestObserver(). // this is an online test, thus not the default configuration 669 TestParser(t, adapter.parseYarnLock) 670 }) 671 } 672 } 673 674 func TestParseYarnFindPackageNames(t *testing.T) { 675 tests := []struct { 676 line string 677 expected string 678 }{ 679 { 680 line: `"@babel/code-frame@npm:7.10.4":`, 681 expected: "@babel/code-frame", 682 }, 683 { 684 line: `"@babel/code-frame@^7.0.0", "@babel/code-frame@^7.10.4":`, 685 expected: "@babel/code-frame", 686 }, 687 { 688 line: "ajv@^6.10.2, ajv@^6.5.5:", 689 expected: "ajv", 690 }, 691 { 692 line: "aws-sdk@2.706.0:", 693 expected: "aws-sdk", 694 }, 695 { 696 line: "asn1.js@^4.0.0:", 697 expected: "asn1.js", 698 }, 699 { 700 line: "c0n-fab_u.laTION@^7.0.0", 701 expected: "c0n-fab_u.laTION", 702 }, 703 { 704 line: `"newtest@workspace:.":`, 705 expected: "newtest", 706 }, 707 { 708 line: `"color-convert@npm:^1.9.0":`, 709 expected: "color-convert", 710 }, 711 { 712 line: `"@npmcorp/code-frame@^7.1.0", "@npmcorp/code-frame@^7.10.4":`, 713 expected: "@npmcorp/code-frame", 714 }, 715 { 716 line: `"@npmcorp/code-frame@^7.2.3":`, 717 expected: "@npmcorp/code-frame", 718 }, 719 { 720 line: `"@s/odd-name@^7.1.2":`, 721 expected: "@s/odd-name", 722 }, 723 { 724 line: `"@/code-frame@^7.3.4":`, 725 expected: "", 726 }, 727 { 728 line: `"code-frame":`, 729 expected: "", 730 }, 731 } 732 733 for _, test := range tests { 734 t.Run(test.expected, func(t *testing.T) { 735 t.Parallel() 736 actual := findPackageName(test.line) 737 assert.Equal(t, test.expected, actual) 738 }) 739 } 740 } 741 742 func generateMockYarnRegistryHandler(responseFixture string) func(w http.ResponseWriter, r *http.Request) { 743 return func(w http.ResponseWriter, r *http.Request) { 744 w.WriteHeader(http.StatusOK) 745 // Copy the file's content to the response writer 746 file, err := os.Open(responseFixture) 747 if err != nil { 748 http.Error(w, err.Error(), http.StatusInternalServerError) 749 return 750 } 751 defer file.Close() 752 753 _, err = io.Copy(w, file) 754 if err != nil { 755 http.Error(w, err.Error(), http.StatusInternalServerError) 756 return 757 } 758 } 759 } 760 761 // setup sets up a test HTTP server for mocking requests to a particular registry. 762 // The returned url is injected into the Config so the client uses the test server. 763 // Tests should register handlers on mux to simulate the expected request/response structure 764 func setupYarnRegistry() (mux *http.ServeMux, serverURL string, teardown func()) { 765 // mux is the HTTP request multiplexer used with the test server. 766 mux = http.NewServeMux() 767 768 // We want to ensure that tests catch mistakes where the endpoint URL is 769 // specified as absolute rather than relative. It only makes a difference 770 // when there's a non-empty base URL path. So, use that. See issue #752. 771 apiHandler := http.NewServeMux() 772 apiHandler.Handle("/", mux) 773 // server is a test HTTP server used to provide mock API responses. 774 server := httptest.NewServer(apiHandler) 775 776 return mux, server.URL, server.Close 777 }