mirror of
https://github.com/anchore/syft.git
synced 2025-11-18 00:43:20 +01:00
Merge pull request #110 from anchore/issue-8
adds the yarn.lock cataloger
This commit is contained in:
commit
bc693829a6
@ -9,7 +9,7 @@ import (
|
|||||||
"github.com/anchore/syft/syft/cataloger/dpkg"
|
"github.com/anchore/syft/syft/cataloger/dpkg"
|
||||||
golang "github.com/anchore/syft/syft/cataloger/golang"
|
golang "github.com/anchore/syft/syft/cataloger/golang"
|
||||||
"github.com/anchore/syft/syft/cataloger/java"
|
"github.com/anchore/syft/syft/cataloger/java"
|
||||||
"github.com/anchore/syft/syft/cataloger/npm"
|
"github.com/anchore/syft/syft/cataloger/javascript"
|
||||||
"github.com/anchore/syft/syft/cataloger/python"
|
"github.com/anchore/syft/syft/cataloger/python"
|
||||||
"github.com/anchore/syft/syft/cataloger/rpmdb"
|
"github.com/anchore/syft/syft/cataloger/rpmdb"
|
||||||
"github.com/anchore/syft/syft/event"
|
"github.com/anchore/syft/syft/event"
|
||||||
@ -53,7 +53,7 @@ func newController() controller {
|
|||||||
ctrlr.add(java.NewCataloger())
|
ctrlr.add(java.NewCataloger())
|
||||||
ctrlr.add(apkdb.NewCataloger())
|
ctrlr.add(apkdb.NewCataloger())
|
||||||
ctrlr.add(golang.NewCataloger())
|
ctrlr.add(golang.NewCataloger())
|
||||||
ctrlr.add(npm.NewCataloger())
|
ctrlr.add(javascript.NewCataloger())
|
||||||
return ctrlr
|
return ctrlr
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
package npm
|
package javascript
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/anchore/stereoscope/pkg/file"
|
"github.com/anchore/stereoscope/pkg/file"
|
||||||
@ -14,6 +14,7 @@ type Cataloger struct {
|
|||||||
func NewCataloger() *Cataloger {
|
func NewCataloger() *Cataloger {
|
||||||
globParsers := map[string]common.ParserFn{
|
globParsers := map[string]common.ParserFn{
|
||||||
"**/package-lock.json": parsePackageLock,
|
"**/package-lock.json": parsePackageLock,
|
||||||
|
"**/yarn.lock": parseYarnLock,
|
||||||
}
|
}
|
||||||
|
|
||||||
return &Cataloger{
|
return &Cataloger{
|
||||||
@ -1,4 +1,4 @@
|
|||||||
package npm
|
package javascript
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
@ -1,4 +1,4 @@
|
|||||||
package npm
|
package javascript
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"os"
|
"os"
|
||||||
75
syft/cataloger/javascript/parse_yarn_lock.go
Normal file
75
syft/cataloger/javascript/parse_yarn_lock.go
Normal file
@ -0,0 +1,75 @@
|
|||||||
|
package javascript
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bufio"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"regexp"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/anchore/syft/internal/log"
|
||||||
|
"github.com/anchore/syft/syft/pkg"
|
||||||
|
)
|
||||||
|
|
||||||
|
var composedNameExp = regexp.MustCompile("^\"(@{1}[^@]+)")
|
||||||
|
var simpleNameExp = regexp.MustCompile(`^[a-zA-Z\-]+@`)
|
||||||
|
var versionExp = regexp.MustCompile(`^\W+(version)\W+`)
|
||||||
|
|
||||||
|
func parseYarnLock(_ string, reader io.Reader) ([]pkg.Package, error) {
|
||||||
|
packages := make([]pkg.Package, 0)
|
||||||
|
fields := make(map[string]string)
|
||||||
|
var currentName string
|
||||||
|
|
||||||
|
scanner := bufio.NewScanner(reader)
|
||||||
|
|
||||||
|
for scanner.Scan() {
|
||||||
|
line := scanner.Text()
|
||||||
|
line = strings.TrimRight(line, "\n")
|
||||||
|
|
||||||
|
// create the entry so that the loop can keep appending versions later
|
||||||
|
_, ok := fields[currentName]
|
||||||
|
if !ok {
|
||||||
|
fields[currentName] = ""
|
||||||
|
}
|
||||||
|
|
||||||
|
switch {
|
||||||
|
case composedNameExp.MatchString(line):
|
||||||
|
name := composedNameExp.FindString(line)
|
||||||
|
if len(name) == 0 {
|
||||||
|
log.Errorf("unable to parse line: '%s'", 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
|
||||||
|
}
|
||||||
|
|
||||||
|
// append the version as a string so that we can check on it later
|
||||||
|
fields[currentName] = versions + " " + version
|
||||||
|
packages = append(packages, pkg.Package{
|
||||||
|
Name: currentName,
|
||||||
|
Version: strings.Trim(version, "\""),
|
||||||
|
Language: pkg.JavaScript,
|
||||||
|
Type: pkg.YarnPkg,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := scanner.Err(); err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to parse yarn.lock file: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return packages, nil
|
||||||
|
}
|
||||||
67
syft/cataloger/javascript/parse_yarn_lock_test.go
Normal file
67
syft/cataloger/javascript/parse_yarn_lock_test.go
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
package javascript
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/anchore/syft/syft/pkg"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestParseYarnLock(t *testing.T) {
|
||||||
|
expected := map[string]pkg.Package{
|
||||||
|
"@babel/code-frame": {
|
||||||
|
Name: "@babel/code-frame",
|
||||||
|
Version: "7.10.4",
|
||||||
|
Language: pkg.JavaScript,
|
||||||
|
Type: pkg.YarnPkg,
|
||||||
|
},
|
||||||
|
"@types/minimatch": {
|
||||||
|
Name: "@types/minimatch",
|
||||||
|
Version: "3.0.3",
|
||||||
|
Language: pkg.JavaScript,
|
||||||
|
Type: pkg.YarnPkg,
|
||||||
|
},
|
||||||
|
"@types/qs": {
|
||||||
|
Name: "@types/qs",
|
||||||
|
Version: "6.9.4",
|
||||||
|
Language: pkg.JavaScript,
|
||||||
|
Type: pkg.YarnPkg,
|
||||||
|
},
|
||||||
|
"ajv": {
|
||||||
|
Name: "ajv",
|
||||||
|
Version: "6.12.3",
|
||||||
|
Language: pkg.JavaScript,
|
||||||
|
Type: pkg.YarnPkg,
|
||||||
|
},
|
||||||
|
"atob": {
|
||||||
|
Name: "atob",
|
||||||
|
Version: "2.1.2",
|
||||||
|
Language: pkg.JavaScript,
|
||||||
|
Type: pkg.YarnPkg,
|
||||||
|
},
|
||||||
|
"aws-sdk": {
|
||||||
|
Name: "aws-sdk",
|
||||||
|
Version: "2.706.0",
|
||||||
|
Language: pkg.JavaScript,
|
||||||
|
Type: pkg.YarnPkg,
|
||||||
|
},
|
||||||
|
"jhipster-core": {
|
||||||
|
Name: "jhipster-core",
|
||||||
|
Version: "7.3.4",
|
||||||
|
Language: pkg.JavaScript,
|
||||||
|
Type: pkg.YarnPkg,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
fixture, err := os.Open("test-fixtures/yarn/yarn.lock")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("failed to open fixture: %+v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
actual, err := parseYarnLock(fixture.Name(), fixture)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("failed to parse yarn.lock: %+v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
assertPkgsEqual(t, actual, expected)
|
||||||
|
|
||||||
|
}
|
||||||
71
syft/cataloger/javascript/test-fixtures/yarn/yarn.lock
Normal file
71
syft/cataloger/javascript/test-fixtures/yarn/yarn.lock
Normal file
@ -0,0 +1,71 @@
|
|||||||
|
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
|
||||||
|
# yarn lockfile v1
|
||||||
|
|
||||||
|
|
||||||
|
"@babel/code-frame@^7.0.0", "@babel/code-frame@^7.10.4":
|
||||||
|
version "7.10.4"
|
||||||
|
resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.10.4.tgz#168da1a36e90da68ae8d49c0f1b48c7c6249213a"
|
||||||
|
integrity sha512-vG6SvB6oYEhvgisZNFRmRCUkLz11c7rp+tbNTynGqc6mS1d5ATd/sGyV6W0KZZnXRKMTzZDRgQT3Ou9jhpAfUg==
|
||||||
|
dependencies:
|
||||||
|
"@babel/highlight" "^7.10.4"
|
||||||
|
|
||||||
|
"@types/minimatch@*", "@types/minimatch@^3.0.3":
|
||||||
|
version "3.0.3"
|
||||||
|
resolved "https://registry.yarnpkg.com/@types/minimatch/-/minimatch-3.0.3.tgz#3dca0e3f33b200fc7d1139c0cd96c1268cadfd9d"
|
||||||
|
integrity sha512-tHq6qdbT9U1IRSGf14CL0pUlULksvY9OZ+5eEgl1N7t+OA3tGvNpxJCzuKQlsNgCVwbAs670L1vcVQi8j9HjnA==
|
||||||
|
|
||||||
|
"@types/qs@^6.2.31":
|
||||||
|
version "6.9.4"
|
||||||
|
resolved "https://registry.yarnpkg.com/@types/qs/-/qs-6.9.4.tgz#a59e851c1ba16c0513ea123830dd639a0a15cb6a"
|
||||||
|
integrity sha512-+wYo+L6ZF6BMoEjtf8zB2esQsqdV6WsjRK/GP9WOgLPrq87PbNWgIxS76dS5uvl/QXtHGakZmwTznIfcPXcKlQ==
|
||||||
|
|
||||||
|
"@types/qs@^6.2.31":
|
||||||
|
version "6.9.4"
|
||||||
|
resolved "https://registry.yarnpkg.com/@types/qs/-/qs-6.9.4.tgz#a59e851c1ba16c0513ea123830dd639a0a15cb6a"
|
||||||
|
integrity sha512-+wYo+L6ZF6BMoEjtf8zB2esQsqdV6WsjRK/GP9WOgLPrq87PbNWgIxS76dS5uvl/QXtHGakZmwTznIfcPXcKlQ==
|
||||||
|
|
||||||
|
ajv@^6.10.2, ajv@^6.5.5:
|
||||||
|
version "6.12.3"
|
||||||
|
resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.3.tgz#18c5af38a111ddeb4f2697bd78d68abc1cabd706"
|
||||||
|
integrity sha512-4K0cK3L1hsqk9xIb2z9vs/XU+PGJZ9PNpJRDS9YLzmNdX6jmVPfamLvTJr0aDAusnHyCHO6MjzlkAsgtqp9teA==
|
||||||
|
dependencies:
|
||||||
|
fast-deep-equal "^3.1.1"
|
||||||
|
fast-json-stable-stringify "^2.0.0"
|
||||||
|
json-schema-traverse "^0.4.1"
|
||||||
|
uri-js "^4.2.2"
|
||||||
|
|
||||||
|
atob@^2.1.2:
|
||||||
|
version "2.1.2"
|
||||||
|
resolved "https://registry.yarnpkg.com/atob/-/atob-2.1.2.tgz#6d9517eb9e030d2436666651e86bd9f6f13533c9"
|
||||||
|
integrity sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==
|
||||||
|
|
||||||
|
atob@^2.1.2:
|
||||||
|
version "2.1.2"
|
||||||
|
resolved "https://registry.yarnpkg.com/atob/-/atob-2.1.2.tgz#6d9517eb9e030d2436666651e86bd9f6f13533c9"
|
||||||
|
integrity sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==
|
||||||
|
|
||||||
|
aws-sdk@2.706.0:
|
||||||
|
version "2.706.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/aws-sdk/-/aws-sdk-2.706.0.tgz#09f65e9a91ecac5a635daf934082abae30eca953"
|
||||||
|
integrity sha512-7GT+yrB5Wb/zOReRdv/Pzkb2Qt+hz6B/8FGMVaoysX3NryHvQUdz7EQWi5yhg9CxOjKxdw5lFwYSs69YlSp1KA==
|
||||||
|
dependencies:
|
||||||
|
buffer "4.9.2"
|
||||||
|
events "1.1.1"
|
||||||
|
ieee754 "1.1.13"
|
||||||
|
jmespath "0.15.0"
|
||||||
|
querystring "0.2.0"
|
||||||
|
sax "1.2.1"
|
||||||
|
url "0.10.3"
|
||||||
|
uuid "3.3.2"
|
||||||
|
xml2js "0.4.19"
|
||||||
|
|
||||||
|
jhipster-core@7.3.4:
|
||||||
|
version "7.3.4"
|
||||||
|
resolved "https://registry.yarnpkg.com/jhipster-core/-/jhipster-core-7.3.4.tgz#c34b8c97c7f4e8b7518dae015517e2112c73cc80"
|
||||||
|
integrity sha512-AUhT69kNkqppaJZVfan/xnKG4Gs9Ggj7YLtTZFVe+xg+THrbMb5Ng7PL07PDlDw4KAEA33GMCwuAf65E8EpC4g==
|
||||||
|
dependencies:
|
||||||
|
chevrotain "7.0.1"
|
||||||
|
fs-extra "8.1.0"
|
||||||
|
lodash "4.17.15"
|
||||||
|
winston "3.2.1"
|
||||||
|
|
||||||
@ -10,6 +10,7 @@ const (
|
|||||||
RpmPkg
|
RpmPkg
|
||||||
WheelPkg
|
WheelPkg
|
||||||
NpmPkg
|
NpmPkg
|
||||||
|
YarnPkg
|
||||||
PythonRequirementsPkg
|
PythonRequirementsPkg
|
||||||
JavaPkg
|
JavaPkg
|
||||||
JenkinsPluginPkg
|
JenkinsPluginPkg
|
||||||
@ -28,6 +29,7 @@ var typeStr = []string{
|
|||||||
"rpm",
|
"rpm",
|
||||||
"wheel",
|
"wheel",
|
||||||
"npm",
|
"npm",
|
||||||
|
"yarn",
|
||||||
"python-requirements",
|
"python-requirements",
|
||||||
"java-archive",
|
"java-archive",
|
||||||
"jenkins-plugin",
|
"jenkins-plugin",
|
||||||
@ -43,6 +45,7 @@ var AllPkgs = []Type{
|
|||||||
RpmPkg,
|
RpmPkg,
|
||||||
WheelPkg,
|
WheelPkg,
|
||||||
NpmPkg,
|
NpmPkg,
|
||||||
|
YarnPkg,
|
||||||
PythonRequirementsPkg,
|
PythonRequirementsPkg,
|
||||||
JavaPkg,
|
JavaPkg,
|
||||||
JenkinsPluginPkg,
|
JenkinsPluginPkg,
|
||||||
|
|||||||
@ -68,6 +68,14 @@ var cases = []struct {
|
|||||||
"get-stdin": "8.0.0",
|
"get-stdin": "8.0.0",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: "find javascript yarn packages",
|
||||||
|
pkgType: pkg.YarnPkg,
|
||||||
|
pkgLanguage: pkg.JavaScript,
|
||||||
|
pkgInfo: map[string]string{
|
||||||
|
"@babel/code-frame": "7.10.4",
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
name: "find python egg packages",
|
name: "find python egg packages",
|
||||||
pkgType: pkg.EggPkg,
|
pkgType: pkg.EggPkg,
|
||||||
|
|||||||
@ -0,0 +1,12 @@
|
|||||||
|
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
|
||||||
|
# yarn lockfile v1
|
||||||
|
|
||||||
|
|
||||||
|
"@babel/code-frame@^7.0.0", "@babel/code-frame@^7.10.4":
|
||||||
|
version "7.10.4"
|
||||||
|
resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.10.4.tgz#168da1a36e90da68ae8d49c0f1b48c7c6249213a"
|
||||||
|
integrity sha512-vG6SvB6oYEhvgisZNFRmRCUkLz11c7rp+tbNTynGqc6mS1d5ATd/sGyV6W0KZZnXRKMTzZDRgQT3Ou9jhpAfUg==
|
||||||
|
dependencies:
|
||||||
|
"@babel/highlight" "^7.10.4"
|
||||||
|
|
||||||
|
|
||||||
Loading…
x
Reference in New Issue
Block a user