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  }