mirror of
https://github.com/anchore/syft.git
synced 2025-11-18 00:43:20 +01:00
Fix yarn.lock parsing (#437)
This commit is contained in:
parent
5a2e2eb679
commit
67b7d63875
@ -5,9 +5,8 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"regexp"
|
"regexp"
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/anchore/syft/internal/log"
|
"github.com/anchore/syft/internal"
|
||||||
"github.com/anchore/syft/syft/pkg"
|
"github.com/anchore/syft/syft/pkg"
|
||||||
"github.com/anchore/syft/syft/pkg/cataloger/common"
|
"github.com/anchore/syft/syft/pkg/cataloger/common"
|
||||||
)
|
)
|
||||||
@ -15,59 +14,53 @@ import (
|
|||||||
// integrity check
|
// integrity check
|
||||||
var _ common.ParserFn = parseYarnLock
|
var _ common.ParserFn = parseYarnLock
|
||||||
|
|
||||||
var composedNameExp = regexp.MustCompile("^\"(@{1}[^@]+)")
|
var (
|
||||||
var simpleNameExp = regexp.MustCompile(`^[a-zA-Z\-]+@`)
|
composedNameExp = regexp.MustCompile(`^"(@[^@]+)`)
|
||||||
var versionExp = regexp.MustCompile(`^\W+(version)\W+`)
|
simpleNameExp = regexp.MustCompile(`^(\w[\w-_.]*)@`)
|
||||||
|
versionExp = regexp.MustCompile(`^\W+version\W+"([\w-_.]+)"`)
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
noPackage = ""
|
||||||
|
noVersion = ""
|
||||||
|
)
|
||||||
|
|
||||||
func parseYarnLock(_ string, reader io.Reader) ([]pkg.Package, error) {
|
func parseYarnLock(_ string, reader io.Reader) ([]pkg.Package, error) {
|
||||||
packages := make([]pkg.Package, 0)
|
var packages []pkg.Package
|
||||||
fields := make(map[string]string)
|
|
||||||
var currentName string
|
|
||||||
|
|
||||||
scanner := bufio.NewScanner(reader)
|
scanner := bufio.NewScanner(reader)
|
||||||
|
parsedPackages := internal.NewStringSet()
|
||||||
|
currentPackage := noPackage
|
||||||
|
|
||||||
for scanner.Scan() {
|
for scanner.Scan() {
|
||||||
line := scanner.Text()
|
line := scanner.Text()
|
||||||
line = strings.TrimRight(line, "\n")
|
|
||||||
|
|
||||||
// create the entry so that the loop can keep appending versions later
|
if currentPackage == noPackage {
|
||||||
_, ok := fields[currentName]
|
// Scan until we find the next package
|
||||||
if !ok {
|
|
||||||
fields[currentName] = ""
|
|
||||||
}
|
|
||||||
|
|
||||||
switch {
|
packageName := findPackageName(line)
|
||||||
case composedNameExp.MatchString(line):
|
if packageName == noPackage {
|
||||||
name := composedNameExp.FindString(line)
|
|
||||||
if len(name) == 0 {
|
|
||||||
log.Warnf("unable to parse yarn.lock line: %q", line)
|
|
||||||
}
|
|
||||||
currentName = strings.TrimLeft(name, "\"")
|
|
||||||
case simpleNameExp.MatchString(line):
|
|
||||||
parts := strings.Split(line, "@")
|
|
||||||
currentName = parts[0]
|
|
||||||
case versionExp.MatchString(line):
|
|
||||||
parts := strings.Split(line, " \"")
|
|
||||||
version := parts[len(parts)-1]
|
|
||||||
|
|
||||||
versions, ok := fields[currentName]
|
|
||||||
if !ok {
|
|
||||||
return nil, fmt.Errorf("no previous key exists, expecting: %s", currentName)
|
|
||||||
}
|
|
||||||
|
|
||||||
if strings.Contains(versions, version) {
|
|
||||||
// already exists from another dependency declaration
|
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
// append the version as a string so that we can check on it later
|
if parsedPackages.Contains(packageName) {
|
||||||
fields[currentName] = versions + " " + version
|
// We don't parse repeated package declarations.
|
||||||
packages = append(packages, pkg.Package{
|
continue
|
||||||
Name: currentName,
|
}
|
||||||
Version: strings.Trim(version, "\""),
|
|
||||||
Language: pkg.JavaScript,
|
currentPackage = packageName
|
||||||
Type: pkg.NpmPkg,
|
parsedPackages.Add(currentPackage)
|
||||||
})
|
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// We've found the package entry, now we just need the version
|
||||||
|
|
||||||
|
if version := findPackageVersion(line); version != noVersion {
|
||||||
|
packages = append(packages, newYarnLockPackage(currentPackage, version))
|
||||||
|
currentPackage = noPackage
|
||||||
|
|
||||||
|
continue
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -77,3 +70,32 @@ func parseYarnLock(_ string, reader io.Reader) ([]pkg.Package, error) {
|
|||||||
|
|
||||||
return packages, nil
|
return packages, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func findPackageName(line string) string {
|
||||||
|
if matches := composedNameExp.FindStringSubmatch(line); len(matches) >= 2 {
|
||||||
|
return matches[1]
|
||||||
|
}
|
||||||
|
|
||||||
|
if matches := simpleNameExp.FindStringSubmatch(line); len(matches) >= 2 {
|
||||||
|
return matches[1]
|
||||||
|
}
|
||||||
|
|
||||||
|
return noPackage
|
||||||
|
}
|
||||||
|
|
||||||
|
func findPackageVersion(line string) string {
|
||||||
|
if matches := versionExp.FindStringSubmatch(line); len(matches) >= 2 {
|
||||||
|
return matches[1]
|
||||||
|
}
|
||||||
|
|
||||||
|
return noVersion
|
||||||
|
}
|
||||||
|
|
||||||
|
func newYarnLockPackage(name, version string) pkg.Package {
|
||||||
|
return pkg.Package{
|
||||||
|
Name: name,
|
||||||
|
Version: version,
|
||||||
|
Language: pkg.JavaScript,
|
||||||
|
Type: pkg.NpmPkg,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@ -51,7 +51,20 @@ func TestParseYarnLock(t *testing.T) {
|
|||||||
Language: pkg.JavaScript,
|
Language: pkg.JavaScript,
|
||||||
Type: pkg.NpmPkg,
|
Type: pkg.NpmPkg,
|
||||||
},
|
},
|
||||||
|
"asn1.js": {
|
||||||
|
Name: "asn1.js",
|
||||||
|
Version: "4.10.1",
|
||||||
|
Language: pkg.JavaScript,
|
||||||
|
Type: pkg.NpmPkg,
|
||||||
|
},
|
||||||
|
"c0n-fab_u.laTION": {
|
||||||
|
Name: "c0n-fab_u.laTION",
|
||||||
|
Version: "7.7.7",
|
||||||
|
Language: pkg.JavaScript,
|
||||||
|
Type: pkg.NpmPkg,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
fixture, err := os.Open("test-fixtures/yarn/yarn.lock")
|
fixture, err := os.Open("test-fixtures/yarn/yarn.lock")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("failed to open fixture: %+v", err)
|
t.Fatalf("failed to open fixture: %+v", err)
|
||||||
@ -63,5 +76,4 @@ func TestParseYarnLock(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
assertPkgsEqual(t, actual, expected)
|
assertPkgsEqual(t, actual, expected)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -69,3 +69,16 @@ jhipster-core@7.3.4:
|
|||||||
lodash "4.17.15"
|
lodash "4.17.15"
|
||||||
winston "3.2.1"
|
winston "3.2.1"
|
||||||
|
|
||||||
|
asn1.js@^4.0.0:
|
||||||
|
version "4.10.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/asn1.js/-/asn1.js-4.10.1.tgz#b9c2bf5805f1e64aadeed6df3a2bfafb5a73f5a0"
|
||||||
|
integrity sha512-p32cOF5q0Zqs9uBiONKYLm6BClCoBCM5O9JfeUSlnQLBTxYdTK+pW+nXflm8UkKd2UYlEbYz5qEi0JuZR9ckSw==
|
||||||
|
dependencies:
|
||||||
|
bn.js "^4.0.0"
|
||||||
|
inherits "^2.0.1"
|
||||||
|
minimalistic-assert "^1.0.0"
|
||||||
|
|
||||||
|
c0n-fab_u.laTION@^7.0.0:
|
||||||
|
version "7.7.7"
|
||||||
|
resolved "https://registry.yarnpkg.com/something-i-made-up/-/c0n-fab_u.laTION-7.7.7.tgz#b9c2bf5805f1e64aadeed6df3a2bfafb5a73f5a0"
|
||||||
|
integrity sha512-p32cOF5q0Zqs9uBiONKYLm6BClCoBCM5O9JfeUSlnQLBTxYdTK+pW+nXflm8UkKd2UYlEbYz5qEi0JuZR9ckSw==
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user