Projects STRLCPY syft Commits a3c55502
🤬
  • ■ ■ ■ ■ ■ ■
    syft/pkg/cataloger/javascript/parse_pnpm_lock.go
    skipped 2 lines
    3 3  import (
    4 4   "fmt"
    5 5   "io"
     6 + "regexp"
     7 + "strconv"
    6 8   "strings"
    7 9   
    8 10   "gopkg.in/yaml.v3"
    9 11   
     12 + "github.com/anchore/syft/internal/log"
    10 13   "github.com/anchore/syft/syft/artifact"
    11 14   "github.com/anchore/syft/syft/pkg"
    12 15   "github.com/anchore/syft/syft/pkg/cataloger/generic"
    skipped 4 lines
    17 20  var _ generic.Parser = parsePnpmLock
    18 21   
    19 22  type pnpmLockYaml struct {
    20  - Dependencies map[string]string `json:"dependencies"`
    21  - Packages map[string]interface{} `json:"packages"`
     23 + Version string `json:"lockfileVersion" yaml:"lockfileVersion"`
     24 + Dependencies map[string]interface{} `json:"dependencies" yaml:"dependencies"`
     25 + Packages map[string]interface{} `json:"packages" yaml:"packages"`
    22 26  }
    23 27   
    24 28  func parsePnpmLock(resolver source.FileResolver, _ *generic.Environment, reader source.LocationReadCloser) ([]pkg.Package, []artifact.Relationship, error) {
    skipped 9 lines
    34 38   return nil, nil, fmt.Errorf("failed to parse pnpm-lock.yaml file: %w", err)
    35 39   }
    36 40   
    37  - for name, version := range lockFile.Dependencies {
     41 + lockVersion, _ := strconv.ParseFloat(lockFile.Version, 64)
     42 + 
     43 + for name, info := range lockFile.Dependencies {
     44 + version := ""
     45 + 
     46 + switch info := info.(type) {
     47 + case string:
     48 + version = info
     49 + case map[string]interface{}:
     50 + v, ok := info["version"]
     51 + if !ok {
     52 + break
     53 + }
     54 + ver, ok := v.(string)
     55 + if ok {
     56 + version = parseVersion(ver)
     57 + }
     58 + default:
     59 + log.Tracef("unsupported pnpm dependency type: %+v", info)
     60 + continue
     61 + }
     62 + 
     63 + if hasPkg(pkgs, name, version) {
     64 + continue
     65 + }
     66 + 
    38 67   pkgs = append(pkgs, newPnpmPackage(resolver, reader.Location, name, version))
    39 68   }
    40 69   
     70 + packageNameRegex := regexp.MustCompile(`^/?([^(]*)(?:\(.*\))*$`)
     71 + splitChar := "/"
     72 + if lockVersion >= 6.0 {
     73 + splitChar = "@"
     74 + }
     75 + 
    41 76   // parse packages from packages section of pnpm-lock.yaml
    42 77   for nameVersion := range lockFile.Packages {
    43  - nameVersionSplit := strings.Split(strings.TrimPrefix(nameVersion, "/"), "/")
     78 + nameVersion = packageNameRegex.ReplaceAllString(nameVersion, "$1")
     79 + nameVersionSplit := strings.Split(strings.TrimPrefix(nameVersion, "/"), splitChar)
    44 80   
    45 81   // last element in split array is version
    46 82   version := nameVersionSplit[len(nameVersionSplit)-1]
    47 83   
    48 84   // construct name from all array items other than last item (version)
    49  - name := strings.Join(nameVersionSplit[:len(nameVersionSplit)-1], "/")
     85 + name := strings.Join(nameVersionSplit[:len(nameVersionSplit)-1], splitChar)
     86 + 
     87 + if hasPkg(pkgs, name, version) {
     88 + continue
     89 + }
    50 90   
    51 91   pkgs = append(pkgs, newPnpmPackage(resolver, reader.Location, name, version))
    52 92   }
    skipped 3 lines
    56 96   return pkgs, nil, nil
    57 97  }
    58 98   
     99 +func hasPkg(pkgs []pkg.Package, name, version string) bool {
     100 + for _, p := range pkgs {
     101 + if p.Name == name && p.Version == version {
     102 + return true
     103 + }
     104 + }
     105 + return false
     106 +}
     107 + 
     108 +func parseVersion(version string) string {
     109 + return strings.SplitN(version, "(", 2)[0]
     110 +}
     111 + 
  • ■ ■ ■ ■ ■ ■
    syft/pkg/cataloger/javascript/parse_pnpm_lock_test.go
    skipped 52 lines
    53 53   pkgtest.TestFileParser(t, fixture, parsePnpmLock, expectedPkgs, expectedRelationships)
    54 54  }
    55 55   
     56 +func TestParsePnpmV6Lock(t *testing.T) {
     57 + var expectedRelationships []artifact.Relationship
     58 + fixture := "test-fixtures/pnpm-v6/pnpm-lock.yaml"
     59 + 
     60 + locationSet := source.NewLocationSet(source.NewLocation(fixture))
     61 + 
     62 + expectedPkgs := []pkg.Package{
     63 + {
     64 + Name: "@testing-library/jest-dom",
     65 + Version: "5.16.5",
     66 + PURL: "pkg:npm/%40testing-library/[email protected]",
     67 + Locations: locationSet,
     68 + Language: pkg.JavaScript,
     69 + Type: pkg.NpmPkg,
     70 + },
     71 + {
     72 + Name: "@testing-library/react",
     73 + Version: "13.4.0",
     74 + PURL: "pkg:npm/%40testing-library/[email protected]",
     75 + Locations: locationSet,
     76 + Language: pkg.JavaScript,
     77 + Type: pkg.NpmPkg,
     78 + },
     79 + {
     80 + Name: "@testing-library/user-event",
     81 + Version: "13.5.0",
     82 + PURL: "pkg:npm/%40testing-library/[email protected]",
     83 + Locations: locationSet,
     84 + Language: pkg.JavaScript,
     85 + Type: pkg.NpmPkg,
     86 + },
     87 + {
     88 + Name: "react",
     89 + Version: "18.2.0",
     90 + PURL: "pkg:npm/[email protected]",
     91 + Locations: locationSet,
     92 + Language: pkg.JavaScript,
     93 + Type: pkg.NpmPkg,
     94 + },
     95 + {
     96 + Name: "react-dom",
     97 + Version: "18.2.0",
     98 + PURL: "pkg:npm/[email protected]",
     99 + Locations: locationSet,
     100 + Language: pkg.JavaScript,
     101 + Type: pkg.NpmPkg,
     102 + },
     103 + {
     104 + Name: "web-vitals",
     105 + Version: "2.1.4",
     106 + PURL: "pkg:npm/[email protected]",
     107 + Locations: locationSet,
     108 + Language: pkg.JavaScript,
     109 + Type: pkg.NpmPkg,
     110 + },
     111 + {
     112 + Name: "@babel/core",
     113 + Version: "7.21.4",
     114 + PURL: "pkg:npm/%40babel/[email protected]",
     115 + Locations: locationSet,
     116 + Language: pkg.JavaScript,
     117 + Type: pkg.NpmPkg,
     118 + },
     119 + {
     120 + Name: "@types/eslint",
     121 + Version: "8.37.0",
     122 + PURL: "pkg:npm/%40types/[email protected]",
     123 + Locations: locationSet,
     124 + Language: pkg.JavaScript,
     125 + Type: pkg.NpmPkg,
     126 + },
     127 + {
     128 + Name: "read-cache",
     129 + Version: "1.0.0",
     130 + PURL: "pkg:npm/[email protected]",
     131 + Locations: locationSet,
     132 + Language: pkg.JavaScript,
     133 + Type: pkg.NpmPkg,
     134 + },
     135 + {
     136 + Name: "schema-utils",
     137 + Version: "3.1.2",
     138 + PURL: "pkg:npm/[email protected]",
     139 + Locations: locationSet,
     140 + Language: pkg.JavaScript,
     141 + Type: pkg.NpmPkg,
     142 + },
     143 + }
     144 + 
     145 + pkgtest.TestFileParser(t, fixture, parsePnpmLock, expectedPkgs, expectedRelationships)
     146 +}
     147 + 
  • ■ ■ ■ ■ ■ ■
    syft/pkg/cataloger/javascript/test-fixtures/pnpm-v6/pnpm-lock.yaml
     1 +lockfileVersion: '6.0'
     2 + 
     3 +dependencies:
     4 + '@testing-library/jest-dom':
     5 + specifier: ^5.16.5
     6 + version: 5.16.5
     7 + '@testing-library/react':
     8 + specifier: ^13.4.0
     9 + version: 13.4.0([email protected])([email protected])
     10 + '@testing-library/user-event':
     11 + specifier: ^13.5.0
     12 + version: 13.5.0(@testing-library/[email protected])
     13 + react:
     14 + specifier: ^18.2.0
     15 + version: 18.2.0
     16 + react-dom:
     17 + specifier: ^18.2.0
     18 + version: 18.2.0([email protected])
     19 + web-vitals:
     20 + specifier: ^2.1.4
     21 + version: 2.1.4
     22 + 
     23 +packages:
     24 + /@babel/[email protected]:
     25 + resolution: {integrity: sha512-qt/YV149Jman/6AfmlxJ04LMIu8bMoyl3RB91yTFrxQmgbrSvQMy7cI8Q62FHx1t8wJ8B5fu0UDoLwHAhUo1QA==}
     26 + engines: {node: '>=6.9.0'}
     27 + dependencies:
     28 + '@ampproject/remapping': 2.2.1
     29 + '@babel/code-frame': 7.21.4
     30 + '@babel/generator': 7.21.4
     31 + '@babel/helper-compilation-targets': 7.21.4(@babel/[email protected])
     32 + '@babel/helper-module-transforms': 7.21.2
     33 + '@babel/helpers': 7.21.0
     34 + '@babel/parser': 7.21.4
     35 + '@babel/template': 7.20.7
     36 + '@babel/traverse': 7.21.4
     37 + '@babel/types': 7.21.4
     38 + convert-source-map: 1.9.0
     39 + debug: 4.3.4
     40 + gensync: 1.0.0-beta.2
     41 + json5: 2.2.3
     42 + semver: 6.3.0
     43 + transitivePeerDependencies:
     44 + - supports-color
     45 + dev: false
     46 + 
     47 + /@testing-library/[email protected]:
     48 + resolution: {integrity: sha512-N5ixQ2qKpi5OLYfwQmUb/5mSV9LneAcaUfp32pn4yCnpb8r/Yz0pXFPck21dIicKmi+ta5WRAknkZCfA8refMA==}
     49 + engines: {node: '>=8', npm: '>=6', yarn: '>=1'}
     50 + dependencies:
     51 + '@adobe/css-tools': 4.2.0
     52 + '@babel/runtime': 7.21.0
     53 + '@types/testing-library__jest-dom': 5.14.5
     54 + aria-query: 5.1.3
     55 + chalk: 3.0.0
     56 + css.escape: 1.5.1
     57 + dom-accessibility-api: 0.5.16
     58 + lodash: 4.17.21
     59 + redent: 3.0.0
     60 + dev: false
     61 + 
     62 + /@testing-library/[email protected]([email protected])([email protected]):
     63 + resolution: {integrity: sha512-sXOGON+WNTh3MLE9rve97ftaZukN3oNf2KjDy7YTx6hcTO2uuLHuCGynMDhFwGw/jYf4OJ2Qk0i4i79qMNNkyw==}
     64 + engines: {node: '>=12'}
     65 + peerDependencies:
     66 + react: ^18.0.0
     67 + react-dom: ^18.0.0
     68 + dependencies:
     69 + '@babel/runtime': 7.21.0
     70 + '@testing-library/dom': 8.20.0
     71 + '@types/react-dom': 18.2.1
     72 + react: 18.2.0
     73 + react-dom: 18.2.0([email protected])
     74 + dev: false
     75 + 
     76 + /@testing-library/[email protected](@testing-library/[email protected]):
     77 + resolution: {integrity: sha512-5Kwtbo3Y/NowpkbRuSepbyMFkZmHgD+vPzYB/RJ4oxt5Gj/avFFBYjhw27cqSVPVw/3a67NK1PbiIr9k4Gwmdg==}
     78 + engines: {node: '>=10', npm: '>=6'}
     79 + peerDependencies:
     80 + '@testing-library/dom': '>=7.21.4'
     81 + dependencies:
     82 + '@babel/runtime': 7.21.0
     83 + '@testing-library/dom': 9.2.0
     84 + dev: false
     85 + 
     86 + /@types/[email protected]:
     87 + resolution: {integrity: sha512-Piet7dG2JBuDIfohBngQ3rCt7MgO9xCO4xIMKxBThCq5PNRB91IjlJ10eJVwfoNtvTErmxLzwBZ7rHZtbOMmFQ==}
     88 + dependencies:
     89 + '@types/estree': 1.0.1
     90 + '@types/json-schema': 7.0.11
     91 + dev: false
     92 + 
     93 + /[email protected]([email protected]):
     94 + resolution: {integrity: sha512-6IMTriUmvsjHUjNtEDudZfuDQUoWXVxKHhlEGSk81n4YFS+r/Kl99wXiwlVXtPBtJenozv2P+hxDsw9eA7Xo6g==}
     95 + peerDependencies:
     96 + react: ^18.2.0
     97 + dependencies:
     98 + loose-envify: 1.4.0
     99 + react: 18.2.0
     100 + scheduler: 0.23.0
     101 + dev: false
     102 + 
     103 + /[email protected]:
     104 + resolution: {integrity: sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==}
     105 + engines: {node: '>=0.10.0'}
     106 + dependencies:
     107 + loose-envify: 1.4.0
     108 + dev: false
     109 + 
     110 + /[email protected]:
     111 + resolution: {integrity: sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA==}
     112 + dependencies:
     113 + pify: 2.3.0
     114 + dev: false
     115 + 
     116 + /[email protected]:
     117 + resolution: {integrity: sha512-pvjEHOgWc9OWA/f/DE3ohBWTD6EleVLf7iFUkoSwAxttdBhB9QUebQgxER2kWueOvRJXPHNnyrvvh9eZINB8Eg==}
     118 + engines: {node: '>= 10.13.0'}
     119 + dependencies:
     120 + '@types/json-schema': 7.0.11
     121 + ajv: 6.12.6
     122 + ajv-keywords: 3.5.2([email protected])
     123 + dev: false
     124 + 
     125 + /[email protected]:
     126 + resolution: {integrity: sha512-sVWcwhU5mX6crfI5Vd2dC4qchyTqxV8URinzt25XqVh+bHEPGH4C3NPrNionCP7Obx59wrYEbNlw4Z8sjALzZg==}
     127 + dev: false
     128 + 
Please wait...
Page is in error, reload to recover