github.com/google/osv-scalibr@v0.4.1/extractor/filesystem/language/javascript/pnpmlock/pnpmlock_test.go (about) 1 // Copyright 2025 Google LLC 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package pnpmlock_test 16 17 import ( 18 "testing" 19 20 "github.com/google/go-cmp/cmp" 21 "github.com/google/go-cmp/cmp/cmpopts" 22 "github.com/google/osv-scalibr/extractor" 23 "github.com/google/osv-scalibr/extractor/filesystem/language/javascript/pnpmlock" 24 "github.com/google/osv-scalibr/extractor/filesystem/osv" 25 "github.com/google/osv-scalibr/extractor/filesystem/simplefileapi" 26 "github.com/google/osv-scalibr/inventory" 27 "github.com/google/osv-scalibr/purl" 28 "github.com/google/osv-scalibr/testing/extracttest" 29 ) 30 31 func TestExtractor_FileRequired(t *testing.T) { 32 tests := []struct { 33 name string 34 inputPath string 35 want bool 36 }{ 37 { 38 name: "", 39 inputPath: "", 40 want: false, 41 }, 42 { 43 name: "", 44 inputPath: "pnpm-lock.yaml", 45 want: true, 46 }, 47 { 48 name: "", 49 inputPath: "path/to/my/pnpm-lock.yaml", 50 want: true, 51 }, 52 { 53 name: "", 54 inputPath: "path/to/my/pnpm-lock.yaml/file", 55 want: false, 56 }, 57 { 58 name: "", 59 inputPath: "path/to/my/pnpm-lock.yaml.file", 60 want: false, 61 }, 62 { 63 name: "", 64 inputPath: "path.to.my.pnpm-lock.yaml", 65 want: false, 66 }, 67 { 68 name: "", 69 inputPath: "foo/node_modules/bar/pnpn-lock.yaml", 70 want: false, 71 }, 72 } 73 for _, tt := range tests { 74 t.Run(tt.name, func(t *testing.T) { 75 e := pnpmlock.Extractor{} 76 got := e.FileRequired(simplefileapi.New(tt.inputPath, nil)) 77 if got != tt.want { 78 t.Errorf("FileRequired(%s, FileInfo) got = %v, want %v", tt.inputPath, got, tt.want) 79 } 80 }) 81 } 82 } 83 84 func TestExtractor_Extract(t *testing.T) { 85 tests := []extracttest.TestTableEntry{ 86 { 87 Name: "invalid yaml", 88 InputConfig: extracttest.ScanInputMockConfig{ 89 Path: "testdata/not-yaml.txt", 90 }, 91 WantErr: extracttest.ContainsErrStr{Str: "could not extract"}, 92 WantPackages: nil, 93 }, 94 { 95 Name: "invalid dep path", 96 InputConfig: extracttest.ScanInputMockConfig{ 97 Path: "testdata/invalid-path.yaml", 98 }, 99 WantErr: extracttest.ContainsErrStr{Str: "invalid dependency path"}, 100 WantPackages: []*extractor.Package{ 101 { 102 Name: "acorn", 103 Version: "8.7.0", 104 PURLType: purl.TypeNPM, 105 Locations: []string{"testdata/invalid-path.yaml"}, 106 SourceCode: &extractor.SourceCodeIdentifier{}, 107 Metadata: osv.DepGroupMetadata{ 108 DepGroupVals: []string{}, 109 }, 110 }, 111 }, 112 }, 113 { 114 Name: "invalid dep paths (first error)", 115 InputConfig: extracttest.ScanInputMockConfig{ 116 Path: "testdata/invalid-paths.yaml", 117 }, 118 WantErr: extracttest.ContainsErrStr{Str: "invalid dependency path: invalidpath1"}, 119 WantPackages: []*extractor.Package{ 120 { 121 Name: "acorn", 122 Version: "8.7.0", 123 PURLType: purl.TypeNPM, 124 Locations: []string{"testdata/invalid-paths.yaml"}, 125 SourceCode: &extractor.SourceCodeIdentifier{}, 126 Metadata: osv.DepGroupMetadata{ 127 DepGroupVals: []string{}, 128 }, 129 }, 130 }, 131 }, 132 { 133 Name: "invalid dep paths (second error)", 134 InputConfig: extracttest.ScanInputMockConfig{ 135 Path: "testdata/invalid-paths.yaml", 136 }, 137 WantErr: extracttest.ContainsErrStr{Str: "invalid dependency path: invalidpath2"}, 138 WantPackages: []*extractor.Package{ 139 { 140 Name: "acorn", 141 Version: "8.7.0", 142 PURLType: purl.TypeNPM, 143 Locations: []string{"testdata/invalid-paths.yaml"}, 144 SourceCode: &extractor.SourceCodeIdentifier{}, 145 Metadata: osv.DepGroupMetadata{ 146 DepGroupVals: []string{}, 147 }, 148 }, 149 }, 150 }, 151 { 152 Name: "empty", 153 InputConfig: extracttest.ScanInputMockConfig{ 154 Path: "testdata/empty.yaml", 155 }, 156 WantPackages: []*extractor.Package{}, 157 }, 158 { 159 Name: "no packages", 160 InputConfig: extracttest.ScanInputMockConfig{ 161 Path: "testdata/no-packages.yaml", 162 }, 163 WantPackages: []*extractor.Package{}, 164 }, 165 { 166 Name: "one package", 167 InputConfig: extracttest.ScanInputMockConfig{ 168 Path: "testdata/one-package.yaml", 169 }, 170 WantPackages: []*extractor.Package{ 171 { 172 Name: "acorn", 173 Version: "8.7.0", 174 PURLType: purl.TypeNPM, 175 Locations: []string{"testdata/one-package.yaml"}, 176 SourceCode: &extractor.SourceCodeIdentifier{}, 177 Metadata: osv.DepGroupMetadata{ 178 DepGroupVals: []string{}, 179 }, 180 }, 181 }, 182 }, 183 { 184 Name: "one package v6 lockfile", 185 InputConfig: extracttest.ScanInputMockConfig{ 186 Path: "testdata/one-package-v6-lockfile.yaml", 187 }, 188 WantPackages: []*extractor.Package{ 189 { 190 Name: "acorn", 191 Version: "8.7.0", 192 PURLType: purl.TypeNPM, 193 Locations: []string{"testdata/one-package-v6-lockfile.yaml"}, 194 SourceCode: &extractor.SourceCodeIdentifier{}, 195 Metadata: osv.DepGroupMetadata{ 196 DepGroupVals: []string{}, 197 }, 198 }, 199 }, 200 }, 201 { 202 Name: "one package dev", 203 InputConfig: extracttest.ScanInputMockConfig{ 204 Path: "testdata/one-package-dev.yaml", 205 }, 206 WantPackages: []*extractor.Package{ 207 { 208 Name: "acorn", 209 Version: "8.7.0", 210 PURLType: purl.TypeNPM, 211 Locations: []string{"testdata/one-package-dev.yaml"}, 212 SourceCode: &extractor.SourceCodeIdentifier{}, 213 Metadata: osv.DepGroupMetadata{ 214 DepGroupVals: []string{}, 215 }, 216 }, 217 }, 218 }, 219 { 220 Name: "scoped packages", 221 InputConfig: extracttest.ScanInputMockConfig{ 222 Path: "testdata/scoped-packages.yaml", 223 }, 224 WantPackages: []*extractor.Package{ 225 { 226 Name: "@typescript-eslint/types", 227 Version: "5.13.0", 228 PURLType: purl.TypeNPM, 229 Locations: []string{"testdata/scoped-packages.yaml"}, 230 SourceCode: &extractor.SourceCodeIdentifier{}, 231 Metadata: osv.DepGroupMetadata{ 232 DepGroupVals: []string{}, 233 }, 234 }, 235 }, 236 }, 237 { 238 Name: "scoped packages v6 lockfile", 239 InputConfig: extracttest.ScanInputMockConfig{ 240 Path: "testdata/scoped-packages-v6-lockfile.yaml", 241 }, 242 WantPackages: []*extractor.Package{ 243 { 244 Name: "@typescript-eslint/types", 245 Version: "5.57.1", 246 PURLType: purl.TypeNPM, 247 Locations: []string{"testdata/scoped-packages-v6-lockfile.yaml"}, 248 SourceCode: &extractor.SourceCodeIdentifier{}, 249 Metadata: osv.DepGroupMetadata{ 250 DepGroupVals: []string{}, 251 }, 252 }, 253 }, 254 }, 255 { 256 Name: "peer dependencies", 257 InputConfig: extracttest.ScanInputMockConfig{ 258 Path: "testdata/peer-dependencies.yaml", 259 }, 260 WantPackages: []*extractor.Package{ 261 { 262 Name: "acorn-jsx", 263 Version: "5.3.2", 264 PURLType: purl.TypeNPM, 265 Locations: []string{"testdata/peer-dependencies.yaml"}, 266 SourceCode: &extractor.SourceCodeIdentifier{}, 267 Metadata: osv.DepGroupMetadata{ 268 DepGroupVals: []string{}, 269 }, 270 }, 271 { 272 Name: "acorn", 273 Version: "8.7.0", 274 PURLType: purl.TypeNPM, 275 Locations: []string{"testdata/peer-dependencies.yaml"}, 276 SourceCode: &extractor.SourceCodeIdentifier{}, 277 Metadata: osv.DepGroupMetadata{ 278 DepGroupVals: []string{}, 279 }, 280 }, 281 }, 282 }, 283 { 284 Name: "peer_dependencies_v6", 285 InputConfig: extracttest.ScanInputMockConfig{ 286 Path: "testdata/peer-dependencies-v6.yaml", 287 }, 288 WantPackages: []*extractor.Package{ 289 { 290 Name: "js-tokens", 291 Version: "4.0.0", 292 PURLType: purl.TypeNPM, 293 Locations: []string{"testdata/peer-dependencies-v6.yaml"}, 294 SourceCode: &extractor.SourceCodeIdentifier{}, 295 Metadata: osv.DepGroupMetadata{ 296 DepGroupVals: []string{}, 297 }, 298 }, 299 { 300 Name: "loose-envify", 301 Version: "1.4.0", 302 PURLType: purl.TypeNPM, 303 Locations: []string{"testdata/peer-dependencies-v6.yaml"}, 304 SourceCode: &extractor.SourceCodeIdentifier{}, 305 Metadata: osv.DepGroupMetadata{ 306 DepGroupVals: []string{}, 307 }, 308 }, 309 { 310 Name: "react-dom", 311 Version: "18.2.0", 312 PURLType: purl.TypeNPM, 313 Locations: []string{"testdata/peer-dependencies-v6.yaml"}, 314 SourceCode: &extractor.SourceCodeIdentifier{}, 315 Metadata: osv.DepGroupMetadata{ 316 DepGroupVals: []string{}, 317 }, 318 }, 319 { 320 Name: "react", 321 Version: "18.2.0", 322 PURLType: purl.TypeNPM, 323 Locations: []string{"testdata/peer-dependencies-v6.yaml"}, 324 SourceCode: &extractor.SourceCodeIdentifier{}, 325 Metadata: osv.DepGroupMetadata{ 326 DepGroupVals: []string{}, 327 }, 328 }, 329 { 330 Name: "scheduler", 331 Version: "0.23.0", 332 PURLType: purl.TypeNPM, 333 Locations: []string{"testdata/peer-dependencies-v6.yaml"}, 334 SourceCode: &extractor.SourceCodeIdentifier{}, 335 Metadata: osv.DepGroupMetadata{ 336 DepGroupVals: []string{}, 337 }, 338 }, 339 }, 340 }, 341 { 342 Name: "peer dependencies advanced", 343 InputConfig: extracttest.ScanInputMockConfig{ 344 Path: "testdata/peer-dependencies-advanced.yaml", 345 }, 346 WantPackages: []*extractor.Package{ 347 { 348 Name: "@typescript-eslint/eslint-plugin", 349 Version: "5.13.0", 350 PURLType: purl.TypeNPM, 351 Locations: []string{"testdata/peer-dependencies-advanced.yaml"}, 352 SourceCode: &extractor.SourceCodeIdentifier{}, 353 Metadata: osv.DepGroupMetadata{ 354 DepGroupVals: []string{}, 355 }, 356 }, 357 { 358 Name: "@typescript-eslint/parser", 359 Version: "5.13.0", 360 PURLType: purl.TypeNPM, 361 Locations: []string{"testdata/peer-dependencies-advanced.yaml"}, 362 SourceCode: &extractor.SourceCodeIdentifier{}, 363 Metadata: osv.DepGroupMetadata{ 364 DepGroupVals: []string{}, 365 }, 366 }, 367 { 368 Name: "@typescript-eslint/type-utils", 369 Version: "5.13.0", 370 PURLType: purl.TypeNPM, 371 Locations: []string{"testdata/peer-dependencies-advanced.yaml"}, 372 SourceCode: &extractor.SourceCodeIdentifier{}, 373 Metadata: osv.DepGroupMetadata{ 374 DepGroupVals: []string{}, 375 }, 376 }, 377 { 378 Name: "@typescript-eslint/types", 379 Version: "5.13.0", 380 PURLType: purl.TypeNPM, 381 Locations: []string{"testdata/peer-dependencies-advanced.yaml"}, 382 SourceCode: &extractor.SourceCodeIdentifier{}, 383 Metadata: osv.DepGroupMetadata{ 384 DepGroupVals: []string{}, 385 }, 386 }, 387 { 388 Name: "@typescript-eslint/typescript-estree", 389 Version: "5.13.0", 390 PURLType: purl.TypeNPM, 391 Locations: []string{"testdata/peer-dependencies-advanced.yaml"}, 392 SourceCode: &extractor.SourceCodeIdentifier{}, 393 Metadata: osv.DepGroupMetadata{ 394 DepGroupVals: []string{}, 395 }, 396 }, 397 { 398 Name: "@typescript-eslint/utils", 399 Version: "5.13.0", 400 PURLType: purl.TypeNPM, 401 Locations: []string{"testdata/peer-dependencies-advanced.yaml"}, 402 SourceCode: &extractor.SourceCodeIdentifier{}, 403 Metadata: osv.DepGroupMetadata{ 404 DepGroupVals: []string{}, 405 }, 406 }, 407 { 408 Name: "eslint-utils", 409 Version: "3.0.0", 410 PURLType: purl.TypeNPM, 411 Locations: []string{"testdata/peer-dependencies-advanced.yaml"}, 412 SourceCode: &extractor.SourceCodeIdentifier{}, 413 Metadata: osv.DepGroupMetadata{ 414 DepGroupVals: []string{}, 415 }, 416 }, 417 { 418 Name: "eslint", 419 Version: "8.10.0", 420 PURLType: purl.TypeNPM, 421 Locations: []string{"testdata/peer-dependencies-advanced.yaml"}, 422 SourceCode: &extractor.SourceCodeIdentifier{}, 423 Metadata: osv.DepGroupMetadata{ 424 DepGroupVals: []string{}, 425 }, 426 }, 427 { 428 Name: "tsutils", 429 Version: "3.21.0", 430 PURLType: purl.TypeNPM, 431 Locations: []string{"testdata/peer-dependencies-advanced.yaml"}, 432 SourceCode: &extractor.SourceCodeIdentifier{}, 433 Metadata: osv.DepGroupMetadata{ 434 DepGroupVals: []string{}, 435 }, 436 }, 437 }, 438 }, 439 { 440 Name: "peer_dependencies_advanced_v6", 441 InputConfig: extracttest.ScanInputMockConfig{ 442 Path: "testdata/peer-dependencies-advanced-v6.yaml", 443 }, 444 WantPackages: []*extractor.Package{ 445 { 446 Name: "js-tokens", 447 Version: "4.0.0", 448 PURLType: purl.TypeNPM, 449 Locations: []string{"testdata/peer-dependencies-advanced-v6.yaml"}, 450 SourceCode: &extractor.SourceCodeIdentifier{}, 451 Metadata: osv.DepGroupMetadata{ 452 DepGroupVals: []string{}, 453 }, 454 }, 455 { 456 Name: "loose-envify", 457 Version: "1.4.0", 458 PURLType: purl.TypeNPM, 459 Locations: []string{"testdata/peer-dependencies-advanced-v6.yaml"}, 460 SourceCode: &extractor.SourceCodeIdentifier{}, 461 Metadata: osv.DepGroupMetadata{ 462 DepGroupVals: []string{}, 463 }, 464 }, 465 { 466 Name: "react-dom", 467 Version: "18.3.0-canary-ab31a9ed2-20230824", 468 PURLType: purl.TypeNPM, 469 Locations: []string{"testdata/peer-dependencies-advanced-v6.yaml"}, 470 SourceCode: &extractor.SourceCodeIdentifier{}, 471 Metadata: osv.DepGroupMetadata{ 472 DepGroupVals: []string{}, 473 }, 474 }, 475 { 476 Name: "react", 477 Version: "18.3.0-canary-ab31a9ed2-20230824", 478 PURLType: purl.TypeNPM, 479 Locations: []string{"testdata/peer-dependencies-advanced-v6.yaml"}, 480 SourceCode: &extractor.SourceCodeIdentifier{}, 481 Metadata: osv.DepGroupMetadata{ 482 DepGroupVals: []string{}, 483 }, 484 }, 485 { 486 Name: "scheduler", 487 Version: "0.24.0-canary-ab31a9ed2-20230824", 488 PURLType: purl.TypeNPM, 489 Locations: []string{"testdata/peer-dependencies-advanced-v6.yaml"}, 490 SourceCode: &extractor.SourceCodeIdentifier{}, 491 Metadata: osv.DepGroupMetadata{ 492 DepGroupVals: []string{}, 493 }, 494 }, 495 }, 496 }, 497 { 498 Name: "peer_dependencies_advanced_rc_v6", 499 InputConfig: extracttest.ScanInputMockConfig{ 500 Path: "testdata/peer-dependencies-advanced-rc-v6.yaml", 501 }, 502 WantPackages: []*extractor.Package{ 503 { 504 Name: "js-tokens", 505 Version: "4.0.0", 506 PURLType: purl.TypeNPM, 507 Locations: []string{"testdata/peer-dependencies-advanced-rc-v6.yaml"}, 508 SourceCode: &extractor.SourceCodeIdentifier{}, 509 Metadata: osv.DepGroupMetadata{ 510 DepGroupVals: []string{}, 511 }, 512 }, 513 { 514 Name: "loose-envify", 515 Version: "1.4.0", 516 PURLType: purl.TypeNPM, 517 Locations: []string{"testdata/peer-dependencies-advanced-rc-v6.yaml"}, 518 SourceCode: &extractor.SourceCodeIdentifier{}, 519 Metadata: osv.DepGroupMetadata{ 520 DepGroupVals: []string{}, 521 }, 522 }, 523 { 524 Name: "react-dom", 525 Version: "18.0.0-rc.3", 526 PURLType: purl.TypeNPM, 527 Locations: []string{"testdata/peer-dependencies-advanced-rc-v6.yaml"}, 528 SourceCode: &extractor.SourceCodeIdentifier{}, 529 Metadata: osv.DepGroupMetadata{ 530 DepGroupVals: []string{}, 531 }, 532 }, 533 { 534 Name: "react", 535 Version: "18.2.0", 536 PURLType: purl.TypeNPM, 537 Locations: []string{"testdata/peer-dependencies-advanced-rc-v6.yaml"}, 538 SourceCode: &extractor.SourceCodeIdentifier{}, 539 Metadata: osv.DepGroupMetadata{ 540 DepGroupVals: []string{}, 541 }, 542 }, 543 { 544 Name: "scheduler", 545 Version: "0.21.0", 546 PURLType: purl.TypeNPM, 547 Locations: []string{"testdata/peer-dependencies-advanced-rc-v6.yaml"}, 548 SourceCode: &extractor.SourceCodeIdentifier{}, 549 Metadata: osv.DepGroupMetadata{ 550 DepGroupVals: []string{}, 551 }, 552 }, 553 }, 554 }, 555 { 556 Name: "multiple packages", 557 InputConfig: extracttest.ScanInputMockConfig{ 558 Path: "testdata/multiple-packages.yaml", 559 }, 560 WantPackages: []*extractor.Package{ 561 { 562 Name: "aws-sdk", 563 Version: "2.1087.0", 564 PURLType: purl.TypeNPM, 565 Locations: []string{"testdata/multiple-packages.yaml"}, 566 SourceCode: &extractor.SourceCodeIdentifier{}, 567 Metadata: osv.DepGroupMetadata{ 568 DepGroupVals: []string{}, 569 }, 570 }, 571 { 572 Name: "base64-js", 573 Version: "1.5.1", 574 PURLType: purl.TypeNPM, 575 Locations: []string{"testdata/multiple-packages.yaml"}, 576 SourceCode: &extractor.SourceCodeIdentifier{}, 577 Metadata: osv.DepGroupMetadata{ 578 DepGroupVals: []string{}, 579 }, 580 }, 581 { 582 Name: "buffer", 583 Version: "4.9.2", 584 PURLType: purl.TypeNPM, 585 Locations: []string{"testdata/multiple-packages.yaml"}, 586 SourceCode: &extractor.SourceCodeIdentifier{}, 587 Metadata: osv.DepGroupMetadata{ 588 DepGroupVals: []string{}, 589 }, 590 }, 591 { 592 Name: "events", 593 Version: "1.1.1", 594 PURLType: purl.TypeNPM, 595 Locations: []string{"testdata/multiple-packages.yaml"}, 596 SourceCode: &extractor.SourceCodeIdentifier{}, 597 Metadata: osv.DepGroupMetadata{ 598 DepGroupVals: []string{}, 599 }, 600 }, 601 { 602 Name: "ieee754", 603 Version: "1.1.13", 604 PURLType: purl.TypeNPM, 605 Locations: []string{"testdata/multiple-packages.yaml"}, 606 SourceCode: &extractor.SourceCodeIdentifier{}, 607 Metadata: osv.DepGroupMetadata{ 608 DepGroupVals: []string{}, 609 }, 610 }, 611 { 612 Name: "isarray", 613 Version: "1.0.0", 614 PURLType: purl.TypeNPM, 615 Locations: []string{"testdata/multiple-packages.yaml"}, 616 SourceCode: &extractor.SourceCodeIdentifier{}, 617 Metadata: osv.DepGroupMetadata{ 618 DepGroupVals: []string{}, 619 }, 620 }, 621 { 622 Name: "jmespath", 623 Version: "0.16.0", 624 PURLType: purl.TypeNPM, 625 Locations: []string{"testdata/multiple-packages.yaml"}, 626 SourceCode: &extractor.SourceCodeIdentifier{}, 627 Metadata: osv.DepGroupMetadata{ 628 DepGroupVals: []string{}, 629 }, 630 }, 631 { 632 Name: "punycode", 633 Version: "1.3.2", 634 PURLType: purl.TypeNPM, 635 Locations: []string{"testdata/multiple-packages.yaml"}, 636 SourceCode: &extractor.SourceCodeIdentifier{}, 637 Metadata: osv.DepGroupMetadata{ 638 DepGroupVals: []string{}, 639 }, 640 }, 641 { 642 Name: "querystring", 643 Version: "0.2.0", 644 PURLType: purl.TypeNPM, 645 Locations: []string{"testdata/multiple-packages.yaml"}, 646 SourceCode: &extractor.SourceCodeIdentifier{}, 647 Metadata: osv.DepGroupMetadata{ 648 DepGroupVals: []string{}, 649 }, 650 }, 651 { 652 Name: "sax", 653 Version: "1.2.1", 654 PURLType: purl.TypeNPM, 655 Locations: []string{"testdata/multiple-packages.yaml"}, 656 SourceCode: &extractor.SourceCodeIdentifier{}, 657 Metadata: osv.DepGroupMetadata{ 658 DepGroupVals: []string{}, 659 }, 660 }, 661 { 662 Name: "url", 663 Version: "0.10.3", 664 PURLType: purl.TypeNPM, 665 Locations: []string{"testdata/multiple-packages.yaml"}, 666 SourceCode: &extractor.SourceCodeIdentifier{}, 667 Metadata: osv.DepGroupMetadata{ 668 DepGroupVals: []string{}, 669 }, 670 }, 671 { 672 Name: "uuid", 673 Version: "3.3.2", 674 PURLType: purl.TypeNPM, 675 Locations: []string{"testdata/multiple-packages.yaml"}, 676 SourceCode: &extractor.SourceCodeIdentifier{}, 677 Metadata: osv.DepGroupMetadata{ 678 DepGroupVals: []string{}, 679 }, 680 }, 681 { 682 Name: "xml2js", 683 Version: "0.4.19", 684 PURLType: purl.TypeNPM, 685 Locations: []string{"testdata/multiple-packages.yaml"}, 686 SourceCode: &extractor.SourceCodeIdentifier{}, 687 Metadata: osv.DepGroupMetadata{ 688 DepGroupVals: []string{}, 689 }, 690 }, 691 { 692 Name: "xmlbuilder", 693 Version: "9.0.7", 694 PURLType: purl.TypeNPM, 695 Locations: []string{"testdata/multiple-packages.yaml"}, 696 SourceCode: &extractor.SourceCodeIdentifier{}, 697 Metadata: osv.DepGroupMetadata{ 698 DepGroupVals: []string{}, 699 }, 700 }, 701 }, 702 }, 703 { 704 Name: "multiple versions", 705 InputConfig: extracttest.ScanInputMockConfig{ 706 Path: "testdata/multiple-versions.yaml", 707 }, 708 WantPackages: []*extractor.Package{ 709 { 710 Name: "uuid", 711 Version: "3.3.2", 712 PURLType: purl.TypeNPM, 713 Locations: []string{"testdata/multiple-versions.yaml"}, 714 SourceCode: &extractor.SourceCodeIdentifier{}, 715 Metadata: osv.DepGroupMetadata{ 716 DepGroupVals: []string{}, 717 }, 718 }, 719 { 720 Name: "uuid", 721 Version: "8.3.2", 722 PURLType: purl.TypeNPM, 723 Locations: []string{"testdata/multiple-versions.yaml"}, 724 SourceCode: &extractor.SourceCodeIdentifier{}, 725 Metadata: osv.DepGroupMetadata{ 726 DepGroupVals: []string{}, 727 }, 728 }, 729 { 730 Name: "xmlbuilder", 731 Version: "9.0.7", 732 PURLType: purl.TypeNPM, 733 Locations: []string{"testdata/multiple-versions.yaml"}, 734 SourceCode: &extractor.SourceCodeIdentifier{}, 735 Metadata: osv.DepGroupMetadata{ 736 DepGroupVals: []string{}, 737 }, 738 }, 739 }, 740 }, 741 { 742 Name: "tarball", 743 InputConfig: extracttest.ScanInputMockConfig{ 744 Path: "testdata/tarball.yaml", 745 }, 746 WantPackages: []*extractor.Package{ 747 { 748 Name: "@my-org/my-package", 749 Version: "3.2.3", 750 PURLType: purl.TypeNPM, 751 Locations: []string{"testdata/tarball.yaml"}, 752 SourceCode: &extractor.SourceCodeIdentifier{}, 753 Metadata: osv.DepGroupMetadata{ 754 DepGroupVals: []string{"dev"}, 755 }, 756 }, 757 }, 758 }, 759 { 760 Name: "exotic", 761 InputConfig: extracttest.ScanInputMockConfig{ 762 Path: "testdata/exotic.yaml", 763 }, 764 WantPackages: []*extractor.Package{ 765 { 766 Name: "foo", 767 Version: "1.0.0", 768 PURLType: purl.TypeNPM, 769 Locations: []string{"testdata/exotic.yaml"}, 770 SourceCode: &extractor.SourceCodeIdentifier{}, 771 Metadata: osv.DepGroupMetadata{ 772 DepGroupVals: []string{}, 773 }, 774 }, 775 { 776 Name: "@foo/bar", 777 Version: "1.0.0", 778 PURLType: purl.TypeNPM, 779 Locations: []string{"testdata/exotic.yaml"}, 780 SourceCode: &extractor.SourceCodeIdentifier{}, 781 Metadata: osv.DepGroupMetadata{ 782 DepGroupVals: []string{}, 783 }, 784 }, 785 { 786 Name: "foo", 787 Version: "1.1.0", 788 PURLType: purl.TypeNPM, 789 Locations: []string{"testdata/exotic.yaml"}, 790 SourceCode: &extractor.SourceCodeIdentifier{}, 791 Metadata: osv.DepGroupMetadata{ 792 DepGroupVals: []string{}, 793 }, 794 }, 795 { 796 Name: "@foo/bar", 797 Version: "1.1.0", 798 PURLType: purl.TypeNPM, 799 Locations: []string{"testdata/exotic.yaml"}, 800 SourceCode: &extractor.SourceCodeIdentifier{}, 801 Metadata: osv.DepGroupMetadata{ 802 DepGroupVals: []string{}, 803 }, 804 }, 805 { 806 Name: "foo", 807 Version: "1.2.0", 808 PURLType: purl.TypeNPM, 809 Locations: []string{"testdata/exotic.yaml"}, 810 SourceCode: &extractor.SourceCodeIdentifier{}, 811 Metadata: osv.DepGroupMetadata{ 812 DepGroupVals: []string{}, 813 }, 814 }, 815 { 816 Name: "foo", 817 Version: "1.3.0", 818 PURLType: purl.TypeNPM, 819 Locations: []string{"testdata/exotic.yaml"}, 820 SourceCode: &extractor.SourceCodeIdentifier{}, 821 Metadata: osv.DepGroupMetadata{ 822 DepGroupVals: []string{}, 823 }, 824 }, 825 { 826 Name: "foo", 827 Version: "1.4.0", 828 PURLType: purl.TypeNPM, 829 Locations: []string{"testdata/exotic.yaml"}, 830 SourceCode: &extractor.SourceCodeIdentifier{}, 831 Metadata: osv.DepGroupMetadata{ 832 DepGroupVals: []string{}, 833 }, 834 }, 835 }, 836 }, 837 { 838 Name: "commits", 839 InputConfig: extracttest.ScanInputMockConfig{ 840 Path: "testdata/commits.yaml", 841 }, 842 WantPackages: []*extractor.Package{ 843 { 844 Name: "my-bitbucket-package", 845 Version: "1.0.0", 846 PURLType: purl.TypeNPM, 847 Locations: []string{"testdata/commits.yaml"}, 848 SourceCode: &extractor.SourceCodeIdentifier{ 849 Commit: "6104ae42cd32c3d724036d3964678f197b2c9cdb", 850 }, 851 Metadata: osv.DepGroupMetadata{ 852 DepGroupVals: []string{}, 853 }, 854 }, 855 { 856 Name: "@my-scope/my-package", 857 Version: "1.0.0", 858 PURLType: purl.TypeNPM, 859 Locations: []string{"testdata/commits.yaml"}, 860 SourceCode: &extractor.SourceCodeIdentifier{ 861 Commit: "267087851ad5fac92a184749c27cd539e2fc862e", 862 }, 863 Metadata: osv.DepGroupMetadata{ 864 DepGroupVals: []string{}, 865 }, 866 }, 867 { 868 Name: "@my-scope/my-other-package", 869 Version: "1.0.0", 870 PURLType: purl.TypeNPM, 871 Locations: []string{"testdata/commits.yaml"}, 872 SourceCode: &extractor.SourceCodeIdentifier{ 873 Commit: "fbfc962ab51eb1d754749b68c064460221fbd689", 874 }, 875 Metadata: osv.DepGroupMetadata{ 876 DepGroupVals: []string{}, 877 }, 878 }, 879 { 880 Name: "faker-parser", 881 Version: "0.0.1", 882 PURLType: purl.TypeNPM, 883 Locations: []string{"testdata/commits.yaml"}, 884 SourceCode: &extractor.SourceCodeIdentifier{ 885 Commit: "d2dc42a9351d4d89ec48c525e34f612b6d77993f", 886 }, 887 Metadata: osv.DepGroupMetadata{ 888 DepGroupVals: []string{}, 889 }, 890 }, 891 { 892 Name: "mocks", 893 Version: "20.0.1", 894 PURLType: purl.TypeNPM, 895 Locations: []string{"testdata/commits.yaml"}, 896 SourceCode: &extractor.SourceCodeIdentifier{ 897 Commit: "590f321b4eb3f692bb211bd74e22947639a6f79d", 898 }, 899 Metadata: osv.DepGroupMetadata{ 900 DepGroupVals: []string{}, 901 }, 902 }, 903 }, 904 }, 905 { 906 Name: "files", 907 InputConfig: extracttest.ScanInputMockConfig{ 908 Path: "testdata/files.yaml", 909 }, 910 WantPackages: []*extractor.Package{ 911 { 912 Name: "my-file-package", 913 Version: "0.0.0", 914 PURLType: purl.TypeNPM, 915 Locations: []string{"testdata/files.yaml"}, 916 SourceCode: &extractor.SourceCodeIdentifier{}, 917 Metadata: osv.DepGroupMetadata{ 918 DepGroupVals: []string{}, 919 }, 920 }, 921 { 922 Name: "a-local-package", 923 Version: "1.0.0", 924 PURLType: purl.TypeNPM, 925 Locations: []string{"testdata/files.yaml"}, 926 SourceCode: &extractor.SourceCodeIdentifier{}, 927 Metadata: osv.DepGroupMetadata{ 928 DepGroupVals: []string{}, 929 }, 930 }, 931 { 932 Name: "a-nested-local-package", 933 Version: "1.0.0", 934 PURLType: purl.TypeNPM, 935 Locations: []string{"testdata/files.yaml"}, 936 SourceCode: &extractor.SourceCodeIdentifier{}, 937 Metadata: osv.DepGroupMetadata{ 938 DepGroupVals: []string{}, 939 }, 940 }, 941 { 942 Name: "one-up", 943 Version: "1.0.0", 944 PURLType: purl.TypeNPM, 945 Locations: []string{"testdata/files.yaml"}, 946 SourceCode: &extractor.SourceCodeIdentifier{}, 947 Metadata: osv.DepGroupMetadata{ 948 DepGroupVals: []string{}, 949 }, 950 }, 951 { 952 Name: "one-up-with-peer", 953 Version: "1.0.0", 954 PURLType: purl.TypeNPM, 955 Locations: []string{"testdata/files.yaml"}, 956 SourceCode: &extractor.SourceCodeIdentifier{}, 957 Metadata: osv.DepGroupMetadata{ 958 DepGroupVals: []string{}, 959 }, 960 }, 961 }, 962 }, 963 } 964 965 for _, tt := range tests { 966 t.Run(tt.Name, func(t *testing.T) { 967 extr := pnpmlock.Extractor{} 968 969 scanInput := extracttest.GenerateScanInputMock(t, tt.InputConfig) 970 defer extracttest.CloseTestScanInput(t, scanInput) 971 972 got, err := extr.Extract(t.Context(), &scanInput) 973 974 if diff := cmp.Diff(tt.WantErr, err, cmpopts.EquateErrors()); diff != "" { 975 t.Errorf("%s.Extract(%q) error diff (-want +got):\n%s", extr.Name(), tt.InputConfig.Path, diff) 976 return 977 } 978 979 wantInv := inventory.Inventory{Packages: tt.WantPackages} 980 if diff := cmp.Diff(wantInv, got, cmpopts.SortSlices(extracttest.PackageCmpLess)); diff != "" { 981 t.Errorf("%s.Extract(%q) diff (-want +got):\n%s", extr.Name(), tt.InputConfig.Path, diff) 982 } 983 }) 984 } 985 }