diff --git a/integration/testdata/conan.json.golden b/integration/testdata/conan.json.golden index 8cee1572ba19..1aac990b6304 100644 --- a/integration/testdata/conan.json.golden +++ b/integration/testdata/conan.json.golden @@ -21,6 +21,30 @@ "Class": "lang-pkgs", "Type": "conan", "Packages": [ + { + "ID": "poco/1.9.4", + "Name": "poco", + "Identifier": { + "PURL": "pkg:conan/poco@1.9.4", + "UID": "312753cebe80c0eb" + }, + "Version": "1.9.4", + "Relationship": "direct", + "DependsOn": [ + "pcre/8.43", + "zlib/1.2.12", + "expat/2.4.8", + "sqlite3/3.39.2", + "openssl/1.1.1q" + ], + "Layer": {}, + "Locations": [ + { + "StartLine": 12, + "EndLine": 25 + } + ] + }, { "ID": "bzip2/1.0.8", "Name": "bzip2", @@ -97,30 +121,6 @@ } ] }, - { - "ID": "poco/1.9.4", - "Name": "poco", - "Identifier": { - "PURL": "pkg:conan/poco@1.9.4", - "UID": "312753cebe80c0eb" - }, - "Version": "1.9.4", - "Relationship": "direct", - "DependsOn": [ - "pcre/8.43", - "zlib/1.2.12", - "expat/2.4.8", - "sqlite3/3.39.2", - "openssl/1.1.1q" - ], - "Layer": {}, - "Locations": [ - { - "StartLine": 12, - "EndLine": 25 - } - ] - }, { "ID": "sqlite3/3.39.2", "Name": "sqlite3", diff --git a/integration/testdata/poetry.json.golden b/integration/testdata/poetry.json.golden index f1ddf6802143..384c982876d3 100644 --- a/integration/testdata/poetry.json.golden +++ b/integration/testdata/poetry.json.golden @@ -35,6 +35,17 @@ ], "Layer": {} }, + { + "ID": "werkzeug@0.14", + "Name": "werkzeug", + "Identifier": { + "PURL": "pkg:pypi/werkzeug@0.14", + "UID": "4176be111ad01070" + }, + "Version": "0.14", + "Relationship": "direct", + "Layer": {} + }, { "ID": "colorama@0.4.6", "Name": "colorama", @@ -46,17 +57,6 @@ "Indirect": true, "Relationship": "indirect", "Layer": {} - }, - { - "ID": "werkzeug@0.14", - "Name": "werkzeug", - "Identifier": { - "PURL": "pkg:pypi/werkzeug@0.14", - "UID": "4176be111ad01070" - }, - "Version": "0.14", - "Relationship": "direct", - "Layer": {} } ], "Vulnerabilities": [ diff --git a/pkg/dependency/parser/c/conan/parse.go b/pkg/dependency/parser/c/conan/parse.go index 06c583b47282..4528da67b778 100644 --- a/pkg/dependency/parser/c/conan/parse.go +++ b/pkg/dependency/parser/c/conan/parse.go @@ -10,7 +10,6 @@ import ( "golang.org/x/xerrors" "github.com/aquasecurity/trivy/pkg/dependency" - "github.com/aquasecurity/trivy/pkg/dependency/types" ftypes "github.com/aquasecurity/trivy/pkg/fanal/types" "github.com/aquasecurity/trivy/pkg/log" xio "github.com/aquasecurity/trivy/pkg/x/io" @@ -44,27 +43,27 @@ type Parser struct { logger *log.Logger } -func NewParser() types.Parser { +func NewParser() *Parser { return &Parser{ logger: log.WithPrefix("conan"), } } -func (p *Parser) parseV1(lock LockFile) ([]types.Library, []types.Dependency, error) { - var libs []types.Library - var deps []types.Dependency +func (p *Parser) parseV1(lock LockFile) ([]ftypes.Package, []ftypes.Dependency, error) { + var pkgs []ftypes.Package + var deps []ftypes.Dependency var directDeps []string if root, ok := lock.GraphLock.Nodes["0"]; ok { directDeps = root.Requires } // Parse packages - parsed := make(map[string]types.Library) + parsed := make(map[string]ftypes.Package) for i, node := range lock.GraphLock.Nodes { if node.Ref == "" { continue } - lib, err := toLibrary(node.Ref, node.StartLine, node.EndLine) + pkg, err := toPackage(node.Ref, node.StartLine, node.EndLine) if err != nil { p.logger.Debug("Parse ref error", log.Err(err)) continue @@ -72,14 +71,14 @@ func (p *Parser) parseV1(lock LockFile) ([]types.Library, []types.Dependency, er // Determine if the package is a direct dependency or not direct := slices.Contains(directDeps, i) - lib.Relationship = lo.Ternary(direct, types.RelationshipDirect, types.RelationshipIndirect) + pkg.Relationship = lo.Ternary(direct, ftypes.RelationshipDirect, ftypes.RelationshipIndirect) - parsed[i] = lib + parsed[i] = pkg } // Parse dependency graph for i, node := range lock.GraphLock.Nodes { - lib, ok := parsed[i] + pkg, ok := parsed[i] if !ok { continue } @@ -91,33 +90,33 @@ func (p *Parser) parseV1(lock LockFile) ([]types.Library, []types.Dependency, er } } if len(childDeps) != 0 { - deps = append(deps, types.Dependency{ - ID: lib.ID, + deps = append(deps, ftypes.Dependency{ + ID: pkg.ID, DependsOn: childDeps, }) } - libs = append(libs, lib) + pkgs = append(pkgs, pkg) } - return libs, deps, nil + return pkgs, deps, nil } -func (p *Parser) parseV2(lock LockFile) ([]types.Library, []types.Dependency, error) { - var libs []types.Library +func (p *Parser) parseV2(lock LockFile) ([]ftypes.Package, []ftypes.Dependency, error) { + var pkgs []ftypes.Package for _, req := range lock.Requires { - lib, err := toLibrary(req.Dependency, req.StartLine, req.EndLine) + pkg, err := toPackage(req.Dependency, req.StartLine, req.EndLine) if err != nil { - p.logger.Debug("Creating library entry from requirement failed", err) + p.logger.Debug("Creating package entry from requirement failed", err) continue } - libs = append(libs, lib) + pkgs = append(pkgs, pkg) } - return libs, []types.Dependency{}, nil + return pkgs, []ftypes.Dependency{}, nil } -func (p *Parser) Parse(r xio.ReadSeekerAt) ([]types.Library, []types.Dependency, error) { +func (p *Parser) Parse(r xio.ReadSeekerAt) ([]ftypes.Package, []ftypes.Dependency, error) { var lock LockFile input, err := io.ReadAll(r) @@ -153,16 +152,16 @@ func parsePackage(text string) (string, string, error) { return ss[0], ss[1], nil } -func toLibrary(pkg string, startLine, endLine int) (types.Library, error) { +func toPackage(pkg string, startLine, endLine int) (ftypes.Package, error) { name, version, err := parsePackage(pkg) if err != nil { - return types.Library{}, err + return ftypes.Package{}, err } - return types.Library{ + return ftypes.Package{ ID: dependency.ID(ftypes.Conan, name, version), Name: name, Version: version, - Locations: []types.Location{ + Locations: []ftypes.Location{ { StartLine: startLine, EndLine: endLine, diff --git a/pkg/dependency/parser/c/conan/parse_test.go b/pkg/dependency/parser/c/conan/parse_test.go index abbf9f921a18..48abd9f0c0ac 100644 --- a/pkg/dependency/parser/c/conan/parse_test.go +++ b/pkg/dependency/parser/c/conan/parse_test.go @@ -3,65 +3,64 @@ package conan_test import ( "os" "sort" - "strings" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "github.com/aquasecurity/trivy/pkg/dependency/parser/c/conan" - "github.com/aquasecurity/trivy/pkg/dependency/types" + ftypes "github.com/aquasecurity/trivy/pkg/fanal/types" ) func TestParse(t *testing.T) { tests := []struct { name string inputFile string // Test input file - wantLibs []types.Library - wantDeps []types.Dependency + wantPkgs []ftypes.Package + wantDeps []ftypes.Dependency }{ { name: "happy path", inputFile: "testdata/happy_v1_case1.lock", - wantLibs: []types.Library{ + wantPkgs: []ftypes.Package{ { ID: "pkga/0.0.1", Name: "pkga", Version: "0.0.1", - Relationship: types.RelationshipDirect, - Locations: []types.Location{ + Relationship: ftypes.RelationshipDirect, + Locations: []ftypes.Location{ { StartLine: 13, EndLine: 22, }, }, }, - { - ID: "pkgb/system", - Name: "pkgb", - Version: "system", - Relationship: types.RelationshipIndirect, - Locations: []types.Location{ - { - StartLine: 23, - EndLine: 29, - }, - }, - }, { ID: "pkgc/0.1.1", Name: "pkgc", Version: "0.1.1", - Relationship: types.RelationshipDirect, - Locations: []types.Location{ + Relationship: ftypes.RelationshipDirect, + Locations: []ftypes.Location{ { StartLine: 30, EndLine: 35, }, }, }, + { + ID: "pkgb/system", + Name: "pkgb", + Version: "system", + Relationship: ftypes.RelationshipIndirect, + Locations: []ftypes.Location{ + { + StartLine: 23, + EndLine: 29, + }, + }, + }, }, - wantDeps: []types.Dependency{ + wantDeps: []ftypes.Dependency{ { ID: "pkga/0.0.1", DependsOn: []string{ @@ -73,13 +72,13 @@ func TestParse(t *testing.T) { { name: "happy path. lock file with revisions support", inputFile: "testdata/happy_v1_case2.lock", - wantLibs: []types.Library{ + wantPkgs: []ftypes.Package{ { ID: "openssl/3.0.3", Name: "openssl", Version: "3.0.3", - Relationship: types.RelationshipDirect, - Locations: []types.Location{ + Relationship: ftypes.RelationshipDirect, + Locations: []ftypes.Location{ { StartLine: 12, EndLine: 22, @@ -90,8 +89,8 @@ func TestParse(t *testing.T) { ID: "zlib/1.2.12", Name: "zlib", Version: "1.2.12", - Relationship: types.RelationshipIndirect, - Locations: []types.Location{ + Relationship: ftypes.RelationshipIndirect, + Locations: []ftypes.Location{ { StartLine: 23, EndLine: 30, @@ -99,7 +98,7 @@ func TestParse(t *testing.T) { }, }, }, - wantDeps: []types.Dependency{ + wantDeps: []ftypes.Dependency{ { ID: "openssl/3.0.3", DependsOn: []string{ @@ -111,12 +110,12 @@ func TestParse(t *testing.T) { { name: "happy path conan v2", inputFile: "testdata/happy_v2.lock", - wantLibs: []types.Library{ + wantPkgs: []ftypes.Package{ { ID: "matrix/1.3", Name: "matrix", Version: "1.3", - Locations: []types.Location{ + Locations: []ftypes.Location{ { StartLine: 5, EndLine: 5, @@ -127,7 +126,7 @@ func TestParse(t *testing.T) { ID: "sound32/1.0", Name: "sound32", Version: "1.0", - Locations: []types.Location{ + Locations: []ftypes.Location{ { StartLine: 4, EndLine: 4, @@ -135,7 +134,7 @@ func TestParse(t *testing.T) { }, }, }, - wantDeps: []types.Dependency{}, + wantDeps: []ftypes.Dependency{}, }, { name: "happy path. lock file without dependencies", @@ -153,18 +152,12 @@ func TestParse(t *testing.T) { require.NoError(t, err) defer f.Close() - gotLibs, gotDeps, err := conan.NewParser().Parse(f) + gotPkgs, gotDeps, err := conan.NewParser().Parse(f) require.NoError(t, err) - sort.Slice(gotLibs, func(i, j int) bool { - ret := strings.Compare(gotLibs[i].Name, gotLibs[j].Name) - if ret != 0 { - return ret < 0 - } - return gotLibs[i].Version < gotLibs[j].Version - }) + sort.Sort(ftypes.Packages(gotPkgs)) - assert.Equal(t, tt.wantLibs, gotLibs) + assert.Equal(t, tt.wantPkgs, gotPkgs) assert.Equal(t, tt.wantDeps, gotDeps) }) } diff --git a/pkg/dependency/parser/conda/environment/parse.go b/pkg/dependency/parser/conda/environment/parse.go index 8a4418699f2f..f8bdcfb49a92 100644 --- a/pkg/dependency/parser/conda/environment/parse.go +++ b/pkg/dependency/parser/conda/environment/parse.go @@ -9,7 +9,7 @@ import ( "gopkg.in/yaml.v3" "github.com/aquasecurity/go-version/pkg/version" - "github.com/aquasecurity/trivy/pkg/dependency/types" + ftypes "github.com/aquasecurity/trivy/pkg/fanal/types" "github.com/aquasecurity/trivy/pkg/log" xio "github.com/aquasecurity/trivy/pkg/x/io" ) @@ -28,44 +28,44 @@ type Parser struct { once sync.Once } -func NewParser() types.Parser { +func NewParser() *Parser { return &Parser{ logger: log.WithPrefix("conda"), once: sync.Once{}, } } -func (p *Parser) Parse(r xio.ReadSeekerAt) ([]types.Library, []types.Dependency, error) { +func (p *Parser) Parse(r xio.ReadSeekerAt) ([]ftypes.Package, []ftypes.Dependency, error) { var env environment if err := yaml.NewDecoder(r).Decode(&env); err != nil { return nil, nil, xerrors.Errorf("unable to decode conda environment.yml file: %w", err) } - var libs []types.Library + var pkgs ftypes.Packages for _, dep := range env.Dependencies { - lib := p.toLibrary(dep) - // Skip empty libs - if lib.Name == "" { + pkg := p.toPackage(dep) + // Skip empty pkgs + if pkg.Name == "" { continue } - libs = append(libs, lib) + pkgs = append(pkgs, pkg) } - sort.Sort(types.Libraries(libs)) - return libs, nil, nil + sort.Sort(pkgs) + return pkgs, nil, nil } -func (p *Parser) toLibrary(dep Dependency) types.Library { +func (p *Parser) toPackage(dep Dependency) ftypes.Package { name, ver := p.parseDependency(dep.Value) if ver == "" { p.once.Do(func() { p.logger.Warn("Unable to detect the dependency versions from `environment.yml` as those versions are not pinned. Use `conda env export` to pin versions.") }) } - return types.Library{ + return ftypes.Package{ Name: name, Version: ver, - Locations: types.Locations{ + Locations: ftypes.Locations{ { StartLine: dep.Line, EndLine: dep.Line, diff --git a/pkg/dependency/parser/conda/environment/parse_test.go b/pkg/dependency/parser/conda/environment/parse_test.go index f68736947119..109f53a405bd 100644 --- a/pkg/dependency/parser/conda/environment/parse_test.go +++ b/pkg/dependency/parser/conda/environment/parse_test.go @@ -8,23 +8,23 @@ import ( "github.com/stretchr/testify/require" "github.com/aquasecurity/trivy/pkg/dependency/parser/conda/environment" - "github.com/aquasecurity/trivy/pkg/dependency/types" + ftypes "github.com/aquasecurity/trivy/pkg/fanal/types" ) func TestParse(t *testing.T) { tests := []struct { name string input string - want []types.Library + want []ftypes.Package wantErr string }{ { name: "happy path", input: "testdata/happy.yaml", - want: []types.Library{ + want: []ftypes.Package{ { Name: "_openmp_mutex", - Locations: types.Locations{ + Locations: ftypes.Locations{ { StartLine: 6, EndLine: 6, @@ -34,7 +34,7 @@ func TestParse(t *testing.T) { { Name: "blas", Version: "1.0", - Locations: types.Locations{ + Locations: ftypes.Locations{ { StartLine: 5, EndLine: 5, @@ -44,7 +44,7 @@ func TestParse(t *testing.T) { { Name: "bzip2", Version: "1.0.8", - Locations: types.Locations{ + Locations: ftypes.Locations{ { StartLine: 19, EndLine: 19, @@ -54,7 +54,7 @@ func TestParse(t *testing.T) { { Name: "ca-certificates", Version: "2024.2", - Locations: types.Locations{ + Locations: ftypes.Locations{ { StartLine: 7, EndLine: 7, @@ -63,7 +63,7 @@ func TestParse(t *testing.T) { }, { Name: "ld_impl_linux-aarch64", - Locations: types.Locations{ + Locations: ftypes.Locations{ { StartLine: 8, EndLine: 8, @@ -72,7 +72,7 @@ func TestParse(t *testing.T) { }, { Name: "libblas", - Locations: types.Locations{ + Locations: ftypes.Locations{ { StartLine: 9, EndLine: 9, @@ -81,7 +81,7 @@ func TestParse(t *testing.T) { }, { Name: "libcblas", - Locations: types.Locations{ + Locations: ftypes.Locations{ { StartLine: 10, EndLine: 10, @@ -91,7 +91,7 @@ func TestParse(t *testing.T) { { Name: "libexpat", Version: "2.6.2", - Locations: types.Locations{ + Locations: ftypes.Locations{ { StartLine: 11, EndLine: 11, @@ -101,7 +101,7 @@ func TestParse(t *testing.T) { { Name: "libffi", Version: "3.4.2", - Locations: types.Locations{ + Locations: ftypes.Locations{ { StartLine: 12, EndLine: 12, @@ -110,7 +110,7 @@ func TestParse(t *testing.T) { }, { Name: "libgcc-ng", - Locations: types.Locations{ + Locations: ftypes.Locations{ { StartLine: 13, EndLine: 13, @@ -119,7 +119,7 @@ func TestParse(t *testing.T) { }, { Name: "libgfortran-ng", - Locations: types.Locations{ + Locations: ftypes.Locations{ { StartLine: 14, EndLine: 14, @@ -128,7 +128,7 @@ func TestParse(t *testing.T) { }, { Name: "libgfortran5", - Locations: types.Locations{ + Locations: ftypes.Locations{ { StartLine: 15, EndLine: 15, @@ -138,7 +138,7 @@ func TestParse(t *testing.T) { { Name: "libgomp", Version: "13.2.0", - Locations: types.Locations{ + Locations: ftypes.Locations{ { StartLine: 16, EndLine: 16, @@ -147,7 +147,7 @@ func TestParse(t *testing.T) { }, { Name: "liblapack", - Locations: types.Locations{ + Locations: ftypes.Locations{ { StartLine: 17, EndLine: 17, @@ -157,7 +157,7 @@ func TestParse(t *testing.T) { { Name: "libnsl", Version: "2.0.1", - Locations: types.Locations{ + Locations: ftypes.Locations{ { StartLine: 18, EndLine: 18, diff --git a/pkg/dependency/parser/conda/meta/parse.go b/pkg/dependency/parser/conda/meta/parse.go index 30d344bfdfa3..08f5623fa052 100644 --- a/pkg/dependency/parser/conda/meta/parse.go +++ b/pkg/dependency/parser/conda/meta/parse.go @@ -3,9 +3,10 @@ package meta import ( "encoding/json" + "github.com/samber/lo" "golang.org/x/xerrors" - "github.com/aquasecurity/trivy/pkg/dependency/types" + ftypes "github.com/aquasecurity/trivy/pkg/fanal/types" xio "github.com/aquasecurity/trivy/pkg/x/io" ) @@ -17,14 +18,14 @@ type packageJSON struct { type Parser struct{} -func NewParser() types.Parser { +func NewParser() *Parser { return &Parser{} } // Parse parses Anaconda (a.k.a. conda) environment metadata. // e.g. /envs//conda-meta/.json // For details see https://conda.io/projects/conda/en/latest/user-guide/concepts/environments.html -func (p *Parser) Parse(r xio.ReadSeekerAt) ([]types.Library, []types.Dependency, error) { +func (p *Parser) Parse(r xio.ReadSeekerAt) ([]ftypes.Package, []ftypes.Dependency, error) { var data packageJSON err := json.NewDecoder(r).Decode(&data) if err != nil { @@ -35,11 +36,11 @@ func (p *Parser) Parse(r xio.ReadSeekerAt) ([]types.Library, []types.Dependency, return nil, nil, xerrors.Errorf("unable to parse conda package") } - return []types.Library{ + return []ftypes.Package{ { - Name: data.Name, - Version: data.Version, - License: data.License, // can be empty + Name: data.Name, + Version: data.Version, + Licenses: lo.Ternary(data.License != "", []string{data.License}, nil), }, }, nil, nil } diff --git a/pkg/dependency/parser/conda/meta/parse_test.go b/pkg/dependency/parser/conda/meta/parse_test.go index 8bde5e184f0e..b2a4eafd6b08 100644 --- a/pkg/dependency/parser/conda/meta/parse_test.go +++ b/pkg/dependency/parser/conda/meta/parse_test.go @@ -8,25 +8,36 @@ import ( "github.com/stretchr/testify/require" "github.com/aquasecurity/trivy/pkg/dependency/parser/conda/meta" - "github.com/aquasecurity/trivy/pkg/dependency/types" + ftypes "github.com/aquasecurity/trivy/pkg/fanal/types" ) func TestParse(t *testing.T) { tests := []struct { name string input string - want []types.Library + want []ftypes.Package wantErr string }{ { name: "_libgcc_mutex", input: "testdata/_libgcc_mutex-0.1-main.json", - want: []types.Library{{Name: "_libgcc_mutex", Version: "0.1"}}, + want: []ftypes.Package{ + { + Name: "_libgcc_mutex", + Version: "0.1", + }, + }, }, { name: "libgomp", input: "testdata/libgomp-11.2.0-h1234567_1.json", - want: []types.Library{{Name: "libgomp", Version: "11.2.0", License: "GPL-3.0-only WITH GCC-exception-3.1"}}, + want: []ftypes.Package{ + { + Name: "libgomp", + Version: "11.2.0", + Licenses: []string{"GPL-3.0-only WITH GCC-exception-3.1"}, + }, + }, }, { name: "invalid_json", diff --git a/pkg/dependency/parser/dart/pub/parse.go b/pkg/dependency/parser/dart/pub/parse.go index 4d38fd686252..10b1e7ab729a 100644 --- a/pkg/dependency/parser/dart/pub/parse.go +++ b/pkg/dependency/parser/dart/pub/parse.go @@ -5,7 +5,6 @@ import ( "gopkg.in/yaml.v3" "github.com/aquasecurity/trivy/pkg/dependency" - "github.com/aquasecurity/trivy/pkg/dependency/types" ftypes "github.com/aquasecurity/trivy/pkg/fanal/types" xio "github.com/aquasecurity/trivy/pkg/x/io" ) @@ -19,7 +18,7 @@ const ( // Parser is a parser for pubspec.lock type Parser struct{} -func NewParser() types.Parser { +func NewParser() *Parser { return &Parser{} } @@ -32,36 +31,36 @@ type Dep struct { Version string `yaml:"version"` } -func (p Parser) Parse(r xio.ReadSeekerAt) ([]types.Library, []types.Dependency, error) { +func (p Parser) Parse(r xio.ReadSeekerAt) ([]ftypes.Package, []ftypes.Dependency, error) { l := &lock{} if err := yaml.NewDecoder(r).Decode(&l); err != nil { return nil, nil, xerrors.Errorf("failed to decode pubspec.lock: %w", err) } - var libs []types.Library + var pkgs []ftypes.Package for name, dep := range l.Packages { // We would like to exclude dev dependencies, but we cannot identify // which indirect dependencies were introduced by dev dependencies // as there are 3 dependency types, "direct main", "direct dev" and "transitive". // It will be confusing if we exclude direct dev dependencies and include transitive dev dependencies. // We decided to keep all dev dependencies until Pub will add support for "transitive main" and "transitive dev". - lib := types.Library{ + pkg := ftypes.Package{ ID: dependency.ID(ftypes.Pub, name, dep.Version), Name: name, Version: dep.Version, Relationship: p.relationship(dep.Dependency), } - libs = append(libs, lib) + pkgs = append(pkgs, pkg) } - return libs, nil, nil + return pkgs, nil, nil } -func (p Parser) relationship(dep string) types.Relationship { +func (p Parser) relationship(dep string) ftypes.Relationship { switch dep { case directMain, directDev: - return types.RelationshipDirect + return ftypes.RelationshipDirect case transitiveDep: - return types.RelationshipIndirect + return ftypes.RelationshipIndirect } - return types.RelationshipUnknown + return ftypes.RelationshipUnknown } diff --git a/pkg/dependency/parser/dart/pub/parse_test.go b/pkg/dependency/parser/dart/pub/parse_test.go index 7c28355e5a92..be698a7933c5 100644 --- a/pkg/dependency/parser/dart/pub/parse_test.go +++ b/pkg/dependency/parser/dart/pub/parse_test.go @@ -10,37 +10,37 @@ import ( "github.com/stretchr/testify/require" "github.com/aquasecurity/trivy/pkg/dependency/parser/dart/pub" - "github.com/aquasecurity/trivy/pkg/dependency/types" + ftypes "github.com/aquasecurity/trivy/pkg/fanal/types" ) func TestParser_Parse(t *testing.T) { tests := []struct { name string inputFile string - want []types.Library + want []ftypes.Package wantErr assert.ErrorAssertionFunc }{ { name: "happy path", inputFile: "testdata/happy.lock", - want: []types.Library{ + want: []ftypes.Package{ { ID: "crypto@3.0.2", Name: "crypto", Version: "3.0.2", - Relationship: types.RelationshipDirect, + Relationship: ftypes.RelationshipDirect, }, { ID: "flutter_test@0.0.0", Name: "flutter_test", Version: "0.0.0", - Relationship: types.RelationshipDirect, + Relationship: ftypes.RelationshipDirect, }, { ID: "uuid@3.0.6", Name: "uuid", Version: "3.0.6", - Relationship: types.RelationshipIndirect, + Relationship: ftypes.RelationshipIndirect, }, }, wantErr: assert.NoError, @@ -63,13 +63,13 @@ func TestParser_Parse(t *testing.T) { require.NoError(t, err) defer f.Close() - gotLibs, _, err := pub.NewParser().Parse(f) + gotPkgs, _, err := pub.NewParser().Parse(f) if !tt.wantErr(t, err, fmt.Sprintf("Parse(%v)", tt.inputFile)) { return } - sort.Sort(types.Libraries(gotLibs)) - assert.Equal(t, tt.want, gotLibs) + sort.Sort(ftypes.Packages(gotPkgs)) + assert.Equal(t, tt.want, gotPkgs) }) } } diff --git a/pkg/dependency/parser/dotnet/core_deps/parse.go b/pkg/dependency/parser/dotnet/core_deps/parse.go index 399c38736779..4314e9af9b3d 100644 --- a/pkg/dependency/parser/dotnet/core_deps/parse.go +++ b/pkg/dependency/parser/dotnet/core_deps/parse.go @@ -7,7 +7,7 @@ import ( "github.com/liamg/jfather" "golang.org/x/xerrors" - "github.com/aquasecurity/trivy/pkg/dependency/types" + ftypes "github.com/aquasecurity/trivy/pkg/fanal/types" "github.com/aquasecurity/trivy/pkg/log" xio "github.com/aquasecurity/trivy/pkg/x/io" ) @@ -16,13 +16,13 @@ type Parser struct { logger *log.Logger } -func NewParser() types.Parser { +func NewParser() *Parser { return &Parser{ logger: log.WithPrefix("dotnet"), } } -func (p *Parser) Parse(r xio.ReadSeekerAt) ([]types.Library, []types.Dependency, error) { +func (p *Parser) Parse(r xio.ReadSeekerAt) ([]ftypes.Package, []ftypes.Dependency, error) { var depsFile dotNetDependencies input, err := io.ReadAll(r) @@ -33,7 +33,7 @@ func (p *Parser) Parse(r xio.ReadSeekerAt) ([]types.Library, []types.Dependency, return nil, nil, xerrors.Errorf("failed to decode .deps.json file: %w", err) } - var libraries []types.Library + var pkgs []ftypes.Package for nameVer, lib := range depsFile.Libraries { if !strings.EqualFold(lib.Type, "package") { continue @@ -46,10 +46,10 @@ func (p *Parser) Parse(r xio.ReadSeekerAt) ([]types.Library, []types.Dependency, continue } - libraries = append(libraries, types.Library{ + pkgs = append(pkgs, ftypes.Package{ Name: split[0], Version: split[1], - Locations: []types.Location{ + Locations: []ftypes.Location{ { StartLine: lib.StartLine, EndLine: lib.EndLine, @@ -58,7 +58,7 @@ func (p *Parser) Parse(r xio.ReadSeekerAt) ([]types.Library, []types.Dependency, }) } - return libraries, nil, nil + return pkgs, nil, nil } type dotNetDependencies struct { diff --git a/pkg/dependency/parser/dotnet/core_deps/parse_test.go b/pkg/dependency/parser/dotnet/core_deps/parse_test.go index 839cf9ed97ba..dfd0a9cd96f7 100644 --- a/pkg/dependency/parser/dotnet/core_deps/parse_test.go +++ b/pkg/dependency/parser/dotnet/core_deps/parse_test.go @@ -4,25 +4,24 @@ import ( "os" "path" "sort" - "strings" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - "github.com/aquasecurity/trivy/pkg/dependency/types" + ftypes "github.com/aquasecurity/trivy/pkg/fanal/types" ) func TestParse(t *testing.T) { vectors := []struct { file string // Test input file - want []types.Library + want []ftypes.Package wantErr string }{ { file: "testdata/ExampleApp1.deps.json", - want: []types.Library{ - {Name: "Newtonsoft.Json", Version: "13.0.1", Locations: []types.Location{{StartLine: 33, EndLine: 39}}}, + want: []ftypes.Package{ + {Name: "Newtonsoft.Json", Version: "13.0.1", Locations: []ftypes.Location{{StartLine: 33, EndLine: 39}}}, }, }, { @@ -47,21 +46,8 @@ func TestParse(t *testing.T) { } else { require.NoError(t, err) - sort.Slice(got, func(i, j int) bool { - ret := strings.Compare(got[i].Name, got[j].Name) - if ret == 0 { - return got[i].Version < got[j].Version - } - return ret < 0 - }) - - sort.Slice(tt.want, func(i, j int) bool { - ret := strings.Compare(tt.want[i].Name, tt.want[j].Name) - if ret == 0 { - return tt.want[i].Version < tt.want[j].Version - } - return ret < 0 - }) + sort.Sort(ftypes.Packages(got)) + sort.Sort(ftypes.Packages(tt.want)) assert.Equal(t, tt.want, got) } diff --git a/pkg/dependency/parser/frameworks/wordpress/parse.go b/pkg/dependency/parser/frameworks/wordpress/parse.go index 61e00ded81cc..561dfde403d1 100644 --- a/pkg/dependency/parser/frameworks/wordpress/parse.go +++ b/pkg/dependency/parser/frameworks/wordpress/parse.go @@ -7,10 +7,10 @@ import ( "golang.org/x/xerrors" - "github.com/aquasecurity/trivy/pkg/dependency/types" + ftypes "github.com/aquasecurity/trivy/pkg/fanal/types" ) -func Parse(r io.Reader) (lib types.Library, err error) { +func Parse(r io.Reader) (lib ftypes.Package, err error) { // If wordpress file, open file and // find line with content @@ -68,10 +68,10 @@ func Parse(r io.Reader) (lib types.Library, err error) { } if err = scanner.Err(); err != nil || version == "" { - return types.Library{}, xerrors.New("version.php could not be parsed") + return ftypes.Package{}, xerrors.New("version.php could not be parsed") } - return types.Library{ + return ftypes.Package{ Name: "wordpress", Version: version, }, nil diff --git a/pkg/dependency/parser/frameworks/wordpress/parse_test.go b/pkg/dependency/parser/frameworks/wordpress/parse_test.go index 623ae06b87c7..b717d9cbc50c 100644 --- a/pkg/dependency/parser/frameworks/wordpress/parse_test.go +++ b/pkg/dependency/parser/frameworks/wordpress/parse_test.go @@ -8,18 +8,18 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - "github.com/aquasecurity/trivy/pkg/dependency/types" + ftypes "github.com/aquasecurity/trivy/pkg/fanal/types" ) func TestParseWordPress(t *testing.T) { tests := []struct { file string // Test input file - want types.Library + want ftypes.Package wantErr string }{ { file: "testdata/version.php", - want: types.Library{ + want: ftypes.Package{ Name: "wordpress", Version: "4.9.4-alpha", }, diff --git a/pkg/dependency/parser/golang/binary/parse.go b/pkg/dependency/parser/golang/binary/parse.go index ae7d4d81adae..171d3574800e 100644 --- a/pkg/dependency/parser/golang/binary/parse.go +++ b/pkg/dependency/parser/golang/binary/parse.go @@ -11,7 +11,7 @@ import ( "golang.org/x/mod/semver" "golang.org/x/xerrors" - "github.com/aquasecurity/trivy/pkg/dependency/types" + ftypes "github.com/aquasecurity/trivy/pkg/fanal/types" "github.com/aquasecurity/trivy/pkg/log" xio "github.com/aquasecurity/trivy/pkg/x/io" ) @@ -39,22 +39,22 @@ type Parser struct { logger *log.Logger } -func NewParser() types.Parser { +func NewParser() *Parser { return &Parser{ logger: log.WithPrefix("gobinary"), } } // Parse scans file to try to report the Go and module versions. -func (p *Parser) Parse(r xio.ReadSeekerAt) ([]types.Library, []types.Dependency, error) { +func (p *Parser) Parse(r xio.ReadSeekerAt) ([]ftypes.Package, []ftypes.Dependency, error) { info, err := buildinfo.Read(r) if err != nil { return nil, nil, convertError(err) } ldflags := p.ldFlags(info.Settings) - libs := make([]types.Library, 0, len(info.Deps)+2) - libs = append(libs, []types.Library{ + pkgs := make(ftypes.Packages, 0, len(info.Deps)+2) + pkgs = append(pkgs, []ftypes.Package{ { // Add main module Name: info.Main.Path, @@ -64,13 +64,13 @@ func (p *Parser) Parse(r xio.ReadSeekerAt) ([]types.Library, []types.Dependency, // as a secondary source. // See https://github.com/aquasecurity/trivy/issues/1837#issuecomment-1832523477. Version: cmp.Or(p.checkVersion(info.Main.Path, info.Main.Version), p.ParseLDFlags(info.Main.Path, ldflags)), - Relationship: types.RelationshipRoot, + Relationship: ftypes.RelationshipRoot, }, { // Add the Go version used to build this binary. Name: "stdlib", Version: strings.TrimPrefix(info.GoVersion, "go"), - Relationship: types.RelationshipDirect, // Considered a direct dependency as the main module depends on the standard packages. + Relationship: ftypes.RelationshipDirect, // Considered a direct dependency as the main module depends on the standard packages. }, }...) @@ -87,14 +87,14 @@ func (p *Parser) Parse(r xio.ReadSeekerAt) ([]types.Library, []types.Dependency, mod = dep.Replace } - libs = append(libs, types.Library{ + pkgs = append(pkgs, ftypes.Package{ Name: mod.Path, Version: p.checkVersion(mod.Path, mod.Version), }) } - sort.Sort(types.Libraries(libs)) - return libs, nil, nil + sort.Sort(pkgs) + return pkgs, nil, nil } // checkVersion detects `(devel)` versions, removes them and adds a debug message about it. diff --git a/pkg/dependency/parser/golang/binary/parse_test.go b/pkg/dependency/parser/golang/binary/parse_test.go index 96dc7213311c..e3144064ffe3 100644 --- a/pkg/dependency/parser/golang/binary/parse_test.go +++ b/pkg/dependency/parser/golang/binary/parse_test.go @@ -8,20 +8,20 @@ import ( "github.com/stretchr/testify/require" "github.com/aquasecurity/trivy/pkg/dependency/parser/golang/binary" - "github.com/aquasecurity/trivy/pkg/dependency/types" + ftypes "github.com/aquasecurity/trivy/pkg/fanal/types" ) func TestParse(t *testing.T) { - wantLibs := []types.Library{ + wantPkgs := []ftypes.Package{ { Name: "github.com/aquasecurity/test", Version: "", - Relationship: types.RelationshipRoot, + Relationship: ftypes.RelationshipRoot, }, { Name: "stdlib", Version: "1.15.2", - Relationship: types.RelationshipDirect, + Relationship: ftypes.RelationshipDirect, }, { Name: "github.com/aquasecurity/go-pep440-version", @@ -40,37 +40,37 @@ func TestParse(t *testing.T) { tests := []struct { name string inputFile string - want []types.Library + want []ftypes.Package wantErr string }{ { name: "ELF", inputFile: "testdata/test.elf", - want: wantLibs, + want: wantPkgs, }, { name: "PE", inputFile: "testdata/test.exe", - want: wantLibs, + want: wantPkgs, }, { name: "Mach-O", inputFile: "testdata/test.macho", - want: wantLibs, + want: wantPkgs, }, { name: "with replace directive", inputFile: "testdata/replace.elf", - want: []types.Library{ + want: []ftypes.Package{ { Name: "github.com/ebati/trivy-mod-parse", Version: "", - Relationship: types.RelationshipRoot, + Relationship: ftypes.RelationshipRoot, }, { Name: "stdlib", Version: "1.16.4", - Relationship: types.RelationshipDirect, + Relationship: ftypes.RelationshipDirect, }, { Name: "github.com/davecgh/go-spew", @@ -85,32 +85,32 @@ func TestParse(t *testing.T) { { name: "with semver main module version", inputFile: "testdata/semver-main-module-version.macho", - want: []types.Library{ + want: []ftypes.Package{ { Name: "go.etcd.io/bbolt", Version: "v1.3.5", - Relationship: types.RelationshipRoot, + Relationship: ftypes.RelationshipRoot, }, { Name: "stdlib", Version: "1.20.6", - Relationship: types.RelationshipDirect, + Relationship: ftypes.RelationshipDirect, }, }, }, { name: "with -ldflags=\"-X main.version=v1.0.0\"", inputFile: "testdata/main-version-via-ldflags.elf", - want: []types.Library{ + want: []ftypes.Package{ { Name: "github.com/aquasecurity/test", Version: "v1.0.0", - Relationship: types.RelationshipRoot, + Relationship: ftypes.RelationshipRoot, }, { Name: "stdlib", Version: "1.22.1", - Relationship: types.RelationshipDirect, + Relationship: ftypes.RelationshipDirect, }, }, }, @@ -238,7 +238,7 @@ func TestParser_ParseLDFlags(t *testing.T) { } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - p := binary.NewParser().(*binary.Parser) + p := binary.NewParser() assert.Equal(t, tt.want, p.ParseLDFlags(tt.args.name, tt.args.flags)) }) } diff --git a/pkg/dependency/parser/golang/mod/parse.go b/pkg/dependency/parser/golang/mod/parse.go index 3be3bb0c2800..fa5116f19bfa 100644 --- a/pkg/dependency/parser/golang/mod/parse.go +++ b/pkg/dependency/parser/golang/mod/parse.go @@ -12,7 +12,6 @@ import ( "golang.org/x/xerrors" "github.com/aquasecurity/trivy/pkg/dependency" - "github.com/aquasecurity/trivy/pkg/dependency/types" ftypes "github.com/aquasecurity/trivy/pkg/fanal/types" xio "github.com/aquasecurity/trivy/pkg/x/io" ) @@ -34,17 +33,17 @@ type Parser struct { replace bool // 'replace' represents if the 'replace' directive should be taken into account. } -func NewParser(replace bool) types.Parser { +func NewParser(replace bool) *Parser { return &Parser{ replace: replace, } } -func (p *Parser) GetExternalRefs(path string) []types.ExternalRef { +func (p *Parser) GetExternalRefs(path string) []ftypes.ExternalRef { if url := resolveVCSUrl(path); url != "" { - return []types.ExternalRef{ + return []ftypes.ExternalRef{ { - Type: types.RefVCS, + Type: ftypes.RefVCS, URL: url, }, } @@ -67,8 +66,8 @@ func resolveVCSUrl(modulePath string) string { } // Parse parses a go.mod file -func (p *Parser) Parse(r xio.ReadSeekerAt) ([]types.Library, []types.Dependency, error) { - libs := make(map[string]types.Library) +func (p *Parser) Parse(r xio.ReadSeekerAt) ([]ftypes.Package, []ftypes.Dependency, error) { + pkgs := make(map[string]ftypes.Package) goModData, err := io.ReadAll(r) if err != nil { @@ -88,12 +87,12 @@ func (p *Parser) Parse(r xio.ReadSeekerAt) ([]types.Library, []types.Dependency, // Main module if m := modFileParsed.Module; m != nil { ver := strings.TrimPrefix(m.Mod.Version, "v") - libs[m.Mod.Path] = types.Library{ + pkgs[m.Mod.Path] = ftypes.Package{ ID: packageID(m.Mod.Path, ver), Name: m.Mod.Path, Version: ver, ExternalReferences: p.GetExternalRefs(m.Mod.Path), - Relationship: types.RelationshipRoot, + Relationship: ftypes.RelationshipRoot, } } @@ -104,11 +103,11 @@ func (p *Parser) Parse(r xio.ReadSeekerAt) ([]types.Library, []types.Dependency, continue } ver := strings.TrimPrefix(require.Mod.Version, "v") - libs[require.Mod.Path] = types.Library{ + pkgs[require.Mod.Path] = ftypes.Package{ ID: packageID(require.Mod.Path, ver), Name: require.Mod.Path, Version: ver, - Relationship: lo.Ternary(require.Indirect, types.RelationshipIndirect, types.RelationshipDirect), + Relationship: lo.Ternary(require.Indirect, ftypes.RelationshipIndirect, ftypes.RelationshipDirect), ExternalReferences: p.GetExternalRefs(require.Mod.Path), } } @@ -116,8 +115,8 @@ func (p *Parser) Parse(r xio.ReadSeekerAt) ([]types.Library, []types.Dependency, // No need to evaluate the 'replace' directive for indirect dependencies if p.replace { for _, rep := range modFileParsed.Replace { - // Check if replaced path is actually in our libs. - old, ok := libs[rep.Old.Path] + // Check if replaced path is actually in our pkgs. + old, ok := pkgs[rep.Old.Path] if !ok { continue } @@ -130,16 +129,16 @@ func (p *Parser) Parse(r xio.ReadSeekerAt) ([]types.Library, []types.Dependency, // Only support replace directive with version on the right side. // Directive without version is a local path. if rep.New.Version == "" { - // Delete old lib, since it's a local path now. - delete(libs, rep.Old.Path) + // Delete old pkg, since it's a local path now. + delete(pkgs, rep.Old.Path) continue } - // Delete old lib, in case the path has changed. - delete(libs, rep.Old.Path) + // Delete old pkg, in case the path has changed. + delete(pkgs, rep.Old.Path) - // Add replaced library to library register. - libs[rep.New.Path] = types.Library{ + // Add replaced package to package register. + pkgs[rep.New.Path] = ftypes.Package{ ID: packageID(rep.New.Path, rep.New.Version[1:]), Name: rep.New.Path, Version: rep.New.Version[1:], @@ -149,7 +148,7 @@ func (p *Parser) Parse(r xio.ReadSeekerAt) ([]types.Library, []types.Dependency, } } - return maps.Values(libs), nil, nil + return maps.Values(pkgs), nil, nil } // Check if the Go version is less than 1.17 diff --git a/pkg/dependency/parser/golang/mod/parse_test.go b/pkg/dependency/parser/golang/mod/parse_test.go index 6372785df058..598cb3fe70f3 100644 --- a/pkg/dependency/parser/golang/mod/parse_test.go +++ b/pkg/dependency/parser/golang/mod/parse_test.go @@ -8,7 +8,7 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - "github.com/aquasecurity/trivy/pkg/dependency/types" + ftypes "github.com/aquasecurity/trivy/pkg/fanal/types" ) func TestParse(t *testing.T) { @@ -16,7 +16,7 @@ func TestParse(t *testing.T) { name string file string replace bool - want []types.Library + want []ftypes.Package }{ { name: "normal", @@ -88,12 +88,8 @@ func TestParse(t *testing.T) { got, _, err := NewParser(tt.replace).Parse(f) require.NoError(t, err) - sort.Slice(got, func(i, j int) bool { - return got[i].Name < got[j].Name - }) - sort.Slice(tt.want, func(i, j int) bool { - return tt.want[i].Name < tt.want[j].Name - }) + sort.Sort(ftypes.Packages(got)) + sort.Sort(ftypes.Packages(tt.want)) assert.Equal(t, tt.want, got) }) diff --git a/pkg/dependency/parser/golang/mod/parse_testcase.go b/pkg/dependency/parser/golang/mod/parse_testcase.go index dfadc32f67c3..5a07b939c549 100644 --- a/pkg/dependency/parser/golang/mod/parse_testcase.go +++ b/pkg/dependency/parser/golang/mod/parse_testcase.go @@ -1,17 +1,17 @@ package mod -import "github.com/aquasecurity/trivy/pkg/dependency/types" +import ftypes "github.com/aquasecurity/trivy/pkg/fanal/types" var ( // execute go mod tidy in normal folder - GoModNormal = []types.Library{ + GoModNormal = []ftypes.Package{ { ID: "github.com/org/repo", Name: "github.com/org/repo", - Relationship: types.RelationshipRoot, - ExternalReferences: []types.ExternalRef{ + Relationship: ftypes.RelationshipRoot, + ExternalReferences: []ftypes.ExternalRef{ { - Type: types.RefVCS, + Type: ftypes.RefVCS, URL: "https://github.com/org/repo", }, }, @@ -20,10 +20,10 @@ var ( ID: "github.com/aquasecurity/go-dep-parser@v0.0.0-20211224170007-df43bca6b6ff", Name: "github.com/aquasecurity/go-dep-parser", Version: "0.0.0-20211224170007-df43bca6b6ff", - Relationship: types.RelationshipDirect, - ExternalReferences: []types.ExternalRef{ + Relationship: ftypes.RelationshipDirect, + ExternalReferences: []ftypes.ExternalRef{ { - Type: types.RefVCS, + Type: ftypes.RefVCS, URL: "https://github.com/aquasecurity/go-dep-parser", }, }, @@ -32,16 +32,16 @@ var ( ID: "golang.org/x/xerrors@v0.0.0-20200804184101-5ec99f83aff1", Name: "golang.org/x/xerrors", Version: "0.0.0-20200804184101-5ec99f83aff1", - Relationship: types.RelationshipIndirect, + Relationship: ftypes.RelationshipIndirect, }, { ID: "gopkg.in/yaml.v3@v3.0.0-20210107192922-496545a6307b", Name: "gopkg.in/yaml.v3", Version: "3.0.0-20210107192922-496545a6307b", - Relationship: types.RelationshipIndirect, - ExternalReferences: []types.ExternalRef{ + Relationship: ftypes.RelationshipIndirect, + ExternalReferences: []ftypes.ExternalRef{ { - Type: types.RefVCS, + Type: ftypes.RefVCS, URL: "https://github.com/go-yaml/yaml", }, }, @@ -49,14 +49,14 @@ var ( } // execute go mod tidy in replaced folder - GoModReplaced = []types.Library{ + GoModReplaced = []ftypes.Package{ { ID: "github.com/org/repo", Name: "github.com/org/repo", - Relationship: types.RelationshipRoot, - ExternalReferences: []types.ExternalRef{ + Relationship: ftypes.RelationshipRoot, + ExternalReferences: []ftypes.ExternalRef{ { - Type: types.RefVCS, + Type: ftypes.RefVCS, URL: "https://github.com/org/repo", }, }, @@ -65,10 +65,10 @@ var ( ID: "github.com/aquasecurity/go-dep-parser@v0.0.0-20220406074731-71021a481237", Name: "github.com/aquasecurity/go-dep-parser", Version: "0.0.0-20220406074731-71021a481237", - Relationship: types.RelationshipDirect, - ExternalReferences: []types.ExternalRef{ + Relationship: ftypes.RelationshipDirect, + ExternalReferences: []ftypes.ExternalRef{ { - Type: types.RefVCS, + Type: ftypes.RefVCS, URL: "https://github.com/aquasecurity/go-dep-parser", }, }, @@ -77,19 +77,19 @@ var ( ID: "golang.org/x/xerrors@v0.0.0-20200804184101-5ec99f83aff1", Name: "golang.org/x/xerrors", Version: "0.0.0-20200804184101-5ec99f83aff1", - Relationship: types.RelationshipIndirect, + Relationship: ftypes.RelationshipIndirect, }, } // execute go mod tidy in replaced folder - GoModUnreplaced = []types.Library{ + GoModUnreplaced = []ftypes.Package{ { ID: "github.com/org/repo", Name: "github.com/org/repo", - Relationship: types.RelationshipRoot, - ExternalReferences: []types.ExternalRef{ + Relationship: ftypes.RelationshipRoot, + ExternalReferences: []ftypes.ExternalRef{ { - Type: types.RefVCS, + Type: ftypes.RefVCS, URL: "https://github.com/org/repo", }, }, @@ -98,10 +98,10 @@ var ( ID: "github.com/aquasecurity/go-dep-parser@v0.0.0-20211110174639-8257534ffed3", Name: "github.com/aquasecurity/go-dep-parser", Version: "0.0.0-20211110174639-8257534ffed3", - Relationship: types.RelationshipDirect, - ExternalReferences: []types.ExternalRef{ + Relationship: ftypes.RelationshipDirect, + ExternalReferences: []ftypes.ExternalRef{ { - Type: types.RefVCS, + Type: ftypes.RefVCS, URL: "https://github.com/aquasecurity/go-dep-parser", }, }, @@ -110,19 +110,19 @@ var ( ID: "golang.org/x/xerrors@v0.0.0-20200804184101-5ec99f83aff1", Name: "golang.org/x/xerrors", Version: "0.0.0-20200804184101-5ec99f83aff1", - Relationship: types.RelationshipIndirect, + Relationship: ftypes.RelationshipIndirect, }, } // execute go mod tidy in replaced-with-version folder - GoModReplacedWithVersion = []types.Library{ + GoModReplacedWithVersion = []ftypes.Package{ { ID: "github.com/org/repo", Name: "github.com/org/repo", - Relationship: types.RelationshipRoot, - ExternalReferences: []types.ExternalRef{ + Relationship: ftypes.RelationshipRoot, + ExternalReferences: []ftypes.ExternalRef{ { - Type: types.RefVCS, + Type: ftypes.RefVCS, URL: "https://github.com/org/repo", }, }, @@ -131,10 +131,10 @@ var ( ID: "github.com/aquasecurity/go-dep-parser@v0.0.0-20220406074731-71021a481237", Name: "github.com/aquasecurity/go-dep-parser", Version: "0.0.0-20220406074731-71021a481237", - Relationship: types.RelationshipDirect, - ExternalReferences: []types.ExternalRef{ + Relationship: ftypes.RelationshipDirect, + ExternalReferences: []ftypes.ExternalRef{ { - Type: types.RefVCS, + Type: ftypes.RefVCS, URL: "https://github.com/aquasecurity/go-dep-parser", }, }, @@ -143,19 +143,19 @@ var ( ID: "golang.org/x/xerrors@v0.0.0-20200804184101-5ec99f83aff1", Name: "golang.org/x/xerrors", Version: "0.0.0-20200804184101-5ec99f83aff1", - Relationship: types.RelationshipIndirect, + Relationship: ftypes.RelationshipIndirect, }, } // execute go mod tidy in replaced-with-version-mismatch folder - GoModReplacedWithVersionMismatch = []types.Library{ + GoModReplacedWithVersionMismatch = []ftypes.Package{ { ID: "github.com/org/repo", Name: "github.com/org/repo", - Relationship: types.RelationshipRoot, - ExternalReferences: []types.ExternalRef{ + Relationship: ftypes.RelationshipRoot, + ExternalReferences: []ftypes.ExternalRef{ { - Type: types.RefVCS, + Type: ftypes.RefVCS, URL: "https://github.com/org/repo", }, }, @@ -164,10 +164,10 @@ var ( ID: "github.com/aquasecurity/go-dep-parser@v0.0.0-20211224170007-df43bca6b6ff", Name: "github.com/aquasecurity/go-dep-parser", Version: "0.0.0-20211224170007-df43bca6b6ff", - Relationship: types.RelationshipDirect, - ExternalReferences: []types.ExternalRef{ + Relationship: ftypes.RelationshipDirect, + ExternalReferences: []ftypes.ExternalRef{ { - Type: types.RefVCS, + Type: ftypes.RefVCS, URL: "https://github.com/aquasecurity/go-dep-parser", }, }, @@ -176,16 +176,16 @@ var ( ID: "golang.org/x/xerrors@v0.0.0-20200804184101-5ec99f83aff1", Name: "golang.org/x/xerrors", Version: "0.0.0-20200804184101-5ec99f83aff1", - Relationship: types.RelationshipIndirect, + Relationship: ftypes.RelationshipIndirect, }, { ID: "gopkg.in/yaml.v3@v3.0.0-20210107192922-496545a6307b", Name: "gopkg.in/yaml.v3", Version: "3.0.0-20210107192922-496545a6307b", - Relationship: types.RelationshipIndirect, - ExternalReferences: []types.ExternalRef{ + Relationship: ftypes.RelationshipIndirect, + ExternalReferences: []ftypes.ExternalRef{ { - Type: types.RefVCS, + Type: ftypes.RefVCS, URL: "https://github.com/go-yaml/yaml", }, }, @@ -193,14 +193,14 @@ var ( } // execute go mod tidy in replaced-with-local-path folder - GoModReplacedWithLocalPath = []types.Library{ + GoModReplacedWithLocalPath = []ftypes.Package{ { ID: "github.com/org/repo", Name: "github.com/org/repo", - Relationship: types.RelationshipRoot, - ExternalReferences: []types.ExternalRef{ + Relationship: ftypes.RelationshipRoot, + ExternalReferences: []ftypes.ExternalRef{ { - Type: types.RefVCS, + Type: ftypes.RefVCS, URL: "https://github.com/org/repo", }, }, @@ -209,10 +209,10 @@ var ( ID: "github.com/aquasecurity/go-dep-parser@v0.0.0-20211224170007-df43bca6b6ff", Name: "github.com/aquasecurity/go-dep-parser", Version: "0.0.0-20211224170007-df43bca6b6ff", - Relationship: types.RelationshipDirect, - ExternalReferences: []types.ExternalRef{ + Relationship: ftypes.RelationshipDirect, + ExternalReferences: []ftypes.ExternalRef{ { - Type: types.RefVCS, + Type: ftypes.RefVCS, URL: "https://github.com/aquasecurity/go-dep-parser", }, }, @@ -221,10 +221,10 @@ var ( ID: "gopkg.in/yaml.v3@v3.0.0-20210107192922-496545a6307b", Name: "gopkg.in/yaml.v3", Version: "3.0.0-20210107192922-496545a6307b", - Relationship: types.RelationshipIndirect, - ExternalReferences: []types.ExternalRef{ + Relationship: ftypes.RelationshipIndirect, + ExternalReferences: []ftypes.ExternalRef{ { - Type: types.RefVCS, + Type: ftypes.RefVCS, URL: "https://github.com/go-yaml/yaml", }, }, @@ -232,14 +232,14 @@ var ( } // execute go mod tidy in replaced-with-local-path-and-version folder - GoModReplacedWithLocalPathAndVersion = []types.Library{ + GoModReplacedWithLocalPathAndVersion = []ftypes.Package{ { ID: "github.com/org/repo", Name: "github.com/org/repo", - Relationship: types.RelationshipRoot, - ExternalReferences: []types.ExternalRef{ + Relationship: ftypes.RelationshipRoot, + ExternalReferences: []ftypes.ExternalRef{ { - Type: types.RefVCS, + Type: ftypes.RefVCS, URL: "https://github.com/org/repo", }, }, @@ -248,10 +248,10 @@ var ( ID: "github.com/aquasecurity/go-dep-parser@v0.0.0-20211224170007-df43bca6b6ff", Name: "github.com/aquasecurity/go-dep-parser", Version: "0.0.0-20211224170007-df43bca6b6ff", - Relationship: types.RelationshipDirect, - ExternalReferences: []types.ExternalRef{ + Relationship: ftypes.RelationshipDirect, + ExternalReferences: []ftypes.ExternalRef{ { - Type: types.RefVCS, + Type: ftypes.RefVCS, URL: "https://github.com/aquasecurity/go-dep-parser", }, }, @@ -260,10 +260,10 @@ var ( ID: "gopkg.in/yaml.v3@v3.0.0-20210107192922-496545a6307b", Name: "gopkg.in/yaml.v3", Version: "3.0.0-20210107192922-496545a6307b", - Relationship: types.RelationshipIndirect, - ExternalReferences: []types.ExternalRef{ + Relationship: ftypes.RelationshipIndirect, + ExternalReferences: []ftypes.ExternalRef{ { - Type: types.RefVCS, + Type: ftypes.RefVCS, URL: "https://github.com/go-yaml/yaml", }, }, @@ -271,14 +271,14 @@ var ( } // execute go mod tidy in replaced-with-local-path-and-version-mismatch folder - GoModReplacedWithLocalPathAndVersionMismatch = []types.Library{ + GoModReplacedWithLocalPathAndVersionMismatch = []ftypes.Package{ { ID: "github.com/org/repo", Name: "github.com/org/repo", - Relationship: types.RelationshipRoot, - ExternalReferences: []types.ExternalRef{ + Relationship: ftypes.RelationshipRoot, + ExternalReferences: []ftypes.ExternalRef{ { - Type: types.RefVCS, + Type: ftypes.RefVCS, URL: "https://github.com/org/repo", }, }, @@ -287,10 +287,10 @@ var ( ID: "github.com/aquasecurity/go-dep-parser@v0.0.0-20211224170007-df43bca6b6ff", Name: "github.com/aquasecurity/go-dep-parser", Version: "0.0.0-20211224170007-df43bca6b6ff", - Relationship: types.RelationshipDirect, - ExternalReferences: []types.ExternalRef{ + Relationship: ftypes.RelationshipDirect, + ExternalReferences: []ftypes.ExternalRef{ { - Type: types.RefVCS, + Type: ftypes.RefVCS, URL: "https://github.com/aquasecurity/go-dep-parser", }, }, @@ -299,16 +299,16 @@ var ( ID: "golang.org/x/xerrors@v0.0.0-20200804184101-5ec99f83aff1", Name: "golang.org/x/xerrors", Version: "0.0.0-20200804184101-5ec99f83aff1", - Relationship: types.RelationshipIndirect, + Relationship: ftypes.RelationshipIndirect, }, { ID: "gopkg.in/yaml.v3@v3.0.0-20210107192922-496545a6307b", Name: "gopkg.in/yaml.v3", Version: "3.0.0-20210107192922-496545a6307b", - Relationship: types.RelationshipIndirect, - ExternalReferences: []types.ExternalRef{ + Relationship: ftypes.RelationshipIndirect, + ExternalReferences: []ftypes.ExternalRef{ { - Type: types.RefVCS, + Type: ftypes.RefVCS, URL: "https://github.com/go-yaml/yaml", }, }, @@ -316,14 +316,14 @@ var ( } // execute go mod tidy in go116 folder - GoMod116 = []types.Library{ + GoMod116 = []ftypes.Package{ { ID: "github.com/org/repo", Name: "github.com/org/repo", - Relationship: types.RelationshipRoot, - ExternalReferences: []types.ExternalRef{ + Relationship: ftypes.RelationshipRoot, + ExternalReferences: []ftypes.ExternalRef{ { - Type: types.RefVCS, + Type: ftypes.RefVCS, URL: "https://github.com/org/repo", }, }, @@ -332,10 +332,10 @@ var ( ID: "github.com/aquasecurity/go-dep-parser@v0.0.0-20211224170007-df43bca6b6ff", Name: "github.com/aquasecurity/go-dep-parser", Version: "0.0.0-20211224170007-df43bca6b6ff", - Relationship: types.RelationshipDirect, - ExternalReferences: []types.ExternalRef{ + Relationship: ftypes.RelationshipDirect, + ExternalReferences: []ftypes.ExternalRef{ { - Type: types.RefVCS, + Type: ftypes.RefVCS, URL: "https://github.com/aquasecurity/go-dep-parser", }, }, @@ -343,14 +343,14 @@ var ( } // execute go mod tidy in no-go-version folder - GoModNoGoVersion = []types.Library{ + GoModNoGoVersion = []ftypes.Package{ { ID: "github.com/org/repo", Name: "github.com/org/repo", - Relationship: types.RelationshipRoot, - ExternalReferences: []types.ExternalRef{ + Relationship: ftypes.RelationshipRoot, + ExternalReferences: []ftypes.ExternalRef{ { - Type: types.RefVCS, + Type: ftypes.RefVCS, URL: "https://github.com/org/repo", }, }, @@ -359,10 +359,10 @@ var ( ID: "github.com/aquasecurity/go-dep-parser@v0.0.0-20211224170007-df43bca6b6ff", Name: "github.com/aquasecurity/go-dep-parser", Version: "0.0.0-20211224170007-df43bca6b6ff", - Relationship: types.RelationshipDirect, - ExternalReferences: []types.ExternalRef{ + Relationship: ftypes.RelationshipDirect, + ExternalReferences: []ftypes.ExternalRef{ { - Type: types.RefVCS, + Type: ftypes.RefVCS, URL: "https://github.com/aquasecurity/go-dep-parser", }, }, diff --git a/pkg/dependency/parser/golang/sum/parse.go b/pkg/dependency/parser/golang/sum/parse.go index e06b474c0a97..4ec742b1bae2 100644 --- a/pkg/dependency/parser/golang/sum/parse.go +++ b/pkg/dependency/parser/golang/sum/parse.go @@ -7,21 +7,20 @@ import ( "golang.org/x/xerrors" "github.com/aquasecurity/trivy/pkg/dependency" - "github.com/aquasecurity/trivy/pkg/dependency/types" ftypes "github.com/aquasecurity/trivy/pkg/fanal/types" xio "github.com/aquasecurity/trivy/pkg/x/io" ) type Parser struct{} -func NewParser() types.Parser { +func NewParser() *Parser { return &Parser{} } // Parse parses a go.sum file -func (p *Parser) Parse(r xio.ReadSeekerAt) ([]types.Library, []types.Dependency, error) { - var libs []types.Library - uniqueLibs := make(map[string]string) +func (p *Parser) Parse(r xio.ReadSeekerAt) ([]ftypes.Package, []ftypes.Dependency, error) { + var pkgs []ftypes.Package + uniquePkgs := make(map[string]string) scanner := bufio.NewScanner(r) for scanner.Scan() { @@ -33,19 +32,19 @@ func (p *Parser) Parse(r xio.ReadSeekerAt) ([]types.Library, []types.Dependency, // go.sum records and sorts all non-major versions // with the latest version as last entry - uniqueLibs[s[0]] = strings.TrimSuffix(strings.TrimPrefix(s[1], "v"), "/go.mod") + uniquePkgs[s[0]] = strings.TrimSuffix(strings.TrimPrefix(s[1], "v"), "/go.mod") } if err := scanner.Err(); err != nil { return nil, nil, xerrors.Errorf("scan error: %w", err) } - for k, v := range uniqueLibs { - libs = append(libs, types.Library{ + for k, v := range uniquePkgs { + pkgs = append(pkgs, ftypes.Package{ ID: dependency.ID(ftypes.GoModule, k, v), Name: k, Version: v, }) } - return libs, nil, nil + return pkgs, nil, nil } diff --git a/pkg/dependency/parser/golang/sum/parse_test.go b/pkg/dependency/parser/golang/sum/parse_test.go index 3888743cdf85..90578d0a8a62 100644 --- a/pkg/dependency/parser/golang/sum/parse_test.go +++ b/pkg/dependency/parser/golang/sum/parse_test.go @@ -9,13 +9,13 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - "github.com/aquasecurity/trivy/pkg/dependency/types" + ftypes "github.com/aquasecurity/trivy/pkg/fanal/types" ) func TestParse(t *testing.T) { vectors := []struct { file string - want []types.Library + want []ftypes.Package }{ { file: "testdata/gomod_normal.sum", @@ -48,12 +48,8 @@ func TestParse(t *testing.T) { got[i].ID = "" // Not compare IDs, tested in mod.TestModuleID() } - sort.Slice(got, func(i, j int) bool { - return got[i].Name < got[j].Name - }) - sort.Slice(v.want, func(i, j int) bool { - return v.want[i].Name < v.want[j].Name - }) + sort.Sort(ftypes.Packages(got)) + sort.Sort(ftypes.Packages(v.want)) assert.Equal(t, v.want, got) }) diff --git a/pkg/dependency/parser/golang/sum/parse_testcase.go b/pkg/dependency/parser/golang/sum/parse_testcase.go index 70d4972c6f76..fc607de86e2a 100644 --- a/pkg/dependency/parser/golang/sum/parse_testcase.go +++ b/pkg/dependency/parser/golang/sum/parse_testcase.go @@ -1,6 +1,6 @@ package sum -import "github.com/aquasecurity/trivy/pkg/dependency/types" +import ftypes "github.com/aquasecurity/trivy/pkg/fanal/types" var ( // docker run --name gomod --rm -it golang:1.15 bash @@ -10,12 +10,12 @@ var ( // go mod init github.com/org/repo // go get golang.org/x/xerrors // go list -m all | awk 'NR>1 {sub(/^v/, "", $2); printf("{\""$1"\", \""$2"\", },\n")}' - GoModNormal = []types.Library{ + GoModNormal = []ftypes.Package{ {Name: "golang.org/x/xerrors", Version: "0.0.0-20200804184101-5ec99f83aff1"}, } // https://github.com/uudashr/gopkgs/blob/616744904701ef01d868da4b66aad0e6856c361d/v2/go.sum - GoModEmptyLine = []types.Library{ + GoModEmptyLine = []ftypes.Package{ {Name: "github.com/karrick/godirwalk", Version: "1.12.0"}, {Name: "github.com/pkg/errors", Version: "0.8.1"}, } @@ -30,7 +30,7 @@ var ( // go get github.com/stretchr/testify // go get github.com/BurntSushi/toml // go list -m all | awk 'NR>1 {sub(/^v/, "", $2); printf("{\""$1"\", \""$2"\", },\n")}' - GoModMany = []types.Library{ + GoModMany = []ftypes.Package{ {Name: "github.com/BurntSushi/toml", Version: "0.3.1"}, {Name: "github.com/cpuguy83/go-md2man/v2", Version: "2.0.0-20190314233015-f79a8a8ca69d"}, {Name: "github.com/davecgh/go-spew", Version: "1.1.0"}, @@ -53,7 +53,7 @@ var ( // go mod init github.com/org/repo // go get github.com/aquasecurity/trivy // go list -m all | awk 'NR>1 {sub(/^v/, "", $2); printf("{\""$1"\", \""$2"\", },\n")}' - GoModTrivy = []types.Library{ + GoModTrivy = []ftypes.Package{ {Name: "cloud.google.com/go", Version: "0.65.0"}, {Name: "cloud.google.com/go/bigquery", Version: "1.8.0"}, {Name: "cloud.google.com/go/datastore", Version: "1.1.0"}, diff --git a/pkg/dependency/parser/gradle/lockfile/parse.go b/pkg/dependency/parser/gradle/lockfile/parse.go index 47827faca036..9210d6d2f865 100644 --- a/pkg/dependency/parser/gradle/lockfile/parse.go +++ b/pkg/dependency/parser/gradle/lockfile/parse.go @@ -6,19 +6,18 @@ import ( "github.com/aquasecurity/trivy/pkg/dependency" "github.com/aquasecurity/trivy/pkg/dependency/parser/utils" - "github.com/aquasecurity/trivy/pkg/dependency/types" ftypes "github.com/aquasecurity/trivy/pkg/fanal/types" xio "github.com/aquasecurity/trivy/pkg/x/io" ) type Parser struct{} -func NewParser() types.Parser { +func NewParser() *Parser { return &Parser{} } -func (Parser) Parse(r xio.ReadSeekerAt) ([]types.Library, []types.Dependency, error) { - var libs []types.Library +func (Parser) Parse(r xio.ReadSeekerAt) ([]ftypes.Package, []ftypes.Dependency, error) { + var pkgs []ftypes.Package scanner := bufio.NewScanner(r) var lineNum int for scanner.Scan() { @@ -36,19 +35,19 @@ func (Parser) Parse(r xio.ReadSeekerAt) ([]types.Library, []types.Dependency, er name := strings.Join(dep[:2], ":") version := strings.Split(dep[2], "=")[0] // remove classPaths - libs = append(libs, types.Library{ + pkgs = append(pkgs, ftypes.Package{ ID: dependency.ID(ftypes.Gradle, name, version), Name: name, Version: version, - Locations: []types.Location{ + Locations: []ftypes.Location{ { StartLine: lineNum, EndLine: lineNum, }, }, - Relationship: types.RelationshipUnknown, + Relationship: ftypes.RelationshipUnknown, }) } - return utils.UniqueLibraries(libs), nil, nil + return utils.UniquePackages(pkgs), nil, nil } diff --git a/pkg/dependency/parser/gradle/lockfile/parse_test.go b/pkg/dependency/parser/gradle/lockfile/parse_test.go index e9f76883e4e5..fa73ea81122e 100644 --- a/pkg/dependency/parser/gradle/lockfile/parse_test.go +++ b/pkg/dependency/parser/gradle/lockfile/parse_test.go @@ -3,10 +3,9 @@ package lockfile import ( "os" "sort" - "strings" "testing" - "github.com/aquasecurity/trivy/pkg/dependency/types" + ftypes "github.com/aquasecurity/trivy/pkg/fanal/types" "github.com/stretchr/testify/assert" ) @@ -14,17 +13,17 @@ func TestParser_Parse(t *testing.T) { tests := []struct { name string inputFile string - want []types.Library + want []ftypes.Package }{ { name: "happy path", inputFile: "testdata/happy.lockfile", - want: []types.Library{ + want: []ftypes.Package{ { ID: "cglib:cglib-nodep:2.1.2", Name: "cglib:cglib-nodep", Version: "2.1.2", - Locations: []types.Location{ + Locations: []ftypes.Location{ { StartLine: 4, EndLine: 4, @@ -35,7 +34,7 @@ func TestParser_Parse(t *testing.T) { ID: "org.springframework:spring-asm:3.1.3.RELEASE", Name: "org.springframework:spring-asm", Version: "3.1.3.RELEASE", - Locations: []types.Location{ + Locations: []ftypes.Location{ { StartLine: 5, EndLine: 5, @@ -46,7 +45,7 @@ func TestParser_Parse(t *testing.T) { ID: "org.springframework:spring-beans:5.0.5.RELEASE", Name: "org.springframework:spring-beans", Version: "5.0.5.RELEASE", - Locations: []types.Location{ + Locations: []ftypes.Location{ { StartLine: 6, EndLine: 6, @@ -68,19 +67,9 @@ func TestParser_Parse(t *testing.T) { f, err := os.Open(tt.inputFile) assert.NoError(t, err) - libs, _, _ := parser.Parse(f) - sortLibs(libs) - assert.Equal(t, tt.want, libs) + pkgs, _, _ := parser.Parse(f) + sort.Sort(ftypes.Packages(pkgs)) + assert.Equal(t, tt.want, pkgs) }) } } - -func sortLibs(libs []types.Library) { - sort.Slice(libs, func(i, j int) bool { - ret := strings.Compare(libs[i].Name, libs[j].Name) - if ret == 0 { - return libs[i].Version < libs[j].Version - } - return ret < 0 - }) -} diff --git a/pkg/dependency/parser/hex/mix/parse.go b/pkg/dependency/parser/hex/mix/parse.go index ed5543ca4507..b95a375b29bd 100644 --- a/pkg/dependency/parser/hex/mix/parse.go +++ b/pkg/dependency/parser/hex/mix/parse.go @@ -7,7 +7,6 @@ import ( "github.com/aquasecurity/trivy/pkg/dependency" "github.com/aquasecurity/trivy/pkg/dependency/parser/utils" - "github.com/aquasecurity/trivy/pkg/dependency/types" ftypes "github.com/aquasecurity/trivy/pkg/fanal/types" "github.com/aquasecurity/trivy/pkg/log" xio "github.com/aquasecurity/trivy/pkg/x/io" @@ -18,14 +17,14 @@ type Parser struct { logger *log.Logger } -func NewParser() types.Parser { +func NewParser() *Parser { return &Parser{ logger: log.WithPrefix("mix"), } } -func (p *Parser) Parse(r xio.ReadSeekerAt) ([]types.Library, []types.Dependency, error) { - var libs []types.Library +func (p *Parser) Parse(r xio.ReadSeekerAt) ([]ftypes.Package, []ftypes.Dependency, error) { + var pkgs []ftypes.Package scanner := bufio.NewScanner(r) var lineNumber int // It is used to save dependency location for scanner.Scan() { @@ -54,11 +53,11 @@ func (p *Parser) Parse(r xio.ReadSeekerAt) ([]types.Library, []types.Dependency, continue } version := strings.Trim(ss[2], `"`) - libs = append(libs, types.Library{ + pkgs = append(pkgs, ftypes.Package{ ID: dependency.ID(ftypes.Hex, name, version), Name: name, Version: version, - Locations: []types.Location{ + Locations: []ftypes.Location{ { StartLine: lineNumber, EndLine: lineNumber, @@ -67,5 +66,5 @@ func (p *Parser) Parse(r xio.ReadSeekerAt) ([]types.Library, []types.Dependency, }) } - return utils.UniqueLibraries(libs), nil, nil + return utils.UniquePackages(pkgs), nil, nil } diff --git a/pkg/dependency/parser/hex/mix/parse_test.go b/pkg/dependency/parser/hex/mix/parse_test.go index ab3d929dd96f..a46f35f8d158 100644 --- a/pkg/dependency/parser/hex/mix/parse_test.go +++ b/pkg/dependency/parser/hex/mix/parse_test.go @@ -3,10 +3,9 @@ package mix import ( "os" "sort" - "strings" "testing" - "github.com/aquasecurity/trivy/pkg/dependency/types" + ftypes "github.com/aquasecurity/trivy/pkg/fanal/types" "github.com/stretchr/testify/assert" ) @@ -14,35 +13,55 @@ func TestParser_Parse(t *testing.T) { tests := []struct { name string inputFile string - want []types.Library + want []ftypes.Package }{ { name: "happy path", inputFile: "testdata/happy.mix.lock", - want: []types.Library{ + want: []ftypes.Package{ { - ID: "bunt@0.2.0", - Name: "bunt", - Version: "0.2.0", - Locations: []types.Location{{StartLine: 2, EndLine: 2}}, + ID: "bunt@0.2.0", + Name: "bunt", + Version: "0.2.0", + Locations: []ftypes.Location{ + { + StartLine: 2, + EndLine: 2, + }, + }, }, { - ID: "credo@1.6.6", - Name: "credo", - Version: "1.6.6", - Locations: []types.Location{{StartLine: 3, EndLine: 3}}, + ID: "credo@1.6.6", + Name: "credo", + Version: "1.6.6", + Locations: []ftypes.Location{ + { + StartLine: 3, + EndLine: 3, + }, + }, }, { - ID: "file_system@0.2.10", - Name: "file_system", - Version: "0.2.10", - Locations: []types.Location{{StartLine: 4, EndLine: 4}}, + ID: "file_system@0.2.10", + Name: "file_system", + Version: "0.2.10", + Locations: []ftypes.Location{ + { + StartLine: 4, + EndLine: 4, + }, + }, }, { - ID: "jason@1.3.0", - Name: "jason", - Version: "1.3.0", - Locations: []types.Location{{StartLine: 5, EndLine: 5}}, + ID: "jason@1.3.0", + Name: "jason", + Version: "1.3.0", + Locations: []ftypes.Location{ + { + StartLine: 5, + EndLine: 5, + }, + }, }, }, }, @@ -59,19 +78,9 @@ func TestParser_Parse(t *testing.T) { f, err := os.Open(tt.inputFile) assert.NoError(t, err) - libs, _, _ := parser.Parse(f) - sortLibs(libs) - assert.Equal(t, tt.want, libs) + pkgs, _, _ := parser.Parse(f) + sort.Sort(ftypes.Packages(pkgs)) + assert.Equal(t, tt.want, pkgs) }) } } - -func sortLibs(libs []types.Library) { - sort.Slice(libs, func(i, j int) bool { - ret := strings.Compare(libs[i].Name, libs[j].Name) - if ret == 0 { - return libs[i].Version < libs[j].Version - } - return ret < 0 - }) -} diff --git a/pkg/dependency/parser/java/jar/parse.go b/pkg/dependency/parser/java/jar/parse.go index 06f130c6b07c..86bfb64a5ed6 100644 --- a/pkg/dependency/parser/java/jar/parse.go +++ b/pkg/dependency/parser/java/jar/parse.go @@ -17,7 +17,7 @@ import ( "github.com/samber/lo" "golang.org/x/xerrors" - "github.com/aquasecurity/trivy/pkg/dependency/types" + ftypes "github.com/aquasecurity/trivy/pkg/fanal/types" "github.com/aquasecurity/trivy/pkg/log" xio "github.com/aquasecurity/trivy/pkg/x/io" ) @@ -61,7 +61,7 @@ func WithSize(size int64) Option { } } -func NewParser(c Client, opts ...Option) types.Parser { +func NewParser(c Client, opts ...Option) *Parser { p := &Parser{ logger: log.WithPrefix("jar"), client: c, @@ -74,15 +74,15 @@ func NewParser(c Client, opts ...Option) types.Parser { return p } -func (p *Parser) Parse(r xio.ReadSeekerAt) ([]types.Library, []types.Dependency, error) { - libs, deps, err := p.parseArtifact(p.rootFilePath, p.size, r) +func (p *Parser) Parse(r xio.ReadSeekerAt) ([]ftypes.Package, []ftypes.Dependency, error) { + pkgs, deps, err := p.parseArtifact(p.rootFilePath, p.size, r) if err != nil { return nil, nil, xerrors.Errorf("unable to parse %s: %w", p.rootFilePath, err) } - return removeLibraryDuplicates(libs), deps, nil + return removePackageDuplicates(pkgs), deps, nil } -func (p *Parser) parseArtifact(filePath string, size int64, r xio.ReadSeekerAt) ([]types.Library, []types.Dependency, error) { +func (p *Parser) parseArtifact(filePath string, size int64, r xio.ReadSeekerAt) ([]ftypes.Package, []ftypes.Dependency, error) { p.logger.Debug("Parsing Java artifacts...", log.String("file", filePath)) // Try to extract artifactId and version from the file name @@ -90,14 +90,14 @@ func (p *Parser) parseArtifact(filePath string, size int64, r xio.ReadSeekerAt) fileName := filepath.Base(filePath) fileProps := parseFileName(filePath) - libs, m, foundPomProps, err := p.traverseZip(filePath, size, r, fileProps) + pkgs, m, foundPomProps, err := p.traverseZip(filePath, size, r, fileProps) if err != nil { return nil, nil, xerrors.Errorf("zip error: %w", err) } // If pom.properties is found, it should be preferred than MANIFEST.MF. if foundPomProps { - return libs, nil, nil + return pkgs, nil, nil } manifestProps := m.properties(filePath) @@ -105,9 +105,9 @@ func (p *Parser) parseArtifact(filePath string, size int64, r xio.ReadSeekerAt) // In offline mode, we will not check if the artifact information is correct. if !manifestProps.Valid() { p.logger.Debug("Unable to identify POM in offline mode", log.String("file", fileName)) - return libs, nil, nil + return pkgs, nil, nil } - return append(libs, manifestProps.Library()), nil, nil + return append(pkgs, manifestProps.Package()), nil, nil } if manifestProps.Valid() { @@ -115,14 +115,14 @@ func (p *Parser) parseArtifact(filePath string, size int64, r xio.ReadSeekerAt) // We have to make sure that the artifact exists actually. if ok, _ := p.client.Exists(manifestProps.GroupID, manifestProps.ArtifactID); ok { // If groupId and artifactId are valid, they will be returned. - return append(libs, manifestProps.Library()), nil, nil + return append(pkgs, manifestProps.Package()), nil, nil } } // If groupId and artifactId are not found, call Maven Central's search API with SHA-1 digest. props, err := p.searchBySHA1(r, filePath) if err == nil { - return append(libs, props.Library()), nil, nil + return append(pkgs, props.Package()), nil, nil } else if !errors.Is(err, ArtifactNotFoundErr) { return nil, nil, xerrors.Errorf("failed to search by SHA1: %w", err) } @@ -131,7 +131,7 @@ func (p *Parser) parseArtifact(filePath string, size int64, r xio.ReadSeekerAt) // Return when artifactId or version from the file name are empty if fileProps.ArtifactID == "" || fileProps.Version == "" { - return libs, nil, nil + return pkgs, nil, nil } // Try to search groupId by artifactId via sonatype API @@ -140,17 +140,17 @@ func (p *Parser) parseArtifact(filePath string, size int64, r xio.ReadSeekerAt) if err == nil { p.logger.Debug("POM was determined in a heuristic way", log.String("file", fileName), log.String("artifact", fileProps.String())) - libs = append(libs, fileProps.Library()) + pkgs = append(pkgs, fileProps.Package()) } else if !errors.Is(err, ArtifactNotFoundErr) { return nil, nil, xerrors.Errorf("failed to search by artifact id: %w", err) } - return libs, nil, nil + return pkgs, nil, nil } func (p *Parser) traverseZip(filePath string, size int64, r xio.ReadSeekerAt, fileProps Properties) ( - []types.Library, manifest, bool, error) { - var libs []types.Library + []ftypes.Package, manifest, bool, error) { + var pkgs []ftypes.Package var m manifest var foundPomProps bool @@ -166,9 +166,9 @@ func (p *Parser) traverseZip(filePath string, size int64, r xio.ReadSeekerAt, fi if err != nil { return nil, manifest{}, false, xerrors.Errorf("failed to parse %s: %w", fileInJar.Name, err) } - // Validation of props to avoid getting libs with empty Name/Version + // Validation of props to avoid getting packages with empty Name/Version if props.Valid() { - libs = append(libs, props.Library()) + pkgs = append(pkgs, props.Package()) // Check if the pom.properties is for the original JAR/WAR/EAR if fileProps.ArtifactID == props.ArtifactID && fileProps.Version == props.Version { @@ -181,18 +181,18 @@ func (p *Parser) traverseZip(filePath string, size int64, r xio.ReadSeekerAt, fi return nil, manifest{}, false, xerrors.Errorf("failed to parse MANIFEST.MF: %w", err) } case isArtifact(fileInJar.Name): - innerLibs, _, err := p.parseInnerJar(fileInJar, filePath) // TODO process inner deps + innerPkgs, _, err := p.parseInnerJar(fileInJar, filePath) // TODO process inner deps if err != nil { p.logger.Debug("Failed to parse", log.String("file", fileInJar.Name), log.Err(err)) continue } - libs = append(libs, innerLibs...) + pkgs = append(pkgs, innerPkgs...) } } - return libs, m, foundPomProps, nil + return pkgs, m, foundPomProps, nil } -func (p *Parser) parseInnerJar(zf *zip.File, rootPath string) ([]types.Library, []types.Dependency, error) { +func (p *Parser) parseInnerJar(zf *zip.File, rootPath string) ([]ftypes.Package, []ftypes.Dependency, error) { fr, err := zf.Open() if err != nil { return nil, nil, xerrors.Errorf("unable to open %s: %w", zf.Name, err) @@ -221,12 +221,12 @@ func (p *Parser) parseInnerJar(zf *zip.File, rootPath string) ([]types.Library, } // Parse jar/war/ear recursively - innerLibs, innerDeps, err := p.parseArtifact(fullPath, int64(zf.UncompressedSize64), f) + innerPkgs, innerDeps, err := p.parseArtifact(fullPath, int64(zf.UncompressedSize64), f) if err != nil { return nil, nil, xerrors.Errorf("failed to parse %s: %w", zf.Name, err) } - return innerLibs, innerDeps, nil + return innerPkgs, innerDeps, nil } func (p *Parser) searchBySHA1(r io.ReadSeeker, filePath string) (Properties, error) { @@ -438,8 +438,8 @@ func (m manifest) determineVersion() (string, error) { return strings.TrimSpace(version), nil } -func removeLibraryDuplicates(libs []types.Library) []types.Library { - return lo.UniqBy(libs, func(lib types.Library) string { - return fmt.Sprintf("%s::%s::%s", lib.Name, lib.Version, lib.FilePath) +func removePackageDuplicates(pkgs []ftypes.Package) []ftypes.Package { + return lo.UniqBy(pkgs, func(pkg ftypes.Package) string { + return fmt.Sprintf("%s::%s::%s", pkg.Name, pkg.Version, pkg.FilePath) }) } diff --git a/pkg/dependency/parser/java/jar/parse_test.go b/pkg/dependency/parser/java/jar/parse_test.go index 88125a5a34b1..6813349e9754 100644 --- a/pkg/dependency/parser/java/jar/parse_test.go +++ b/pkg/dependency/parser/java/jar/parse_test.go @@ -14,7 +14,7 @@ import ( "github.com/stretchr/testify/require" "github.com/aquasecurity/trivy/pkg/dependency/parser/java/jar" - "github.com/aquasecurity/trivy/pkg/dependency/types" + ftypes "github.com/aquasecurity/trivy/pkg/fanal/types" ) var ( @@ -23,7 +23,7 @@ var ( // mvn dependency:list // mvn dependency:tree -Dscope=compile -Dscope=runtime | awk '/:tree/,/BUILD SUCCESS/' | awk 'NR > 1 { print }' | head -n -2 | awk '{print $NF}' | awk -F":" '{printf("{\""$1":"$2"\", \""$4 "\", \"\"},\n")}' // paths filled in manually - wantMaven = []types.Library{ + wantMaven = []ftypes.Package{ { Name: "com.example:web-app", Version: "1.0-SNAPSHOT", @@ -70,7 +70,7 @@ var ( // docker run --rm --name test -it test bash // gradle app:dependencies --configuration implementation | grep "[+\]---" | cut -d" " -f2 | awk -F":" '{printf("{\""$1":"$2"\", \""$3"\", \"\"},\n")}' // paths filled in manually - wantGradle = []types.Library{ + wantGradle = []ftypes.Package{ { Name: "commons-dbcp:commons-dbcp", Version: "1.4", @@ -94,7 +94,7 @@ var ( } // manually created - wantSHA1 = []types.Library{ + wantSHA1 = []ftypes.Package{ { Name: "org.springframework:spring-core", Version: "5.3.3", @@ -103,7 +103,7 @@ var ( } // offline - wantOffline = []types.Library{ + wantOffline = []ftypes.Package{ { Name: "org.springframework:Spring Framework", Version: "2.5.6.SEC03", @@ -112,7 +112,7 @@ var ( } // manually created - wantHeuristic = []types.Library{ + wantHeuristic = []ftypes.Package{ { Name: "com.example:heuristic", Version: "1.0.0-SNAPSHOT", @@ -121,7 +121,7 @@ var ( } // manually created - wantFatjar = []types.Library{ + wantFatjar = []ftypes.Package{ { Name: "com.google.guava:failureaccess", Version: "1.0.1", @@ -150,7 +150,7 @@ var ( } // manually created - wantNestedJar = []types.Library{ + wantNestedJar = []ftypes.Package{ { Name: "test:nested", Version: "0.0.1", @@ -169,7 +169,7 @@ var ( } // manually created - wantDuplicatesJar = []types.Library{ + wantDuplicatesJar = []ftypes.Package{ { Name: "io.quarkus.gizmo:gizmo", Version: "1.1.1.Final", @@ -211,7 +211,7 @@ func TestParse(t *testing.T) { name string file string // Test input file offline bool - want []types.Library + want []ftypes.Package }{ { name: "maven", @@ -319,12 +319,8 @@ func TestParse(t *testing.T) { got, _, err := p.Parse(f) require.NoError(t, err) - sort.Slice(got, func(i, j int) bool { - return got[i].Name < got[j].Name - }) - sort.Slice(v.want, func(i, j int) bool { - return v.want[i].Name < v.want[j].Name - }) + sort.Sort(ftypes.Packages(got)) + sort.Sort(ftypes.Packages(v.want)) assert.Equal(t, v.want, got) }) diff --git a/pkg/dependency/parser/java/jar/types.go b/pkg/dependency/parser/java/jar/types.go index ddd378b778b7..4246bbceb27f 100644 --- a/pkg/dependency/parser/java/jar/types.go +++ b/pkg/dependency/parser/java/jar/types.go @@ -5,7 +5,7 @@ import ( "golang.org/x/xerrors" - "github.com/aquasecurity/trivy/pkg/dependency/types" + ftypes "github.com/aquasecurity/trivy/pkg/fanal/types" ) var ArtifactNotFoundErr = xerrors.New("no artifact found") @@ -17,8 +17,8 @@ type Properties struct { FilePath string // path to file containing these props } -func (p Properties) Library() types.Library { - return types.Library{ +func (p Properties) Package() ftypes.Package { + return ftypes.Package{ Name: fmt.Sprintf("%s:%s", p.GroupID, p.ArtifactID), Version: p.Version, FilePath: p.FilePath, diff --git a/pkg/dependency/parser/java/pom/artifact.go b/pkg/dependency/parser/java/pom/artifact.go index 1e849aa6cab5..a99ff8569357 100644 --- a/pkg/dependency/parser/java/pom/artifact.go +++ b/pkg/dependency/parser/java/pom/artifact.go @@ -9,7 +9,7 @@ import ( "github.com/samber/lo" "golang.org/x/exp/slices" - "github.com/aquasecurity/trivy/pkg/dependency/types" + ftypes "github.com/aquasecurity/trivy/pkg/fanal/types" "github.com/aquasecurity/trivy/pkg/log" ) @@ -26,9 +26,9 @@ type artifact struct { Exclusions map[string]struct{} Module bool - Relationship types.Relationship + Relationship ftypes.Relationship - Locations types.Locations + Locations ftypes.Locations } func newArtifact(groupID, artifactID, version string, licenses []string, props map[string]string) artifact { @@ -37,7 +37,7 @@ func newArtifact(groupID, artifactID, version string, licenses []string, props m ArtifactID: evaluateVariable(artifactID, props, nil), Version: newVersion(evaluateVariable(version, props, nil)), Licenses: licenses, - Relationship: types.RelationshipIndirect, // default + Relationship: ftypes.RelationshipIndirect, // default } } @@ -49,10 +49,6 @@ func (a artifact) Equal(o artifact) bool { return a.GroupID == o.GroupID || a.ArtifactID == o.ArtifactID || a.Version.String() == o.Version.String() } -func (a artifact) JoinLicenses() string { - return strings.Join(a.Licenses, ", ") -} - func (a artifact) ToPOMLicenses() pomLicenses { return pomLicenses{ License: lo.Map(a.Licenses, func(lic string, _ int) pomLicense { diff --git a/pkg/dependency/parser/java/pom/parse.go b/pkg/dependency/parser/java/pom/parse.go index 59551a0e98ff..bf8df2ad1c0a 100644 --- a/pkg/dependency/parser/java/pom/parse.go +++ b/pkg/dependency/parser/java/pom/parse.go @@ -19,7 +19,6 @@ import ( "github.com/aquasecurity/trivy/pkg/dependency" "github.com/aquasecurity/trivy/pkg/dependency/parser/utils" - "github.com/aquasecurity/trivy/pkg/dependency/types" ftypes "github.com/aquasecurity/trivy/pkg/fanal/types" "github.com/aquasecurity/trivy/pkg/log" xio "github.com/aquasecurity/trivy/pkg/x/io" @@ -49,7 +48,7 @@ func WithReleaseRemoteRepos(repos []string) option { } } -type parser struct { +type Parser struct { logger *log.Logger rootPath string cache pomCache @@ -60,7 +59,7 @@ type parser struct { servers []Server } -func NewParser(filePath string, opts ...option) types.Parser { +func NewParser(filePath string, opts ...option) *Parser { o := &options{ offline: false, releaseRemoteRepos: []string{centralURL}, // Maven doesn't use central repository for snapshot dependencies @@ -77,7 +76,7 @@ func NewParser(filePath string, opts ...option) types.Parser { localRepository = filepath.Join(homeDir, ".m2", "repository") } - return &parser{ + return &Parser{ logger: log.WithPrefix("pom"), rootPath: filepath.Clean(filePath), cache: newPOMCache(), @@ -89,7 +88,7 @@ func NewParser(filePath string, opts ...option) types.Parser { } } -func (p *parser) Parse(r xio.ReadSeekerAt) ([]types.Library, []types.Dependency, error) { +func (p *Parser) Parse(r xio.ReadSeekerAt) ([]ftypes.Package, []ftypes.Dependency, error) { content, err := parsePom(r) if err != nil { return nil, nil, xerrors.Errorf("failed to parse POM: %w", err) @@ -112,18 +111,18 @@ func (p *parser) Parse(r xio.ReadSeekerAt) ([]types.Library, []types.Dependency, return p.parseRoot(root.artifact(), make(map[string]struct{})) } -func (p *parser) parseRoot(root artifact, uniqModules map[string]struct{}) ([]types.Library, []types.Dependency, error) { +func (p *Parser) parseRoot(root artifact, uniqModules map[string]struct{}) ([]ftypes.Package, []ftypes.Dependency, error) { // Prepare a queue for dependencies queue := newArtifactQueue() // Enqueue root POM - root.Relationship = types.RelationshipRoot + root.Relationship = ftypes.RelationshipRoot root.Module = false queue.enqueue(root) var ( - libs []types.Library - deps []types.Dependency + pkgs ftypes.Packages + deps ftypes.Dependencies rootDepManagement []pomDependency uniqArtifacts = make(map[string]artifact) uniqDeps = make(map[string][]string) @@ -141,12 +140,12 @@ func (p *parser) parseRoot(root artifact, uniqModules map[string]struct{}) ([]ty } uniqModules[art.String()] = struct{}{} - moduleLibs, moduleDeps, err := p.parseRoot(art, uniqModules) + modulePkgs, moduleDeps, err := p.parseRoot(art, uniqModules) if err != nil { return nil, nil, err } - libs = append(libs, moduleLibs...) + pkgs = append(pkgs, modulePkgs...) if moduleDeps != nil { deps = append(deps, moduleDeps...) } @@ -160,7 +159,7 @@ func (p *parser) parseRoot(root artifact, uniqModules map[string]struct{}) ([]ty } // mark artifact as Direct, if saved artifact is Direct // take a look `hard requirement for the specified version` test - if uniqueArt.Relationship == types.RelationshipRoot || uniqueArt.Relationship == types.RelationshipDirect { + if uniqueArt.Relationship == ftypes.RelationshipRoot || uniqueArt.Relationship == ftypes.RelationshipDirect { art.Relationship = uniqueArt.Relationship } // We don't need to overwrite dependency location for hard links @@ -174,13 +173,13 @@ func (p *parser) parseRoot(root artifact, uniqModules map[string]struct{}) ([]ty return nil, nil, xerrors.Errorf("resolve error (%s): %w", art, err) } - if art.Relationship == types.RelationshipRoot { + if art.Relationship == ftypes.RelationshipRoot { // Managed dependencies in the root POM affect transitive dependencies rootDepManagement = p.resolveDepManagement(result.properties, result.dependencyManagement) // mark its dependencies as "direct" result.dependencies = lo.Map(result.dependencies, func(dep artifact, _ int) artifact { - dep.Relationship = types.RelationshipDirect + dep.Relationship = ftypes.RelationshipDirect return dep }) } @@ -219,37 +218,37 @@ func (p *parser) parseRoot(root artifact, uniqModules map[string]struct{}) ([]ty } } - // Convert to []types.Library and []types.Dependency + // Convert to []ftypes.Package and []ftypes.Dependency for name, art := range uniqArtifacts { - lib := types.Library{ + pkg := ftypes.Package{ ID: packageID(name, art.Version.String()), Name: name, Version: art.Version.String(), - License: art.JoinLicenses(), + Licenses: art.Licenses, Relationship: art.Relationship, Locations: art.Locations, } - libs = append(libs, lib) + pkgs = append(pkgs, pkg) // Convert dependency names into dependency IDs - dependsOn := lo.FilterMap(uniqDeps[lib.ID], func(dependOnName string, _ int) (string, bool) { + dependsOn := lo.FilterMap(uniqDeps[pkg.ID], func(dependOnName string, _ int) (string, bool) { ver := depVersion(dependOnName, uniqArtifacts) return packageID(dependOnName, ver), ver != "" }) sort.Strings(dependsOn) if len(dependsOn) > 0 { - deps = append(deps, types.Dependency{ - ID: lib.ID, + deps = append(deps, ftypes.Dependency{ + ID: pkg.ID, DependsOn: dependsOn, }) } } - sort.Sort(types.Libraries(libs)) - sort.Sort(types.Dependencies(deps)) + sort.Sort(pkgs) + sort.Sort(deps) - return libs, deps, nil + return pkgs, deps, nil } // depVersion finds dependency in uniqArtifacts and return its version @@ -260,7 +259,7 @@ func depVersion(depName string, uniqArtifacts map[string]artifact) string { return "" } -func (p *parser) parseModule(currentPath, relativePath string) (artifact, error) { +func (p *Parser) parseModule(currentPath, relativePath string) (artifact, error) { // modulePath: "root/" + "module/" => "root/module" module, err := p.openRelativePom(currentPath, relativePath) if err != nil { @@ -280,7 +279,7 @@ func (p *parser) parseModule(currentPath, relativePath string) (artifact, error) return moduleArtifact, nil } -func (p *parser) resolve(art artifact, rootDepManagement []pomDependency) (analysisResult, error) { +func (p *Parser) resolve(art artifact, rootDepManagement []pomDependency) (analysisResult, error) { // If the artifact is found in cache, it is returned. if result := p.cache.get(art); result != nil { return *result, nil @@ -319,7 +318,7 @@ type analysisOptions struct { lineNumber bool // Save line numbers } -func (p *parser) analyze(pom *pom, opts analysisOptions) (analysisResult, error) { +func (p *Parser) analyze(pom *pom, opts analysisOptions) (analysisResult, error) { if pom == nil || pom.content == nil { return analysisResult{}, nil } @@ -362,7 +361,7 @@ func (p *parser) analyze(pom *pom, opts analysisOptions) (analysisResult, error) }, nil } -func (p *parser) mergeDependencyManagements(depManagements ...[]pomDependency) []pomDependency { +func (p *Parser) mergeDependencyManagements(depManagements ...[]pomDependency) []pomDependency { uniq := make(map[string]struct{}) var depManagement []pomDependency // The preceding argument takes precedence. @@ -378,7 +377,7 @@ func (p *parser) mergeDependencyManagements(depManagements ...[]pomDependency) [ return depManagement } -func (p *parser) parseDependencies(deps []pomDependency, props map[string]string, depManagement []pomDependency, +func (p *Parser) parseDependencies(deps []pomDependency, props map[string]string, depManagement []pomDependency, opts analysisOptions) []artifact { // Imported POMs often have no dependencies, so dependencyManagement resolution can be skipped. if len(deps) == 0 { @@ -403,7 +402,7 @@ func (p *parser) parseDependencies(deps []pomDependency, props map[string]string return dependencies } -func (p *parser) resolveDepManagement(props map[string]string, depManagement []pomDependency) []pomDependency { +func (p *Parser) resolveDepManagement(props map[string]string, depManagement []pomDependency) []pomDependency { var newDepManagement, imports []pomDependency for _, dep := range depManagement { // cf. https://howtodoinjava.com/maven/maven-dependency-scopes/#import @@ -437,7 +436,7 @@ func (p *parser) resolveDepManagement(props map[string]string, depManagement []p return newDepManagement } -func (p *parser) mergeDependencies(parent, child []artifact, exclusions map[string]struct{}) []artifact { +func (p *Parser) mergeDependencies(parent, child []artifact, exclusions map[string]struct{}) []artifact { var deps []artifact unique := make(map[string]struct{}) @@ -471,7 +470,7 @@ func excludeDep(exclusions map[string]struct{}, art artifact) bool { return false } -func (p *parser) parseParent(currentPath string, parent pomParent) (analysisResult, error) { +func (p *Parser) parseParent(currentPath string, parent pomParent) (analysisResult, error) { // Pass nil properties so that variables in are not evaluated. target := newArtifact(parent.GroupId, parent.ArtifactId, parent.Version, nil, nil) // if version is property (e.g. ${revision}) - we still need to parse this pom @@ -503,7 +502,7 @@ func (p *parser) parseParent(currentPath string, parent pomParent) (analysisResu return result, nil } -func (p *parser) retrieveParent(currentPath, relativePath string, target artifact) (*pom, error) { +func (p *Parser) retrieveParent(currentPath, relativePath string, target artifact) (*pom, error) { var errs error // Try relativePath @@ -536,7 +535,7 @@ func (p *parser) retrieveParent(currentPath, relativePath string, target artifac return nil, errs } -func (p *parser) tryRelativePath(parentArtifact artifact, currentPath, relativePath string) (*pom, error) { +func (p *Parser) tryRelativePath(parentArtifact artifact, currentPath, relativePath string) (*pom, error) { pom, err := p.openRelativePom(currentPath, relativePath) if err != nil { return nil, err @@ -563,7 +562,7 @@ func (p *parser) tryRelativePath(parentArtifact artifact, currentPath, relativeP return pom, nil } -func (p *parser) openRelativePom(currentPath, relativePath string) (*pom, error) { +func (p *Parser) openRelativePom(currentPath, relativePath string) (*pom, error) { // e.g. child/pom.xml => child/ dir := filepath.Dir(currentPath) @@ -585,7 +584,7 @@ func (p *parser) openRelativePom(currentPath, relativePath string) (*pom, error) return pom, nil } -func (p *parser) openPom(filePath string) (*pom, error) { +func (p *Parser) openPom(filePath string) (*pom, error) { f, err := os.Open(filePath) if err != nil { return nil, xerrors.Errorf("file open error (%s): %w", filePath, err) @@ -601,7 +600,7 @@ func (p *parser) openPom(filePath string) (*pom, error) { content: content, }, nil } -func (p *parser) tryRepository(groupID, artifactID, version string) (*pom, error) { +func (p *Parser) tryRepository(groupID, artifactID, version string) (*pom, error) { if version == "" { return nil, xerrors.Errorf("Version missing for %s:%s", groupID, artifactID) } @@ -627,14 +626,14 @@ func (p *parser) tryRepository(groupID, artifactID, version string) (*pom, error return nil, xerrors.Errorf("%s:%s:%s was not found in local/remote repositories", groupID, artifactID, version) } -func (p *parser) loadPOMFromLocalRepository(paths []string) (*pom, error) { +func (p *Parser) loadPOMFromLocalRepository(paths []string) (*pom, error) { paths = append([]string{p.localRepository}, paths...) localPath := filepath.Join(paths...) return p.openPom(localPath) } -func (p *parser) fetchPOMFromRemoteRepositories(paths []string, snapshot bool) (*pom, error) { +func (p *Parser) fetchPOMFromRemoteRepositories(paths []string, snapshot bool) (*pom, error) { // Do not try fetching pom.xml from remote repositories in offline mode if p.offline { p.logger.Debug("Fetching the remote pom.xml is skipped") @@ -660,7 +659,7 @@ func (p *parser) fetchPOMFromRemoteRepositories(paths []string, snapshot bool) ( return nil, xerrors.Errorf("the POM was not found in remote remoteRepositories") } -func (p *parser) fetchPOMFromRemoteRepository(repo string, paths []string) (*pom, error) { +func (p *Parser) fetchPOMFromRemoteRepository(repo string, paths []string) (*pom, error) { repoURL, err := url.Parse(repo) if err != nil { p.logger.Error("URL parse error", log.String("repo", repo)) diff --git a/pkg/dependency/parser/java/pom/parse_test.go b/pkg/dependency/parser/java/pom/parse_test.go index 7c14839ec3fa..3627a5c2eb90 100644 --- a/pkg/dependency/parser/java/pom/parse_test.go +++ b/pkg/dependency/parser/java/pom/parse_test.go @@ -11,7 +11,7 @@ import ( "github.com/stretchr/testify/require" "github.com/aquasecurity/trivy/pkg/dependency/parser/java/pom" - "github.com/aquasecurity/trivy/pkg/dependency/types" + ftypes "github.com/aquasecurity/trivy/pkg/fanal/types" ) func TestPom_Parse(t *testing.T) { @@ -20,29 +20,29 @@ func TestPom_Parse(t *testing.T) { inputFile string local bool offline bool - want []types.Library - wantDeps []types.Dependency + want []ftypes.Package + wantDeps []ftypes.Dependency wantErr string }{ { name: "local repository", inputFile: filepath.Join("testdata", "happy", "pom.xml"), local: true, - want: []types.Library{ + want: []ftypes.Package{ { ID: "com.example:happy:1.0.0", Name: "com.example:happy", Version: "1.0.0", - License: "BSD-3-Clause", - Relationship: types.RelationshipRoot, + Licenses: []string{"BSD-3-Clause"}, + Relationship: ftypes.RelationshipRoot, }, { ID: "org.example:example-api:1.7.30", Name: "org.example:example-api", Version: "1.7.30", - License: "The Apache Software License, Version 2.0", - Relationship: types.RelationshipDirect, - Locations: types.Locations{ + Licenses: []string{"The Apache Software License, Version 2.0"}, + Relationship: ftypes.RelationshipDirect, + Locations: ftypes.Locations{ { StartLine: 32, EndLine: 36, @@ -53,8 +53,8 @@ func TestPom_Parse(t *testing.T) { ID: "org.example:example-runtime:1.0.0", Name: "org.example:example-runtime", Version: "1.0.0", - Relationship: types.RelationshipDirect, - Locations: types.Locations{ + Relationship: ftypes.RelationshipDirect, + Locations: ftypes.Locations{ { StartLine: 37, EndLine: 42, @@ -62,7 +62,7 @@ func TestPom_Parse(t *testing.T) { }, }, }, - wantDeps: []types.Dependency{ + wantDeps: []ftypes.Dependency{ { ID: "com.example:happy:1.0.0", DependsOn: []string{ @@ -76,21 +76,21 @@ func TestPom_Parse(t *testing.T) { name: "remote release repository", inputFile: filepath.Join("testdata", "happy", "pom.xml"), local: false, - want: []types.Library{ + want: []ftypes.Package{ { ID: "com.example:happy:1.0.0", Name: "com.example:happy", Version: "1.0.0", - License: "BSD-3-Clause", - Relationship: types.RelationshipRoot, + Licenses: []string{"BSD-3-Clause"}, + Relationship: ftypes.RelationshipRoot, }, { ID: "org.example:example-api:1.7.30", Name: "org.example:example-api", Version: "1.7.30", - License: "The Apache Software License, Version 2.0", - Relationship: types.RelationshipDirect, - Locations: types.Locations{ + Licenses: []string{"The Apache Software License, Version 2.0"}, + Relationship: ftypes.RelationshipDirect, + Locations: ftypes.Locations{ { StartLine: 32, EndLine: 36, @@ -101,8 +101,8 @@ func TestPom_Parse(t *testing.T) { ID: "org.example:example-runtime:1.0.0", Name: "org.example:example-runtime", Version: "1.0.0", - Relationship: types.RelationshipDirect, - Locations: types.Locations{ + Relationship: ftypes.RelationshipDirect, + Locations: ftypes.Locations{ { StartLine: 37, EndLine: 42, @@ -110,7 +110,7 @@ func TestPom_Parse(t *testing.T) { }, }, }, - wantDeps: []types.Dependency{ + wantDeps: []ftypes.Dependency{ { ID: "com.example:happy:1.0.0", DependsOn: []string{ @@ -124,19 +124,19 @@ func TestPom_Parse(t *testing.T) { name: "snapshot dependency", inputFile: filepath.Join("testdata", "snapshot", "pom.xml"), local: false, - want: []types.Library{ + want: []ftypes.Package{ { ID: "com.example:happy:1.0.0", Name: "com.example:happy", Version: "1.0.0", - Relationship: types.RelationshipRoot, + Relationship: ftypes.RelationshipRoot, }, { ID: "org.example:example-dependency:1.2.3-SNAPSHOT", Name: "org.example:example-dependency", Version: "1.2.3-SNAPSHOT", - Relationship: types.RelationshipDirect, - Locations: types.Locations{ + Relationship: ftypes.RelationshipDirect, + Locations: ftypes.Locations{ { StartLine: 14, EndLine: 18, @@ -144,7 +144,7 @@ func TestPom_Parse(t *testing.T) { }, }, }, - wantDeps: []types.Dependency{ + wantDeps: []ftypes.Dependency{ { ID: "com.example:happy:1.0.0", DependsOn: []string{ @@ -158,13 +158,13 @@ func TestPom_Parse(t *testing.T) { inputFile: filepath.Join("testdata", "offline", "pom.xml"), local: false, offline: true, - want: []types.Library{ + want: []ftypes.Package{ { ID: "org.example:example-offline:2.3.4", Name: "org.example:example-offline", Version: "2.3.4", - Relationship: types.RelationshipDirect, - Locations: types.Locations{ + Relationship: ftypes.RelationshipDirect, + Locations: ftypes.Locations{ { StartLine: 17, EndLine: 21, @@ -177,21 +177,21 @@ func TestPom_Parse(t *testing.T) { name: "inherit parent properties", inputFile: filepath.Join("testdata", "parent-properties", "child", "pom.xml"), local: true, - want: []types.Library{ + want: []ftypes.Package{ { ID: "com.example:child:1.0.0", Name: "com.example:child", Version: "1.0.0", - License: "Apache 2.0", - Relationship: types.RelationshipRoot, + Licenses: []string{"Apache 2.0"}, + Relationship: ftypes.RelationshipRoot, }, { ID: "org.example:example-api:1.7.30", Name: "org.example:example-api", Version: "1.7.30", - License: "The Apache Software License, Version 2.0", - Relationship: types.RelationshipDirect, - Locations: types.Locations{ + Licenses: []string{"The Apache Software License, Version 2.0"}, + Relationship: ftypes.RelationshipDirect, + Locations: ftypes.Locations{ { StartLine: 33, EndLine: 37, @@ -199,7 +199,7 @@ func TestPom_Parse(t *testing.T) { }, }, }, - wantDeps: []types.Dependency{ + wantDeps: []ftypes.Dependency{ { ID: "com.example:child:1.0.0", DependsOn: []string{ @@ -212,20 +212,20 @@ func TestPom_Parse(t *testing.T) { name: "inherit project properties from parent", inputFile: filepath.Join("testdata", "project-version-from-parent", "child", "pom.xml"), local: true, - want: []types.Library{ + want: []ftypes.Package{ { ID: "com.example:child:2.0.0", Name: "com.example:child", Version: "2.0.0", - Relationship: types.RelationshipRoot, + Relationship: ftypes.RelationshipRoot, }, { ID: "org.example:example-api:2.0.0", Name: "org.example:example-api", Version: "2.0.0", - License: "The Apache Software License, Version 2.0", - Relationship: types.RelationshipDirect, - Locations: types.Locations{ + Licenses: []string{"The Apache Software License, Version 2.0"}, + Relationship: ftypes.RelationshipDirect, + Locations: ftypes.Locations{ { StartLine: 18, EndLine: 22, @@ -233,7 +233,7 @@ func TestPom_Parse(t *testing.T) { }, }, }, - wantDeps: []types.Dependency{ + wantDeps: []ftypes.Dependency{ { ID: "com.example:child:2.0.0", DependsOn: []string{ @@ -246,20 +246,20 @@ func TestPom_Parse(t *testing.T) { name: "inherit properties in parent depManagement with import scope", inputFile: filepath.Join("testdata", "inherit-props", "base", "pom.xml"), local: true, - want: []types.Library{ + want: []ftypes.Package{ { ID: "com.example:test:0.0.1-SNAPSHOT", Name: "com.example:test", Version: "0.0.1-SNAPSHOT", - Relationship: types.RelationshipRoot, + Relationship: ftypes.RelationshipRoot, }, { ID: "org.example:example-api:2.0.0", Name: "org.example:example-api", Version: "2.0.0", - License: "The Apache Software License, Version 2.0", - Relationship: types.RelationshipDirect, - Locations: types.Locations{ + Licenses: []string{"The Apache Software License, Version 2.0"}, + Relationship: ftypes.RelationshipDirect, + Locations: ftypes.Locations{ { StartLine: 18, EndLine: 21, @@ -267,7 +267,7 @@ func TestPom_Parse(t *testing.T) { }, }, }, - wantDeps: []types.Dependency{ + wantDeps: []ftypes.Dependency{ { ID: "com.example:test:0.0.1-SNAPSHOT", DependsOn: []string{ @@ -280,19 +280,19 @@ func TestPom_Parse(t *testing.T) { name: "dependencyManagement prefers child properties", inputFile: filepath.Join("testdata", "parent-child-properties", "child", "pom.xml"), local: true, - want: []types.Library{ + want: []ftypes.Package{ { ID: "com.example:child:1.0.0", Name: "com.example:child", Version: "1.0.0", - Relationship: types.RelationshipRoot, + Relationship: ftypes.RelationshipRoot, }, { ID: "org.example:example-dependency:1.2.3", Name: "org.example:example-dependency", Version: "1.2.3", - Relationship: types.RelationshipDirect, - Locations: types.Locations{ + Relationship: ftypes.RelationshipDirect, + Locations: ftypes.Locations{ { StartLine: 22, EndLine: 26, @@ -303,10 +303,10 @@ func TestPom_Parse(t *testing.T) { ID: "org.example:example-api:4.0.0", Name: "org.example:example-api", Version: "4.0.0", - Relationship: types.RelationshipIndirect, + Relationship: ftypes.RelationshipIndirect, }, }, - wantDeps: []types.Dependency{ + wantDeps: []ftypes.Dependency{ { ID: "com.example:child:1.0.0", DependsOn: []string{ @@ -325,23 +325,23 @@ func TestPom_Parse(t *testing.T) { name: "inherit parent dependencies", inputFile: filepath.Join("testdata", "parent-dependencies", "child", "pom.xml"), local: false, - want: []types.Library{ + want: []ftypes.Package{ { ID: "com.example:child:1.0.0-SNAPSHOT", Name: "com.example:child", Version: "1.0.0-SNAPSHOT", - License: "Apache 2.0", - Relationship: types.RelationshipRoot, + Licenses: []string{"Apache 2.0"}, + Relationship: ftypes.RelationshipRoot, }, { ID: "org.example:example-api:1.7.30", Name: "org.example:example-api", Version: "1.7.30", - License: "The Apache Software License, Version 2.0", - Relationship: types.RelationshipDirect, + Licenses: []string{"The Apache Software License, Version 2.0"}, + Relationship: ftypes.RelationshipDirect, }, }, - wantDeps: []types.Dependency{ + wantDeps: []ftypes.Dependency{ { ID: "com.example:child:1.0.0-SNAPSHOT", DependsOn: []string{ @@ -354,21 +354,21 @@ func TestPom_Parse(t *testing.T) { name: "inherit parent dependencyManagement", inputFile: filepath.Join("testdata", "parent-dependency-management", "child", "pom.xml"), local: true, - want: []types.Library{ + want: []ftypes.Package{ { ID: "com.example:child:3.0.0", Name: "com.example:child", Version: "3.0.0", - License: "Apache 2.0", - Relationship: types.RelationshipRoot, + Licenses: []string{"Apache 2.0"}, + Relationship: ftypes.RelationshipRoot, }, { ID: "org.example:example-api:1.7.30", Name: "org.example:example-api", Version: "1.7.30", - License: "The Apache Software License, Version 2.0", - Relationship: types.RelationshipDirect, - Locations: types.Locations{ + Licenses: []string{"The Apache Software License, Version 2.0"}, + Relationship: ftypes.RelationshipDirect, + Locations: ftypes.Locations{ { StartLine: 26, EndLine: 29, @@ -376,7 +376,7 @@ func TestPom_Parse(t *testing.T) { }, }, }, - wantDeps: []types.Dependency{ + wantDeps: []ftypes.Dependency{ { ID: "com.example:child:3.0.0", DependsOn: []string{ @@ -389,21 +389,21 @@ func TestPom_Parse(t *testing.T) { name: "transitive parents", inputFile: filepath.Join("testdata", "transitive-parents", "base", "pom.xml"), local: true, - want: []types.Library{ + want: []ftypes.Package{ { ID: "com.example:base:4.0.0", Name: "com.example:base", Version: "4.0.0", - License: "Apache 2.0", - Relationship: types.RelationshipRoot, + Licenses: []string{"Apache 2.0"}, + Relationship: ftypes.RelationshipRoot, }, { ID: "org.example:example-child:2.0.0", Name: "org.example:example-child", Version: "2.0.0", - License: "Apache 2.0", - Relationship: types.RelationshipDirect, - Locations: types.Locations{ + Licenses: []string{"Apache 2.0"}, + Relationship: ftypes.RelationshipDirect, + Locations: ftypes.Locations{ { StartLine: 28, EndLine: 32, @@ -414,11 +414,11 @@ func TestPom_Parse(t *testing.T) { ID: "org.example:example-api:1.7.30", Name: "org.example:example-api", Version: "1.7.30", - License: "The Apache Software License, Version 2.0", - Relationship: types.RelationshipIndirect, + Licenses: []string{"The Apache Software License, Version 2.0"}, + Relationship: ftypes.RelationshipIndirect, }, }, - wantDeps: []types.Dependency{ + wantDeps: []ftypes.Dependency{ { ID: "com.example:base:4.0.0", DependsOn: []string{ @@ -437,21 +437,21 @@ func TestPom_Parse(t *testing.T) { name: "parent relativePath", inputFile: filepath.Join("testdata", "parent-relative-path", "pom.xml"), local: true, - want: []types.Library{ + want: []ftypes.Package{ { ID: "com.example:child:1.0.0", Name: "com.example:child", Version: "1.0.0", - License: "Apache 2.0", - Relationship: types.RelationshipRoot, + Licenses: []string{"Apache 2.0"}, + Relationship: ftypes.RelationshipRoot, }, { ID: "org.example:example-api:1.7.30", Name: "org.example:example-api", Version: "1.7.30", - License: "The Apache Software License, Version 2.0", - Relationship: types.RelationshipDirect, - Locations: types.Locations{ + Licenses: []string{"The Apache Software License, Version 2.0"}, + Relationship: ftypes.RelationshipDirect, + Locations: ftypes.Locations{ { StartLine: 26, EndLine: 30, @@ -459,7 +459,7 @@ func TestPom_Parse(t *testing.T) { }, }, }, - wantDeps: []types.Dependency{ + wantDeps: []ftypes.Dependency{ { ID: "com.example:child:1.0.0", DependsOn: []string{ @@ -472,19 +472,19 @@ func TestPom_Parse(t *testing.T) { name: "parent version in property", inputFile: filepath.Join("testdata", "parent-version-is-property", "child", "pom.xml"), local: false, - want: []types.Library{ + want: []ftypes.Package{ { ID: "com.example:child:1.0.0-SNAPSHOT", Name: "com.example:child", Version: "1.0.0-SNAPSHOT", - Relationship: types.RelationshipRoot, + Relationship: ftypes.RelationshipRoot, }, { ID: "org.example:example-api:1.1.1", Name: "org.example:example-api", Version: "1.1.1", - Relationship: types.RelationshipDirect, - Locations: types.Locations{ + Relationship: ftypes.RelationshipDirect, + Locations: ftypes.Locations{ { StartLine: 19, EndLine: 22, @@ -492,7 +492,7 @@ func TestPom_Parse(t *testing.T) { }, }, }, - wantDeps: []types.Dependency{ + wantDeps: []ftypes.Dependency{ { ID: "com.example:child:1.0.0-SNAPSHOT", DependsOn: []string{ @@ -505,21 +505,21 @@ func TestPom_Parse(t *testing.T) { name: "parent in a remote repository", inputFile: filepath.Join("testdata", "parent-remote-repository", "pom.xml"), local: true, - want: []types.Library{ + want: []ftypes.Package{ { ID: "org.example:child:1.0.0", Name: "org.example:child", Version: "1.0.0", - License: "Apache 2.0", - Relationship: types.RelationshipRoot, + Licenses: []string{"Apache 2.0"}, + Relationship: ftypes.RelationshipRoot, }, { ID: "org.example:example-api:1.7.30", Name: "org.example:example-api", Version: "1.7.30", - License: "The Apache Software License, Version 2.0", - Relationship: types.RelationshipDirect, - Locations: types.Locations{ + Licenses: []string{"The Apache Software License, Version 2.0"}, + Relationship: ftypes.RelationshipDirect, + Locations: ftypes.Locations{ { StartLine: 25, EndLine: 29, @@ -527,7 +527,7 @@ func TestPom_Parse(t *testing.T) { }, }, }, - wantDeps: []types.Dependency{ + wantDeps: []ftypes.Dependency{ { ID: "org.example:child:1.0.0", DependsOn: []string{ @@ -541,25 +541,25 @@ func TestPom_Parse(t *testing.T) { // [INFO] com.example:soft:jar:1.0.0 // [INFO] +- org.example:example-api:jar:1.7.30:compile // [INFO] \- org.example:example-dependency:jar:1.2.3:compile - // Save DependsOn for each library - https://github.com/aquasecurity/go-dep-parser/pull/243#discussion_r1303904548 + // Save DependsOn for each package - https://github.com/aquasecurity/go-dep-parser/pull/243#discussion_r1303904548 name: "soft requirement", inputFile: filepath.Join("testdata", "soft-requirement", "pom.xml"), local: true, - want: []types.Library{ + want: []ftypes.Package{ { ID: "com.example:soft:1.0.0", Name: "com.example:soft", Version: "1.0.0", - License: "Apache 2.0", - Relationship: types.RelationshipRoot, + Licenses: []string{"Apache 2.0"}, + Relationship: ftypes.RelationshipRoot, }, { ID: "org.example:example-api:1.7.30", Name: "org.example:example-api", Version: "1.7.30", - License: "The Apache Software License, Version 2.0", - Relationship: types.RelationshipDirect, - Locations: types.Locations{ + Licenses: []string{"The Apache Software License, Version 2.0"}, + Relationship: ftypes.RelationshipDirect, + Locations: ftypes.Locations{ { StartLine: 32, EndLine: 36, @@ -570,8 +570,8 @@ func TestPom_Parse(t *testing.T) { ID: "org.example:example-dependency:1.2.3", Name: "org.example:example-dependency", Version: "1.2.3", - Relationship: types.RelationshipDirect, - Locations: types.Locations{ + Relationship: ftypes.RelationshipDirect, + Locations: ftypes.Locations{ { StartLine: 37, EndLine: 41, @@ -579,7 +579,7 @@ func TestPom_Parse(t *testing.T) { }, }, }, - wantDeps: []types.Dependency{ + wantDeps: []ftypes.Dependency{ { ID: "com.example:soft:1.0.0", DependsOn: []string{ @@ -601,50 +601,50 @@ func TestPom_Parse(t *testing.T) { // [INFO] +- org.example:example-dependency:jar:1.2.3:compile // [INFO] | \- org.example:example-api:jar:2.0.0:compile // [INFO] \- org.example:example-dependency2:jar:2.3.4:compile - // Save DependsOn for each library - https://github.com/aquasecurity/go-dep-parser/pull/243#discussion_r1303904548 + // Save DependsOn for each package - https://github.com/aquasecurity/go-dep-parser/pull/243#discussion_r1303904548 name: "soft requirement with transitive dependencies", inputFile: filepath.Join("testdata", "soft-requirement-with-transitive-dependencies", "pom.xml"), local: true, - want: []types.Library{ + want: []ftypes.Package{ { ID: "com.example:soft-transitive:1.0.0", Name: "com.example:soft-transitive", Version: "1.0.0", - Relationship: types.RelationshipRoot, - }, - { - ID: "org.example:example-dependency2:2.3.4", - Name: "org.example:example-dependency2", - Version: "2.3.4", - Relationship: types.RelationshipDirect, - Locations: types.Locations{ - { - StartLine: 18, - EndLine: 22, - }, - }, + Relationship: ftypes.RelationshipRoot, }, { ID: "org.example:example-dependency:1.2.3", Name: "org.example:example-dependency", Version: "1.2.3", - Relationship: types.RelationshipDirect, - Locations: types.Locations{ + Relationship: ftypes.RelationshipDirect, + Locations: ftypes.Locations{ { StartLine: 13, EndLine: 17, }, }, }, + { + ID: "org.example:example-dependency2:2.3.4", + Name: "org.example:example-dependency2", + Version: "2.3.4", + Relationship: ftypes.RelationshipDirect, + Locations: ftypes.Locations{ + { + StartLine: 18, + EndLine: 22, + }, + }, + }, { ID: "org.example:example-api:2.0.0", Name: "org.example:example-api", Version: "2.0.0", - License: "The Apache Software License, Version 2.0", - Relationship: types.RelationshipIndirect, + Licenses: []string{"The Apache Software License, Version 2.0"}, + Relationship: ftypes.RelationshipIndirect, }, }, - wantDeps: []types.Dependency{ + wantDeps: []ftypes.Dependency{ { ID: "com.example:soft-transitive:1.0.0", DependsOn: []string{ @@ -672,24 +672,24 @@ func TestPom_Parse(t *testing.T) { //[INFO] +- org.example:example-nested:jar:3.3.4:compile //[INFO] \- org.example:example-dependency:jar:1.2.3:compile //[INFO] \- org.example:example-api:jar:2.0.0:compile - // Save DependsOn for each library - https://github.com/aquasecurity/go-dep-parser/pull/243#discussion_r1303904548 + // Save DependsOn for each package - https://github.com/aquasecurity/go-dep-parser/pull/243#discussion_r1303904548 name: "hard requirement for the specified version", inputFile: filepath.Join("testdata", "hard-requirement", "pom.xml"), local: true, - want: []types.Library{ + want: []ftypes.Package{ { ID: "com.example:hard:1.0.0", Name: "com.example:hard", Version: "1.0.0", - License: "Apache 2.0", - Relationship: types.RelationshipRoot, + Licenses: []string{"Apache 2.0"}, + Relationship: ftypes.RelationshipRoot, }, { ID: "org.example:example-dependency:1.2.3", Name: "org.example:example-dependency", Version: "1.2.3", - Relationship: types.RelationshipDirect, - Locations: types.Locations{ + Relationship: ftypes.RelationshipDirect, + Locations: ftypes.Locations{ { StartLine: 33, EndLine: 37, @@ -700,8 +700,8 @@ func TestPom_Parse(t *testing.T) { ID: "org.example:example-nested:3.3.4", Name: "org.example:example-nested", Version: "3.3.4", - Relationship: types.RelationshipDirect, - Locations: types.Locations{ + Relationship: ftypes.RelationshipDirect, + Locations: ftypes.Locations{ { StartLine: 28, EndLine: 32, @@ -712,11 +712,11 @@ func TestPom_Parse(t *testing.T) { ID: "org.example:example-api:2.0.0", Name: "org.example:example-api", Version: "2.0.0", - License: "The Apache Software License, Version 2.0", - Relationship: types.RelationshipIndirect, + Licenses: []string{"The Apache Software License, Version 2.0"}, + Relationship: ftypes.RelationshipIndirect, }, }, - wantDeps: []types.Dependency{ + wantDeps: []ftypes.Dependency{ { ID: "com.example:hard:1.0.0", DependsOn: []string{ @@ -742,13 +742,13 @@ func TestPom_Parse(t *testing.T) { name: "version requirement", inputFile: filepath.Join("testdata", "version-requirement", "pom.xml"), local: true, - want: []types.Library{ + want: []ftypes.Package{ { ID: "com.example:hard:1.0.0", Name: "com.example:hard", Version: "1.0.0", - License: "Apache 2.0", - Relationship: types.RelationshipRoot, + Licenses: []string{"Apache 2.0"}, + Relationship: ftypes.RelationshipRoot, }, }, }, @@ -756,21 +756,21 @@ func TestPom_Parse(t *testing.T) { name: "import dependencyManagement", inputFile: filepath.Join("testdata", "import-dependency-management", "pom.xml"), local: true, - want: []types.Library{ + want: []ftypes.Package{ { ID: "com.example:import:2.0.0", Name: "com.example:import", Version: "2.0.0", - License: "Apache 2.0", - Relationship: types.RelationshipRoot, + Licenses: []string{"Apache 2.0"}, + Relationship: ftypes.RelationshipRoot, }, { ID: "org.example:example-api:1.7.30", Name: "org.example:example-api", Version: "1.7.30", - License: "The Apache Software License, Version 2.0", - Relationship: types.RelationshipDirect, - Locations: types.Locations{ + Licenses: []string{"The Apache Software License, Version 2.0"}, + Relationship: ftypes.RelationshipDirect, + Locations: ftypes.Locations{ { StartLine: 34, EndLine: 37, @@ -778,7 +778,7 @@ func TestPom_Parse(t *testing.T) { }, }, }, - wantDeps: []types.Dependency{ + wantDeps: []ftypes.Dependency{ { ID: "com.example:import:2.0.0", DependsOn: []string{ @@ -791,21 +791,21 @@ func TestPom_Parse(t *testing.T) { name: "import multiple dependencyManagement", inputFile: filepath.Join("testdata", "import-dependency-management-multiple", "pom.xml"), local: true, - want: []types.Library{ + want: []ftypes.Package{ { ID: "com.example:import:2.0.0", Name: "com.example:import", Version: "2.0.0", - License: "Apache 2.0", - Relationship: types.RelationshipRoot, + Licenses: []string{"Apache 2.0"}, + Relationship: ftypes.RelationshipRoot, }, { ID: "org.example:example-api:1.7.30", Name: "org.example:example-api", Version: "1.7.30", - License: "The Apache Software License, Version 2.0", - Relationship: types.RelationshipDirect, - Locations: types.Locations{ + Licenses: []string{"The Apache Software License, Version 2.0"}, + Relationship: ftypes.RelationshipDirect, + Locations: ftypes.Locations{ { StartLine: 42, EndLine: 45, @@ -813,7 +813,7 @@ func TestPom_Parse(t *testing.T) { }, }, }, - wantDeps: []types.Dependency{ + wantDeps: []ftypes.Dependency{ { ID: "com.example:import:2.0.0", DependsOn: []string{ @@ -826,19 +826,19 @@ func TestPom_Parse(t *testing.T) { name: "exclusions", inputFile: filepath.Join("testdata", "exclusions", "pom.xml"), local: true, - want: []types.Library{ + want: []ftypes.Package{ { ID: "com.example:exclusions:3.0.0", Name: "com.example:exclusions", Version: "3.0.0", - Relationship: types.RelationshipRoot, + Relationship: ftypes.RelationshipRoot, }, { ID: "org.example:example-nested:3.3.3", Name: "org.example:example-nested", Version: "3.3.3", - Relationship: types.RelationshipDirect, - Locations: types.Locations{ + Relationship: ftypes.RelationshipDirect, + Locations: ftypes.Locations{ { StartLine: 14, EndLine: 28, @@ -849,10 +849,10 @@ func TestPom_Parse(t *testing.T) { ID: "org.example:example-dependency:1.2.3", Name: "org.example:example-dependency", Version: "1.2.3", - Relationship: types.RelationshipIndirect, + Relationship: ftypes.RelationshipIndirect, }, }, - wantDeps: []types.Dependency{ + wantDeps: []ftypes.Dependency{ { ID: "com.example:exclusions:3.0.0", DependsOn: []string{ @@ -871,19 +871,19 @@ func TestPom_Parse(t *testing.T) { name: "exclusions in child", inputFile: filepath.Join("testdata", "exclusions-in-child", "pom.xml"), local: true, - want: []types.Library{ + want: []ftypes.Package{ { ID: "com.example:example:1.0.0", Name: "com.example:example", Version: "1.0.0", - Relationship: types.RelationshipRoot, + Relationship: ftypes.RelationshipRoot, }, { ID: "org.example:example-exclusions:4.0.0", Name: "org.example:example-exclusions", Version: "4.0.0", - Relationship: types.RelationshipDirect, - Locations: types.Locations{ + Relationship: ftypes.RelationshipDirect, + Locations: ftypes.Locations{ { StartLine: 10, EndLine: 14, @@ -894,17 +894,17 @@ func TestPom_Parse(t *testing.T) { ID: "org.example:example-api:1.7.30", Name: "org.example:example-api", Version: "1.7.30", - License: "The Apache Software License, Version 2.0", - Relationship: types.RelationshipIndirect, + Licenses: []string{"The Apache Software License, Version 2.0"}, + Relationship: ftypes.RelationshipIndirect, }, { ID: "org.example:example-dependency:1.2.3", Name: "org.example:example-dependency", Version: "1.2.3", - Relationship: types.RelationshipIndirect, + Relationship: ftypes.RelationshipIndirect, }, }, - wantDeps: []types.Dependency{ + wantDeps: []ftypes.Dependency{ { ID: "com.example:example:1.0.0", DependsOn: []string{ @@ -924,43 +924,43 @@ func TestPom_Parse(t *testing.T) { name: "exclusions with wildcards", inputFile: filepath.Join("testdata", "wildcard-exclusions", "pom.xml"), local: true, - want: []types.Library{ + want: []ftypes.Package{ { ID: "com.example:wildcard-exclusions:4.0.0", Name: "com.example:wildcard-exclusions", Version: "4.0.0", - Relationship: types.RelationshipRoot, - }, - { - ID: "org.example:example-dependency2:2.3.4", - Name: "org.example:example-dependency2", - Version: "2.3.4", - Relationship: types.RelationshipDirect, - Locations: types.Locations{ - { - StartLine: 25, - EndLine: 35, - }, - }, + Relationship: ftypes.RelationshipRoot, }, { ID: "org.example:example-dependency:1.2.3", Name: "org.example:example-dependency", Version: "1.2.3", - Relationship: types.RelationshipDirect, - Locations: types.Locations{ + Relationship: ftypes.RelationshipDirect, + Locations: ftypes.Locations{ { StartLine: 14, EndLine: 24, }, }, }, + { + ID: "org.example:example-dependency2:2.3.4", + Name: "org.example:example-dependency2", + Version: "2.3.4", + Relationship: ftypes.RelationshipDirect, + Locations: ftypes.Locations{ + { + StartLine: 25, + EndLine: 35, + }, + }, + }, { ID: "org.example:example-nested:3.3.3", Name: "org.example:example-nested", Version: "3.3.3", - Relationship: types.RelationshipDirect, - Locations: types.Locations{ + Relationship: ftypes.RelationshipDirect, + Locations: ftypes.Locations{ { StartLine: 36, EndLine: 46, @@ -968,7 +968,7 @@ func TestPom_Parse(t *testing.T) { }, }, }, - wantDeps: []types.Dependency{ + wantDeps: []ftypes.Dependency{ { ID: "com.example:wildcard-exclusions:4.0.0", DependsOn: []string{ @@ -983,33 +983,33 @@ func TestPom_Parse(t *testing.T) { name: "multi module", inputFile: filepath.Join("testdata", "multi-module", "pom.xml"), local: true, - want: []types.Library{ + want: []ftypes.Package{ { ID: "com.example:aggregation:1.0.0", Name: "com.example:aggregation", Version: "1.0.0", - License: "Apache 2.0", - Relationship: types.RelationshipRoot, + Licenses: []string{"Apache 2.0"}, + Relationship: ftypes.RelationshipRoot, }, { ID: "com.example:module:1.1.1", Name: "com.example:module", Version: "1.1.1", - License: "Apache 2.0", - Relationship: types.RelationshipRoot, // TODO: Several root modules break SBOM relationships + Licenses: []string{"Apache 2.0"}, + Relationship: ftypes.RelationshipRoot, // TODO: Several root modules break SBOM relationships }, { ID: "org.example:example-dependency:1.2.3", Name: "org.example:example-dependency", Version: "1.2.3", - Relationship: types.RelationshipDirect, + Relationship: ftypes.RelationshipDirect, }, { ID: "org.example:example-api:2.0.0", Name: "org.example:example-api", Version: "2.0.0", - License: "The Apache Software License, Version 2.0", - Relationship: types.RelationshipIndirect, + Licenses: []string{"The Apache Software License, Version 2.0"}, + Relationship: ftypes.RelationshipIndirect, }, }, // maven doesn't include modules in dep tree of root pom @@ -1029,7 +1029,7 @@ func TestPom_Parse(t *testing.T) { // [INFO] // [INFO] --- dependency:3.6.0:tree (default-cli) @ aggregation --- // [INFO] com.example:aggregation:pom:1.0.0 - wantDeps: []types.Dependency{ + wantDeps: []ftypes.Dependency{ { ID: "com.example:module:1.1.1", DependsOn: []string{ @@ -1048,35 +1048,35 @@ func TestPom_Parse(t *testing.T) { name: "Infinity loop for modules", inputFile: filepath.Join("testdata", "modules-infinity-loop", "pom.xml"), local: true, - want: []types.Library{ + want: []ftypes.Package{ // as module { ID: "org.example:module-1:2.0.0", Name: "org.example:module-1", Version: "2.0.0", - Relationship: types.RelationshipRoot, + Relationship: ftypes.RelationshipRoot, }, { ID: "org.example:module-2:3.0.0", Name: "org.example:module-2", Version: "3.0.0", - Relationship: types.RelationshipRoot, // TODO: Several root modules break SBOM relationships + Relationship: ftypes.RelationshipRoot, // TODO: Several root modules break SBOM relationships }, { ID: "org.example:root:1.0.0", Name: "org.example:root", Version: "1.0.0", - Relationship: types.RelationshipRoot, // TODO: Several root modules break SBOM relationships + Relationship: ftypes.RelationshipRoot, // TODO: Several root modules break SBOM relationships }, // as dependency { ID: "org.example:module-1:2.0.0", Name: "org.example:module-1", Version: "2.0.0", - Relationship: types.RelationshipDirect, + Relationship: ftypes.RelationshipDirect, }, }, - wantDeps: []types.Dependency{ + wantDeps: []ftypes.Dependency{ { ID: "org.example:module-2:3.0.0", DependsOn: []string{ @@ -1089,41 +1089,41 @@ func TestPom_Parse(t *testing.T) { name: "multi module soft requirement", inputFile: filepath.Join("testdata", "multi-module-soft-requirement", "pom.xml"), local: true, - want: []types.Library{ + want: []ftypes.Package{ { ID: "com.example:aggregation:1.0.0", Name: "com.example:aggregation", Version: "1.0.0", - Relationship: types.RelationshipRoot, + Relationship: ftypes.RelationshipRoot, }, { ID: "com.example:module1:1.1.1", Name: "com.example:module1", Version: "1.1.1", - Relationship: types.RelationshipRoot, + Relationship: ftypes.RelationshipRoot, }, { ID: "com.example:module2:1.1.1", Name: "com.example:module2", Version: "1.1.1", - Relationship: types.RelationshipRoot, + Relationship: ftypes.RelationshipRoot, }, { ID: "org.example:example-api:1.7.30", Name: "org.example:example-api", Version: "1.7.30", - License: "The Apache Software License, Version 2.0", - Relationship: types.RelationshipDirect, + Licenses: []string{"The Apache Software License, Version 2.0"}, + Relationship: ftypes.RelationshipDirect, }, { ID: "org.example:example-api:2.0.0", Name: "org.example:example-api", Version: "2.0.0", - License: "The Apache Software License, Version 2.0", - Relationship: types.RelationshipDirect, + Licenses: []string{"The Apache Software License, Version 2.0"}, + Relationship: ftypes.RelationshipDirect, }, }, - wantDeps: []types.Dependency{ + wantDeps: []ftypes.Dependency{ { ID: "com.example:module1:1.1.1", DependsOn: []string{ @@ -1142,19 +1142,19 @@ func TestPom_Parse(t *testing.T) { name: "overwrite artifact version from dependencyManagement in the root POM", inputFile: filepath.Join("testdata", "root-pom-dep-management", "pom.xml"), local: true, - want: []types.Library{ + want: []ftypes.Package{ { ID: "com.example:root-pom-dep-management:1.0.0", Name: "com.example:root-pom-dep-management", Version: "1.0.0", - Relationship: types.RelationshipRoot, + Relationship: ftypes.RelationshipRoot, }, { ID: "org.example:example-nested:3.3.3", Name: "org.example:example-nested", Version: "3.3.3", - Relationship: types.RelationshipDirect, - Locations: types.Locations{ + Relationship: ftypes.RelationshipDirect, + Locations: ftypes.Locations{ { StartLine: 20, EndLine: 24, @@ -1165,8 +1165,8 @@ func TestPom_Parse(t *testing.T) { ID: "org.example:example-api:2.0.0", Name: "org.example:example-api", Version: "2.0.0", - License: "The Apache Software License, Version 2.0", - Relationship: types.RelationshipIndirect, + Licenses: []string{"The Apache Software License, Version 2.0"}, + Relationship: ftypes.RelationshipIndirect, }, // dependency version is taken from `com.example:root-pom-dep-management` from dependencyManagement // not from `com.example:example-nested` from `com.example:example-nested` @@ -1174,10 +1174,10 @@ func TestPom_Parse(t *testing.T) { ID: "org.example:example-dependency:1.2.4", Name: "org.example:example-dependency", Version: "1.2.4", - Relationship: types.RelationshipIndirect, + Relationship: ftypes.RelationshipIndirect, }, }, - wantDeps: []types.Dependency{ + wantDeps: []ftypes.Dependency{ { ID: "com.example:root-pom-dep-management:1.0.0", DependsOn: []string{ @@ -1202,19 +1202,19 @@ func TestPom_Parse(t *testing.T) { name: "transitive dependencyManagement should not be inherited", inputFile: filepath.Join("testdata", "transitive-dependency-management", "pom.xml"), local: true, - want: []types.Library{ + want: []ftypes.Package{ { ID: "org.example:transitive-dependency-management:2.0.0", Name: "org.example:transitive-dependency-management", Version: "2.0.0", - Relationship: types.RelationshipRoot, + Relationship: ftypes.RelationshipRoot, }, { ID: "org.example:example-dependency-management3:1.1.1", Name: "org.example:example-dependency-management3", Version: "1.1.1", - Relationship: types.RelationshipDirect, - Locations: types.Locations{ + Relationship: ftypes.RelationshipDirect, + Locations: ftypes.Locations{ { StartLine: 14, EndLine: 18, @@ -1227,17 +1227,17 @@ func TestPom_Parse(t *testing.T) { ID: "org.example:example-api:2.0.0", Name: "org.example:example-api", Version: "2.0.0", - License: "The Apache Software License, Version 2.0", - Relationship: types.RelationshipIndirect, + Licenses: []string{"The Apache Software License, Version 2.0"}, + Relationship: ftypes.RelationshipIndirect, }, { ID: "org.example:example-dependency:1.2.3", Name: "org.example:example-dependency", Version: "1.2.3", - Relationship: types.RelationshipIndirect, + Relationship: ftypes.RelationshipIndirect, }, }, - wantDeps: []types.Dependency{ + wantDeps: []ftypes.Dependency{ { ID: "org.example:example-dependency-management3:1.1.1", DependsOn: []string{ @@ -1262,21 +1262,21 @@ func TestPom_Parse(t *testing.T) { name: "parent not found", inputFile: filepath.Join("testdata", "not-found-parent", "pom.xml"), local: true, - want: []types.Library{ + want: []ftypes.Package{ { ID: "com.example:no-parent:1.0-SNAPSHOT", Name: "com.example:no-parent", Version: "1.0-SNAPSHOT", - License: "Apache 2.0", - Relationship: types.RelationshipRoot, + Licenses: []string{"Apache 2.0"}, + Relationship: ftypes.RelationshipRoot, }, { ID: "org.example:example-api:1.7.30", Name: "org.example:example-api", Version: "1.7.30", - License: "The Apache Software License, Version 2.0", - Relationship: types.RelationshipDirect, - Locations: types.Locations{ + Licenses: []string{"The Apache Software License, Version 2.0"}, + Relationship: ftypes.RelationshipDirect, + Locations: ftypes.Locations{ { StartLine: 27, EndLine: 31, @@ -1284,7 +1284,7 @@ func TestPom_Parse(t *testing.T) { }, }, }, - wantDeps: []types.Dependency{ + wantDeps: []ftypes.Dependency{ { ID: "com.example:no-parent:1.0-SNAPSHOT", DependsOn: []string{ @@ -1297,20 +1297,20 @@ func TestPom_Parse(t *testing.T) { name: "dependency not found", inputFile: filepath.Join("testdata", "not-found-dependency", "pom.xml"), local: true, - want: []types.Library{ + want: []ftypes.Package{ { ID: "com.example:not-found-dependency:1.0.0", Name: "com.example:not-found-dependency", Version: "1.0.0", - License: "Apache 2.0", - Relationship: types.RelationshipRoot, + Licenses: []string{"Apache 2.0"}, + Relationship: ftypes.RelationshipRoot, }, { ID: "org.example:example-not-found:999", Name: "org.example:example-not-found", Version: "999", - Relationship: types.RelationshipDirect, - Locations: types.Locations{ + Relationship: ftypes.RelationshipDirect, + Locations: ftypes.Locations{ { StartLine: 21, EndLine: 25, @@ -1318,7 +1318,7 @@ func TestPom_Parse(t *testing.T) { }, }, }, - wantDeps: []types.Dependency{ + wantDeps: []ftypes.Dependency{ { ID: "com.example:not-found-dependency:1.0.0", DependsOn: []string{ @@ -1331,13 +1331,13 @@ func TestPom_Parse(t *testing.T) { name: "module not found - unable to parse module", inputFile: filepath.Join("testdata", "not-found-module", "pom.xml"), local: true, - want: []types.Library{ + want: []ftypes.Package{ { ID: "com.example:aggregation:1.0.0", Name: "com.example:aggregation", Version: "1.0.0", - License: "Apache 2.0", - Relationship: types.RelationshipRoot, + Licenses: []string{"Apache 2.0"}, + Relationship: ftypes.RelationshipRoot, }, }, }, @@ -1345,13 +1345,16 @@ func TestPom_Parse(t *testing.T) { name: "multiply licenses", inputFile: filepath.Join("testdata", "multiply-licenses", "pom.xml"), local: true, - want: []types.Library{ + want: []ftypes.Package{ { - ID: "com.example:multiply-licenses:1.0.0", - Name: "com.example:multiply-licenses", - Version: "1.0.0", - License: "MIT, Apache 2.0", - Relationship: types.RelationshipRoot, + ID: "com.example:multiply-licenses:1.0.0", + Name: "com.example:multiply-licenses", + Version: "1.0.0", + Licenses: []string{ + "MIT", + "Apache 2.0", + }, + Relationship: ftypes.RelationshipRoot, }, }, }, @@ -1359,13 +1362,13 @@ func TestPom_Parse(t *testing.T) { name: "inherit parent license", inputFile: filepath.Join("testdata", "inherit-license", "module", "submodule", "pom.xml"), local: true, - want: []types.Library{ + want: []ftypes.Package{ { ID: "com.example.app:submodule:1.0.0", Name: "com.example.app:submodule", Version: "1.0.0", - License: "Apache-2.0", - Relationship: types.RelationshipRoot, + Licenses: []string{"Apache-2.0"}, + Relationship: ftypes.RelationshipRoot, }, }, }, @@ -1373,13 +1376,13 @@ func TestPom_Parse(t *testing.T) { name: "compare ArtifactIDs for base and parent pom's", inputFile: filepath.Join("testdata", "no-parent-infinity-loop", "pom.xml"), local: true, - want: []types.Library{ + want: []ftypes.Package{ { ID: "com.example:child:1.0.0", Name: "com.example:child", Version: "1.0.0", - License: "The Apache Software License, Version 2.0", - Relationship: types.RelationshipRoot, + Licenses: []string{"The Apache Software License, Version 2.0"}, + Relationship: ftypes.RelationshipRoot, }, }, }, @@ -1403,7 +1406,7 @@ func TestPom_Parse(t *testing.T) { p := pom.NewParser(tt.inputFile, pom.WithReleaseRemoteRepos(remoteRepos), pom.WithOffline(tt.offline)) - gotLibs, gotDeps, err := p.Parse(f) + gotPkgs, gotDeps, err := p.Parse(f) if tt.wantErr != "" { require.NotNil(t, err) assert.Contains(t, err.Error(), tt.wantErr) @@ -1411,7 +1414,7 @@ func TestPom_Parse(t *testing.T) { } require.NoError(t, err) - assert.Equal(t, tt.want, gotLibs) + assert.Equal(t, tt.want, gotPkgs) assert.Equal(t, tt.wantDeps, gotDeps) }) } diff --git a/pkg/dependency/parser/java/pom/pom.go b/pkg/dependency/parser/java/pom/pom.go index 7ae73fd6edd9..3a0170d36811 100644 --- a/pkg/dependency/parser/java/pom/pom.go +++ b/pkg/dependency/parser/java/pom/pom.go @@ -13,8 +13,9 @@ import ( "golang.org/x/xerrors" "github.com/aquasecurity/trivy/pkg/dependency/parser/utils" - "github.com/aquasecurity/trivy/pkg/dependency/types" + ftypes "github.com/aquasecurity/trivy/pkg/fanal/types" "github.com/aquasecurity/trivy/pkg/log" + "github.com/aquasecurity/trivy/pkg/x/slices" ) type pom struct { @@ -110,9 +111,9 @@ func (p pom) artifact() artifact { } func (p pom) licenses() []string { - return lo.FilterMap(p.content.Licenses.License, func(lic pomLicense, _ int) (string, bool) { + return slices.ZeroToNil(lo.FilterMap(p.content.Licenses.License, func(lic pomLicense, _ int) (string, bool) { return lic.Name, lic.Name != "" - }) + })) } func (p pom) repositories(servers []Server) ([]string, []string) { @@ -286,9 +287,9 @@ func (d pomDependency) ToArtifact(opts analysisOptions) artifact { exclusions[fmt.Sprintf("%s:%s", e.GroupID, e.ArtifactID)] = struct{}{} } - var locations types.Locations + var locations ftypes.Locations if opts.lineNumber { - locations = types.Locations{ + locations = ftypes.Locations{ { StartLine: d.StartLine, EndLine: d.EndLine, @@ -302,7 +303,7 @@ func (d pomDependency) ToArtifact(opts analysisOptions) artifact { Version: newVersion(d.Version), Exclusions: exclusions, Locations: locations, - Relationship: types.RelationshipIndirect, // default + Relationship: ftypes.RelationshipIndirect, // default } } diff --git a/pkg/dependency/parser/julia/manifest/parse.go b/pkg/dependency/parser/julia/manifest/parse.go index 685a54074629..061676d3f599 100644 --- a/pkg/dependency/parser/julia/manifest/parse.go +++ b/pkg/dependency/parser/julia/manifest/parse.go @@ -8,7 +8,7 @@ import ( "golang.org/x/exp/maps" "golang.org/x/xerrors" - "github.com/aquasecurity/trivy/pkg/dependency/types" + ftypes "github.com/aquasecurity/trivy/pkg/fanal/types" xio "github.com/aquasecurity/trivy/pkg/x/io" ) @@ -27,11 +27,11 @@ type primitiveDependency struct { type Parser struct{} -func NewParser() types.Parser { +func NewParser() *Parser { return &Parser{} } -func (p *Parser) Parse(r xio.ReadSeekerAt) ([]types.Library, []types.Dependency, error) { +func (p *Parser) Parse(r xio.ReadSeekerAt) ([]ftypes.Package, []ftypes.Dependency, error) { var oldDeps map[string][]primitiveDependency var primMan primitiveManifest var manMetadata toml.MetaData @@ -68,19 +68,19 @@ func (p *Parser) Parse(r xio.ReadSeekerAt) ([]types.Library, []types.Dependency, pkgParser := naivePkgParser{r: r} lineNumIdx := pkgParser.parse() - var libs []types.Library - var deps []types.Dependency + var pkgs ftypes.Packages + var deps ftypes.Dependencies for name, manifestDeps := range man.Dependencies { for _, manifestDep := range manifestDeps { version := depVersion(manifestDep.Version, man.JuliaVersion) pkgID := manifestDep.UUID - lib := types.Library{ + pkg := ftypes.Package{ ID: pkgID, Name: name, Version: version, } if pos, ok := lineNumIdx[manifestDep.UUID]; ok { - lib.Locations = []types.Location{ + pkg.Locations = []ftypes.Location{ { StartLine: pos.start, EndLine: pos.end, @@ -88,19 +88,19 @@ func (p *Parser) Parse(r xio.ReadSeekerAt) ([]types.Library, []types.Dependency, } } - libs = append(libs, lib) + pkgs = append(pkgs, pkg) if len(manifestDep.DependsOn) > 0 { - deps = append(deps, types.Dependency{ + deps = append(deps, ftypes.Dependency{ ID: pkgID, DependsOn: manifestDep.DependsOn, }) } } } - sort.Sort(types.Libraries(libs)) - sort.Sort(types.Dependencies(deps)) - return libs, deps, nil + sort.Sort(pkgs) + sort.Sort(deps) + return pkgs, deps, nil } // Returns the effective version of the `dep`. diff --git a/pkg/dependency/parser/julia/manifest/parse_test.go b/pkg/dependency/parser/julia/manifest/parse_test.go index 6eacf5a76133..229499c6cb71 100644 --- a/pkg/dependency/parser/julia/manifest/parse_test.go +++ b/pkg/dependency/parser/julia/manifest/parse_test.go @@ -8,26 +8,26 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - "github.com/aquasecurity/trivy/pkg/dependency/types" + ftypes "github.com/aquasecurity/trivy/pkg/fanal/types" ) func TestParse(t *testing.T) { tests := []struct { name string file string // Test input file - want []types.Library - wantDeps []types.Dependency + want []ftypes.Package + wantDeps []ftypes.Dependency }{ { name: "Manifest v1.6", file: "testdata/primary/Manifest_v1.6.toml", - want: juliaV1_6Libs, + want: juliaV1_6Pkgs, wantDeps: juliaV1_6Deps, }, { name: "Manifest v1.8", file: "testdata/primary/Manifest_v1.8.toml", - want: juliaV1_8Libs, + want: juliaV1_8Pkgs, wantDeps: juliaV1_8Deps, }, { @@ -45,13 +45,13 @@ func TestParse(t *testing.T) { { name: "dep extensions v1.9", file: "testdata/dep_ext_v1.9/Manifest.toml", - want: juliaV1_9DepExtLibs, + want: juliaV1_9DepExtPkgs, wantDeps: nil, }, { name: "shadowed dep v1.9", file: "testdata/shadowed_dep_v1.9/Manifest.toml", - want: juliaV1_9ShadowedDepLibs, + want: juliaV1_9ShadowedDepPkgs, wantDeps: juliaV1_9ShadowedDepDeps, }, } @@ -61,13 +61,13 @@ func TestParse(t *testing.T) { f, err := os.Open(tt.file) require.NoError(t, err) - gotLibs, gotDeps, err := NewParser().Parse(f) + gotPkgs, gotDeps, err := NewParser().Parse(f) require.NoError(t, err) - sort.Sort(types.Libraries(tt.want)) - assert.Equal(t, tt.want, gotLibs) + sort.Sort(ftypes.Packages(tt.want)) + assert.Equal(t, tt.want, gotPkgs) if tt.wantDeps != nil { - sort.Sort(types.Dependencies(tt.wantDeps)) + sort.Sort(ftypes.Dependencies(tt.wantDeps)) assert.Equal(t, tt.wantDeps, gotDeps) } }) diff --git a/pkg/dependency/parser/julia/manifest/parse_testcase.go b/pkg/dependency/parser/julia/manifest/parse_testcase.go index 3055cc8d15a8..75602f7311f8 100644 --- a/pkg/dependency/parser/julia/manifest/parse_testcase.go +++ b/pkg/dependency/parser/julia/manifest/parse_testcase.go @@ -1,18 +1,18 @@ package julia -import "github.com/aquasecurity/trivy/pkg/dependency/types" +import ftypes "github.com/aquasecurity/trivy/pkg/fanal/types" var ( - juliaV1_6Libs = []types.Library{ - {ID: "ade2ca70-3891-5945-98fb-dc099432e06a", Name: "Dates", Version: "unknown", Locations: []types.Location{{StartLine: 3, EndLine: 5}}}, - {ID: "682c06a0-de6a-54ab-a142-c8b1cf79cde6", Name: "JSON", Version: "0.21.4", Locations: []types.Location{{StartLine: 7, EndLine: 11}}}, - {ID: "a63ad114-7e13-5084-954f-fe012c677804", Name: "Mmap", Version: "unknown", Locations: []types.Location{{StartLine: 13, EndLine: 14}}}, - {ID: "69de0a69-1ddd-5017-9359-2bf0b02dc9f0", Name: "Parsers", Version: "2.4.2", Locations: []types.Location{{StartLine: 16, EndLine: 20}}}, - {ID: "de0858da-6303-5e67-8744-51eddeeeb8d7", Name: "Printf", Version: "unknown", Locations: []types.Location{{StartLine: 22, EndLine: 24}}}, - {ID: "4ec0a83e-493e-50e2-b9ac-8f72acf5a8f5", Name: "Unicode", Version: "unknown", Locations: []types.Location{{StartLine: 26, EndLine: 27}}}, + juliaV1_6Pkgs = []ftypes.Package{ + {ID: "ade2ca70-3891-5945-98fb-dc099432e06a", Name: "Dates", Version: "unknown", Locations: []ftypes.Location{{StartLine: 3, EndLine: 5}}}, + {ID: "682c06a0-de6a-54ab-a142-c8b1cf79cde6", Name: "JSON", Version: "0.21.4", Locations: []ftypes.Location{{StartLine: 7, EndLine: 11}}}, + {ID: "a63ad114-7e13-5084-954f-fe012c677804", Name: "Mmap", Version: "unknown", Locations: []ftypes.Location{{StartLine: 13, EndLine: 14}}}, + {ID: "69de0a69-1ddd-5017-9359-2bf0b02dc9f0", Name: "Parsers", Version: "2.4.2", Locations: []ftypes.Location{{StartLine: 16, EndLine: 20}}}, + {ID: "de0858da-6303-5e67-8744-51eddeeeb8d7", Name: "Printf", Version: "unknown", Locations: []ftypes.Location{{StartLine: 22, EndLine: 24}}}, + {ID: "4ec0a83e-493e-50e2-b9ac-8f72acf5a8f5", Name: "Unicode", Version: "unknown", Locations: []ftypes.Location{{StartLine: 26, EndLine: 27}}}, } - juliaV1_6Deps = []types.Dependency{ + juliaV1_6Deps = []ftypes.Dependency{ {ID: "ade2ca70-3891-5945-98fb-dc099432e06a", DependsOn: []string{"de0858da-6303-5e67-8744-51eddeeeb8d7"}}, {ID: "682c06a0-de6a-54ab-a142-c8b1cf79cde6", DependsOn: []string{ "4ec0a83e-493e-50e2-b9ac-8f72acf5a8f5", @@ -24,23 +24,23 @@ var ( {ID: "de0858da-6303-5e67-8744-51eddeeeb8d7", DependsOn: []string{"4ec0a83e-493e-50e2-b9ac-8f72acf5a8f5"}}, } - juliaV1_8Libs = []types.Library{ - {ID: "ade2ca70-3891-5945-98fb-dc099432e06a", Name: "Dates", Version: "1.8.5", Locations: []types.Location{{StartLine: 7, EndLine: 9}}}, - {ID: "682c06a0-de6a-54ab-a142-c8b1cf79cde6", Name: "JSON", Version: "0.21.4", Locations: []types.Location{{StartLine: 11, EndLine: 15}}}, - {ID: "a63ad114-7e13-5084-954f-fe012c677804", Name: "Mmap", Version: "1.8.5", Locations: []types.Location{{StartLine: 17, EndLine: 18}}}, - {ID: "69de0a69-1ddd-5017-9359-2bf0b02dc9f0", Name: "Parsers", Version: "2.5.10", Locations: []types.Location{{StartLine: 20, EndLine: 24}}}, - {ID: "aea7be01-6a6a-4083-8856-8a6e6704d82a", Name: "PrecompileTools", Version: "1.1.1", Locations: []types.Location{{StartLine: 26, EndLine: 30}}}, - {ID: "21216c6a-2e73-6563-6e65-726566657250", Name: "Preferences", Version: "1.4.0", Locations: []types.Location{{StartLine: 32, EndLine: 36}}}, - {ID: "de0858da-6303-5e67-8744-51eddeeeb8d7", Name: "Printf", Version: "1.8.5", Locations: []types.Location{{StartLine: 38, EndLine: 40}}}, - {ID: "9a3f8284-a2c9-5f02-9a11-845980a1fd5c", Name: "Random", Version: "1.8.5", Locations: []types.Location{{StartLine: 42, EndLine: 44}}}, - {ID: "ea8e919c-243c-51af-8825-aaa63cd721ce", Name: "SHA", Version: "0.7.0", Locations: []types.Location{{StartLine: 46, EndLine: 48}}}, - {ID: "9e88b42a-f829-5b0c-bbe9-9e923198166b", Name: "Serialization", Version: "1.8.5", Locations: []types.Location{{StartLine: 50, EndLine: 51}}}, - {ID: "fa267f1f-6049-4f14-aa54-33bafae1ed76", Name: "TOML", Version: "1.0.0", Locations: []types.Location{{StartLine: 53, EndLine: 56}}}, - {ID: "cf7118a7-6976-5b1a-9a39-7adc72f591a4", Name: "UUIDs", Version: "1.8.5", Locations: []types.Location{{StartLine: 58, EndLine: 60}}}, - {ID: "4ec0a83e-493e-50e2-b9ac-8f72acf5a8f5", Name: "Unicode", Version: "1.8.5", Locations: []types.Location{{StartLine: 62, EndLine: 63}}}, + juliaV1_8Pkgs = []ftypes.Package{ + {ID: "ade2ca70-3891-5945-98fb-dc099432e06a", Name: "Dates", Version: "1.8.5", Locations: []ftypes.Location{{StartLine: 7, EndLine: 9}}}, + {ID: "682c06a0-de6a-54ab-a142-c8b1cf79cde6", Name: "JSON", Version: "0.21.4", Locations: []ftypes.Location{{StartLine: 11, EndLine: 15}}}, + {ID: "a63ad114-7e13-5084-954f-fe012c677804", Name: "Mmap", Version: "1.8.5", Locations: []ftypes.Location{{StartLine: 17, EndLine: 18}}}, + {ID: "69de0a69-1ddd-5017-9359-2bf0b02dc9f0", Name: "Parsers", Version: "2.5.10", Locations: []ftypes.Location{{StartLine: 20, EndLine: 24}}}, + {ID: "aea7be01-6a6a-4083-8856-8a6e6704d82a", Name: "PrecompileTools", Version: "1.1.1", Locations: []ftypes.Location{{StartLine: 26, EndLine: 30}}}, + {ID: "21216c6a-2e73-6563-6e65-726566657250", Name: "Preferences", Version: "1.4.0", Locations: []ftypes.Location{{StartLine: 32, EndLine: 36}}}, + {ID: "de0858da-6303-5e67-8744-51eddeeeb8d7", Name: "Printf", Version: "1.8.5", Locations: []ftypes.Location{{StartLine: 38, EndLine: 40}}}, + {ID: "9a3f8284-a2c9-5f02-9a11-845980a1fd5c", Name: "Random", Version: "1.8.5", Locations: []ftypes.Location{{StartLine: 42, EndLine: 44}}}, + {ID: "ea8e919c-243c-51af-8825-aaa63cd721ce", Name: "SHA", Version: "0.7.0", Locations: []ftypes.Location{{StartLine: 46, EndLine: 48}}}, + {ID: "9e88b42a-f829-5b0c-bbe9-9e923198166b", Name: "Serialization", Version: "1.8.5", Locations: []ftypes.Location{{StartLine: 50, EndLine: 51}}}, + {ID: "fa267f1f-6049-4f14-aa54-33bafae1ed76", Name: "TOML", Version: "1.0.0", Locations: []ftypes.Location{{StartLine: 53, EndLine: 56}}}, + {ID: "cf7118a7-6976-5b1a-9a39-7adc72f591a4", Name: "UUIDs", Version: "1.8.5", Locations: []ftypes.Location{{StartLine: 58, EndLine: 60}}}, + {ID: "4ec0a83e-493e-50e2-b9ac-8f72acf5a8f5", Name: "Unicode", Version: "1.8.5", Locations: []ftypes.Location{{StartLine: 62, EndLine: 63}}}, } - juliaV1_8Deps = []types.Dependency{ + juliaV1_8Deps = []ftypes.Dependency{ {ID: "ade2ca70-3891-5945-98fb-dc099432e06a", DependsOn: []string{"de0858da-6303-5e67-8744-51eddeeeb8d7"}}, {ID: "682c06a0-de6a-54ab-a142-c8b1cf79cde6", DependsOn: []string{ "4ec0a83e-493e-50e2-b9ac-8f72acf5a8f5", @@ -61,17 +61,17 @@ var ( {ID: "cf7118a7-6976-5b1a-9a39-7adc72f591a4", DependsOn: []string{"9a3f8284-a2c9-5f02-9a11-845980a1fd5c", "ea8e919c-243c-51af-8825-aaa63cd721ce"}}, } - juliaV1_9DepExtLibs = []types.Library{ - {ID: "621f4979-c628-5d54-868e-fcf4e3e8185c", Name: "AbstractFFTs", Version: "1.3.1", Locations: []types.Location{{StartLine: 7, EndLine: 10}}}, + juliaV1_9DepExtPkgs = []ftypes.Package{ + {ID: "621f4979-c628-5d54-868e-fcf4e3e8185c", Name: "AbstractFFTs", Version: "1.3.1", Locations: []ftypes.Location{{StartLine: 7, EndLine: 10}}}, } - juliaV1_9ShadowedDepLibs = []types.Library{ - {ID: "ead4f63c-334e-11e9-00e6-e7f0a5f21b60", Name: "A", Version: "1.9.0", Locations: []types.Location{{StartLine: 7, EndLine: 8}}}, - {ID: "f41f7b98-334e-11e9-1257-49272045fb24", Name: "B", Version: "1.9.0", Locations: []types.Location{{StartLine: 13, EndLine: 14}}}, - {ID: "edca9bc6-334e-11e9-3554-9595dbb4349c", Name: "B", Version: "1.9.0", Locations: []types.Location{{StartLine: 15, EndLine: 16}}}, + juliaV1_9ShadowedDepPkgs = []ftypes.Package{ + {ID: "ead4f63c-334e-11e9-00e6-e7f0a5f21b60", Name: "A", Version: "1.9.0", Locations: []ftypes.Location{{StartLine: 7, EndLine: 8}}}, + {ID: "f41f7b98-334e-11e9-1257-49272045fb24", Name: "B", Version: "1.9.0", Locations: []ftypes.Location{{StartLine: 13, EndLine: 14}}}, + {ID: "edca9bc6-334e-11e9-3554-9595dbb4349c", Name: "B", Version: "1.9.0", Locations: []ftypes.Location{{StartLine: 15, EndLine: 16}}}, } - juliaV1_9ShadowedDepDeps = []types.Dependency{ + juliaV1_9ShadowedDepDeps = []ftypes.Dependency{ {ID: "ead4f63c-334e-11e9-00e6-e7f0a5f21b60", DependsOn: []string{"f41f7b98-334e-11e9-1257-49272045fb24"}}, } ) diff --git a/pkg/dependency/parser/nodejs/npm/parse.go b/pkg/dependency/parser/nodejs/npm/parse.go index e98bf25bba6d..ec5d654e7469 100644 --- a/pkg/dependency/parser/nodejs/npm/parse.go +++ b/pkg/dependency/parser/nodejs/npm/parse.go @@ -15,7 +15,6 @@ import ( "github.com/aquasecurity/trivy/pkg/dependency" "github.com/aquasecurity/trivy/pkg/dependency/parser/utils" - "github.com/aquasecurity/trivy/pkg/dependency/types" ftypes "github.com/aquasecurity/trivy/pkg/fanal/types" "github.com/aquasecurity/trivy/pkg/log" xio "github.com/aquasecurity/trivy/pkg/x/io" @@ -56,13 +55,13 @@ type Parser struct { logger *log.Logger } -func NewParser() types.Parser { +func NewParser() *Parser { return &Parser{ logger: log.WithPrefix("npm"), } } -func (p *Parser) Parse(r xio.ReadSeekerAt) ([]types.Library, []types.Dependency, error) { +func (p *Parser) Parse(r xio.ReadSeekerAt) ([]ftypes.Package, []ftypes.Dependency, error) { var lockFile LockFile input, err := io.ReadAll(r) if err != nil { @@ -72,20 +71,20 @@ func (p *Parser) Parse(r xio.ReadSeekerAt) ([]types.Library, []types.Dependency, return nil, nil, xerrors.Errorf("decode error: %w", err) } - var libs []types.Library - var deps []types.Dependency + var pkgs []ftypes.Package + var deps []ftypes.Dependency if lockFile.LockfileVersion == 1 { - libs, deps = p.parseV1(lockFile.Dependencies, make(map[string]string)) + pkgs, deps = p.parseV1(lockFile.Dependencies, make(map[string]string)) } else { - libs, deps = p.parseV2(lockFile.Packages) + pkgs, deps = p.parseV2(lockFile.Packages) } - return utils.UniqueLibraries(libs), uniqueDeps(deps), nil + return utils.UniquePackages(pkgs), uniqueDeps(deps), nil } -func (p *Parser) parseV2(packages map[string]Package) ([]types.Library, []types.Dependency) { - libs := make(map[string]types.Library, len(packages)-1) - var deps []types.Dependency +func (p *Parser) parseV2(packages map[string]Package) ([]ftypes.Package, []ftypes.Dependency) { + pkgs := make(map[string]ftypes.Package, len(packages)-1) + var deps []ftypes.Dependency // Resolve links first // https://docs.npmjs.com/cli/v9/configuring-npm/package-lock-json#packages @@ -116,51 +115,51 @@ func (p *Parser) parseV2(packages map[string]Package) ([]types.Library, []types. } pkgID := packageID(pkgName, pkg.Version) - location := types.Location{ + location := ftypes.Location{ StartLine: pkg.StartLine, EndLine: pkg.EndLine, } - var ref types.ExternalRef + var ref ftypes.ExternalRef if pkg.Resolved != "" { - ref = types.ExternalRef{ - Type: types.RefOther, + ref = ftypes.ExternalRef{ + Type: ftypes.RefOther, URL: pkg.Resolved, } } - pkgIndirect := isIndirectLib(pkgPath, directDeps) + pkgIndirect := isIndirectPkg(pkgPath, directDeps) - // There are cases when similar libraries use same dependencies + // There are cases when similar packages use same dependencies // we need to add location for each these dependencies - if savedLib, ok := libs[pkgID]; ok { - savedLib.Dev = savedLib.Dev && pkg.Dev - if savedLib.Relationship == types.RelationshipIndirect && !pkgIndirect { - savedLib.Relationship = types.RelationshipDirect + if savedPkg, ok := pkgs[pkgID]; ok { + savedPkg.Dev = savedPkg.Dev && pkg.Dev + if savedPkg.Relationship == ftypes.RelationshipIndirect && !pkgIndirect { + savedPkg.Relationship = ftypes.RelationshipDirect } - if ref.URL != "" && !slices.Contains(savedLib.ExternalReferences, ref) { - savedLib.ExternalReferences = append(savedLib.ExternalReferences, ref) - sortExternalReferences(savedLib.ExternalReferences) + if ref.URL != "" && !slices.Contains(savedPkg.ExternalReferences, ref) { + savedPkg.ExternalReferences = append(savedPkg.ExternalReferences, ref) + sortExternalReferences(savedPkg.ExternalReferences) } - savedLib.Locations = append(savedLib.Locations, location) - sort.Sort(savedLib.Locations) + savedPkg.Locations = append(savedPkg.Locations, location) + sort.Sort(savedPkg.Locations) - libs[pkgID] = savedLib + pkgs[pkgID] = savedPkg continue } - lib := types.Library{ + newPkg := ftypes.Package{ ID: pkgID, Name: pkgName, Version: pkg.Version, - Relationship: lo.Ternary(pkgIndirect, types.RelationshipIndirect, types.RelationshipDirect), + Relationship: lo.Ternary(pkgIndirect, ftypes.RelationshipIndirect, ftypes.RelationshipDirect), Dev: pkg.Dev, - ExternalReferences: lo.Ternary(ref.URL != "", []types.ExternalRef{ref}, nil), - Locations: []types.Location{location}, + ExternalReferences: lo.Ternary(ref.URL != "", []ftypes.ExternalRef{ref}, nil), + Locations: []ftypes.Location{location}, } - libs[pkgID] = lib + pkgs[pkgID] = newPkg // npm builds graph using optional deps. e.g.: // └─┬ watchpack@1.7.5 @@ -179,15 +178,15 @@ func (p *Parser) parseV2(packages map[string]Package) ([]types.Library, []types. } if len(dependsOn) > 0 { - deps = append(deps, types.Dependency{ - ID: lib.ID, + deps = append(deps, ftypes.Dependency{ + ID: newPkg.ID, DependsOn: dependsOn, }) } } - return maps.Values(libs), deps + return maps.Values(pkgs), deps } // for local package npm uses links. e.g.: @@ -271,73 +270,73 @@ func findDependsOn(pkgPath, depName string, packages map[string]Package) (string return "", xerrors.Errorf("can't find dependsOn for %s", depName) } -func (p *Parser) parseV1(dependencies map[string]Dependency, versions map[string]string) ([]types.Library, []types.Dependency) { +func (p *Parser) parseV1(dependencies map[string]Dependency, versions map[string]string) ([]ftypes.Package, []ftypes.Dependency) { // Update package name and version mapping. for pkgName, dep := range dependencies { // Overwrite the existing package version so that the nested version can take precedence. versions[pkgName] = dep.Version } - var libs []types.Library - var deps []types.Dependency + var pkgs []ftypes.Package + var deps []ftypes.Dependency for pkgName, dep := range dependencies { - lib := types.Library{ + pkg := ftypes.Package{ ID: packageID(pkgName, dep.Version), Name: pkgName, Version: dep.Version, Dev: dep.Dev, - Relationship: types.RelationshipUnknown, // lockfile v1 schema doesn't have information about direct dependencies - ExternalReferences: []types.ExternalRef{ + Relationship: ftypes.RelationshipUnknown, // lockfile v1 schema doesn't have information about direct dependencies + ExternalReferences: []ftypes.ExternalRef{ { - Type: types.RefOther, + Type: ftypes.RefOther, URL: dep.Resolved, }, }, - Locations: []types.Location{ + Locations: []ftypes.Location{ { StartLine: dep.StartLine, EndLine: dep.EndLine, }, }, } - libs = append(libs, lib) + pkgs = append(pkgs, pkg) dependsOn := make([]string, 0, len(dep.Requires)) - for libName, requiredVer := range dep.Requires { + for pName, requiredVer := range dep.Requires { // Try to resolve the version with nested dependencies first - if resolvedDep, ok := dep.Dependencies[libName]; ok { - libID := packageID(libName, resolvedDep.Version) - dependsOn = append(dependsOn, libID) + if resolvedDep, ok := dep.Dependencies[pName]; ok { + pkgID := packageID(pName, resolvedDep.Version) + dependsOn = append(dependsOn, pkgID) continue } // Try to resolve the version with the higher level dependencies - if ver, ok := versions[libName]; ok { - dependsOn = append(dependsOn, packageID(libName, ver)) + if ver, ok := versions[pName]; ok { + dependsOn = append(dependsOn, packageID(pName, ver)) continue } // It should not reach here. p.logger.Warn("Unable to resolve the version", - log.String("name", libName), log.String("version", requiredVer)) + log.String("name", pName), log.String("version", requiredVer)) } if len(dependsOn) > 0 { - deps = append(deps, types.Dependency{ - ID: packageID(lib.Name, lib.Version), + deps = append(deps, ftypes.Dependency{ + ID: packageID(pkg.Name, pkg.Version), DependsOn: dependsOn, }) } if dep.Dependencies != nil { // Recursion - childLibs, childDeps := p.parseV1(dep.Dependencies, maps.Clone(versions)) - libs = append(libs, childLibs...) + childpkgs, childDeps := p.parseV1(dep.Dependencies, maps.Clone(versions)) + pkgs = append(pkgs, childpkgs...) deps = append(deps, childDeps...) } } - return libs, deps + return pkgs, deps } func (p *Parser) pkgNameFromPath(pkgPath string) string { @@ -354,8 +353,8 @@ func (p *Parser) pkgNameFromPath(pkgPath string) string { return pkgPath } -func uniqueDeps(deps []types.Dependency) []types.Dependency { - var uniqDeps []types.Dependency +func uniqueDeps(deps []ftypes.Dependency) []ftypes.Dependency { + var uniqDeps ftypes.Dependencies unique := make(map[string]struct{}) for _, dep := range deps { @@ -367,14 +366,14 @@ func uniqueDeps(deps []types.Dependency) []types.Dependency { } } - sort.Sort(types.Dependencies(uniqDeps)) + sort.Sort(uniqDeps) return uniqDeps } -func isIndirectLib(pkgPath string, directDeps map[string]struct{}) bool { +func isIndirectPkg(pkgPath string, directDeps map[string]struct{}) bool { // A project can contain 2 different versions of the same dependency. // e.g. `node_modules/string-width/node_modules/strip-ansi` and `node_modules/string-ansi` - // direct dependencies always have root path (`node_modules/`) + // direct dependencies always have root path (`node_modules/`) if _, ok := directDeps[pkgPath]; ok { return false } @@ -411,7 +410,7 @@ func packageID(name, version string) string { return dependency.ID(ftypes.Npm, name, version) } -func sortExternalReferences(refs []types.ExternalRef) { +func sortExternalReferences(refs []ftypes.ExternalRef) { sort.Slice(refs, func(i, j int) bool { if refs[i].Type != refs[j].Type { return refs[i].Type < refs[j].Type diff --git a/pkg/dependency/parser/nodejs/npm/parse_test.go b/pkg/dependency/parser/nodejs/npm/parse_test.go index 786fe643dfde..68f5d1e8491f 100644 --- a/pkg/dependency/parser/nodejs/npm/parse_test.go +++ b/pkg/dependency/parser/nodejs/npm/parse_test.go @@ -7,44 +7,44 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - "github.com/aquasecurity/trivy/pkg/dependency/types" + ftypes "github.com/aquasecurity/trivy/pkg/fanal/types" ) func TestParse(t *testing.T) { tests := []struct { name string file string // Test input file - want []types.Library - wantDeps []types.Dependency + want []ftypes.Package + wantDeps []ftypes.Dependency }{ { name: "lock version v1", file: "testdata/package-lock_v1.json", - want: npmV1Libs, + want: npmV1Pkgs, wantDeps: npmDeps, }, { name: "lock version v2", file: "testdata/package-lock_v2.json", - want: npmV2Libs, + want: npmV2Pkgs, wantDeps: npmDeps, }, { name: "lock version v3", file: "testdata/package-lock_v3.json", - want: npmV2Libs, + want: npmV2Pkgs, wantDeps: npmDeps, }, { name: "lock version v3 with workspace", file: "testdata/package-lock_v3_with_workspace.json", - want: npmV3WithWorkspaceLibs, + want: npmV3WithWorkspacePkgs, wantDeps: npmV3WithWorkspaceDeps, }, { name: "lock file v3 contains same dev and non-dev dependencies", file: "testdata/package-lock_v3_with-same-dev-and-non-dev.json", - want: npmV3WithSameDevAndNonDevLibs, + want: npmV3WithSameDevAndNonDevPkgs, wantDeps: npmV3WithSameDevAndNonDevDeps, }, { diff --git a/pkg/dependency/parser/nodejs/npm/parse_testcase.go b/pkg/dependency/parser/nodejs/npm/parse_testcase.go index d5f87cd33cc0..01dcac6711f9 100644 --- a/pkg/dependency/parser/nodejs/npm/parse_testcase.go +++ b/pkg/dependency/parser/nodejs/npm/parse_testcase.go @@ -1,6 +1,6 @@ package npm -import "github.com/aquasecurity/trivy/pkg/dependency/types" +import ftypes "github.com/aquasecurity/trivy/pkg/fanal/types" var ( // docker run --name node --rm -it node@sha256:51dd437f31812df71108b81385e2945071ec813d5815fa3403855669c8f3432b sh @@ -10,22 +10,22 @@ var ( // npm install --save-dev debug@2.5.2 // npm install --save-optional promise // npm i --lockfile-version 1 - // libraries are filled manually + // packages are filled manually - npmV1Libs = []types.Library{ + npmV1Pkgs = []ftypes.Package{ { ID: "@babel/helper-string-parser@7.19.4", Name: "@babel/helper-string-parser", Version: "7.19.4", Dev: false, - Relationship: types.RelationshipUnknown, - ExternalReferences: []types.ExternalRef{ + Relationship: ftypes.RelationshipUnknown, + ExternalReferences: []ftypes.ExternalRef{ { - Type: types.RefOther, + Type: ftypes.RefOther, URL: "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.19.4.tgz", }, }, - Locations: []types.Location{ + Locations: []ftypes.Location{ { StartLine: 7, EndLine: 11, @@ -37,14 +37,14 @@ var ( Name: "asap", Version: "2.0.6", Dev: false, - Relationship: types.RelationshipUnknown, - ExternalReferences: []types.ExternalRef{ + Relationship: ftypes.RelationshipUnknown, + ExternalReferences: []ftypes.ExternalRef{ { - Type: types.RefOther, + Type: ftypes.RefOther, URL: "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz", }, }, - Locations: []types.Location{ + Locations: []ftypes.Location{ { StartLine: 12, EndLine: 17, @@ -56,14 +56,14 @@ var ( Name: "body-parser", Version: "1.18.3", Dev: false, - Relationship: types.RelationshipUnknown, - ExternalReferences: []types.ExternalRef{ + Relationship: ftypes.RelationshipUnknown, + ExternalReferences: []ftypes.ExternalRef{ { - Type: types.RefOther, + Type: ftypes.RefOther, URL: "https://registry.npmjs.org/body-parser/-/body-parser-1.18.3.tgz", }, }, - Locations: []types.Location{ + Locations: []ftypes.Location{ { StartLine: 18, EndLine: 49, @@ -75,14 +75,14 @@ var ( Name: "bytes", Version: "3.0.0", Dev: false, - Relationship: types.RelationshipUnknown, - ExternalReferences: []types.ExternalRef{ + Relationship: ftypes.RelationshipUnknown, + ExternalReferences: []ftypes.ExternalRef{ { - Type: types.RefOther, + Type: ftypes.RefOther, URL: "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz", }, }, - Locations: []types.Location{ + Locations: []ftypes.Location{ { StartLine: 50, EndLine: 54, @@ -94,14 +94,14 @@ var ( Name: "content-type", Version: "1.0.5", Dev: false, - Relationship: types.RelationshipUnknown, - ExternalReferences: []types.ExternalRef{ + Relationship: ftypes.RelationshipUnknown, + ExternalReferences: []ftypes.ExternalRef{ { - Type: types.RefOther, + Type: ftypes.RefOther, URL: "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", }, }, - Locations: []types.Location{ + Locations: []ftypes.Location{ { StartLine: 55, EndLine: 59, @@ -113,14 +113,14 @@ var ( Name: "debug", Version: "2.5.2", Dev: true, - Relationship: types.RelationshipUnknown, - ExternalReferences: []types.ExternalRef{ + Relationship: ftypes.RelationshipUnknown, + ExternalReferences: []ftypes.ExternalRef{ { - Type: types.RefOther, + Type: ftypes.RefOther, URL: "https://registry.npmjs.org/debug/-/debug-2.5.2.tgz", }, }, - Locations: []types.Location{ + Locations: []ftypes.Location{ { StartLine: 60, EndLine: 76, @@ -132,14 +132,14 @@ var ( Name: "debug", Version: "2.6.9", Dev: false, - Relationship: types.RelationshipUnknown, - ExternalReferences: []types.ExternalRef{ + Relationship: ftypes.RelationshipUnknown, + ExternalReferences: []ftypes.ExternalRef{ { - Type: types.RefOther, + Type: ftypes.RefOther, URL: "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", }, }, - Locations: []types.Location{ + Locations: []ftypes.Location{ { StartLine: 35, EndLine: 42, @@ -155,14 +155,14 @@ var ( Name: "depd", Version: "1.1.2", Dev: false, - Relationship: types.RelationshipUnknown, - ExternalReferences: []types.ExternalRef{ + Relationship: ftypes.RelationshipUnknown, + ExternalReferences: []ftypes.ExternalRef{ { - Type: types.RefOther, + Type: ftypes.RefOther, URL: "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", }, }, - Locations: []types.Location{ + Locations: []ftypes.Location{ { StartLine: 77, EndLine: 81, @@ -174,14 +174,14 @@ var ( Name: "ee-first", Version: "1.1.1", Dev: false, - Relationship: types.RelationshipUnknown, - ExternalReferences: []types.ExternalRef{ + Relationship: ftypes.RelationshipUnknown, + ExternalReferences: []ftypes.ExternalRef{ { - Type: types.RefOther, + Type: ftypes.RefOther, URL: "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", }, }, - Locations: []types.Location{ + Locations: []ftypes.Location{ { StartLine: 82, EndLine: 86, @@ -193,14 +193,14 @@ var ( Name: "encodeurl", Version: "1.0.2", Dev: false, - Relationship: types.RelationshipUnknown, - ExternalReferences: []types.ExternalRef{ + Relationship: ftypes.RelationshipUnknown, + ExternalReferences: []ftypes.ExternalRef{ { - Type: types.RefOther, + Type: ftypes.RefOther, URL: "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", }, }, - Locations: []types.Location{ + Locations: []ftypes.Location{ { StartLine: 87, EndLine: 91, @@ -212,14 +212,14 @@ var ( Name: "escape-html", Version: "1.0.3", Dev: false, - Relationship: types.RelationshipUnknown, - ExternalReferences: []types.ExternalRef{ + Relationship: ftypes.RelationshipUnknown, + ExternalReferences: []ftypes.ExternalRef{ { - Type: types.RefOther, + Type: ftypes.RefOther, URL: "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", }, }, - Locations: []types.Location{ + Locations: []ftypes.Location{ { StartLine: 92, EndLine: 96, @@ -231,14 +231,14 @@ var ( Name: "finalhandler", Version: "1.1.1", Dev: false, - Relationship: types.RelationshipUnknown, - ExternalReferences: []types.ExternalRef{ + Relationship: ftypes.RelationshipUnknown, + ExternalReferences: []ftypes.ExternalRef{ { - Type: types.RefOther, + Type: ftypes.RefOther, URL: "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.1.tgz", }, }, - Locations: []types.Location{ + Locations: []ftypes.Location{ { StartLine: 97, EndLine: 125, @@ -250,14 +250,14 @@ var ( Name: "http-errors", Version: "1.6.3", Dev: false, - Relationship: types.RelationshipUnknown, - ExternalReferences: []types.ExternalRef{ + Relationship: ftypes.RelationshipUnknown, + ExternalReferences: []ftypes.ExternalRef{ { - Type: types.RefOther, + Type: ftypes.RefOther, URL: "https://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz", }, }, - Locations: []types.Location{ + Locations: []ftypes.Location{ { StartLine: 126, EndLine: 136, @@ -269,14 +269,14 @@ var ( Name: "iconv-lite", Version: "0.4.23", Dev: false, - Relationship: types.RelationshipUnknown, - ExternalReferences: []types.ExternalRef{ + Relationship: ftypes.RelationshipUnknown, + ExternalReferences: []ftypes.ExternalRef{ { - Type: types.RefOther, + Type: ftypes.RefOther, URL: "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.23.tgz", }, }, - Locations: []types.Location{ + Locations: []ftypes.Location{ { StartLine: 137, EndLine: 144, @@ -288,14 +288,14 @@ var ( Name: "inherits", Version: "2.0.3", Dev: false, - Relationship: types.RelationshipUnknown, - ExternalReferences: []types.ExternalRef{ + Relationship: ftypes.RelationshipUnknown, + ExternalReferences: []ftypes.ExternalRef{ { - Type: types.RefOther, + Type: ftypes.RefOther, URL: "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", }, }, - Locations: []types.Location{ + Locations: []ftypes.Location{ { StartLine: 145, EndLine: 149, @@ -307,14 +307,14 @@ var ( Name: "media-typer", Version: "0.3.0", Dev: false, - Relationship: types.RelationshipUnknown, - ExternalReferences: []types.ExternalRef{ + Relationship: ftypes.RelationshipUnknown, + ExternalReferences: []ftypes.ExternalRef{ { - Type: types.RefOther, + Type: ftypes.RefOther, URL: "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", }, }, - Locations: []types.Location{ + Locations: []ftypes.Location{ { StartLine: 150, EndLine: 154, @@ -326,14 +326,14 @@ var ( Name: "mime-db", Version: "1.52.0", Dev: false, - Relationship: types.RelationshipUnknown, - ExternalReferences: []types.ExternalRef{ + Relationship: ftypes.RelationshipUnknown, + ExternalReferences: []ftypes.ExternalRef{ { - Type: types.RefOther, + Type: ftypes.RefOther, URL: "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", }, }, - Locations: []types.Location{ + Locations: []ftypes.Location{ { StartLine: 155, EndLine: 159, @@ -345,14 +345,14 @@ var ( Name: "mime-types", Version: "2.1.35", Dev: false, - Relationship: types.RelationshipUnknown, - ExternalReferences: []types.ExternalRef{ + Relationship: ftypes.RelationshipUnknown, + ExternalReferences: []ftypes.ExternalRef{ { - Type: types.RefOther, + Type: ftypes.RefOther, URL: "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", }, }, - Locations: []types.Location{ + Locations: []ftypes.Location{ { StartLine: 160, EndLine: 167, @@ -364,14 +364,14 @@ var ( Name: "ms", Version: "0.7.2", Dev: true, - Relationship: types.RelationshipUnknown, - ExternalReferences: []types.ExternalRef{ + Relationship: ftypes.RelationshipUnknown, + ExternalReferences: []ftypes.ExternalRef{ { - Type: types.RefOther, + Type: ftypes.RefOther, URL: "https://registry.npmjs.org/ms/-/ms-0.7.2.tgz", }, }, - Locations: []types.Location{ + Locations: []ftypes.Location{ { StartLine: 69, EndLine: 74, @@ -383,14 +383,14 @@ var ( Name: "ms", Version: "1.0.0", Dev: false, - Relationship: types.RelationshipUnknown, - ExternalReferences: []types.ExternalRef{ + Relationship: ftypes.RelationshipUnknown, + ExternalReferences: []ftypes.ExternalRef{ { - Type: types.RefOther, + Type: ftypes.RefOther, URL: "https://registry.npmjs.org/ms/-/ms-1.0.0.tgz", }, }, - Locations: []types.Location{ + Locations: []ftypes.Location{ { StartLine: 168, EndLine: 172, @@ -402,14 +402,14 @@ var ( Name: "ms", Version: "2.0.0", Dev: false, - Relationship: types.RelationshipUnknown, - ExternalReferences: []types.ExternalRef{ + Relationship: ftypes.RelationshipUnknown, + ExternalReferences: []ftypes.ExternalRef{ { - Type: types.RefOther, + Type: ftypes.RefOther, URL: "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", }, }, - Locations: []types.Location{ + Locations: []ftypes.Location{ { StartLine: 43, EndLine: 47, @@ -425,14 +425,14 @@ var ( Name: "on-finished", Version: "2.3.0", Dev: false, - Relationship: types.RelationshipUnknown, - ExternalReferences: []types.ExternalRef{ + Relationship: ftypes.RelationshipUnknown, + ExternalReferences: []ftypes.ExternalRef{ { - Type: types.RefOther, + Type: ftypes.RefOther, URL: "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", }, }, - Locations: []types.Location{ + Locations: []ftypes.Location{ { StartLine: 173, EndLine: 180, @@ -444,14 +444,14 @@ var ( Name: "parseurl", Version: "1.3.3", Dev: false, - Relationship: types.RelationshipUnknown, - ExternalReferences: []types.ExternalRef{ + Relationship: ftypes.RelationshipUnknown, + ExternalReferences: []ftypes.ExternalRef{ { - Type: types.RefOther, + Type: ftypes.RefOther, URL: "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", }, }, - Locations: []types.Location{ + Locations: []ftypes.Location{ { StartLine: 181, EndLine: 185, @@ -463,14 +463,14 @@ var ( Name: "promise", Version: "8.3.0", Dev: false, - Relationship: types.RelationshipUnknown, - ExternalReferences: []types.ExternalRef{ + Relationship: ftypes.RelationshipUnknown, + ExternalReferences: []ftypes.ExternalRef{ { - Type: types.RefOther, + Type: ftypes.RefOther, URL: "https://registry.npmjs.org/promise/-/promise-8.3.0.tgz", }, }, - Locations: []types.Location{ + Locations: []ftypes.Location{ { StartLine: 186, EndLine: 194, @@ -482,14 +482,14 @@ var ( Name: "qs", Version: "6.5.2", Dev: false, - Relationship: types.RelationshipUnknown, - ExternalReferences: []types.ExternalRef{ + Relationship: ftypes.RelationshipUnknown, + ExternalReferences: []ftypes.ExternalRef{ { - Type: types.RefOther, + Type: ftypes.RefOther, URL: "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz", }, }, - Locations: []types.Location{ + Locations: []ftypes.Location{ { StartLine: 195, EndLine: 199, @@ -501,14 +501,14 @@ var ( Name: "raw-body", Version: "2.3.3", Dev: false, - Relationship: types.RelationshipUnknown, - ExternalReferences: []types.ExternalRef{ + Relationship: ftypes.RelationshipUnknown, + ExternalReferences: []ftypes.ExternalRef{ { - Type: types.RefOther, + Type: ftypes.RefOther, URL: "https://registry.npmjs.org/raw-body/-/raw-body-2.3.3.tgz", }, }, - Locations: []types.Location{ + Locations: []ftypes.Location{ { StartLine: 200, EndLine: 210, @@ -520,14 +520,14 @@ var ( Name: "safer-buffer", Version: "2.1.2", Dev: false, - Relationship: types.RelationshipUnknown, - ExternalReferences: []types.ExternalRef{ + Relationship: ftypes.RelationshipUnknown, + ExternalReferences: []ftypes.ExternalRef{ { - Type: types.RefOther, + Type: ftypes.RefOther, URL: "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", }, }, - Locations: []types.Location{ + Locations: []ftypes.Location{ { StartLine: 211, EndLine: 215, @@ -539,14 +539,14 @@ var ( Name: "setprototypeof", Version: "1.1.0", Dev: false, - Relationship: types.RelationshipUnknown, - ExternalReferences: []types.ExternalRef{ + Relationship: ftypes.RelationshipUnknown, + ExternalReferences: []ftypes.ExternalRef{ { - Type: types.RefOther, + Type: ftypes.RefOther, URL: "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz", }, }, - Locations: []types.Location{ + Locations: []ftypes.Location{ { StartLine: 216, EndLine: 220, @@ -558,14 +558,14 @@ var ( Name: "statuses", Version: "1.4.0", Dev: false, - Relationship: types.RelationshipUnknown, - ExternalReferences: []types.ExternalRef{ + Relationship: ftypes.RelationshipUnknown, + ExternalReferences: []ftypes.ExternalRef{ { - Type: types.RefOther, + Type: ftypes.RefOther, URL: "https://registry.npmjs.org/statuses/-/statuses-1.4.0.tgz", }, }, - Locations: []types.Location{ + Locations: []ftypes.Location{ { StartLine: 221, EndLine: 225, @@ -577,14 +577,14 @@ var ( Name: "type-is", Version: "1.6.18", Dev: false, - Relationship: types.RelationshipUnknown, - ExternalReferences: []types.ExternalRef{ + Relationship: ftypes.RelationshipUnknown, + ExternalReferences: []ftypes.ExternalRef{ { - Type: types.RefOther, + Type: ftypes.RefOther, URL: "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", }, }, - Locations: []types.Location{ + Locations: []ftypes.Location{ { StartLine: 226, EndLine: 234, @@ -596,14 +596,14 @@ var ( Name: "unpipe", Version: "1.0.0", Dev: false, - Relationship: types.RelationshipUnknown, - ExternalReferences: []types.ExternalRef{ + Relationship: ftypes.RelationshipUnknown, + ExternalReferences: []ftypes.ExternalRef{ { - Type: types.RefOther, + Type: ftypes.RefOther, URL: "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", }, }, - Locations: []types.Location{ + Locations: []ftypes.Location{ { StartLine: 235, EndLine: 239, @@ -613,7 +613,7 @@ var ( } // dependencies are filled manually - npmDeps = []types.Dependency{ + npmDeps = []ftypes.Dependency{ { ID: "body-parser@1.18.3", DependsOn: []string{ @@ -694,25 +694,25 @@ var ( // ... and // npm i --lockfile-version 2 - // same as npmV1Libs but change `Indirect` field to false for `body-parser@1.18.3`, `finalhandler@1.1.1`, `@babel/helper-string-parser@7.19.4`, `promise@8.3.0` and `ms@1.0.0` libraries. + // same as npmV1Pkgs but change `Indirect` field to false for `body-parser@1.18.3`, `finalhandler@1.1.1`, `@babel/helper-string-parser@7.19.4`, `promise@8.3.0` and `ms@1.0.0` packages. // also need to get locations from `packages` struct // --- lockfile version 3 --- // npm i --lockfile-version 3 - // same as npmV2Libs. - npmV2Libs = []types.Library{ + // same as npmV2Pkgs. + npmV2Pkgs = []ftypes.Package{ { ID: "@babel/helper-string-parser@7.19.4", Name: "@babel/helper-string-parser", Version: "7.19.4", Dev: false, - Relationship: types.RelationshipDirect, - ExternalReferences: []types.ExternalRef{ + Relationship: ftypes.RelationshipDirect, + ExternalReferences: []ftypes.ExternalRef{ { - Type: types.RefOther, + Type: ftypes.RefOther, URL: "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.19.4.tgz", }, }, - Locations: []types.Location{ + Locations: []ftypes.Location{ { StartLine: 24, EndLine: 31, @@ -724,14 +724,14 @@ var ( Name: "body-parser", Version: "1.18.3", Dev: false, - Relationship: types.RelationshipDirect, - ExternalReferences: []types.ExternalRef{ + Relationship: ftypes.RelationshipDirect, + ExternalReferences: []ftypes.ExternalRef{ { - Type: types.RefOther, + Type: ftypes.RefOther, URL: "https://registry.npmjs.org/body-parser/-/body-parser-1.18.3.tgz", }, }, - Locations: []types.Location{ + Locations: []ftypes.Location{ { StartLine: 38, EndLine: 57, @@ -743,14 +743,14 @@ var ( Name: "debug", Version: "2.5.2", Dev: true, - Relationship: types.RelationshipDirect, - ExternalReferences: []types.ExternalRef{ + Relationship: ftypes.RelationshipDirect, + ExternalReferences: []ftypes.ExternalRef{ { - Type: types.RefOther, + Type: ftypes.RefOther, URL: "https://registry.npmjs.org/debug/-/debug-2.5.2.tgz", }, }, - Locations: []types.Location{ + Locations: []ftypes.Location{ { StartLine: 87, EndLine: 95, @@ -762,14 +762,14 @@ var ( Name: "finalhandler", Version: "1.1.1", Dev: false, - Relationship: types.RelationshipDirect, - ExternalReferences: []types.ExternalRef{ + Relationship: ftypes.RelationshipDirect, + ExternalReferences: []ftypes.ExternalRef{ { - Type: types.RefOther, + Type: ftypes.RefOther, URL: "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.1.tgz", }, }, - Locations: []types.Location{ + Locations: []ftypes.Location{ { StartLine: 128, EndLine: 144, @@ -781,14 +781,14 @@ var ( Name: "ms", Version: "1.0.0", Dev: false, - Relationship: types.RelationshipDirect, - ExternalReferences: []types.ExternalRef{ + Relationship: ftypes.RelationshipDirect, + ExternalReferences: []ftypes.ExternalRef{ { - Type: types.RefOther, + Type: ftypes.RefOther, URL: "https://registry.npmjs.org/ms/-/ms-1.0.0.tgz", }, }, - Locations: []types.Location{ + Locations: []ftypes.Location{ { StartLine: 215, EndLine: 219, @@ -800,14 +800,14 @@ var ( Name: "promise", Version: "8.3.0", Dev: false, - Relationship: types.RelationshipDirect, - ExternalReferences: []types.ExternalRef{ + Relationship: ftypes.RelationshipDirect, + ExternalReferences: []ftypes.ExternalRef{ { - Type: types.RefOther, + Type: ftypes.RefOther, URL: "https://registry.npmjs.org/promise/-/promise-8.3.0.tgz", }, }, - Locations: []types.Location{ + Locations: []ftypes.Location{ { StartLine: 239, EndLine: 247, @@ -819,14 +819,14 @@ var ( Name: "asap", Version: "2.0.6", Dev: false, - Relationship: types.RelationshipIndirect, - ExternalReferences: []types.ExternalRef{ + Relationship: ftypes.RelationshipIndirect, + ExternalReferences: []ftypes.ExternalRef{ { - Type: types.RefOther, + Type: ftypes.RefOther, URL: "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz", }, }, - Locations: []types.Location{ + Locations: []ftypes.Location{ { StartLine: 32, EndLine: 37, @@ -838,14 +838,14 @@ var ( Name: "bytes", Version: "3.0.0", Dev: false, - Relationship: types.RelationshipIndirect, - ExternalReferences: []types.ExternalRef{ + Relationship: ftypes.RelationshipIndirect, + ExternalReferences: []ftypes.ExternalRef{ { - Type: types.RefOther, + Type: ftypes.RefOther, URL: "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz", }, }, - Locations: []types.Location{ + Locations: []ftypes.Location{ { StartLine: 71, EndLine: 78, @@ -857,14 +857,14 @@ var ( Name: "content-type", Version: "1.0.5", Dev: false, - Relationship: types.RelationshipIndirect, - ExternalReferences: []types.ExternalRef{ + Relationship: ftypes.RelationshipIndirect, + ExternalReferences: []ftypes.ExternalRef{ { - Type: types.RefOther, + Type: ftypes.RefOther, URL: "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", }, }, - Locations: []types.Location{ + Locations: []ftypes.Location{ { StartLine: 79, EndLine: 86, @@ -876,14 +876,14 @@ var ( Name: "debug", Version: "2.6.9", Dev: false, - Relationship: types.RelationshipIndirect, - ExternalReferences: []types.ExternalRef{ + Relationship: ftypes.RelationshipIndirect, + ExternalReferences: []ftypes.ExternalRef{ { - Type: types.RefOther, + Type: ftypes.RefOther, URL: "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", }, }, - Locations: []types.Location{ + Locations: []ftypes.Location{ { StartLine: 58, EndLine: 65, @@ -899,14 +899,14 @@ var ( Name: "depd", Version: "1.1.2", Dev: false, - Relationship: types.RelationshipIndirect, - ExternalReferences: []types.ExternalRef{ + Relationship: ftypes.RelationshipIndirect, + ExternalReferences: []ftypes.ExternalRef{ { - Type: types.RefOther, + Type: ftypes.RefOther, URL: "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", }, }, - Locations: []types.Location{ + Locations: []ftypes.Location{ { StartLine: 102, EndLine: 109, @@ -918,14 +918,14 @@ var ( Name: "ee-first", Version: "1.1.1", Dev: false, - Relationship: types.RelationshipIndirect, - ExternalReferences: []types.ExternalRef{ + Relationship: ftypes.RelationshipIndirect, + ExternalReferences: []ftypes.ExternalRef{ { - Type: types.RefOther, + Type: ftypes.RefOther, URL: "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", }, }, - Locations: []types.Location{ + Locations: []ftypes.Location{ { StartLine: 110, EndLine: 114, @@ -937,14 +937,14 @@ var ( Name: "encodeurl", Version: "1.0.2", Dev: false, - Relationship: types.RelationshipIndirect, - ExternalReferences: []types.ExternalRef{ + Relationship: ftypes.RelationshipIndirect, + ExternalReferences: []ftypes.ExternalRef{ { - Type: types.RefOther, + Type: ftypes.RefOther, URL: "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", }, }, - Locations: []types.Location{ + Locations: []ftypes.Location{ { StartLine: 115, EndLine: 122, @@ -956,14 +956,14 @@ var ( Name: "escape-html", Version: "1.0.3", Dev: false, - Relationship: types.RelationshipIndirect, - ExternalReferences: []types.ExternalRef{ + Relationship: ftypes.RelationshipIndirect, + ExternalReferences: []ftypes.ExternalRef{ { - Type: types.RefOther, + Type: ftypes.RefOther, URL: "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", }, }, - Locations: []types.Location{ + Locations: []ftypes.Location{ { StartLine: 123, EndLine: 127, @@ -975,14 +975,14 @@ var ( Name: "http-errors", Version: "1.6.3", Dev: false, - Relationship: types.RelationshipIndirect, - ExternalReferences: []types.ExternalRef{ + Relationship: ftypes.RelationshipIndirect, + ExternalReferences: []ftypes.ExternalRef{ { - Type: types.RefOther, + Type: ftypes.RefOther, URL: "https://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz", }, }, - Locations: []types.Location{ + Locations: []ftypes.Location{ { StartLine: 158, EndLine: 171, @@ -994,14 +994,14 @@ var ( Name: "iconv-lite", Version: "0.4.23", Dev: false, - Relationship: types.RelationshipIndirect, - ExternalReferences: []types.ExternalRef{ + Relationship: ftypes.RelationshipIndirect, + ExternalReferences: []ftypes.ExternalRef{ { - Type: types.RefOther, + Type: ftypes.RefOther, URL: "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.23.tgz", }, }, - Locations: []types.Location{ + Locations: []ftypes.Location{ { StartLine: 172, EndLine: 182, @@ -1013,14 +1013,14 @@ var ( Name: "inherits", Version: "2.0.3", Dev: false, - Relationship: types.RelationshipIndirect, - ExternalReferences: []types.ExternalRef{ + Relationship: ftypes.RelationshipIndirect, + ExternalReferences: []ftypes.ExternalRef{ { - Type: types.RefOther, + Type: ftypes.RefOther, URL: "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", }, }, - Locations: []types.Location{ + Locations: []ftypes.Location{ { StartLine: 183, EndLine: 187, @@ -1032,14 +1032,14 @@ var ( Name: "media-typer", Version: "0.3.0", Dev: false, - Relationship: types.RelationshipIndirect, - ExternalReferences: []types.ExternalRef{ + Relationship: ftypes.RelationshipIndirect, + ExternalReferences: []ftypes.ExternalRef{ { - Type: types.RefOther, + Type: ftypes.RefOther, URL: "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", }, }, - Locations: []types.Location{ + Locations: []ftypes.Location{ { StartLine: 188, EndLine: 195, @@ -1051,14 +1051,14 @@ var ( Name: "mime-db", Version: "1.52.0", Dev: false, - Relationship: types.RelationshipIndirect, - ExternalReferences: []types.ExternalRef{ + Relationship: ftypes.RelationshipIndirect, + ExternalReferences: []ftypes.ExternalRef{ { - Type: types.RefOther, + Type: ftypes.RefOther, URL: "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", }, }, - Locations: []types.Location{ + Locations: []ftypes.Location{ { StartLine: 196, EndLine: 203, @@ -1070,14 +1070,14 @@ var ( Name: "mime-types", Version: "2.1.35", Dev: false, - Relationship: types.RelationshipIndirect, - ExternalReferences: []types.ExternalRef{ + Relationship: ftypes.RelationshipIndirect, + ExternalReferences: []ftypes.ExternalRef{ { - Type: types.RefOther, + Type: ftypes.RefOther, URL: "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", }, }, - Locations: []types.Location{ + Locations: []ftypes.Location{ { StartLine: 204, EndLine: 214, @@ -1089,14 +1089,14 @@ var ( Name: "ms", Version: "0.7.2", Dev: true, - Relationship: types.RelationshipIndirect, - ExternalReferences: []types.ExternalRef{ + Relationship: ftypes.RelationshipIndirect, + ExternalReferences: []ftypes.ExternalRef{ { - Type: types.RefOther, + Type: ftypes.RefOther, URL: "https://registry.npmjs.org/ms/-/ms-0.7.2.tgz", }, }, - Locations: []types.Location{ + Locations: []ftypes.Location{ { StartLine: 96, EndLine: 101, @@ -1108,14 +1108,14 @@ var ( Name: "ms", Version: "2.0.0", Dev: false, - Relationship: types.RelationshipIndirect, - ExternalReferences: []types.ExternalRef{ + Relationship: ftypes.RelationshipIndirect, + ExternalReferences: []ftypes.ExternalRef{ { - Type: types.RefOther, + Type: ftypes.RefOther, URL: "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", }, }, - Locations: []types.Location{ + Locations: []ftypes.Location{ { StartLine: 66, EndLine: 70, @@ -1131,14 +1131,14 @@ var ( Name: "on-finished", Version: "2.3.0", Dev: false, - Relationship: types.RelationshipIndirect, - ExternalReferences: []types.ExternalRef{ + Relationship: ftypes.RelationshipIndirect, + ExternalReferences: []ftypes.ExternalRef{ { - Type: types.RefOther, + Type: ftypes.RefOther, URL: "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", }, }, - Locations: []types.Location{ + Locations: []ftypes.Location{ { StartLine: 220, EndLine: 230, @@ -1150,14 +1150,14 @@ var ( Name: "parseurl", Version: "1.3.3", Dev: false, - Relationship: types.RelationshipIndirect, - ExternalReferences: []types.ExternalRef{ + Relationship: ftypes.RelationshipIndirect, + ExternalReferences: []ftypes.ExternalRef{ { - Type: types.RefOther, + Type: ftypes.RefOther, URL: "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", }, }, - Locations: []types.Location{ + Locations: []ftypes.Location{ { StartLine: 231, EndLine: 238, @@ -1169,14 +1169,14 @@ var ( Name: "qs", Version: "6.5.2", Dev: false, - Relationship: types.RelationshipIndirect, - ExternalReferences: []types.ExternalRef{ + Relationship: ftypes.RelationshipIndirect, + ExternalReferences: []ftypes.ExternalRef{ { - Type: types.RefOther, + Type: ftypes.RefOther, URL: "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz", }, }, - Locations: []types.Location{ + Locations: []ftypes.Location{ { StartLine: 248, EndLine: 255, @@ -1188,14 +1188,14 @@ var ( Name: "raw-body", Version: "2.3.3", Dev: false, - Relationship: types.RelationshipIndirect, - ExternalReferences: []types.ExternalRef{ + Relationship: ftypes.RelationshipIndirect, + ExternalReferences: []ftypes.ExternalRef{ { - Type: types.RefOther, + Type: ftypes.RefOther, URL: "https://registry.npmjs.org/raw-body/-/raw-body-2.3.3.tgz", }, }, - Locations: []types.Location{ + Locations: []ftypes.Location{ { StartLine: 256, EndLine: 269, @@ -1207,14 +1207,14 @@ var ( Name: "safer-buffer", Version: "2.1.2", Dev: false, - Relationship: types.RelationshipIndirect, - ExternalReferences: []types.ExternalRef{ + Relationship: ftypes.RelationshipIndirect, + ExternalReferences: []ftypes.ExternalRef{ { - Type: types.RefOther, + Type: ftypes.RefOther, URL: "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", }, }, - Locations: []types.Location{ + Locations: []ftypes.Location{ { StartLine: 270, EndLine: 274, @@ -1226,14 +1226,14 @@ var ( Name: "setprototypeof", Version: "1.1.0", Dev: false, - Relationship: types.RelationshipIndirect, - ExternalReferences: []types.ExternalRef{ + Relationship: ftypes.RelationshipIndirect, + ExternalReferences: []ftypes.ExternalRef{ { - Type: types.RefOther, + Type: ftypes.RefOther, URL: "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz", }, }, - Locations: []types.Location{ + Locations: []ftypes.Location{ { StartLine: 275, EndLine: 279, @@ -1245,14 +1245,14 @@ var ( Name: "statuses", Version: "1.4.0", Dev: false, - Relationship: types.RelationshipIndirect, - ExternalReferences: []types.ExternalRef{ + Relationship: ftypes.RelationshipIndirect, + ExternalReferences: []ftypes.ExternalRef{ { - Type: types.RefOther, + Type: ftypes.RefOther, URL: "https://registry.npmjs.org/statuses/-/statuses-1.4.0.tgz", }, }, - Locations: []types.Location{ + Locations: []ftypes.Location{ { StartLine: 280, EndLine: 287, @@ -1264,14 +1264,14 @@ var ( Name: "type-is", Version: "1.6.18", Dev: false, - Relationship: types.RelationshipIndirect, - ExternalReferences: []types.ExternalRef{ + Relationship: ftypes.RelationshipIndirect, + ExternalReferences: []ftypes.ExternalRef{ { - Type: types.RefOther, + Type: ftypes.RefOther, URL: "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", }, }, - Locations: []types.Location{ + Locations: []ftypes.Location{ { StartLine: 288, EndLine: 299, @@ -1283,14 +1283,14 @@ var ( Name: "unpipe", Version: "1.0.0", Dev: false, - Relationship: types.RelationshipIndirect, - ExternalReferences: []types.ExternalRef{ + Relationship: ftypes.RelationshipIndirect, + ExternalReferences: []ftypes.ExternalRef{ { - Type: types.RefOther, + Type: ftypes.RefOther, URL: "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", }, }, - Locations: []types.Location{ + Locations: []ftypes.Location{ { StartLine: 300, EndLine: 307, @@ -1312,20 +1312,20 @@ var ( // grep -v "functions/func1" ./package.json > tmpfile && mv tmpfile ./package.json // sed -i 's/functions\/nested_func/functions\/*/g' package.json // npm update - // libraries are filled manually - npmV3WithWorkspaceLibs = []types.Library{ + // packages are filled manually + npmV3WithWorkspacePkgs = []ftypes.Package{ { ID: "debug@2.5.2", Name: "debug", Version: "2.5.2", - Relationship: types.RelationshipDirect, - ExternalReferences: []types.ExternalRef{ + Relationship: ftypes.RelationshipDirect, + ExternalReferences: []ftypes.ExternalRef{ { - Type: types.RefOther, + Type: ftypes.RefOther, URL: "https://registry.npmjs.org/debug/-/debug-2.5.2.tgz", }, }, - Locations: []types.Location{ + Locations: []ftypes.Location{ { StartLine: 39, EndLine: 46, @@ -1336,14 +1336,14 @@ var ( ID: "function1", Name: "function1", Version: "", - Relationship: types.RelationshipDirect, - ExternalReferences: []types.ExternalRef{ + Relationship: ftypes.RelationshipDirect, + ExternalReferences: []ftypes.ExternalRef{ { - Type: types.RefOther, + Type: ftypes.RefOther, URL: "functions/func1", }, }, - Locations: []types.Location{ + Locations: []ftypes.Location{ { StartLine: 18, EndLine: 23, @@ -1354,14 +1354,14 @@ var ( ID: "nested_func@1.0.0", Name: "nested_func", Version: "1.0.0", - Relationship: types.RelationshipDirect, - ExternalReferences: []types.ExternalRef{ + Relationship: ftypes.RelationshipDirect, + ExternalReferences: []ftypes.ExternalRef{ { - Type: types.RefOther, + Type: ftypes.RefOther, URL: "functions/nested_func", }, }, - Locations: []types.Location{ + Locations: []ftypes.Location{ { StartLine: 24, EndLine: 30, @@ -1372,14 +1372,14 @@ var ( ID: "debug@2.6.9", Name: "debug", Version: "2.6.9", - Relationship: types.RelationshipIndirect, - ExternalReferences: []types.ExternalRef{ + Relationship: ftypes.RelationshipIndirect, + ExternalReferences: []ftypes.ExternalRef{ { - Type: types.RefOther, + Type: ftypes.RefOther, URL: "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", }, }, - Locations: []types.Location{ + Locations: []ftypes.Location{ { StartLine: 31, EndLine: 38, @@ -1390,14 +1390,14 @@ var ( ID: "ms@0.7.2", Name: "ms", Version: "0.7.2", - Relationship: types.RelationshipIndirect, - ExternalReferences: []types.ExternalRef{ + Relationship: ftypes.RelationshipIndirect, + ExternalReferences: []ftypes.ExternalRef{ { - Type: types.RefOther, + Type: ftypes.RefOther, URL: "https://registry.npmjs.org/ms/-/ms-0.7.2.tgz", }, }, - Locations: []types.Location{ + Locations: []ftypes.Location{ { StartLine: 47, EndLine: 51, @@ -1408,14 +1408,14 @@ var ( ID: "ms@2.0.0", Name: "ms", Version: "2.0.0", - Relationship: types.RelationshipIndirect, - ExternalReferences: []types.ExternalRef{ + Relationship: ftypes.RelationshipIndirect, + ExternalReferences: []ftypes.ExternalRef{ { - Type: types.RefOther, + Type: ftypes.RefOther, URL: "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", }, }, - Locations: []types.Location{ + Locations: []ftypes.Location{ { StartLine: 56, EndLine: 60, @@ -1424,7 +1424,7 @@ var ( }, } - npmV3WithWorkspaceDeps = []types.Dependency{ + npmV3WithWorkspaceDeps = []ftypes.Dependency{ { ID: "debug@2.5.2", DependsOn: []string{"ms@0.7.2"}, @@ -1448,20 +1448,20 @@ var ( // npm init --force // npm init -w ./functions/func1 --force // npm install --save debug@2.6.9 -w func1 - // libraries are filled manually - npmV3WithoutRootDepsField = []types.Library{ + // packages are filled manually + npmV3WithoutRootDepsField = []ftypes.Package{ { ID: "func1@1.0.0", Name: "func1", Version: "1.0.0", - Relationship: types.RelationshipDirect, - ExternalReferences: []types.ExternalRef{ + Relationship: ftypes.RelationshipDirect, + ExternalReferences: []ftypes.ExternalRef{ { - Type: types.RefOther, + Type: ftypes.RefOther, URL: "functions/func1", }, }, - Locations: []types.Location{ + Locations: []ftypes.Location{ { StartLine: 15, EndLine: 21, @@ -1472,14 +1472,14 @@ var ( ID: "debug@2.6.9", Name: "debug", Version: "2.6.9", - Relationship: types.RelationshipIndirect, - ExternalReferences: []types.ExternalRef{ + Relationship: ftypes.RelationshipIndirect, + ExternalReferences: []ftypes.ExternalRef{ { - Type: types.RefOther, + Type: ftypes.RefOther, URL: "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", }, }, - Locations: []types.Location{ + Locations: []ftypes.Location{ { StartLine: 22, EndLine: 29, @@ -1490,14 +1490,14 @@ var ( ID: "ms@2.0.0", Name: "ms", Version: "2.0.0", - Relationship: types.RelationshipIndirect, - ExternalReferences: []types.ExternalRef{ + Relationship: ftypes.RelationshipIndirect, + ExternalReferences: []ftypes.ExternalRef{ { - Type: types.RefOther, + Type: ftypes.RefOther, URL: "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", }, }, - Locations: []types.Location{ + Locations: []ftypes.Location{ { StartLine: 34, EndLine: 38, @@ -1506,7 +1506,7 @@ var ( }, } - npmV3WithoutRootDepsFieldDeps = []types.Dependency{ + npmV3WithoutRootDepsFieldDeps = []ftypes.Dependency{ { ID: "debug@2.6.9", DependsOn: []string{"ms@2.0.0"}, @@ -1517,20 +1517,20 @@ var ( }, } - npmV3WithSameDevAndNonDevLibs = []types.Library{ + npmV3WithSameDevAndNonDevPkgs = []ftypes.Package{ { ID: "fsevents@1.2.9", Name: "fsevents", Version: "1.2.9", - Relationship: types.RelationshipDirect, + Relationship: ftypes.RelationshipDirect, Dev: true, - ExternalReferences: []types.ExternalRef{ + ExternalReferences: []ftypes.ExternalRef{ { - Type: types.RefOther, + Type: ftypes.RefOther, URL: "https://registry.npmjs.org/fsevents/-/fsevents-1.2.9.tgz", }, }, - Locations: []types.Location{ + Locations: []ftypes.Location{ { StartLine: 18, EndLine: 37, @@ -1541,15 +1541,15 @@ var ( ID: "minimist@0.0.8", Name: "minimist", Version: "0.0.8", - Relationship: types.RelationshipDirect, + Relationship: ftypes.RelationshipDirect, Dev: false, - ExternalReferences: []types.ExternalRef{ + ExternalReferences: []ftypes.ExternalRef{ { - Type: types.RefOther, + Type: ftypes.RefOther, URL: "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", }, }, - Locations: []types.Location{ + Locations: []ftypes.Location{ { StartLine: 38, EndLine: 43, @@ -1564,9 +1564,9 @@ var ( ID: "mkdirp@0.5.1", Name: "mkdirp", Version: "0.5.1", - Relationship: types.RelationshipIndirect, + Relationship: ftypes.RelationshipIndirect, Dev: true, - Locations: []types.Location{ + Locations: []ftypes.Location{ { StartLine: 44, EndLine: 55, @@ -1577,9 +1577,9 @@ var ( ID: "node-pre-gyp@0.12.0", Name: "node-pre-gyp", Version: "0.12.0", - Relationship: types.RelationshipIndirect, + Relationship: ftypes.RelationshipIndirect, Dev: true, - Locations: []types.Location{ + Locations: []ftypes.Location{ { StartLine: 56, EndLine: 67, @@ -1588,7 +1588,7 @@ var ( }, } - npmV3WithSameDevAndNonDevDeps = []types.Dependency{ + npmV3WithSameDevAndNonDevDeps = []ftypes.Dependency{ { ID: "fsevents@1.2.9", DependsOn: []string{"node-pre-gyp@0.12.0"}, diff --git a/pkg/dependency/parser/nodejs/packagejson/parse.go b/pkg/dependency/parser/nodejs/packagejson/parse.go index 19a53679f2d0..80d11e2193bf 100644 --- a/pkg/dependency/parser/nodejs/packagejson/parse.go +++ b/pkg/dependency/parser/nodejs/packagejson/parse.go @@ -9,7 +9,6 @@ import ( "golang.org/x/xerrors" "github.com/aquasecurity/trivy/pkg/dependency" - "github.com/aquasecurity/trivy/pkg/dependency/types" ftypes "github.com/aquasecurity/trivy/pkg/fanal/types" ) @@ -26,7 +25,7 @@ type packageJSON struct { } type Package struct { - types.Library + ftypes.Package Dependencies map[string]string OptionalDependencies map[string]string DevDependencies map[string]string @@ -57,11 +56,11 @@ func (p *Parser) Parse(r io.Reader) (Package, error) { } return Package{ - Library: types.Library{ - ID: id, - Name: pkgJSON.Name, - Version: pkgJSON.Version, - License: parseLicense(pkgJSON.License), + Package: ftypes.Package{ + ID: id, + Name: pkgJSON.Name, + Version: pkgJSON.Version, + Licenses: parseLicense(pkgJSON.License), }, Dependencies: pkgJSON.Dependencies, OptionalDependencies: pkgJSON.OptionalDependencies, @@ -70,17 +69,21 @@ func (p *Parser) Parse(r io.Reader) (Package, error) { }, nil } -func parseLicense(val interface{}) string { +func parseLicense(val interface{}) []string { // the license isn't always a string, check for legacy struct if not string switch v := val.(type) { case string: - return v + if v != "" { + return []string{v} + } case map[string]interface{}: if license, ok := v["type"]; ok { - return license.(string) + if s, ok := license.(string); ok && s != "" { + return []string{s} + } } } - return "" + return nil } // parseWorkspaces returns slice of workspaces diff --git a/pkg/dependency/parser/nodejs/packagejson/parse_test.go b/pkg/dependency/parser/nodejs/packagejson/parse_test.go index 97a0027d22ef..1896186129ae 100644 --- a/pkg/dependency/parser/nodejs/packagejson/parse_test.go +++ b/pkg/dependency/parser/nodejs/packagejson/parse_test.go @@ -8,7 +8,7 @@ import ( "github.com/stretchr/testify/require" "github.com/aquasecurity/trivy/pkg/dependency/parser/nodejs/packagejson" - "github.com/aquasecurity/trivy/pkg/dependency/types" + ftypes "github.com/aquasecurity/trivy/pkg/fanal/types" ) func TestParse(t *testing.T) { @@ -27,11 +27,11 @@ func TestParse(t *testing.T) { // npm install --save promise jquery // npm ls | grep -E -o "\S+@\S+" | awk -F@ 'NR>0 {printf("{\""$1"\", \""$2"\"},\n")}' want: packagejson.Package{ - Library: types.Library{ - ID: "bootstrap@5.0.2", - Name: "bootstrap", - Version: "5.0.2", - License: "MIT", + Package: ftypes.Package{ + ID: "bootstrap@5.0.2", + Name: "bootstrap", + Version: "5.0.2", + Licenses: []string{"MIT"}, }, Dependencies: map[string]string{ "js-tokens": "^4.0.0", @@ -53,11 +53,11 @@ func TestParse(t *testing.T) { name: "happy path - legacy license", inputFile: "testdata/legacy_package.json", want: packagejson.Package{ - Library: types.Library{ - ID: "angular@4.1.2", - Name: "angular", - Version: "4.1.2", - License: "ISC", + Package: ftypes.Package{ + ID: "angular@4.1.2", + Name: "angular", + Version: "4.1.2", + Licenses: []string{"ISC"}, }, Dependencies: map[string]string{}, DevDependencies: map[string]string{ @@ -70,7 +70,7 @@ func TestParse(t *testing.T) { name: "happy path - version doesn't exist", inputFile: "testdata/without_version_package.json", want: packagejson.Package{ - Library: types.Library{ + Package: ftypes.Package{ ID: "", Name: "angular", }, @@ -80,7 +80,7 @@ func TestParse(t *testing.T) { name: "happy path - workspace as struct", inputFile: "testdata/workspace_as_map_package.json", want: packagejson.Package{ - Library: types.Library{ + Package: ftypes.Package{ ID: "example@1.0.0", Name: "example", Version: "1.0.0", @@ -109,8 +109,8 @@ func TestParse(t *testing.T) { name: "without name and version", inputFile: "testdata/without_name_and_version_package.json", want: packagejson.Package{ - Library: types.Library{ - License: "MIT", + Package: ftypes.Package{ + Licenses: []string{"MIT"}, }, }, }, @@ -162,7 +162,8 @@ func TestIsValidName(t *testing.T) { { name: "test@package", want: false, - }, { + }, + { name: "test?package", want: false, }, diff --git a/pkg/dependency/parser/nodejs/pnpm/parse.go b/pkg/dependency/parser/nodejs/pnpm/parse.go index b11646851462..92fdc6131744 100644 --- a/pkg/dependency/parser/nodejs/pnpm/parse.go +++ b/pkg/dependency/parser/nodejs/pnpm/parse.go @@ -11,7 +11,6 @@ import ( "github.com/aquasecurity/go-version/pkg/semver" "github.com/aquasecurity/trivy/pkg/dependency" - "github.com/aquasecurity/trivy/pkg/dependency/types" ftypes "github.com/aquasecurity/trivy/pkg/fanal/types" "github.com/aquasecurity/trivy/pkg/log" xio "github.com/aquasecurity/trivy/pkg/x/io" @@ -47,7 +46,7 @@ func NewParser() *Parser { } } -func (p *Parser) Parse(r xio.ReadSeekerAt) ([]types.Library, []types.Dependency, error) { +func (p *Parser) Parse(r xio.ReadSeekerAt) ([]ftypes.Package, []ftypes.Dependency, error) { var lockFile LockFile if err := yaml.NewDecoder(r).Decode(&lockFile); err != nil { return nil, nil, xerrors.Errorf("decode error: %w", err) @@ -58,14 +57,14 @@ func (p *Parser) Parse(r xio.ReadSeekerAt) ([]types.Library, []types.Dependency, return nil, nil, nil } - libs, deps := p.parse(lockVer, lockFile) + pkgs, deps := p.parse(lockVer, lockFile) - return libs, deps, nil + return pkgs, deps, nil } -func (p *Parser) parse(lockVer float64, lockFile LockFile) ([]types.Library, []types.Dependency) { - var libs []types.Library - var deps []types.Dependency +func (p *Parser) parse(lockVer float64, lockFile LockFile) ([]ftypes.Package, []ftypes.Dependency) { + var pkgs []ftypes.Package + var deps []ftypes.Dependency // Dependency path is a path to a dependency with a specific set of resolved subdependencies. // cf. https://github.com/pnpm/spec/blob/ad27a225f81d9215becadfa540ef05fa4ad6dd60/dependency-path.md @@ -90,22 +89,22 @@ func (p *Parser) parse(lockVer float64, lockFile LockFile) ([]types.Library, []t dependencies = append(dependencies, packageID(depName, depVer)) } - libs = append(libs, types.Library{ + pkgs = append(pkgs, ftypes.Package{ ID: pkgID, Name: name, Version: version, - Relationship: lo.Ternary(isDirectLib(name, lockFile.Dependencies), types.RelationshipDirect, types.RelationshipIndirect), + Relationship: lo.Ternary(isDirectPkg(name, lockFile.Dependencies), ftypes.RelationshipDirect, ftypes.RelationshipIndirect), }) if len(dependencies) > 0 { - deps = append(deps, types.Dependency{ + deps = append(deps, ftypes.Dependency{ ID: pkgID, DependsOn: dependencies, }) } } - return libs, deps + return pkgs, deps } func (p *Parser) parseLockfileVersion(lockFile LockFile) float64 { @@ -179,7 +178,7 @@ func (p *Parser) parseDepPath(depPath, versionSep string) (string, string) { return name, version } -func isDirectLib(name string, directDeps map[string]interface{}) bool { +func isDirectPkg(name string, directDeps map[string]interface{}) bool { _, ok := directDeps[name] return ok } diff --git a/pkg/dependency/parser/nodejs/pnpm/parse_test.go b/pkg/dependency/parser/nodejs/pnpm/parse_test.go index 606bc37de54d..b5d8816516fe 100644 --- a/pkg/dependency/parser/nodejs/pnpm/parse_test.go +++ b/pkg/dependency/parser/nodejs/pnpm/parse_test.go @@ -3,21 +3,20 @@ package pnpm import ( "os" "sort" - "strings" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - "github.com/aquasecurity/trivy/pkg/dependency/types" + ftypes "github.com/aquasecurity/trivy/pkg/fanal/types" ) func TestParse(t *testing.T) { tests := []struct { name string file string // Test input file - want []types.Library - wantDeps []types.Dependency + want []ftypes.Package + wantDeps []ftypes.Dependency }{ { name: "normal", @@ -65,39 +64,25 @@ func TestParse(t *testing.T) { got, deps, err := NewParser().Parse(f) require.NoError(t, err) - sortLibs(got) - sortLibs(tt.want) - + sort.Sort(ftypes.Packages(got)) + sort.Sort(ftypes.Packages(tt.want)) assert.Equal(t, tt.want, got) + if tt.wantDeps != nil { - sortDeps(deps) - sortDeps(tt.wantDeps) + sort.Sort(ftypes.Dependencies(deps)) + sort.Sort(ftypes.Dependencies(tt.wantDeps)) + for _, dep := range deps { + sort.Strings(dep.DependsOn) + } + for _, dep := range tt.wantDeps { + sort.Strings(dep.DependsOn) + } assert.Equal(t, tt.wantDeps, deps) } }) } } -func sortDeps(deps []types.Dependency) { - sort.Slice(deps, func(i, j int) bool { - return strings.Compare(deps[i].ID, deps[j].ID) < 0 - }) - - for i := range deps { - sort.Strings(deps[i].DependsOn) - } -} - -func sortLibs(libs []types.Library) { - sort.Slice(libs, func(i, j int) bool { - ret := strings.Compare(libs[i].Name, libs[j].Name) - if ret == 0 { - return libs[i].Version < libs[j].Version - } - return ret < 0 - }) -} - func Test_parsePackage(t *testing.T) { tests := []struct { name string diff --git a/pkg/dependency/parser/nodejs/pnpm/parse_testcase.go b/pkg/dependency/parser/nodejs/pnpm/parse_testcase.go index d41ac4c0cee7..45eb7a7202e7 100644 --- a/pkg/dependency/parser/nodejs/pnpm/parse_testcase.go +++ b/pkg/dependency/parser/nodejs/pnpm/parse_testcase.go @@ -1,33 +1,33 @@ package pnpm -import "github.com/aquasecurity/trivy/pkg/dependency/types" +import ftypes "github.com/aquasecurity/trivy/pkg/fanal/types" var ( // docker run --name node --rm -it node:16-alpine sh // npm install -g pnpm // pnpm add promise jquery - // pnpm list --prod --depth 10 | grep -E -o "\S+\s+[0-9]+(\.[0-9]+)+$" | awk '{printf("{ID: \""$1"@"$2"\", Name: \""$1"\", Version: \""$2"\", Relationship: types.RelationshipIndirect},\n")}' | sort -u - pnpmNormal = []types.Library{ + // pnpm list --prod --depth 10 | grep -E -o "\S+\s+[0-9]+(\.[0-9]+)+$" | awk '{printf("{ID: \""$1"@"$2"\", Name: \""$1"\", Version: \""$2"\", Relationship: ftypes.RelationshipIndirect},\n")}' | sort -u + pnpmNormal = []ftypes.Package{ { ID: "asap@2.0.6", Name: "asap", Version: "2.0.6", - Relationship: types.RelationshipIndirect, + Relationship: ftypes.RelationshipIndirect, }, { ID: "jquery@3.6.0", Name: "jquery", Version: "3.6.0", - Relationship: types.RelationshipDirect, + Relationship: ftypes.RelationshipDirect, }, { ID: "promise@8.1.0", Name: "promise", Version: "8.1.0", - Relationship: types.RelationshipDirect, + Relationship: ftypes.RelationshipDirect, }, } - pnpmNormalDeps = []types.Dependency{ + pnpmNormalDeps = []ftypes.Dependency{ { ID: "promise@8.1.0", DependsOn: []string{"asap@2.0.6"}, @@ -38,46 +38,46 @@ var ( // npm install -g pnpm // pnpm add react redux // pnpm add -D mocha - // pnpm list --prod --depth 10 | grep -E -o "\S+\s+[0-9]+(\.[0-9]+)+$" | awk '{printf("{ID: \""$1"@"$2"\", Name: \""$1"\", Version: \""$2"\", Relationship: types.RelationshipIndirect},\n")}' | sort -u - pnpmWithDev = []types.Library{ + // pnpm list --prod --depth 10 | grep -E -o "\S+\s+[0-9]+(\.[0-9]+)+$" | awk '{printf("{ID: \""$1"@"$2"\", Name: \""$1"\", Version: \""$2"\", Relationship: ftypes.RelationshipIndirect},\n")}' | sort -u + pnpmWithDev = []ftypes.Package{ { ID: "@babel/runtime@7.18.3", Name: "@babel/runtime", Version: "7.18.3", - Relationship: types.RelationshipIndirect, + Relationship: ftypes.RelationshipIndirect, }, { ID: "js-tokens@4.0.0", Name: "js-tokens", Version: "4.0.0", - Relationship: types.RelationshipIndirect, + Relationship: ftypes.RelationshipIndirect, }, { ID: "loose-envify@1.4.0", Name: "loose-envify", Version: "1.4.0", - Relationship: types.RelationshipIndirect, + Relationship: ftypes.RelationshipIndirect, }, { ID: "react@18.1.0", Name: "react", Version: "18.1.0", - Relationship: types.RelationshipDirect, + Relationship: ftypes.RelationshipDirect, }, { ID: "redux@4.2.0", Name: "redux", Version: "4.2.0", - Relationship: types.RelationshipDirect, + Relationship: ftypes.RelationshipDirect, }, { ID: "regenerator-runtime@0.13.9", Name: "regenerator-runtime", Version: "0.13.9", - Relationship: types.RelationshipIndirect, + Relationship: ftypes.RelationshipIndirect, }, } - pnpmWithDevDeps = []types.Dependency{ + pnpmWithDevDeps = []ftypes.Dependency{ { ID: "@babel/runtime@7.18.3", DependsOn: []string{"regenerator-runtime@0.13.9"}, @@ -100,346 +100,346 @@ var ( // npm install -g pnpm // pnpm add react redux lodash request chalk commander // pnpm add -D mocha - // pnpm list --prod --depth 10 | grep -E -o "\S+\s+[0-9]+(\.[0-9]+)+$" | awk '{printf("{ID: \""$1"@"$2"\", Name: \""$1"\", Version: \""$2"\", Relationship: types.RelationshipIndirect},\n")}' | sort -u - pnpmMany = []types.Library{ + // pnpm list --prod --depth 10 | grep -E -o "\S+\s+[0-9]+(\.[0-9]+)+$" | awk '{printf("{ID: \""$1"@"$2"\", Name: \""$1"\", Version: \""$2"\", Relationship: ftypes.RelationshipIndirect},\n")}' | sort -u + pnpmMany = []ftypes.Package{ { ID: "@babel/runtime@7.18.3", Name: "@babel/runtime", Version: "7.18.3", - Relationship: types.RelationshipIndirect, + Relationship: ftypes.RelationshipIndirect, }, { ID: "ajv@6.12.6", Name: "ajv", Version: "6.12.6", - Relationship: types.RelationshipIndirect, + Relationship: ftypes.RelationshipIndirect, }, { ID: "asn1@0.2.6", Name: "asn1", Version: "0.2.6", - Relationship: types.RelationshipIndirect, + Relationship: ftypes.RelationshipIndirect, }, { ID: "assert-plus@1.0.0", Name: "assert-plus", Version: "1.0.0", - Relationship: types.RelationshipIndirect, + Relationship: ftypes.RelationshipIndirect, }, { ID: "asynckit@0.4.0", Name: "asynckit", Version: "0.4.0", - Relationship: types.RelationshipIndirect, + Relationship: ftypes.RelationshipIndirect, }, { ID: "aws-sign2@0.7.0", Name: "aws-sign2", Version: "0.7.0", - Relationship: types.RelationshipIndirect, + Relationship: ftypes.RelationshipIndirect, }, { ID: "aws4@1.11.0", Name: "aws4", Version: "1.11.0", - Relationship: types.RelationshipIndirect, + Relationship: ftypes.RelationshipIndirect, }, { ID: "bcrypt-pbkdf@1.0.2", Name: "bcrypt-pbkdf", Version: "1.0.2", - Relationship: types.RelationshipIndirect, + Relationship: ftypes.RelationshipIndirect, }, { ID: "caseless@0.12.0", Name: "caseless", Version: "0.12.0", - Relationship: types.RelationshipIndirect, + Relationship: ftypes.RelationshipIndirect, }, { ID: "chalk@5.0.1", Name: "chalk", Version: "5.0.1", - Relationship: types.RelationshipDirect, + Relationship: ftypes.RelationshipDirect, }, { ID: "combined-stream@1.0.8", Name: "combined-stream", Version: "1.0.8", - Relationship: types.RelationshipIndirect, + Relationship: ftypes.RelationshipIndirect, }, { ID: "commander@9.3.0", Name: "commander", Version: "9.3.0", - Relationship: types.RelationshipDirect, + Relationship: ftypes.RelationshipDirect, }, { ID: "core-util-is@1.0.2", Name: "core-util-is", Version: "1.0.2", - Relationship: types.RelationshipIndirect, + Relationship: ftypes.RelationshipIndirect, }, { ID: "dashdash@1.14.1", Name: "dashdash", Version: "1.14.1", - Relationship: types.RelationshipIndirect, + Relationship: ftypes.RelationshipIndirect, }, { ID: "delayed-stream@1.0.0", Name: "delayed-stream", Version: "1.0.0", - Relationship: types.RelationshipIndirect, + Relationship: ftypes.RelationshipIndirect, }, { ID: "ecc-jsbn@0.1.2", Name: "ecc-jsbn", Version: "0.1.2", - Relationship: types.RelationshipIndirect, + Relationship: ftypes.RelationshipIndirect, }, { ID: "extend@3.0.2", Name: "extend", Version: "3.0.2", - Relationship: types.RelationshipIndirect, + Relationship: ftypes.RelationshipIndirect, }, { ID: "extsprintf@1.3.0", Name: "extsprintf", Version: "1.3.0", - Relationship: types.RelationshipIndirect, + Relationship: ftypes.RelationshipIndirect, }, { ID: "fast-deep-equal@3.1.3", Name: "fast-deep-equal", Version: "3.1.3", - Relationship: types.RelationshipIndirect, + Relationship: ftypes.RelationshipIndirect, }, { ID: "fast-json-stable-stringify@2.1.0", Name: "fast-json-stable-stringify", Version: "2.1.0", - Relationship: types.RelationshipIndirect, + Relationship: ftypes.RelationshipIndirect, }, { ID: "forever-agent@0.6.1", Name: "forever-agent", Version: "0.6.1", - Relationship: types.RelationshipIndirect, + Relationship: ftypes.RelationshipIndirect, }, { ID: "form-data@2.3.3", Name: "form-data", Version: "2.3.3", - Relationship: types.RelationshipIndirect, + Relationship: ftypes.RelationshipIndirect, }, { ID: "getpass@0.1.7", Name: "getpass", Version: "0.1.7", - Relationship: types.RelationshipIndirect, + Relationship: ftypes.RelationshipIndirect, }, { ID: "har-schema@2.0.0", Name: "har-schema", Version: "2.0.0", - Relationship: types.RelationshipIndirect, + Relationship: ftypes.RelationshipIndirect, }, { ID: "har-validator@5.1.5", Name: "har-validator", Version: "5.1.5", - Relationship: types.RelationshipIndirect, + Relationship: ftypes.RelationshipIndirect, }, { ID: "http-signature@1.2.0", Name: "http-signature", Version: "1.2.0", - Relationship: types.RelationshipIndirect, + Relationship: ftypes.RelationshipIndirect, }, { ID: "is-typedarray@1.0.0", Name: "is-typedarray", Version: "1.0.0", - Relationship: types.RelationshipIndirect, + Relationship: ftypes.RelationshipIndirect, }, { ID: "isstream@0.1.2", Name: "isstream", Version: "0.1.2", - Relationship: types.RelationshipIndirect, + Relationship: ftypes.RelationshipIndirect, }, { ID: "js-tokens@4.0.0", Name: "js-tokens", Version: "4.0.0", - Relationship: types.RelationshipIndirect, + Relationship: ftypes.RelationshipIndirect, }, { ID: "jsbn@0.1.1", Name: "jsbn", Version: "0.1.1", - Relationship: types.RelationshipIndirect, + Relationship: ftypes.RelationshipIndirect, }, { ID: "json-schema-traverse@0.4.1", Name: "json-schema-traverse", Version: "0.4.1", - Relationship: types.RelationshipIndirect, + Relationship: ftypes.RelationshipIndirect, }, { ID: "json-schema@0.4.0", Name: "json-schema", Version: "0.4.0", - Relationship: types.RelationshipIndirect, + Relationship: ftypes.RelationshipIndirect, }, { ID: "json-stringify-safe@5.0.1", Name: "json-stringify-safe", Version: "5.0.1", - Relationship: types.RelationshipIndirect, + Relationship: ftypes.RelationshipIndirect, }, { ID: "jsprim@1.4.2", Name: "jsprim", Version: "1.4.2", - Relationship: types.RelationshipIndirect, + Relationship: ftypes.RelationshipIndirect, }, { ID: "lodash@4.17.21", Name: "lodash", Version: "4.17.21", - Relationship: types.RelationshipDirect, + Relationship: ftypes.RelationshipDirect, }, { ID: "loose-envify@1.4.0", Name: "loose-envify", Version: "1.4.0", - Relationship: types.RelationshipIndirect, + Relationship: ftypes.RelationshipIndirect, }, { ID: "mime-db@1.52.0", Name: "mime-db", Version: "1.52.0", - Relationship: types.RelationshipIndirect, + Relationship: ftypes.RelationshipIndirect, }, { ID: "mime-types@2.1.35", Name: "mime-types", Version: "2.1.35", - Relationship: types.RelationshipIndirect, + Relationship: ftypes.RelationshipIndirect, }, { ID: "oauth-sign@0.9.0", Name: "oauth-sign", Version: "0.9.0", - Relationship: types.RelationshipIndirect, + Relationship: ftypes.RelationshipIndirect, }, { ID: "performance-now@2.1.0", Name: "performance-now", Version: "2.1.0", - Relationship: types.RelationshipIndirect, + Relationship: ftypes.RelationshipIndirect, }, { ID: "psl@1.8.0", Name: "psl", Version: "1.8.0", - Relationship: types.RelationshipIndirect, + Relationship: ftypes.RelationshipIndirect, }, { ID: "punycode@2.1.1", Name: "punycode", Version: "2.1.1", - Relationship: types.RelationshipIndirect, + Relationship: ftypes.RelationshipIndirect, }, { ID: "qs@6.5.3", Name: "qs", Version: "6.5.3", - Relationship: types.RelationshipIndirect, + Relationship: ftypes.RelationshipIndirect, }, { ID: "react@18.1.0", Name: "react", Version: "18.1.0", - Relationship: types.RelationshipDirect, + Relationship: ftypes.RelationshipDirect, }, { ID: "redux@4.2.0", Name: "redux", Version: "4.2.0", - Relationship: types.RelationshipDirect, + Relationship: ftypes.RelationshipDirect, }, { ID: "regenerator-runtime@0.13.9", Name: "regenerator-runtime", Version: "0.13.9", - Relationship: types.RelationshipIndirect, + Relationship: ftypes.RelationshipIndirect, }, { ID: "request@2.88.2", Name: "request", Version: "2.88.2", - Relationship: types.RelationshipDirect, + Relationship: ftypes.RelationshipDirect, }, { ID: "safe-buffer@5.2.1", Name: "safe-buffer", Version: "5.2.1", - Relationship: types.RelationshipIndirect, + Relationship: ftypes.RelationshipIndirect, }, { ID: "safer-buffer@2.1.2", Name: "safer-buffer", Version: "2.1.2", - Relationship: types.RelationshipIndirect, + Relationship: ftypes.RelationshipIndirect, }, { ID: "sshpk@1.17.0", Name: "sshpk", Version: "1.17.0", - Relationship: types.RelationshipIndirect, + Relationship: ftypes.RelationshipIndirect, }, { ID: "tough-cookie@2.5.0", Name: "tough-cookie", Version: "2.5.0", - Relationship: types.RelationshipIndirect, + Relationship: ftypes.RelationshipIndirect, }, { ID: "tunnel-agent@0.6.0", Name: "tunnel-agent", Version: "0.6.0", - Relationship: types.RelationshipIndirect, + Relationship: ftypes.RelationshipIndirect, }, { ID: "tweetnacl@0.14.5", Name: "tweetnacl", Version: "0.14.5", - Relationship: types.RelationshipIndirect, + Relationship: ftypes.RelationshipIndirect, }, { ID: "uri-js@4.4.1", Name: "uri-js", Version: "4.4.1", - Relationship: types.RelationshipIndirect, + Relationship: ftypes.RelationshipIndirect, }, { ID: "uuid@3.4.0", Name: "uuid", Version: "3.4.0", - Relationship: types.RelationshipIndirect, + Relationship: ftypes.RelationshipIndirect, }, { ID: "verror@1.10.0", Name: "verror", Version: "1.10.0", - Relationship: types.RelationshipIndirect, + Relationship: ftypes.RelationshipIndirect, }, } - pnpmManyDeps = []types.Dependency{ + pnpmManyDeps = []ftypes.Dependency{ { ID: "@babel/runtime@7.18.3", DependsOn: []string{"regenerator-runtime@0.13.9"}, @@ -610,48 +610,48 @@ var ( // pnpm update // pnpm add https://github.com/debug-js/debug/tarball/4.3.4 // pnpm add https://codeload.github.com/zkochan/is-negative/tar.gz/2fa0531ab04e300a24ef4fd7fb3a280eccb7ccc5 - // pnpm list --prod --depth 10 | grep -E -o "\S+\s+[0-9]+(\.[0-9]+)+$" | awk '{printf("{ID: \""$1"@"$2"\", Name: \""$1"\", Version: \""$2"\", Relationship: types.RelationshipDirect},\n")}' | sort -u + // pnpm list --prod --depth 10 | grep -E -o "\S+\s+[0-9]+(\.[0-9]+)+$" | awk '{printf("{ID: \""$1"@"$2"\", Name: \""$1"\", Version: \""$2"\", Relationship: ftypes.RelationshipDirect},\n")}' | sort -u // manually update `Indirect` fields - pnpmArchives = []types.Library{ + pnpmArchives = []ftypes.Package{ { ID: "asynckit@0.4.0", Name: "asynckit", Version: "0.4.0", - Relationship: types.RelationshipIndirect, + Relationship: ftypes.RelationshipIndirect, }, { ID: "debug@4.3.4", Name: "debug", Version: "4.3.4", - Relationship: types.RelationshipDirect, + Relationship: ftypes.RelationshipDirect, }, { ID: "is-negative@2.0.1", Name: "is-negative", Version: "2.0.1", - Relationship: types.RelationshipDirect, + Relationship: ftypes.RelationshipDirect, }, { ID: "lodash@4.17.21", Name: "lodash", Version: "4.17.21", - Relationship: types.RelationshipDirect, + Relationship: ftypes.RelationshipDirect, }, { ID: "ms@2.1.2", Name: "ms", Version: "2.1.2", - Relationship: types.RelationshipIndirect, + Relationship: ftypes.RelationshipIndirect, }, { ID: "package1@1.0.0", Name: "package1", Version: "1.0.0", - Relationship: types.RelationshipDirect, + Relationship: ftypes.RelationshipDirect, }, } - pnpmArchivesDeps = []types.Dependency{ + pnpmArchivesDeps = []ftypes.Dependency{ { ID: "debug@4.3.4", DependsOn: []string{"ms@2.1.2"}, @@ -665,7 +665,7 @@ var ( // docker run --name node --rm -it node@sha256:710a2c192ca426e03e4f3ec1869e5c29db855eb6969b74e6c50fd270ffccd3f1 sh // npm install -g pnpm@8.5.1 // pnpm add promise@8.1.0 jquery@3.6.0 - // pnpm list --prod --depth 10 | grep -E -o "\S+\s+[0-9]+(\.[0-9]+)+$" | awk '{printf("{ID: \""$1"@"$2"\", Name: \""$1"\", Version: \""$2"\", Relationship: types.RelationshipIndirect},\n")}' | sort -u + // pnpm list --prod --depth 10 | grep -E -o "\S+\s+[0-9]+(\.[0-9]+)+$" | awk '{printf("{ID: \""$1"@"$2"\", Name: \""$1"\", Version: \""$2"\", Relationship: ftypes.RelationshipIndirect},\n")}' | sort -u pnpmV6 = pnpmNormal pnpmV6Deps = pnpmNormalDeps @@ -673,46 +673,46 @@ var ( // npm install -g pnpm@8.5.1 // pnpm add react@18.1.0 redux@4.2.0 // pnpm add -D mocha@10.0.0 - // pnpm list --prod --depth 10 | grep -E -o "\S+\s+[0-9]+(\.[0-9]+)+$" | awk '{printf("{ID: \""$1"@"$2"\", Name: \""$1"\", Version: \""$2"\", Relationship: types.RelationshipIndirect},\n")}' | sort -u - pnpmV6WithDev = []types.Library{ + // pnpm list --prod --depth 10 | grep -E -o "\S+\s+[0-9]+(\.[0-9]+)+$" | awk '{printf("{ID: \""$1"@"$2"\", Name: \""$1"\", Version: \""$2"\", Relationship: ftypes.RelationshipIndirect},\n")}' | sort -u + pnpmV6WithDev = []ftypes.Package{ { ID: "@babel/runtime@7.22.3", Name: "@babel/runtime", Version: "7.22.3", - Relationship: types.RelationshipIndirect, + Relationship: ftypes.RelationshipIndirect, }, { ID: "js-tokens@4.0.0", Name: "js-tokens", Version: "4.0.0", - Relationship: types.RelationshipIndirect, + Relationship: ftypes.RelationshipIndirect, }, { ID: "loose-envify@1.4.0", Name: "loose-envify", Version: "1.4.0", - Relationship: types.RelationshipIndirect, + Relationship: ftypes.RelationshipIndirect, }, { ID: "react@18.1.0", Name: "react", Version: "18.1.0", - Relationship: types.RelationshipDirect, + Relationship: ftypes.RelationshipDirect, }, { ID: "redux@4.2.0", Name: "redux", Version: "4.2.0", - Relationship: types.RelationshipDirect, + Relationship: ftypes.RelationshipDirect, }, { ID: "regenerator-runtime@0.13.11", Name: "regenerator-runtime", Version: "0.13.11", - Relationship: types.RelationshipIndirect, + Relationship: ftypes.RelationshipIndirect, }, } - pnpmV6WithDevDeps = []types.Dependency{ + pnpmV6WithDevDeps = []ftypes.Dependency{ { ID: "@babel/runtime@7.22.3", DependsOn: []string{"regenerator-runtime@0.13.11"}, diff --git a/pkg/dependency/parser/nodejs/yarn/parse.go b/pkg/dependency/parser/nodejs/yarn/parse.go index d1d195d59641..813554730bea 100644 --- a/pkg/dependency/parser/nodejs/yarn/parse.go +++ b/pkg/dependency/parser/nodejs/yarn/parse.go @@ -11,7 +11,6 @@ import ( "golang.org/x/xerrors" "github.com/aquasecurity/trivy/pkg/dependency" - "github.com/aquasecurity/trivy/pkg/dependency/types" ftypes "github.com/aquasecurity/trivy/pkg/fanal/types" "github.com/aquasecurity/trivy/pkg/log" xio "github.com/aquasecurity/trivy/pkg/x/io" @@ -31,7 +30,7 @@ type Library struct { Patterns []string Name string Version string - Location types.Location + Location ftypes.Location } type Dependency struct { Pattern string @@ -128,14 +127,14 @@ func ignoreProtocol(protocol string) bool { return false } -func parseResults(patternIDs map[string]string, dependsOn map[string][]string) (deps []types.Dependency) { +func parseResults(patternIDs map[string]string, dependsOn map[string][]string) (deps []ftypes.Dependency) { // find dependencies by patterns - for libID, depPatterns := range dependsOn { + for pkgID, depPatterns := range dependsOn { depIDs := lo.Map(depPatterns, func(pattern string, index int) string { return patternIDs[pattern] }) - deps = append(deps, types.Dependency{ - ID: libID, + deps = append(deps, ftypes.Dependency{ + ID: pkgID, DependsOn: depIDs, }) } @@ -146,7 +145,7 @@ type Parser struct { logger *log.Logger } -func NewParser() types.Parser { +func NewParser() *Parser { return &Parser{ logger: log.WithPrefix("yarn"), } @@ -236,7 +235,7 @@ func (p *Parser) parseBlock(block []byte, lineNum int) (lib Library, deps []stri return Library{}, nil, scanner.LineNum(lineNum), nil } - lib.Location = types.Location{ + lib.Location = ftypes.Location{ StartLine: lineNum + emptyLines, EndLine: scanner.LineNum(lineNum), } @@ -270,9 +269,9 @@ func parseDependency(line string) (string, error) { } } -func (p *Parser) Parse(r xio.ReadSeekerAt) ([]types.Library, []types.Dependency, error) { +func (p *Parser) Parse(r xio.ReadSeekerAt) ([]ftypes.Package, []ftypes.Dependency, error) { lineNumber := 1 - var libs []types.Library + var pkgs []ftypes.Package // patternIDs holds mapping between patterns and library IDs // e.g. ajv@^6.5.5 => ajv@6.10.0 @@ -291,21 +290,21 @@ func (p *Parser) Parse(r xio.ReadSeekerAt) ([]types.Library, []types.Dependency, continue } - libID := packageID(lib.Name, lib.Version) - libs = append(libs, types.Library{ - ID: libID, + pkgID := packageID(lib.Name, lib.Version) + pkgs = append(pkgs, ftypes.Package{ + ID: pkgID, Name: lib.Name, Version: lib.Version, - Locations: []types.Location{lib.Location}, + Locations: []ftypes.Location{lib.Location}, }) for _, pattern := range lib.Patterns { // e.g. // combined-stream@^1.0.6 => combined-stream@1.0.8 // combined-stream@~1.0.6 => combined-stream@1.0.8 - patternIDs[pattern] = libID + patternIDs[pattern] = pkgID if len(deps) > 0 { - dependsOn[libID] = deps + dependsOn[pkgID] = deps } } } @@ -317,7 +316,7 @@ func (p *Parser) Parse(r xio.ReadSeekerAt) ([]types.Library, []types.Dependency, // Replace dependency patterns with library IDs // e.g. ajv@^6.5.5 => ajv@6.10.0 deps := parseResults(patternIDs, dependsOn) - return libs, deps, nil + return pkgs, deps, nil } func packageID(name, version string) string { diff --git a/pkg/dependency/parser/nodejs/yarn/parse_test.go b/pkg/dependency/parser/nodejs/yarn/parse_test.go index 90ce497ed9d8..275514351954 100644 --- a/pkg/dependency/parser/nodejs/yarn/parse_test.go +++ b/pkg/dependency/parser/nodejs/yarn/parse_test.go @@ -3,13 +3,12 @@ package yarn import ( "os" "sort" - "strings" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - "github.com/aquasecurity/trivy/pkg/dependency/types" + ftypes "github.com/aquasecurity/trivy/pkg/fanal/types" ) func TestParsePattern(t *testing.T) { @@ -255,8 +254,8 @@ func TestParse(t *testing.T) { tests := []struct { name string file string // Test input file - want []types.Library - wantDeps []types.Dependency + want []ftypes.Package + wantDeps []ftypes.Dependency }{ { name: "happy", @@ -305,10 +304,10 @@ func TestParse(t *testing.T) { got, deps, err := NewParser().Parse(f) require.NoError(t, err) - sortLibs(got) - sortLibs(tt.want) - + sortPkgs(got) + sortPkgs(tt.want) assert.Equal(t, tt.want, got) + if tt.wantDeps != nil { sortDeps(deps) sortDeps(tt.wantDeps) @@ -318,31 +317,16 @@ func TestParse(t *testing.T) { } } -func sortDeps(deps []types.Dependency) { - sort.Slice(deps, func(i, j int) bool { - return strings.Compare(deps[i].ID, deps[j].ID) < 0 - }) - - for i := range deps { - sort.Strings(deps[i].DependsOn) +func sortPkgs(pkgs ftypes.Packages) { + sort.Sort(pkgs) + for _, pkg := range pkgs { + sort.Sort(pkg.Locations) } } -func sortLibs(libs []types.Library) { - sort.Slice(libs, func(i, j int) bool { - ret := strings.Compare(libs[i].Name, libs[j].Name) - if ret == 0 { - return libs[i].Version < libs[j].Version - } - return ret < 0 - }) - for _, lib := range libs { - sortLocations(lib.Locations) +func sortDeps(deps ftypes.Dependencies) { + sort.Sort(deps) + for _, dep := range deps { + sort.Strings(dep.DependsOn) } } - -func sortLocations(locs []types.Location) { - sort.Slice(locs, func(i, j int) bool { - return locs[i].StartLine < locs[j].StartLine - }) -} diff --git a/pkg/dependency/parser/nodejs/yarn/parse_testcase.go b/pkg/dependency/parser/nodejs/yarn/parse_testcase.go index e9d48c246f29..8d829fb195cd 100644 --- a/pkg/dependency/parser/nodejs/yarn/parse_testcase.go +++ b/pkg/dependency/parser/nodejs/yarn/parse_testcase.go @@ -1,30 +1,30 @@ package yarn -import "github.com/aquasecurity/trivy/pkg/dependency/types" +import ftypes "github.com/aquasecurity/trivy/pkg/fanal/types" var ( - yarnHappy = []types.Library{ - {ID: "@babel/helper-regex@7.4.4", Name: "@babel/helper-regex", Version: "7.4.4", Locations: []types.Location{{StartLine: 4, EndLine: 9}}}, - {ID: "ansi-regex@2.1.1", Name: "ansi-regex", Version: "2.1.1", Locations: []types.Location{{StartLine: 11, EndLine: 14}}}, - {ID: "ansi-regex@3.0.0", Name: "ansi-regex", Version: "3.0.0", Locations: []types.Location{{StartLine: 16, EndLine: 19}}}, - {ID: "asap@2.0.6", Name: "asap", Version: "2.0.6", Locations: []types.Location{{StartLine: 21, EndLine: 24}}}, - {ID: "inherits@2.0.3", Name: "inherits", Version: "2.0.3", Locations: []types.Location{{StartLine: 26, EndLine: 29}}}, - {ID: "is-fullwidth-code-point@2.0.0", Name: "is-fullwidth-code-point", Version: "2.0.0", Locations: []types.Location{{StartLine: 31, EndLine: 34}}}, - {ID: "jquery@3.4.1", Name: "jquery", Version: "3.4.1", Locations: []types.Location{{StartLine: 41, EndLine: 44}}}, - {ID: "js-tokens@4.0.0", Name: "js-tokens", Version: "4.0.0", Locations: []types.Location{{StartLine: 36, EndLine: 39}}}, - {ID: "lodash@4.17.11", Name: "lodash", Version: "4.17.11", Locations: []types.Location{{StartLine: 46, EndLine: 49}}}, - {ID: "promise@8.0.3", Name: "promise", Version: "8.0.3", Locations: []types.Location{{StartLine: 51, EndLine: 56}}}, - {ID: "safe-buffer@5.1.2", Name: "safe-buffer", Version: "5.1.2", Locations: []types.Location{{StartLine: 58, EndLine: 61}}}, - {ID: "safer-buffer@2.1.2", Name: "safer-buffer", Version: "2.1.2", Locations: []types.Location{{StartLine: 63, EndLine: 66}}}, - {ID: "statuses@1.5.0", Name: "statuses", Version: "1.5.0", Locations: []types.Location{{StartLine: 68, EndLine: 71}}}, - {ID: "string-width@2.1.1", Name: "string-width", Version: "2.1.1", Locations: []types.Location{{StartLine: 73, EndLine: 79}}}, - {ID: "strip-ansi@3.0.1", Name: "strip-ansi", Version: "3.0.1", Locations: []types.Location{{StartLine: 82, EndLine: 87}}}, - {ID: "strip-ansi@4.0.0", Name: "strip-ansi", Version: "4.0.0", Locations: []types.Location{{StartLine: 89, EndLine: 94}}}, - {ID: "whatwg-fetch@3.0.0", Name: "whatwg-fetch", Version: "3.0.0", Locations: []types.Location{{StartLine: 96, EndLine: 99}}}, - {ID: "wide-align@1.1.3", Name: "wide-align", Version: "1.1.3", Locations: []types.Location{{StartLine: 101, EndLine: 106}}}, + yarnHappy = []ftypes.Package{ + {ID: "@babel/helper-regex@7.4.4", Name: "@babel/helper-regex", Version: "7.4.4", Locations: []ftypes.Location{{StartLine: 4, EndLine: 9}}}, + {ID: "ansi-regex@2.1.1", Name: "ansi-regex", Version: "2.1.1", Locations: []ftypes.Location{{StartLine: 11, EndLine: 14}}}, + {ID: "ansi-regex@3.0.0", Name: "ansi-regex", Version: "3.0.0", Locations: []ftypes.Location{{StartLine: 16, EndLine: 19}}}, + {ID: "asap@2.0.6", Name: "asap", Version: "2.0.6", Locations: []ftypes.Location{{StartLine: 21, EndLine: 24}}}, + {ID: "inherits@2.0.3", Name: "inherits", Version: "2.0.3", Locations: []ftypes.Location{{StartLine: 26, EndLine: 29}}}, + {ID: "is-fullwidth-code-point@2.0.0", Name: "is-fullwidth-code-point", Version: "2.0.0", Locations: []ftypes.Location{{StartLine: 31, EndLine: 34}}}, + {ID: "jquery@3.4.1", Name: "jquery", Version: "3.4.1", Locations: []ftypes.Location{{StartLine: 41, EndLine: 44}}}, + {ID: "js-tokens@4.0.0", Name: "js-tokens", Version: "4.0.0", Locations: []ftypes.Location{{StartLine: 36, EndLine: 39}}}, + {ID: "lodash@4.17.11", Name: "lodash", Version: "4.17.11", Locations: []ftypes.Location{{StartLine: 46, EndLine: 49}}}, + {ID: "promise@8.0.3", Name: "promise", Version: "8.0.3", Locations: []ftypes.Location{{StartLine: 51, EndLine: 56}}}, + {ID: "safe-buffer@5.1.2", Name: "safe-buffer", Version: "5.1.2", Locations: []ftypes.Location{{StartLine: 58, EndLine: 61}}}, + {ID: "safer-buffer@2.1.2", Name: "safer-buffer", Version: "2.1.2", Locations: []ftypes.Location{{StartLine: 63, EndLine: 66}}}, + {ID: "statuses@1.5.0", Name: "statuses", Version: "1.5.0", Locations: []ftypes.Location{{StartLine: 68, EndLine: 71}}}, + {ID: "string-width@2.1.1", Name: "string-width", Version: "2.1.1", Locations: []ftypes.Location{{StartLine: 73, EndLine: 79}}}, + {ID: "strip-ansi@3.0.1", Name: "strip-ansi", Version: "3.0.1", Locations: []ftypes.Location{{StartLine: 82, EndLine: 87}}}, + {ID: "strip-ansi@4.0.0", Name: "strip-ansi", Version: "4.0.0", Locations: []ftypes.Location{{StartLine: 89, EndLine: 94}}}, + {ID: "whatwg-fetch@3.0.0", Name: "whatwg-fetch", Version: "3.0.0", Locations: []ftypes.Location{{StartLine: 96, EndLine: 99}}}, + {ID: "wide-align@1.1.3", Name: "wide-align", Version: "1.1.3", Locations: []ftypes.Location{{StartLine: 101, EndLine: 106}}}, } - yarnHappyDeps = []types.Dependency{ + yarnHappyDeps = []ftypes.Dependency{ { ID: "@babel/helper-regex@7.4.4", DependsOn: []string{ @@ -64,26 +64,26 @@ var ( }, } - yarnV2Happy = []types.Library{ - {ID: "@types/color-name@1.1.1", Name: "@types/color-name", Version: "1.1.1", Locations: []types.Location{{StartLine: 8, EndLine: 13}}}, - {ID: "abbrev@1.1.1", Name: "abbrev", Version: "1.1.1", Locations: []types.Location{{StartLine: 15, EndLine: 20}}}, - {ID: "ansi-styles@3.2.1", Name: "ansi-styles", Version: "3.2.1", Locations: []types.Location{{StartLine: 22, EndLine: 29}}}, - {ID: "ansi-styles@4.2.1", Name: "ansi-styles", Version: "4.2.1", Locations: []types.Location{{StartLine: 31, EndLine: 39}}}, - {ID: "assert-plus@1.0.0", Name: "assert-plus", Version: "1.0.0", Locations: []types.Location{{StartLine: 41, EndLine: 46}}}, - {ID: "async@3.2.0", Name: "async", Version: "3.2.0", Locations: []types.Location{{StartLine: 48, EndLine: 53}}}, - {ID: "color-convert@1.9.3", Name: "color-convert", Version: "1.9.3", Locations: []types.Location{{StartLine: 63, EndLine: 70}}}, - {ID: "color-convert@2.0.1", Name: "color-convert", Version: "2.0.1", Locations: []types.Location{{StartLine: 72, EndLine: 79}}}, - {ID: "color-name@1.1.3", Name: "color-name", Version: "1.1.3", Locations: []types.Location{{StartLine: 81, EndLine: 86}}}, - {ID: "color-name@1.1.4", Name: "color-name", Version: "1.1.4", Locations: []types.Location{{StartLine: 88, EndLine: 93}}}, - {ID: "ipaddr.js@1.9.1", Name: "ipaddr.js", Version: "1.9.1", Locations: []types.Location{{StartLine: 104, EndLine: 109}}}, - {ID: "js-tokens@4.0.0", Name: "js-tokens", Version: "4.0.0", Locations: []types.Location{{StartLine: 111, EndLine: 116}}}, - {ID: "loose-envify@1.4.0", Name: "loose-envify", Version: "1.4.0", Locations: []types.Location{{StartLine: 118, EndLine: 127}}}, - {ID: "node-gyp@7.1.0", Name: "node-gyp", Version: "7.1.0", Locations: []types.Location{{StartLine: 129, EndLine: 136}}}, - {ID: "once@1.4.0", Name: "once", Version: "1.4.0", Locations: []types.Location{{StartLine: 138, EndLine: 145}}}, - {ID: "wrappy@1.0.2", Name: "wrappy", Version: "1.0.2", Locations: []types.Location{{StartLine: 147, EndLine: 152}}}, + yarnV2Happy = []ftypes.Package{ + {ID: "@types/color-name@1.1.1", Name: "@types/color-name", Version: "1.1.1", Locations: []ftypes.Location{{StartLine: 8, EndLine: 13}}}, + {ID: "abbrev@1.1.1", Name: "abbrev", Version: "1.1.1", Locations: []ftypes.Location{{StartLine: 15, EndLine: 20}}}, + {ID: "ansi-styles@3.2.1", Name: "ansi-styles", Version: "3.2.1", Locations: []ftypes.Location{{StartLine: 22, EndLine: 29}}}, + {ID: "ansi-styles@4.2.1", Name: "ansi-styles", Version: "4.2.1", Locations: []ftypes.Location{{StartLine: 31, EndLine: 39}}}, + {ID: "assert-plus@1.0.0", Name: "assert-plus", Version: "1.0.0", Locations: []ftypes.Location{{StartLine: 41, EndLine: 46}}}, + {ID: "async@3.2.0", Name: "async", Version: "3.2.0", Locations: []ftypes.Location{{StartLine: 48, EndLine: 53}}}, + {ID: "color-convert@1.9.3", Name: "color-convert", Version: "1.9.3", Locations: []ftypes.Location{{StartLine: 63, EndLine: 70}}}, + {ID: "color-convert@2.0.1", Name: "color-convert", Version: "2.0.1", Locations: []ftypes.Location{{StartLine: 72, EndLine: 79}}}, + {ID: "color-name@1.1.3", Name: "color-name", Version: "1.1.3", Locations: []ftypes.Location{{StartLine: 81, EndLine: 86}}}, + {ID: "color-name@1.1.4", Name: "color-name", Version: "1.1.4", Locations: []ftypes.Location{{StartLine: 88, EndLine: 93}}}, + {ID: "ipaddr.js@1.9.1", Name: "ipaddr.js", Version: "1.9.1", Locations: []ftypes.Location{{StartLine: 104, EndLine: 109}}}, + {ID: "js-tokens@4.0.0", Name: "js-tokens", Version: "4.0.0", Locations: []ftypes.Location{{StartLine: 111, EndLine: 116}}}, + {ID: "loose-envify@1.4.0", Name: "loose-envify", Version: "1.4.0", Locations: []ftypes.Location{{StartLine: 118, EndLine: 127}}}, + {ID: "node-gyp@7.1.0", Name: "node-gyp", Version: "7.1.0", Locations: []ftypes.Location{{StartLine: 129, EndLine: 136}}}, + {ID: "once@1.4.0", Name: "once", Version: "1.4.0", Locations: []ftypes.Location{{StartLine: 138, EndLine: 145}}}, + {ID: "wrappy@1.0.2", Name: "wrappy", Version: "1.0.2", Locations: []ftypes.Location{{StartLine: 147, EndLine: 152}}}, } - yarnV2HappyDeps = []types.Dependency{ + yarnV2HappyDeps = []ftypes.Dependency{ { ID: "ansi-styles@3.2.1", DependsOn: []string{ @@ -123,13 +123,13 @@ var ( }, } - yarnWithLocal = []types.Library{ - {ID: "asap@2.0.6", Name: "asap", Version: "2.0.6", Locations: []types.Location{{StartLine: 5, EndLine: 8}}}, - {ID: "jquery@3.4.1", Name: "jquery", Version: "3.4.1", Locations: []types.Location{{StartLine: 10, EndLine: 13}}}, - {ID: "promise@8.0.3", Name: "promise", Version: "8.0.3", Locations: []types.Location{{StartLine: 15, EndLine: 20}}}, + yarnWithLocal = []ftypes.Package{ + {ID: "asap@2.0.6", Name: "asap", Version: "2.0.6", Locations: []ftypes.Location{{StartLine: 5, EndLine: 8}}}, + {ID: "jquery@3.4.1", Name: "jquery", Version: "3.4.1", Locations: []ftypes.Location{{StartLine: 10, EndLine: 13}}}, + {ID: "promise@8.0.3", Name: "promise", Version: "8.0.3", Locations: []ftypes.Location{{StartLine: 15, EndLine: 20}}}, } - yarnWithLocalDeps = []types.Dependency{ + yarnWithLocalDeps = []ftypes.Dependency{ { ID: "promise@8.0.3", DependsOn: []string{ @@ -138,20 +138,20 @@ var ( }, } - yarnWithNpm = []types.Library{ - {ID: "jquery@3.6.0", Name: "jquery", Version: "3.6.0", Locations: []types.Location{{StartLine: 1, EndLine: 4}}}, + yarnWithNpm = []ftypes.Package{ + {ID: "jquery@3.6.0", Name: "jquery", Version: "3.6.0", Locations: []ftypes.Location{{StartLine: 1, EndLine: 4}}}, } - yarnBadProtocol = []types.Library{ - {ID: "jquery@3.4.1", Name: "jquery", Version: "3.4.1", Locations: []types.Location{{StartLine: 4, EndLine: 7}}}, + yarnBadProtocol = []ftypes.Package{ + {ID: "jquery@3.4.1", Name: "jquery", Version: "3.4.1", Locations: []ftypes.Location{{StartLine: 4, EndLine: 7}}}, } - yarnV2DepsWithProtocol = []types.Library{ - {ID: "debug@4.3.4", Name: "debug", Version: "4.3.4", Locations: []types.Location{{StartLine: 16, EndLine: 26}}}, - {ID: "ms@2.1.2", Name: "ms", Version: "2.1.2", Locations: []types.Location{{StartLine: 28, EndLine: 33}}}, + yarnV2DepsWithProtocol = []ftypes.Package{ + {ID: "debug@4.3.4", Name: "debug", Version: "4.3.4", Locations: []ftypes.Location{{StartLine: 16, EndLine: 26}}}, + {ID: "ms@2.1.2", Name: "ms", Version: "2.1.2", Locations: []ftypes.Location{{StartLine: 28, EndLine: 33}}}, } - yarnV2DepsWithProtocolDeps = []types.Dependency{ + yarnV2DepsWithProtocolDeps = []ftypes.Dependency{ { ID: "debug@4.3.4", DependsOn: []string{"ms@2.1.2"}, diff --git a/pkg/dependency/parser/nuget/config/parse.go b/pkg/dependency/parser/nuget/config/parse.go index 6a43d30ddf94..561a21843207 100644 --- a/pkg/dependency/parser/nuget/config/parse.go +++ b/pkg/dependency/parser/nuget/config/parse.go @@ -6,7 +6,7 @@ import ( "golang.org/x/xerrors" "github.com/aquasecurity/trivy/pkg/dependency/parser/utils" - "github.com/aquasecurity/trivy/pkg/dependency/types" + ftypes "github.com/aquasecurity/trivy/pkg/fanal/types" xio "github.com/aquasecurity/trivy/pkg/x/io" ) @@ -25,29 +25,27 @@ type config struct { type Parser struct{} -func NewParser() types.Parser { +func NewParser() *Parser { return &Parser{} } -func (p *Parser) Parse(r xio.ReadSeekerAt) ([]types.Library, []types.Dependency, error) { +func (p *Parser) Parse(r xio.ReadSeekerAt) ([]ftypes.Package, []ftypes.Dependency, error) { var cfgData config if err := xml.NewDecoder(r).Decode(&cfgData); err != nil { return nil, nil, xerrors.Errorf("failed to decode .config file: %w", err) } - var libs []types.Library + var pkgs []ftypes.Package for _, pkg := range cfgData.Packages { if pkg.ID == "" || pkg.DevDependency { continue } - lib := types.Library{ + pkgs = append(pkgs, ftypes.Package{ Name: pkg.ID, Version: pkg.Version, - } - - libs = append(libs, lib) + }) } - return utils.UniqueLibraries(libs), nil, nil + return utils.UniquePackages(pkgs), nil, nil } diff --git a/pkg/dependency/parser/nuget/config/parse_test.go b/pkg/dependency/parser/nuget/config/parse_test.go index 864246bc9c44..b216fd81d703 100644 --- a/pkg/dependency/parser/nuget/config/parse_test.go +++ b/pkg/dependency/parser/nuget/config/parse_test.go @@ -8,20 +8,20 @@ import ( "github.com/stretchr/testify/require" "github.com/aquasecurity/trivy/pkg/dependency/parser/nuget/config" - "github.com/aquasecurity/trivy/pkg/dependency/types" + ftypes "github.com/aquasecurity/trivy/pkg/fanal/types" ) func TestParse(t *testing.T) { tests := []struct { name string // Test input file inputFile string - want []types.Library + want []ftypes.Package wantErr string }{ { name: "Config", inputFile: "testdata/packages.config", - want: []types.Library{ + want: []ftypes.Package{ {Name: "Newtonsoft.Json", Version: "6.0.4"}, {Name: "Microsoft.AspNet.WebApi", Version: "5.2.2"}, }, @@ -29,7 +29,7 @@ func TestParse(t *testing.T) { { name: "with development dependency", inputFile: "testdata/dev_dependency.config", - want: []types.Library{ + want: []ftypes.Package{ {Name: "Newtonsoft.Json", Version: "8.0.3"}, }, }, diff --git a/pkg/dependency/parser/nuget/lock/parse.go b/pkg/dependency/parser/nuget/lock/parse.go index d5bb54f0e21d..7852680f5749 100644 --- a/pkg/dependency/parser/nuget/lock/parse.go +++ b/pkg/dependency/parser/nuget/lock/parse.go @@ -9,7 +9,6 @@ import ( "github.com/aquasecurity/trivy/pkg/dependency" "github.com/aquasecurity/trivy/pkg/dependency/parser/utils" - "github.com/aquasecurity/trivy/pkg/dependency/types" ftypes "github.com/aquasecurity/trivy/pkg/fanal/types" xio "github.com/aquasecurity/trivy/pkg/x/io" ) @@ -31,11 +30,11 @@ type Dependency struct { type Parser struct{} -func NewParser() types.Parser { +func NewParser() *Parser { return &Parser{} } -func (p *Parser) Parse(r xio.ReadSeekerAt) ([]types.Library, []types.Dependency, error) { +func (p *Parser) Parse(r xio.ReadSeekerAt) ([]ftypes.Package, []ftypes.Dependency, error) { var lockFile LockFile input, err := io.ReadAll(r) if err != nil { @@ -45,7 +44,7 @@ func (p *Parser) Parse(r xio.ReadSeekerAt) ([]types.Library, []types.Dependency, return nil, nil, xerrors.Errorf("failed to decode packages.lock.json: %w", err) } - var libs []types.Library + var pkgs []ftypes.Package depsMap := make(map[string][]string) for _, targetContent := range lockFile.Targets { for packageName, packageContent := range targetContent { @@ -56,19 +55,19 @@ func (p *Parser) Parse(r xio.ReadSeekerAt) ([]types.Library, []types.Dependency, depId := packageID(packageName, packageContent.Resolved) - lib := types.Library{ + pkg := ftypes.Package{ ID: depId, Name: packageName, Version: packageContent.Resolved, - Relationship: lo.Ternary(packageContent.Type == "Direct", types.RelationshipDirect, types.RelationshipIndirect), - Locations: []types.Location{ + Relationship: lo.Ternary(packageContent.Type == "Direct", ftypes.RelationshipDirect, ftypes.RelationshipIndirect), + Locations: []ftypes.Location{ { StartLine: packageContent.StartLine, EndLine: packageContent.EndLine, }, }, } - libs = append(libs, lib) + pkgs = append(pkgs, pkg) var dependsOn []string @@ -86,16 +85,16 @@ func (p *Parser) Parse(r xio.ReadSeekerAt) ([]types.Library, []types.Dependency, } } - var deps []types.Dependency + var deps []ftypes.Dependency for depId, dependsOn := range depsMap { - dep := types.Dependency{ + dep := ftypes.Dependency{ ID: depId, DependsOn: dependsOn, } deps = append(deps, dep) } - return utils.UniqueLibraries(libs), deps, nil + return utils.UniquePackages(pkgs), deps, nil } // UnmarshalJSONWithMetadata needed to detect start and end lines of deps diff --git a/pkg/dependency/parser/nuget/lock/parse_test.go b/pkg/dependency/parser/nuget/lock/parse_test.go index 04ddb22244df..561eed5dfc88 100644 --- a/pkg/dependency/parser/nuget/lock/parse_test.go +++ b/pkg/dependency/parser/nuget/lock/parse_test.go @@ -10,14 +10,14 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - "github.com/aquasecurity/trivy/pkg/dependency/types" + ftypes "github.com/aquasecurity/trivy/pkg/fanal/types" ) func TestParse(t *testing.T) { vectors := []struct { file string // Test input file - want []types.Library - wantDeps []types.Dependency + want []ftypes.Package + wantDeps []ftypes.Dependency }{ { file: "testdata/packages_lock_simple.json", @@ -49,21 +49,8 @@ func TestParse(t *testing.T) { got, deps, err := NewParser().Parse(f) require.NoError(t, err) - sort.Slice(got, func(i, j int) bool { - ret := strings.Compare(got[i].Name, got[j].Name) - if ret == 0 { - return got[i].Version < got[j].Version - } - return ret < 0 - }) - - sort.Slice(v.want, func(i, j int) bool { - ret := strings.Compare(v.want[i].Name, v.want[j].Name) - if ret == 0 { - return v.want[i].Version < v.want[j].Version - } - return ret < 0 - }) + sort.Sort(ftypes.Packages(got)) + sort.Sort(ftypes.Packages(v.want)) assert.Equal(t, v.want, got) @@ -76,7 +63,7 @@ func TestParse(t *testing.T) { } } -func sortDeps(deps []types.Dependency) { +func sortDeps(deps []ftypes.Dependency) { sort.Slice(deps, func(i, j int) bool { return strings.Compare(deps[i].ID, deps[j].ID) < 0 }) diff --git a/pkg/dependency/parser/nuget/lock/parse_testcase.go b/pkg/dependency/parser/nuget/lock/parse_testcase.go index a499fc158e3e..d528e2d2a421 100644 --- a/pkg/dependency/parser/nuget/lock/parse_testcase.go +++ b/pkg/dependency/parser/nuget/lock/parse_testcase.go @@ -1,6 +1,6 @@ package lock -import "github.com/aquasecurity/trivy/pkg/dependency/types" +import ftypes "github.com/aquasecurity/trivy/pkg/fanal/types" var ( // docker run --rm -i -t mcr.microsoft.com/dotnet/sdk:latest @@ -11,13 +11,13 @@ var ( // dotnet add package NuGet.Frameworks // dotnet restore --use-lock-file // cat packages.lock.json | jq -rc '.dependencies[] | keys[] as $k | "{\"\($k)\", \"\(.[$k] | .resolved)\", \"\"},"' - nuGetSimple = []types.Library{ + nuGetSimple = []ftypes.Package{ { ID: "Newtonsoft.Json@12.0.3", Name: "Newtonsoft.Json", Version: "12.0.3", - Relationship: types.RelationshipDirect, - Locations: []types.Location{ + Relationship: ftypes.RelationshipDirect, + Locations: []ftypes.Location{ { StartLine: 5, EndLine: 10, @@ -28,8 +28,8 @@ var ( ID: "NuGet.Frameworks@5.7.0", Name: "NuGet.Frameworks", Version: "5.7.0", - Relationship: types.RelationshipDirect, - Locations: []types.Location{ + Relationship: ftypes.RelationshipDirect, + Locations: []ftypes.Location{ { StartLine: 11, EndLine: 16, @@ -37,7 +37,7 @@ var ( }, }, } - nuGetSimpleDeps []types.Dependency + nuGetSimpleDeps []ftypes.Dependency // docker run --rm -i -t mcr.microsoft.com/dotnet/sdk:latest // apt -y update && apt -y install jq @@ -47,13 +47,13 @@ var ( // dotnet add package NuGet.Frameworks // dotnet restore --use-lock-file // cat packages.lock.json | jq -rc '.dependencies[] | keys[] as $k | "{\"\($k)\", \"\(.[$k] | .resolved)\", \"\"},"' - nuGetSubDependencies = []types.Library{ + nuGetSubDependencies = []ftypes.Package{ { ID: "Microsoft.Extensions.ApiDescription.Server@3.0.0", Name: "Microsoft.Extensions.ApiDescription.Server", Version: "3.0.0", - Relationship: types.RelationshipIndirect, - Locations: []types.Location{ + Relationship: ftypes.RelationshipIndirect, + Locations: []ftypes.Location{ { StartLine: 29, EndLine: 33, @@ -64,8 +64,8 @@ var ( ID: "Microsoft.OpenApi@1.1.4", Name: "Microsoft.OpenApi", Version: "1.1.4", - Relationship: types.RelationshipIndirect, - Locations: []types.Location{ + Relationship: ftypes.RelationshipIndirect, + Locations: []ftypes.Location{ { StartLine: 34, EndLine: 38, @@ -76,8 +76,8 @@ var ( ID: "Newtonsoft.Json@12.0.3", Name: "Newtonsoft.Json", Version: "12.0.3", - Relationship: types.RelationshipDirect, - Locations: []types.Location{ + Relationship: ftypes.RelationshipDirect, + Locations: []ftypes.Location{ { StartLine: 5, EndLine: 10, @@ -88,8 +88,8 @@ var ( ID: "NuGet.Frameworks@5.7.0", Name: "NuGet.Frameworks", Version: "5.7.0", - Relationship: types.RelationshipDirect, - Locations: []types.Location{ + Relationship: ftypes.RelationshipDirect, + Locations: []ftypes.Location{ { StartLine: 11, EndLine: 16, @@ -100,8 +100,8 @@ var ( ID: "Swashbuckle.AspNetCore@5.5.1", Name: "Swashbuckle.AspNetCore", Version: "5.5.1", - Relationship: types.RelationshipDirect, - Locations: []types.Location{ + Relationship: ftypes.RelationshipDirect, + Locations: []ftypes.Location{ { StartLine: 17, EndLine: 28, @@ -112,8 +112,8 @@ var ( ID: "Swashbuckle.AspNetCore.Swagger@5.5.1", Name: "Swashbuckle.AspNetCore.Swagger", Version: "5.5.1", - Relationship: types.RelationshipIndirect, - Locations: []types.Location{ + Relationship: ftypes.RelationshipIndirect, + Locations: []ftypes.Location{ { StartLine: 39, EndLine: 46, @@ -124,8 +124,8 @@ var ( ID: "Swashbuckle.AspNetCore.SwaggerGen@5.5.1", Name: "Swashbuckle.AspNetCore.SwaggerGen", Version: "5.5.1", - Relationship: types.RelationshipIndirect, - Locations: []types.Location{ + Relationship: ftypes.RelationshipIndirect, + Locations: []ftypes.Location{ { StartLine: 47, EndLine: 54, @@ -136,8 +136,8 @@ var ( ID: "Swashbuckle.AspNetCore.SwaggerUI@5.5.1", Name: "Swashbuckle.AspNetCore.SwaggerUI", Version: "5.5.1", - Relationship: types.RelationshipIndirect, - Locations: []types.Location{ + Relationship: ftypes.RelationshipIndirect, + Locations: []ftypes.Location{ { StartLine: 55, EndLine: 59, @@ -145,7 +145,7 @@ var ( }, }, } - nuGetSubDependenciesDeps = []types.Dependency{ + nuGetSubDependenciesDeps = []ftypes.Dependency{ { ID: "Swashbuckle.AspNetCore.Swagger@5.5.1", DependsOn: []string{"Microsoft.OpenApi@1.1.4"}, @@ -173,13 +173,13 @@ var ( // dotnet add package AWSSDK.Core // dotnet restore --use-lock-file // cat packages.lock.json | jq -rc '.dependencies[] | keys[] as $k | "{\"\($k)\", \"\(.[$k] | .resolved)\", \"\"},"' - nuGetLegacy = []types.Library{ + nuGetLegacy = []ftypes.Package{ { ID: "AWSSDK.Core@3.5.1.30", Name: "AWSSDK.Core", Version: "3.5.1.30", - Relationship: types.RelationshipDirect, - Locations: []types.Location{ + Relationship: ftypes.RelationshipDirect, + Locations: []ftypes.Location{ { StartLine: 5, EndLine: 10, @@ -190,8 +190,8 @@ var ( ID: "Newtonsoft.Json@12.0.3", Name: "Newtonsoft.Json", Version: "12.0.3", - Relationship: types.RelationshipDirect, - Locations: []types.Location{ + Relationship: ftypes.RelationshipDirect, + Locations: []ftypes.Location{ { StartLine: 11, EndLine: 16, @@ -199,7 +199,7 @@ var ( }, }, } - nuGetLegacyDeps []types.Dependency + nuGetLegacyDeps []ftypes.Dependency // docker run --rm -i -t mcr.microsoft.com/dotnet/sdk:latest // apt -y update && apt -y install jq @@ -210,13 +210,13 @@ var ( // dotnet restore --use-lock-file // dotnet add package AWSSDK.Core // cat packages.lock.json | jq -rc '.dependencies[] | keys[] as $k | "{\"\($k)\", \"\(.[$k] | .resolved)\", \"\"},"' | sort -u - nuGetMultiTarget = []types.Library{ + nuGetMultiTarget = []ftypes.Package{ { ID: "AWSSDK.Core@3.5.1.30", Name: "AWSSDK.Core", Version: "3.5.1.30", - Relationship: types.RelationshipDirect, - Locations: []types.Location{ + Relationship: ftypes.RelationshipDirect, + Locations: []ftypes.Location{ { StartLine: 5, EndLine: 10, @@ -243,8 +243,8 @@ var ( ID: "Microsoft.Bcl.AsyncInterfaces@1.1.0", Name: "Microsoft.Bcl.AsyncInterfaces", Version: "1.1.0", - Relationship: types.RelationshipIndirect, - Locations: []types.Location{ + Relationship: ftypes.RelationshipIndirect, + Locations: []ftypes.Location{ { StartLine: 460, EndLine: 467, @@ -255,8 +255,8 @@ var ( ID: "Microsoft.CSharp@4.3.0", Name: "Microsoft.CSharp", Version: "4.3.0", - Relationship: types.RelationshipIndirect, - Locations: []types.Location{ + Relationship: ftypes.RelationshipIndirect, + Locations: []ftypes.Location{ { StartLine: 138, EndLine: 147, @@ -267,8 +267,8 @@ var ( ID: "Microsoft.NETCore.Platforms@1.1.0", Name: "Microsoft.NETCore.Platforms", Version: "1.1.0", - Relationship: types.RelationshipIndirect, - Locations: []types.Location{ + Relationship: ftypes.RelationshipIndirect, + Locations: []ftypes.Location{ { StartLine: 148, EndLine: 152, @@ -283,8 +283,8 @@ var ( ID: "Microsoft.NETCore.Targets@1.1.0", Name: "Microsoft.NETCore.Targets", Version: "1.1.0", - Relationship: types.RelationshipIndirect, - Locations: []types.Location{ + Relationship: ftypes.RelationshipIndirect, + Locations: []ftypes.Location{ { StartLine: 153, EndLine: 157, @@ -295,8 +295,8 @@ var ( ID: "Microsoft.NETFramework.ReferenceAssemblies@1.0.0", Name: "Microsoft.NETFramework.ReferenceAssemblies", Version: "1.0.0", - Relationship: types.RelationshipDirect, - Locations: []types.Location{ + Relationship: ftypes.RelationshipDirect, + Locations: []ftypes.Location{ { StartLine: 11, EndLine: 19, @@ -315,8 +315,8 @@ var ( ID: "Microsoft.NETFramework.ReferenceAssemblies.net20@1.0.0", Name: "Microsoft.NETFramework.ReferenceAssemblies.net20", Version: "1.0.0", - Relationship: types.RelationshipIndirect, - Locations: []types.Location{ + Relationship: ftypes.RelationshipIndirect, + Locations: []ftypes.Location{ { StartLine: 26, EndLine: 30, @@ -331,8 +331,8 @@ var ( ID: "Microsoft.NETFramework.ReferenceAssemblies.net40@1.0.0", Name: "Microsoft.NETFramework.ReferenceAssemblies.net40", Version: "1.0.0", - Relationship: types.RelationshipIndirect, - Locations: []types.Location{ + Relationship: ftypes.RelationshipIndirect, + Locations: []ftypes.Location{ { StartLine: 82, EndLine: 86, @@ -343,8 +343,8 @@ var ( ID: "NETStandard.Library@1.6.1", Name: "NETStandard.Library", Version: "1.6.1", - Relationship: types.RelationshipDirect, - Locations: []types.Location{ + Relationship: ftypes.RelationshipDirect, + Locations: []ftypes.Location{ { StartLine: 95, EndLine: 125, @@ -355,8 +355,8 @@ var ( ID: "NETStandard.Library@2.0.3", Name: "NETStandard.Library", Version: "2.0.3", - Relationship: types.RelationshipDirect, - Locations: []types.Location{ + Relationship: ftypes.RelationshipDirect, + Locations: []ftypes.Location{ { StartLine: 445, EndLine: 453, @@ -367,8 +367,8 @@ var ( ID: "Newtonsoft.Json@12.0.3", Name: "Newtonsoft.Json", Version: "12.0.3", - Relationship: types.RelationshipDirect, - Locations: []types.Location{ + Relationship: ftypes.RelationshipDirect, + Locations: []ftypes.Location{ { StartLine: 20, EndLine: 25, @@ -395,8 +395,8 @@ var ( ID: "System.Collections@4.3.0", Name: "System.Collections", Version: "4.3.0", - Relationship: types.RelationshipIndirect, - Locations: []types.Location{ + Relationship: ftypes.RelationshipIndirect, + Locations: []ftypes.Location{ { StartLine: 158, EndLine: 167, @@ -407,8 +407,8 @@ var ( ID: "System.ComponentModel@4.3.0", Name: "System.ComponentModel", Version: "4.3.0", - Relationship: types.RelationshipIndirect, - Locations: []types.Location{ + Relationship: ftypes.RelationshipIndirect, + Locations: []ftypes.Location{ { StartLine: 168, EndLine: 175, @@ -418,9 +418,9 @@ var ( { ID: "System.ComponentModel.Primitives@4.3.0", Name: "System.ComponentModel.Primitives", - Relationship: types.RelationshipIndirect, + Relationship: ftypes.RelationshipIndirect, Version: "4.3.0", - Locations: []types.Location{ + Locations: []ftypes.Location{ { StartLine: 176, EndLine: 185, @@ -430,9 +430,9 @@ var ( { ID: "System.ComponentModel.TypeConverter@4.3.0", Name: "System.ComponentModel.TypeConverter", - Relationship: types.RelationshipIndirect, + Relationship: ftypes.RelationshipIndirect, Version: "4.3.0", - Locations: []types.Location{ + Locations: []ftypes.Location{ { StartLine: 186, EndLine: 203, @@ -443,8 +443,8 @@ var ( ID: "System.Diagnostics.Debug@4.3.0", Name: "System.Diagnostics.Debug", Version: "4.3.0", - Relationship: types.RelationshipIndirect, - Locations: []types.Location{ + Relationship: ftypes.RelationshipIndirect, + Locations: []ftypes.Location{ { StartLine: 204, EndLine: 213, @@ -455,8 +455,8 @@ var ( ID: "System.Diagnostics.Tools@4.3.0", Name: "System.Diagnostics.Tools", Version: "4.3.0", - Relationship: types.RelationshipIndirect, - Locations: []types.Location{ + Relationship: ftypes.RelationshipIndirect, + Locations: []ftypes.Location{ { StartLine: 214, EndLine: 223, @@ -467,8 +467,8 @@ var ( ID: "System.Dynamic.Runtime@4.3.0", Name: "System.Dynamic.Runtime", Version: "4.3.0", - Relationship: types.RelationshipIndirect, - Locations: []types.Location{ + Relationship: ftypes.RelationshipIndirect, + Locations: []ftypes.Location{ { StartLine: 224, EndLine: 234, @@ -479,8 +479,8 @@ var ( ID: "System.Globalization@4.3.0", Name: "System.Globalization", Version: "4.3.0", - Relationship: types.RelationshipIndirect, - Locations: []types.Location{ + Relationship: ftypes.RelationshipIndirect, + Locations: []ftypes.Location{ { StartLine: 235, EndLine: 244, @@ -491,8 +491,8 @@ var ( ID: "System.IO@4.3.0", Name: "System.IO", Version: "4.3.0", - Relationship: types.RelationshipIndirect, - Locations: []types.Location{ + Relationship: ftypes.RelationshipIndirect, + Locations: []ftypes.Location{ { StartLine: 245, EndLine: 256, @@ -503,8 +503,8 @@ var ( ID: "System.Linq@4.3.0", Name: "System.Linq", Version: "4.3.0", - Relationship: types.RelationshipIndirect, - Locations: []types.Location{ + Relationship: ftypes.RelationshipIndirect, + Locations: []ftypes.Location{ { StartLine: 257, EndLine: 265, @@ -515,8 +515,8 @@ var ( ID: "System.Linq.Expressions@4.3.0", Name: "System.Linq.Expressions", Version: "4.3.0", - Relationship: types.RelationshipIndirect, - Locations: []types.Location{ + Relationship: ftypes.RelationshipIndirect, + Locations: []ftypes.Location{ { StartLine: 266, EndLine: 274, @@ -527,8 +527,8 @@ var ( ID: "System.Net.Primitives@4.3.0", Name: "System.Net.Primitives", Version: "4.3.0", - Relationship: types.RelationshipIndirect, - Locations: []types.Location{ + Relationship: ftypes.RelationshipIndirect, + Locations: []ftypes.Location{ { StartLine: 275, EndLine: 284, @@ -539,8 +539,8 @@ var ( ID: "System.ObjectModel@4.3.0", Name: "System.ObjectModel", Version: "4.3.0", - Relationship: types.RelationshipIndirect, - Locations: []types.Location{ + Relationship: ftypes.RelationshipIndirect, + Locations: []ftypes.Location{ { StartLine: 285, EndLine: 292, @@ -551,8 +551,8 @@ var ( ID: "System.Reflection@4.3.0", Name: "System.Reflection", Version: "4.3.0", - Relationship: types.RelationshipIndirect, - Locations: []types.Location{ + Relationship: ftypes.RelationshipIndirect, + Locations: []ftypes.Location{ { StartLine: 293, EndLine: 304, @@ -562,9 +562,9 @@ var ( { ID: "System.Reflection.Extensions@4.3.0", Name: "System.Reflection.Extensions", - Relationship: types.RelationshipIndirect, + Relationship: ftypes.RelationshipIndirect, Version: "4.3.0", - Locations: []types.Location{ + Locations: []ftypes.Location{ { StartLine: 305, EndLine: 315, @@ -574,9 +574,9 @@ var ( { ID: "System.Reflection.Primitives@4.3.0", Name: "System.Reflection.Primitives", - Relationship: types.RelationshipIndirect, + Relationship: ftypes.RelationshipIndirect, Version: "4.3.0", - Locations: []types.Location{ + Locations: []ftypes.Location{ { StartLine: 316, EndLine: 325, @@ -586,9 +586,9 @@ var ( { ID: "System.Resources.ResourceManager@4.3.0", Name: "System.Resources.ResourceManager", - Relationship: types.RelationshipIndirect, + Relationship: ftypes.RelationshipIndirect, Version: "4.3.0", - Locations: []types.Location{ + Locations: []ftypes.Location{ { StartLine: 326, EndLine: 337, @@ -599,8 +599,8 @@ var ( ID: "System.Runtime@4.3.0", Name: "System.Runtime", Version: "4.3.0", - Relationship: types.RelationshipIndirect, - Locations: []types.Location{ + Relationship: ftypes.RelationshipIndirect, + Locations: []ftypes.Location{ { StartLine: 338, EndLine: 346, @@ -611,8 +611,8 @@ var ( ID: "System.Runtime.CompilerServices.Unsafe@4.5.2", Name: "System.Runtime.CompilerServices.Unsafe", Version: "4.5.2", - Relationship: types.RelationshipIndirect, - Locations: []types.Location{ + Relationship: ftypes.RelationshipIndirect, + Locations: []ftypes.Location{ { StartLine: 473, EndLine: 477, @@ -623,8 +623,8 @@ var ( ID: "System.Runtime.Extensions@4.3.0", Name: "System.Runtime.Extensions", Version: "4.3.0", - Relationship: types.RelationshipIndirect, - Locations: []types.Location{ + Relationship: ftypes.RelationshipIndirect, + Locations: []ftypes.Location{ { StartLine: 347, EndLine: 356, @@ -635,8 +635,8 @@ var ( ID: "System.Runtime.Serialization.Primitives@4.3.0", Name: "System.Runtime.Serialization.Primitives", Version: "4.3.0", - Relationship: types.RelationshipIndirect, - Locations: []types.Location{ + Relationship: ftypes.RelationshipIndirect, + Locations: []ftypes.Location{ { StartLine: 357, EndLine: 364, @@ -647,8 +647,8 @@ var ( ID: "System.Text.Encoding@4.3.0", Name: "System.Text.Encoding", Version: "4.3.0", - Relationship: types.RelationshipIndirect, - Locations: []types.Location{ + Relationship: ftypes.RelationshipIndirect, + Locations: []ftypes.Location{ { StartLine: 365, EndLine: 374, @@ -659,8 +659,8 @@ var ( ID: "System.Text.Encoding.Extensions@4.3.0", Name: "System.Text.Encoding.Extensions", Version: "4.3.0", - Relationship: types.RelationshipIndirect, - Locations: []types.Location{ + Relationship: ftypes.RelationshipIndirect, + Locations: []ftypes.Location{ { StartLine: 375, EndLine: 385, @@ -671,8 +671,8 @@ var ( ID: "System.Text.RegularExpressions@4.3.0", Name: "System.Text.RegularExpressions", Version: "4.3.0", - Relationship: types.RelationshipIndirect, - Locations: []types.Location{ + Relationship: ftypes.RelationshipIndirect, + Locations: []ftypes.Location{ { StartLine: 386, EndLine: 393, @@ -683,8 +683,8 @@ var ( ID: "System.Threading@4.3.0", Name: "System.Threading", Version: "4.3.0", - Relationship: types.RelationshipIndirect, - Locations: []types.Location{ + Relationship: ftypes.RelationshipIndirect, + Locations: []ftypes.Location{ { StartLine: 394, EndLine: 402, @@ -695,8 +695,8 @@ var ( ID: "System.Threading.Tasks@4.3.0", Name: "System.Threading.Tasks", Version: "4.3.0", - Relationship: types.RelationshipIndirect, - Locations: []types.Location{ + Relationship: ftypes.RelationshipIndirect, + Locations: []ftypes.Location{ { StartLine: 403, EndLine: 412, @@ -707,8 +707,8 @@ var ( ID: "System.Threading.Tasks.Extensions@4.5.2", Name: "System.Threading.Tasks.Extensions", Version: "4.5.2", - Relationship: types.RelationshipIndirect, - Locations: []types.Location{ + Relationship: ftypes.RelationshipIndirect, + Locations: []ftypes.Location{ { StartLine: 478, EndLine: 485, @@ -719,8 +719,8 @@ var ( ID: "System.Xml.ReaderWriter@4.3.0", Name: "System.Xml.ReaderWriter", Version: "4.3.0", - Relationship: types.RelationshipIndirect, - Locations: []types.Location{ + Relationship: ftypes.RelationshipIndirect, + Locations: []ftypes.Location{ { StartLine: 413, EndLine: 423, @@ -731,8 +731,8 @@ var ( ID: "System.Xml.XDocument@4.3.0", Name: "System.Xml.XDocument", Version: "4.3.0", - Relationship: types.RelationshipIndirect, - Locations: []types.Location{ + Relationship: ftypes.RelationshipIndirect, + Locations: []ftypes.Location{ { StartLine: 424, EndLine: 433, @@ -740,7 +740,7 @@ var ( }, }, } - nuGetMultiTargetDeps = []types.Dependency{ + nuGetMultiTargetDeps = []ftypes.Dependency{ { ID: "AWSSDK.Core@3.5.1.30", DependsOn: []string{"Microsoft.Bcl.AsyncInterfaces@1.1.0"}, diff --git a/pkg/dependency/parser/nuget/packagesprops/parse.go b/pkg/dependency/parser/nuget/packagesprops/parse.go index 5e4c6831d1a1..606261703311 100644 --- a/pkg/dependency/parser/nuget/packagesprops/parse.go +++ b/pkg/dependency/parser/nuget/packagesprops/parse.go @@ -8,12 +8,11 @@ import ( "github.com/aquasecurity/trivy/pkg/dependency" "github.com/aquasecurity/trivy/pkg/dependency/parser/utils" - "github.com/aquasecurity/trivy/pkg/dependency/types" ftypes "github.com/aquasecurity/trivy/pkg/fanal/types" xio "github.com/aquasecurity/trivy/pkg/x/io" ) -type pkg struct { +type Pkg struct { Version string `xml:"Version,attr"` UpdatePackageName string `xml:"Update,attr"` IncludePackageName string `xml:"Include,attr"` @@ -21,8 +20,8 @@ type pkg struct { // https://github.com/dotnet/roslyn-tools/blob/b4c5220f5dfc4278847b6d38eff91cc1188f8066/src/RoslynInsertionTool/RoslynInsertionTool/CoreXT.cs#L150 type itemGroup struct { - PackageReferenceEntry []pkg `xml:"PackageReference"` - PackageVersionEntry []pkg `xml:"PackageVersion"` + PackageReferenceEntry []Pkg `xml:"PackageReference"` + PackageVersionEntry []Pkg `xml:"PackageVersion"` } type project struct { @@ -32,11 +31,11 @@ type project struct { type Parser struct{} -func NewParser() types.Parser { +func NewParser() *Parser { return &Parser{} } -func (p pkg) library() types.Library { +func (p Pkg) Package() ftypes.Package { // Update attribute is considered legacy, so preferring Include name := p.UpdatePackageName if p.IncludePackageName != "" { @@ -45,20 +44,20 @@ func (p pkg) library() types.Library { name = strings.TrimSpace(name) version := strings.TrimSpace(p.Version) - return types.Library{ + return ftypes.Package{ ID: dependency.ID(ftypes.NuGet, name, version), Name: name, Version: version, } } -func shouldSkipLib(lib types.Library) bool { - if lib.Name == "" || lib.Version == "" { +func shouldSkipPkg(pkg ftypes.Package) bool { + if pkg.Name == "" || pkg.Version == "" { return true } // *packages.props files don't contain variable resolution information. // So we need to skip them. - if isVariable(lib.Name) || isVariable(lib.Version) { + if isVariable(pkg.Name) || isVariable(pkg.Version) { return true } return false @@ -68,20 +67,20 @@ func isVariable(s string) bool { return strings.HasPrefix(s, "$(") && strings.HasSuffix(s, ")") } -func (p *Parser) Parse(r xio.ReadSeekerAt) ([]types.Library, []types.Dependency, error) { +func (p *Parser) Parse(r xio.ReadSeekerAt) ([]ftypes.Package, []ftypes.Dependency, error) { var configData project if err := xml.NewDecoder(r).Decode(&configData); err != nil { return nil, nil, xerrors.Errorf("failed to decode '*.packages.props' file: %w", err) } - var libs []types.Library + var pkgs []ftypes.Package for _, item := range configData.ItemGroups { for _, pkg := range append(item.PackageReferenceEntry, item.PackageVersionEntry...) { - lib := pkg.library() - if !shouldSkipLib(lib) { - libs = append(libs, lib) + pkg := pkg.Package() + if !shouldSkipPkg(pkg) { + pkgs = append(pkgs, pkg) } } } - return utils.UniqueLibraries(libs), nil, nil + return utils.UniquePackages(pkgs), nil, nil } diff --git a/pkg/dependency/parser/nuget/packagesprops/parse_test.go b/pkg/dependency/parser/nuget/packagesprops/parse_test.go index 96a50716d7ef..58c5209da333 100644 --- a/pkg/dependency/parser/nuget/packagesprops/parse_test.go +++ b/pkg/dependency/parser/nuget/packagesprops/parse_test.go @@ -8,20 +8,20 @@ import ( "github.com/stretchr/testify/require" config "github.com/aquasecurity/trivy/pkg/dependency/parser/nuget/packagesprops" - "github.com/aquasecurity/trivy/pkg/dependency/types" + ftypes "github.com/aquasecurity/trivy/pkg/fanal/types" ) func TestParse(t *testing.T) { tests := []struct { name string // Test input file inputFile string - want []types.Library + want []ftypes.Package wantErr string }{ { name: "PackagesProps", inputFile: "testdata/packages.props", - want: []types.Library{ + want: []ftypes.Package{ {Name: "Microsoft.Extensions.Configuration", Version: "2.1.1", ID: "Microsoft.Extensions.Configuration@2.1.1"}, {Name: "Microsoft.Extensions.DependencyInjection.Abstractions", Version: "2.2.1", ID: "Microsoft.Extensions.DependencyInjection.Abstractions@2.2.1"}, {Name: "Microsoft.Extensions.Http", Version: "3.2.1", ID: "Microsoft.Extensions.Http@3.2.1"}, @@ -30,7 +30,7 @@ func TestParse(t *testing.T) { { name: "DirectoryPackagesProps", inputFile: "testdata/Directory.Packages.props", - want: []types.Library{ + want: []ftypes.Package{ {Name: "PackageOne", Version: "6.2.3", ID: "PackageOne@6.2.3"}, {Name: "PackageThree", Version: "2.4.1", ID: "PackageThree@2.4.1"}, {Name: "PackageTwo", Version: "6.0.0", ID: "PackageTwo@6.0.0"}, @@ -39,7 +39,7 @@ func TestParse(t *testing.T) { { name: "SeveralItemGroupElements", inputFile: "testdata/several_item_groups", - want: []types.Library{ + want: []ftypes.Package{ {Name: "PackageOne", Version: "6.2.3", ID: "PackageOne@6.2.3"}, {Name: "PackageThree", Version: "2.4.1", ID: "PackageThree@2.4.1"}, {Name: "PackageTwo", Version: "6.0.0", ID: "PackageTwo@6.0.0"}, @@ -48,14 +48,14 @@ func TestParse(t *testing.T) { { name: "VariablesAsNamesOrVersion", inputFile: "testdata/variables_and_empty", - want: []types.Library{ + want: []ftypes.Package{ {Name: "PackageFour", Version: "2.4.1", ID: "PackageFour@2.4.1"}, }, }, { name: "NoItemGroupInXMLStructure", inputFile: "testdata/no_item_group.props", - want: []types.Library(nil), + want: []ftypes.Package(nil), }, { name: "NoProject", diff --git a/pkg/dependency/parser/php/composer/parse.go b/pkg/dependency/parser/php/composer/parse.go index 49b73c7994c8..1b1e72bb7a10 100644 --- a/pkg/dependency/parser/php/composer/parse.go +++ b/pkg/dependency/parser/php/composer/parse.go @@ -10,13 +10,12 @@ import ( "golang.org/x/xerrors" "github.com/aquasecurity/trivy/pkg/dependency" - "github.com/aquasecurity/trivy/pkg/dependency/types" ftypes "github.com/aquasecurity/trivy/pkg/fanal/types" "github.com/aquasecurity/trivy/pkg/log" xio "github.com/aquasecurity/trivy/pkg/x/io" ) -type lockFile struct { +type LockFile struct { Packages []packageInfo `json:"packages"` } type packageInfo struct { @@ -32,14 +31,14 @@ type Parser struct { logger *log.Logger } -func NewParser() types.Parser { +func NewParser() *Parser { return &Parser{ logger: log.WithPrefix("composer"), } } -func (p *Parser) Parse(r xio.ReadSeekerAt) ([]types.Library, []types.Dependency, error) { - var lockFile lockFile +func (p *Parser) Parse(r xio.ReadSeekerAt) ([]ftypes.Package, []ftypes.Dependency, error) { + var lockFile LockFile input, err := io.ReadAll(r) if err != nil { return nil, nil, xerrors.Errorf("read error: %w", err) @@ -48,61 +47,61 @@ func (p *Parser) Parse(r xio.ReadSeekerAt) ([]types.Library, []types.Dependency, return nil, nil, xerrors.Errorf("decode error: %w", err) } - libs := make(map[string]types.Library) + pkgs := make(map[string]ftypes.Package) foundDeps := make(map[string][]string) - for _, pkg := range lockFile.Packages { - lib := types.Library{ - ID: dependency.ID(ftypes.Composer, pkg.Name, pkg.Version), - Name: pkg.Name, - Version: pkg.Version, - Relationship: types.RelationshipUnknown, // composer.lock file doesn't have info about direct/indirect dependencies - License: strings.Join(pkg.License, ", "), - Locations: []types.Location{ + for _, lpkg := range lockFile.Packages { + pkg := ftypes.Package{ + ID: dependency.ID(ftypes.Composer, lpkg.Name, lpkg.Version), + Name: lpkg.Name, + Version: lpkg.Version, + Relationship: ftypes.RelationshipUnknown, // composer.lock file doesn't have info about direct/indirect dependencies + Licenses: lpkg.License, + Locations: []ftypes.Location{ { - StartLine: pkg.StartLine, - EndLine: pkg.EndLine, + StartLine: lpkg.StartLine, + EndLine: lpkg.EndLine, }, }, } - libs[lib.Name] = lib + pkgs[pkg.Name] = pkg var dependsOn []string - for depName := range pkg.Require { + for depName := range lpkg.Require { // Require field includes required php version, skip this // Also skip PHP extensions if depName == "php" || strings.HasPrefix(depName, "ext") { continue } - dependsOn = append(dependsOn, depName) // field uses range of versions, so later we will fill in the versions from the libraries + dependsOn = append(dependsOn, depName) // field uses range of versions, so later we will fill in the versions from the packages } if len(dependsOn) > 0 { - foundDeps[lib.ID] = dependsOn + foundDeps[pkg.ID] = dependsOn } } // fill deps versions - var deps []types.Dependency - for libID, depsOn := range foundDeps { + var deps ftypes.Dependencies + for pkgID, depsOn := range foundDeps { var dependsOn []string for _, depName := range depsOn { - if lib, ok := libs[depName]; ok { - dependsOn = append(dependsOn, lib.ID) + if pkg, ok := pkgs[depName]; ok { + dependsOn = append(dependsOn, pkg.ID) continue } p.logger.Debug("Unable to find version", log.String("name", depName)) } sort.Strings(dependsOn) - deps = append(deps, types.Dependency{ - ID: libID, + deps = append(deps, ftypes.Dependency{ + ID: pkgID, DependsOn: dependsOn, }) } - libSlice := maps.Values(libs) - sort.Sort(types.Libraries(libSlice)) - sort.Sort(types.Dependencies(deps)) + pkgSlice := maps.Values(pkgs) + sort.Sort(ftypes.Packages(pkgSlice)) + sort.Sort(deps) - return libSlice, deps, nil + return pkgSlice, deps, nil } // UnmarshalJSONWithMetadata needed to detect start and end lines of deps diff --git a/pkg/dependency/parser/php/composer/parse_test.go b/pkg/dependency/parser/php/composer/parse_test.go index 8c80899bc4ba..726ac4676b37 100644 --- a/pkg/dependency/parser/php/composer/parse_test.go +++ b/pkg/dependency/parser/php/composer/parse_test.go @@ -1,7 +1,7 @@ package composer import ( - "github.com/aquasecurity/trivy/pkg/dependency/types" + ftypes "github.com/aquasecurity/trivy/pkg/fanal/types" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "os" @@ -13,15 +13,15 @@ var ( // apk add jq // composer require guzzlehttp/guzzle:6.5.8 // composer require pear/log:1.13.3 --dev - // composer show -i --no-dev -f json | jq --sort-keys -rc '.installed[] | "{ID: \"\(.name)@\(.version)\", Name: \"\(.name)\", Version: \"\(.version)\", License: \"MIT\", Locations: []types.Location{{StartLine: , EndLine: }}},"' + // composer show -i --no-dev -f json | jq --sort-keys -rc '.installed[] | "{ID: \"\(.name)@\(.version)\", Name: \"\(.name)\", Version: \"\(.version)\", License: \"MIT\", Locations: []ftypes.Location{{StartLine: , EndLine: }}},"' // locations are filled manually - composerLibs = []types.Library{ + composerPkgs = []ftypes.Package{ { - ID: "guzzlehttp/guzzle@6.5.8", - Name: "guzzlehttp/guzzle", - Version: "6.5.8", - License: "MIT", - Locations: []types.Location{ + ID: "guzzlehttp/guzzle@6.5.8", + Name: "guzzlehttp/guzzle", + Version: "6.5.8", + Licenses: []string{"MIT"}, + Locations: []ftypes.Location{ { StartLine: 9, EndLine: 123, @@ -29,11 +29,11 @@ var ( }, }, { - ID: "guzzlehttp/promises@1.5.2", - Name: "guzzlehttp/promises", - Version: "1.5.2", - License: "MIT", - Locations: []types.Location{ + ID: "guzzlehttp/promises@1.5.2", + Name: "guzzlehttp/promises", + Version: "1.5.2", + Licenses: []string{"MIT"}, + Locations: []ftypes.Location{ { StartLine: 124, EndLine: 207, @@ -41,11 +41,11 @@ var ( }, }, { - ID: "guzzlehttp/psr7@1.9.0", - Name: "guzzlehttp/psr7", - Version: "1.9.0", - License: "MIT", - Locations: []types.Location{ + ID: "guzzlehttp/psr7@1.9.0", + Name: "guzzlehttp/psr7", + Version: "1.9.0", + Licenses: []string{"MIT"}, + Locations: []ftypes.Location{ { StartLine: 208, EndLine: 317, @@ -53,11 +53,11 @@ var ( }, }, { - ID: "psr/http-message@1.0.1", - Name: "psr/http-message", - Version: "1.0.1", - License: "MIT", - Locations: []types.Location{ + ID: "psr/http-message@1.0.1", + Name: "psr/http-message", + Version: "1.0.1", + Licenses: []string{"MIT"}, + Locations: []ftypes.Location{ { StartLine: 318, EndLine: 370, @@ -65,11 +65,11 @@ var ( }, }, { - ID: "ralouphie/getallheaders@3.0.3", - Name: "ralouphie/getallheaders", - Version: "3.0.3", - License: "MIT", - Locations: []types.Location{ + ID: "ralouphie/getallheaders@3.0.3", + Name: "ralouphie/getallheaders", + Version: "3.0.3", + Licenses: []string{"MIT"}, + Locations: []ftypes.Location{ { StartLine: 371, EndLine: 414, @@ -77,11 +77,11 @@ var ( }, }, { - ID: "symfony/polyfill-intl-idn@v1.27.0", - Name: "symfony/polyfill-intl-idn", - Version: "v1.27.0", - License: "MIT", - Locations: []types.Location{ + ID: "symfony/polyfill-intl-idn@v1.27.0", + Name: "symfony/polyfill-intl-idn", + Version: "v1.27.0", + Licenses: []string{"MIT"}, + Locations: []ftypes.Location{ { StartLine: 415, EndLine: 501, @@ -89,11 +89,11 @@ var ( }, }, { - ID: "symfony/polyfill-intl-normalizer@v1.27.0", - Name: "symfony/polyfill-intl-normalizer", - Version: "v1.27.0", - License: "MIT", - Locations: []types.Location{ + ID: "symfony/polyfill-intl-normalizer@v1.27.0", + Name: "symfony/polyfill-intl-normalizer", + Version: "v1.27.0", + Licenses: []string{"MIT"}, + Locations: []ftypes.Location{ { StartLine: 502, EndLine: 585, @@ -101,11 +101,11 @@ var ( }, }, { - ID: "symfony/polyfill-php72@v1.27.0", - Name: "symfony/polyfill-php72", - Version: "v1.27.0", - License: "MIT", - Locations: []types.Location{ + ID: "symfony/polyfill-php72@v1.27.0", + Name: "symfony/polyfill-php72", + Version: "v1.27.0", + Licenses: []string{"MIT"}, + Locations: []ftypes.Location{ { StartLine: 586, EndLine: 661, @@ -114,7 +114,7 @@ var ( }, } // dependencies are filled manually - composerDeps = []types.Dependency{ + composerDeps = []ftypes.Dependency{ { ID: "guzzlehttp/guzzle@6.5.8", DependsOn: []string{ @@ -144,13 +144,13 @@ func TestParse(t *testing.T) { tests := []struct { name string file string - wantLibs []types.Library - wantDeps []types.Dependency + wantPkgs []ftypes.Package + wantDeps []ftypes.Dependency }{ { name: "happy path", file: "testdata/composer_happy.lock", - wantLibs: composerLibs, + wantPkgs: composerPkgs, wantDeps: composerDeps, }, } @@ -161,10 +161,10 @@ func TestParse(t *testing.T) { require.NoError(t, err) defer f.Close() - gotLibs, gotDeps, err := NewParser().Parse(f) + gotPkgs, gotDeps, err := NewParser().Parse(f) require.NoError(t, err) - assert.Equal(t, tt.wantLibs, gotLibs) + assert.Equal(t, tt.wantPkgs, gotPkgs) assert.Equal(t, tt.wantDeps, gotDeps) }) } diff --git a/pkg/dependency/parser/python/packaging/parse.go b/pkg/dependency/parser/python/packaging/parse.go index 495e0d4d78ab..c8376a8066f2 100644 --- a/pkg/dependency/parser/python/packaging/parse.go +++ b/pkg/dependency/parser/python/packaging/parse.go @@ -7,9 +7,10 @@ import ( "net/textproto" "strings" + "github.com/samber/lo" "golang.org/x/xerrors" - "github.com/aquasecurity/trivy/pkg/dependency/types" + ftypes "github.com/aquasecurity/trivy/pkg/fanal/types" "github.com/aquasecurity/trivy/pkg/log" xio "github.com/aquasecurity/trivy/pkg/x/io" ) @@ -18,7 +19,7 @@ type Parser struct { logger *log.Logger } -func NewParser() types.Parser { +func NewParser() *Parser { return &Parser{ logger: log.WithPrefix("python"), } @@ -26,7 +27,7 @@ func NewParser() types.Parser { // Parse parses egg and wheel metadata. // e.g. .egg-info/PKG-INFO and dist-info/METADATA -func (p *Parser) Parse(r xio.ReadSeekerAt) ([]types.Library, []types.Dependency, error) { +func (p *Parser) Parse(r xio.ReadSeekerAt) ([]ftypes.Package, []ftypes.Dependency, error) { rd := textproto.NewReader(bufio.NewReader(r)) h, err := rd.ReadMIMEHeader() if e := textproto.ProtocolError(""); errors.As(err, &e) { @@ -82,11 +83,11 @@ func (p *Parser) Parse(r xio.ReadSeekerAt) ([]types.Library, []types.Dependency, license = "file://" + h.Get("License-File") } - return []types.Library{ + return []ftypes.Package{ { - Name: name, - Version: version, - License: license, + Name: name, + Version: version, + Licenses: lo.Ternary(license != "", []string{license}, nil), }, }, nil, nil } diff --git a/pkg/dependency/parser/python/packaging/parse_test.go b/pkg/dependency/parser/python/packaging/parse_test.go index ee08c5bdca82..cde70dea19ce 100644 --- a/pkg/dependency/parser/python/packaging/parse_test.go +++ b/pkg/dependency/parser/python/packaging/parse_test.go @@ -8,14 +8,14 @@ import ( "github.com/stretchr/testify/require" "github.com/aquasecurity/trivy/pkg/dependency/parser/python/packaging" - "github.com/aquasecurity/trivy/pkg/dependency/types" + ftypes "github.com/aquasecurity/trivy/pkg/fanal/types" ) func TestParse(t *testing.T) { tests := []struct { name string input string - want []types.Library + want []ftypes.Package wantErr bool }{ // listing dependencies based on METADATA/PKG-INFO files @@ -33,16 +33,22 @@ func TestParse(t *testing.T) { // cd /usr/lib/python3.9/site-packages/setuptools-52.0.0-py3.9.egg-info/ // cat PKG-INFO | grep -e "^Name:" -e "^Version:" -e "^License:" | cut -d" " -f2- | \ // tr "\n" "\t" | awk -F "\t" '{printf("\{\""$1"\", \""$2"\", \""$3"\"\}\n")}' - want: []types.Library{{Name: "setuptools", Version: "51.3.3", License: "UNKNOWN"}}, + want: []ftypes.Package{ + { + Name: "setuptools", + Version: "51.3.3", + Licenses: []string{"UNKNOWN"}, + }, + }, }, { name: "egg PKG-INFO with description containing non-RFC 7230 bytes", input: "testdata/unidecode-egg-info.PKG-INFO", - want: []types.Library{ + want: []ftypes.Package{ { - Name: "Unidecode", - Version: "0.4.1", - License: "UNKNOWN", + Name: "Unidecode", + Version: "0.4.1", + Licenses: []string{"UNKNOWN"}, }, }, }, @@ -55,7 +61,13 @@ func TestParse(t *testing.T) { // cd /usr/lib/python3.9/site-packages/ // cat distlib-0.3.1-py3.9.egg-info | grep -e "^Name:" -e "^Version:" -e "^License:" | cut -d" " -f2- | \ // tr "\n" "\t" | awk -F "\t" '{printf("\{\""$1"\", \""$2"\", \""$3"\"\}\n")}' - want: []types.Library{{Name: "distlib", Version: "0.3.1", License: "Python license"}}, + want: []ftypes.Package{ + { + Name: "distlib", + Version: "0.3.1", + Licenses: []string{"Python license"}, + }, + }, }, { name: "wheel METADATA", @@ -67,31 +79,53 @@ func TestParse(t *testing.T) { // find dist-infos/ | grep -v METADATA | xargs rm -R // for single METADATA file with known name - // cat "{{ libname }}.METADATA | grep -e "^Name:" -e "^Version:" -e "^License:" | cut -d" " -f2- | tr "\n" "\t" | awk -F "\t" '{printf("\{\""$1"\", \""$2"\", \""$3"\"\}\n")}' - want: []types.Library{{Name: "simple", Version: "0.1.0", License: ""}}, + // cat "{{ libname }}.METADATA | grep -e "^Name:" -e "^Version:" -e "^Licenses: []string{" | cut -d" " -f2- | tr "\n" "\t" | awk -F "\t" '{printf("\{\""$1"\"}, \""$2"\", \""$3"\"\}\n")}' + want: []ftypes.Package{ + { + Name: "simple", + Version: "0.1.0", + Licenses: nil, + }, + }, }, { name: "wheel METADATA", // for single METADATA file with known name - // cat "{{ libname }}.METADATA | grep -e "^Name:" -e "^Version:" -e "^License:" | cut -d" " -f2- | tr "\n" "\t" | awk -F "\t" '{printf("\{\""$1"\", \""$2"\", \""$3"\"\}\n")}' + // cat "{{ libname }}.METADATA | grep -e "^Name:" -e "^Version:" -e "^Licenses: []string{" | cut -d" " -f2- | tr "\n" "\t" | awk -F "\t" '{printf("\{\""$1"\"}, \""$2"\", \""$3"\"\}\n")}' input: "testdata/distlib-0.3.1.METADATA", - want: []types.Library{{Name: "distlib", Version: "0.3.1", License: "Python Software Foundation License"}}, + want: []ftypes.Package{ + { + Name: "distlib", + Version: "0.3.1", + Licenses: []string{"Python Software Foundation License"}, + }, + }, }, { name: "wheel METADATA", // Input defines "Classifier: License" but it ends at "OSI Approved" which doesn't define any specific license, thus "License" field is added to results input: "testdata/asyncssh-2.14.2.METADATA", - want: []types.Library{{Name: "asyncssh", Version: "2.14.2", License: "Eclipse Public License v2.0"}}, + want: []ftypes.Package{ + { + Name: "asyncssh", + Version: "2.14.2", + Licenses: []string{"Eclipse Public License v2.0"}, + }, + }, }, { name: "wheel METADATA", // Input defines multiple "Classifier: License" input: "testdata/pyphen-0.14.0.METADATA", - want: []types.Library{ - {Name: "pyphen", Version: "0.14.0", License: "GNU General Public License v2 or later (GPLv2+), GNU Lesser General Public License v2 or later (LGPLv2+), Mozilla Public License 1.1 (MPL 1.1)"}, + want: []ftypes.Package{ + { + Name: "pyphen", + Version: "0.14.0", + Licenses: []string{"GNU General Public License v2 or later (GPLv2+), GNU Lesser General Public License v2 or later (LGPLv2+), Mozilla Public License 1.1 (MPL 1.1)"}, + }, }, }, { @@ -102,33 +136,33 @@ func TestParse(t *testing.T) { { name: "with License-Expression field", input: "testdata/iniconfig-2.0.0.METADATA", - want: []types.Library{ + want: []ftypes.Package{ { - Name: "iniconfig", - Version: "2.0.0", - License: "MIT", + Name: "iniconfig", + Version: "2.0.0", + Licenses: []string{"MIT"}, }, }, }, { name: "with an empty license field but with license in Classifier", input: "testdata/zipp-3.12.1.METADATA", - want: []types.Library{ + want: []ftypes.Package{ { - Name: "zipp", - Version: "3.12.1", - License: "MIT License", + Name: "zipp", + Version: "3.12.1", + Licenses: []string{"MIT License"}, }, }, }, { name: "without licenses, but with a license file (a license in Classifier was removed)", input: "testdata/networkx-3.0.METADATA", - want: []types.Library{ + want: []ftypes.Package{ { - Name: "networkx", - Version: "3.0", - License: "file://LICENSE.txt", + Name: "networkx", + Version: "3.0", + Licenses: []string{"file://LICENSE.txt"}, }, }, }, diff --git a/pkg/dependency/parser/python/pip/parse.go b/pkg/dependency/parser/python/pip/parse.go index 4d4f893d63c0..00eee4349b0b 100644 --- a/pkg/dependency/parser/python/pip/parse.go +++ b/pkg/dependency/parser/python/pip/parse.go @@ -10,7 +10,7 @@ import ( "golang.org/x/text/transform" "golang.org/x/xerrors" - "github.com/aquasecurity/trivy/pkg/dependency/types" + ftypes "github.com/aquasecurity/trivy/pkg/fanal/types" xio "github.com/aquasecurity/trivy/pkg/x/io" ) @@ -24,11 +24,11 @@ const ( type Parser struct{} -func NewParser() types.Parser { +func NewParser() *Parser { return &Parser{} } -func (p *Parser) Parse(r xio.ReadSeekerAt) ([]types.Library, []types.Dependency, error) { +func (p *Parser) Parse(r xio.ReadSeekerAt) ([]ftypes.Package, []ftypes.Dependency, error) { // `requirements.txt` can use byte order marks (BOM) // e.g. on Windows `requirements.txt` can use UTF-16LE with BOM // We need to override them to avoid the file being read incorrectly @@ -36,7 +36,7 @@ func (p *Parser) Parse(r xio.ReadSeekerAt) ([]types.Library, []types.Dependency, decodedReader := transform.NewReader(r, transformer) scanner := bufio.NewScanner(decodedReader) - var libs []types.Library + var pkgs []ftypes.Package for scanner.Scan() { line := scanner.Text() line = strings.ReplaceAll(line, " ", "") @@ -49,7 +49,7 @@ func (p *Parser) Parse(r xio.ReadSeekerAt) ([]types.Library, []types.Dependency, if len(s) != 2 { continue } - libs = append(libs, types.Library{ + pkgs = append(pkgs, ftypes.Package{ Name: s[0], Version: s[1], }) @@ -57,7 +57,7 @@ func (p *Parser) Parse(r xio.ReadSeekerAt) ([]types.Library, []types.Dependency, if err := scanner.Err(); err != nil { return nil, nil, xerrors.Errorf("scan error: %w", err) } - return libs, nil, nil + return pkgs, nil, nil } func rStripByKey(line, key string) string { diff --git a/pkg/dependency/parser/python/pip/parse_test.go b/pkg/dependency/parser/python/pip/parse_test.go index a3a183f94a8e..d887205fb148 100644 --- a/pkg/dependency/parser/python/pip/parse_test.go +++ b/pkg/dependency/parser/python/pip/parse_test.go @@ -8,13 +8,13 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - "github.com/aquasecurity/trivy/pkg/dependency/types" + ftypes "github.com/aquasecurity/trivy/pkg/fanal/types" ) func TestParse(t *testing.T) { vectors := []struct { file string - want []types.Library + want []ftypes.Package }{ { file: "testdata/requirements_flask.txt", diff --git a/pkg/dependency/parser/python/pip/parse_testcase.go b/pkg/dependency/parser/python/pip/parse_testcase.go index 45642d47f2fa..dc119c3ba054 100644 --- a/pkg/dependency/parser/python/pip/parse_testcase.go +++ b/pkg/dependency/parser/python/pip/parse_testcase.go @@ -1,9 +1,9 @@ package pip -import "github.com/aquasecurity/trivy/pkg/dependency/types" +import ftypes "github.com/aquasecurity/trivy/pkg/fanal/types" var ( - requirementsFlask = []types.Library{ + requirementsFlask = []ftypes.Package{ {Name: "click", Version: "8.0.0"}, {Name: "Flask", Version: "2.0.0"}, {Name: "itsdangerous", Version: "2.0.0"}, @@ -12,45 +12,45 @@ var ( {Name: "Werkzeug", Version: "2.0.0"}, } - requirementsComments = []types.Library{ + requirementsComments = []ftypes.Package{ {Name: "click", Version: "8.0.0"}, {Name: "Flask", Version: "2.0.0"}, {Name: "Jinja2", Version: "3.0.0"}, {Name: "MarkupSafe", Version: "2.0.0"}, } - requirementsSpaces = []types.Library{ + requirementsSpaces = []ftypes.Package{ {Name: "click", Version: "8.0.0"}, {Name: "Flask", Version: "2.0.0"}, {Name: "itsdangerous", Version: "2.0.0"}, {Name: "Jinja2", Version: "3.0.0"}, } - requirementsNoVersion = []types.Library{ + requirementsNoVersion = []ftypes.Package{ {Name: "Flask", Version: "2.0.0"}, } - requirementsOperator = []types.Library{ + requirementsOperator = []ftypes.Package{ {Name: "Django", Version: "2.3.4"}, {Name: "SomeProject", Version: "5.4"}, } - requirementsHash = []types.Library{ + requirementsHash = []ftypes.Package{ {Name: "FooProject", Version: "1.2"}, {Name: "Jinja2", Version: "3.0.0"}, } - requirementsHyphens = []types.Library{ + requirementsHyphens = []ftypes.Package{ {Name: "oauth2-client", Version: "4.0.0"}, {Name: "python-gitlab", Version: "2.0.0"}, } - requirementsExtras = []types.Library{ + requirementsExtras = []ftypes.Package{ {Name: "pyjwt", Version: "2.1.0"}, {Name: "celery", Version: "4.4.7"}, } - requirementsUtf16le = []types.Library{ + requirementsUtf16le = []ftypes.Package{ {Name: "attrs", Version: "20.3.0"}, } ) diff --git a/pkg/dependency/parser/python/pipenv/parse.go b/pkg/dependency/parser/python/pipenv/parse.go index 70332764195e..8fbb70132c05 100644 --- a/pkg/dependency/parser/python/pipenv/parse.go +++ b/pkg/dependency/parser/python/pipenv/parse.go @@ -7,7 +7,7 @@ import ( "github.com/liamg/jfather" "golang.org/x/xerrors" - "github.com/aquasecurity/trivy/pkg/dependency/types" + ftypes "github.com/aquasecurity/trivy/pkg/fanal/types" xio "github.com/aquasecurity/trivy/pkg/x/io" ) @@ -22,11 +22,11 @@ type dependency struct { type Parser struct{} -func NewParser() types.Parser { +func NewParser() *Parser { return &Parser{} } -func (p *Parser) Parse(r xio.ReadSeekerAt) ([]types.Library, []types.Dependency, error) { +func (p *Parser) Parse(r xio.ReadSeekerAt) ([]ftypes.Package, []ftypes.Dependency, error) { var lockFile lockFile input, err := io.ReadAll(r) if err != nil { @@ -36,20 +36,20 @@ func (p *Parser) Parse(r xio.ReadSeekerAt) ([]types.Library, []types.Dependency, return nil, nil, xerrors.Errorf("failed to decode Pipenv.lock: %w", err) } - var libs []types.Library - for pkgName, dependency := range lockFile.Default { - libs = append(libs, types.Library{ + var pkgs []ftypes.Package + for pkgName, dep := range lockFile.Default { + pkgs = append(pkgs, ftypes.Package{ Name: pkgName, - Version: strings.TrimLeft(dependency.Version, "="), - Locations: []types.Location{ + Version: strings.TrimLeft(dep.Version, "="), + Locations: []ftypes.Location{ { - StartLine: dependency.StartLine, - EndLine: dependency.EndLine, + StartLine: dep.StartLine, + EndLine: dep.EndLine, }, }, }) } - return libs, nil, nil + return pkgs, nil, nil } // UnmarshalJSONWithMetadata needed to detect start and end lines of deps diff --git a/pkg/dependency/parser/python/pipenv/parse_test.go b/pkg/dependency/parser/python/pipenv/parse_test.go index 03fbe573ee7b..db578110a626 100644 --- a/pkg/dependency/parser/python/pipenv/parse_test.go +++ b/pkg/dependency/parser/python/pipenv/parse_test.go @@ -4,19 +4,18 @@ import ( "os" "path" "sort" - "strings" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - "github.com/aquasecurity/trivy/pkg/dependency/types" + ftypes "github.com/aquasecurity/trivy/pkg/fanal/types" ) func TestParse(t *testing.T) { vectors := []struct { file string // Test input file - want []types.Library + want []ftypes.Package }{ { file: "testdata/Pipfile_normal.lock", @@ -40,21 +39,8 @@ func TestParse(t *testing.T) { got, _, err := NewParser().Parse(f) require.NoError(t, err) - sort.Slice(got, func(i, j int) bool { - ret := strings.Compare(got[i].Name, got[j].Name) - if ret == 0 { - return got[i].Version < got[j].Version - } - return ret < 0 - }) - - sort.Slice(v.want, func(i, j int) bool { - ret := strings.Compare(v.want[i].Name, v.want[j].Name) - if ret == 0 { - return v.want[i].Version < v.want[j].Version - } - return ret < 0 - }) + sort.Sort(ftypes.Packages(got)) + sort.Sort(ftypes.Packages(v.want)) assert.Equal(t, v.want, got) }) diff --git a/pkg/dependency/parser/python/pipenv/parse_testcase.go b/pkg/dependency/parser/python/pipenv/parse_testcase.go index 6a611944d3eb..6d52afbfd861 100644 --- a/pkg/dependency/parser/python/pipenv/parse_testcase.go +++ b/pkg/dependency/parser/python/pipenv/parse_testcase.go @@ -1,6 +1,6 @@ package pipenv -import "github.com/aquasecurity/trivy/pkg/dependency/types" +import ftypes "github.com/aquasecurity/trivy/pkg/fanal/types" var ( // docker run --name pipenv --rm -it python:3.9-alpine sh @@ -11,13 +11,13 @@ var ( // pipenv graph --json | jq -rc '.[] | "{\"\(.package.package_name | ascii_downcase)\", \"\(.package.installed_version)\", \"\"},"' // graph doesn't contain information about location of dependency in lock file. // add locations manually - pipenvNormal = []types.Library{ - {Name: "urllib3", Version: "1.24.2", Locations: []types.Location{{StartLine: 65, EndLine: 71}}}, - {Name: "requests", Version: "2.21.0", Locations: []types.Location{{StartLine: 57, EndLine: 64}}}, - {Name: "pyyaml", Version: "5.1", Locations: []types.Location{{StartLine: 40, EndLine: 56}}}, - {Name: "idna", Version: "2.8", Locations: []types.Location{{StartLine: 33, EndLine: 39}}}, - {Name: "chardet", Version: "3.0.4", Locations: []types.Location{{StartLine: 26, EndLine: 32}}}, - {Name: "certifi", Version: "2019.3.9", Locations: []types.Location{{StartLine: 19, EndLine: 25}}}, + pipenvNormal = []ftypes.Package{ + {Name: "urllib3", Version: "1.24.2", Locations: []ftypes.Location{{StartLine: 65, EndLine: 71}}}, + {Name: "requests", Version: "2.21.0", Locations: []ftypes.Location{{StartLine: 57, EndLine: 64}}}, + {Name: "pyyaml", Version: "5.1", Locations: []ftypes.Location{{StartLine: 40, EndLine: 56}}}, + {Name: "idna", Version: "2.8", Locations: []ftypes.Location{{StartLine: 33, EndLine: 39}}}, + {Name: "chardet", Version: "3.0.4", Locations: []ftypes.Location{{StartLine: 26, EndLine: 32}}}, + {Name: "certifi", Version: "2019.3.9", Locations: []ftypes.Location{{StartLine: 19, EndLine: 25}}}, } // docker run --name pipenv --rm -it python:3.9-alpine bash @@ -28,17 +28,17 @@ var ( // pipenv graph --json | jq -rc '.[] | "{\"\(.package.package_name | ascii_downcase)\", \"\(.package.installed_version)\", \"\"},"' // graph doesn't contain information about location of dependency in lock file. // add locations manually - pipenvDjango = []types.Library{ - {Name: "urllib3", Version: "1.24.2", Locations: []types.Location{{StartLine: 95, EndLine: 101}}}, - {Name: "sqlparse", Version: "0.3.0", Locations: []types.Location{{StartLine: 88, EndLine: 94}}}, - {Name: "requests", Version: "2.21.0", Locations: []types.Location{{StartLine: 80, EndLine: 87}}}, - {Name: "pyyaml", Version: "5.1", Locations: []types.Location{{StartLine: 63, EndLine: 79}}}, - {Name: "pytz", Version: "2019.1", Locations: []types.Location{{StartLine: 56, EndLine: 62}}}, - {Name: "idna", Version: "2.8", Locations: []types.Location{{StartLine: 49, EndLine: 55}}}, - {Name: "djangorestframework", Version: "3.9.3", Locations: []types.Location{{StartLine: 41, EndLine: 48}}}, - {Name: "django", Version: "2.2", Locations: []types.Location{{StartLine: 33, EndLine: 40}}}, - {Name: "chardet", Version: "3.0.4", Locations: []types.Location{{StartLine: 26, EndLine: 32}}}, - {Name: "certifi", Version: "2019.3.9", Locations: []types.Location{{StartLine: 19, EndLine: 25}}}, + pipenvDjango = []ftypes.Package{ + {Name: "urllib3", Version: "1.24.2", Locations: []ftypes.Location{{StartLine: 95, EndLine: 101}}}, + {Name: "sqlparse", Version: "0.3.0", Locations: []ftypes.Location{{StartLine: 88, EndLine: 94}}}, + {Name: "requests", Version: "2.21.0", Locations: []ftypes.Location{{StartLine: 80, EndLine: 87}}}, + {Name: "pyyaml", Version: "5.1", Locations: []ftypes.Location{{StartLine: 63, EndLine: 79}}}, + {Name: "pytz", Version: "2019.1", Locations: []ftypes.Location{{StartLine: 56, EndLine: 62}}}, + {Name: "idna", Version: "2.8", Locations: []ftypes.Location{{StartLine: 49, EndLine: 55}}}, + {Name: "djangorestframework", Version: "3.9.3", Locations: []ftypes.Location{{StartLine: 41, EndLine: 48}}}, + {Name: "django", Version: "2.2", Locations: []ftypes.Location{{StartLine: 33, EndLine: 40}}}, + {Name: "chardet", Version: "3.0.4", Locations: []ftypes.Location{{StartLine: 26, EndLine: 32}}}, + {Name: "certifi", Version: "2019.3.9", Locations: []ftypes.Location{{StartLine: 19, EndLine: 25}}}, } // docker run --name pipenv --rm -it python:3.9-alpine bash @@ -49,30 +49,30 @@ var ( // pipenv graph --json | jq -rc '.[] | "{\"\(.package.package_name | ascii_downcase)\", \"\(.package.installed_version)\", \"\"},"' // graph doesn't contain information about location of dependency in lock file. // add locations manually - pipenvMany = []types.Library{ - {Name: "urllib3", Version: "1.24.2", Locations: []types.Location{{StartLine: 237, EndLine: 244}}}, - {Name: "sqlparse", Version: "0.3.0", Locations: []types.Location{{StartLine: 230, EndLine: 236}}}, - {Name: "six", Version: "1.12.0", Locations: []types.Location{{StartLine: 222, EndLine: 229}}}, - {Name: "simplejson", Version: "3.16.0", Locations: []types.Location{{StartLine: 204, EndLine: 221}}}, - {Name: "s3transfer", Version: "0.2.0", Locations: []types.Location{{StartLine: 197, EndLine: 203}}}, - {Name: "rsa", Version: "3.4.2", Locations: []types.Location{{StartLine: 190, EndLine: 196}}}, - {Name: "requests", Version: "2.21.0", Locations: []types.Location{{StartLine: 182, EndLine: 189}}}, - {Name: "pyyaml", Version: "3.13", Locations: []types.Location{{StartLine: 165, EndLine: 181}}}, - {Name: "pytz", Version: "2019.1", Locations: []types.Location{{StartLine: 158, EndLine: 164}}}, - {Name: "python-dateutil", Version: "2.8.0", Locations: []types.Location{{StartLine: 150, EndLine: 157}}}, - {Name: "pyasn1", Version: "0.4.5", Locations: []types.Location{{StartLine: 142, EndLine: 149}}}, - {Name: "markupsafe", Version: "1.1.1", Locations: []types.Location{{StartLine: 109, EndLine: 141}}}, - {Name: "jmespath", Version: "0.9.4", Locations: []types.Location{{StartLine: 102, EndLine: 108}}}, - {Name: "jinja2", Version: "2.10.1", Locations: []types.Location{{StartLine: 94, EndLine: 101}}}, - {Name: "idna", Version: "2.8", Locations: []types.Location{{StartLine: 87, EndLine: 93}}}, - {Name: "framework", Version: "0.1.0", Locations: []types.Location{{StartLine: 80, EndLine: 86}}}, - {Name: "docutils", Version: "0.14", Locations: []types.Location{{StartLine: 72, EndLine: 79}}}, - {Name: "djangorestframework", Version: "3.9.3", Locations: []types.Location{{StartLine: 64, EndLine: 71}}}, - {Name: "django", Version: "2.2", Locations: []types.Location{{StartLine: 56, EndLine: 63}}}, - {Name: "colorama", Version: "0.3.9", Locations: []types.Location{{StartLine: 49, EndLine: 55}}}, - {Name: "chardet", Version: "3.0.4", Locations: []types.Location{{StartLine: 42, EndLine: 48}}}, - {Name: "certifi", Version: "2019.3.9", Locations: []types.Location{{StartLine: 35, EndLine: 41}}}, - {Name: "botocore", Version: "1.12.137", Locations: []types.Location{{StartLine: 27, EndLine: 34}}}, - {Name: "awscli", Version: "1.16.147", Locations: []types.Location{{StartLine: 19, EndLine: 26}}}, + pipenvMany = []ftypes.Package{ + {Name: "urllib3", Version: "1.24.2", Locations: []ftypes.Location{{StartLine: 237, EndLine: 244}}}, + {Name: "sqlparse", Version: "0.3.0", Locations: []ftypes.Location{{StartLine: 230, EndLine: 236}}}, + {Name: "six", Version: "1.12.0", Locations: []ftypes.Location{{StartLine: 222, EndLine: 229}}}, + {Name: "simplejson", Version: "3.16.0", Locations: []ftypes.Location{{StartLine: 204, EndLine: 221}}}, + {Name: "s3transfer", Version: "0.2.0", Locations: []ftypes.Location{{StartLine: 197, EndLine: 203}}}, + {Name: "rsa", Version: "3.4.2", Locations: []ftypes.Location{{StartLine: 190, EndLine: 196}}}, + {Name: "requests", Version: "2.21.0", Locations: []ftypes.Location{{StartLine: 182, EndLine: 189}}}, + {Name: "pyyaml", Version: "3.13", Locations: []ftypes.Location{{StartLine: 165, EndLine: 181}}}, + {Name: "pytz", Version: "2019.1", Locations: []ftypes.Location{{StartLine: 158, EndLine: 164}}}, + {Name: "python-dateutil", Version: "2.8.0", Locations: []ftypes.Location{{StartLine: 150, EndLine: 157}}}, + {Name: "pyasn1", Version: "0.4.5", Locations: []ftypes.Location{{StartLine: 142, EndLine: 149}}}, + {Name: "markupsafe", Version: "1.1.1", Locations: []ftypes.Location{{StartLine: 109, EndLine: 141}}}, + {Name: "jmespath", Version: "0.9.4", Locations: []ftypes.Location{{StartLine: 102, EndLine: 108}}}, + {Name: "jinja2", Version: "2.10.1", Locations: []ftypes.Location{{StartLine: 94, EndLine: 101}}}, + {Name: "idna", Version: "2.8", Locations: []ftypes.Location{{StartLine: 87, EndLine: 93}}}, + {Name: "framework", Version: "0.1.0", Locations: []ftypes.Location{{StartLine: 80, EndLine: 86}}}, + {Name: "docutils", Version: "0.14", Locations: []ftypes.Location{{StartLine: 72, EndLine: 79}}}, + {Name: "djangorestframework", Version: "3.9.3", Locations: []ftypes.Location{{StartLine: 64, EndLine: 71}}}, + {Name: "django", Version: "2.2", Locations: []ftypes.Location{{StartLine: 56, EndLine: 63}}}, + {Name: "colorama", Version: "0.3.9", Locations: []ftypes.Location{{StartLine: 49, EndLine: 55}}}, + {Name: "chardet", Version: "3.0.4", Locations: []ftypes.Location{{StartLine: 42, EndLine: 48}}}, + {Name: "certifi", Version: "2019.3.9", Locations: []ftypes.Location{{StartLine: 35, EndLine: 41}}}, + {Name: "botocore", Version: "1.12.137", Locations: []ftypes.Location{{StartLine: 27, EndLine: 34}}}, + {Name: "awscli", Version: "1.16.147", Locations: []ftypes.Location{{StartLine: 19, EndLine: 26}}}, } ) diff --git a/pkg/dependency/parser/python/poetry/parse.go b/pkg/dependency/parser/python/poetry/parse.go index 30708cc67add..b7a365a17488 100644 --- a/pkg/dependency/parser/python/poetry/parse.go +++ b/pkg/dependency/parser/python/poetry/parse.go @@ -9,7 +9,6 @@ import ( version "github.com/aquasecurity/go-pep440-version" "github.com/aquasecurity/trivy/pkg/dependency" - "github.com/aquasecurity/trivy/pkg/dependency/types" ftypes "github.com/aquasecurity/trivy/pkg/fanal/types" "github.com/aquasecurity/trivy/pkg/log" xio "github.com/aquasecurity/trivy/pkg/x/io" @@ -39,61 +38,61 @@ func NewParser() *Parser { } } -func (p *Parser) Parse(r xio.ReadSeekerAt) ([]types.Library, []types.Dependency, error) { +func (p *Parser) Parse(r xio.ReadSeekerAt) ([]ftypes.Package, []ftypes.Dependency, error) { var lockfile Lockfile if _, err := toml.NewDecoder(r).Decode(&lockfile); err != nil { return nil, nil, xerrors.Errorf("failed to decode poetry.lock: %w", err) } // Keep all installed versions - libVersions := p.parseVersions(lockfile) + pkgVersions := p.parseVersions(lockfile) - var libs []types.Library - var deps []types.Dependency + var pkgs []ftypes.Package + var deps []ftypes.Dependency for _, pkg := range lockfile.Packages { if pkg.Category == "dev" { continue } pkgID := packageID(pkg.Name, pkg.Version) - libs = append(libs, types.Library{ + pkgs = append(pkgs, ftypes.Package{ ID: pkgID, Name: pkg.Name, Version: pkg.Version, }) - dependsOn := p.parseDependencies(pkg.Dependencies, libVersions) + dependsOn := p.parseDependencies(pkg.Dependencies, pkgVersions) if len(dependsOn) != 0 { - deps = append(deps, types.Dependency{ + deps = append(deps, ftypes.Dependency{ ID: pkgID, DependsOn: dependsOn, }) } } - return libs, deps, nil + return pkgs, deps, nil } -// parseVersions stores all installed versions of libraries for use in dependsOn -// as the dependencies of libraries use version range. +// parseVersions stores all installed versions of packages for use in dependsOn +// as the dependencies of packages use version range. func (p *Parser) parseVersions(lockfile Lockfile) map[string][]string { - libVersions := make(map[string][]string) + pkgVersions := make(map[string][]string) for _, pkg := range lockfile.Packages { if pkg.Category == "dev" { continue } - if vers, ok := libVersions[pkg.Name]; ok { - libVersions[pkg.Name] = append(vers, pkg.Version) + if vers, ok := pkgVersions[pkg.Name]; ok { + pkgVersions[pkg.Name] = append(vers, pkg.Version) } else { - libVersions[pkg.Name] = []string{pkg.Version} + pkgVersions[pkg.Name] = []string{pkg.Version} } } - return libVersions + return pkgVersions } -func (p *Parser) parseDependencies(deps map[string]any, libVersions map[string][]string) []string { +func (p *Parser) parseDependencies(deps map[string]any, pkgVersions map[string][]string) []string { var dependsOn []string for name, versRange := range deps { - if dep, err := p.parseDependency(name, versRange, libVersions); err != nil { + if dep, err := p.parseDependency(name, versRange, pkgVersions); err != nil { p.logger.Debug("Failed to parse poetry dependency", log.Err(err)) } else if dep != "" { dependsOn = append(dependsOn, dep) @@ -105,9 +104,9 @@ func (p *Parser) parseDependencies(deps map[string]any, libVersions map[string][ return dependsOn } -func (p *Parser) parseDependency(name string, versRange any, libVersions map[string][]string) (string, error) { +func (p *Parser) parseDependency(name string, versRange any, pkgVersions map[string][]string) (string, error) { name = normalizePkgName(name) - vers, ok := libVersions[name] + vers, ok := pkgVersions[name] if !ok { return "", xerrors.Errorf("no version found for %q", name) } diff --git a/pkg/dependency/parser/python/poetry/parse_test.go b/pkg/dependency/parser/python/poetry/parse_test.go index d7f7adf630eb..5ce44ddcea8f 100644 --- a/pkg/dependency/parser/python/poetry/parse_test.go +++ b/pkg/dependency/parser/python/poetry/parse_test.go @@ -8,34 +8,34 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - "github.com/aquasecurity/trivy/pkg/dependency/types" + ftypes "github.com/aquasecurity/trivy/pkg/fanal/types" ) func TestParser_Parse(t *testing.T) { tests := []struct { name string file string - wantLibs []types.Library - wantDeps []types.Dependency + wantPkgs []ftypes.Package + wantDeps []ftypes.Dependency wantErr assert.ErrorAssertionFunc }{ { name: "normal", file: "testdata/poetry_normal.lock", - wantLibs: poetryNormal, + wantPkgs: poetryNormal, wantErr: assert.NoError, }, { name: "many", file: "testdata/poetry_many.lock", - wantLibs: poetryMany, + wantPkgs: poetryMany, wantDeps: poetryManyDeps, wantErr: assert.NoError, }, { name: "flask", file: "testdata/poetry_flask.lock", - wantLibs: poetryFlask, + wantPkgs: poetryFlask, wantDeps: poetryFlaskDeps, wantErr: assert.NoError, }, @@ -47,11 +47,11 @@ func TestParser_Parse(t *testing.T) { defer f.Close() p := NewParser() - gotLibs, gotDeps, err := p.Parse(f) + gotPkgs, gotDeps, err := p.Parse(f) if !tt.wantErr(t, err, fmt.Sprintf("Parse(%v)", tt.file)) { return } - assert.Equalf(t, tt.wantLibs, gotLibs, "Parse(%v)", tt.file) + assert.Equalf(t, tt.wantPkgs, gotPkgs, "Parse(%v)", tt.file) assert.Equalf(t, tt.wantDeps, gotDeps, "Parse(%v)", tt.file) }) } @@ -62,7 +62,7 @@ func TestParseDependency(t *testing.T) { name string packageName string versionRange interface{} - libsVersions map[string][]string + pkgsVersions map[string][]string want string wantErr string }{ @@ -70,7 +70,7 @@ func TestParseDependency(t *testing.T) { name: "handle package name", packageName: "Test_project.Name", versionRange: "*", - libsVersions: map[string][]string{ + pkgsVersions: map[string][]string{ "test-project-name": {"1.0.0"}, }, want: "test-project-name@1.0.0", @@ -79,7 +79,7 @@ func TestParseDependency(t *testing.T) { name: "version range as string", packageName: "test", versionRange: ">=1.0.0", - libsVersions: map[string][]string{ + pkgsVersions: map[string][]string{ "test": {"2.0.0"}, }, want: "test@2.0.0", @@ -88,7 +88,7 @@ func TestParseDependency(t *testing.T) { name: "version range == *", packageName: "test", versionRange: "*", - libsVersions: map[string][]string{ + pkgsVersions: map[string][]string{ "test": {"3.0.0"}, }, want: "test@3.0.0", @@ -100,23 +100,23 @@ func TestParseDependency(t *testing.T) { "version": ">=4.8.3", "markers": "python_version < \"3.8\"", }, - libsVersions: map[string][]string{ + pkgsVersions: map[string][]string{ "test": {"5.0.0"}, }, want: "test@5.0.0", }, { - name: "libsVersions doesn't contain required version", + name: "pkgsVersions doesn't contain required version", packageName: "test", versionRange: ">=1.0.0", - libsVersions: map[string][]string{}, + pkgsVersions: map[string][]string{}, wantErr: "no version found", }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - got, err := NewParser().parseDependency(tt.packageName, tt.versionRange, tt.libsVersions) + got, err := NewParser().parseDependency(tt.packageName, tt.versionRange, tt.pkgsVersions) if tt.wantErr != "" { assert.ErrorContains(t, err, tt.wantErr) return diff --git a/pkg/dependency/parser/python/poetry/parse_testcase.go b/pkg/dependency/parser/python/poetry/parse_testcase.go index c6511c0bd089..3e54a465c2f1 100644 --- a/pkg/dependency/parser/python/poetry/parse_testcase.go +++ b/pkg/dependency/parser/python/poetry/parse_testcase.go @@ -1,6 +1,6 @@ package poetry -import "github.com/aquasecurity/trivy/pkg/dependency/types" +import ftypes "github.com/aquasecurity/trivy/pkg/fanal/types" var ( // docker run --name pipenv --rm -it python@sha256:e1141f10176d74d1a0e87a7c0a0a5a98dd98ec5ac12ce867768f40c6feae2fd9 sh @@ -10,7 +10,7 @@ var ( // poetry new normal && cd normal // poetry add pypi@2.1 // poetry show -a | awk '{gsub(/\(!\)/, ""); printf("{ID: \""$1"@"$2"\", Name: \""$1"\", Version: \""$2"\"},\n") }' - poetryNormal = []types.Library{ + poetryNormal = []ftypes.Package{ {ID: "pypi@2.1", Name: "pypi", Version: "2.1"}, } @@ -24,7 +24,7 @@ var ( // poetry show -a | awk '{gsub(/\(!\)/, ""); printf("{ID: \""$1"@"$2"\", Name: \""$1"\", Version: \""$2"\"},\n") }' // `--no-dev` flag uncorrected returns deps. Then need to remove `dev` deps manually // list of dev deps - cat poetry.lock | grep 'category = "dev"' -B 3 - poetryMany = []types.Library{ + poetryMany = []ftypes.Package{ {ID: "attrs@22.2.0", Name: "attrs", Version: "22.2.0"}, {ID: "backports-cached-property@1.0.2", Name: "backports-cached-property", Version: "1.0.2"}, {ID: "build@0.10.0", Name: "build", Version: "0.10.0"}, @@ -82,7 +82,7 @@ var ( } // cat poetry.lock | grep "\[package.dependencies\]" -B 3 -A 8 - it might help to complete this slice - poetryManyDeps = []types.Dependency{ + poetryManyDeps = []ftypes.Dependency{ {ID: "build@0.10.0", DependsOn: []string{"colorama@0.4.6", "importlib-metadata@6.0.0", "packaging@23.0", "pyproject-hooks@1.0.0", "tomli@2.0.1"}}, {ID: "cachecontrol@0.12.11", DependsOn: []string{"lockfile@0.12.2", "msgpack@1.0.4", "requests@2.28.2"}}, {ID: "cffi@1.15.1", DependsOn: []string{"pycparser@2.21"}}, @@ -115,7 +115,7 @@ var ( // poetry new web && cd web // poetry add flask@1.0.3 // poetry show -a | awk '{gsub(/\(!\)/, ""); printf("{ID: \""$1"@"$2"\", Name: \""$1"\", Version: \""$2"\"},\n") }' - poetryFlask = []types.Library{ + poetryFlask = []ftypes.Package{ {ID: "click@8.1.3", Name: "click", Version: "8.1.3"}, {ID: "colorama@0.4.6", Name: "colorama", Version: "0.4.6"}, {ID: "flask@1.0.3", Name: "flask", Version: "1.0.3"}, @@ -126,7 +126,7 @@ var ( } // cat poetry.lock | grep "\[package.dependencies\]" -B 3 -A 8 - it might help to complete this slice - poetryFlaskDeps = []types.Dependency{ + poetryFlaskDeps = []ftypes.Dependency{ {ID: "click@8.1.3", DependsOn: []string{"colorama@0.4.6"}}, {ID: "flask@1.0.3", DependsOn: []string{"click@8.1.3", "itsdangerous@2.1.2", "jinja2@3.1.2", "werkzeug@2.2.3"}}, {ID: "jinja2@3.1.2", DependsOn: []string{"markupsafe@2.1.2"}}, diff --git a/pkg/dependency/parser/ruby/bundler/parse.go b/pkg/dependency/parser/ruby/bundler/parse.go index 6c59eeca2d49..89f3a9ab4ab8 100644 --- a/pkg/dependency/parser/ruby/bundler/parse.go +++ b/pkg/dependency/parser/ruby/bundler/parse.go @@ -9,21 +9,20 @@ import ( "golang.org/x/xerrors" "github.com/aquasecurity/trivy/pkg/dependency" - "github.com/aquasecurity/trivy/pkg/dependency/types" ftypes "github.com/aquasecurity/trivy/pkg/fanal/types" xio "github.com/aquasecurity/trivy/pkg/x/io" ) type Parser struct{} -func NewParser() types.Parser { +func NewParser() *Parser { return &Parser{} } -func (p *Parser) Parse(r xio.ReadSeekerAt) ([]types.Library, []types.Dependency, error) { - libs := make(map[string]types.Library) +func (p *Parser) Parse(r xio.ReadSeekerAt) ([]ftypes.Package, []ftypes.Dependency, error) { + pkgs := make(map[string]ftypes.Package) var dependsOn, directDeps []string - var deps []types.Dependency + var deps []ftypes.Dependency var pkgID string lineNum := 1 @@ -34,7 +33,7 @@ func (p *Parser) Parse(r xio.ReadSeekerAt) ([]types.Library, []types.Dependency, // Parse dependencies if countLeadingSpace(line) == 4 { if len(dependsOn) > 0 { - deps = append(deps, types.Dependency{ + deps = append(deps, ftypes.Dependency{ ID: pkgID, DependsOn: dependsOn, }) @@ -49,12 +48,12 @@ func (p *Parser) Parse(r xio.ReadSeekerAt) ([]types.Library, []types.Dependency, version = strings.SplitN(version, "-", 2)[0] // drop platform (e.g. 1.13.6-x86_64-linux => 1.13.6) name := s[0] pkgID = packageID(name, version) - libs[name] = types.Library{ + pkgs[name] = ftypes.Package{ ID: pkgID, Name: name, Version: version, - Relationship: types.RelationshipIndirect, - Locations: []types.Location{ + Relationship: ftypes.RelationshipIndirect, + Locations: []ftypes.Location{ { StartLine: lineNum, EndLine: lineNum, @@ -77,7 +76,7 @@ func (p *Parser) Parse(r xio.ReadSeekerAt) ([]types.Library, []types.Dependency, } // append last dependency (if any) if len(dependsOn) > 0 { - deps = append(deps, types.Dependency{ + deps = append(deps, ftypes.Dependency{ ID: pkgID, DependsOn: dependsOn, }) @@ -85,17 +84,17 @@ func (p *Parser) Parse(r xio.ReadSeekerAt) ([]types.Library, []types.Dependency, // Identify which are direct dependencies for _, d := range directDeps { - if l, ok := libs[d]; ok { - l.Relationship = types.RelationshipDirect - libs[d] = l + if l, ok := pkgs[d]; ok { + l.Relationship = ftypes.RelationshipDirect + pkgs[d] = l } } for i, dep := range deps { dependsOn = make([]string, 0) for _, pkgName := range dep.DependsOn { - if lib, ok := libs[pkgName]; ok { - dependsOn = append(dependsOn, packageID(pkgName, lib.Version)) + if pkg, ok := pkgs[pkgName]; ok { + dependsOn = append(dependsOn, packageID(pkgName, pkg.Version)) } } deps[i].DependsOn = dependsOn @@ -104,11 +103,9 @@ func (p *Parser) Parse(r xio.ReadSeekerAt) ([]types.Library, []types.Dependency, return nil, nil, xerrors.Errorf("scan error: %w", err) } - libSlice := maps.Values(libs) - sort.Slice(libSlice, func(i, j int) bool { - return libSlice[i].Name < libSlice[j].Name - }) - return libSlice, deps, nil + pkgSlice := maps.Values(pkgs) + sort.Sort(ftypes.Packages(pkgSlice)) + return pkgSlice, deps, nil } func countLeadingSpace(line string) int { diff --git a/pkg/dependency/parser/ruby/bundler/parse_test.go b/pkg/dependency/parser/ruby/bundler/parse_test.go index f172225e6f02..0668bbd5bfbc 100644 --- a/pkg/dependency/parser/ruby/bundler/parse_test.go +++ b/pkg/dependency/parser/ruby/bundler/parse_test.go @@ -9,41 +9,17 @@ import ( "github.com/stretchr/testify/require" "github.com/aquasecurity/trivy/pkg/dependency/parser/ruby/bundler" - "github.com/aquasecurity/trivy/pkg/dependency/types" + ftypes "github.com/aquasecurity/trivy/pkg/fanal/types" ) var ( - NormalLibs = []types.Library{ - { - ID: "coderay@1.1.2", - Name: "coderay", - Version: "1.1.2", - Relationship: types.RelationshipIndirect, - Locations: []types.Location{ - { - StartLine: 4, - EndLine: 4, - }, - }, - }, - { - ID: "concurrent-ruby@1.1.5", - Name: "concurrent-ruby", - Version: "1.1.5", - Relationship: types.RelationshipIndirect, - Locations: []types.Location{ - { - StartLine: 5, - EndLine: 5, - }, - }, - }, + NormalPkgs = []ftypes.Package{ { ID: "dotenv@2.7.2", Name: "dotenv", Version: "2.7.2", - Relationship: types.RelationshipDirect, - Locations: []types.Location{ + Relationship: ftypes.RelationshipDirect, + Locations: []ftypes.Location{ { StartLine: 6, EndLine: 6, @@ -54,20 +30,56 @@ var ( ID: "faker@1.9.3", Name: "faker", Version: "1.9.3", - Relationship: types.RelationshipDirect, - Locations: []types.Location{ + Relationship: ftypes.RelationshipDirect, + Locations: []ftypes.Location{ { StartLine: 7, EndLine: 7, }, }, }, + { + ID: "pry@0.12.2", + Name: "pry", + Version: "0.12.2", + Relationship: ftypes.RelationshipDirect, + Locations: []ftypes.Location{ + { + StartLine: 12, + EndLine: 12, + }, + }, + }, + { + ID: "coderay@1.1.2", + Name: "coderay", + Version: "1.1.2", + Relationship: ftypes.RelationshipIndirect, + Locations: []ftypes.Location{ + { + StartLine: 4, + EndLine: 4, + }, + }, + }, + { + ID: "concurrent-ruby@1.1.5", + Name: "concurrent-ruby", + Version: "1.1.5", + Relationship: ftypes.RelationshipIndirect, + Locations: []ftypes.Location{ + { + StartLine: 5, + EndLine: 5, + }, + }, + }, { ID: "i18n@1.6.0", Name: "i18n", Version: "1.6.0", - Relationship: types.RelationshipIndirect, - Locations: []types.Location{ + Relationship: ftypes.RelationshipIndirect, + Locations: []ftypes.Location{ { StartLine: 9, EndLine: 9, @@ -78,28 +90,16 @@ var ( ID: "method_source@0.9.2", Name: "method_source", Version: "0.9.2", - Relationship: types.RelationshipIndirect, - Locations: []types.Location{ + Relationship: ftypes.RelationshipIndirect, + Locations: []ftypes.Location{ { StartLine: 11, EndLine: 11, }, }, }, - { - ID: "pry@0.12.2", - Name: "pry", - Version: "0.12.2", - Relationship: types.RelationshipDirect, - Locations: []types.Location{ - { - StartLine: 12, - EndLine: 12, - }, - }, - }, } - NormalDeps = []types.Dependency{ + NormalDeps = []ftypes.Dependency{ { ID: "faker@1.9.3", DependsOn: []string{"i18n@1.6.0"}, @@ -116,37 +116,13 @@ var ( }, }, } - Bundler2Libs = []types.Library{ - { - ID: "coderay@1.1.3", - Name: "coderay", - Version: "1.1.3", - Relationship: types.RelationshipIndirect, - Locations: []types.Location{ - { - StartLine: 4, - EndLine: 4, - }, - }, - }, - { - ID: "concurrent-ruby@1.1.10", - Name: "concurrent-ruby", - Version: "1.1.10", - Relationship: types.RelationshipIndirect, - Locations: []types.Location{ - { - StartLine: 5, - EndLine: 5, - }, - }, - }, + Bundler2Pkgs = []ftypes.Package{ { ID: "dotenv@2.7.6", Name: "dotenv", Version: "2.7.6", - Relationship: types.RelationshipDirect, - Locations: []types.Location{ + Relationship: ftypes.RelationshipDirect, + Locations: []ftypes.Location{ { StartLine: 6, EndLine: 6, @@ -157,64 +133,88 @@ var ( ID: "faker@2.21.0", Name: "faker", Version: "2.21.0", - Relationship: types.RelationshipDirect, - Locations: []types.Location{ + Relationship: ftypes.RelationshipDirect, + Locations: []ftypes.Location{ { StartLine: 7, EndLine: 7, }, }, }, - { - ID: "i18n@1.10.0", - Name: "i18n", - Version: "1.10.0", - Relationship: types.RelationshipIndirect, - Locations: []types.Location{ - { - StartLine: 9, - EndLine: 9, - }, - }, - }, { ID: "json@2.6.2", Name: "json", Version: "2.6.2", - Relationship: types.RelationshipDirect, - Locations: []types.Location{ + Relationship: ftypes.RelationshipDirect, + Locations: []ftypes.Location{ { StartLine: 11, EndLine: 11, }, }, }, - { - ID: "method_source@1.0.0", - Name: "method_source", - Version: "1.0.0", - Relationship: types.RelationshipIndirect, - Locations: []types.Location{ - { - StartLine: 12, - EndLine: 12, - }, - }, - }, { ID: "pry@0.14.1", Name: "pry", Version: "0.14.1", - Relationship: types.RelationshipDirect, - Locations: []types.Location{ + Relationship: ftypes.RelationshipDirect, + Locations: []ftypes.Location{ { StartLine: 13, EndLine: 13, }, }, }, + { + ID: "coderay@1.1.3", + Name: "coderay", + Version: "1.1.3", + Relationship: ftypes.RelationshipIndirect, + Locations: []ftypes.Location{ + { + StartLine: 4, + EndLine: 4, + }, + }, + }, + { + ID: "concurrent-ruby@1.1.10", + Name: "concurrent-ruby", + Version: "1.1.10", + Relationship: ftypes.RelationshipIndirect, + Locations: []ftypes.Location{ + { + StartLine: 5, + EndLine: 5, + }, + }, + }, + { + ID: "i18n@1.10.0", + Name: "i18n", + Version: "1.10.0", + Relationship: ftypes.RelationshipIndirect, + Locations: []ftypes.Location{ + { + StartLine: 9, + EndLine: 9, + }, + }, + }, + { + ID: "method_source@1.0.0", + Name: "method_source", + Version: "1.0.0", + Relationship: ftypes.RelationshipIndirect, + Locations: []ftypes.Location{ + { + StartLine: 12, + EndLine: 12, + }, + }, + }, } - Bundler2Deps = []types.Dependency{ + Bundler2Deps = []ftypes.Dependency{ { ID: "faker@2.21.0", DependsOn: []string{"i18n@1.10.0"}, @@ -237,28 +237,28 @@ func TestParser_Parse(t *testing.T) { tests := []struct { name string file string - wantLibs []types.Library - wantDeps []types.Dependency + wantPkgs []ftypes.Package + wantDeps []ftypes.Dependency wantErr assert.ErrorAssertionFunc }{ { name: "normal", file: "testdata/Gemfile_normal.lock", - wantLibs: NormalLibs, + wantPkgs: NormalPkgs, wantDeps: NormalDeps, wantErr: assert.NoError, }, { name: "bundler2", file: "testdata/Gemfile_bundler2.lock", - wantLibs: Bundler2Libs, + wantPkgs: Bundler2Pkgs, wantDeps: Bundler2Deps, wantErr: assert.NoError, }, { name: "malformed", file: "testdata/Gemfile_malformed.lock", - wantLibs: []types.Library{}, + wantPkgs: []ftypes.Package{}, wantErr: assert.NoError, }, } @@ -269,11 +269,11 @@ func TestParser_Parse(t *testing.T) { defer f.Close() p := &bundler.Parser{} - gotLibs, gotDeps, err := p.Parse(f) + gotPkgs, gotDeps, err := p.Parse(f) if !tt.wantErr(t, err, fmt.Sprintf("Parse(%v)", tt.file)) { return } - assert.Equalf(t, tt.wantLibs, gotLibs, "Parse(%v)", tt.file) + assert.Equalf(t, tt.wantPkgs, gotPkgs, "Parse(%v)", tt.file) assert.Equalf(t, tt.wantDeps, gotDeps, "Parse(%v)", tt.file) }) } diff --git a/pkg/dependency/parser/ruby/gemspec/parse.go b/pkg/dependency/parser/ruby/gemspec/parse.go index e458f6bacd0e..6fa0b140deda 100644 --- a/pkg/dependency/parser/ruby/gemspec/parse.go +++ b/pkg/dependency/parser/ruby/gemspec/parse.go @@ -8,7 +8,8 @@ import ( "golang.org/x/xerrors" - "github.com/aquasecurity/trivy/pkg/dependency/types" + ftypes "github.com/aquasecurity/trivy/pkg/fanal/types" + "github.com/aquasecurity/trivy/pkg/licensing" xio "github.com/aquasecurity/trivy/pkg/x/io" ) @@ -43,11 +44,11 @@ var ( type Parser struct{} -func NewParser() types.Parser { +func NewParser() *Parser { return &Parser{} } -func (p *Parser) Parse(r xio.ReadSeekerAt) (libs []types.Library, deps []types.Dependency, err error) { +func (p *Parser) Parse(r xio.ReadSeekerAt) (pkgs []ftypes.Package, deps []ftypes.Dependency, err error) { var newVar, name, version, license string scanner := bufio.NewScanner(r) @@ -94,11 +95,11 @@ func (p *Parser) Parse(r xio.ReadSeekerAt) (libs []types.Library, deps []types.D return nil, nil, xerrors.New("failed to parse gemspec") } - return []types.Library{ + return []ftypes.Package{ { - Name: name, - Version: version, - License: license, + Name: name, + Version: version, + Licenses: licensing.SplitLicenses(license), }, }, nil, nil } diff --git a/pkg/dependency/parser/ruby/gemspec/parse_test.go b/pkg/dependency/parser/ruby/gemspec/parse_test.go index 586c0ee6b941..292b6e7a74d7 100644 --- a/pkg/dependency/parser/ruby/gemspec/parse_test.go +++ b/pkg/dependency/parser/ruby/gemspec/parse_test.go @@ -8,50 +8,62 @@ import ( "github.com/stretchr/testify/require" "github.com/aquasecurity/trivy/pkg/dependency/parser/ruby/gemspec" - "github.com/aquasecurity/trivy/pkg/dependency/types" + ftypes "github.com/aquasecurity/trivy/pkg/fanal/types" ) func TestParse(t *testing.T) { tests := []struct { name string inputFile string - want []types.Library + want []ftypes.Package wantErr string }{ { name: "happy", inputFile: "testdata/normal00.gemspec", - want: []types.Library{{ - Name: "rake", - Version: "13.0.3", - License: "MIT", - }}, + want: []ftypes.Package{ + { + Name: "rake", + Version: "13.0.3", + Licenses: []string{"MIT"}, + }, + }, }, { name: "another variable name", inputFile: "testdata/normal01.gemspec", - want: []types.Library{{ - Name: "async", - Version: "1.25.0", - }}, + want: []ftypes.Package{ + { + Name: "async", + Version: "1.25.0", + }, + }, }, { name: "license", inputFile: "testdata/license.gemspec", - want: []types.Library{{ - Name: "async", - Version: "1.25.0", - License: "MIT", - }}, + want: []ftypes.Package{ + { + Name: "async", + Version: "1.25.0", + Licenses: []string{"MIT"}, + }, + }, }, { name: "multiple licenses", inputFile: "testdata/multiple_licenses.gemspec", - want: []types.Library{{ - Name: "test-unit", - Version: "3.3.7", - License: "Ruby, BSDL, PSFL", - }}, + want: []ftypes.Package{ + { + Name: "test-unit", + Version: "3.3.7", + Licenses: []string{ + "Ruby", + "BSDL", + "PSFL", + }, + }, + }, }, { name: "malformed variable name", diff --git a/pkg/dependency/parser/rust/binary/parse.go b/pkg/dependency/parser/rust/binary/parse.go index 793b626aa8d2..093299d0a4a0 100644 --- a/pkg/dependency/parser/rust/binary/parse.go +++ b/pkg/dependency/parser/rust/binary/parse.go @@ -7,7 +7,6 @@ import ( "golang.org/x/xerrors" "github.com/aquasecurity/trivy/pkg/dependency" - "github.com/aquasecurity/trivy/pkg/dependency/types" ftypes "github.com/aquasecurity/trivy/pkg/fanal/types" xio "github.com/aquasecurity/trivy/pkg/x/io" ) @@ -32,30 +31,30 @@ func convertError(err error) error { type Parser struct{} -func NewParser() types.Parser { +func NewParser() *Parser { return &Parser{} } // Parse scans files to try to report Rust crates and version injected into Rust binaries // via https://github.com/rust-secure-code/cargo-auditable -func (p *Parser) Parse(r xio.ReadSeekerAt) ([]types.Library, []types.Dependency, error) { +func (p *Parser) Parse(r xio.ReadSeekerAt) ([]ftypes.Package, []ftypes.Dependency, error) { info, err := rustaudit.GetDependencyInfo(r) if err != nil { return nil, nil, convertError(err) } - var libs []types.Library - var deps []types.Dependency + var pkgs []ftypes.Package + var deps []ftypes.Dependency for _, pkg := range info.Packages { if pkg.Kind != rustaudit.Runtime { continue } pkgID := packageID(pkg.Name, pkg.Version) - libs = append(libs, types.Library{ + pkgs = append(pkgs, ftypes.Package{ ID: pkgID, Name: pkg.Name, Version: pkg.Version, - Relationship: lo.Ternary(pkg.Root, types.RelationshipRoot, types.RelationshipUnknown), // TODO: Determine the direct dependencies by checking the dependencies of the root crate + Relationship: lo.Ternary(pkg.Root, ftypes.RelationshipRoot, ftypes.RelationshipUnknown), // TODO: Determine the direct dependencies by checking the dependencies of the root crate }) var childDeps []string @@ -66,14 +65,14 @@ func (p *Parser) Parse(r xio.ReadSeekerAt) ([]types.Library, []types.Dependency, } } if len(childDeps) > 0 { - deps = append(deps, types.Dependency{ + deps = append(deps, ftypes.Dependency{ ID: pkgID, DependsOn: childDeps, }) } } - return libs, deps, nil + return pkgs, deps, nil } func packageID(name, version string) string { diff --git a/pkg/dependency/parser/rust/binary/parse_test.go b/pkg/dependency/parser/rust/binary/parse_test.go index 8275a7ea2b72..d914a93ffb4b 100644 --- a/pkg/dependency/parser/rust/binary/parse_test.go +++ b/pkg/dependency/parser/rust/binary/parse_test.go @@ -8,28 +8,28 @@ import ( "github.com/stretchr/testify/require" "github.com/aquasecurity/trivy/pkg/dependency/parser/rust/binary" - "github.com/aquasecurity/trivy/pkg/dependency/types" + ftypes "github.com/aquasecurity/trivy/pkg/fanal/types" ) // Test binaries generated from cargo-auditable test fixture // https://github.com/rust-secure-code/cargo-auditable/tree/6b77151/cargo-auditable/tests/fixtures/workspace var ( - libs = []types.Library{ + pkgs = []ftypes.Package{ { ID: "crate_with_features@0.1.0", Name: "crate_with_features", Version: "0.1.0", - Relationship: types.RelationshipRoot, + Relationship: ftypes.RelationshipRoot, }, { ID: "library_crate@0.1.0", Name: "library_crate", Version: "0.1.0", - Relationship: types.RelationshipUnknown, + Relationship: ftypes.RelationshipUnknown, }, } - deps = []types.Dependency{ + deps = []ftypes.Dependency{ { ID: "crate_with_features@0.1.0", DependsOn: []string{"library_crate@0.1.0"}, @@ -41,26 +41,26 @@ func TestParse(t *testing.T) { tests := []struct { name string inputFile string - want []types.Library - wantDeps []types.Dependency + want []ftypes.Package + wantDeps []ftypes.Dependency wantErr string }{ { name: "ELF", inputFile: "testdata/test.elf", - want: libs, + want: pkgs, wantDeps: deps, }, { name: "PE", inputFile: "testdata/test.exe", - want: libs, + want: pkgs, wantDeps: deps, }, { name: "Mach-O", inputFile: "testdata/test.macho", - want: libs, + want: pkgs, wantDeps: deps, }, { diff --git a/pkg/dependency/parser/rust/cargo/parse.go b/pkg/dependency/parser/rust/cargo/parse.go index 2fd6686224bc..d3fbbce00bb4 100644 --- a/pkg/dependency/parser/rust/cargo/parse.go +++ b/pkg/dependency/parser/rust/cargo/parse.go @@ -10,7 +10,6 @@ import ( "golang.org/x/xerrors" "github.com/aquasecurity/trivy/pkg/dependency" - "github.com/aquasecurity/trivy/pkg/dependency/types" ftypes "github.com/aquasecurity/trivy/pkg/fanal/types" "github.com/aquasecurity/trivy/pkg/log" xio "github.com/aquasecurity/trivy/pkg/x/io" @@ -30,13 +29,13 @@ type Parser struct { logger *log.Logger } -func NewParser() types.Parser { +func NewParser() *Parser { return &Parser{ logger: log.WithPrefix("cargo"), } } -func (p *Parser) Parse(r xio.ReadSeekerAt) ([]types.Library, []types.Dependency, error) { +func (p *Parser) Parse(r xio.ReadSeekerAt) ([]ftypes.Package, []ftypes.Dependency, error) { var lockfile Lockfile decoder := toml.NewDecoder(r) if _, err := decoder.Decode(&lockfile); err != nil { @@ -52,21 +51,21 @@ func (p *Parser) Parse(r xio.ReadSeekerAt) ([]types.Library, []types.Dependency, lineNumIdx := pkgParser.parse() // We need to get version for unique dependencies for lockfile v3 from lockfile.Packages - pkgs := lo.SliceToMap(lockfile.Packages, func(pkg cargoPkg) (string, cargoPkg) { + pkgMap := lo.SliceToMap(lockfile.Packages, func(pkg cargoPkg) (string, cargoPkg) { return pkg.Name, pkg }) - var libs []types.Library - var deps []types.Dependency - for _, pkg := range lockfile.Packages { - pkgID := packageID(pkg.Name, pkg.Version) - lib := types.Library{ + var pkgs ftypes.Packages + var deps ftypes.Dependencies + for _, lpkg := range lockfile.Packages { + pkgID := packageID(lpkg.Name, lpkg.Version) + pkg := ftypes.Package{ ID: pkgID, - Name: pkg.Name, - Version: pkg.Version, + Name: lpkg.Name, + Version: lpkg.Version, } if pos, ok := lineNumIdx[pkgID]; ok { - lib.Locations = []types.Location{ + pkg.Locations = []ftypes.Location{ { StartLine: pos.start, EndLine: pos.end, @@ -74,17 +73,17 @@ func (p *Parser) Parse(r xio.ReadSeekerAt) ([]types.Library, []types.Dependency, } } - libs = append(libs, lib) - dep := p.parseDependencies(pkgID, pkg, pkgs) + pkgs = append(pkgs, pkg) + dep := p.parseDependencies(pkgID, lpkg, pkgMap) if dep != nil { deps = append(deps, *dep) } } - sort.Sort(types.Libraries(libs)) - sort.Sort(types.Dependencies(deps)) - return libs, deps, nil + sort.Sort(pkgs) + sort.Sort(deps) + return pkgs, deps, nil } -func (p *Parser) parseDependencies(pkgId string, pkg cargoPkg, pkgs map[string]cargoPkg) *types.Dependency { +func (p *Parser) parseDependencies(pkgId string, pkg cargoPkg, pkgs map[string]cargoPkg) *ftypes.Dependency { var dependOn []string for _, pkgDep := range pkg.Dependencies { @@ -118,7 +117,7 @@ func (p *Parser) parseDependencies(pkgId string, pkg cargoPkg, pkgs map[string]c } if len(dependOn) > 0 { sort.Strings(dependOn) - return &types.Dependency{ + return &ftypes.Dependency{ ID: pkgId, DependsOn: dependOn, } diff --git a/pkg/dependency/parser/rust/cargo/parse_test.go b/pkg/dependency/parser/rust/cargo/parse_test.go index 903cf0190a7d..8472f801d9d0 100644 --- a/pkg/dependency/parser/rust/cargo/parse_test.go +++ b/pkg/dependency/parser/rust/cargo/parse_test.go @@ -5,77 +5,339 @@ import ( "os" "path" "sort" - "strings" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - "github.com/aquasecurity/trivy/pkg/dependency/types" + ftypes "github.com/aquasecurity/trivy/pkg/fanal/types" ) var ( - cargoNormalLibs = []types.Library{ - {ID: "normal@0.1.0", Name: "normal", Version: "0.1.0", Locations: []types.Location{{StartLine: 8, EndLine: 13}}}, - {ID: "libc@0.2.54", Name: "libc", Version: "0.2.54", Locations: []types.Location{{StartLine: 3, EndLine: 6}}}, - {ID: "typemap@0.3.3", Name: "typemap", Version: "0.3.3", Locations: []types.Location{{StartLine: 20, EndLine: 26}}}, - {ID: "url@1.7.2", Name: "url", Version: "1.7.2", Locations: []types.Location{{StartLine: 43, EndLine: 51}}}, - {ID: "unsafe-any@0.4.2", Name: "unsafe-any", Version: "0.4.2", Locations: []types.Location{{StartLine: 15, EndLine: 18}}}, - {ID: "matches@0.1.8", Name: "matches", Version: "0.1.8", Locations: []types.Location{{StartLine: 33, EndLine: 36}}}, - {ID: "idna@0.1.5", Name: "idna", Version: "0.1.5", Locations: []types.Location{{StartLine: 28, EndLine: 31}}}, - {ID: "percent-encoding@1.0.1", Name: "percent-encoding", Version: "1.0.1", Locations: []types.Location{{StartLine: 38, EndLine: 41}}}, + cargoNormalPkgs = []ftypes.Package{ + { + ID: "normal@0.1.0", + Name: "normal", + Version: "0.1.0", + Locations: []ftypes.Location{ + { + StartLine: 8, + EndLine: 13, + }, + }, + }, + { + ID: "libc@0.2.54", + Name: "libc", + Version: "0.2.54", + Locations: []ftypes.Location{ + { + StartLine: 3, + EndLine: 6, + }, + }, + }, + { + ID: "typemap@0.3.3", + Name: "typemap", + Version: "0.3.3", + Locations: []ftypes.Location{ + { + StartLine: 20, + EndLine: 26, + }, + }, + }, + { + ID: "url@1.7.2", + Name: "url", + Version: "1.7.2", + Locations: []ftypes.Location{ + { + StartLine: 43, + EndLine: 51, + }, + }, + }, + { + ID: "unsafe-any@0.4.2", + Name: "unsafe-any", + Version: "0.4.2", + Locations: []ftypes.Location{ + { + StartLine: 15, + EndLine: 18, + }, + }, + }, + { + ID: "matches@0.1.8", + Name: "matches", + Version: "0.1.8", + Locations: []ftypes.Location{ + { + StartLine: 33, + EndLine: 36, + }, + }, + }, + { + ID: "idna@0.1.5", + Name: "idna", + Version: "0.1.5", + Locations: []ftypes.Location{ + { + StartLine: 28, + EndLine: 31, + }, + }, + }, + { + ID: "percent-encoding@1.0.1", + Name: "percent-encoding", + Version: "1.0.1", + Locations: []ftypes.Location{ + { + StartLine: 38, + EndLine: 41, + }, + }, + }, } - cargoNormalDeps = []types.Dependency{ + cargoNormalDeps = []ftypes.Dependency{ { ID: "normal@0.1.0", - DependsOn: []string{"libc@0.2.54"}}, + DependsOn: []string{"libc@0.2.54"}, + }, { ID: "typemap@0.3.3", DependsOn: []string{"unsafe-any@0.4.2"}, }, { - ID: "url@1.7.2", - DependsOn: []string{"idna@0.1.5", "matches@0.1.8", "percent-encoding@1.0.1"}, + ID: "url@1.7.2", + DependsOn: []string{ + "idna@0.1.5", + "matches@0.1.8", + "percent-encoding@1.0.1", + }, }, } - cargoMixedLibs = []types.Library{ - {ID: "normal@0.1.0", Name: "normal", Version: "0.1.0", Locations: []types.Location{{StartLine: 17, EndLine: 22}}}, - {ID: "libc@0.2.54", Name: "libc", Version: "0.2.54", Locations: []types.Location{{StartLine: 3, EndLine: 6}}}, - {ID: "typemap@0.3.3", Name: "typemap", Version: "0.3.3", Locations: []types.Location{{StartLine: 55, EndLine: 61}}}, - {ID: "url@1.7.2", Name: "url", Version: "1.7.2", Locations: []types.Location{{StartLine: 26, EndLine: 34}}}, - {ID: "unsafe-any@0.4.2", Name: "unsafe-any", Version: "0.4.2", Locations: []types.Location{{StartLine: 9, EndLine: 12}}}, - {ID: "matches@0.1.8", Name: "matches", Version: "0.1.8", Locations: []types.Location{{StartLine: 41, EndLine: 44}}}, - {ID: "idna@0.1.5", Name: "idna", Version: "0.1.5", Locations: []types.Location{{StartLine: 36, EndLine: 39}}}, - {ID: "percent-encoding@1.0.1", Name: "percent-encoding", Version: "1.0.1", Locations: []types.Location{{StartLine: 46, EndLine: 49}}}, + cargoMixedPkgs = []ftypes.Package{ + { + ID: "normal@0.1.0", + Name: "normal", + Version: "0.1.0", + Locations: []ftypes.Location{ + { + StartLine: 17, + EndLine: 22, + }, + }, + }, + { + ID: "libc@0.2.54", + Name: "libc", + Version: "0.2.54", + Locations: []ftypes.Location{ + { + StartLine: 3, + EndLine: 6, + }, + }, + }, + { + ID: "typemap@0.3.3", + Name: "typemap", + Version: "0.3.3", + Locations: []ftypes.Location{ + { + StartLine: 55, + EndLine: 61, + }, + }, + }, + { + ID: "url@1.7.2", + Name: "url", + Version: "1.7.2", + Locations: []ftypes.Location{ + { + StartLine: 26, + EndLine: 34, + }, + }, + }, + { + ID: "unsafe-any@0.4.2", + Name: "unsafe-any", + Version: "0.4.2", + Locations: []ftypes.Location{ + { + StartLine: 9, + EndLine: 12, + }, + }, + }, + { + ID: "matches@0.1.8", + Name: "matches", + Version: "0.1.8", + Locations: []ftypes.Location{ + { + StartLine: 41, + EndLine: 44, + }, + }, + }, + { + ID: "idna@0.1.5", + Name: "idna", + Version: "0.1.5", + Locations: []ftypes.Location{ + { + StartLine: 36, + EndLine: 39, + }, + }, + }, + { + ID: "percent-encoding@1.0.1", + Name: "percent-encoding", + Version: "1.0.1", + Locations: []ftypes.Location{ + { + StartLine: 46, + EndLine: 49, + }, + }, + }, } - - cargoV3Libs = []types.Library{ - {ID: "aho-corasick@0.7.20", Name: "aho-corasick", Version: "0.7.20", Locations: []types.Location{{StartLine: 5, EndLine: 12}}}, - {ID: "app@0.1.0", Name: "app", Version: "0.1.0", Locations: []types.Location{{StartLine: 14, EndLine: 21}}}, - {ID: "libc@0.2.140", Name: "libc", Version: "0.2.140", Locations: []types.Location{{StartLine: 23, EndLine: 27}}}, - {ID: "memchr@1.0.2", Name: "memchr", Version: "1.0.2", Locations: []types.Location{{StartLine: 29, EndLine: 36}}}, - {ID: "memchr@2.5.0", Name: "memchr", Version: "2.5.0", Locations: []types.Location{{StartLine: 38, EndLine: 42}}}, - {ID: "regex@1.7.3", Name: "regex", Version: "1.7.3", Locations: []types.Location{{StartLine: 44, EndLine: 53}}}, - {ID: "regex-syntax@0.5.6", Name: "regex-syntax", Version: "0.5.6", Locations: []types.Location{{StartLine: 55, EndLine: 62}}}, - {ID: "regex-syntax@0.6.29", Name: "regex-syntax", Version: "0.6.29", Locations: []types.Location{{StartLine: 64, EndLine: 68}}}, - {ID: "ucd-util@0.1.10", Name: "ucd-util", Version: "0.1.10", Locations: []types.Location{{StartLine: 70, EndLine: 74}}}, + cargoV3Pkgs = []ftypes.Package{ + { + ID: "aho-corasick@0.7.20", + Name: "aho-corasick", + Version: "0.7.20", + Locations: []ftypes.Location{ + { + StartLine: 5, + EndLine: 12, + }, + }, + }, + { + ID: "app@0.1.0", + Name: "app", + Version: "0.1.0", + Locations: []ftypes.Location{ + { + StartLine: 14, + EndLine: 21, + }, + }, + }, + { + ID: "libc@0.2.140", + Name: "libc", + Version: "0.2.140", + Locations: []ftypes.Location{ + { + StartLine: 23, + EndLine: 27, + }, + }, + }, + { + ID: "memchr@1.0.2", + Name: "memchr", + Version: "1.0.2", + Locations: []ftypes.Location{ + { + StartLine: 29, + EndLine: 36, + }, + }, + }, + { + ID: "memchr@2.5.0", + Name: "memchr", + Version: "2.5.0", + Locations: []ftypes.Location{ + { + StartLine: 38, + EndLine: 42, + }, + }, + }, + { + ID: "regex@1.7.3", + Name: "regex", + Version: "1.7.3", + Locations: []ftypes.Location{ + { + StartLine: 44, + EndLine: 53, + }, + }, + }, + { + ID: "regex-syntax@0.5.6", + Name: "regex-syntax", + Version: "0.5.6", + Locations: []ftypes.Location{ + { + StartLine: 55, + EndLine: 62, + }, + }, + }, + { + ID: "regex-syntax@0.6.29", + Name: "regex-syntax", + Version: "0.6.29", + Locations: []ftypes.Location{ + { + StartLine: 64, + EndLine: 68, + }, + }, + }, + { + ID: "ucd-util@0.1.10", + Name: "ucd-util", + Version: "0.1.10", + Locations: []ftypes.Location{ + { + StartLine: 70, + EndLine: 74, + }, + }, + }, } - cargoV3Deps = []types.Dependency{ + cargoV3Deps = []ftypes.Dependency{ { ID: "aho-corasick@0.7.20", - DependsOn: []string{"memchr@2.5.0"}}, + DependsOn: []string{"memchr@2.5.0"}, + }, { - ID: "app@0.1.0", - DependsOn: []string{"memchr@1.0.2", "regex-syntax@0.5.6", "regex@1.7.3"}, + ID: "app@0.1.0", + DependsOn: []string{ + "memchr@1.0.2", + "regex-syntax@0.5.6", + "regex@1.7.3", + }, }, { ID: "memchr@1.0.2", DependsOn: []string{"libc@0.2.140"}, }, { - ID: "regex@1.7.3", - DependsOn: []string{"aho-corasick@0.7.20", "memchr@2.5.0", "regex-syntax@0.6.29"}, + ID: "regex@1.7.3", + DependsOn: []string{ + "aho-corasick@0.7.20", + "memchr@2.5.0", + "regex-syntax@0.6.29", + }, }, { ID: "regex-syntax@0.5.6", @@ -87,25 +349,25 @@ var ( func TestParse(t *testing.T) { vectors := []struct { file string // Test input file - wantLibs []types.Library - wantDeps []types.Dependency + wantPkgs []ftypes.Package + wantDeps []ftypes.Dependency wantErr assert.ErrorAssertionFunc }{ { file: "testdata/cargo_normal.lock", - wantLibs: cargoNormalLibs, + wantPkgs: cargoNormalPkgs, wantDeps: cargoNormalDeps, wantErr: assert.NoError, }, { file: "testdata/cargo_mixed.lock", - wantLibs: cargoMixedLibs, + wantPkgs: cargoMixedPkgs, wantDeps: cargoNormalDeps, wantErr: assert.NoError, }, { file: "testdata/cargo_v3.lock", - wantLibs: cargoV3Libs, + wantPkgs: cargoV3Pkgs, wantDeps: cargoV3Deps, wantErr: assert.NoError, }, @@ -120,7 +382,7 @@ func TestParse(t *testing.T) { f, err := os.Open(v.file) require.NoError(t, err) - gotLibs, gotDeps, err := NewParser().Parse(f) + gotPkgs, gotDeps, err := NewParser().Parse(f) if !v.wantErr(t, err, fmt.Sprintf("Parse(%v)", v.file)) { return @@ -130,23 +392,10 @@ func TestParse(t *testing.T) { return } - sortLibs(v.wantLibs) - sortDeps(v.wantDeps) - - assert.Equalf(t, v.wantLibs, gotLibs, "Parse libraries(%v)", v.file) + sort.Sort(ftypes.Packages(v.wantPkgs)) + sort.Sort(ftypes.Dependencies(v.wantDeps)) + assert.Equalf(t, v.wantPkgs, gotPkgs, "Parse libraries(%v)", v.file) assert.Equalf(t, v.wantDeps, gotDeps, "Parse dependencies(%v)", v.file) }) } } - -func sortLibs(libs []types.Library) { - sort.Slice(libs, func(i, j int) bool { - return strings.Compare(libs[i].ID, libs[j].ID) < 0 - }) -} - -func sortDeps(deps []types.Dependency) { - sort.Slice(deps, func(i, j int) bool { - return strings.Compare(deps[i].ID, deps[j].ID) < 0 - }) -} diff --git a/pkg/dependency/parser/swift/cocoapods/parse.go b/pkg/dependency/parser/swift/cocoapods/parse.go index ae71bc09a3d7..eb5a960679f7 100644 --- a/pkg/dependency/parser/swift/cocoapods/parse.go +++ b/pkg/dependency/parser/swift/cocoapods/parse.go @@ -10,7 +10,6 @@ import ( "github.com/aquasecurity/trivy/pkg/dependency" "github.com/aquasecurity/trivy/pkg/dependency/parser/utils" - "github.com/aquasecurity/trivy/pkg/dependency/types" ftypes "github.com/aquasecurity/trivy/pkg/fanal/types" "github.com/aquasecurity/trivy/pkg/log" xio "github.com/aquasecurity/trivy/pkg/x/io" @@ -20,7 +19,7 @@ type Parser struct { logger *log.Logger } -func NewParser() types.Parser { +func NewParser() *Parser { return &Parser{ logger: log.WithPrefix("cocoapods"), } @@ -30,32 +29,32 @@ type lockFile struct { Pods []any `yaml:"PODS"` // pod can be string or map[string]interface{} } -func (p *Parser) Parse(r xio.ReadSeekerAt) ([]types.Library, []types.Dependency, error) { +func (p *Parser) Parse(r xio.ReadSeekerAt) ([]ftypes.Package, []ftypes.Dependency, error) { lock := &lockFile{} decoder := yaml.NewDecoder(r) if err := decoder.Decode(&lock); err != nil { return nil, nil, xerrors.Errorf("failed to decode cocoapods lock file: %s", err.Error()) } - parsedDeps := make(map[string]types.Library) // dependency name => Library - directDeps := make(map[string][]string) // dependency name => slice of child dependency names + parsedDeps := make(map[string]ftypes.Package) // dependency name => Package + directDeps := make(map[string][]string) // dependency name => slice of child dependency names for _, pod := range lock.Pods { switch dep := pod.(type) { case string: // dependency with version number - lib, err := parseDep(dep) + pkg, err := parseDep(dep) if err != nil { p.logger.Debug("Dependency parse error", log.Err(err)) continue } - parsedDeps[lib.Name] = lib + parsedDeps[pkg.Name] = pkg case map[string]interface{}: // dependency with its child dependencies for dep, childDeps := range dep { - lib, err := parseDep(dep) + pkg, err := parseDep(dep) if err != nil { p.logger.Debug("Dependency parse error", log.Err(err)) continue } - parsedDeps[lib.Name] = lib + parsedDeps[pkg.Name] = pkg children, ok := childDeps.([]interface{}) if !ok { @@ -67,30 +66,30 @@ func (p *Parser) Parse(r xio.ReadSeekerAt) ([]types.Library, []types.Dependency, if !ok { return nil, nil, xerrors.Errorf("must be string: %q", childDep) } - directDeps[lib.Name] = append(directDeps[lib.Name], strings.Fields(s)[0]) + directDeps[pkg.Name] = append(directDeps[pkg.Name], strings.Fields(s)[0]) } } } } - var deps []types.Dependency + var deps ftypes.Dependencies for dep, childDeps := range directDeps { var dependsOn []string // find versions for child dependencies for _, childDep := range childDeps { dependsOn = append(dependsOn, packageID(childDep, parsedDeps[childDep].Version)) } - deps = append(deps, types.Dependency{ + deps = append(deps, ftypes.Dependency{ ID: parsedDeps[dep].ID, DependsOn: dependsOn, }) } - sort.Sort(types.Dependencies(deps)) - return utils.UniqueLibraries(maps.Values(parsedDeps)), deps, nil + sort.Sort(deps) + return utils.UniquePackages(maps.Values(parsedDeps)), deps, nil } -func parseDep(dep string) (types.Library, error) { +func parseDep(dep string) (ftypes.Package, error) { // dep example: // 'AppCenter (4.2.0)' // direct dep examples: @@ -99,18 +98,18 @@ func parseDep(dep string) (types.Library, error) { // 'AppCenter/Analytics (-> 4.2.0)' ss := strings.Split(dep, " (") if len(ss) != 2 { - return types.Library{}, xerrors.Errorf("Unable to determine cocoapods dependency: %q", dep) + return ftypes.Package{}, xerrors.Errorf("Unable to determine cocoapods dependency: %q", dep) } name := ss[0] version := strings.Trim(strings.TrimSpace(ss[1]), "()") - lib := types.Library{ + pkg := ftypes.Package{ ID: packageID(name, version), Name: name, Version: version, } - return lib, nil + return pkg, nil } func packageID(name, version string) string { diff --git a/pkg/dependency/parser/swift/cocoapods/parse_test.go b/pkg/dependency/parser/swift/cocoapods/parse_test.go index 3a0823338713..f81b81929654 100644 --- a/pkg/dependency/parser/swift/cocoapods/parse_test.go +++ b/pkg/dependency/parser/swift/cocoapods/parse_test.go @@ -5,7 +5,7 @@ import ( "testing" "github.com/aquasecurity/trivy/pkg/dependency/parser/swift/cocoapods" - "github.com/aquasecurity/trivy/pkg/dependency/types" + ftypes "github.com/aquasecurity/trivy/pkg/fanal/types" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) @@ -14,13 +14,18 @@ func TestParse(t *testing.T) { tests := []struct { name string inputFile string // Test input file - wantLibs []types.Library - wantDeps []types.Dependency + wantPkgs []ftypes.Package + wantDeps []ftypes.Dependency }{ { name: "happy path", inputFile: "testdata/happy.lock", - wantLibs: []types.Library{ + wantPkgs: []ftypes.Package{ + { + ID: "AppCenter@4.2.0", + Name: "AppCenter", + Version: "4.2.0", + }, { ID: "AppCenter/Analytics@4.2.0", Name: "AppCenter/Analytics", @@ -36,18 +41,13 @@ func TestParse(t *testing.T) { Name: "AppCenter/Crashes", Version: "4.2.0", }, - { - ID: "AppCenter@4.2.0", - Name: "AppCenter", - Version: "4.2.0", - }, { ID: "KeychainAccess@4.2.1", Name: "KeychainAccess", Version: "4.2.1", }, }, - wantDeps: []types.Dependency{ + wantDeps: []ftypes.Dependency{ { ID: "AppCenter/Analytics@4.2.0", DependsOn: []string{ @@ -85,10 +85,10 @@ func TestParse(t *testing.T) { require.NoError(t, err) defer f.Close() - gotLibs, gotDeps, err := cocoapods.NewParser().Parse(f) + gotPkgs, gotDeps, err := cocoapods.NewParser().Parse(f) require.NoError(t, err) - assert.Equal(t, tt.wantLibs, gotLibs) + assert.Equal(t, tt.wantPkgs, gotPkgs) assert.Equal(t, tt.wantDeps, gotDeps) }) } diff --git a/pkg/dependency/parser/swift/swift/parse.go b/pkg/dependency/parser/swift/swift/parse.go index 74a507f847fb..aefa2a066faf 100644 --- a/pkg/dependency/parser/swift/swift/parse.go +++ b/pkg/dependency/parser/swift/swift/parse.go @@ -10,7 +10,6 @@ import ( "golang.org/x/xerrors" "github.com/aquasecurity/trivy/pkg/dependency" - "github.com/aquasecurity/trivy/pkg/dependency/types" ftypes "github.com/aquasecurity/trivy/pkg/fanal/types" "github.com/aquasecurity/trivy/pkg/log" xio "github.com/aquasecurity/trivy/pkg/x/io" @@ -21,13 +20,13 @@ type Parser struct { logger *log.Logger } -func NewParser() types.Parser { +func NewParser() *Parser { return &Parser{ logger: log.WithPrefix("swift"), } } -func (p *Parser) Parse(r xio.ReadSeekerAt) ([]types.Library, []types.Dependency, error) { +func (p *Parser) Parse(r xio.ReadSeekerAt) ([]ftypes.Package, []ftypes.Dependency, error) { var lockFile LockFile input, err := io.ReadAll(r) if err != nil { @@ -37,13 +36,13 @@ func (p *Parser) Parse(r xio.ReadSeekerAt) ([]types.Library, []types.Dependency, return nil, nil, xerrors.Errorf("decode error: %w", err) } - var libs types.Libraries + var pkgs ftypes.Packages pins := lockFile.Object.Pins if lockFile.Version > 1 { pins = lockFile.Pins } for _, pin := range pins { - name := libraryName(pin, lockFile.Version) + name := pkgName(pin, lockFile.Version) // Skip packages for which we cannot resolve the version if pin.State.Version == "" && pin.State.Branch == "" { @@ -55,11 +54,11 @@ func (p *Parser) Parse(r xio.ReadSeekerAt) ([]types.Library, []types.Dependency, // e.g. https://github.com/element-hq/element-ios/blob/6a9bcc88ea37147efba8f0a7bcf3ec187f4a4011/Riot.xcworkspace/xcshareddata/swiftpm/Package.resolved#L84-L92 version := lo.Ternary(pin.State.Version != "", pin.State.Version, pin.State.Branch) - libs = append(libs, types.Library{ + pkgs = append(pkgs, ftypes.Package{ ID: dependency.ID(ftypes.Swift, name, version), Name: name, Version: version, - Locations: []types.Location{ + Locations: []ftypes.Location{ { StartLine: pin.StartLine, EndLine: pin.EndLine, @@ -67,11 +66,11 @@ func (p *Parser) Parse(r xio.ReadSeekerAt) ([]types.Library, []types.Dependency, }, }) } - sort.Sort(libs) - return libs, nil, nil + sort.Sort(pkgs) + return pkgs, nil, nil } -func libraryName(pin Pin, lockVersion int) string { +func pkgName(pin Pin, lockVersion int) string { // Package.resolved v1 uses `RepositoryURL` // v2 uses `Location` name := pin.RepositoryURL diff --git a/pkg/dependency/parser/swift/swift/parse_test.go b/pkg/dependency/parser/swift/swift/parse_test.go index b1d3d127a85a..cd90d26fc6e4 100644 --- a/pkg/dependency/parser/swift/swift/parse_test.go +++ b/pkg/dependency/parser/swift/swift/parse_test.go @@ -1,7 +1,7 @@ package swift import ( - "github.com/aquasecurity/trivy/pkg/dependency/types" + ftypes "github.com/aquasecurity/trivy/pkg/fanal/types" "github.com/stretchr/testify/assert" "os" "testing" @@ -11,7 +11,7 @@ func TestParser_Parse(t *testing.T) { tests := []struct { name string inputFile string - want []types.Library + want []ftypes.Package }{ // docker run -it --rm swift@sha256:3c62ac97506ecf19ca15e4db57d7930e6a71559b23b19aa57e13d380133a54db // mkdir app && cd app @@ -22,60 +22,60 @@ func TestParser_Parse(t *testing.T) { { name: "happy path v1", inputFile: "testdata/happy-v1-Package.resolved", - want: []types.Library{ + want: []ftypes.Package{ { ID: "github.com/Quick/Nimble@9.2.1", Name: "github.com/Quick/Nimble", Version: "9.2.1", - Locations: []types.Location{{StartLine: 4, EndLine: 12}}, + Locations: []ftypes.Location{{StartLine: 4, EndLine: 12}}, }, { ID: "github.com/ReactiveCocoa/ReactiveSwift@7.1.1", Name: "github.com/ReactiveCocoa/ReactiveSwift", Version: "7.1.1", - Locations: []types.Location{{StartLine: 13, EndLine: 21}}, + Locations: []ftypes.Location{{StartLine: 13, EndLine: 21}}, }, }, }, { name: "happy path v2", inputFile: "testdata/happy-v2-Package.resolved", - want: []types.Library{ + want: []ftypes.Package{ { ID: "github.com/Quick/Nimble@9.2.1", Name: "github.com/Quick/Nimble", Version: "9.2.1", - Locations: []types.Location{{StartLine: 21, EndLine: 29}}, + Locations: []ftypes.Location{{StartLine: 21, EndLine: 29}}, }, { ID: "github.com/Quick/Quick@7.2.0", Name: "github.com/Quick/Quick", Version: "7.2.0", - Locations: []types.Location{{StartLine: 30, EndLine: 38}}, + Locations: []ftypes.Location{{StartLine: 30, EndLine: 38}}, }, { ID: "github.com/ReactiveCocoa/ReactiveSwift@7.1.1", Name: "github.com/ReactiveCocoa/ReactiveSwift", Version: "7.1.1", - Locations: []types.Location{{StartLine: 39, EndLine: 47}}, + Locations: []ftypes.Location{{StartLine: 39, EndLine: 47}}, }, { ID: "github.com/element-hq/swift-ogg@0.0.1", Name: "github.com/element-hq/swift-ogg", Version: "0.0.1", - Locations: []types.Location{{StartLine: 48, EndLine: 56}}, + Locations: []ftypes.Location{{StartLine: 48, EndLine: 56}}, }, { ID: "github.com/mattgallagher/CwlCatchException@2.1.2", Name: "github.com/mattgallagher/CwlCatchException", Version: "2.1.2", - Locations: []types.Location{{StartLine: 3, EndLine: 11}}, + Locations: []ftypes.Location{{StartLine: 3, EndLine: 11}}, }, { ID: "github.com/mattgallagher/CwlPreconditionTesting@2.1.2", Name: "github.com/mattgallagher/CwlPreconditionTesting", Version: "2.1.2", - Locations: []types.Location{{StartLine: 12, EndLine: 20}}, + Locations: []ftypes.Location{{StartLine: 12, EndLine: 20}}, }, }, }, @@ -92,9 +92,9 @@ func TestParser_Parse(t *testing.T) { f, err := os.Open(tt.inputFile) assert.NoError(t, err) - libs, _, err := parser.Parse(f) + gotPkgs, _, err := parser.Parse(f) assert.NoError(t, err) - assert.Equal(t, tt.want, libs) + assert.Equal(t, tt.want, gotPkgs) }) } } diff --git a/pkg/dependency/parser/utils/utils.go b/pkg/dependency/parser/utils/utils.go index e89bc4ca3b65..f22e994a7cb0 100644 --- a/pkg/dependency/parser/utils/utils.go +++ b/pkg/dependency/parser/utils/utils.go @@ -6,7 +6,7 @@ import ( "golang.org/x/exp/maps" - "github.com/aquasecurity/trivy/pkg/dependency/types" + ftypes "github.com/aquasecurity/trivy/pkg/fanal/types" ) func UniqueStrings(ss []string) []string { @@ -22,36 +22,36 @@ func UniqueStrings(ss []string) []string { return results } -func UniqueLibraries(libs []types.Library) []types.Library { - if len(libs) == 0 { +func UniquePackages(pkgs []ftypes.Package) []ftypes.Package { + if len(pkgs) == 0 { return nil } - unique := make(map[string]types.Library) - for _, lib := range libs { - identifier := fmt.Sprintf("%s@%s", lib.Name, lib.Version) + unique := make(map[string]ftypes.Package) + for _, pkg := range pkgs { + identifier := fmt.Sprintf("%s@%s", pkg.Name, pkg.Version) if l, ok := unique[identifier]; !ok { - unique[identifier] = lib + unique[identifier] = pkg } else { - // There are times when we get 2 same libraries as root and dev dependencies. + // There are times when we get 2 same packages as root and dev dependencies. // https://github.com/aquasecurity/trivy/issues/5532 // In these cases, we need to mark the dependency as a root dependency. - if !lib.Dev { - l.Dev = lib.Dev + if !pkg.Dev { + l.Dev = pkg.Dev unique[identifier] = l } - if len(lib.Locations) > 0 { + if len(pkg.Locations) > 0 { // merge locations - l.Locations = append(l.Locations, lib.Locations...) + l.Locations = append(l.Locations, pkg.Locations...) sort.Sort(l.Locations) unique[identifier] = l } } } - libSlice := maps.Values(unique) - sort.Sort(types.Libraries(libSlice)) + pkgSlice := maps.Values(unique) + sort.Sort(ftypes.Packages(pkgSlice)) - return libSlice + return pkgSlice } func MergeMaps(parent, child map[string]string) map[string]string { diff --git a/pkg/dependency/parser/utils/utils_test.go b/pkg/dependency/parser/utils/utils_test.go index ca8c8ab67568..ed5d84135c19 100644 --- a/pkg/dependency/parser/utils/utils_test.go +++ b/pkg/dependency/parser/utils/utils_test.go @@ -1,7 +1,7 @@ package utils import ( - "github.com/aquasecurity/trivy/pkg/dependency/types" + ftypes "github.com/aquasecurity/trivy/pkg/fanal/types" "github.com/stretchr/testify/require" "testing" ) @@ -9,17 +9,17 @@ import ( func TestUniqueLibraries(t *testing.T) { tests := []struct { name string - libs []types.Library - wantLibs []types.Library + pkgs []ftypes.Package + wantPkgs []ftypes.Package }{ { name: "happy path merge locations", - libs: []types.Library{ + pkgs: []ftypes.Package{ { ID: "asn1@0.2.6", Name: "asn1", Version: "0.2.6", - Locations: []types.Location{ + Locations: []ftypes.Location{ { StartLine: 10, EndLine: 14, @@ -30,7 +30,7 @@ func TestUniqueLibraries(t *testing.T) { ID: "asn1@0.2.6", Name: "asn1", Version: "0.2.6", - Locations: []types.Location{ + Locations: []ftypes.Location{ { StartLine: 24, EndLine: 30, @@ -38,12 +38,12 @@ func TestUniqueLibraries(t *testing.T) { }, }, }, - wantLibs: []types.Library{ + wantPkgs: []ftypes.Package{ { ID: "asn1@0.2.6", Name: "asn1", Version: "0.2.6", - Locations: []types.Location{ + Locations: []ftypes.Location{ { StartLine: 10, EndLine: 14, @@ -58,7 +58,7 @@ func TestUniqueLibraries(t *testing.T) { }, { name: "happy path Dev and Root deps", - libs: []types.Library{ + pkgs: []ftypes.Package{ { ID: "asn1@0.2.6", Name: "asn1", @@ -72,7 +72,7 @@ func TestUniqueLibraries(t *testing.T) { Dev: false, }, }, - wantLibs: []types.Library{ + wantPkgs: []ftypes.Package{ { ID: "asn1@0.2.6", Name: "asn1", @@ -83,7 +83,7 @@ func TestUniqueLibraries(t *testing.T) { }, { name: "happy path Root and Dev deps", - libs: []types.Library{ + pkgs: []ftypes.Package{ { ID: "asn1@0.2.6", Name: "asn1", @@ -97,7 +97,7 @@ func TestUniqueLibraries(t *testing.T) { Dev: true, }, }, - wantLibs: []types.Library{ + wantPkgs: []ftypes.Package{ { ID: "asn1@0.2.6", Name: "asn1", @@ -110,8 +110,8 @@ func TestUniqueLibraries(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - gotLibs := UniqueLibraries(tt.libs) - require.Equal(t, tt.wantLibs, gotLibs) + gotPkgs := UniquePackages(tt.pkgs) + require.Equal(t, tt.wantPkgs, gotPkgs) }) } } diff --git a/pkg/dependency/types/types.go b/pkg/dependency/types/types.go deleted file mode 100644 index be7022fc301a..000000000000 --- a/pkg/dependency/types/types.go +++ /dev/null @@ -1,127 +0,0 @@ -package types - -import ( - "encoding/json" - - "golang.org/x/xerrors" - - xio "github.com/aquasecurity/trivy/pkg/x/io" -) - -type Library struct { - ID string `json:",omitempty"` - Name string - Version string - Dev bool `json:",omitempty"` - Relationship Relationship `json:",omitempty"` - License string `json:",omitempty"` - ExternalReferences []ExternalRef `json:",omitempty"` - Locations Locations `json:",omitempty"` - FilePath string `json:",omitempty"` // Required to show nested jars -} - -type Libraries []Library - -func (libs Libraries) Len() int { return len(libs) } -func (libs Libraries) Less(i, j int) bool { - switch { - case libs[i].Relationship != libs[j].Relationship: - if libs[i].Relationship == RelationshipUnknown { - return false - } else if libs[j].Relationship == RelationshipUnknown { - return true - } - return libs[i].Relationship < libs[j].Relationship - case libs[i].ID != libs[j].ID: // ID could be empty - return libs[i].ID < libs[j].ID - case libs[i].Name != libs[j].Name: // Name could be the same - return libs[i].Name < libs[j].Name - } - return libs[i].Version < libs[j].Version -} -func (libs Libraries) Swap(i, j int) { libs[i], libs[j] = libs[j], libs[i] } - -// Location in lock file -type Location struct { - StartLine int `json:",omitempty"` - EndLine int `json:",omitempty"` -} - -type Locations []Location - -func (locs Locations) Len() int { return len(locs) } -func (locs Locations) Less(i, j int) bool { - return locs[i].StartLine < locs[j].StartLine -} -func (locs Locations) Swap(i, j int) { locs[i], locs[j] = locs[j], locs[i] } - -type ExternalRef struct { - Type RefType - URL string -} - -type Dependency struct { - ID string - DependsOn []string -} - -type Dependencies []Dependency - -func (deps Dependencies) Len() int { return len(deps) } -func (deps Dependencies) Less(i, j int) bool { - return deps[i].ID < deps[j].ID -} -func (deps Dependencies) Swap(i, j int) { deps[i], deps[j] = deps[j], deps[i] } - -type Parser interface { - // Parse parses the dependency file - Parse(r xio.ReadSeekerAt) ([]Library, []Dependency, error) -} - -type RefType string - -const ( - RefVCS RefType = "vcs" - RefOther RefType = "other" -) - -type Relationship int - -const ( - RelationshipUnknown Relationship = iota - RelationshipRoot - RelationshipDirect - RelationshipIndirect -) - -var relationshipNames = [...]string{ - "unknown", - "root", - "direct", - "indirect", -} - -func (r Relationship) String() string { - if r <= RelationshipUnknown || int(r) >= len(relationshipNames) { - return "unknown" - } - return relationshipNames[r] -} - -func (r Relationship) MarshalJSON() ([]byte, error) { - return json.Marshal(r.String()) -} - -func (r *Relationship) UnmarshalJSON(data []byte) error { - var s string - if err := json.Unmarshal(data, &s); err != nil { - return err - } - for i, name := range relationshipNames { - if s == name { - *r = Relationship(i) - return nil - } - } - return xerrors.Errorf("invalid relationship (%s)", s) -} diff --git a/pkg/fanal/analyzer/analyzer.go b/pkg/fanal/analyzer/analyzer.go index 9312a90ad283..56bb518f1b73 100644 --- a/pkg/fanal/analyzer/analyzer.go +++ b/pkg/fanal/analyzer/analyzer.go @@ -202,7 +202,7 @@ func (r *AnalysisResult) Sort() { }) for _, app := range r.Applications { - sort.Sort(app.Libraries) + sort.Sort(app.Packages) } // Custom resources @@ -475,12 +475,12 @@ func (ag AnalyzerGroup) PostAnalyze(ctx context.Context, compositeFS *CompositeF skippedFiles := result.SystemInstalledFiles for _, app := range result.Applications { skippedFiles = append(skippedFiles, app.FilePath) - for _, lib := range app.Libraries { + for _, pkg := range app.Packages { // The analysis result could contain packages listed in SBOM. // The files of those packages don't have to be analyzed. // This is especially helpful for expensive post-analyzers such as the JAR analyzer. - if lib.FilePath != "" { - skippedFiles = append(skippedFiles, lib.FilePath) + if pkg.FilePath != "" { + skippedFiles = append(skippedFiles, pkg.FilePath) } } } diff --git a/pkg/fanal/analyzer/analyzer_test.go b/pkg/fanal/analyzer/analyzer_test.go index df1398155b2c..169bbce3e8e6 100644 --- a/pkg/fanal/analyzer/analyzer_test.go +++ b/pkg/fanal/analyzer/analyzer_test.go @@ -69,7 +69,7 @@ func TestAnalysisResult_Merge(t *testing.T) { { Type: "bundler", FilePath: "app/Gemfile.lock", - Libraries: types.Packages{ + Packages: types.Packages{ { Name: "rails", Version: "5.0.0", @@ -95,7 +95,7 @@ func TestAnalysisResult_Merge(t *testing.T) { { Type: "bundler", FilePath: "app2/Gemfile.lock", - Libraries: types.Packages{ + Packages: types.Packages{ { Name: "nokogiri", Version: "1.0.0", @@ -134,7 +134,7 @@ func TestAnalysisResult_Merge(t *testing.T) { { Type: "bundler", FilePath: "app/Gemfile.lock", - Libraries: types.Packages{ + Packages: types.Packages{ { Name: "rails", Version: "5.0.0", @@ -144,7 +144,7 @@ func TestAnalysisResult_Merge(t *testing.T) { { Type: "bundler", FilePath: "app2/Gemfile.lock", - Libraries: types.Packages{ + Packages: types.Packages{ { Name: "nokogiri", Version: "1.0.0", @@ -378,7 +378,7 @@ func TestAnalyzerGroup_AnalyzeFile(t *testing.T) { { Type: "bundler", FilePath: "/app/Gemfile.lock", - Libraries: types.Packages{ + Packages: types.Packages{ { ID: "actioncable@5.2.3", Name: "actioncable", @@ -441,7 +441,7 @@ func TestAnalyzerGroup_AnalyzeFile(t *testing.T) { { Type: "bundler", FilePath: "/app/Gemfile-dev.lock", - Libraries: types.Packages{ + Packages: types.Packages{ { ID: "actioncable@5.2.3", Name: "actioncable", @@ -576,7 +576,7 @@ func TestAnalyzerGroup_PostAnalyze(t *testing.T) { { Type: types.Jar, FilePath: "testdata/post-apps/jar/jackson-annotations-2.15.0-rc2.jar", - Libraries: types.Packages{ + Packages: types.Packages{ { Name: "com.fasterxml.jackson.core:jackson-annotations", Version: "2.15.0-rc2", @@ -596,7 +596,7 @@ func TestAnalyzerGroup_PostAnalyze(t *testing.T) { { Type: types.Poetry, FilePath: "testdata/post-apps/poetry/happy/poetry.lock", - Libraries: types.Packages{ + Packages: types.Packages{ { ID: "certifi@2022.12.7", Name: "certifi", diff --git a/pkg/fanal/analyzer/language/analyze.go b/pkg/fanal/analyzer/language/analyze.go index 84b0261f86b7..6ecbaba65752 100644 --- a/pkg/fanal/analyzer/language/analyze.go +++ b/pkg/fanal/analyzer/language/analyze.go @@ -2,11 +2,9 @@ package language import ( "io" - "strings" "golang.org/x/xerrors" - godeptypes "github.com/aquasecurity/trivy/pkg/dependency/types" "github.com/aquasecurity/trivy/pkg/digest" "github.com/aquasecurity/trivy/pkg/fanal/analyzer" "github.com/aquasecurity/trivy/pkg/fanal/types" @@ -15,8 +13,13 @@ import ( xio "github.com/aquasecurity/trivy/pkg/x/io" ) +type Parser interface { + // Parse parses the dependency file + Parse(r xio.ReadSeekerAt) ([]types.Package, []types.Dependency, error) +} + // Analyze returns an analysis result of the lock file -func Analyze(fileType types.LangType, filePath string, r xio.ReadSeekerAt, parser godeptypes.Parser) (*analyzer.AnalysisResult, error) { +func Analyze(fileType types.LangType, filePath string, r xio.ReadSeekerAt, parser Parser) (*analyzer.AnalysisResult, error) { app, err := Parse(fileType, filePath, r, parser) if err != nil { return nil, xerrors.Errorf("failed to parse %s: %w", filePath, err) @@ -30,7 +33,7 @@ func Analyze(fileType types.LangType, filePath string, r xio.ReadSeekerAt, parse } // AnalyzePackage returns an analysis result of the package file other than lock files -func AnalyzePackage(fileType types.LangType, filePath string, r xio.ReadSeekerAt, parser godeptypes.Parser, checksum bool) (*analyzer.AnalysisResult, error) { +func AnalyzePackage(fileType types.LangType, filePath string, r xio.ReadSeekerAt, parser Parser, checksum bool) (*analyzer.AnalysisResult, error) { app, err := ParsePackage(fileType, filePath, r, parser, checksum) if err != nil { return nil, xerrors.Errorf("failed to parse %s: %w", filePath, err) @@ -44,24 +47,24 @@ func AnalyzePackage(fileType types.LangType, filePath string, r xio.ReadSeekerAt } // Parse returns a parsed result of the lock file -func Parse(fileType types.LangType, filePath string, r io.Reader, parser godeptypes.Parser) (*types.Application, error) { +func Parse(fileType types.LangType, filePath string, r io.Reader, parser Parser) (*types.Application, error) { rr, err := xio.NewReadSeekerAt(r) if err != nil { return nil, xerrors.Errorf("reader error: %w", err) } - parsedLibs, parsedDependencies, err := parser.Parse(rr) + parsedPkgs, parsedDependencies, err := parser.Parse(rr) if err != nil { return nil, xerrors.Errorf("failed to parse %s: %w", filePath, err) } // The file path of each library should be empty in case of dependency list such as lock file // since they all will be the same path. - return toApplication(fileType, filePath, "", nil, parsedLibs, parsedDependencies), nil + return toApplication(fileType, filePath, "", nil, parsedPkgs, parsedDependencies), nil } // ParsePackage returns a parsed result of the package file -func ParsePackage(fileType types.LangType, filePath string, r xio.ReadSeekerAt, parser godeptypes.Parser, checksum bool) (*types.Application, error) { - parsedLibs, parsedDependencies, err := parser.Parse(r) +func ParsePackage(fileType types.LangType, filePath string, r xio.ReadSeekerAt, parser Parser, checksum bool) (*types.Application, error) { + parsedPkgs, parsedDependencies, err := parser.Parse(r) if err != nil { return nil, xerrors.Errorf("failed to parse %s: %w", filePath, err) } @@ -73,11 +76,11 @@ func ParsePackage(fileType types.LangType, filePath string, r xio.ReadSeekerAt, // The file path of each library should be empty in case of dependency list such as lock file // since they all will be the same path. - return toApplication(fileType, filePath, filePath, r, parsedLibs, parsedDependencies), nil + return toApplication(fileType, filePath, filePath, r, parsedPkgs, parsedDependencies), nil } -func toApplication(fileType types.LangType, filePath, libFilePath string, r xio.ReadSeekerAt, libs []godeptypes.Library, depGraph []godeptypes.Dependency) *types.Application { - if len(libs) == 0 { +func toApplication(fileType types.LangType, filePath, libFilePath string, r xio.ReadSeekerAt, pkgs []types.Package, depGraph []types.Dependency) *types.Application { + if len(pkgs) == 0 { return nil } @@ -92,50 +95,24 @@ func toApplication(fileType types.LangType, filePath, libFilePath string, r xio. deps[dep.ID] = dep.DependsOn } - var pkgs []types.Package - for _, lib := range libs { - var licenses []string - if lib.License != "" { - licenses = licensing.SplitLicenses(lib.License) - for i, license := range licenses { - licenses[i] = licensing.Normalize(strings.TrimSpace(license)) - } - } - var locs []types.Location - for _, loc := range lib.Locations { - l := types.Location{ - StartLine: loc.StartLine, - EndLine: loc.EndLine, - } - locs = append(locs, l) - } - + for i, pkg := range pkgs { // This file path is populated for virtual file paths within archives, such as nested JAR files. - libPath := libFilePath - if lib.FilePath != "" { - libPath = lib.FilePath + if pkg.FilePath == "" { + pkgs[i].FilePath = libFilePath } + pkgs[i].DependsOn = deps[pkg.ID] + pkgs[i].Digest = d + pkgs[i].Indirect = isIndirect(pkg.Relationship) // For backward compatibility - newPkg := types.Package{ - ID: lib.ID, - Name: lib.Name, - Version: lib.Version, - Dev: lib.Dev, - FilePath: libPath, - Indirect: isIndirect(lib.Relationship), // For backward compatibility - Relationship: lib.Relationship, - Licenses: licenses, - DependsOn: deps[lib.ID], - Locations: locs, - Digest: d, + for j, license := range pkg.Licenses { + pkgs[i].Licenses[j] = licensing.Normalize(license) } - pkgs = append(pkgs, newPkg) } return &types.Application{ - Type: fileType, - FilePath: filePath, - Libraries: pkgs, + Type: fileType, + FilePath: filePath, + Packages: pkgs, } } diff --git a/pkg/fanal/analyzer/language/analyze_test.go b/pkg/fanal/analyzer/language/analyze_test.go index 260c86b59ae8..8b6c9dad44de 100644 --- a/pkg/fanal/analyzer/language/analyze_test.go +++ b/pkg/fanal/analyzer/language/analyze_test.go @@ -9,7 +9,6 @@ import ( "github.com/stretchr/testify/require" "golang.org/x/xerrors" - godeptypes "github.com/aquasecurity/trivy/pkg/dependency/types" "github.com/aquasecurity/trivy/pkg/fanal/analyzer" "github.com/aquasecurity/trivy/pkg/fanal/analyzer/language" "github.com/aquasecurity/trivy/pkg/fanal/types" @@ -20,13 +19,13 @@ type mockParser struct { t *testing.T } -func (p *mockParser) Parse(r xio.ReadSeekerAt) ([]godeptypes.Library, []godeptypes.Dependency, error) { +func (p *mockParser) Parse(r xio.ReadSeekerAt) ([]types.Package, []types.Dependency, error) { b, err := io.ReadAll(r) require.NoError(p.t, err) switch string(b) { case "happy": - return []godeptypes.Library{ + return []types.Package{ { Name: "test", Version: "1.2.3", @@ -63,7 +62,7 @@ func TestAnalyze(t *testing.T) { { Type: types.GoBinary, FilePath: "app/myweb", - Libraries: types.Packages{ + Packages: types.Packages{ { Name: "test", Version: "1.2.3", diff --git a/pkg/fanal/analyzer/language/c/conan/conan.go b/pkg/fanal/analyzer/language/c/conan/conan.go index 891ebac08695..50252c2bb603 100644 --- a/pkg/fanal/analyzer/language/c/conan/conan.go +++ b/pkg/fanal/analyzer/language/c/conan/conan.go @@ -14,7 +14,6 @@ import ( "golang.org/x/xerrors" "github.com/aquasecurity/trivy/pkg/dependency/parser/c/conan" - godeptypes "github.com/aquasecurity/trivy/pkg/dependency/types" "github.com/aquasecurity/trivy/pkg/fanal/analyzer" "github.com/aquasecurity/trivy/pkg/fanal/analyzer/language" "github.com/aquasecurity/trivy/pkg/fanal/types" @@ -33,7 +32,7 @@ const ( // conanLockAnalyzer analyzes conan.lock type conanLockAnalyzer struct { logger *log.Logger - parser godeptypes.Parser + parser language.Parser } func newConanLockAnalyzer(_ analyzer.AnalyzerOptions) (analyzer.PostAnalyzer, error) { @@ -65,15 +64,15 @@ func (a conanLockAnalyzer) PostAnalyze(_ context.Context, input analyzer.PostAna } // Fill licenses - for i, lib := range app.Libraries { + for i, lib := range app.Packages { if license, ok := licenses[lib.Name]; ok { - app.Libraries[i].Licenses = []string{ + app.Packages[i].Licenses = []string{ license, } } } - sort.Sort(app.Libraries) + sort.Sort(app.Packages) apps = append(apps, *app) return nil }); err != nil { diff --git a/pkg/fanal/analyzer/language/c/conan/conan_test.go b/pkg/fanal/analyzer/language/c/conan/conan_test.go index 622632c39c1f..bfc2054ebe66 100644 --- a/pkg/fanal/analyzer/language/c/conan/conan_test.go +++ b/pkg/fanal/analyzer/language/c/conan/conan_test.go @@ -27,7 +27,7 @@ func Test_conanLockAnalyzer_Analyze(t *testing.T) { { Type: types.Conan, FilePath: "conan.lock", - Libraries: types.Packages{ + Packages: types.Packages{ { ID: "openssl/3.0.5", Name: "openssl", @@ -70,7 +70,7 @@ func Test_conanLockAnalyzer_Analyze(t *testing.T) { { Type: types.Conan, FilePath: "conan.lock", - Libraries: types.Packages{ + Packages: types.Packages{ { ID: "openssl/3.0.5", Name: "openssl", diff --git a/pkg/fanal/analyzer/language/conda/environment/environment_test.go b/pkg/fanal/analyzer/language/conda/environment/environment_test.go index d511ac3e50a1..c9610289584e 100644 --- a/pkg/fanal/analyzer/language/conda/environment/environment_test.go +++ b/pkg/fanal/analyzer/language/conda/environment/environment_test.go @@ -25,7 +25,7 @@ func Test_environmentAnalyzer_Analyze(t *testing.T) { { Type: types.CondaEnv, FilePath: "testdata/environment.yaml", - Libraries: types.Packages{ + Packages: types.Packages{ { Name: "_libgcc_mutex", Locations: []types.Location{ diff --git a/pkg/fanal/analyzer/language/conda/meta/meta_test.go b/pkg/fanal/analyzer/language/conda/meta/meta_test.go index 0b7a988e9ade..3cb4f18e4b2b 100644 --- a/pkg/fanal/analyzer/language/conda/meta/meta_test.go +++ b/pkg/fanal/analyzer/language/conda/meta/meta_test.go @@ -27,7 +27,7 @@ func Test_packagingAnalyzer_Analyze(t *testing.T) { { Type: types.CondaPkg, FilePath: "testdata/pip-22.2.2-py38h06a4308_0.json", - Libraries: types.Packages{ + Packages: types.Packages{ { Name: "pip", Version: "22.2.2", diff --git a/pkg/fanal/analyzer/language/dart/pub/pubspec.go b/pkg/fanal/analyzer/language/dart/pub/pubspec.go index 1981e08a023d..ad8a5396e255 100644 --- a/pkg/fanal/analyzer/language/dart/pub/pubspec.go +++ b/pkg/fanal/analyzer/language/dart/pub/pubspec.go @@ -16,7 +16,6 @@ import ( "github.com/aquasecurity/trivy/pkg/dependency" "github.com/aquasecurity/trivy/pkg/dependency/parser/dart/pub" - godeptypes "github.com/aquasecurity/trivy/pkg/dependency/types" "github.com/aquasecurity/trivy/pkg/fanal/analyzer" "github.com/aquasecurity/trivy/pkg/fanal/analyzer/language" "github.com/aquasecurity/trivy/pkg/fanal/types" @@ -36,7 +35,7 @@ const ( // pubSpecLockAnalyzer analyzes `pubspec.lock` type pubSpecLockAnalyzer struct { logger *log.Logger - parser godeptypes.Parser + parser language.Parser } func newPubSpecLockAnalyzer(_ analyzer.AnalyzerOptions) (analyzer.PostAnalyzer, error) { @@ -72,22 +71,22 @@ func (a pubSpecLockAnalyzer) PostAnalyze(_ context.Context, input analyzer.PostA if allDependsOn != nil { // Required to search for library versions for DependsOn. - libs := lo.SliceToMap(app.Libraries, func(lib types.Package) (string, string) { + pkgs := lo.SliceToMap(app.Packages, func(lib types.Package) (string, string) { return lib.Name, lib.ID }) - for i, lib := range app.Libraries { + for i, lib := range app.Packages { var dependsOn []string for _, depName := range allDependsOn[lib.ID] { - if depID, ok := libs[depName]; ok { + if depID, ok := pkgs[depName]; ok { dependsOn = append(dependsOn, depID) } } - app.Libraries[i].DependsOn = dependsOn + app.Packages[i].DependsOn = dependsOn } } - sort.Sort(app.Libraries) + sort.Sort(app.Packages) apps = append(apps, *app) return nil }) diff --git a/pkg/fanal/analyzer/language/dart/pub/pubspec_test.go b/pkg/fanal/analyzer/language/dart/pub/pubspec_test.go index 2c57e1b3e75a..b464ddf5cd57 100644 --- a/pkg/fanal/analyzer/language/dart/pub/pubspec_test.go +++ b/pkg/fanal/analyzer/language/dart/pub/pubspec_test.go @@ -32,14 +32,7 @@ func Test_pubSpecLockAnalyzer_Analyze(t *testing.T) { { Type: types.Pub, FilePath: "pubspec.lock", - Libraries: types.Packages{ - { - ID: "collection@1.17.0", - Name: "collection", - Version: "1.17.0", - Indirect: true, - Relationship: types.RelationshipIndirect, - }, + Packages: types.Packages{ { ID: "crypto@3.0.3", Name: "crypto", @@ -55,6 +48,13 @@ func Test_pubSpecLockAnalyzer_Analyze(t *testing.T) { Version: "1.11.0", Relationship: types.RelationshipDirect, }, + { + ID: "collection@1.17.0", + Name: "collection", + Version: "1.17.0", + Indirect: true, + Relationship: types.RelationshipIndirect, + }, { ID: "typed_data@1.3.2", Name: "typed_data", @@ -80,14 +80,7 @@ func Test_pubSpecLockAnalyzer_Analyze(t *testing.T) { { Type: types.Pub, FilePath: "pubspec.lock", - Libraries: types.Packages{ - { - ID: "collection@1.17.0", - Name: "collection", - Version: "1.17.0", - Indirect: true, - Relationship: types.RelationshipIndirect, - }, + Packages: types.Packages{ { ID: "crypto@3.0.3", Name: "crypto", @@ -100,6 +93,13 @@ func Test_pubSpecLockAnalyzer_Analyze(t *testing.T) { Version: "1.11.0", Relationship: types.RelationshipDirect, }, + { + ID: "collection@1.17.0", + Name: "collection", + Version: "1.17.0", + Indirect: true, + Relationship: types.RelationshipIndirect, + }, { ID: "typed_data@1.3.2", Name: "typed_data", diff --git a/pkg/fanal/analyzer/language/dotnet/deps/deps_test.go b/pkg/fanal/analyzer/language/dotnet/deps/deps_test.go index 37f23d2774f2..e3cdf2730e72 100644 --- a/pkg/fanal/analyzer/language/dotnet/deps/deps_test.go +++ b/pkg/fanal/analyzer/language/dotnet/deps/deps_test.go @@ -27,7 +27,7 @@ func Test_depsLibraryAnalyzer_Analyze(t *testing.T) { { Type: types.DotNetCore, FilePath: "testdata/datacollector.deps.json", - Libraries: types.Packages{ + Packages: types.Packages{ { Name: "Newtonsoft.Json", Version: "9.0.1", diff --git a/pkg/fanal/analyzer/language/dotnet/nuget/nuget.go b/pkg/fanal/analyzer/language/dotnet/nuget/nuget.go index 6411f4d1bc8d..2e24610719e4 100644 --- a/pkg/fanal/analyzer/language/dotnet/nuget/nuget.go +++ b/pkg/fanal/analyzer/language/dotnet/nuget/nuget.go @@ -14,7 +14,6 @@ import ( "github.com/aquasecurity/trivy/pkg/dependency/parser/nuget/config" "github.com/aquasecurity/trivy/pkg/dependency/parser/nuget/lock" - godeptypes "github.com/aquasecurity/trivy/pkg/dependency/types" "github.com/aquasecurity/trivy/pkg/fanal/analyzer" "github.com/aquasecurity/trivy/pkg/fanal/analyzer/language" "github.com/aquasecurity/trivy/pkg/fanal/types" @@ -31,11 +30,14 @@ const ( configFile = types.NuGetPkgsConfig ) -var requiredFiles = []string{lockFile, configFile} +var requiredFiles = []string{ + lockFile, + configFile, +} type nugetLibraryAnalyzer struct { - lockParser godeptypes.Parser - configParser godeptypes.Parser + lockParser language.Parser + configParser language.Parser licenseParser nuspecParser } @@ -76,7 +78,7 @@ func (a *nugetLibraryAnalyzer) PostAnalyze(_ context.Context, input analyzer.Pos return nil } - for i, lib := range app.Libraries { + for i, lib := range app.Packages { license, ok := foundLicenses[lib.ID] if !ok { license, err = a.licenseParser.findLicense(lib.Name, lib.Version) @@ -86,10 +88,10 @@ func (a *nugetLibraryAnalyzer) PostAnalyze(_ context.Context, input analyzer.Pos foundLicenses[lib.ID] = license } - app.Libraries[i].Licenses = license + app.Packages[i].Licenses = license } - sort.Sort(app.Libraries) + sort.Sort(app.Packages) apps = append(apps, *app) return nil }) diff --git a/pkg/fanal/analyzer/language/dotnet/nuget/nuget_test.go b/pkg/fanal/analyzer/language/dotnet/nuget/nuget_test.go index f0494b69d97d..07b5023a392d 100644 --- a/pkg/fanal/analyzer/language/dotnet/nuget/nuget_test.go +++ b/pkg/fanal/analyzer/language/dotnet/nuget/nuget_test.go @@ -30,7 +30,7 @@ func Test_nugetibraryAnalyzer_Analyze(t *testing.T) { { Type: types.NuGet, FilePath: "packages.config", - Libraries: types.Packages{ + Packages: types.Packages{ { Name: "Microsoft.AspNet.WebApi", Version: "5.2.2", @@ -55,7 +55,7 @@ func Test_nugetibraryAnalyzer_Analyze(t *testing.T) { { Type: types.NuGet, FilePath: "packages.lock.json", - Libraries: types.Packages{ + Packages: types.Packages{ { ID: "Newtonsoft.Json@12.0.3", Name: "Newtonsoft.Json", @@ -98,7 +98,7 @@ func Test_nugetibraryAnalyzer_Analyze(t *testing.T) { { Type: types.NuGet, FilePath: "packages.lock.json", - Libraries: types.Packages{ + Packages: types.Packages{ { ID: "Newtonsoft.Json@12.0.3", Name: "Newtonsoft.Json", @@ -141,7 +141,7 @@ func Test_nugetibraryAnalyzer_Analyze(t *testing.T) { { Type: types.NuGet, FilePath: "packages.lock.json", - Libraries: types.Packages{ + Packages: types.Packages{ { ID: "Newtonsoft.Json@12.0.3", Name: "Newtonsoft.Json", diff --git a/pkg/fanal/analyzer/language/dotnet/packagesprops/packagesprops_test.go b/pkg/fanal/analyzer/language/dotnet/packagesprops/packagesprops_test.go index 0fb12d4ba837..ee398028de6e 100644 --- a/pkg/fanal/analyzer/language/dotnet/packagesprops/packagesprops_test.go +++ b/pkg/fanal/analyzer/language/dotnet/packagesprops/packagesprops_test.go @@ -27,7 +27,7 @@ func Test_packagesPropsAnalyzer_Analyze(t *testing.T) { { Type: types.PackagesProps, FilePath: "testdata/Packages.props", - Libraries: types.Packages{ + Packages: types.Packages{ { ID: "Package1@22.1.4", Name: "Package1", @@ -51,7 +51,7 @@ func Test_packagesPropsAnalyzer_Analyze(t *testing.T) { { Type: types.PackagesProps, FilePath: "testdata/Directory.Packages.props", - Libraries: types.Packages{ + Packages: types.Packages{ { ID: "Package1@4.2.1", Name: "Package1", diff --git a/pkg/fanal/analyzer/language/elixir/mix/mix_test.go b/pkg/fanal/analyzer/language/elixir/mix/mix_test.go index 5c836c260555..d375014fd97a 100644 --- a/pkg/fanal/analyzer/language/elixir/mix/mix_test.go +++ b/pkg/fanal/analyzer/language/elixir/mix/mix_test.go @@ -25,7 +25,7 @@ func Test_mixLockAnalyzer_Analyze(t *testing.T) { { Type: types.Hex, FilePath: "testdata/happy.mix.lock", - Libraries: types.Packages{ + Packages: types.Packages{ { ID: "bunt@0.2.0", Name: "bunt", diff --git a/pkg/fanal/analyzer/language/golang/binary/binary_test.go b/pkg/fanal/analyzer/language/golang/binary/binary_test.go index 839084be36bd..7c2b678ac0a5 100644 --- a/pkg/fanal/analyzer/language/golang/binary/binary_test.go +++ b/pkg/fanal/analyzer/language/golang/binary/binary_test.go @@ -28,7 +28,7 @@ func Test_gobinaryLibraryAnalyzer_Analyze(t *testing.T) { { Type: types.GoBinary, FilePath: "testdata/executable_gobinary", - Libraries: types.Packages{ + Packages: types.Packages{ { Name: "github.com/aquasecurity/test", Version: "", diff --git a/pkg/fanal/analyzer/language/golang/mod/mod.go b/pkg/fanal/analyzer/language/golang/mod/mod.go index bc2c564429ab..f97d9bed5add 100644 --- a/pkg/fanal/analyzer/language/golang/mod/mod.go +++ b/pkg/fanal/analyzer/language/golang/mod/mod.go @@ -19,7 +19,6 @@ import ( "github.com/aquasecurity/trivy/pkg/dependency/parser/golang/mod" "github.com/aquasecurity/trivy/pkg/dependency/parser/golang/sum" - godeptypes "github.com/aquasecurity/trivy/pkg/dependency/types" "github.com/aquasecurity/trivy/pkg/fanal/analyzer" "github.com/aquasecurity/trivy/pkg/fanal/analyzer/language" "github.com/aquasecurity/trivy/pkg/fanal/types" @@ -45,11 +44,11 @@ var ( type gomodAnalyzer struct { // root go.mod/go.sum - modParser godeptypes.Parser - sumParser godeptypes.Parser + modParser language.Parser + sumParser language.Parser // go.mod/go.sum in dependencies - leafModParser godeptypes.Parser + leafModParser language.Parser licenseClassifierConfidenceLevel float64 @@ -139,13 +138,13 @@ func (a *gomodAnalyzer) fillAdditionalData(apps []types.Application) error { licenses := make(map[string][]string) for i, app := range apps { // Actually used dependencies - usedLibs := lo.SliceToMap(app.Libraries, func(pkg types.Package) (string, types.Package) { + usedPkgs := lo.SliceToMap(app.Packages, func(pkg types.Package) (string, types.Package) { return pkg.Name, pkg }) - for j, lib := range app.Libraries { + for j, lib := range app.Packages { if l, ok := licenses[lib.ID]; ok { // Fill licenses - apps[i].Libraries[j].Licenses = l + apps[i].Packages[j].Licenses = l continue } @@ -160,7 +159,7 @@ func (a *gomodAnalyzer) fillAdditionalData(apps []types.Application) error { licenses[lib.ID] = licenseNames // Fill licenses - apps[i].Libraries[j].Licenses = licenseNames + apps[i].Packages[j].Licenses = licenseNames } // Collect dependencies of the direct dependency @@ -171,8 +170,8 @@ func (a *gomodAnalyzer) fillAdditionalData(apps []types.Application) error { continue } else { // Filter out unused dependencies and convert module names to module IDs - apps[i].Libraries[j].DependsOn = lo.FilterMap(dep.DependsOn, func(modName string, _ int) (string, bool) { - if m, ok := usedLibs[modName]; !ok { + apps[i].Packages[j].DependsOn = lo.FilterMap(dep.DependsOn, func(modName string, _ int) (string, bool) { + if m, ok := usedPkgs[modName]; !ok { return "", false } else { return m.ID, true @@ -184,37 +183,37 @@ func (a *gomodAnalyzer) fillAdditionalData(apps []types.Application) error { return nil } -func (a *gomodAnalyzer) collectDeps(modDir, pkgID string) (godeptypes.Dependency, error) { +func (a *gomodAnalyzer) collectDeps(modDir, pkgID string) (types.Dependency, error) { // e.g. $GOPATH/pkg/mod/github.com/aquasecurity/go-dep-parser@v0.0.0-20220406074731-71021a481237/go.mod modPath := filepath.Join(modDir, "go.mod") f, err := os.Open(modPath) if errors.Is(err, fs.ErrNotExist) { a.logger.Debug("Unable to identify dependencies as it doesn't support Go modules", log.String("module", pkgID)) - return godeptypes.Dependency{}, nil + return types.Dependency{}, nil } else if err != nil { - return godeptypes.Dependency{}, xerrors.Errorf("file open error: %w", err) + return types.Dependency{}, xerrors.Errorf("file open error: %w", err) } defer f.Close() // Parse go.mod under $GOPATH/pkg/mod - libs, _, err := a.leafModParser.Parse(f) + pkgs, _, err := a.leafModParser.Parse(f) if err != nil { - return godeptypes.Dependency{}, xerrors.Errorf("%s parse error: %w", modPath, err) + return types.Dependency{}, xerrors.Errorf("%s parse error: %w", modPath, err) } // Filter out indirect dependencies - dependsOn := lo.FilterMap(libs, func(lib godeptypes.Library, index int) (string, bool) { + dependsOn := lo.FilterMap(pkgs, func(lib types.Package, index int) (string, bool) { return lib.Name, lib.Relationship == types.RelationshipDirect }) - return godeptypes.Dependency{ + return types.Dependency{ ID: pkgID, DependsOn: dependsOn, }, nil } -func parse(fsys fs.FS, path string, parser godeptypes.Parser) (*types.Application, error) { +func parse(fsys fs.FS, path string, parser language.Parser) (*types.Application, error) { f, err := fsys.Open(path) if err != nil { return nil, xerrors.Errorf("file open error: %w", err) @@ -231,7 +230,7 @@ func parse(fsys fs.FS, path string, parser godeptypes.Parser) (*types.Applicatio } func lessThanGo117(gomod *types.Application) bool { - for _, lib := range gomod.Libraries { + for _, lib := range gomod.Packages { // The indirect field is populated only in Go 1.17+ if lib.Relationship == types.RelationshipIndirect { return false @@ -245,13 +244,13 @@ func mergeGoSum(gomod, gosum *types.Application) { return } uniq := make(map[string]types.Package) - for _, lib := range gomod.Libraries { + for _, lib := range gomod.Packages { // It will be used for merging go.sum. uniq[lib.Name] = lib } // For Go 1.16 or less, we need to merge go.sum into go.mod. - for _, lib := range gosum.Libraries { + for _, lib := range gosum.Packages { // Skip dependencies in go.mod so that go.mod should be preferred. if _, ok := uniq[lib.Name]; ok { continue @@ -263,7 +262,7 @@ func mergeGoSum(gomod, gosum *types.Application) { uniq[lib.Name] = lib } - gomod.Libraries = maps.Values(uniq) + gomod.Packages = maps.Values(uniq) } func findLicense(dir string, classifierConfidenceLevel float64) ([]string, error) { diff --git a/pkg/fanal/analyzer/language/golang/mod/mod_test.go b/pkg/fanal/analyzer/language/golang/mod/mod_test.go index c667170af7a6..02ed84c91ed7 100644 --- a/pkg/fanal/analyzer/language/golang/mod/mod_test.go +++ b/pkg/fanal/analyzer/language/golang/mod/mod_test.go @@ -31,19 +31,29 @@ func Test_gomodAnalyzer_Analyze(t *testing.T) { { Type: types.GoModule, FilePath: "go.mod", - Libraries: types.Packages{ + Packages: types.Packages{ { ID: "github.com/org/repo", Name: "github.com/org/repo", Relationship: types.RelationshipRoot, + ExternalReferences: []types.ExternalRef{ + { + Type: types.RefVCS, + URL: "https://github.com/org/repo", + }, + }, }, { ID: "github.com/aquasecurity/go-dep-parser@v0.0.0-20220406074731-71021a481237", Name: "github.com/aquasecurity/go-dep-parser", Version: "0.0.0-20220406074731-71021a481237", Relationship: types.RelationshipDirect, - Licenses: []string{ - "MIT", + Licenses: []string{"MIT"}, + ExternalReferences: []types.ExternalRef{ + { + Type: types.RefVCS, + URL: "https://github.com/aquasecurity/go-dep-parser", + }, }, DependsOn: []string{ "golang.org/x/xerrors@v0.0.0-20200804184101-5ec99f83aff1", @@ -71,17 +81,29 @@ func Test_gomodAnalyzer_Analyze(t *testing.T) { { Type: types.GoModule, FilePath: "go.mod", - Libraries: types.Packages{ + Packages: types.Packages{ { ID: "github.com/org/repo", Name: "github.com/org/repo", Relationship: types.RelationshipRoot, + ExternalReferences: []types.ExternalRef{ + { + Type: types.RefVCS, + URL: "https://github.com/org/repo", + }, + }, }, { ID: "github.com/sad/sad@v0.0.1", Name: "github.com/sad/sad", Version: "0.0.1", Relationship: types.RelationshipDirect, + ExternalReferences: []types.ExternalRef{ + { + Type: types.RefVCS, + URL: "https://github.com/sad/sad", + }, + }, }, }, }, @@ -99,11 +121,17 @@ func Test_gomodAnalyzer_Analyze(t *testing.T) { { Type: types.GoModule, FilePath: "go.mod", - Libraries: types.Packages{ + Packages: types.Packages{ { ID: "github.com/org/repo", Name: "github.com/org/repo", Relationship: types.RelationshipRoot, + ExternalReferences: []types.ExternalRef{ + { + Type: types.RefVCS, + URL: "https://github.com/org/repo", + }, + }, }, { ID: "github.com/aquasecurity/go-dep-parser@v0.0.0-20230219131432-590b1dfb6edd", @@ -113,6 +141,12 @@ func Test_gomodAnalyzer_Analyze(t *testing.T) { DependsOn: []string{ "github.com/BurntSushi/toml@v0.3.1", }, + ExternalReferences: []types.ExternalRef{ + { + Type: types.RefVCS, + URL: "https://github.com/aquasecurity/go-dep-parser", + }, + }, }, { ID: "github.com/BurntSushi/toml@v0.3.1", @@ -139,11 +173,17 @@ func Test_gomodAnalyzer_Analyze(t *testing.T) { { Type: types.GoModule, FilePath: "go.mod", - Libraries: types.Packages{ + Packages: types.Packages{ { ID: "github.com/org/repo", Name: "github.com/org/repo", Relationship: types.RelationshipRoot, + ExternalReferences: []types.ExternalRef{ + { + Type: types.RefVCS, + URL: "https://github.com/org/repo", + }, + }, }, { ID: "github.com/aquasecurity/go-dep-parser@v0.0.0-20230219131432-590b1dfb6edd", @@ -151,6 +191,12 @@ func Test_gomodAnalyzer_Analyze(t *testing.T) { Version: "0.0.0-20230219131432-590b1dfb6edd", Relationship: types.RelationshipDirect, DependsOn: []string{}, + ExternalReferences: []types.ExternalRef{ + { + Type: types.RefVCS, + URL: "https://github.com/aquasecurity/go-dep-parser", + }, + }, }, }, }, @@ -188,8 +234,8 @@ func Test_gomodAnalyzer_Analyze(t *testing.T) { assert.NoError(t, err) if len(got.Applications) > 0 { - sort.Sort(got.Applications[0].Libraries) - sort.Sort(tt.want.Applications[0].Libraries) + sort.Sort(got.Applications[0].Packages) + sort.Sort(tt.want.Applications[0].Packages) } assert.NoError(t, err) assert.Equal(t, tt.want, got) diff --git a/pkg/fanal/analyzer/language/java/gradle/lockfile.go b/pkg/fanal/analyzer/language/java/gradle/lockfile.go index 2426722c31ca..ce7fc2c31e59 100644 --- a/pkg/fanal/analyzer/language/java/gradle/lockfile.go +++ b/pkg/fanal/analyzer/language/java/gradle/lockfile.go @@ -13,7 +13,6 @@ import ( "golang.org/x/xerrors" "github.com/aquasecurity/trivy/pkg/dependency/parser/gradle/lockfile" - godeptypes "github.com/aquasecurity/trivy/pkg/dependency/types" "github.com/aquasecurity/trivy/pkg/fanal/analyzer" "github.com/aquasecurity/trivy/pkg/fanal/analyzer/language" "github.com/aquasecurity/trivy/pkg/fanal/types" @@ -33,7 +32,7 @@ const ( // gradleLockAnalyzer analyzes '*gradle.lockfile' type gradleLockAnalyzer struct { logger *log.Logger - parser godeptypes.Parser + parser language.Parser } func newGradleLockAnalyzer(_ analyzer.AnalyzerOptions) (analyzer.PostAnalyzer, error) { @@ -65,16 +64,16 @@ func (a gradleLockAnalyzer) PostAnalyze(_ context.Context, input analyzer.PostAn return nil } - libs := lo.SliceToMap(app.Libraries, func(lib types.Package) (string, struct{}) { + pkgs := lo.SliceToMap(app.Packages, func(lib types.Package) (string, struct{}) { return lib.ID, struct{}{} }) - for i, lib := range app.Libraries { + for i, lib := range app.Packages { pom := poms[lib.ID] // Fill licenses from pom file if len(pom.Licenses.License) > 0 { - app.Libraries[i].Licenses = lo.Map(pom.Licenses.License, func(license License, _ int) string { + app.Packages[i].Licenses = lo.Map(pom.Licenses.License, func(license License, _ int) string { return license.Name }) } @@ -83,15 +82,15 @@ func (a gradleLockAnalyzer) PostAnalyze(_ context.Context, input analyzer.PostAn var deps []string for _, dep := range pom.Dependencies.Dependency { id := packageID(dep.GroupID, dep.ArtifactID, dep.Version) - if _, ok := libs[id]; ok { + if _, ok := pkgs[id]; ok { deps = append(deps, id) } } sort.Strings(deps) - app.Libraries[i].DependsOn = deps + app.Packages[i].DependsOn = deps } - sort.Sort(app.Libraries) + sort.Sort(app.Packages) apps = append(apps, *app) return nil }) diff --git a/pkg/fanal/analyzer/language/java/gradle/lockfile_test.go b/pkg/fanal/analyzer/language/java/gradle/lockfile_test.go index 0f5c67d9049c..e226b542f7d1 100644 --- a/pkg/fanal/analyzer/language/java/gradle/lockfile_test.go +++ b/pkg/fanal/analyzer/language/java/gradle/lockfile_test.go @@ -28,7 +28,7 @@ func Test_gradleLockAnalyzer_Analyze(t *testing.T) { { Type: types.Gradle, FilePath: "gradle.lockfile", - Libraries: types.Packages{ + Packages: types.Packages{ { ID: "junit:junit:4.13", Name: "junit:junit", @@ -72,7 +72,7 @@ func Test_gradleLockAnalyzer_Analyze(t *testing.T) { { Type: types.Gradle, FilePath: "gradle.lockfile", - Libraries: types.Packages{ + Packages: types.Packages{ { ID: "junit:junit:4.13", Name: "junit:junit", diff --git a/pkg/fanal/analyzer/language/java/jar/jar_test.go b/pkg/fanal/analyzer/language/java/jar/jar_test.go index 3988dc27daf5..d1cf6ab1f491 100644 --- a/pkg/fanal/analyzer/language/java/jar/jar_test.go +++ b/pkg/fanal/analyzer/language/java/jar/jar_test.go @@ -37,7 +37,7 @@ func Test_javaLibraryAnalyzer_Analyze(t *testing.T) { { Type: types.Jar, FilePath: "testdata/test.war", - Libraries: types.Packages{ + Packages: types.Packages{ { Name: "org.glassfish:javax.el", FilePath: "testdata/test.war/WEB-INF/lib/javax.el-3.0.0.jar", @@ -92,7 +92,7 @@ func Test_javaLibraryAnalyzer_Analyze(t *testing.T) { { Type: types.Jar, FilePath: "testdata/test.par", - Libraries: types.Packages{ + Packages: types.Packages{ { Name: "com.fasterxml.jackson.core:jackson-core", FilePath: "testdata/test.par/lib/jackson-core-2.9.10.jar", @@ -112,7 +112,7 @@ func Test_javaLibraryAnalyzer_Analyze(t *testing.T) { { Type: types.Jar, FilePath: "testdata/test.jar", - Libraries: types.Packages{ + Packages: types.Packages{ { Name: "org.apache.tomcat.embed:tomcat-embed-websocket", FilePath: "testdata/test.jar", diff --git a/pkg/fanal/analyzer/language/java/pom/pom.go b/pkg/fanal/analyzer/language/java/pom/pom.go index d192d69dfc07..2980b469107c 100644 --- a/pkg/fanal/analyzer/language/java/pom/pom.go +++ b/pkg/fanal/analyzer/language/java/pom/pom.go @@ -34,8 +34,8 @@ func (a pomAnalyzer) Analyze(_ context.Context, input analyzer.AnalysisInput) (* // Mark integration test pom files for `maven-invoker-plugin` as Dev to skip them by default. if isIntegrationTestDir(filePath) { for i := range res.Applications { - for j := range res.Applications[i].Libraries { - res.Applications[i].Libraries[j].Dev = true + for j := range res.Applications[i].Packages { + res.Applications[i].Packages[j].Dev = true } } } diff --git a/pkg/fanal/analyzer/language/java/pom/pom_test.go b/pkg/fanal/analyzer/language/java/pom/pom_test.go index 3ea44231e7a5..865f2cb5471b 100644 --- a/pkg/fanal/analyzer/language/java/pom/pom_test.go +++ b/pkg/fanal/analyzer/language/java/pom/pom_test.go @@ -28,7 +28,7 @@ func Test_pomAnalyzer_Analyze(t *testing.T) { { Type: types.Pom, FilePath: "testdata/happy/pom.xml", - Libraries: types.Packages{ + Packages: types.Packages{ { ID: "com.example:example:1.0.0", Name: "com.example:example", @@ -65,7 +65,7 @@ func Test_pomAnalyzer_Analyze(t *testing.T) { { Type: types.Pom, FilePath: "pom.xml", - Libraries: types.Packages{ + Packages: types.Packages{ { ID: "com.example:example:1.0.0", Name: "com.example:example", @@ -101,7 +101,7 @@ func Test_pomAnalyzer_Analyze(t *testing.T) { { Type: types.Pom, FilePath: "testdata/mark-as-dev/src/it/example/pom.xml", - Libraries: types.Packages{ + Packages: types.Packages{ { ID: "com.example:example:1.0.0", Name: "com.example:example", @@ -139,7 +139,7 @@ func Test_pomAnalyzer_Analyze(t *testing.T) { { Type: types.Pom, FilePath: "testdata/requirements/pom.xml", - Libraries: types.Packages{ + Packages: types.Packages{ { ID: "com.example:example:2.0.0", Name: "com.example:example", diff --git a/pkg/fanal/analyzer/language/nodejs/license/license.go b/pkg/fanal/analyzer/language/nodejs/license/license.go index 0a797c558e56..529a8137d359 100644 --- a/pkg/fanal/analyzer/language/nodejs/license/license.go +++ b/pkg/fanal/analyzer/language/nodejs/license/license.go @@ -38,9 +38,9 @@ func (l *License) Traverse(fsys fs.FS, root string) (map[string][]string, error) return xerrors.Errorf("unable to parse %q: %w", pkgJSONPath, err) } - ok, licenseFileName := IsLicenseRefToFile(pkg.License) + ok, licenseFileName := IsLicenseRefToFile(pkg.Licenses) if !ok { - licenses[pkg.ID] = []string{pkg.License} + licenses[pkg.ID] = pkg.Licenses return nil } @@ -68,19 +68,19 @@ func (l *License) Traverse(fsys fs.FS, root string) (map[string][]string, error) // IsLicenseRefToFile The license field can refer to a file // https://docs.npmjs.com/cli/v9/configuring-npm/package-json -func IsLicenseRefToFile(maybeLicense string) (bool, string) { - if maybeLicense == "" { +func IsLicenseRefToFile(maybeLicenses []string) (bool, string) { + if len(maybeLicenses) != 1 { // trying to find at least the LICENSE file return true, "LICENSE" } var licenseFileName string - if strings.HasPrefix(maybeLicense, "LicenseRef-") { + if strings.HasPrefix(maybeLicenses[0], "LicenseRef-") { // LicenseRef- - licenseFileName = strings.Split(maybeLicense, "-")[1] - } else if strings.HasPrefix(maybeLicense, "SEE LICENSE IN ") { + licenseFileName = strings.Split(maybeLicenses[0], "-")[1] + } else if strings.HasPrefix(maybeLicenses[0], "SEE LICENSE IN ") { // SEE LICENSE IN - parts := strings.Split(maybeLicense, " ") + parts := strings.Split(maybeLicenses[0], " ") licenseFileName = parts[len(parts)-1] } diff --git a/pkg/fanal/analyzer/language/nodejs/license/license_test.go b/pkg/fanal/analyzer/language/nodejs/license/license_test.go index a282bc4bf6de..745d24cb4044 100644 --- a/pkg/fanal/analyzer/language/nodejs/license/license_test.go +++ b/pkg/fanal/analyzer/language/nodejs/license/license_test.go @@ -51,13 +51,13 @@ func Test_ParseLicenses(t *testing.T) { func Test_IsLicenseRefToFile(t *testing.T) { tests := []struct { name string - input string + input []string wantOk bool wantFileName string }{ { name: "no ref to file", - input: "MIT", + input: []string{"MIT"}, }, { name: "empty input", @@ -66,24 +66,24 @@ func Test_IsLicenseRefToFile(t *testing.T) { }, { name: "happy `SEE LICENSE IN`", - input: "SEE LICENSE IN LICENSE.md", + input: []string{"SEE LICENSE IN LICENSE.md"}, wantOk: true, wantFileName: "LICENSE.md", }, { name: "sad `SEE LICENSE IN`", - input: "SEE LICENSE IN ", + input: []string{"SEE LICENSE IN "}, wantOk: false, }, { name: "happy `LicenseRef-`", - input: "LicenseRef-LICENSE.txt", + input: []string{"LicenseRef-LICENSE.txt"}, wantOk: true, wantFileName: "LICENSE.txt", }, { name: "sad `LicenseRef-`", - input: "LicenseRef-", + input: []string{"LicenseRef-"}, wantOk: false, }, } @@ -92,7 +92,7 @@ func Test_IsLicenseRefToFile(t *testing.T) { t.Run(tt.name, func(t *testing.T) { ok, licenseFileName := license.IsLicenseRefToFile(tt.input) assert.Equal(t, ok, tt.wantOk) - assert.Equal(t, licenseFileName, tt.wantFileName) + assert.Equal(t, tt.wantFileName, licenseFileName) }) } } diff --git a/pkg/fanal/analyzer/language/nodejs/npm/npm.go b/pkg/fanal/analyzer/language/nodejs/npm/npm.go index 44123eade970..870ba1be88e7 100644 --- a/pkg/fanal/analyzer/language/nodejs/npm/npm.go +++ b/pkg/fanal/analyzer/language/nodejs/npm/npm.go @@ -13,7 +13,6 @@ import ( "github.com/aquasecurity/trivy/pkg/dependency/parser/nodejs/npm" "github.com/aquasecurity/trivy/pkg/dependency/parser/nodejs/packagejson" - godeptypes "github.com/aquasecurity/trivy/pkg/dependency/types" "github.com/aquasecurity/trivy/pkg/fanal/analyzer" "github.com/aquasecurity/trivy/pkg/fanal/analyzer/language" "github.com/aquasecurity/trivy/pkg/fanal/types" @@ -33,7 +32,7 @@ const ( type npmLibraryAnalyzer struct { logger *log.Logger - lockParser godeptypes.Parser + lockParser language.Parser packageParser *packagejson.Parser } @@ -57,7 +56,7 @@ func (a npmLibraryAnalyzer) PostAnalyze(_ context.Context, input analyzer.PostAn licenses, err := a.findLicenses(input.FS, filePath) if err != nil { a.logger.Error("Unable to collect licenses", log.Err(err)) - licenses = make(map[string]string) + licenses = make(map[string][]string) } app, err := a.parseNpmPkgLock(input.FS, filePath) @@ -68,9 +67,9 @@ func (a npmLibraryAnalyzer) PostAnalyze(_ context.Context, input analyzer.PostAn } // Fill licenses - for i, lib := range app.Libraries { - if license, ok := licenses[lib.ID]; ok { - app.Libraries[i].Licenses = []string{license} + for i, lib := range app.Packages { + if ll, ok := licenses[lib.ID]; ok { + app.Packages[i].Licenses = ll } } @@ -125,7 +124,7 @@ func (a npmLibraryAnalyzer) parseNpmPkgLock(fsys fs.FS, filePath string) (*types return language.Parse(types.Npm, filePath, file, a.lockParser) } -func (a npmLibraryAnalyzer) findLicenses(fsys fs.FS, lockPath string) (map[string]string, error) { +func (a npmLibraryAnalyzer) findLicenses(fsys fs.FS, lockPath string) (map[string][]string, error) { dir := path.Dir(lockPath) root := path.Join(dir, "node_modules") if _, err := fs.Stat(fsys, root); errors.Is(err, fs.ErrNotExist) { @@ -142,14 +141,14 @@ func (a npmLibraryAnalyzer) findLicenses(fsys fs.FS, lockPath string) (map[strin // Traverse node_modules dir and find licenses // Note that fs.FS is always slashed regardless of the platform, // and path.Join should be used rather than filepath.Join. - licenses := make(map[string]string) + licenses := make(map[string][]string) err := fsutils.WalkDir(fsys, root, required, func(filePath string, d fs.DirEntry, r io.Reader) error { pkg, err := a.packageParser.Parse(r) if err != nil { return xerrors.Errorf("unable to parse %q: %w", filePath, err) } - licenses[pkg.ID] = pkg.License + licenses[pkg.ID] = pkg.Licenses return nil }) if err != nil { diff --git a/pkg/fanal/analyzer/language/nodejs/npm/npm_test.go b/pkg/fanal/analyzer/language/nodejs/npm/npm_test.go index 82130279836d..010a6207502d 100644 --- a/pkg/fanal/analyzer/language/nodejs/npm/npm_test.go +++ b/pkg/fanal/analyzer/language/nodejs/npm/npm_test.go @@ -33,7 +33,7 @@ func Test_npmLibraryAnalyzer_Analyze(t *testing.T) { { Type: types.Npm, FilePath: "package-lock.json", - Libraries: types.Packages{ + Packages: types.Packages{ { ID: "@babel/parser@7.23.6", Name: "@babel/parser", @@ -45,6 +45,12 @@ func Test_npmLibraryAnalyzer_Analyze(t *testing.T) { EndLine: 10, }, }, + ExternalReferences: []types.ExternalRef{ + { + Type: types.RefOther, + URL: "https://registry.npmjs.org/@babel/parser/-/parser-7.23.6.tgz", + }, + }, }, { ID: "ansi-colors@3.2.3", @@ -57,6 +63,12 @@ func Test_npmLibraryAnalyzer_Analyze(t *testing.T) { EndLine: 16, }, }, + ExternalReferences: []types.ExternalRef{ + { + Type: types.RefOther, + URL: "https://registry.npmjs.org/ansi-colors/-/ansi-colors-3.2.3.tgz", + }, + }, }, { ID: "array-flatten@1.1.1", @@ -68,6 +80,12 @@ func Test_npmLibraryAnalyzer_Analyze(t *testing.T) { EndLine: 21, }, }, + ExternalReferences: []types.ExternalRef{ + { + Type: types.RefOther, + URL: "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", + }, + }, }, { ID: "body-parser@1.18.3", @@ -81,6 +99,12 @@ func Test_npmLibraryAnalyzer_Analyze(t *testing.T) { EndLine: 44, }, }, + ExternalReferences: []types.ExternalRef{ + { + Type: types.RefOther, + URL: "https://registry.npmjs.org/body-parser/-/body-parser-1.18.3.tgz", + }, + }, }, { ID: "debug@2.6.9", @@ -98,6 +122,12 @@ func Test_npmLibraryAnalyzer_Analyze(t *testing.T) { EndLine: 60, }, }, + ExternalReferences: []types.ExternalRef{ + { + Type: types.RefOther, + URL: "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + }, + }, }, { ID: "express@4.16.4", @@ -111,6 +141,12 @@ func Test_npmLibraryAnalyzer_Analyze(t *testing.T) { EndLine: 67, }, }, + ExternalReferences: []types.ExternalRef{ + { + Type: types.RefOther, + URL: "https://registry.npmjs.org/express/-/express-4.16.4.tgz", + }, + }, }, { ID: "ms@2.0.0", @@ -127,6 +163,12 @@ func Test_npmLibraryAnalyzer_Analyze(t *testing.T) { EndLine: 65, }, }, + ExternalReferences: []types.ExternalRef{ + { + Type: types.RefOther, + URL: "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + }, + }, }, { ID: "ms@2.1.1", @@ -139,6 +181,12 @@ func Test_npmLibraryAnalyzer_Analyze(t *testing.T) { EndLine: 72, }, }, + ExternalReferences: []types.ExternalRef{ + { + Type: types.RefOther, + URL: "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", + }, + }, }, }, }, @@ -153,7 +201,7 @@ func Test_npmLibraryAnalyzer_Analyze(t *testing.T) { { Type: types.Npm, FilePath: "package-lock.json", - Libraries: types.Packages{ + Packages: types.Packages{ { ID: "ms@2.1.1", Name: "ms", @@ -164,6 +212,12 @@ func Test_npmLibraryAnalyzer_Analyze(t *testing.T) { EndLine: 10, }, }, + ExternalReferences: []types.ExternalRef{ + { + Type: types.RefOther, + URL: "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", + }, + }, }, }, }, @@ -187,7 +241,7 @@ func Test_npmLibraryAnalyzer_Analyze(t *testing.T) { assert.NoError(t, err) if len(got.Applications) > 0 { - sort.Sort(got.Applications[0].Libraries) + sort.Sort(got.Applications[0].Packages) } assert.Equal(t, tt.want, got) }) diff --git a/pkg/fanal/analyzer/language/nodejs/pkg/pkg.go b/pkg/fanal/analyzer/language/nodejs/pkg/pkg.go index aabc4da6b6a2..5ca5d4eeae80 100644 --- a/pkg/fanal/analyzer/language/nodejs/pkg/pkg.go +++ b/pkg/fanal/analyzer/language/nodejs/pkg/pkg.go @@ -6,7 +6,6 @@ import ( "path/filepath" "github.com/aquasecurity/trivy/pkg/dependency/parser/nodejs/packagejson" - godeptypes "github.com/aquasecurity/trivy/pkg/dependency/types" "github.com/aquasecurity/trivy/pkg/fanal/analyzer" "github.com/aquasecurity/trivy/pkg/fanal/analyzer/language" "github.com/aquasecurity/trivy/pkg/fanal/types" @@ -24,20 +23,20 @@ const ( type parser struct{} -func (*parser) Parse(r xio.ReadSeekerAt) ([]godeptypes.Library, []godeptypes.Dependency, error) { +func (*parser) Parse(r xio.ReadSeekerAt) ([]types.Package, []types.Dependency, error) { p := packagejson.NewParser() pkg, err := p.Parse(r) if err != nil { return nil, nil, err } // skip packages without name/version - if pkg.Library.ID == "" { + if pkg.Package.ID == "" { return nil, nil, nil } // package.json may contain version range in `dependencies` fields // e.g. "devDependencies": { "mocha": "^5.2.0", } // so we get only information about project - return []godeptypes.Library{pkg.Library}, nil, nil + return []types.Package{pkg.Package}, nil, nil } type nodePkgLibraryAnalyzer struct{} diff --git a/pkg/fanal/analyzer/language/nodejs/pkg/pkg_test.go b/pkg/fanal/analyzer/language/nodejs/pkg/pkg_test.go index 91a6bb6d708d..c27032b45166 100644 --- a/pkg/fanal/analyzer/language/nodejs/pkg/pkg_test.go +++ b/pkg/fanal/analyzer/language/nodejs/pkg/pkg_test.go @@ -28,7 +28,7 @@ func Test_nodePkgLibraryAnalyzer_Analyze(t *testing.T) { { Type: types.NodePkg, FilePath: "testdata/package.json", - Libraries: types.Packages{ + Packages: types.Packages{ { ID: "lodash@5.0.0", Name: "lodash", @@ -50,7 +50,7 @@ func Test_nodePkgLibraryAnalyzer_Analyze(t *testing.T) { { Type: types.NodePkg, FilePath: "testdata/package.json", - Libraries: types.Packages{ + Packages: types.Packages{ { ID: "lodash@5.0.0", Name: "lodash", diff --git a/pkg/fanal/analyzer/language/nodejs/pnpm/pnpm_test.go b/pkg/fanal/analyzer/language/nodejs/pnpm/pnpm_test.go index 85200cccc2e7..c3a50922a569 100644 --- a/pkg/fanal/analyzer/language/nodejs/pnpm/pnpm_test.go +++ b/pkg/fanal/analyzer/language/nodejs/pnpm/pnpm_test.go @@ -27,7 +27,7 @@ func Test_pnpmPkgLibraryAnalyzer_Analyze(t *testing.T) { { Type: types.Pnpm, FilePath: "testdata/pnpm-lock.yaml", - Libraries: types.Packages{ + Packages: types.Packages{ { ID: "lodash@4.17.21", Name: "lodash", diff --git a/pkg/fanal/analyzer/language/nodejs/yarn/yarn.go b/pkg/fanal/analyzer/language/nodejs/yarn/yarn.go index feabf4d6abc1..086f5fe7f615 100644 --- a/pkg/fanal/analyzer/language/nodejs/yarn/yarn.go +++ b/pkg/fanal/analyzer/language/nodejs/yarn/yarn.go @@ -20,7 +20,6 @@ import ( "github.com/aquasecurity/trivy/pkg/dependency/parser/nodejs/packagejson" "github.com/aquasecurity/trivy/pkg/dependency/parser/nodejs/yarn" - godeptypes "github.com/aquasecurity/trivy/pkg/dependency/types" "github.com/aquasecurity/trivy/pkg/detector/library/compare/npm" "github.com/aquasecurity/trivy/pkg/fanal/analyzer" "github.com/aquasecurity/trivy/pkg/fanal/analyzer/language" @@ -44,7 +43,7 @@ var fragmentRegexp = regexp.MustCompile(`(\S+):(@?.*?)(@(.*?)|)$`) type yarnAnalyzer struct { logger *log.Logger packageJsonParser *packagejson.Parser - lockParser godeptypes.Parser + lockParser language.Parser comparer npm.Comparer license *license.License } @@ -87,9 +86,9 @@ func (a yarnAnalyzer) PostAnalyze(_ context.Context, input analyzer.PostAnalysis } // Fill licenses - for i, lib := range app.Libraries { + for i, lib := range app.Packages { if l, ok := licenses[lib.ID]; ok { - app.Libraries[i].Licenses = l + app.Packages[i].Licenses = l } } @@ -165,20 +164,20 @@ func (a yarnAnalyzer) analyzeDependencies(fsys fs.FS, dir string, app *types.App return xerrors.Errorf("unable to parse %s: %w", dir, err) } - // yarn.lock file can contain same libraries with different versions + // yarn.lock file can contain same packages with different versions // save versions separately for version comparison by comparator - pkgIDs := lo.SliceToMap(app.Libraries, func(pkg types.Package) (string, types.Package) { + pkgIDs := lo.SliceToMap(app.Packages, func(pkg types.Package) (string, types.Package) { return pkg.ID, pkg }) // Walk prod dependencies - pkgs, err := a.walkDependencies(app.Libraries, pkgIDs, directDeps, false) + pkgs, err := a.walkDependencies(app.Packages, pkgIDs, directDeps, false) if err != nil { return xerrors.Errorf("unable to walk dependencies: %w", err) } // Walk dev dependencies - devPkgs, err := a.walkDependencies(app.Libraries, pkgIDs, directDevDeps, true) + devPkgs, err := a.walkDependencies(app.Packages, pkgIDs, directDevDeps, true) if err != nil { return xerrors.Errorf("unable to walk dependencies: %w", err) } @@ -190,17 +189,17 @@ func (a yarnAnalyzer) analyzeDependencies(fsys fs.FS, dir string, app *types.App pkgSlice := maps.Values(pkgs) sort.Sort(types.Packages(pkgSlice)) - // Save libraries - app.Libraries = pkgSlice + // Save packages + app.Packages = pkgSlice return nil } -func (a yarnAnalyzer) walkDependencies(libs []types.Package, pkgIDs map[string]types.Package, +func (a yarnAnalyzer) walkDependencies(pkgs []types.Package, pkgIDs map[string]types.Package, directDeps map[string]string, dev bool) (map[string]types.Package, error) { // Identify direct dependencies - pkgs := make(map[string]types.Package) - for _, pkg := range libs { + directPkgs := make(map[string]types.Package) + for _, pkg := range pkgs { constraint, ok := directDeps[pkg.Name] if !ok { continue @@ -224,16 +223,16 @@ func (a yarnAnalyzer) walkDependencies(libs []types.Package, pkgIDs map[string]t pkg.Indirect = false pkg.Relationship = types.RelationshipDirect pkg.Dev = dev - pkgs[pkg.ID] = pkg + directPkgs[pkg.ID] = pkg } // Walk indirect dependencies - for _, pkg := range pkgs { - a.walkIndirectDependencies(pkg, pkgIDs, pkgs) + for _, pkg := range directPkgs { + a.walkIndirectDependencies(pkg, pkgIDs, directPkgs) } - return pkgs, nil + return directPkgs, nil } func (a yarnAnalyzer) walkIndirectDependencies(pkg types.Package, pkgIDs, deps map[string]types.Package) { diff --git a/pkg/fanal/analyzer/language/nodejs/yarn/yarn_test.go b/pkg/fanal/analyzer/language/nodejs/yarn/yarn_test.go index 6815dd6b4127..7aae5d5181ae 100644 --- a/pkg/fanal/analyzer/language/nodejs/yarn/yarn_test.go +++ b/pkg/fanal/analyzer/language/nodejs/yarn/yarn_test.go @@ -26,7 +26,7 @@ func Test_yarnLibraryAnalyzer_Analyze(t *testing.T) { { Type: types.Yarn, FilePath: "yarn.lock", - Libraries: types.Packages{ + Packages: types.Packages{ { ID: "js-tokens@2.0.0", Name: "js-tokens", @@ -39,6 +39,40 @@ func Test_yarnLibraryAnalyzer_Analyze(t *testing.T) { }, }, }, + { + ID: "prop-types@15.7.2", + Name: "prop-types", + Version: "15.7.2", + Dev: true, + Relationship: types.RelationshipDirect, + Locations: []types.Location{ + { + StartLine: 27, + EndLine: 34, + }, + }, + DependsOn: []string{ + "loose-envify@1.4.0", + "object-assign@4.1.1", + "react-is@16.13.1", + }, + }, + { + ID: "scheduler@0.13.6", + Name: "scheduler", + Version: "0.13.6", + Relationship: types.RelationshipDirect, + Locations: []types.Location{ + { + StartLine: 41, + EndLine: 47, + }, + }, + DependsOn: []string{ + "loose-envify@1.4.0", + "object-assign@4.1.1", + }, + }, { ID: "js-tokens@4.0.0", Name: "js-tokens", @@ -81,24 +115,6 @@ func Test_yarnLibraryAnalyzer_Analyze(t *testing.T) { }, }, }, - { - ID: "prop-types@15.7.2", - Name: "prop-types", - Version: "15.7.2", - Dev: true, - Relationship: types.RelationshipDirect, - Locations: []types.Location{ - { - StartLine: 27, - EndLine: 34, - }, - }, - DependsOn: []string{ - "loose-envify@1.4.0", - "object-assign@4.1.1", - "react-is@16.13.1", - }, - }, { ID: "react-is@16.13.1", Name: "react-is", @@ -113,22 +129,6 @@ func Test_yarnLibraryAnalyzer_Analyze(t *testing.T) { }, }, }, - { - ID: "scheduler@0.13.6", - Name: "scheduler", - Version: "0.13.6", - Relationship: types.RelationshipDirect, - Locations: []types.Location{ - { - StartLine: 41, - EndLine: 47, - }, - }, - DependsOn: []string{ - "loose-envify@1.4.0", - "object-assign@4.1.1", - }, - }, }, }, }, @@ -142,7 +142,7 @@ func Test_yarnLibraryAnalyzer_Analyze(t *testing.T) { { Type: types.Yarn, FilePath: "foo/yarn.lock", - Libraries: types.Packages{ + Packages: types.Packages{ { ID: "hoek@6.1.3", Name: "hoek", @@ -168,7 +168,7 @@ func Test_yarnLibraryAnalyzer_Analyze(t *testing.T) { { Type: types.Yarn, FilePath: "yarn.lock", - Libraries: types.Packages{ + Packages: types.Packages{ { ID: "js-tokens@2.0.0", Name: "js-tokens", @@ -271,7 +271,7 @@ func Test_yarnLibraryAnalyzer_Analyze(t *testing.T) { { Type: types.Yarn, FilePath: "yarn.lock", - Libraries: types.Packages{ + Packages: types.Packages{ { ID: "js-tokens@2.0.0", Name: "js-tokens", @@ -307,7 +307,7 @@ func Test_yarnLibraryAnalyzer_Analyze(t *testing.T) { { Type: types.Yarn, FilePath: "yarn.lock", - Libraries: []types.Package{ + Packages: []types.Package{ { ID: "is-callable@1.2.7", Name: "is-callable", @@ -321,20 +321,6 @@ func Test_yarnLibraryAnalyzer_Analyze(t *testing.T) { }, }, }, - { - ID: "is-number@6.0.0", - Name: "is-number", - Version: "6.0.0", - Licenses: []string{"MIT"}, - Indirect: true, - Relationship: types.RelationshipIndirect, - Locations: []types.Location{ - { - StartLine: 15, - EndLine: 20, - }, - }, - }, { ID: "is-odd@3.0.1", Name: "is-odd", @@ -349,6 +335,20 @@ func Test_yarnLibraryAnalyzer_Analyze(t *testing.T) { }, }, }, + { + ID: "is-number@6.0.0", + Name: "is-number", + Version: "6.0.0", + Licenses: []string{"MIT"}, + Indirect: true, + Relationship: types.RelationshipIndirect, + Locations: []types.Location{ + { + StartLine: 15, + EndLine: 20, + }, + }, + }, }, }, }, @@ -362,7 +362,7 @@ func Test_yarnLibraryAnalyzer_Analyze(t *testing.T) { { Type: types.Yarn, FilePath: "yarn.lock", - Libraries: types.Packages{ + Packages: types.Packages{ { ID: "foo-json@0.8.33", Name: "@types/jsonstream", @@ -380,23 +380,6 @@ func Test_yarnLibraryAnalyzer_Analyze(t *testing.T) { "@types/node@20.10.5", }, }, - { - ID: "@types/node@20.10.5", - Name: "@types/node", - Version: "20.10.5", - Indirect: true, - Relationship: types.RelationshipIndirect, - Dev: true, - Locations: []types.Location{ - { - StartLine: 5, - EndLine: 10, - }, - }, - DependsOn: []string{ - "undici-types@5.26.5", - }, - }, { ID: "foo-uuid@9.0.7", Name: "@types/uuid", @@ -428,28 +411,45 @@ func Test_yarnLibraryAnalyzer_Analyze(t *testing.T) { }, }, { - ID: "ms@2.1.2", + ID: "foo-ms@2.1.3", Name: "ms", - Version: "2.1.2", + Version: "2.1.3", + Indirect: false, + Relationship: types.RelationshipDirect, + Locations: []types.Location{ + { + StartLine: 26, + EndLine: 29, + }, + }, + }, + { + ID: "@types/node@20.10.5", + Name: "@types/node", + Version: "20.10.5", Indirect: true, Relationship: types.RelationshipIndirect, + Dev: true, Locations: []types.Location{ { - StartLine: 36, - EndLine: 39, + StartLine: 5, + EndLine: 10, }, }, + DependsOn: []string{ + "undici-types@5.26.5", + }, }, { - ID: "foo-ms@2.1.3", + ID: "ms@2.1.2", Name: "ms", - Version: "2.1.3", - Indirect: false, - Relationship: types.RelationshipDirect, + Version: "2.1.2", + Indirect: true, + Relationship: types.RelationshipIndirect, Locations: []types.Location{ { - StartLine: 26, - EndLine: 29, + StartLine: 36, + EndLine: 39, }, }, }, @@ -480,20 +480,7 @@ func Test_yarnLibraryAnalyzer_Analyze(t *testing.T) { { Type: types.Yarn, FilePath: "yarn.lock", - Libraries: types.Packages{ - { - ID: "is-number@6.0.0", - Name: "is-number", - Version: "6.0.0", - Indirect: true, - Relationship: types.RelationshipIndirect, - Locations: []types.Location{ - { - StartLine: 16, - EndLine: 21, - }, - }, - }, + Packages: types.Packages{ { ID: "is-number@7.0.0", Name: "is-number", @@ -519,19 +506,6 @@ func Test_yarnLibraryAnalyzer_Analyze(t *testing.T) { }, }, }, - { - ID: "js-tokens@4.0.0", - Name: "js-tokens", - Version: "4.0.0", - Indirect: true, - Relationship: types.RelationshipIndirect, - Locations: []types.Location{ - { - StartLine: 39, - EndLine: 44, - }, - }, - }, { ID: "js-tokens@8.0.1", Name: "js-tokens", @@ -544,34 +518,6 @@ func Test_yarnLibraryAnalyzer_Analyze(t *testing.T) { }, }, }, - { - ID: "loose-envify@1.4.0", - Name: "loose-envify", - Version: "1.4.0", - Indirect: true, - Relationship: types.RelationshipIndirect, - DependsOn: []string{"js-tokens@4.0.0"}, - Locations: []types.Location{ - { - StartLine: 53, - EndLine: 62, - }, - }, - }, - { - ID: "object-assign@4.1.1", - Name: "object-assign", - Version: "4.1.1", - Indirect: true, - Relationship: types.RelationshipIndirect, - Dev: true, - Locations: []types.Location{ - { - StartLine: 64, - EndLine: 69, - }, - }, - }, { ID: "prettier@2.8.8", Name: "prettier", @@ -604,29 +550,83 @@ func Test_yarnLibraryAnalyzer_Analyze(t *testing.T) { }, }, { - ID: "react-is@16.13.1", - Name: "react-is", - Version: "16.13.1", + ID: "scheduler@0.23.0", + Name: "scheduler", + Version: "0.23.0", + Relationship: types.RelationshipDirect, + DependsOn: []string{"loose-envify@1.4.0"}, + Locations: []types.Location{ + { + StartLine: 114, + EndLine: 121, + }, + }, + }, + { + ID: "is-number@6.0.0", + Name: "is-number", + Version: "6.0.0", + Indirect: true, + Relationship: types.RelationshipIndirect, + Locations: []types.Location{ + { + StartLine: 16, + EndLine: 21, + }, + }, + }, + { + ID: "js-tokens@4.0.0", + Name: "js-tokens", + Version: "4.0.0", + Indirect: true, + Relationship: types.RelationshipIndirect, + Locations: []types.Location{ + { + StartLine: 39, + EndLine: 44, + }, + }, + }, + { + ID: "loose-envify@1.4.0", + Name: "loose-envify", + Version: "1.4.0", + Indirect: true, + Relationship: types.RelationshipIndirect, + DependsOn: []string{"js-tokens@4.0.0"}, + Locations: []types.Location{ + { + StartLine: 53, + EndLine: 62, + }, + }, + }, + { + ID: "object-assign@4.1.1", + Name: "object-assign", + Version: "4.1.1", Indirect: true, Relationship: types.RelationshipIndirect, Dev: true, Locations: []types.Location{ { - StartLine: 107, - EndLine: 112, + StartLine: 64, + EndLine: 69, }, }, }, { - ID: "scheduler@0.23.0", - Name: "scheduler", - Version: "0.23.0", - Relationship: types.RelationshipDirect, - DependsOn: []string{"loose-envify@1.4.0"}, + ID: "react-is@16.13.1", + Name: "react-is", + Version: "16.13.1", + Indirect: true, + Relationship: types.RelationshipIndirect, + Dev: true, Locations: []types.Location{ { - StartLine: 114, - EndLine: 121, + StartLine: 107, + EndLine: 112, }, }, }, @@ -647,21 +647,7 @@ func Test_yarnLibraryAnalyzer_Analyze(t *testing.T) { { Type: types.Yarn, FilePath: "yarn.lock", - Libraries: []types.Package{ - { - ID: "@babel/parser@7.22.7", - Name: "@babel/parser", - Version: "7.22.7", - Indirect: true, - Relationship: types.RelationshipIndirect, - Locations: []types.Location{ - { - StartLine: 5, - EndLine: 8, - }, - }, - Licenses: []string{"MIT"}, - }, + Packages: []types.Package{ { ID: "@vue/compiler-sfc@2.7.14", Name: "@vue/compiler-sfc", @@ -681,6 +667,20 @@ func Test_yarnLibraryAnalyzer_Analyze(t *testing.T) { "source-map@0.6.1", }, }, + { + ID: "@babel/parser@7.22.7", + Name: "@babel/parser", + Version: "7.22.7", + Indirect: true, + Relationship: types.RelationshipIndirect, + Locations: []types.Location{ + { + StartLine: 5, + EndLine: 8, + }, + }, + Licenses: []string{"MIT"}, + }, { ID: "nanoid@3.3.6", Name: "nanoid", diff --git a/pkg/fanal/analyzer/language/php/composer/composer.go b/pkg/fanal/analyzer/language/php/composer/composer.go index 06f8e7487c62..5e726168a5ae 100644 --- a/pkg/fanal/analyzer/language/php/composer/composer.go +++ b/pkg/fanal/analyzer/language/php/composer/composer.go @@ -15,7 +15,6 @@ import ( "golang.org/x/xerrors" "github.com/aquasecurity/trivy/pkg/dependency/parser/php/composer" - godeptypes "github.com/aquasecurity/trivy/pkg/dependency/types" "github.com/aquasecurity/trivy/pkg/fanal/analyzer" "github.com/aquasecurity/trivy/pkg/fanal/analyzer/language" "github.com/aquasecurity/trivy/pkg/fanal/types" @@ -35,7 +34,7 @@ var requiredFiles = []string{ } type composerAnalyzer struct { - lockParser godeptypes.Parser + lockParser language.Parser } func newComposerAnalyzer(_ analyzer.AnalyzerOptions) (analyzer.PostAnalyzer, error) { @@ -65,7 +64,7 @@ func (a composerAnalyzer) PostAnalyze(_ context.Context, input analyzer.PostAnal log.Warn("Unable to parse composer.json to identify direct dependencies", log.String("path", filepath.Join(filepath.Dir(path), types.ComposerJson)), log.Err(err)) } - sort.Sort(app.Libraries) + sort.Sort(app.Packages) apps = append(apps, *app) return nil @@ -116,13 +115,13 @@ func (a composerAnalyzer) mergeComposerJson(fsys fs.FS, dir string, app *types.A return xerrors.Errorf("unable to parse %s: %w", path, err) } - for i, lib := range app.Libraries { + for i, pkg := range app.Packages { // Identify the direct/transitive dependencies - if _, ok := p[lib.Name]; ok { - app.Libraries[i].Relationship = types.RelationshipDirect + if _, ok := p[pkg.Name]; ok { + app.Packages[i].Relationship = types.RelationshipDirect } else { - app.Libraries[i].Indirect = true - app.Libraries[i].Relationship = types.RelationshipIndirect + app.Packages[i].Indirect = true + app.Packages[i].Relationship = types.RelationshipIndirect } } diff --git a/pkg/fanal/analyzer/language/php/composer/composer_test.go b/pkg/fanal/analyzer/language/php/composer/composer_test.go index 61cc3af8bc50..cc5d6908fc84 100644 --- a/pkg/fanal/analyzer/language/php/composer/composer_test.go +++ b/pkg/fanal/analyzer/language/php/composer/composer_test.go @@ -26,7 +26,7 @@ func Test_composerAnalyzer_PostAnalyze(t *testing.T) { { Type: types.Composer, FilePath: "composer.lock", - Libraries: types.Packages{ + Packages: types.Packages{ { ID: "pear/log@1.13.3", Name: "pear/log", @@ -69,7 +69,7 @@ func Test_composerAnalyzer_PostAnalyze(t *testing.T) { { Type: types.Composer, FilePath: "composer.lock", - Libraries: types.Packages{ + Packages: types.Packages{ { ID: "pear/log@1.13.3", Name: "pear/log", @@ -112,7 +112,7 @@ func Test_composerAnalyzer_PostAnalyze(t *testing.T) { { Type: types.Composer, FilePath: "composer.lock", - Libraries: types.Packages{ + Packages: types.Packages{ { ID: "pear/log@1.13.3", Name: "pear/log", diff --git a/pkg/fanal/analyzer/language/python/packaging/packaging.go b/pkg/fanal/analyzer/language/python/packaging/packaging.go index 6f2c508b5404..51fd585d8a6c 100644 --- a/pkg/fanal/analyzer/language/python/packaging/packaging.go +++ b/pkg/fanal/analyzer/language/python/packaging/packaging.go @@ -16,7 +16,6 @@ import ( "golang.org/x/xerrors" "github.com/aquasecurity/trivy/pkg/dependency/parser/python/packaging" - godeptypes "github.com/aquasecurity/trivy/pkg/dependency/types" "github.com/aquasecurity/trivy/pkg/fanal/analyzer" "github.com/aquasecurity/trivy/pkg/fanal/analyzer/language" "github.com/aquasecurity/trivy/pkg/fanal/types" @@ -56,7 +55,7 @@ var ( type packagingAnalyzer struct { logger *log.Logger - pkgParser godeptypes.Parser + pkgParser language.Parser licenseClassifierConfidenceLevel float64 } @@ -117,9 +116,9 @@ func (a packagingAnalyzer) PostAnalyze(_ context.Context, input analyzer.PostAna } func (a packagingAnalyzer) fillAdditionalData(fsys fs.FS, app *types.Application) error { - for i, lib := range app.Libraries { + for i, pkg := range app.Packages { var licenses []string - for _, lic := range lib.Licenses { + for _, lic := range pkg.Licenses { // Parser adds `file://` prefix to filepath from `License-File` field // We need to read this file to find licenses // Otherwise, this is the name of the license @@ -142,7 +141,7 @@ func (a packagingAnalyzer) fillAdditionalData(fsys fs.FS, app *types.Application }) licenses = append(licenses, foundLicenses...) } - app.Libraries[i].Licenses = licenses + app.Packages[i].Licenses = licenses } return nil diff --git a/pkg/fanal/analyzer/language/python/packaging/packaging_test.go b/pkg/fanal/analyzer/language/python/packaging/packaging_test.go index 2dbfd603e92b..eac4d29f5e84 100644 --- a/pkg/fanal/analyzer/language/python/packaging/packaging_test.go +++ b/pkg/fanal/analyzer/language/python/packaging/packaging_test.go @@ -28,7 +28,7 @@ func Test_packagingAnalyzer_Analyze(t *testing.T) { { Type: types.PythonPkg, FilePath: "kitchen-1.2.6-py2.7.egg", - Libraries: types.Packages{ + Packages: types.Packages{ { Name: "kitchen", Version: "1.2.6", @@ -51,7 +51,7 @@ func Test_packagingAnalyzer_Analyze(t *testing.T) { { Type: types.PythonPkg, FilePath: "distlib-0.3.1.egg-info/PKG-INFO", - Libraries: types.Packages{ + Packages: types.Packages{ { Name: "distlib", Version: "0.3.1", @@ -72,7 +72,7 @@ func Test_packagingAnalyzer_Analyze(t *testing.T) { { Type: types.PythonPkg, FilePath: "setuptools-51.3.3.egg-info/PKG-INFO", - Libraries: types.Packages{ + Packages: types.Packages{ { Name: "setuptools", Version: "51.3.3", @@ -92,7 +92,7 @@ func Test_packagingAnalyzer_Analyze(t *testing.T) { { Type: types.PythonPkg, FilePath: "setuptools-51.3.3.dist-info/METADATA", - Libraries: types.Packages{ + Packages: types.Packages{ { Name: "setuptools", Version: "51.3.3", @@ -112,7 +112,7 @@ func Test_packagingAnalyzer_Analyze(t *testing.T) { { Type: types.PythonPkg, FilePath: "distlib-0.3.1.dist-info/METADATA", - Libraries: types.Packages{ + Packages: types.Packages{ { Name: "distlib", Version: "0.3.1", @@ -137,11 +137,16 @@ func Test_packagingAnalyzer_Analyze(t *testing.T) { { Type: types.PythonPkg, FilePath: "typing_extensions-4.4.0.dist-info/METADATA", - Libraries: []types.Package{ + Packages: []types.Package{ { - Name: "typing_extensions", - Version: "4.4.0", - Licenses: []string{"BeOpen", "CNRI-Python-GPL-Compatible", "LicenseRef-MIT-Lucent", "Python-2.0"}, + Name: "typing_extensions", + Version: "4.4.0", + Licenses: []string{ + "BeOpen", + "CNRI-Python-GPL-Compatible", + "LicenseRef-MIT-Lucent", + "Python-2.0", + }, FilePath: "typing_extensions-4.4.0.dist-info/METADATA", }, }, diff --git a/pkg/fanal/analyzer/language/python/pip/pip_test.go b/pkg/fanal/analyzer/language/python/pip/pip_test.go index b023648ae5d0..0a930f5cce51 100644 --- a/pkg/fanal/analyzer/language/python/pip/pip_test.go +++ b/pkg/fanal/analyzer/language/python/pip/pip_test.go @@ -27,7 +27,7 @@ func Test_pipAnalyzer_Analyze(t *testing.T) { { Type: types.Pip, FilePath: "testdata/requirements.txt", - Libraries: types.Packages{ + Packages: types.Packages{ { Name: "click", Version: "8.0.0", diff --git a/pkg/fanal/analyzer/language/python/poetry/poetry.go b/pkg/fanal/analyzer/language/python/poetry/poetry.go index bff6ae68e129..84af54c587df 100644 --- a/pkg/fanal/analyzer/language/python/poetry/poetry.go +++ b/pkg/fanal/analyzer/language/python/poetry/poetry.go @@ -12,7 +12,6 @@ import ( "github.com/aquasecurity/trivy/pkg/dependency/parser/python/poetry" "github.com/aquasecurity/trivy/pkg/dependency/parser/python/pyproject" - godeptypes "github.com/aquasecurity/trivy/pkg/dependency/types" "github.com/aquasecurity/trivy/pkg/fanal/analyzer" "github.com/aquasecurity/trivy/pkg/fanal/analyzer/language" "github.com/aquasecurity/trivy/pkg/fanal/types" @@ -29,7 +28,7 @@ const version = 1 type poetryAnalyzer struct { logger *log.Logger pyprojectParser *pyproject.Parser - lockParser godeptypes.Parser + lockParser language.Parser } func newPoetryAnalyzer(_ analyzer.AnalyzerOptions) (analyzer.PostAnalyzer, error) { @@ -103,13 +102,13 @@ func (a poetryAnalyzer) mergePyProject(fsys fs.FS, dir string, app *types.Applic return xerrors.Errorf("unable to parse %s: %w", path, err) } - for i, lib := range app.Libraries { + for i, pkg := range app.Packages { // Identify the direct/transitive dependencies - if _, ok := p[lib.Name]; ok { - app.Libraries[i].Relationship = types.RelationshipDirect + if _, ok := p[pkg.Name]; ok { + app.Packages[i].Relationship = types.RelationshipDirect } else { - app.Libraries[i].Indirect = true - app.Libraries[i].Relationship = types.RelationshipIndirect + app.Packages[i].Indirect = true + app.Packages[i].Relationship = types.RelationshipIndirect } } diff --git a/pkg/fanal/analyzer/language/python/poetry/poetry_test.go b/pkg/fanal/analyzer/language/python/poetry/poetry_test.go index 49cc06c420b6..b0e38a51f5e0 100644 --- a/pkg/fanal/analyzer/language/python/poetry/poetry_test.go +++ b/pkg/fanal/analyzer/language/python/poetry/poetry_test.go @@ -26,7 +26,7 @@ func Test_poetryLibraryAnalyzer_Analyze(t *testing.T) { { Type: types.Poetry, FilePath: "poetry.lock", - Libraries: types.Packages{ + Packages: types.Packages{ { ID: "certifi@2022.12.7", Name: "certifi", @@ -130,7 +130,7 @@ func Test_poetryLibraryAnalyzer_Analyze(t *testing.T) { { Type: types.Poetry, FilePath: "poetry.lock", - Libraries: types.Packages{ + Packages: types.Packages{ { ID: "click@8.1.3", Name: "click", @@ -157,7 +157,7 @@ func Test_poetryLibraryAnalyzer_Analyze(t *testing.T) { { Type: types.Poetry, FilePath: "poetry.lock", - Libraries: types.Packages{ + Packages: types.Packages{ { ID: "click@8.1.3", Name: "click", diff --git a/pkg/fanal/analyzer/language/ruby/gemspec/gemspec_test.go b/pkg/fanal/analyzer/language/ruby/gemspec/gemspec_test.go index 4bd48d379f8b..41e4746b68b6 100644 --- a/pkg/fanal/analyzer/language/ruby/gemspec/gemspec_test.go +++ b/pkg/fanal/analyzer/language/ruby/gemspec/gemspec_test.go @@ -28,7 +28,7 @@ func Test_gemspecLibraryAnalyzer_Analyze(t *testing.T) { { Type: types.GemSpec, FilePath: "testdata/multiple_licenses.gemspec", - Libraries: types.Packages{ + Packages: types.Packages{ { Name: "test-unit", Version: "3.3.7", @@ -53,7 +53,7 @@ func Test_gemspecLibraryAnalyzer_Analyze(t *testing.T) { { Type: types.GemSpec, FilePath: "testdata/multiple_licenses.gemspec", - Libraries: types.Packages{ + Packages: types.Packages{ { Name: "test-unit", Version: "3.3.7", diff --git a/pkg/fanal/analyzer/language/rust/binary/binary_test.go b/pkg/fanal/analyzer/language/rust/binary/binary_test.go index b2a87e52d63a..27bfce04eea0 100644 --- a/pkg/fanal/analyzer/language/rust/binary/binary_test.go +++ b/pkg/fanal/analyzer/language/rust/binary/binary_test.go @@ -28,7 +28,7 @@ func Test_rustBinaryLibraryAnalyzer_Analyze(t *testing.T) { { Type: types.RustBinary, FilePath: "testdata/executable_rust", - Libraries: types.Packages{ + Packages: types.Packages{ { ID: "crate_with_features@0.1.0", Name: "crate_with_features", diff --git a/pkg/fanal/analyzer/language/rust/cargo/cargo.go b/pkg/fanal/analyzer/language/rust/cargo/cargo.go index e4a6bcc4736b..5795586ab33a 100644 --- a/pkg/fanal/analyzer/language/rust/cargo/cargo.go +++ b/pkg/fanal/analyzer/language/rust/cargo/cargo.go @@ -20,7 +20,6 @@ import ( "github.com/aquasecurity/go-version/pkg/semver" goversion "github.com/aquasecurity/go-version/pkg/version" "github.com/aquasecurity/trivy/pkg/dependency/parser/rust/cargo" - godeptypes "github.com/aquasecurity/trivy/pkg/dependency/types" "github.com/aquasecurity/trivy/pkg/detector/library/compare" "github.com/aquasecurity/trivy/pkg/fanal/analyzer" "github.com/aquasecurity/trivy/pkg/fanal/analyzer/language" @@ -42,7 +41,7 @@ var requiredFiles = []string{ type cargoAnalyzer struct { logger *log.Logger - lockParser godeptypes.Parser + lockParser language.Parser comparer compare.GenericComparer } @@ -75,7 +74,7 @@ func (a cargoAnalyzer) PostAnalyze(_ context.Context, input analyzer.PostAnalysi a.logger.Warn("Unable to parse Cargo.toml q to identify direct dependencies", log.String("path", path.Join(path.Dir(filePath), types.CargoToml)), log.Err(err)) } - sort.Sort(app.Libraries) + sort.Sort(app.Packages) apps = append(apps, *app) return nil @@ -116,16 +115,16 @@ func (a cargoAnalyzer) removeDevDependencies(fsys fs.FS, dir string, app *types. return xerrors.Errorf("unable to parse %s: %w", cargoTOMLPath, err) } - // Cargo.toml file can contain same libraries with different versions. + // Cargo.toml file can contain same packages with different versions. // Save versions separately for version comparison by comparator - pkgIDs := lo.SliceToMap(app.Libraries, func(pkg types.Package) (string, types.Package) { + pkgIDs := lo.SliceToMap(app.Packages, func(pkg types.Package) (string, types.Package) { return pkg.ID, pkg }) // Identify direct dependencies pkgs := make(map[string]types.Package) for name, constraint := range directDeps { - for _, pkg := range app.Libraries { + for _, pkg := range app.Packages { if pkg.Name != name { continue } @@ -152,8 +151,8 @@ func (a cargoAnalyzer) removeDevDependencies(fsys fs.FS, dir string, app *types. pkgSlice := maps.Values(pkgs) sort.Sort(types.Packages(pkgSlice)) - // Save only prod libraries - app.Libraries = pkgSlice + // Save only prod packages + app.Packages = pkgSlice return nil } diff --git a/pkg/fanal/analyzer/language/rust/cargo/cargo_test.go b/pkg/fanal/analyzer/language/rust/cargo/cargo_test.go index c5fb27278069..52c5820faa04 100644 --- a/pkg/fanal/analyzer/language/rust/cargo/cargo_test.go +++ b/pkg/fanal/analyzer/language/rust/cargo/cargo_test.go @@ -27,34 +27,7 @@ func Test_cargoAnalyzer_Analyze(t *testing.T) { { Type: types.Cargo, FilePath: "Cargo.lock", - Libraries: types.Packages{ - { - ID: "aho-corasick@0.7.20", - Name: "aho-corasick", - Version: "0.7.20", - Indirect: true, - Relationship: types.RelationshipIndirect, - Locations: []types.Location{ - { - StartLine: 4, - EndLine: 11, - }, - }, - DependsOn: []string{"memchr@2.5.0"}, - }, - { - ID: "libc@0.2.140", - Name: "libc", - Version: "0.2.140", - Indirect: true, - Relationship: types.RelationshipIndirect, - Locations: []types.Location{ - { - StartLine: 22, - EndLine: 26, - }, - }, - }, + Packages: types.Packages{ { ID: "memchr@1.0.2", Name: "memchr", @@ -69,19 +42,6 @@ func Test_cargoAnalyzer_Analyze(t *testing.T) { }, DependsOn: []string{"libc@0.2.140"}, }, - { - ID: "memchr@2.5.0", - Name: "memchr", - Version: "2.5.0", - Indirect: true, - Relationship: types.RelationshipIndirect, - Locations: []types.Location{ - { - StartLine: 37, - EndLine: 41, - }, - }, - }, { ID: "regex@1.7.3", Name: "regex", @@ -114,6 +74,46 @@ func Test_cargoAnalyzer_Analyze(t *testing.T) { }, DependsOn: []string{"ucd-util@0.1.10"}, }, + { + ID: "aho-corasick@0.7.20", + Name: "aho-corasick", + Version: "0.7.20", + Indirect: true, + Relationship: types.RelationshipIndirect, + Locations: []types.Location{ + { + StartLine: 4, + EndLine: 11, + }, + }, + DependsOn: []string{"memchr@2.5.0"}, + }, + { + ID: "libc@0.2.140", + Name: "libc", + Version: "0.2.140", + Indirect: true, + Relationship: types.RelationshipIndirect, + Locations: []types.Location{ + { + StartLine: 22, + EndLine: 26, + }, + }, + }, + { + ID: "memchr@2.5.0", + Name: "memchr", + Version: "2.5.0", + Indirect: true, + Relationship: types.RelationshipIndirect, + Locations: []types.Location{ + { + StartLine: 37, + EndLine: 41, + }, + }, + }, { ID: "regex-syntax@0.6.29", Name: "regex-syntax", @@ -153,7 +153,7 @@ func Test_cargoAnalyzer_Analyze(t *testing.T) { { Type: types.Cargo, FilePath: "Cargo.lock", - Libraries: types.Packages{ + Packages: types.Packages{ { ID: "memchr@2.5.0", Name: "memchr", @@ -180,7 +180,7 @@ func Test_cargoAnalyzer_Analyze(t *testing.T) { { Type: types.Cargo, FilePath: "Cargo.lock", - Libraries: types.Packages{ + Packages: types.Packages{ { ID: "aho-corasick@0.7.20", Name: "aho-corasick", @@ -367,7 +367,7 @@ func Test_cargoAnalyzer_Analyze(t *testing.T) { { Type: types.Cargo, FilePath: "Cargo.lock", - Libraries: types.Packages{ + Packages: types.Packages{ { ID: "app@0.1.0", Name: "app", @@ -413,21 +413,7 @@ func Test_cargoAnalyzer_Analyze(t *testing.T) { { Type: types.Cargo, FilePath: "Cargo.lock", - Libraries: types.Packages{ - { - ID: "aho-corasick@1.1.2", - Name: "aho-corasick", - Version: "1.1.2", - Indirect: true, - Relationship: types.RelationshipIndirect, - Locations: []types.Location{ - { - StartLine: 5, - EndLine: 12, - }, - }, - DependsOn: []string{"memchr@2.6.4"}, - }, + Packages: types.Packages{ { ID: "gdb-command@0.7.6", Name: "gdb-command", @@ -445,6 +431,38 @@ func Test_cargoAnalyzer_Analyze(t *testing.T) { "wait-timeout@0.2.0", }, }, + { + ID: "regex@1.10.2", + Name: "regex", + Version: "1.10.2", + Relationship: types.RelationshipDirect, + Locations: []types.Location{ + { + StartLine: 50, + EndLine: 60, + }, + }, + DependsOn: []string{ + "aho-corasick@1.1.2", + "memchr@2.6.4", + "regex-automata@0.4.3", + "regex-syntax@0.8.2", + }, + }, + { + ID: "aho-corasick@1.1.2", + Name: "aho-corasick", + Version: "1.1.2", + Indirect: true, + Relationship: types.RelationshipIndirect, + Locations: []types.Location{ + { + StartLine: 5, + EndLine: 12, + }, + }, + DependsOn: []string{"memchr@2.6.4"}, + }, { ID: "libc@0.2.150", Name: "libc", @@ -471,24 +489,6 @@ func Test_cargoAnalyzer_Analyze(t *testing.T) { }, }, }, - { - ID: "regex@1.10.2", - Name: "regex", - Version: "1.10.2", - Relationship: types.RelationshipDirect, - Locations: []types.Location{ - { - StartLine: 50, - EndLine: 60, - }, - }, - DependsOn: []string{ - "aho-corasick@1.1.2", - "memchr@2.6.4", - "regex-automata@0.4.3", - "regex-syntax@0.8.2", - }, - }, { ID: "regex-automata@0.4.3", Name: "regex-automata", diff --git a/pkg/fanal/analyzer/language/swift/cocoapods/cocoapods_test.go b/pkg/fanal/analyzer/language/swift/cocoapods/cocoapods_test.go index fcf2e7254f59..5dfc9be18d56 100644 --- a/pkg/fanal/analyzer/language/swift/cocoapods/cocoapods_test.go +++ b/pkg/fanal/analyzer/language/swift/cocoapods/cocoapods_test.go @@ -26,7 +26,7 @@ func Test_cocoaPodsLockAnalyzer_Analyze(t *testing.T) { { Type: types.Cocoapods, FilePath: "testdata/happy.lock", - Libraries: types.Packages{ + Packages: types.Packages{ { ID: "AppCenter@4.2.0", Name: "AppCenter", @@ -87,7 +87,7 @@ func Test_cocoaPodsLockAnalyzer_Analyze(t *testing.T) { if got != nil { for _, app := range got.Applications { - sort.Sort(app.Libraries) + sort.Sort(app.Packages) } } diff --git a/pkg/fanal/analyzer/language/swift/swift/swift_test.go b/pkg/fanal/analyzer/language/swift/swift/swift_test.go index 9a7fc981c1fc..73066aa69948 100644 --- a/pkg/fanal/analyzer/language/swift/swift/swift_test.go +++ b/pkg/fanal/analyzer/language/swift/swift/swift_test.go @@ -25,7 +25,7 @@ func Test_swiftLockAnalyzer_Analyze(t *testing.T) { { Type: types.Swift, FilePath: "testdata/happy/Package.resolved", - Libraries: types.Packages{ + Packages: types.Packages{ { ID: "github.com/Quick/Nimble@9.2.1", diff --git a/pkg/fanal/analyzer/sbom/sbom.go b/pkg/fanal/analyzer/sbom/sbom.go index efb9829a1593..6392f0200da3 100644 --- a/pkg/fanal/analyzer/sbom/sbom.go +++ b/pkg/fanal/analyzer/sbom/sbom.go @@ -77,17 +77,17 @@ func handleBitnamiImages(componentPath string, bom types.SBOM) { if app.Type == ftypes.Bitnami { // Set the component dir path to the application bom.Applications[i].FilePath = componentPath - // Either Application.FilePath or Application.Libraries[].FilePath should be set + // Either Application.FilePath or Application.Packages[].FilePath should be set continue } - for j, pkg := range app.Libraries { + for j, pkg := range app.Packages { // Set the absolute path since SBOM in Bitnami images contain a relative path // e.g. modules/apm/elastic-apm-agent-1.36.0.jar // => opt/bitnami/elasticsearch/modules/apm/elastic-apm-agent-1.36.0.jar // If the file path is empty, the file path will be set to the component dir path. filePath := path.Join(componentPath, pkg.FilePath) - bom.Applications[i].Libraries[j].FilePath = filePath + bom.Applications[i].Packages[j].FilePath = filePath } } } diff --git a/pkg/fanal/analyzer/sbom/sbom_test.go b/pkg/fanal/analyzer/sbom/sbom_test.go index 3bcb619d402b..c1c09b24a5bc 100644 --- a/pkg/fanal/analyzer/sbom/sbom_test.go +++ b/pkg/fanal/analyzer/sbom/sbom_test.go @@ -29,7 +29,7 @@ func Test_sbomAnalyzer_Analyze(t *testing.T) { Applications: []types.Application{ { Type: types.Jar, - Libraries: types.Packages{ + Packages: types.Packages{ { ID: "co.elastic.apm:apm-agent:1.36.0", Name: "co.elastic.apm:apm-agent", @@ -91,7 +91,7 @@ func Test_sbomAnalyzer_Analyze(t *testing.T) { { Type: types.Bitnami, FilePath: "opt/bitnami/elasticsearch", - Libraries: types.Packages{ + Packages: types.Packages{ { ID: "Elasticsearch@8.9.1", Name: "Elasticsearch", @@ -126,7 +126,7 @@ func Test_sbomAnalyzer_Analyze(t *testing.T) { Applications: []types.Application{ { Type: types.Jar, - Libraries: types.Packages{ + Packages: types.Packages{ { FilePath: "opt/bitnami/elasticsearch/modules/apm/elastic-apm-agent-1.36.0.jar", ID: "co.elastic.apm:apm-agent:1.36.0", @@ -172,7 +172,7 @@ func Test_sbomAnalyzer_Analyze(t *testing.T) { { Type: types.Bitnami, FilePath: "opt/bitnami/postgresql", - Libraries: types.Packages{ + Packages: types.Packages{ { ID: "GDAL@3.7.1", Name: "GDAL", diff --git a/pkg/fanal/applier/applier_test.go b/pkg/fanal/applier/applier_test.go index bea3f30fa0c5..a1844c5bb545 100644 --- a/pkg/fanal/applier/applier_test.go +++ b/pkg/fanal/applier/applier_test.go @@ -111,7 +111,7 @@ func TestApplier_ApplyLayers(t *testing.T) { { Type: "composer", FilePath: "php-app/composer.lock", - Libraries: types.Packages{ + Packages: types.Packages{ { Name: "guzzlehttp/guzzle", Version: "6.2.0", @@ -200,7 +200,7 @@ func TestApplier_ApplyLayers(t *testing.T) { { Type: "composer", FilePath: "php-app/composer.lock", - Libraries: types.Packages{ + Packages: types.Packages{ { Name: "guzzlehttp/guzzle", Version: "6.2.0", @@ -623,7 +623,7 @@ func TestApplier_ApplyLayers(t *testing.T) { { Type: "composer", FilePath: "php-app/composer.lock", - Libraries: types.Packages{ + Packages: types.Packages{ { Name: "guzzlehttp/guzzle", Version: "6.2.0", @@ -672,7 +672,7 @@ func TestApplier_ApplyLayers(t *testing.T) { { Type: "composer", FilePath: "php-app/composer.lock", - Libraries: types.Packages{ + Packages: types.Packages{ { Name: "guzzlehttp/guzzle", Version: "6.2.0", @@ -833,7 +833,7 @@ func TestApplier_ApplyLayers(t *testing.T) { { Type: "composer", FilePath: "php-app/composer.lock", - Libraries: types.Packages{ + Packages: types.Packages{ { Name: "guzzlehttp/guzzle", Version: "6.2.0", @@ -885,7 +885,7 @@ func TestApplier_ApplyLayers(t *testing.T) { { Type: "composer", FilePath: "php-app/composer.lock", - Libraries: types.Packages{ + Packages: types.Packages{ { Name: "guzzlehttp/guzzle", Version: "6.2.0", @@ -980,7 +980,7 @@ func TestApplier_ApplyLayers(t *testing.T) { sort.Sort(got.Packages) for _, app := range got.Applications { - sort.Sort(app.Libraries) + sort.Sort(app.Packages) } sort.Slice(got.CustomResources, func(i, j int) bool { diff --git a/pkg/fanal/applier/docker.go b/pkg/fanal/applier/docker.go index 7640cfadaec6..41487819b4ae 100644 --- a/pkg/fanal/applier/docker.go +++ b/pkg/fanal/applier/docker.go @@ -81,7 +81,7 @@ func lookupOriginLayerForLib(filePath string, lib ftypes.Package, layers []ftype if filePath != layerApp.FilePath { continue } - if containsPackage(lib, layerApp.Libraries) { + if containsPackage(lib, layerApp.Packages) { return layer.Digest, layer.DiffID } } @@ -230,19 +230,19 @@ func ApplyLayers(layers []ftypes.BlobInfo) ftypes.ArtifactDetail { } for _, app := range mergedLayer.Applications { - for i, lib := range app.Libraries { + for i, pkg := range app.Packages { // Skip lookup for SBOM - if lo.IsEmpty(lib.Layer) { - originLayerDigest, originLayerDiffID := lookupOriginLayerForLib(app.FilePath, lib, layers) - app.Libraries[i].Layer = ftypes.Layer{ + if lo.IsEmpty(pkg.Layer) { + originLayerDigest, originLayerDiffID := lookupOriginLayerForLib(app.FilePath, pkg, layers) + app.Packages[i].Layer = ftypes.Layer{ Digest: originLayerDigest, DiffID: originLayerDiffID, } } - if lib.Identifier.PURL == nil { - app.Libraries[i].Identifier.PURL = newPURL(app.Type, types.Metadata{}, lib) + if pkg.Identifier.PURL == nil { + app.Packages[i].Identifier.PURL = newPURL(app.Type, types.Metadata{}, pkg) } - app.Libraries[i].Identifier.UID = calcPkgUID(app.FilePath, lib) + app.Packages[i].Identifier.UID = calcPkgUID(app.FilePath, pkg) } } @@ -292,11 +292,11 @@ func aggregate(detail *ftypes.ArtifactDetail) { apps = append(apps, app) continue } - a.Libraries = append(a.Libraries, app.Libraries...) + a.Packages = append(a.Packages, app.Packages...) } for _, app := range aggregatedApps { - if len(app.Libraries) > 0 { + if len(app.Packages) > 0 { apps = append(apps, *app) } } diff --git a/pkg/fanal/applier/docker_test.go b/pkg/fanal/applier/docker_test.go index 9a5f043c6e3c..f5bccfa86bf6 100644 --- a/pkg/fanal/applier/docker_test.go +++ b/pkg/fanal/applier/docker_test.go @@ -44,7 +44,7 @@ func TestApplyLayers(t *testing.T) { { Type: types.Bundler, FilePath: "app/Gemfile.lock", - Libraries: types.Packages{ + Packages: types.Packages{ { Name: "gemlibrary1", Version: "1.2.3", @@ -54,7 +54,7 @@ func TestApplyLayers(t *testing.T) { { Type: types.Composer, FilePath: "app/composer.lock", - Libraries: types.Packages{ + Packages: types.Packages{ { Name: "phplibrary1", Version: "6.6.6", @@ -64,7 +64,7 @@ func TestApplyLayers(t *testing.T) { { Type: types.GemSpec, FilePath: "usr/local/bundle/specifications/gon-6.3.2.gemspec", - Libraries: types.Packages{ + Packages: types.Packages{ { Name: "gon", Version: "6.3.2", @@ -123,7 +123,7 @@ func TestApplyLayers(t *testing.T) { { Type: types.GemSpec, FilePath: "var/lib/gems/2.5.0/specifications/activesupport-6.0.2.1.gemspec", - Libraries: types.Packages{ + Packages: types.Packages{ { Name: "activesupport", Version: "6.0.2.1", @@ -192,7 +192,7 @@ func TestApplyLayers(t *testing.T) { Applications: []types.Application{ { Type: types.GemSpec, - Libraries: types.Packages{ + Packages: types.Packages{ { Name: "activesupport", Version: "6.0.2.1", @@ -232,7 +232,7 @@ func TestApplyLayers(t *testing.T) { { Type: types.Bundler, FilePath: "app/Gemfile.lock", - Libraries: types.Packages{ + Packages: types.Packages{ { Name: "gemlibrary1", Version: "1.2.3", @@ -284,7 +284,7 @@ func TestApplyLayers(t *testing.T) { Applications: []types.Application{ { Type: types.PythonPkg, - Libraries: types.Packages{ + Packages: types.Packages{ { Name: "pip", Version: "23.0.1", @@ -339,7 +339,7 @@ func TestApplyLayers(t *testing.T) { Applications: []types.Application{ { Type: types.PythonPkg, - Libraries: types.Packages{ + Packages: types.Packages{ { Name: "pip", Version: "23.0.1", @@ -406,7 +406,7 @@ func TestApplyLayers(t *testing.T) { { Type: types.Bundler, FilePath: "app/Gemfile.lock", - Libraries: types.Packages{ + Packages: types.Packages{ { Name: "rails", Version: "5.0.0", @@ -420,7 +420,7 @@ func TestApplyLayers(t *testing.T) { { Type: types.Composer, FilePath: "app/composer.lock", - Libraries: types.Packages{ + Packages: types.Packages{ { Name: "phplibrary1", Version: "6.6.6", @@ -430,7 +430,7 @@ func TestApplyLayers(t *testing.T) { { Type: types.GemSpec, FilePath: "var/lib/gems/2.5.0/specifications/activesupport-6.0.2.1.gemspec", - Libraries: types.Packages{ + Packages: types.Packages{ { Name: "activesupport", Version: "6.0.2.1", @@ -448,7 +448,7 @@ func TestApplyLayers(t *testing.T) { { Type: types.Bundler, FilePath: "app/Gemfile.lock", - Libraries: types.Packages{ + Packages: types.Packages{ { Name: "rails", Version: "6.0.0", @@ -462,7 +462,7 @@ func TestApplyLayers(t *testing.T) { { Type: "composer", FilePath: "app/composer2.lock", - Libraries: types.Packages{ + Packages: types.Packages{ { Name: "phplibrary1", Version: "6.6.6", @@ -485,7 +485,7 @@ func TestApplyLayers(t *testing.T) { { Type: types.Bundler, FilePath: "app/Gemfile.lock", - Libraries: types.Packages{ + Packages: types.Packages{ { Name: "rack", Version: "4.0.0", @@ -523,7 +523,7 @@ func TestApplyLayers(t *testing.T) { { Type: types.Composer, FilePath: "app/composer2.lock", - Libraries: types.Packages{ + Packages: types.Packages{ { Name: "phplibrary1", Version: "6.6.6", @@ -736,7 +736,7 @@ func TestApplyLayers(t *testing.T) { { Type: "composer", FilePath: "app/composer.lock", - Libraries: types.Packages{ + Packages: types.Packages{ { Name: "phplibrary1", Version: "6.6.6", @@ -854,7 +854,7 @@ func TestApplyLayers(t *testing.T) { { Type: "composer", FilePath: "app/composer.lock", - Libraries: types.Packages{ + Packages: types.Packages{ { Name: "phplibrary1", Version: "6.6.6", @@ -1069,7 +1069,7 @@ func TestApplyLayers(t *testing.T) { { Type: types.Bundler, FilePath: "app1/Gemfile.lock", - Libraries: types.Packages{ + Packages: types.Packages{ { Name: "gemlibrary1", Version: "1.2.3", @@ -1079,7 +1079,7 @@ func TestApplyLayers(t *testing.T) { { Type: types.Bundler, FilePath: "app2/Gemfile.lock", - Libraries: types.Packages{ + Packages: types.Packages{ { Name: "gemlibrary1", Version: "1.2.3", @@ -1094,7 +1094,7 @@ func TestApplyLayers(t *testing.T) { { Type: types.Bundler, FilePath: "app1/Gemfile.lock", - Libraries: types.Packages{ + Packages: types.Packages{ { Name: "gemlibrary1", Version: "1.2.3", @@ -1116,7 +1116,7 @@ func TestApplyLayers(t *testing.T) { { Type: types.Bundler, FilePath: "app2/Gemfile.lock", - Libraries: types.Packages{ + Packages: types.Packages{ { Name: "gemlibrary1", Version: "1.2.3", @@ -1148,7 +1148,7 @@ func TestApplyLayers(t *testing.T) { return got.Applications[i].FilePath < got.Applications[j].FilePath }) for _, app := range got.Applications { - sort.Sort(app.Libraries) + sort.Sort(app.Packages) } assert.Equal(t, tt.want, got, tt.name) }) diff --git a/pkg/fanal/artifact/image/image_test.go b/pkg/fanal/artifact/image/image_test.go index d741b78e4c9f..fbcddef9ce4a 100644 --- a/pkg/fanal/artifact/image/image_test.go +++ b/pkg/fanal/artifact/image/image_test.go @@ -700,7 +700,7 @@ func TestArtifact_Inspect(t *testing.T) { { Type: "composer", FilePath: "php-app/composer.lock", - Libraries: types.Packages{ + Packages: types.Packages{ { ID: "guzzlehttp/guzzle@6.2.0", Name: "guzzlehttp/guzzle", @@ -908,7 +908,114 @@ func TestArtifact_Inspect(t *testing.T) { { Type: "bundler", FilePath: "ruby-app/Gemfile.lock", - Libraries: types.Packages{ + Packages: types.Packages{ + { + ID: "dotenv@2.7.2", + Name: "dotenv", + Version: "2.7.2", + Indirect: false, + Relationship: types.RelationshipDirect, + DependsOn: []string(nil), + Locations: []types.Location{ + { + StartLine: 51, + EndLine: 51, + }, + }, + }, + { + ID: "faker@1.9.3", + Name: "faker", + Version: "1.9.3", + Indirect: false, + Relationship: types.RelationshipDirect, + DependsOn: []string{"i18n@1.6.0"}, + Locations: []types.Location{ + { + StartLine: 53, + EndLine: 53, + }, + }, + }, + { + ID: "json@2.2.0", + Name: "json", + Version: "2.2.0", + Indirect: false, + Relationship: types.RelationshipDirect, + DependsOn: []string(nil), + Locations: []types.Location{ + { + StartLine: 60, + EndLine: 60, + }, + }, + }, + { + ID: "pry@0.12.2", + Name: "pry", + Version: "0.12.2", + Indirect: false, + Relationship: types.RelationshipDirect, + DependsOn: []string{ + "coderay@1.1.2", + "method_source@0.9.2", + }, + Locations: []types.Location{ + { + StartLine: 79, + EndLine: 79, + }, + }, + }, + { + ID: "rails@5.2.0", + Name: "rails", + Version: "5.2.0", + Indirect: false, + Relationship: types.RelationshipDirect, + DependsOn: []string{ + "actioncable@5.2.3", + "actionmailer@5.2.3", + "actionpack@5.2.3", + "actionview@5.2.3", + "activejob@5.2.3", + "activemodel@5.2.3", + "activerecord@5.2.3", + "activestorage@5.2.3", + "activesupport@5.2.3", + "railties@5.2.3", + "sprockets-rails@3.2.1", + }, + Locations: []types.Location{ + { + StartLine: 86, + EndLine: 86, + }, + }, + }, + { + ID: "rubocop@0.67.2", + Name: "rubocop", + Version: "0.67.2", + Indirect: false, + Relationship: types.RelationshipDirect, + DependsOn: []string{ + "jaro_winkler@1.5.2", + "parallel@1.17.0", + "parser@2.6.3.0", + "psych@3.1.0", + "rainbow@3.0.0", + "ruby-progressbar@1.10.0", + "unicode-display_width@1.5.0", + }, + Locations: []types.Location{ + { + StartLine: 112, + EndLine: 112, + }, + }, + }, { ID: "actioncable@5.2.3", Name: "actioncable", @@ -1158,20 +1265,6 @@ func TestArtifact_Inspect(t *testing.T) { }, }, }, - { - ID: "dotenv@2.7.2", - Name: "dotenv", - Version: "2.7.2", - Indirect: false, - Relationship: types.RelationshipDirect, - DependsOn: []string(nil), - Locations: []types.Location{ - { - StartLine: 51, - EndLine: 51, - }, - }, - }, { ID: "erubi@1.8.0", Name: "erubi", @@ -1186,20 +1279,6 @@ func TestArtifact_Inspect(t *testing.T) { }, }, }, - { - ID: "faker@1.9.3", - Name: "faker", - Version: "1.9.3", - Indirect: false, - Relationship: types.RelationshipDirect, - DependsOn: []string{"i18n@1.6.0"}, - Locations: []types.Location{ - { - StartLine: 53, - EndLine: 53, - }, - }, - }, { ID: "globalid@0.4.2", Name: "globalid", @@ -1242,20 +1321,6 @@ func TestArtifact_Inspect(t *testing.T) { }, }, }, - { - ID: "json@2.2.0", - Name: "json", - Version: "2.2.0", - Indirect: false, - Relationship: types.RelationshipDirect, - DependsOn: []string(nil), - Locations: []types.Location{ - { - StartLine: 60, - EndLine: 60, - }, - }, - }, { ID: "loofah@2.2.3", Name: "loofah", @@ -1427,23 +1492,6 @@ func TestArtifact_Inspect(t *testing.T) { }, }, }, - { - ID: "pry@0.12.2", - Name: "pry", - Version: "0.12.2", - Indirect: false, - Relationship: types.RelationshipDirect, - DependsOn: []string{ - "coderay@1.1.2", - "method_source@0.9.2", - }, - Locations: []types.Location{ - { - StartLine: 79, - EndLine: 79, - }, - }, - }, { ID: "psych@3.1.0", Name: "psych", @@ -1486,32 +1534,6 @@ func TestArtifact_Inspect(t *testing.T) { }, }, }, - { - ID: "rails@5.2.0", - Name: "rails", - Version: "5.2.0", - Indirect: false, - Relationship: types.RelationshipDirect, - DependsOn: []string{ - "actioncable@5.2.3", - "actionmailer@5.2.3", - "actionpack@5.2.3", - "actionview@5.2.3", - "activejob@5.2.3", - "activemodel@5.2.3", - "activerecord@5.2.3", - "activestorage@5.2.3", - "activesupport@5.2.3", - "railties@5.2.3", - "sprockets-rails@3.2.1", - }, - Locations: []types.Location{ - { - StartLine: 86, - EndLine: 86, - }, - }, - }, { ID: "rails-dom-testing@2.0.3", Name: "rails-dom-testing", @@ -1591,28 +1613,6 @@ func TestArtifact_Inspect(t *testing.T) { }, }, }, - { - ID: "rubocop@0.67.2", - Name: "rubocop", - Version: "0.67.2", - Indirect: false, - Relationship: types.RelationshipDirect, - DependsOn: []string{ - "jaro_winkler@1.5.2", - "parallel@1.17.0", - "parser@2.6.3.0", - "psych@3.1.0", - "rainbow@3.0.0", - "ruby-progressbar@1.10.0", - "unicode-display_width@1.5.0", - }, - Locations: []types.Location{ - { - StartLine: 112, - EndLine: 112, - }, - }, - }, { ID: "ruby-progressbar@1.10.0", Name: "ruby-progressbar", diff --git a/pkg/fanal/artifact/image/remote_sbom_test.go b/pkg/fanal/artifact/image/remote_sbom_test.go index ef777fe5c641..b38bdc5c6dc5 100644 --- a/pkg/fanal/artifact/image/remote_sbom_test.go +++ b/pkg/fanal/artifact/image/remote_sbom_test.go @@ -223,13 +223,13 @@ func TestArtifact_inspectOCIReferrerSBOM(t *testing.T) { putBlobExpectations: []cache.ArtifactCachePutBlobExpectation{ { Args: cache.ArtifactCachePutBlobArgs{ - BlobID: "sha256:7e0b5476a5ff5a10594ad1ed7566220fcc43ecff29b831236cb2e98e574a1d05", + BlobID: "sha256:a06ed679a3289fba254040e1ce8f3467fadcc454ee3d0d4720f6978065f56684", BlobInfo: types.BlobInfo{ SchemaVersion: types.BlobJSONSchemaVersion, Applications: []types.Application{ { Type: types.GoBinary, - Libraries: types.Packages{ + Packages: types.Packages{ { ID: "github.com/opencontainers/go-digest@v1.0.0", Name: "github.com/opencontainers/go-digest", @@ -268,9 +268,9 @@ func TestArtifact_inspectOCIReferrerSBOM(t *testing.T) { want: types.ArtifactReference{ Name: registry + "/test/image:10", Type: types.ArtifactCycloneDX, - ID: "sha256:7e0b5476a5ff5a10594ad1ed7566220fcc43ecff29b831236cb2e98e574a1d05", + ID: "sha256:a06ed679a3289fba254040e1ce8f3467fadcc454ee3d0d4720f6978065f56684", BlobIDs: []string{ - "sha256:7e0b5476a5ff5a10594ad1ed7566220fcc43ecff29b831236cb2e98e574a1d05", + "sha256:a06ed679a3289fba254040e1ce8f3467fadcc454ee3d0d4720f6978065f56684", }, }, }, diff --git a/pkg/fanal/artifact/local/fs_test.go b/pkg/fanal/artifact/local/fs_test.go index 890679b7f45d..f230cb1340fc 100644 --- a/pkg/fanal/artifact/local/fs_test.go +++ b/pkg/fanal/artifact/local/fs_test.go @@ -174,14 +174,14 @@ func TestArtifact_Inspect(t *testing.T) { }, putBlobExpectation: cache.ArtifactCachePutBlobExpectation{ Args: cache.ArtifactCachePutBlobArgs{ - BlobID: "sha256:f1101f37560adf2f5d9c8fef2ac66beff236be3be94b3ea48c0fb6f86867775f", + BlobID: "sha256:9e999fcf6fd571e175601fb7cc0da28f0d7960e26eab67dad93152e0bebf21ca", BlobInfo: types.BlobInfo{ SchemaVersion: types.BlobJSONSchemaVersion, Applications: []types.Application{ { Type: "pip", FilePath: "requirements.txt", - Libraries: types.Packages{ + Packages: types.Packages{ { Name: "Flask", Version: "2.0.0", @@ -196,9 +196,9 @@ func TestArtifact_Inspect(t *testing.T) { want: types.ArtifactReference{ Name: "testdata/requirements.txt", Type: types.ArtifactFilesystem, - ID: "sha256:f1101f37560adf2f5d9c8fef2ac66beff236be3be94b3ea48c0fb6f86867775f", + ID: "sha256:9e999fcf6fd571e175601fb7cc0da28f0d7960e26eab67dad93152e0bebf21ca", BlobIDs: []string{ - "sha256:f1101f37560adf2f5d9c8fef2ac66beff236be3be94b3ea48c0fb6f86867775f", + "sha256:9e999fcf6fd571e175601fb7cc0da28f0d7960e26eab67dad93152e0bebf21ca", }, }, }, @@ -209,14 +209,14 @@ func TestArtifact_Inspect(t *testing.T) { }, putBlobExpectation: cache.ArtifactCachePutBlobExpectation{ Args: cache.ArtifactCachePutBlobArgs{ - BlobID: "sha256:f1101f37560adf2f5d9c8fef2ac66beff236be3be94b3ea48c0fb6f86867775f", + BlobID: "sha256:9e999fcf6fd571e175601fb7cc0da28f0d7960e26eab67dad93152e0bebf21ca", BlobInfo: types.BlobInfo{ SchemaVersion: types.BlobJSONSchemaVersion, Applications: []types.Application{ { Type: "pip", FilePath: "requirements.txt", - Libraries: types.Packages{ + Packages: types.Packages{ { Name: "Flask", Version: "2.0.0", @@ -231,9 +231,9 @@ func TestArtifact_Inspect(t *testing.T) { want: types.ArtifactReference{ Name: "testdata/requirements.txt", Type: types.ArtifactFilesystem, - ID: "sha256:f1101f37560adf2f5d9c8fef2ac66beff236be3be94b3ea48c0fb6f86867775f", + ID: "sha256:9e999fcf6fd571e175601fb7cc0da28f0d7960e26eab67dad93152e0bebf21ca", BlobIDs: []string{ - "sha256:f1101f37560adf2f5d9c8fef2ac66beff236be3be94b3ea48c0fb6f86867775f", + "sha256:9e999fcf6fd571e175601fb7cc0da28f0d7960e26eab67dad93152e0bebf21ca", }, }, }, diff --git a/pkg/fanal/artifact/sbom/sbom_test.go b/pkg/fanal/artifact/sbom/sbom_test.go index 3b26194cfa55..11ddfdad781b 100644 --- a/pkg/fanal/artifact/sbom/sbom_test.go +++ b/pkg/fanal/artifact/sbom/sbom_test.go @@ -30,7 +30,7 @@ func TestArtifact_Inspect(t *testing.T) { filePath: filepath.Join("testdata", "bom.json"), putBlobExpectation: cache.ArtifactCachePutBlobExpectation{ Args: cache.ArtifactCachePutBlobArgs{ - BlobID: "sha256:f6d4bf4edf2818010ef009b6cd0f837c94dac3464d99e665470c8d05648478e3", + BlobID: "sha256:76bc49ae239d24c6a122e730bafb9d5295d0af380492aeb92a3bf34bea3a14ca", BlobInfo: types.BlobInfo{ SchemaVersion: types.BlobJSONSchemaVersion, OS: types.OS{ @@ -73,7 +73,7 @@ func TestArtifact_Inspect(t *testing.T) { { Type: "composer", FilePath: "app/composer/composer.lock", - Libraries: types.Packages{ + Packages: types.Packages{ { ID: "pear/log@1.13.1", Name: "pear/log", @@ -113,7 +113,7 @@ func TestArtifact_Inspect(t *testing.T) { { Type: "gobinary", FilePath: "app/gobinary/gobinary", - Libraries: types.Packages{ + Packages: types.Packages{ { ID: "github.com/package-url/packageurl-go@v0.1.1-0.20220203205134-d70459300c8a", Name: "github.com/package-url/packageurl-go", @@ -136,7 +136,7 @@ func TestArtifact_Inspect(t *testing.T) { { Type: "jar", FilePath: "", - Libraries: types.Packages{ + Packages: types.Packages{ { ID: "org.codehaus.mojo:child-project:1.0", Name: "org.codehaus.mojo:child-project", @@ -161,7 +161,7 @@ func TestArtifact_Inspect(t *testing.T) { { Type: "node-pkg", FilePath: "", - Libraries: types.Packages{ + Packages: types.Packages{ { ID: "bootstrap@5.0.2", Name: "bootstrap", @@ -191,9 +191,9 @@ func TestArtifact_Inspect(t *testing.T) { want: types.ArtifactReference{ Name: filepath.Join("testdata", "bom.json"), Type: types.ArtifactCycloneDX, - ID: "sha256:f6d4bf4edf2818010ef009b6cd0f837c94dac3464d99e665470c8d05648478e3", + ID: "sha256:76bc49ae239d24c6a122e730bafb9d5295d0af380492aeb92a3bf34bea3a14ca", BlobIDs: []string{ - "sha256:f6d4bf4edf2818010ef009b6cd0f837c94dac3464d99e665470c8d05648478e3", + "sha256:76bc49ae239d24c6a122e730bafb9d5295d0af380492aeb92a3bf34bea3a14ca", }, }, }, @@ -202,7 +202,7 @@ func TestArtifact_Inspect(t *testing.T) { filePath: filepath.Join("testdata", "sbom.cdx.intoto.jsonl"), putBlobExpectation: cache.ArtifactCachePutBlobExpectation{ Args: cache.ArtifactCachePutBlobArgs{ - BlobID: "sha256:f6d4bf4edf2818010ef009b6cd0f837c94dac3464d99e665470c8d05648478e3", + BlobID: "sha256:76bc49ae239d24c6a122e730bafb9d5295d0af380492aeb92a3bf34bea3a14ca", BlobInfo: types.BlobInfo{ SchemaVersion: types.BlobJSONSchemaVersion, OS: types.OS{ @@ -245,7 +245,7 @@ func TestArtifact_Inspect(t *testing.T) { { Type: "composer", FilePath: "app/composer/composer.lock", - Libraries: types.Packages{ + Packages: types.Packages{ { ID: "pear/log@1.13.1", Name: "pear/log", @@ -285,7 +285,7 @@ func TestArtifact_Inspect(t *testing.T) { { Type: "gobinary", FilePath: "app/gobinary/gobinary", - Libraries: types.Packages{ + Packages: types.Packages{ { ID: "github.com/package-url/packageurl-go@v0.1.1-0.20220203205134-d70459300c8a", Name: "github.com/package-url/packageurl-go", @@ -308,7 +308,7 @@ func TestArtifact_Inspect(t *testing.T) { { Type: "jar", FilePath: "", - Libraries: types.Packages{ + Packages: types.Packages{ { ID: "org.codehaus.mojo:child-project:1.0", Name: "org.codehaus.mojo:child-project", @@ -333,7 +333,7 @@ func TestArtifact_Inspect(t *testing.T) { { Type: "node-pkg", FilePath: "", - Libraries: types.Packages{ + Packages: types.Packages{ { ID: "bootstrap@5.0.2", Name: "bootstrap", @@ -363,9 +363,9 @@ func TestArtifact_Inspect(t *testing.T) { want: types.ArtifactReference{ Name: filepath.Join("testdata", "sbom.cdx.intoto.jsonl"), Type: types.ArtifactCycloneDX, - ID: "sha256:f6d4bf4edf2818010ef009b6cd0f837c94dac3464d99e665470c8d05648478e3", + ID: "sha256:76bc49ae239d24c6a122e730bafb9d5295d0af380492aeb92a3bf34bea3a14ca", BlobIDs: []string{ - "sha256:f6d4bf4edf2818010ef009b6cd0f837c94dac3464d99e665470c8d05648478e3", + "sha256:76bc49ae239d24c6a122e730bafb9d5295d0af380492aeb92a3bf34bea3a14ca", }, }, }, diff --git a/pkg/fanal/cache/fs_test.go b/pkg/fanal/cache/fs_test.go index eaa050096d24..ba2d9fe33d01 100644 --- a/pkg/fanal/cache/fs_test.go +++ b/pkg/fanal/cache/fs_test.go @@ -189,7 +189,7 @@ func TestFSCache_PutBlob(t *testing.T) { { Type: "composer", FilePath: "php-app/composer.lock", - Libraries: types.Packages{ + Packages: types.Packages{ { Name: "guzzlehttp/guzzle", Version: "6.2.0", @@ -235,7 +235,7 @@ func TestFSCache_PutBlob(t *testing.T) { { "Type": "composer", "FilePath": "php-app/composer.lock", - "Libraries": [ + "Packages": [ { "Name":"guzzlehttp/guzzle", "Version":"6.2.0", diff --git a/pkg/fanal/handler/sysfile/filter.go b/pkg/fanal/handler/sysfile/filter.go index 09525aebc1e7..5222049c0d16 100644 --- a/pkg/fanal/handler/sysfile/filter.go +++ b/pkg/fanal/handler/sysfile/filter.go @@ -58,7 +58,7 @@ func (h systemFileFilteringPostHandler) Handle(_ context.Context, result *analyz // Trim leading slashes to be the same format as the path in container images. systemFile := strings.TrimPrefix(file, "/") // We should check the root filepath ("/") and ignore it. - // Otherwise libraries with an empty filePath will be removed. + // Otherwise, packages with an empty filePath will be removed. if systemFile != "" { systemFiles = append(systemFiles, systemFile) } @@ -73,7 +73,7 @@ func (h systemFileFilteringPostHandler) Handle(_ context.Context, result *analyz } var pkgs []types.Package - for _, lib := range app.Libraries { + for _, lib := range app.Packages { // If the lang-specific package was installed by OS package manager, it should not be taken. // Otherwise, the package version will be wrong, then it will lead to false positive. if slices.Contains(systemFiles, lib.FilePath) { @@ -82,8 +82,8 @@ func (h systemFileFilteringPostHandler) Handle(_ context.Context, result *analyz pkgs = append(pkgs, lib) } - // Overwrite Libraries - app.Libraries = pkgs + // Overwrite Packages + app.Packages = pkgs apps = append(apps, app) } diff --git a/pkg/fanal/handler/sysfile/filter_test.go b/pkg/fanal/handler/sysfile/filter_test.go index 1b987fd5823f..158f349e9536 100644 --- a/pkg/fanal/handler/sysfile/filter_test.go +++ b/pkg/fanal/handler/sysfile/filter_test.go @@ -63,7 +63,7 @@ func Test_systemFileFilterHook_Hook(t *testing.T) { { Type: types.Pipenv, FilePath: "app/Pipfile.lock", - Libraries: types.Packages{ + Packages: types.Packages{ { Name: "django", Version: "3.1.2", @@ -72,7 +72,7 @@ func Test_systemFileFilterHook_Hook(t *testing.T) { }, { Type: types.PythonPkg, - Libraries: types.Packages{ + Packages: types.Packages{ { Name: "python", Version: "2.7.5", @@ -88,7 +88,7 @@ func Test_systemFileFilterHook_Hook(t *testing.T) { { Type: types.PythonPkg, FilePath: "usr/lib64/python2.7/wsgiref.egg-info", - Libraries: types.Packages{ + Packages: types.Packages{ { Name: "wsgiref", Version: "0.1.2", @@ -98,7 +98,7 @@ func Test_systemFileFilterHook_Hook(t *testing.T) { { Type: types.GoBinary, FilePath: "usr/local/bin/goBinariryFile", - Libraries: types.Packages{ + Packages: types.Packages{ { Name: "cloud.google.com/go", Version: "v0.81.0", @@ -140,7 +140,7 @@ func Test_systemFileFilterHook_Hook(t *testing.T) { { Type: types.Pipenv, FilePath: "app/Pipfile.lock", - Libraries: types.Packages{ + Packages: types.Packages{ { Name: "django", Version: "3.1.2", @@ -149,7 +149,7 @@ func Test_systemFileFilterHook_Hook(t *testing.T) { }, { Type: types.PythonPkg, - Libraries: types.Packages{ + Packages: types.Packages{ { Name: "pycurl", Version: "7.19.0", @@ -160,7 +160,7 @@ func Test_systemFileFilterHook_Hook(t *testing.T) { { Type: types.GoBinary, FilePath: "usr/local/bin/goBinariryFile", - Libraries: types.Packages{ + Packages: types.Packages{ { Name: "cloud.google.com/go", Version: "v0.81.0", @@ -185,7 +185,7 @@ func Test_systemFileFilterHook_Hook(t *testing.T) { { Type: types.PythonPkg, FilePath: "usr/lib/python2.7/lib-dynload/Python-2.7.egg-info", - Libraries: types.Packages{ + Packages: types.Packages{ { Name: "python", Version: "2.7.14", @@ -209,7 +209,7 @@ func Test_systemFileFilterHook_Hook(t *testing.T) { { Type: types.GoBinary, FilePath: "usr/local/bin/goreleaser", - Libraries: types.Packages{ + Packages: types.Packages{ { Name: "github.com/sassoftware/go-rpmutils", Version: "v0.0.0-20190420191620-a8f1baeba37b", @@ -232,7 +232,7 @@ func Test_systemFileFilterHook_Hook(t *testing.T) { { Type: types.Cargo, FilePath: "app/Cargo.lock", - Libraries: types.Packages{ + Packages: types.Packages{ { Name: "ghash", Version: "0.4.4", @@ -246,7 +246,7 @@ func Test_systemFileFilterHook_Hook(t *testing.T) { { Type: types.Cargo, FilePath: "app/Cargo.lock", - Libraries: types.Packages{ + Packages: types.Packages{ { Name: "ghash", Version: "0.4.4", diff --git a/pkg/fanal/handler/unpackaged/unpackaged_test.go b/pkg/fanal/handler/unpackaged/unpackaged_test.go index 685af042d131..be2ddd116151 100644 --- a/pkg/fanal/handler/unpackaged/unpackaged_test.go +++ b/pkg/fanal/handler/unpackaged/unpackaged_test.go @@ -41,7 +41,7 @@ func Test_unpackagedHook_Handle(t *testing.T) { { Type: types.GoModule, FilePath: "go.mod", - Libraries: types.Packages{ + Packages: types.Packages{ { ID: "github.com/spf13/cobra@v1.5.0", Name: "github.com/spf13/cobra", diff --git a/pkg/fanal/test/integration/library_test.go b/pkg/fanal/test/integration/library_test.go index f6a863fc82bd..9e2073185c60 100644 --- a/pkg/fanal/test/integration/library_test.go +++ b/pkg/fanal/test/integration/library_test.go @@ -326,16 +326,16 @@ func checkLangPkgs(detail types.ArtifactDetail, t *testing.T, tc testCase) { }) for _, app := range detail.Applications { - sort.Sort(app.Libraries) - for i := range app.Libraries { - sort.Strings(app.Libraries[i].DependsOn) + sort.Sort(app.Packages) + for i := range app.Packages { + sort.Strings(app.Packages[i].DependsOn) } } // Do not compare layers for _, app := range detail.Applications { - for i := range app.Libraries { - app.Libraries[i].Layer = types.Layer{} + for i := range app.Packages { + app.Packages[i].Layer = types.Layer{} } } diff --git a/pkg/fanal/test/integration/testdata/goldens/vuln-image1.2.3.expectedlibs.golden b/pkg/fanal/test/integration/testdata/goldens/vuln-image1.2.3.expectedlibs.golden index 58abc9c33585..7c52aef32965 100644 --- a/pkg/fanal/test/integration/testdata/goldens/vuln-image1.2.3.expectedlibs.golden +++ b/pkg/fanal/test/integration/testdata/goldens/vuln-image1.2.3.expectedlibs.golden @@ -2,7 +2,138 @@ { "Type": "bundler", "FilePath": "ruby-app/Gemfile.lock", - "Libraries": [ + "Packages": [ + { + "ID": "dotenv@2.7.2", + "Name": "dotenv", + "Identifier": { + "PURL": "pkg:gem/dotenv@2.7.2", + "UID": "bf323ef200ea177a" + }, + "Version": "2.7.2", + "Relationship": "direct", + "Layer": {}, + "Locations": [ + { + "StartLine": 51, + "EndLine": 51 + } + ] + }, + { + "ID": "faker@1.9.3", + "Name": "faker", + "Identifier": { + "PURL": "pkg:gem/faker@1.9.3", + "UID": "b5ac01b24ab4ed39" + }, + "Version": "1.9.3", + "Relationship": "direct", + "DependsOn": [ + "i18n@1.6.0" + ], + "Layer": {}, + "Locations": [ + { + "StartLine": 53, + "EndLine": 53 + } + ] + }, + { + "ID": "json@2.2.0", + "Name": "json", + "Identifier": { + "PURL": "pkg:gem/json@2.2.0", + "UID": "cb6c1eb54f8c6e9d" + }, + "Version": "2.2.0", + "Relationship": "direct", + "Layer": {}, + "Locations": [ + { + "StartLine": 60, + "EndLine": 60 + } + ] + }, + { + "ID": "pry@0.12.2", + "Name": "pry", + "Identifier": { + "PURL": "pkg:gem/pry@0.12.2", + "UID": "1349a1afdbbc80bc" + }, + "Version": "0.12.2", + "Relationship": "direct", + "DependsOn": [ + "coderay@1.1.2", + "method_source@0.9.2" + ], + "Layer": {}, + "Locations": [ + { + "StartLine": 79, + "EndLine": 79 + } + ] + }, + { + "ID": "rails@5.2.0", + "Name": "rails", + "Identifier": { + "PURL": "pkg:gem/rails@5.2.0", + "UID": "edef417a0d4c73e" + }, + "Version": "5.2.0", + "Relationship": "direct", + "DependsOn": [ + "actioncable@5.2.3", + "actionmailer@5.2.3", + "actionpack@5.2.3", + "actionview@5.2.3", + "activejob@5.2.3", + "activemodel@5.2.3", + "activerecord@5.2.3", + "activestorage@5.2.3", + "activesupport@5.2.3", + "railties@5.2.3", + "sprockets-rails@3.2.1" + ], + "Layer": {}, + "Locations": [ + { + "StartLine": 86, + "EndLine": 86 + } + ] + }, + { + "ID": "rubocop@0.67.2", + "Name": "rubocop", + "Identifier": { + "PURL": "pkg:gem/rubocop@0.67.2", + "UID": "68a7b25b67dfb858" + }, + "Version": "0.67.2", + "Relationship": "direct", + "DependsOn": [ + "jaro_winkler@1.5.2", + "parallel@1.17.0", + "parser@2.6.3.0", + "psych@3.1.0", + "rainbow@3.0.0", + "ruby-progressbar@1.10.0", + "unicode-display_width@1.5.0" + ], + "Layer": {}, + "Locations": [ + { + "StartLine": 112, + "EndLine": 112 + } + ] + }, { "ID": "actioncable@5.2.3", "Name": "actioncable", @@ -323,23 +454,6 @@ } ] }, - { - "ID": "dotenv@2.7.2", - "Name": "dotenv", - "Identifier": { - "PURL": "pkg:gem/dotenv@2.7.2", - "UID": "bf323ef200ea177a" - }, - "Version": "2.7.2", - "Relationship": "direct", - "Layer": {}, - "Locations": [ - { - "StartLine": 51, - "EndLine": 51 - } - ] - }, { "ID": "erubi@1.8.0", "Name": "erubi", @@ -358,26 +472,6 @@ } ] }, - { - "ID": "faker@1.9.3", - "Name": "faker", - "Identifier": { - "PURL": "pkg:gem/faker@1.9.3", - "UID": "b5ac01b24ab4ed39" - }, - "Version": "1.9.3", - "Relationship": "direct", - "DependsOn": [ - "i18n@1.6.0" - ], - "Layer": {}, - "Locations": [ - { - "StartLine": 53, - "EndLine": 53 - } - ] - }, { "ID": "globalid@0.4.2", "Name": "globalid", @@ -438,23 +532,6 @@ } ] }, - { - "ID": "json@2.2.0", - "Name": "json", - "Identifier": { - "PURL": "pkg:gem/json@2.2.0", - "UID": "cb6c1eb54f8c6e9d" - }, - "Version": "2.2.0", - "Relationship": "direct", - "Layer": {}, - "Locations": [ - { - "StartLine": 60, - "EndLine": 60 - } - ] - }, { "ID": "loofah@2.2.3", "Name": "loofah", @@ -687,27 +764,6 @@ } ] }, - { - "ID": "pry@0.12.2", - "Name": "pry", - "Identifier": { - "PURL": "pkg:gem/pry@0.12.2", - "UID": "1349a1afdbbc80bc" - }, - "Version": "0.12.2", - "Relationship": "direct", - "DependsOn": [ - "coderay@1.1.2", - "method_source@0.9.2" - ], - "Layer": {}, - "Locations": [ - { - "StartLine": 79, - "EndLine": 79 - } - ] - }, { "ID": "psych@3.1.0", "Name": "psych", @@ -765,36 +821,6 @@ } ] }, - { - "ID": "rails@5.2.0", - "Name": "rails", - "Identifier": { - "PURL": "pkg:gem/rails@5.2.0", - "UID": "edef417a0d4c73e" - }, - "Version": "5.2.0", - "Relationship": "direct", - "DependsOn": [ - "actioncable@5.2.3", - "actionmailer@5.2.3", - "actionpack@5.2.3", - "actionview@5.2.3", - "activejob@5.2.3", - "activemodel@5.2.3", - "activerecord@5.2.3", - "activestorage@5.2.3", - "activesupport@5.2.3", - "railties@5.2.3", - "sprockets-rails@3.2.1" - ], - "Layer": {}, - "Locations": [ - { - "StartLine": 86, - "EndLine": 86 - } - ] - }, { "ID": "rails-dom-testing@2.0.3", "Name": "rails-dom-testing", @@ -899,32 +925,6 @@ } ] }, - { - "ID": "rubocop@0.67.2", - "Name": "rubocop", - "Identifier": { - "PURL": "pkg:gem/rubocop@0.67.2", - "UID": "68a7b25b67dfb858" - }, - "Version": "0.67.2", - "Relationship": "direct", - "DependsOn": [ - "jaro_winkler@1.5.2", - "parallel@1.17.0", - "parser@2.6.3.0", - "psych@3.1.0", - "rainbow@3.0.0", - "ruby-progressbar@1.10.0", - "unicode-display_width@1.5.0" - ], - "Layer": {}, - "Locations": [ - { - "StartLine": 112, - "EndLine": 112 - } - ] - }, { "ID": "ruby-progressbar@1.10.0", "Name": "ruby-progressbar", @@ -1107,7 +1107,7 @@ { "Type": "cargo", "FilePath": "rust-app/Cargo.lock", - "Libraries": [ + "Packages": [ { "ID": "ammonia@1.9.0", "Name": "ammonia", @@ -2519,7 +2519,7 @@ { "Type": "composer", "FilePath": "php-app/composer.lock", - "Libraries": [ + "Packages": [ { "ID": "guzzlehttp/guzzle@6.2.0", "Name": "guzzlehttp/guzzle", @@ -2815,7 +2815,7 @@ { "Type": "npm", "FilePath": "node-app/package-lock.json", - "Libraries": [ + "Packages": [ { "ID": "asap@2.0.6", "Name": "asap", @@ -3054,7 +3054,7 @@ { "Type": "pipenv", "FilePath": "python-app/Pipfile.lock", - "Libraries": [ + "Packages": [ { "Name": "amqp", "Identifier": { diff --git a/pkg/fanal/types/artifact.go b/pkg/fanal/types/artifact.go index 6c213a3fad18..ff8da07b4e2c 100644 --- a/pkg/fanal/types/artifact.go +++ b/pkg/fanal/types/artifact.go @@ -8,8 +8,8 @@ import ( v1 "github.com/google/go-containerregistry/pkg/v1" "github.com/package-url/packageurl-go" "github.com/samber/lo" + "golang.org/x/xerrors" - godeptypes "github.com/aquasecurity/trivy/pkg/dependency/types" "github.com/aquasecurity/trivy/pkg/digest" "github.com/aquasecurity/trivy/pkg/sbom/core" ) @@ -66,31 +66,63 @@ type Layer struct { CreatedBy string `json:",omitempty"` } -// TODO: merge pkg/dependency/types/types.go into this file -type Relationship = godeptypes.Relationship +type Relationship int const ( - RelationshipUnknown = godeptypes.RelationshipUnknown - RelationshipRoot = godeptypes.RelationshipRoot - RelationshipDirect = godeptypes.RelationshipDirect - RelationshipIndirect = godeptypes.RelationshipIndirect + RelationshipUnknown Relationship = iota + RelationshipRoot + RelationshipDirect + RelationshipIndirect ) +var relationshipNames = [...]string{ + "unknown", + "root", + "direct", + "indirect", +} + +func (r Relationship) String() string { + if r <= RelationshipUnknown || int(r) >= len(relationshipNames) { + return "unknown" + } + return relationshipNames[r] +} + +func (r Relationship) MarshalJSON() ([]byte, error) { + return json.Marshal(r.String()) +} + +func (r *Relationship) UnmarshalJSON(data []byte) error { + var s string + if err := json.Unmarshal(data, &s); err != nil { + return err + } + for i, name := range relationshipNames { + if s == name { + *r = Relationship(i) + return nil + } + } + return xerrors.Errorf("invalid relationship (%s)", s) +} + type Package struct { - ID string `json:",omitempty"` - Name string `json:",omitempty"` - Identifier PkgIdentifier `json:",omitempty"` - Version string `json:",omitempty"` - Release string `json:",omitempty"` - Epoch int `json:",omitempty"` - Arch string `json:",omitempty"` - Dev bool `json:",omitempty"` - SrcName string `json:",omitempty"` - SrcVersion string `json:",omitempty"` - SrcRelease string `json:",omitempty"` - SrcEpoch int `json:",omitempty"` - Licenses []string `json:",omitempty"` - Maintainer string `json:",omitempty"` + ID string `json:",omitempty"` + Name string `json:",omitempty"` + Identifier PkgIdentifier `json:",omitempty"` + Version string `json:",omitempty"` + Release string `json:",omitempty"` + Epoch int `json:",omitempty"` + Arch string `json:",omitempty"` + Dev bool `json:",omitempty"` + SrcName string `json:",omitempty"` + SrcVersion string `json:",omitempty"` + SrcRelease string `json:",omitempty"` + SrcEpoch int `json:",omitempty"` + Licenses []string `json:",omitempty"` + Maintainer string `json:",omitempty"` + ExternalReferences []ExternalRef `json:"-"` Modularitylabel string `json:",omitempty"` // only for Red Hat based distributions BuildInfo *BuildInfo `json:",omitempty"` // only for Red Hat @@ -111,7 +143,7 @@ type Package struct { Digest digest.Digest `json:",omitempty"` // lines from the lock file where the dependency is written - Locations []Location `json:",omitempty"` + Locations Locations `json:",omitempty"` // Files installed by the package InstalledFiles []string `json:",omitempty"` @@ -188,11 +220,44 @@ func (id *PkgIdentifier) Match(s string) bool { return false } +type Dependency struct { + ID string + DependsOn []string +} + +type Dependencies []Dependency + +func (deps Dependencies) Len() int { return len(deps) } +func (deps Dependencies) Less(i, j int) bool { + return deps[i].ID < deps[j].ID +} +func (deps Dependencies) Swap(i, j int) { deps[i], deps[j] = deps[j], deps[i] } + type Location struct { StartLine int `json:",omitempty"` EndLine int `json:",omitempty"` } +type Locations []Location + +func (locs Locations) Len() int { return len(locs) } +func (locs Locations) Less(i, j int) bool { + return locs[i].StartLine < locs[j].StartLine +} +func (locs Locations) Swap(i, j int) { locs[i], locs[j] = locs[j], locs[i] } + +type ExternalRef struct { + Type RefType + URL string +} + +type RefType string + +const ( + RefVCS RefType = "vcs" + RefOther RefType = "other" +) + // BuildInfo represents information under /root/buildinfo in RHEL type BuildInfo struct { ContentSets []string `json:",omitempty"` @@ -216,6 +281,13 @@ func (pkgs Packages) Swap(i, j int) { func (pkgs Packages) Less(i, j int) bool { switch { + case pkgs[i].Relationship != pkgs[j].Relationship: + if pkgs[i].Relationship == RelationshipUnknown { + return false + } else if pkgs[j].Relationship == RelationshipUnknown { + return true + } + return pkgs[i].Relationship < pkgs[j].Relationship case pkgs[i].Name != pkgs[j].Name: return pkgs[i].Name < pkgs[j].Name case pkgs[i].Version != pkgs[j].Version: @@ -260,8 +332,8 @@ type Application struct { // Lock files have the file path here, while each package metadata do not have FilePath string `json:",omitempty"` - // Libraries is a list of lang-specific packages - Libraries Packages + // Packages is a list of lang-specific packages + Packages Packages } type File struct { diff --git a/pkg/k8s/scanner/scanner.go b/pkg/k8s/scanner/scanner.go index b0c055e0b886..2ac380dadb58 100644 --- a/pkg/k8s/scanner/scanner.go +++ b/pkg/k8s/scanner/scanner.go @@ -235,7 +235,7 @@ func (s *Scanner) scanK8sVulns(ctx context.Context, artifactsData []*artifacts.A { Type: ftypes.LangType(lang), FilePath: artifact.Name, - Libraries: []ftypes.Package{ + Packages: []ftypes.Package{ { Name: comp.Name, Version: comp.Version, @@ -271,7 +271,7 @@ func (s *Scanner) scanK8sVulns(ctx context.Context, artifactsData []*artifacts.A { Type: ftypes.LangType(lang), FilePath: artifact.Name, - Libraries: []ftypes.Package{ + Packages: []ftypes.Package{ { Name: kubelet, Version: kubeletVersion, @@ -281,7 +281,7 @@ func (s *Scanner) scanK8sVulns(ctx context.Context, artifactsData []*artifacts.A { Type: ftypes.GoBinary, FilePath: artifact.Name, - Libraries: []ftypes.Package{ + Packages: []ftypes.Package{ { Name: runtimeName, Version: runtimeVersion, @@ -316,7 +316,7 @@ func (s *Scanner) scanK8sVulns(ctx context.Context, artifactsData []*artifacts.A { Type: ftypes.LangType(lang), FilePath: artifact.Name, - Libraries: []ftypes.Package{ + Packages: []ftypes.Package{ { Name: cf.Name, Version: cf.Version, diff --git a/pkg/licensing/normalize.go b/pkg/licensing/normalize.go index 0493747a9430..07105e329357 100644 --- a/pkg/licensing/normalize.go +++ b/pkg/licensing/normalize.go @@ -180,6 +180,7 @@ var pythonLicenseExceptions = map[string]string{ var licenseSplitRegexp = regexp.MustCompile("(,?[_ ]+(?:or|and)[_ ]+)|(,[ ]*)") func Normalize(name string) string { + name = strings.TrimSpace(name) if l, ok := mapping[strings.ToUpper(name)]; ok { return l } @@ -187,6 +188,9 @@ func Normalize(name string) string { } func SplitLicenses(str string) []string { + if str == "" { + return nil + } var licenses []string for _, maybeLic := range licenseSplitRegexp.Split(str, -1) { lower := strings.ToLower(maybeLic) diff --git a/pkg/rpc/convert.go b/pkg/rpc/convert.go index 033b1944274a..dcd81ce85ded 100644 --- a/pkg/rpc/convert.go +++ b/pkg/rpc/convert.go @@ -740,9 +740,9 @@ func ConvertFromRPCApplications(rpcApps []*common.Application) []ftypes.Applicat var apps []ftypes.Application for _, rpcApp := range rpcApps { apps = append(apps, ftypes.Application{ - Type: ftypes.LangType(rpcApp.Type), - FilePath: rpcApp.FilePath, - Libraries: ConvertFromRPCPkgs(rpcApp.Libraries), + Type: ftypes.LangType(rpcApp.Type), + FilePath: rpcApp.FilePath, + Packages: ConvertFromRPCPkgs(rpcApp.Packages), }) } return apps @@ -865,9 +865,9 @@ func ConvertToRPCPutBlobRequest(diffID string, blobInfo ftypes.BlobInfo) *cache. var applications []*common.Application for _, app := range blobInfo.Applications { applications = append(applications, &common.Application{ - Type: string(app.Type), - FilePath: app.FilePath, - Libraries: ConvertToRPCPkgs(app.Libraries), + Type: string(app.Type), + FilePath: app.FilePath, + Packages: ConvertToRPCPkgs(app.Packages), }) } diff --git a/pkg/rpc/server/server_test.go b/pkg/rpc/server/server_test.go index 3022ff2cdf0a..a472fcbe8443 100644 --- a/pkg/rpc/server/server_test.go +++ b/pkg/rpc/server/server_test.go @@ -363,7 +363,7 @@ func TestCacheServer_PutBlob(t *testing.T) { { Type: "composer", FilePath: "php-app/composer.lock", - Libraries: []*common.Package{ + Packages: []*common.Package{ { Name: "guzzlehttp/guzzle", Version: "6.2.0", @@ -444,7 +444,7 @@ func TestCacheServer_PutBlob(t *testing.T) { { Type: "composer", FilePath: "php-app/composer.lock", - Libraries: ftypes.Packages{ + Packages: ftypes.Packages{ { Name: "guzzlehttp/guzzle", Version: "6.2.0", diff --git a/pkg/sbom/cyclonedx/unmarshal_test.go b/pkg/sbom/cyclonedx/unmarshal_test.go index 6ffd9ce89ad9..9988d21c75ed 100644 --- a/pkg/sbom/cyclonedx/unmarshal_test.go +++ b/pkg/sbom/cyclonedx/unmarshal_test.go @@ -77,7 +77,7 @@ func TestUnmarshaler_Unmarshal(t *testing.T) { { Type: ftypes.Composer, FilePath: "app/composer/composer.lock", - Libraries: ftypes.Packages{ + Packages: ftypes.Packages{ { ID: "pear/log@1.13.1", Name: "pear/log", @@ -117,7 +117,7 @@ func TestUnmarshaler_Unmarshal(t *testing.T) { { Type: ftypes.GoBinary, FilePath: "app/gobinary/gobinary", - Libraries: ftypes.Packages{ + Packages: ftypes.Packages{ { ID: "github.com/package-url/packageurl-go@v0.1.1-0.20220203205134-d70459300c8a", Name: "github.com/package-url/packageurl-go", @@ -140,7 +140,7 @@ func TestUnmarshaler_Unmarshal(t *testing.T) { { Type: ftypes.Gradle, FilePath: "app/gradle/target/gradle.lockfile", - Libraries: ftypes.Packages{ + Packages: ftypes.Packages{ { ID: "com.example:example:0.0.1", Name: "com.example:example", @@ -162,7 +162,7 @@ func TestUnmarshaler_Unmarshal(t *testing.T) { }, { Type: ftypes.Jar, - Libraries: ftypes.Packages{ + Packages: ftypes.Packages{ { ID: "org.codehaus.mojo:child-project:1.0", Name: "org.codehaus.mojo:child-project", @@ -186,7 +186,7 @@ func TestUnmarshaler_Unmarshal(t *testing.T) { { Type: ftypes.NodePkg, FilePath: "", - Libraries: ftypes.Packages{ + Packages: ftypes.Packages{ { ID: "@example/bootstrap@5.0.2", Name: "@example/bootstrap", @@ -224,7 +224,7 @@ func TestUnmarshaler_Unmarshal(t *testing.T) { Applications: []ftypes.Application{ { Type: ftypes.GoBinary, - Libraries: ftypes.Packages{ + Packages: ftypes.Packages{ { ID: "docker@v24.0.4", Name: "docker", @@ -242,7 +242,7 @@ func TestUnmarshaler_Unmarshal(t *testing.T) { }, { Type: ftypes.K8sUpstream, - Libraries: ftypes.Packages{ + Packages: ftypes.Packages{ { ID: "k8s.io/apiserver@1.27.4", Name: "k8s.io/apiserver", @@ -474,7 +474,7 @@ func TestUnmarshaler_Unmarshal(t *testing.T) { { Type: "composer", FilePath: "", - Libraries: ftypes.Packages{ + Packages: ftypes.Packages{ { ID: "pear/log@1.13.1", Name: "pear/log", @@ -517,7 +517,7 @@ func TestUnmarshaler_Unmarshal(t *testing.T) { { Type: "composer", FilePath: "", - Libraries: ftypes.Packages{ + Packages: ftypes.Packages{ { ID: "pear/log@1.13.1", Name: "pear/log", @@ -545,7 +545,7 @@ func TestUnmarshaler_Unmarshal(t *testing.T) { { Type: "composer", FilePath: "", - Libraries: ftypes.Packages{ + Packages: ftypes.Packages{ { ID: "pear/log@1.13.1", Name: "pear/log", @@ -587,7 +587,7 @@ func TestUnmarshaler_Unmarshal(t *testing.T) { { Type: "composer", FilePath: "", - Libraries: ftypes.Packages{ + Packages: ftypes.Packages{ { ID: "pear/core@1.13.1", Name: "pear/core", @@ -646,7 +646,7 @@ func TestUnmarshaler_Unmarshal(t *testing.T) { Applications: []ftypes.Application{ { Type: "jar", - Libraries: ftypes.Packages{ + Packages: ftypes.Packages{ { ID: "org.springframework:spring-web:5.3.22", Name: "org.springframework:spring-web", @@ -715,7 +715,7 @@ func TestUnmarshaler_Unmarshal(t *testing.T) { Applications: []ftypes.Application{ { Type: ftypes.Composer, - Libraries: ftypes.Packages{ + Packages: ftypes.Packages{ { ID: "pear/core@1.13.1", Name: "pear/core", diff --git a/pkg/sbom/io/decode.go b/pkg/sbom/io/decode.go index 4a699eb59d76..84039973c213 100644 --- a/pkg/sbom/io/decode.go +++ b/pkg/sbom/io/decode.go @@ -334,7 +334,7 @@ func (m *Decoder) addLangPkgs(sbom *types.SBOM) { if !ok { continue } - app.Libraries = append(app.Libraries, *pkg) + app.Packages = append(app.Packages, *pkg) delete(m.pkgs, rel.Dependency) // Delete the added package } sbom.Applications = append(sbom.Applications, *app) @@ -380,8 +380,8 @@ func (m *Decoder) addOrphanPkgs(sbom *types.SBOM) error { for pkgType, pkgs := range langPkgMap { sort.Sort(pkgs) sbom.Applications = append(sbom.Applications, ftypes.Application{ - Type: pkgType, - Libraries: pkgs, + Type: pkgType, + Packages: pkgs, }) } return nil diff --git a/pkg/sbom/spdx/unmarshal_test.go b/pkg/sbom/spdx/unmarshal_test.go index 73f7d2dc934f..4348618e0f4d 100644 --- a/pkg/sbom/spdx/unmarshal_test.go +++ b/pkg/sbom/spdx/unmarshal_test.go @@ -77,7 +77,7 @@ func TestUnmarshaler_Unmarshal(t *testing.T) { { Type: "composer", FilePath: "app/composer/composer.lock", - Libraries: ftypes.Packages{ + Packages: ftypes.Packages{ { ID: "pear/log@1.13.1", Name: "pear/log", @@ -115,7 +115,7 @@ func TestUnmarshaler_Unmarshal(t *testing.T) { { Type: "gobinary", FilePath: "app/gobinary/gobinary", - Libraries: ftypes.Packages{ + Packages: ftypes.Packages{ { ID: "github.com/package-url/packageurl-go@v0.1.1-0.20220203205134-d70459300c8a", Name: "github.com/package-url/packageurl-go", @@ -136,7 +136,7 @@ func TestUnmarshaler_Unmarshal(t *testing.T) { }, { Type: "jar", - Libraries: ftypes.Packages{ + Packages: ftypes.Packages{ { ID: "org.codehaus.mojo:child-project:1.0", Name: "org.codehaus.mojo:child-project", @@ -157,7 +157,7 @@ func TestUnmarshaler_Unmarshal(t *testing.T) { }, { Type: "node-pkg", - Libraries: ftypes.Packages{ + Packages: ftypes.Packages{ { ID: "bootstrap@5.0.2", Name: "bootstrap", @@ -186,7 +186,7 @@ func TestUnmarshaler_Unmarshal(t *testing.T) { Applications: []ftypes.Application{ { Type: ftypes.NodePkg, - Libraries: ftypes.Packages{ + Packages: ftypes.Packages{ { ID: "yargs-parser@21.1.1", Name: "yargs-parser", @@ -213,7 +213,7 @@ func TestUnmarshaler_Unmarshal(t *testing.T) { Applications: []ftypes.Application{ { Type: "node-pkg", - Libraries: ftypes.Packages{ + Packages: ftypes.Packages{ { ID: "yargs-parser@21.1.1", Name: "yargs-parser", @@ -241,7 +241,7 @@ func TestUnmarshaler_Unmarshal(t *testing.T) { { Type: "composer", FilePath: "app/composer/composer.lock", - Libraries: ftypes.Packages{ + Packages: ftypes.Packages{ { ID: "pear/log@1.13.1", Name: "pear/log", @@ -280,7 +280,7 @@ func TestUnmarshaler_Unmarshal(t *testing.T) { Applications: []ftypes.Application{ { Type: ftypes.Jar, - Libraries: ftypes.Packages{ + Packages: ftypes.Packages{ { ID: "co.elastic.apm:apm-agent:1.36.0", Name: "co.elastic.apm:apm-agent", diff --git a/pkg/scanner/langpkg/scan.go b/pkg/scanner/langpkg/scan.go index c718c37c4848..2606727d56e8 100644 --- a/pkg/scanner/langpkg/scan.go +++ b/pkg/scanner/langpkg/scan.go @@ -37,7 +37,7 @@ func NewScanner() Scanner { func (s *scanner) Packages(target types.ScanTarget, _ types.ScanOptions) types.Results { var results types.Results for _, app := range target.Applications { - if len(app.Libraries) == 0 { + if len(app.Packages) == 0 { continue } @@ -45,7 +45,7 @@ func (s *scanner) Packages(target types.ScanTarget, _ types.ScanOptions) types.R Target: targetName(app.Type, app.FilePath), Class: types.ClassLangPkg, Type: app.Type, - Packages: app.Libraries, + Packages: app.Packages, }) } return results @@ -61,7 +61,7 @@ func (s *scanner) Scan(ctx context.Context, target types.ScanTarget, _ types.Sca var results types.Results printedTypes := make(map[ftypes.LangType]struct{}) for _, app := range apps { - if len(app.Libraries) == 0 { + if len(app.Packages) == 0 { continue } @@ -74,9 +74,9 @@ func (s *scanner) Scan(ctx context.Context, target types.ScanTarget, _ types.Sca } log.DebugContext(ctx, "Scanning packages from the file", log.String("file_path", app.FilePath)) - vulns, err := library.Detect(ctx, app.Type, app.Libraries) + vulns, err := library.Detect(ctx, app.Type, app.Packages) if err != nil { - return nil, xerrors.Errorf("failed vulnerability detection of libraries: %w", err) + return nil, xerrors.Errorf("failed vulnerability detection of packages: %w", err) } else if len(vulns) == 0 { continue } diff --git a/pkg/scanner/local/scan.go b/pkg/scanner/local/scan.go index 2f64a3b7693b..4b1591e0a52f 100644 --- a/pkg/scanner/local/scan.go +++ b/pkg/scanner/local/scan.go @@ -311,7 +311,7 @@ func (s Scanner) scanLicenses(target types.ScanTarget, options types.ScanOptions // License - language-specific packages for _, app := range target.Applications { var langLicenses []types.DetectedLicense - for _, lib := range app.Libraries { + for _, lib := range app.Packages { for _, license := range lib.Licenses { category, severity := scanner.Scan(license) langLicenses = append(langLicenses, types.DetectedLicense{ @@ -435,7 +435,7 @@ func excludeDevDeps(apps []ftypes.Application, include bool) { log.Info("Suppressing dependencies for development and testing. To display them, try the '--include-dev-deps' flag.") }) for i := range apps { - apps[i].Libraries = lo.Filter(apps[i].Libraries, func(lib ftypes.Package, index int) bool { + apps[i].Packages = lo.Filter(apps[i].Packages, func(lib ftypes.Package, index int) bool { if lib.Dev { onceInfo() } diff --git a/pkg/scanner/local/scan_test.go b/pkg/scanner/local/scan_test.go index 3b173957cc23..f15c90f2964c 100644 --- a/pkg/scanner/local/scan_test.go +++ b/pkg/scanner/local/scan_test.go @@ -75,7 +75,7 @@ func TestScanner_Scan(t *testing.T) { { Type: ftypes.Bundler, FilePath: "/app/Gemfile.lock", - Libraries: []ftypes.Package{ + Packages: []ftypes.Package{ { Name: "rails", Version: "4.0.2", @@ -184,7 +184,7 @@ func TestScanner_Scan(t *testing.T) { { Type: ftypes.GoModule, FilePath: "/app/go.mod", - Libraries: []ftypes.Package{ + Packages: []ftypes.Package{ { Name: "github.com/google/uuid", Version: "1.6.0", @@ -199,7 +199,7 @@ func TestScanner_Scan(t *testing.T) { { Type: ftypes.PythonPkg, FilePath: "", - Libraries: []ftypes.Package{ + Packages: []ftypes.Package{ { Name: "urllib3", Version: "3.2.1", @@ -318,7 +318,7 @@ func TestScanner_Scan(t *testing.T) { { Type: "bundler", FilePath: "/app/Gemfile.lock", - Libraries: []ftypes.Package{ + Packages: []ftypes.Package{ { Name: "rails", Version: "4.0.2", @@ -470,7 +470,7 @@ func TestScanner_Scan(t *testing.T) { { Type: "bundler", FilePath: "/app/Gemfile.lock", - Libraries: []ftypes.Package{ + Packages: []ftypes.Package{ { Name: "rails", Version: "4.0.2", @@ -556,7 +556,7 @@ func TestScanner_Scan(t *testing.T) { { Type: ftypes.Bundler, FilePath: "/app/Gemfile.lock", - Libraries: []ftypes.Package{ + Packages: []ftypes.Package{ { Name: "innocent", // no vulnerability Version: "1.2.3", @@ -569,7 +569,7 @@ func TestScanner_Scan(t *testing.T) { { Type: ftypes.Bundler, FilePath: "/app/Gemfile.lock", - Libraries: []ftypes.Package{ + Packages: []ftypes.Package{ { Name: "rails", // one vulnerability Version: "4.0.2", @@ -637,7 +637,7 @@ func TestScanner_Scan(t *testing.T) { { Type: "bundler", FilePath: "", - Libraries: []ftypes.Package{ + Packages: []ftypes.Package{ { Name: "rails", Version: "4.0.2", @@ -647,7 +647,7 @@ func TestScanner_Scan(t *testing.T) { { Type: "composer", FilePath: "", - Libraries: []ftypes.Package{ + Packages: []ftypes.Package{ { Name: "laravel/framework", Version: "6.0.0", @@ -740,7 +740,7 @@ func TestScanner_Scan(t *testing.T) { { Type: "bundler", FilePath: "/app/Gemfile.lock", - Libraries: []ftypes.Package{ + Packages: []ftypes.Package{ { Name: "rails", Version: "4.0.2", @@ -824,7 +824,7 @@ func TestScanner_Scan(t *testing.T) { { Type: "bundler", FilePath: "/app/Gemfile.lock", - Libraries: []ftypes.Package{ + Packages: []ftypes.Package{ { Name: "rails", Version: "4.0.2", @@ -930,7 +930,7 @@ func TestScanner_Scan(t *testing.T) { { Type: "bundler", FilePath: "/app/Gemfile.lock", - Libraries: []ftypes.Package{ + Packages: []ftypes.Package{ { Name: "rails", Version: "4.0.2", @@ -943,7 +943,7 @@ func TestScanner_Scan(t *testing.T) { { Type: "composer", FilePath: "/app/composer-lock.json", - Libraries: []ftypes.Package{ + Packages: []ftypes.Package{ { Name: "laravel/framework", Version: "6.0.0", @@ -1216,7 +1216,7 @@ func TestScanner_Scan(t *testing.T) { { Type: "bundler", FilePath: "/app/Gemfile.lock", - Libraries: []ftypes.Package{ + Packages: []ftypes.Package{ { Name: "rails", Version: "6.0", diff --git a/pkg/x/slices/slices.go b/pkg/x/slices/slices.go new file mode 100644 index 000000000000..8e256814bbc7 --- /dev/null +++ b/pkg/x/slices/slices.go @@ -0,0 +1,8 @@ +package slices + +func ZeroToNil[T any](t []T) []T { + if len(t) == 0 { + return nil + } + return t +} diff --git a/rpc/common/service.pb.go b/rpc/common/service.pb.go index 4fcd09927d90..c8d829762956 100644 --- a/rpc/common/service.pb.go +++ b/rpc/common/service.pb.go @@ -379,9 +379,9 @@ type Application struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - Type string `protobuf:"bytes,1,opt,name=type,proto3" json:"type,omitempty"` - FilePath string `protobuf:"bytes,2,opt,name=file_path,json=filePath,proto3" json:"file_path,omitempty"` - Libraries []*Package `protobuf:"bytes,3,rep,name=libraries,proto3" json:"libraries,omitempty"` + Type string `protobuf:"bytes,1,opt,name=type,proto3" json:"type,omitempty"` + FilePath string `protobuf:"bytes,2,opt,name=file_path,json=filePath,proto3" json:"file_path,omitempty"` + Packages []*Package `protobuf:"bytes,3,rep,name=packages,proto3" json:"packages,omitempty"` } func (x *Application) Reset() { @@ -430,9 +430,9 @@ func (x *Application) GetFilePath() string { return "" } -func (x *Application) GetLibraries() []*Package { +func (x *Application) GetPackages() []*Package { if x != nil { - return x.Libraries + return x.Packages } return nil } @@ -2421,367 +2421,367 @@ var file_rpc_common_service_proto_rawDesc = []byte{ 0x65, 0x50, 0x61, 0x74, 0x68, 0x12, 0x31, 0x0a, 0x08, 0x70, 0x61, 0x63, 0x6b, 0x61, 0x67, 0x65, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x74, 0x72, 0x69, 0x76, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x50, 0x61, 0x63, 0x6b, 0x61, 0x67, 0x65, 0x52, 0x08, - 0x70, 0x61, 0x63, 0x6b, 0x61, 0x67, 0x65, 0x73, 0x22, 0x73, 0x0a, 0x0b, 0x41, 0x70, 0x70, 0x6c, + 0x70, 0x61, 0x63, 0x6b, 0x61, 0x67, 0x65, 0x73, 0x22, 0x71, 0x0a, 0x0b, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x1b, 0x0a, 0x09, 0x66, 0x69, 0x6c, 0x65, 0x5f, 0x70, 0x61, 0x74, 0x68, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, - 0x66, 0x69, 0x6c, 0x65, 0x50, 0x61, 0x74, 0x68, 0x12, 0x33, 0x0a, 0x09, 0x6c, 0x69, 0x62, 0x72, - 0x61, 0x72, 0x69, 0x65, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x74, 0x72, - 0x69, 0x76, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x50, 0x61, 0x63, 0x6b, 0x61, - 0x67, 0x65, 0x52, 0x09, 0x6c, 0x69, 0x62, 0x72, 0x61, 0x72, 0x69, 0x65, 0x73, 0x22, 0xc1, 0x04, - 0x0a, 0x07, 0x50, 0x61, 0x63, 0x6b, 0x61, 0x67, 0x65, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, - 0x0d, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, - 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x18, 0x0a, - 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, - 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x18, 0x0a, 0x07, 0x72, 0x65, 0x6c, 0x65, 0x61, - 0x73, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x72, 0x65, 0x6c, 0x65, 0x61, 0x73, - 0x65, 0x12, 0x14, 0x0a, 0x05, 0x65, 0x70, 0x6f, 0x63, 0x68, 0x18, 0x04, 0x20, 0x01, 0x28, 0x05, - 0x52, 0x05, 0x65, 0x70, 0x6f, 0x63, 0x68, 0x12, 0x3b, 0x0a, 0x0a, 0x69, 0x64, 0x65, 0x6e, 0x74, - 0x69, 0x66, 0x69, 0x65, 0x72, 0x18, 0x13, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x74, 0x72, - 0x69, 0x76, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x50, 0x6b, 0x67, 0x49, 0x64, - 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x52, 0x0a, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, - 0x66, 0x69, 0x65, 0x72, 0x12, 0x12, 0x0a, 0x04, 0x61, 0x72, 0x63, 0x68, 0x18, 0x05, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x04, 0x61, 0x72, 0x63, 0x68, 0x12, 0x19, 0x0a, 0x08, 0x73, 0x72, 0x63, 0x5f, - 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x73, 0x72, 0x63, 0x4e, - 0x61, 0x6d, 0x65, 0x12, 0x1f, 0x0a, 0x0b, 0x73, 0x72, 0x63, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, - 0x6f, 0x6e, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x73, 0x72, 0x63, 0x56, 0x65, 0x72, - 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x1f, 0x0a, 0x0b, 0x73, 0x72, 0x63, 0x5f, 0x72, 0x65, 0x6c, 0x65, - 0x61, 0x73, 0x65, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x73, 0x72, 0x63, 0x52, 0x65, - 0x6c, 0x65, 0x61, 0x73, 0x65, 0x12, 0x1b, 0x0a, 0x09, 0x73, 0x72, 0x63, 0x5f, 0x65, 0x70, 0x6f, - 0x63, 0x68, 0x18, 0x09, 0x20, 0x01, 0x28, 0x05, 0x52, 0x08, 0x73, 0x72, 0x63, 0x45, 0x70, 0x6f, - 0x63, 0x68, 0x12, 0x1a, 0x0a, 0x08, 0x6c, 0x69, 0x63, 0x65, 0x6e, 0x73, 0x65, 0x73, 0x18, 0x0f, - 0x20, 0x03, 0x28, 0x09, 0x52, 0x08, 0x6c, 0x69, 0x63, 0x65, 0x6e, 0x73, 0x65, 0x73, 0x12, 0x34, - 0x0a, 0x09, 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x14, 0x20, 0x03, 0x28, - 0x0b, 0x32, 0x16, 0x2e, 0x74, 0x72, 0x69, 0x76, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, - 0x2e, 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x09, 0x6c, 0x6f, 0x63, 0x61, 0x74, - 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x29, 0x0a, 0x05, 0x6c, 0x61, 0x79, 0x65, 0x72, 0x18, 0x0b, 0x20, - 0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x74, 0x72, 0x69, 0x76, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, - 0x6f, 0x6e, 0x2e, 0x4c, 0x61, 0x79, 0x65, 0x72, 0x52, 0x05, 0x6c, 0x61, 0x79, 0x65, 0x72, 0x12, - 0x1b, 0x0a, 0x09, 0x66, 0x69, 0x6c, 0x65, 0x5f, 0x70, 0x61, 0x74, 0x68, 0x18, 0x0c, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x08, 0x66, 0x69, 0x6c, 0x65, 0x50, 0x61, 0x74, 0x68, 0x12, 0x1d, 0x0a, 0x0a, - 0x64, 0x65, 0x70, 0x65, 0x6e, 0x64, 0x73, 0x5f, 0x6f, 0x6e, 0x18, 0x0e, 0x20, 0x03, 0x28, 0x09, - 0x52, 0x09, 0x64, 0x65, 0x70, 0x65, 0x6e, 0x64, 0x73, 0x4f, 0x6e, 0x12, 0x16, 0x0a, 0x06, 0x64, - 0x69, 0x67, 0x65, 0x73, 0x74, 0x18, 0x10, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x64, 0x69, 0x67, - 0x65, 0x73, 0x74, 0x12, 0x10, 0x0a, 0x03, 0x64, 0x65, 0x76, 0x18, 0x11, 0x20, 0x01, 0x28, 0x08, - 0x52, 0x03, 0x64, 0x65, 0x76, 0x12, 0x1a, 0x0a, 0x08, 0x69, 0x6e, 0x64, 0x69, 0x72, 0x65, 0x63, - 0x74, 0x18, 0x12, 0x20, 0x01, 0x28, 0x08, 0x52, 0x08, 0x69, 0x6e, 0x64, 0x69, 0x72, 0x65, 0x63, - 0x74, 0x22, 0x4e, 0x0a, 0x0d, 0x50, 0x6b, 0x67, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, - 0x65, 0x72, 0x12, 0x12, 0x0a, 0x04, 0x70, 0x75, 0x72, 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x04, 0x70, 0x75, 0x72, 0x6c, 0x12, 0x17, 0x0a, 0x07, 0x62, 0x6f, 0x6d, 0x5f, 0x72, 0x65, - 0x66, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x62, 0x6f, 0x6d, 0x52, 0x65, 0x66, 0x12, - 0x10, 0x0a, 0x03, 0x75, 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x75, 0x69, - 0x64, 0x22, 0x44, 0x0a, 0x08, 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x1d, 0x0a, - 0x0a, 0x73, 0x74, 0x61, 0x72, 0x74, 0x5f, 0x6c, 0x69, 0x6e, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x05, 0x52, 0x09, 0x73, 0x74, 0x61, 0x72, 0x74, 0x4c, 0x69, 0x6e, 0x65, 0x12, 0x19, 0x0a, 0x08, - 0x65, 0x6e, 0x64, 0x5f, 0x6c, 0x69, 0x6e, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x07, - 0x65, 0x6e, 0x64, 0x4c, 0x69, 0x6e, 0x65, 0x22, 0xb6, 0x02, 0x0a, 0x10, 0x4d, 0x69, 0x73, 0x63, - 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x1b, 0x0a, 0x09, - 0x66, 0x69, 0x6c, 0x65, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x08, 0x66, 0x69, 0x6c, 0x65, 0x54, 0x79, 0x70, 0x65, 0x12, 0x1b, 0x0a, 0x09, 0x66, 0x69, 0x6c, - 0x65, 0x5f, 0x70, 0x61, 0x74, 0x68, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x66, 0x69, - 0x6c, 0x65, 0x50, 0x61, 0x74, 0x68, 0x12, 0x39, 0x0a, 0x09, 0x73, 0x75, 0x63, 0x63, 0x65, 0x73, - 0x73, 0x65, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x74, 0x72, 0x69, 0x76, - 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x4d, 0x69, 0x73, 0x63, 0x6f, 0x6e, 0x66, - 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x52, 0x09, 0x73, 0x75, 0x63, 0x63, 0x65, 0x73, 0x73, 0x65, - 0x73, 0x12, 0x37, 0x0a, 0x08, 0x77, 0x61, 0x72, 0x6e, 0x69, 0x6e, 0x67, 0x73, 0x18, 0x04, 0x20, - 0x03, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x74, 0x72, 0x69, 0x76, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, - 0x6f, 0x6e, 0x2e, 0x4d, 0x69, 0x73, 0x63, 0x6f, 0x6e, 0x66, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, - 0x52, 0x08, 0x77, 0x61, 0x72, 0x6e, 0x69, 0x6e, 0x67, 0x73, 0x12, 0x37, 0x0a, 0x08, 0x66, 0x61, - 0x69, 0x6c, 0x75, 0x72, 0x65, 0x73, 0x18, 0x05, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x74, - 0x72, 0x69, 0x76, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x4d, 0x69, 0x73, 0x63, - 0x6f, 0x6e, 0x66, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x52, 0x08, 0x66, 0x61, 0x69, 0x6c, 0x75, - 0x72, 0x65, 0x73, 0x12, 0x3b, 0x0a, 0x0a, 0x65, 0x78, 0x63, 0x65, 0x70, 0x74, 0x69, 0x6f, 0x6e, - 0x73, 0x18, 0x06, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x74, 0x72, 0x69, 0x76, 0x79, 0x2e, + 0x66, 0x69, 0x6c, 0x65, 0x50, 0x61, 0x74, 0x68, 0x12, 0x31, 0x0a, 0x08, 0x70, 0x61, 0x63, 0x6b, + 0x61, 0x67, 0x65, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x74, 0x72, 0x69, + 0x76, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x50, 0x61, 0x63, 0x6b, 0x61, 0x67, + 0x65, 0x52, 0x08, 0x70, 0x61, 0x63, 0x6b, 0x61, 0x67, 0x65, 0x73, 0x22, 0xc1, 0x04, 0x0a, 0x07, + 0x50, 0x61, 0x63, 0x6b, 0x61, 0x67, 0x65, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x0d, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x76, + 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x76, 0x65, + 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x18, 0x0a, 0x07, 0x72, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, + 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x72, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x12, + 0x14, 0x0a, 0x05, 0x65, 0x70, 0x6f, 0x63, 0x68, 0x18, 0x04, 0x20, 0x01, 0x28, 0x05, 0x52, 0x05, + 0x65, 0x70, 0x6f, 0x63, 0x68, 0x12, 0x3b, 0x0a, 0x0a, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, + 0x69, 0x65, 0x72, 0x18, 0x13, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x74, 0x72, 0x69, 0x76, + 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x50, 0x6b, 0x67, 0x49, 0x64, 0x65, 0x6e, + 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x52, 0x0a, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, + 0x65, 0x72, 0x12, 0x12, 0x0a, 0x04, 0x61, 0x72, 0x63, 0x68, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x04, 0x61, 0x72, 0x63, 0x68, 0x12, 0x19, 0x0a, 0x08, 0x73, 0x72, 0x63, 0x5f, 0x6e, 0x61, + 0x6d, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x73, 0x72, 0x63, 0x4e, 0x61, 0x6d, + 0x65, 0x12, 0x1f, 0x0a, 0x0b, 0x73, 0x72, 0x63, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, + 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x73, 0x72, 0x63, 0x56, 0x65, 0x72, 0x73, 0x69, + 0x6f, 0x6e, 0x12, 0x1f, 0x0a, 0x0b, 0x73, 0x72, 0x63, 0x5f, 0x72, 0x65, 0x6c, 0x65, 0x61, 0x73, + 0x65, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x73, 0x72, 0x63, 0x52, 0x65, 0x6c, 0x65, + 0x61, 0x73, 0x65, 0x12, 0x1b, 0x0a, 0x09, 0x73, 0x72, 0x63, 0x5f, 0x65, 0x70, 0x6f, 0x63, 0x68, + 0x18, 0x09, 0x20, 0x01, 0x28, 0x05, 0x52, 0x08, 0x73, 0x72, 0x63, 0x45, 0x70, 0x6f, 0x63, 0x68, + 0x12, 0x1a, 0x0a, 0x08, 0x6c, 0x69, 0x63, 0x65, 0x6e, 0x73, 0x65, 0x73, 0x18, 0x0f, 0x20, 0x03, + 0x28, 0x09, 0x52, 0x08, 0x6c, 0x69, 0x63, 0x65, 0x6e, 0x73, 0x65, 0x73, 0x12, 0x34, 0x0a, 0x09, + 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x14, 0x20, 0x03, 0x28, 0x0b, 0x32, + 0x16, 0x2e, 0x74, 0x72, 0x69, 0x76, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x4c, + 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x09, 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, + 0x6e, 0x73, 0x12, 0x29, 0x0a, 0x05, 0x6c, 0x61, 0x79, 0x65, 0x72, 0x18, 0x0b, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x13, 0x2e, 0x74, 0x72, 0x69, 0x76, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, + 0x2e, 0x4c, 0x61, 0x79, 0x65, 0x72, 0x52, 0x05, 0x6c, 0x61, 0x79, 0x65, 0x72, 0x12, 0x1b, 0x0a, + 0x09, 0x66, 0x69, 0x6c, 0x65, 0x5f, 0x70, 0x61, 0x74, 0x68, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x08, 0x66, 0x69, 0x6c, 0x65, 0x50, 0x61, 0x74, 0x68, 0x12, 0x1d, 0x0a, 0x0a, 0x64, 0x65, + 0x70, 0x65, 0x6e, 0x64, 0x73, 0x5f, 0x6f, 0x6e, 0x18, 0x0e, 0x20, 0x03, 0x28, 0x09, 0x52, 0x09, + 0x64, 0x65, 0x70, 0x65, 0x6e, 0x64, 0x73, 0x4f, 0x6e, 0x12, 0x16, 0x0a, 0x06, 0x64, 0x69, 0x67, + 0x65, 0x73, 0x74, 0x18, 0x10, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x64, 0x69, 0x67, 0x65, 0x73, + 0x74, 0x12, 0x10, 0x0a, 0x03, 0x64, 0x65, 0x76, 0x18, 0x11, 0x20, 0x01, 0x28, 0x08, 0x52, 0x03, + 0x64, 0x65, 0x76, 0x12, 0x1a, 0x0a, 0x08, 0x69, 0x6e, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 0x18, + 0x12, 0x20, 0x01, 0x28, 0x08, 0x52, 0x08, 0x69, 0x6e, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 0x22, + 0x4e, 0x0a, 0x0d, 0x50, 0x6b, 0x67, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, + 0x12, 0x12, 0x0a, 0x04, 0x70, 0x75, 0x72, 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, + 0x70, 0x75, 0x72, 0x6c, 0x12, 0x17, 0x0a, 0x07, 0x62, 0x6f, 0x6d, 0x5f, 0x72, 0x65, 0x66, 0x18, + 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x62, 0x6f, 0x6d, 0x52, 0x65, 0x66, 0x12, 0x10, 0x0a, + 0x03, 0x75, 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x75, 0x69, 0x64, 0x22, + 0x44, 0x0a, 0x08, 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x1d, 0x0a, 0x0a, 0x73, + 0x74, 0x61, 0x72, 0x74, 0x5f, 0x6c, 0x69, 0x6e, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, + 0x09, 0x73, 0x74, 0x61, 0x72, 0x74, 0x4c, 0x69, 0x6e, 0x65, 0x12, 0x19, 0x0a, 0x08, 0x65, 0x6e, + 0x64, 0x5f, 0x6c, 0x69, 0x6e, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x07, 0x65, 0x6e, + 0x64, 0x4c, 0x69, 0x6e, 0x65, 0x22, 0xb6, 0x02, 0x0a, 0x10, 0x4d, 0x69, 0x73, 0x63, 0x6f, 0x6e, + 0x66, 0x69, 0x67, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x1b, 0x0a, 0x09, 0x66, 0x69, + 0x6c, 0x65, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x66, + 0x69, 0x6c, 0x65, 0x54, 0x79, 0x70, 0x65, 0x12, 0x1b, 0x0a, 0x09, 0x66, 0x69, 0x6c, 0x65, 0x5f, + 0x70, 0x61, 0x74, 0x68, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x66, 0x69, 0x6c, 0x65, + 0x50, 0x61, 0x74, 0x68, 0x12, 0x39, 0x0a, 0x09, 0x73, 0x75, 0x63, 0x63, 0x65, 0x73, 0x73, 0x65, + 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x74, 0x72, 0x69, 0x76, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x4d, 0x69, 0x73, 0x63, 0x6f, 0x6e, 0x66, 0x52, 0x65, - 0x73, 0x75, 0x6c, 0x74, 0x52, 0x0a, 0x65, 0x78, 0x63, 0x65, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, - 0x22, 0xf3, 0x01, 0x0a, 0x0d, 0x4d, 0x69, 0x73, 0x63, 0x6f, 0x6e, 0x66, 0x52, 0x65, 0x73, 0x75, - 0x6c, 0x74, 0x12, 0x1c, 0x0a, 0x09, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, - 0x12, 0x18, 0x0a, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x45, 0x0a, 0x0f, 0x70, 0x6f, - 0x6c, 0x69, 0x63, 0x79, 0x5f, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x18, 0x07, 0x20, - 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x74, 0x72, 0x69, 0x76, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, - 0x6f, 0x6e, 0x2e, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, - 0x61, 0x52, 0x0e, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, - 0x61, 0x12, 0x42, 0x0a, 0x0e, 0x63, 0x61, 0x75, 0x73, 0x65, 0x5f, 0x6d, 0x65, 0x74, 0x61, 0x64, - 0x61, 0x74, 0x61, 0x18, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x74, 0x72, 0x69, 0x76, - 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x43, 0x61, 0x75, 0x73, 0x65, 0x4d, 0x65, - 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x52, 0x0d, 0x63, 0x61, 0x75, 0x73, 0x65, 0x4d, 0x65, 0x74, - 0x61, 0x64, 0x61, 0x74, 0x61, 0x4a, 0x04, 0x08, 0x03, 0x10, 0x07, 0x52, 0x04, 0x74, 0x79, 0x70, - 0x65, 0x52, 0x02, 0x69, 0x64, 0x52, 0x05, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x52, 0x08, 0x73, 0x65, - 0x76, 0x65, 0x72, 0x69, 0x74, 0x79, 0x22, 0xf0, 0x01, 0x0a, 0x0e, 0x50, 0x6f, 0x6c, 0x69, 0x63, - 0x79, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x15, 0x0a, 0x06, 0x61, 0x64, 0x76, - 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x61, 0x64, 0x76, 0x49, 0x64, - 0x12, 0x12, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, - 0x74, 0x79, 0x70, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x18, 0x04, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x05, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x12, 0x20, 0x0a, 0x0b, 0x64, 0x65, - 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x1a, 0x0a, 0x08, - 0x73, 0x65, 0x76, 0x65, 0x72, 0x69, 0x74, 0x79, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, - 0x73, 0x65, 0x76, 0x65, 0x72, 0x69, 0x74, 0x79, 0x12, 0x2f, 0x0a, 0x13, 0x72, 0x65, 0x63, 0x6f, - 0x6d, 0x6d, 0x65, 0x6e, 0x64, 0x65, 0x64, 0x5f, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, - 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x12, 0x72, 0x65, 0x63, 0x6f, 0x6d, 0x6d, 0x65, 0x6e, 0x64, - 0x65, 0x64, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x1e, 0x0a, 0x0a, 0x72, 0x65, 0x66, - 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x73, 0x18, 0x08, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0a, 0x72, - 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x73, 0x22, 0xf7, 0x03, 0x0a, 0x18, 0x44, 0x65, - 0x74, 0x65, 0x63, 0x74, 0x65, 0x64, 0x4d, 0x69, 0x73, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, - 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, - 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x74, 0x69, - 0x74, 0x6c, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x74, 0x69, 0x74, 0x6c, 0x65, - 0x12, 0x20, 0x0a, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, - 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, - 0x6f, 0x6e, 0x12, 0x18, 0x0a, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x05, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x1c, 0x0a, 0x09, - 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x09, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x12, 0x1e, 0x0a, 0x0a, 0x72, 0x65, - 0x73, 0x6f, 0x6c, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, - 0x72, 0x65, 0x73, 0x6f, 0x6c, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x32, 0x0a, 0x08, 0x73, 0x65, - 0x76, 0x65, 0x72, 0x69, 0x74, 0x79, 0x18, 0x08, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x16, 0x2e, 0x74, - 0x72, 0x69, 0x76, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x53, 0x65, 0x76, 0x65, - 0x72, 0x69, 0x74, 0x79, 0x52, 0x08, 0x73, 0x65, 0x76, 0x65, 0x72, 0x69, 0x74, 0x79, 0x12, 0x1f, - 0x0a, 0x0b, 0x70, 0x72, 0x69, 0x6d, 0x61, 0x72, 0x79, 0x5f, 0x75, 0x72, 0x6c, 0x18, 0x09, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x0a, 0x70, 0x72, 0x69, 0x6d, 0x61, 0x72, 0x79, 0x55, 0x72, 0x6c, 0x12, - 0x1e, 0x0a, 0x0a, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x73, 0x18, 0x0a, 0x20, - 0x03, 0x28, 0x09, 0x52, 0x0a, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x73, 0x12, - 0x16, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x29, 0x0a, 0x05, 0x6c, 0x61, 0x79, 0x65, 0x72, - 0x18, 0x0c, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x74, 0x72, 0x69, 0x76, 0x79, 0x2e, 0x63, - 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x4c, 0x61, 0x79, 0x65, 0x72, 0x52, 0x05, 0x6c, 0x61, 0x79, - 0x65, 0x72, 0x12, 0x42, 0x0a, 0x0e, 0x63, 0x61, 0x75, 0x73, 0x65, 0x5f, 0x6d, 0x65, 0x74, 0x61, - 0x64, 0x61, 0x74, 0x61, 0x18, 0x0d, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x74, 0x72, 0x69, - 0x76, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x43, 0x61, 0x75, 0x73, 0x65, 0x4d, - 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x52, 0x0d, 0x63, 0x61, 0x75, 0x73, 0x65, 0x4d, 0x65, - 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x12, 0x15, 0x0a, 0x06, 0x61, 0x76, 0x64, 0x5f, 0x69, 0x64, - 0x18, 0x0e, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x61, 0x76, 0x64, 0x49, 0x64, 0x12, 0x14, 0x0a, - 0x05, 0x71, 0x75, 0x65, 0x72, 0x79, 0x18, 0x0f, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x71, 0x75, - 0x65, 0x72, 0x79, 0x22, 0xff, 0x09, 0x0a, 0x0d, 0x56, 0x75, 0x6c, 0x6e, 0x65, 0x72, 0x61, 0x62, - 0x69, 0x6c, 0x69, 0x74, 0x79, 0x12, 0x29, 0x0a, 0x10, 0x76, 0x75, 0x6c, 0x6e, 0x65, 0x72, 0x61, - 0x62, 0x69, 0x6c, 0x69, 0x74, 0x79, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x0f, 0x76, 0x75, 0x6c, 0x6e, 0x65, 0x72, 0x61, 0x62, 0x69, 0x6c, 0x69, 0x74, 0x79, 0x49, 0x64, - 0x12, 0x19, 0x0a, 0x08, 0x70, 0x6b, 0x67, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x07, 0x70, 0x6b, 0x67, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x2b, 0x0a, 0x11, 0x69, - 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x65, 0x64, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, - 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x10, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x65, - 0x64, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x23, 0x0a, 0x0d, 0x66, 0x69, 0x78, 0x65, - 0x64, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x0c, 0x66, 0x69, 0x78, 0x65, 0x64, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x14, 0x0a, - 0x05, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x74, 0x69, - 0x74, 0x6c, 0x65, 0x12, 0x20, 0x0a, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, - 0x6f, 0x6e, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, - 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x32, 0x0a, 0x08, 0x73, 0x65, 0x76, 0x65, 0x72, 0x69, 0x74, - 0x79, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x16, 0x2e, 0x74, 0x72, 0x69, 0x76, 0x79, 0x2e, - 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x53, 0x65, 0x76, 0x65, 0x72, 0x69, 0x74, 0x79, 0x52, - 0x08, 0x73, 0x65, 0x76, 0x65, 0x72, 0x69, 0x74, 0x79, 0x12, 0x1e, 0x0a, 0x0a, 0x72, 0x65, 0x66, - 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x73, 0x18, 0x08, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0a, 0x72, - 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x73, 0x12, 0x42, 0x0a, 0x0e, 0x70, 0x6b, 0x67, - 0x5f, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x18, 0x19, 0x20, 0x01, 0x28, + 0x73, 0x75, 0x6c, 0x74, 0x52, 0x09, 0x73, 0x75, 0x63, 0x63, 0x65, 0x73, 0x73, 0x65, 0x73, 0x12, + 0x37, 0x0a, 0x08, 0x77, 0x61, 0x72, 0x6e, 0x69, 0x6e, 0x67, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x74, 0x72, 0x69, 0x76, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, - 0x2e, 0x50, 0x6b, 0x67, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x52, 0x0d, - 0x70, 0x6b, 0x67, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x12, 0x29, 0x0a, - 0x05, 0x6c, 0x61, 0x79, 0x65, 0x72, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x74, - 0x72, 0x69, 0x76, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x4c, 0x61, 0x79, 0x65, - 0x72, 0x52, 0x05, 0x6c, 0x61, 0x79, 0x65, 0x72, 0x12, 0x27, 0x0a, 0x0f, 0x73, 0x65, 0x76, 0x65, - 0x72, 0x69, 0x74, 0x79, 0x5f, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x18, 0x0b, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x0e, 0x73, 0x65, 0x76, 0x65, 0x72, 0x69, 0x74, 0x79, 0x53, 0x6f, 0x75, 0x72, 0x63, - 0x65, 0x12, 0x39, 0x0a, 0x04, 0x63, 0x76, 0x73, 0x73, 0x18, 0x0c, 0x20, 0x03, 0x28, 0x0b, 0x32, - 0x25, 0x2e, 0x74, 0x72, 0x69, 0x76, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x56, - 0x75, 0x6c, 0x6e, 0x65, 0x72, 0x61, 0x62, 0x69, 0x6c, 0x69, 0x74, 0x79, 0x2e, 0x43, 0x76, 0x73, - 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x04, 0x63, 0x76, 0x73, 0x73, 0x12, 0x17, 0x0a, 0x07, - 0x63, 0x77, 0x65, 0x5f, 0x69, 0x64, 0x73, 0x18, 0x0d, 0x20, 0x03, 0x28, 0x09, 0x52, 0x06, 0x63, - 0x77, 0x65, 0x49, 0x64, 0x73, 0x12, 0x1f, 0x0a, 0x0b, 0x70, 0x72, 0x69, 0x6d, 0x61, 0x72, 0x79, - 0x5f, 0x75, 0x72, 0x6c, 0x18, 0x0e, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x70, 0x72, 0x69, 0x6d, - 0x61, 0x72, 0x79, 0x55, 0x72, 0x6c, 0x12, 0x41, 0x0a, 0x0e, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x73, - 0x68, 0x65, 0x64, 0x5f, 0x64, 0x61, 0x74, 0x65, 0x18, 0x0f, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, - 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, - 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x0d, 0x70, 0x75, 0x62, 0x6c, - 0x69, 0x73, 0x68, 0x65, 0x64, 0x44, 0x61, 0x74, 0x65, 0x12, 0x48, 0x0a, 0x12, 0x6c, 0x61, 0x73, - 0x74, 0x5f, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x69, 0x65, 0x64, 0x5f, 0x64, 0x61, 0x74, 0x65, 0x18, - 0x10, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, - 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, - 0x70, 0x52, 0x10, 0x6c, 0x61, 0x73, 0x74, 0x4d, 0x6f, 0x64, 0x69, 0x66, 0x69, 0x65, 0x64, 0x44, - 0x61, 0x74, 0x65, 0x12, 0x48, 0x0a, 0x14, 0x63, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x5f, 0x61, 0x64, - 0x76, 0x69, 0x73, 0x6f, 0x72, 0x79, 0x5f, 0x64, 0x61, 0x74, 0x61, 0x18, 0x11, 0x20, 0x01, 0x28, - 0x0b, 0x32, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, - 0x62, 0x75, 0x66, 0x2e, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x12, 0x63, 0x75, 0x73, 0x74, 0x6f, - 0x6d, 0x41, 0x64, 0x76, 0x69, 0x73, 0x6f, 0x72, 0x79, 0x44, 0x61, 0x74, 0x61, 0x12, 0x40, 0x0a, - 0x10, 0x63, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x5f, 0x76, 0x75, 0x6c, 0x6e, 0x5f, 0x64, 0x61, 0x74, - 0x61, 0x18, 0x12, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, - 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, - 0x0e, 0x63, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x56, 0x75, 0x6c, 0x6e, 0x44, 0x61, 0x74, 0x61, 0x12, - 0x1d, 0x0a, 0x0a, 0x76, 0x65, 0x6e, 0x64, 0x6f, 0x72, 0x5f, 0x69, 0x64, 0x73, 0x18, 0x13, 0x20, - 0x03, 0x28, 0x09, 0x52, 0x09, 0x76, 0x65, 0x6e, 0x64, 0x6f, 0x72, 0x49, 0x64, 0x73, 0x12, 0x39, - 0x0a, 0x0b, 0x64, 0x61, 0x74, 0x61, 0x5f, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x18, 0x14, 0x20, - 0x01, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x74, 0x72, 0x69, 0x76, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, - 0x6f, 0x6e, 0x2e, 0x44, 0x61, 0x74, 0x61, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x52, 0x0a, 0x64, - 0x61, 0x74, 0x61, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x12, 0x58, 0x0a, 0x0f, 0x76, 0x65, 0x6e, - 0x64, 0x6f, 0x72, 0x5f, 0x73, 0x65, 0x76, 0x65, 0x72, 0x69, 0x74, 0x79, 0x18, 0x15, 0x20, 0x03, - 0x28, 0x0b, 0x32, 0x2f, 0x2e, 0x74, 0x72, 0x69, 0x76, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, - 0x6e, 0x2e, 0x56, 0x75, 0x6c, 0x6e, 0x65, 0x72, 0x61, 0x62, 0x69, 0x6c, 0x69, 0x74, 0x79, 0x2e, - 0x56, 0x65, 0x6e, 0x64, 0x6f, 0x72, 0x53, 0x65, 0x76, 0x65, 0x72, 0x69, 0x74, 0x79, 0x45, 0x6e, - 0x74, 0x72, 0x79, 0x52, 0x0e, 0x76, 0x65, 0x6e, 0x64, 0x6f, 0x72, 0x53, 0x65, 0x76, 0x65, 0x72, - 0x69, 0x74, 0x79, 0x12, 0x19, 0x0a, 0x08, 0x70, 0x6b, 0x67, 0x5f, 0x70, 0x61, 0x74, 0x68, 0x18, - 0x16, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x70, 0x6b, 0x67, 0x50, 0x61, 0x74, 0x68, 0x12, 0x15, - 0x0a, 0x06, 0x70, 0x6b, 0x67, 0x5f, 0x69, 0x64, 0x18, 0x17, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, - 0x70, 0x6b, 0x67, 0x49, 0x64, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, - 0x18, 0x20, 0x01, 0x28, 0x05, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x1a, 0x4b, 0x0a, - 0x09, 0x43, 0x76, 0x73, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, - 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x28, 0x0a, 0x05, - 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x74, 0x72, - 0x69, 0x76, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x43, 0x56, 0x53, 0x53, 0x52, - 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x1a, 0x59, 0x0a, 0x13, 0x56, 0x65, - 0x6e, 0x64, 0x6f, 0x72, 0x53, 0x65, 0x76, 0x65, 0x72, 0x69, 0x74, 0x79, 0x45, 0x6e, 0x74, 0x72, - 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, - 0x6b, 0x65, 0x79, 0x12, 0x2c, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, - 0x28, 0x0e, 0x32, 0x16, 0x2e, 0x74, 0x72, 0x69, 0x76, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, - 0x6e, 0x2e, 0x53, 0x65, 0x76, 0x65, 0x72, 0x69, 0x74, 0x79, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, - 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0x42, 0x0a, 0x0a, 0x44, 0x61, 0x74, 0x61, 0x53, 0x6f, 0x75, - 0x72, 0x63, 0x65, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x02, 0x69, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x10, 0x0a, 0x03, 0x75, 0x72, 0x6c, 0x18, 0x03, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x75, 0x72, 0x6c, 0x22, 0x57, 0x0a, 0x05, 0x4c, 0x61, 0x79, - 0x65, 0x72, 0x12, 0x16, 0x0a, 0x06, 0x64, 0x69, 0x67, 0x65, 0x73, 0x74, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x06, 0x64, 0x69, 0x67, 0x65, 0x73, 0x74, 0x12, 0x17, 0x0a, 0x07, 0x64, 0x69, - 0x66, 0x66, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x64, 0x69, 0x66, - 0x66, 0x49, 0x64, 0x12, 0x1d, 0x0a, 0x0a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x62, - 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, - 0x42, 0x79, 0x22, 0xc3, 0x01, 0x0a, 0x0d, 0x43, 0x61, 0x75, 0x73, 0x65, 0x4d, 0x65, 0x74, 0x61, - 0x64, 0x61, 0x74, 0x61, 0x12, 0x1a, 0x0a, 0x08, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, - 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x18, 0x02, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x08, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x12, 0x18, 0x0a, 0x07, - 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x73, - 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x1d, 0x0a, 0x0a, 0x73, 0x74, 0x61, 0x72, 0x74, 0x5f, - 0x6c, 0x69, 0x6e, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x05, 0x52, 0x09, 0x73, 0x74, 0x61, 0x72, - 0x74, 0x4c, 0x69, 0x6e, 0x65, 0x12, 0x19, 0x0a, 0x08, 0x65, 0x6e, 0x64, 0x5f, 0x6c, 0x69, 0x6e, - 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x05, 0x52, 0x07, 0x65, 0x6e, 0x64, 0x4c, 0x69, 0x6e, 0x65, - 0x12, 0x26, 0x0a, 0x04, 0x63, 0x6f, 0x64, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x12, - 0x2e, 0x74, 0x72, 0x69, 0x76, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x43, 0x6f, - 0x64, 0x65, 0x52, 0x04, 0x63, 0x6f, 0x64, 0x65, 0x22, 0x76, 0x0a, 0x04, 0x43, 0x56, 0x53, 0x53, - 0x12, 0x1b, 0x0a, 0x09, 0x76, 0x32, 0x5f, 0x76, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x18, 0x01, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x08, 0x76, 0x32, 0x56, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x12, 0x1b, 0x0a, - 0x09, 0x76, 0x33, 0x5f, 0x76, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x08, 0x76, 0x33, 0x56, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x12, 0x19, 0x0a, 0x08, 0x76, 0x32, - 0x5f, 0x73, 0x63, 0x6f, 0x72, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x01, 0x52, 0x07, 0x76, 0x32, - 0x53, 0x63, 0x6f, 0x72, 0x65, 0x12, 0x19, 0x0a, 0x08, 0x76, 0x33, 0x5f, 0x73, 0x63, 0x6f, 0x72, - 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x01, 0x52, 0x07, 0x76, 0x33, 0x53, 0x63, 0x6f, 0x72, 0x65, - 0x22, 0x98, 0x01, 0x0a, 0x0e, 0x43, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x52, 0x65, 0x73, 0x6f, 0x75, - 0x72, 0x63, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x1b, 0x0a, 0x09, 0x66, 0x69, 0x6c, 0x65, 0x5f, - 0x70, 0x61, 0x74, 0x68, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x66, 0x69, 0x6c, 0x65, - 0x50, 0x61, 0x74, 0x68, 0x12, 0x29, 0x0a, 0x05, 0x6c, 0x61, 0x79, 0x65, 0x72, 0x18, 0x03, 0x20, - 0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x74, 0x72, 0x69, 0x76, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, - 0x6f, 0x6e, 0x2e, 0x4c, 0x61, 0x79, 0x65, 0x72, 0x52, 0x05, 0x6c, 0x61, 0x79, 0x65, 0x72, 0x12, - 0x2a, 0x0a, 0x04, 0x64, 0x61, 0x74, 0x61, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, - 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, - 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x04, 0x64, 0x61, 0x74, 0x61, 0x22, 0xf3, 0x01, 0x0a, 0x04, - 0x4c, 0x69, 0x6e, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x05, 0x52, 0x06, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x12, 0x18, 0x0a, 0x07, - 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x63, - 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x12, 0x19, 0x0a, 0x08, 0x69, 0x73, 0x5f, 0x63, 0x61, 0x75, - 0x73, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x69, 0x73, 0x43, 0x61, 0x75, 0x73, - 0x65, 0x12, 0x1e, 0x0a, 0x0a, 0x61, 0x6e, 0x6e, 0x6f, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, - 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x61, 0x6e, 0x6e, 0x6f, 0x74, 0x61, 0x74, 0x69, 0x6f, - 0x6e, 0x12, 0x1c, 0x0a, 0x09, 0x74, 0x72, 0x75, 0x6e, 0x63, 0x61, 0x74, 0x65, 0x64, 0x18, 0x05, - 0x20, 0x01, 0x28, 0x08, 0x52, 0x09, 0x74, 0x72, 0x75, 0x6e, 0x63, 0x61, 0x74, 0x65, 0x64, 0x12, - 0x20, 0x0a, 0x0b, 0x68, 0x69, 0x67, 0x68, 0x6c, 0x69, 0x67, 0x68, 0x74, 0x65, 0x64, 0x18, 0x06, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x68, 0x69, 0x67, 0x68, 0x6c, 0x69, 0x67, 0x68, 0x74, 0x65, - 0x64, 0x12, 0x1f, 0x0a, 0x0b, 0x66, 0x69, 0x72, 0x73, 0x74, 0x5f, 0x63, 0x61, 0x75, 0x73, 0x65, - 0x18, 0x07, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0a, 0x66, 0x69, 0x72, 0x73, 0x74, 0x43, 0x61, 0x75, - 0x73, 0x65, 0x12, 0x1d, 0x0a, 0x0a, 0x6c, 0x61, 0x73, 0x74, 0x5f, 0x63, 0x61, 0x75, 0x73, 0x65, - 0x18, 0x08, 0x20, 0x01, 0x28, 0x08, 0x52, 0x09, 0x6c, 0x61, 0x73, 0x74, 0x43, 0x61, 0x75, 0x73, - 0x65, 0x22, 0x30, 0x0a, 0x04, 0x43, 0x6f, 0x64, 0x65, 0x12, 0x28, 0x0a, 0x05, 0x6c, 0x69, 0x6e, - 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x74, 0x72, 0x69, 0x76, 0x79, - 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x4c, 0x69, 0x6e, 0x65, 0x52, 0x05, 0x6c, 0x69, - 0x6e, 0x65, 0x73, 0x22, 0x9f, 0x02, 0x0a, 0x0d, 0x53, 0x65, 0x63, 0x72, 0x65, 0x74, 0x46, 0x69, - 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x12, 0x17, 0x0a, 0x07, 0x72, 0x75, 0x6c, 0x65, 0x5f, 0x69, 0x64, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x72, 0x75, 0x6c, 0x65, 0x49, 0x64, 0x12, 0x1a, - 0x0a, 0x08, 0x63, 0x61, 0x74, 0x65, 0x67, 0x6f, 0x72, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x08, 0x63, 0x61, 0x74, 0x65, 0x67, 0x6f, 0x72, 0x79, 0x12, 0x1a, 0x0a, 0x08, 0x73, 0x65, - 0x76, 0x65, 0x72, 0x69, 0x74, 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x73, 0x65, - 0x76, 0x65, 0x72, 0x69, 0x74, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x18, - 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x12, 0x1d, 0x0a, 0x0a, - 0x73, 0x74, 0x61, 0x72, 0x74, 0x5f, 0x6c, 0x69, 0x6e, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x05, - 0x52, 0x09, 0x73, 0x74, 0x61, 0x72, 0x74, 0x4c, 0x69, 0x6e, 0x65, 0x12, 0x19, 0x0a, 0x08, 0x65, - 0x6e, 0x64, 0x5f, 0x6c, 0x69, 0x6e, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x05, 0x52, 0x07, 0x65, - 0x6e, 0x64, 0x4c, 0x69, 0x6e, 0x65, 0x12, 0x26, 0x0a, 0x04, 0x63, 0x6f, 0x64, 0x65, 0x18, 0x07, - 0x20, 0x01, 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x74, 0x72, 0x69, 0x76, 0x79, 0x2e, 0x63, 0x6f, 0x6d, - 0x6d, 0x6f, 0x6e, 0x2e, 0x43, 0x6f, 0x64, 0x65, 0x52, 0x04, 0x63, 0x6f, 0x64, 0x65, 0x12, 0x14, - 0x0a, 0x05, 0x6d, 0x61, 0x74, 0x63, 0x68, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x6d, - 0x61, 0x74, 0x63, 0x68, 0x12, 0x29, 0x0a, 0x05, 0x6c, 0x61, 0x79, 0x65, 0x72, 0x18, 0x0a, 0x20, - 0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x74, 0x72, 0x69, 0x76, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, - 0x6f, 0x6e, 0x2e, 0x4c, 0x61, 0x79, 0x65, 0x72, 0x52, 0x05, 0x6c, 0x61, 0x79, 0x65, 0x72, 0x4a, - 0x04, 0x08, 0x09, 0x10, 0x0a, 0x22, 0x5d, 0x0a, 0x06, 0x53, 0x65, 0x63, 0x72, 0x65, 0x74, 0x12, - 0x1a, 0x0a, 0x08, 0x66, 0x69, 0x6c, 0x65, 0x70, 0x61, 0x74, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x08, 0x66, 0x69, 0x6c, 0x65, 0x70, 0x61, 0x74, 0x68, 0x12, 0x37, 0x0a, 0x08, 0x66, - 0x69, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1b, 0x2e, - 0x74, 0x72, 0x69, 0x76, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x53, 0x65, 0x63, - 0x72, 0x65, 0x74, 0x46, 0x69, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x52, 0x08, 0x66, 0x69, 0x6e, 0x64, - 0x69, 0x6e, 0x67, 0x73, 0x22, 0x85, 0x02, 0x0a, 0x0f, 0x44, 0x65, 0x74, 0x65, 0x63, 0x74, 0x65, - 0x64, 0x4c, 0x69, 0x63, 0x65, 0x6e, 0x73, 0x65, 0x12, 0x32, 0x0a, 0x08, 0x73, 0x65, 0x76, 0x65, - 0x72, 0x69, 0x74, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x16, 0x2e, 0x74, 0x72, 0x69, + 0x2e, 0x4d, 0x69, 0x73, 0x63, 0x6f, 0x6e, 0x66, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x52, 0x08, + 0x77, 0x61, 0x72, 0x6e, 0x69, 0x6e, 0x67, 0x73, 0x12, 0x37, 0x0a, 0x08, 0x66, 0x61, 0x69, 0x6c, + 0x75, 0x72, 0x65, 0x73, 0x18, 0x05, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x74, 0x72, 0x69, + 0x76, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x4d, 0x69, 0x73, 0x63, 0x6f, 0x6e, + 0x66, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x52, 0x08, 0x66, 0x61, 0x69, 0x6c, 0x75, 0x72, 0x65, + 0x73, 0x12, 0x3b, 0x0a, 0x0a, 0x65, 0x78, 0x63, 0x65, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, + 0x06, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x74, 0x72, 0x69, 0x76, 0x79, 0x2e, 0x63, 0x6f, + 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x4d, 0x69, 0x73, 0x63, 0x6f, 0x6e, 0x66, 0x52, 0x65, 0x73, 0x75, + 0x6c, 0x74, 0x52, 0x0a, 0x65, 0x78, 0x63, 0x65, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x22, 0xf3, + 0x01, 0x0a, 0x0d, 0x4d, 0x69, 0x73, 0x63, 0x6f, 0x6e, 0x66, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, + 0x12, 0x1c, 0x0a, 0x09, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x09, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x12, 0x18, + 0x0a, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x45, 0x0a, 0x0f, 0x70, 0x6f, 0x6c, 0x69, + 0x63, 0x79, 0x5f, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x18, 0x07, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x1c, 0x2e, 0x74, 0x72, 0x69, 0x76, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, + 0x2e, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x52, + 0x0e, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x12, + 0x42, 0x0a, 0x0e, 0x63, 0x61, 0x75, 0x73, 0x65, 0x5f, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, + 0x61, 0x18, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x74, 0x72, 0x69, 0x76, 0x79, 0x2e, + 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x43, 0x61, 0x75, 0x73, 0x65, 0x4d, 0x65, 0x74, 0x61, + 0x64, 0x61, 0x74, 0x61, 0x52, 0x0d, 0x63, 0x61, 0x75, 0x73, 0x65, 0x4d, 0x65, 0x74, 0x61, 0x64, + 0x61, 0x74, 0x61, 0x4a, 0x04, 0x08, 0x03, 0x10, 0x07, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x52, + 0x02, 0x69, 0x64, 0x52, 0x05, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x52, 0x08, 0x73, 0x65, 0x76, 0x65, + 0x72, 0x69, 0x74, 0x79, 0x22, 0xf0, 0x01, 0x0a, 0x0e, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x4d, + 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x15, 0x0a, 0x06, 0x61, 0x64, 0x76, 0x5f, 0x69, + 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x61, 0x64, 0x76, 0x49, 0x64, 0x12, 0x12, + 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x74, 0x79, + 0x70, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x05, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x12, 0x20, 0x0a, 0x0b, 0x64, 0x65, 0x73, 0x63, + 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x64, + 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x1a, 0x0a, 0x08, 0x73, 0x65, + 0x76, 0x65, 0x72, 0x69, 0x74, 0x79, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x73, 0x65, + 0x76, 0x65, 0x72, 0x69, 0x74, 0x79, 0x12, 0x2f, 0x0a, 0x13, 0x72, 0x65, 0x63, 0x6f, 0x6d, 0x6d, + 0x65, 0x6e, 0x64, 0x65, 0x64, 0x5f, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x07, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x12, 0x72, 0x65, 0x63, 0x6f, 0x6d, 0x6d, 0x65, 0x6e, 0x64, 0x65, 0x64, + 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x1e, 0x0a, 0x0a, 0x72, 0x65, 0x66, 0x65, 0x72, + 0x65, 0x6e, 0x63, 0x65, 0x73, 0x18, 0x08, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0a, 0x72, 0x65, 0x66, + 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x73, 0x22, 0xf7, 0x03, 0x0a, 0x18, 0x44, 0x65, 0x74, 0x65, + 0x63, 0x74, 0x65, 0x64, 0x4d, 0x69, 0x73, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x02, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x74, 0x69, 0x74, 0x6c, + 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x12, 0x20, + 0x0a, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x04, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, + 0x12, 0x18, 0x0a, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x6e, 0x61, + 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x6e, + 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x12, 0x1e, 0x0a, 0x0a, 0x72, 0x65, 0x73, 0x6f, + 0x6c, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x72, 0x65, + 0x73, 0x6f, 0x6c, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x32, 0x0a, 0x08, 0x73, 0x65, 0x76, 0x65, + 0x72, 0x69, 0x74, 0x79, 0x18, 0x08, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x16, 0x2e, 0x74, 0x72, 0x69, 0x76, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x53, 0x65, 0x76, 0x65, 0x72, 0x69, - 0x74, 0x79, 0x52, 0x08, 0x73, 0x65, 0x76, 0x65, 0x72, 0x69, 0x74, 0x79, 0x12, 0x3e, 0x0a, 0x08, - 0x63, 0x61, 0x74, 0x65, 0x67, 0x6f, 0x72, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x22, - 0x2e, 0x74, 0x72, 0x69, 0x76, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x4c, 0x69, - 0x63, 0x65, 0x6e, 0x73, 0x65, 0x43, 0x61, 0x74, 0x65, 0x67, 0x6f, 0x72, 0x79, 0x2e, 0x45, 0x6e, - 0x75, 0x6d, 0x52, 0x08, 0x63, 0x61, 0x74, 0x65, 0x67, 0x6f, 0x72, 0x79, 0x12, 0x19, 0x0a, 0x08, - 0x70, 0x6b, 0x67, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, - 0x70, 0x6b, 0x67, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x1b, 0x0a, 0x09, 0x66, 0x69, 0x6c, 0x65, 0x5f, - 0x70, 0x61, 0x74, 0x68, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x66, 0x69, 0x6c, 0x65, - 0x50, 0x61, 0x74, 0x68, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x05, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x1e, 0x0a, 0x0a, 0x63, 0x6f, 0x6e, 0x66, - 0x69, 0x64, 0x65, 0x6e, 0x63, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x02, 0x52, 0x0a, 0x63, 0x6f, - 0x6e, 0x66, 0x69, 0x64, 0x65, 0x6e, 0x63, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x6c, 0x69, 0x6e, 0x6b, - 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6c, 0x69, 0x6e, 0x6b, 0x22, 0xed, 0x01, 0x0a, - 0x0b, 0x4c, 0x69, 0x63, 0x65, 0x6e, 0x73, 0x65, 0x46, 0x69, 0x6c, 0x65, 0x12, 0x41, 0x0a, 0x0c, - 0x6c, 0x69, 0x63, 0x65, 0x6e, 0x73, 0x65, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x0e, 0x32, 0x1e, 0x2e, 0x74, 0x72, 0x69, 0x76, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, - 0x6e, 0x2e, 0x4c, 0x69, 0x63, 0x65, 0x6e, 0x73, 0x65, 0x54, 0x79, 0x70, 0x65, 0x2e, 0x45, 0x6e, - 0x75, 0x6d, 0x52, 0x0b, 0x6c, 0x69, 0x63, 0x65, 0x6e, 0x73, 0x65, 0x54, 0x79, 0x70, 0x65, 0x12, - 0x1b, 0x0a, 0x09, 0x66, 0x69, 0x6c, 0x65, 0x5f, 0x70, 0x61, 0x74, 0x68, 0x18, 0x02, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x08, 0x66, 0x69, 0x6c, 0x65, 0x50, 0x61, 0x74, 0x68, 0x12, 0x19, 0x0a, 0x08, - 0x70, 0x6b, 0x67, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, - 0x70, 0x6b, 0x67, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x38, 0x0a, 0x08, 0x66, 0x69, 0x6e, 0x67, 0x69, - 0x6e, 0x67, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x74, 0x72, 0x69, 0x76, - 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x4c, 0x69, 0x63, 0x65, 0x6e, 0x73, 0x65, - 0x46, 0x69, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x52, 0x08, 0x66, 0x69, 0x6e, 0x67, 0x69, 0x6e, 0x67, - 0x73, 0x12, 0x29, 0x0a, 0x05, 0x6c, 0x61, 0x79, 0x65, 0x72, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, - 0x32, 0x13, 0x2e, 0x74, 0x72, 0x69, 0x76, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, - 0x4c, 0x61, 0x79, 0x65, 0x72, 0x52, 0x05, 0x6c, 0x61, 0x79, 0x65, 0x72, 0x22, 0x98, 0x01, 0x0a, - 0x0e, 0x4c, 0x69, 0x63, 0x65, 0x6e, 0x73, 0x65, 0x46, 0x69, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x12, - 0x3e, 0x0a, 0x08, 0x63, 0x61, 0x74, 0x65, 0x67, 0x6f, 0x72, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x0e, 0x32, 0x22, 0x2e, 0x74, 0x72, 0x69, 0x76, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, - 0x2e, 0x4c, 0x69, 0x63, 0x65, 0x6e, 0x73, 0x65, 0x43, 0x61, 0x74, 0x65, 0x67, 0x6f, 0x72, 0x79, - 0x2e, 0x45, 0x6e, 0x75, 0x6d, 0x52, 0x08, 0x63, 0x61, 0x74, 0x65, 0x67, 0x6f, 0x72, 0x79, 0x12, - 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, - 0x61, 0x6d, 0x65, 0x12, 0x1e, 0x0a, 0x0a, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x64, 0x65, 0x6e, 0x63, - 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x02, 0x52, 0x0a, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x64, 0x65, - 0x6e, 0x63, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x6c, 0x69, 0x6e, 0x6b, 0x18, 0x04, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x04, 0x6c, 0x69, 0x6e, 0x6b, 0x22, 0x95, 0x01, 0x0a, 0x0f, 0x4c, 0x69, 0x63, 0x65, - 0x6e, 0x73, 0x65, 0x43, 0x61, 0x74, 0x65, 0x67, 0x6f, 0x72, 0x79, 0x22, 0x81, 0x01, 0x0a, 0x04, + 0x74, 0x79, 0x52, 0x08, 0x73, 0x65, 0x76, 0x65, 0x72, 0x69, 0x74, 0x79, 0x12, 0x1f, 0x0a, 0x0b, + 0x70, 0x72, 0x69, 0x6d, 0x61, 0x72, 0x79, 0x5f, 0x75, 0x72, 0x6c, 0x18, 0x09, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x0a, 0x70, 0x72, 0x69, 0x6d, 0x61, 0x72, 0x79, 0x55, 0x72, 0x6c, 0x12, 0x1e, 0x0a, + 0x0a, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x73, 0x18, 0x0a, 0x20, 0x03, 0x28, + 0x09, 0x52, 0x0a, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x73, 0x12, 0x16, 0x0a, + 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x73, + 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x29, 0x0a, 0x05, 0x6c, 0x61, 0x79, 0x65, 0x72, 0x18, 0x0c, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x74, 0x72, 0x69, 0x76, 0x79, 0x2e, 0x63, 0x6f, 0x6d, + 0x6d, 0x6f, 0x6e, 0x2e, 0x4c, 0x61, 0x79, 0x65, 0x72, 0x52, 0x05, 0x6c, 0x61, 0x79, 0x65, 0x72, + 0x12, 0x42, 0x0a, 0x0e, 0x63, 0x61, 0x75, 0x73, 0x65, 0x5f, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, + 0x74, 0x61, 0x18, 0x0d, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x74, 0x72, 0x69, 0x76, 0x79, + 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x43, 0x61, 0x75, 0x73, 0x65, 0x4d, 0x65, 0x74, + 0x61, 0x64, 0x61, 0x74, 0x61, 0x52, 0x0d, 0x63, 0x61, 0x75, 0x73, 0x65, 0x4d, 0x65, 0x74, 0x61, + 0x64, 0x61, 0x74, 0x61, 0x12, 0x15, 0x0a, 0x06, 0x61, 0x76, 0x64, 0x5f, 0x69, 0x64, 0x18, 0x0e, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x61, 0x76, 0x64, 0x49, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x71, + 0x75, 0x65, 0x72, 0x79, 0x18, 0x0f, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x71, 0x75, 0x65, 0x72, + 0x79, 0x22, 0xff, 0x09, 0x0a, 0x0d, 0x56, 0x75, 0x6c, 0x6e, 0x65, 0x72, 0x61, 0x62, 0x69, 0x6c, + 0x69, 0x74, 0x79, 0x12, 0x29, 0x0a, 0x10, 0x76, 0x75, 0x6c, 0x6e, 0x65, 0x72, 0x61, 0x62, 0x69, + 0x6c, 0x69, 0x74, 0x79, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0f, 0x76, + 0x75, 0x6c, 0x6e, 0x65, 0x72, 0x61, 0x62, 0x69, 0x6c, 0x69, 0x74, 0x79, 0x49, 0x64, 0x12, 0x19, + 0x0a, 0x08, 0x70, 0x6b, 0x67, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x07, 0x70, 0x6b, 0x67, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x2b, 0x0a, 0x11, 0x69, 0x6e, 0x73, + 0x74, 0x61, 0x6c, 0x6c, 0x65, 0x64, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x03, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x10, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x65, 0x64, 0x56, + 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x23, 0x0a, 0x0d, 0x66, 0x69, 0x78, 0x65, 0x64, 0x5f, + 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x66, + 0x69, 0x78, 0x65, 0x64, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x14, 0x0a, 0x05, 0x74, + 0x69, 0x74, 0x6c, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x74, 0x69, 0x74, 0x6c, + 0x65, 0x12, 0x20, 0x0a, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, + 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, + 0x69, 0x6f, 0x6e, 0x12, 0x32, 0x0a, 0x08, 0x73, 0x65, 0x76, 0x65, 0x72, 0x69, 0x74, 0x79, 0x18, + 0x07, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x16, 0x2e, 0x74, 0x72, 0x69, 0x76, 0x79, 0x2e, 0x63, 0x6f, + 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x53, 0x65, 0x76, 0x65, 0x72, 0x69, 0x74, 0x79, 0x52, 0x08, 0x73, + 0x65, 0x76, 0x65, 0x72, 0x69, 0x74, 0x79, 0x12, 0x1e, 0x0a, 0x0a, 0x72, 0x65, 0x66, 0x65, 0x72, + 0x65, 0x6e, 0x63, 0x65, 0x73, 0x18, 0x08, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0a, 0x72, 0x65, 0x66, + 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x73, 0x12, 0x42, 0x0a, 0x0e, 0x70, 0x6b, 0x67, 0x5f, 0x69, + 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x18, 0x19, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x1b, 0x2e, 0x74, 0x72, 0x69, 0x76, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x50, + 0x6b, 0x67, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x52, 0x0d, 0x70, 0x6b, + 0x67, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x12, 0x29, 0x0a, 0x05, 0x6c, + 0x61, 0x79, 0x65, 0x72, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x74, 0x72, 0x69, + 0x76, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x4c, 0x61, 0x79, 0x65, 0x72, 0x52, + 0x05, 0x6c, 0x61, 0x79, 0x65, 0x72, 0x12, 0x27, 0x0a, 0x0f, 0x73, 0x65, 0x76, 0x65, 0x72, 0x69, + 0x74, 0x79, 0x5f, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x0e, 0x73, 0x65, 0x76, 0x65, 0x72, 0x69, 0x74, 0x79, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x12, + 0x39, 0x0a, 0x04, 0x63, 0x76, 0x73, 0x73, 0x18, 0x0c, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x25, 0x2e, + 0x74, 0x72, 0x69, 0x76, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x56, 0x75, 0x6c, + 0x6e, 0x65, 0x72, 0x61, 0x62, 0x69, 0x6c, 0x69, 0x74, 0x79, 0x2e, 0x43, 0x76, 0x73, 0x73, 0x45, + 0x6e, 0x74, 0x72, 0x79, 0x52, 0x04, 0x63, 0x76, 0x73, 0x73, 0x12, 0x17, 0x0a, 0x07, 0x63, 0x77, + 0x65, 0x5f, 0x69, 0x64, 0x73, 0x18, 0x0d, 0x20, 0x03, 0x28, 0x09, 0x52, 0x06, 0x63, 0x77, 0x65, + 0x49, 0x64, 0x73, 0x12, 0x1f, 0x0a, 0x0b, 0x70, 0x72, 0x69, 0x6d, 0x61, 0x72, 0x79, 0x5f, 0x75, + 0x72, 0x6c, 0x18, 0x0e, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x70, 0x72, 0x69, 0x6d, 0x61, 0x72, + 0x79, 0x55, 0x72, 0x6c, 0x12, 0x41, 0x0a, 0x0e, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x73, 0x68, 0x65, + 0x64, 0x5f, 0x64, 0x61, 0x74, 0x65, 0x18, 0x0f, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, + 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, + 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x0d, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x73, + 0x68, 0x65, 0x64, 0x44, 0x61, 0x74, 0x65, 0x12, 0x48, 0x0a, 0x12, 0x6c, 0x61, 0x73, 0x74, 0x5f, + 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x69, 0x65, 0x64, 0x5f, 0x64, 0x61, 0x74, 0x65, 0x18, 0x10, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, + 0x10, 0x6c, 0x61, 0x73, 0x74, 0x4d, 0x6f, 0x64, 0x69, 0x66, 0x69, 0x65, 0x64, 0x44, 0x61, 0x74, + 0x65, 0x12, 0x48, 0x0a, 0x14, 0x63, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x5f, 0x61, 0x64, 0x76, 0x69, + 0x73, 0x6f, 0x72, 0x79, 0x5f, 0x64, 0x61, 0x74, 0x61, 0x18, 0x11, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, + 0x66, 0x2e, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x12, 0x63, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x41, + 0x64, 0x76, 0x69, 0x73, 0x6f, 0x72, 0x79, 0x44, 0x61, 0x74, 0x61, 0x12, 0x40, 0x0a, 0x10, 0x63, + 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x5f, 0x76, 0x75, 0x6c, 0x6e, 0x5f, 0x64, 0x61, 0x74, 0x61, 0x18, + 0x12, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x0e, 0x63, + 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x56, 0x75, 0x6c, 0x6e, 0x44, 0x61, 0x74, 0x61, 0x12, 0x1d, 0x0a, + 0x0a, 0x76, 0x65, 0x6e, 0x64, 0x6f, 0x72, 0x5f, 0x69, 0x64, 0x73, 0x18, 0x13, 0x20, 0x03, 0x28, + 0x09, 0x52, 0x09, 0x76, 0x65, 0x6e, 0x64, 0x6f, 0x72, 0x49, 0x64, 0x73, 0x12, 0x39, 0x0a, 0x0b, + 0x64, 0x61, 0x74, 0x61, 0x5f, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x18, 0x14, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x18, 0x2e, 0x74, 0x72, 0x69, 0x76, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, + 0x2e, 0x44, 0x61, 0x74, 0x61, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x52, 0x0a, 0x64, 0x61, 0x74, + 0x61, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x12, 0x58, 0x0a, 0x0f, 0x76, 0x65, 0x6e, 0x64, 0x6f, + 0x72, 0x5f, 0x73, 0x65, 0x76, 0x65, 0x72, 0x69, 0x74, 0x79, 0x18, 0x15, 0x20, 0x03, 0x28, 0x0b, + 0x32, 0x2f, 0x2e, 0x74, 0x72, 0x69, 0x76, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, + 0x56, 0x75, 0x6c, 0x6e, 0x65, 0x72, 0x61, 0x62, 0x69, 0x6c, 0x69, 0x74, 0x79, 0x2e, 0x56, 0x65, + 0x6e, 0x64, 0x6f, 0x72, 0x53, 0x65, 0x76, 0x65, 0x72, 0x69, 0x74, 0x79, 0x45, 0x6e, 0x74, 0x72, + 0x79, 0x52, 0x0e, 0x76, 0x65, 0x6e, 0x64, 0x6f, 0x72, 0x53, 0x65, 0x76, 0x65, 0x72, 0x69, 0x74, + 0x79, 0x12, 0x19, 0x0a, 0x08, 0x70, 0x6b, 0x67, 0x5f, 0x70, 0x61, 0x74, 0x68, 0x18, 0x16, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x07, 0x70, 0x6b, 0x67, 0x50, 0x61, 0x74, 0x68, 0x12, 0x15, 0x0a, 0x06, + 0x70, 0x6b, 0x67, 0x5f, 0x69, 0x64, 0x18, 0x17, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x70, 0x6b, + 0x67, 0x49, 0x64, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x18, 0x20, + 0x01, 0x28, 0x05, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x1a, 0x4b, 0x0a, 0x09, 0x43, + 0x76, 0x73, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x28, 0x0a, 0x05, 0x76, 0x61, + 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x74, 0x72, 0x69, 0x76, + 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x43, 0x56, 0x53, 0x53, 0x52, 0x05, 0x76, + 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x1a, 0x59, 0x0a, 0x13, 0x56, 0x65, 0x6e, 0x64, + 0x6f, 0x72, 0x53, 0x65, 0x76, 0x65, 0x72, 0x69, 0x74, 0x79, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, + 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, + 0x79, 0x12, 0x2c, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, + 0x32, 0x16, 0x2e, 0x74, 0x72, 0x69, 0x76, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, + 0x53, 0x65, 0x76, 0x65, 0x72, 0x69, 0x74, 0x79, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, + 0x02, 0x38, 0x01, 0x22, 0x42, 0x0a, 0x0a, 0x44, 0x61, 0x74, 0x61, 0x53, 0x6f, 0x75, 0x72, 0x63, + 0x65, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, + 0x64, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x10, 0x0a, 0x03, 0x75, 0x72, 0x6c, 0x18, 0x03, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x03, 0x75, 0x72, 0x6c, 0x22, 0x57, 0x0a, 0x05, 0x4c, 0x61, 0x79, 0x65, 0x72, + 0x12, 0x16, 0x0a, 0x06, 0x64, 0x69, 0x67, 0x65, 0x73, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x06, 0x64, 0x69, 0x67, 0x65, 0x73, 0x74, 0x12, 0x17, 0x0a, 0x07, 0x64, 0x69, 0x66, 0x66, + 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x64, 0x69, 0x66, 0x66, 0x49, + 0x64, 0x12, 0x1d, 0x0a, 0x0a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x62, 0x79, 0x18, + 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x42, 0x79, + 0x22, 0xc3, 0x01, 0x0a, 0x0d, 0x43, 0x61, 0x75, 0x73, 0x65, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, + 0x74, 0x61, 0x12, 0x1a, 0x0a, 0x08, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x12, 0x1a, + 0x0a, 0x08, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x08, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x12, 0x18, 0x0a, 0x07, 0x73, 0x65, + 0x72, 0x76, 0x69, 0x63, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x73, 0x65, 0x72, + 0x76, 0x69, 0x63, 0x65, 0x12, 0x1d, 0x0a, 0x0a, 0x73, 0x74, 0x61, 0x72, 0x74, 0x5f, 0x6c, 0x69, + 0x6e, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x05, 0x52, 0x09, 0x73, 0x74, 0x61, 0x72, 0x74, 0x4c, + 0x69, 0x6e, 0x65, 0x12, 0x19, 0x0a, 0x08, 0x65, 0x6e, 0x64, 0x5f, 0x6c, 0x69, 0x6e, 0x65, 0x18, + 0x05, 0x20, 0x01, 0x28, 0x05, 0x52, 0x07, 0x65, 0x6e, 0x64, 0x4c, 0x69, 0x6e, 0x65, 0x12, 0x26, + 0x0a, 0x04, 0x63, 0x6f, 0x64, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x74, + 0x72, 0x69, 0x76, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x43, 0x6f, 0x64, 0x65, + 0x52, 0x04, 0x63, 0x6f, 0x64, 0x65, 0x22, 0x76, 0x0a, 0x04, 0x43, 0x56, 0x53, 0x53, 0x12, 0x1b, + 0x0a, 0x09, 0x76, 0x32, 0x5f, 0x76, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x08, 0x76, 0x32, 0x56, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x12, 0x1b, 0x0a, 0x09, 0x76, + 0x33, 0x5f, 0x76, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, + 0x76, 0x33, 0x56, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x12, 0x19, 0x0a, 0x08, 0x76, 0x32, 0x5f, 0x73, + 0x63, 0x6f, 0x72, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x01, 0x52, 0x07, 0x76, 0x32, 0x53, 0x63, + 0x6f, 0x72, 0x65, 0x12, 0x19, 0x0a, 0x08, 0x76, 0x33, 0x5f, 0x73, 0x63, 0x6f, 0x72, 0x65, 0x18, + 0x04, 0x20, 0x01, 0x28, 0x01, 0x52, 0x07, 0x76, 0x33, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x22, 0x98, + 0x01, 0x0a, 0x0e, 0x43, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, + 0x65, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x1b, 0x0a, 0x09, 0x66, 0x69, 0x6c, 0x65, 0x5f, 0x70, 0x61, + 0x74, 0x68, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x66, 0x69, 0x6c, 0x65, 0x50, 0x61, + 0x74, 0x68, 0x12, 0x29, 0x0a, 0x05, 0x6c, 0x61, 0x79, 0x65, 0x72, 0x18, 0x03, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x13, 0x2e, 0x74, 0x72, 0x69, 0x76, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, + 0x2e, 0x4c, 0x61, 0x79, 0x65, 0x72, 0x52, 0x05, 0x6c, 0x61, 0x79, 0x65, 0x72, 0x12, 0x2a, 0x0a, + 0x04, 0x64, 0x61, 0x74, 0x61, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x67, 0x6f, + 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x56, 0x61, + 0x6c, 0x75, 0x65, 0x52, 0x04, 0x64, 0x61, 0x74, 0x61, 0x22, 0xf3, 0x01, 0x0a, 0x04, 0x4c, 0x69, + 0x6e, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x05, 0x52, 0x06, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x12, 0x18, 0x0a, 0x07, 0x63, 0x6f, + 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x63, 0x6f, 0x6e, + 0x74, 0x65, 0x6e, 0x74, 0x12, 0x19, 0x0a, 0x08, 0x69, 0x73, 0x5f, 0x63, 0x61, 0x75, 0x73, 0x65, + 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x69, 0x73, 0x43, 0x61, 0x75, 0x73, 0x65, 0x12, + 0x1e, 0x0a, 0x0a, 0x61, 0x6e, 0x6e, 0x6f, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x04, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x0a, 0x61, 0x6e, 0x6e, 0x6f, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, + 0x1c, 0x0a, 0x09, 0x74, 0x72, 0x75, 0x6e, 0x63, 0x61, 0x74, 0x65, 0x64, 0x18, 0x05, 0x20, 0x01, + 0x28, 0x08, 0x52, 0x09, 0x74, 0x72, 0x75, 0x6e, 0x63, 0x61, 0x74, 0x65, 0x64, 0x12, 0x20, 0x0a, + 0x0b, 0x68, 0x69, 0x67, 0x68, 0x6c, 0x69, 0x67, 0x68, 0x74, 0x65, 0x64, 0x18, 0x06, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x0b, 0x68, 0x69, 0x67, 0x68, 0x6c, 0x69, 0x67, 0x68, 0x74, 0x65, 0x64, 0x12, + 0x1f, 0x0a, 0x0b, 0x66, 0x69, 0x72, 0x73, 0x74, 0x5f, 0x63, 0x61, 0x75, 0x73, 0x65, 0x18, 0x07, + 0x20, 0x01, 0x28, 0x08, 0x52, 0x0a, 0x66, 0x69, 0x72, 0x73, 0x74, 0x43, 0x61, 0x75, 0x73, 0x65, + 0x12, 0x1d, 0x0a, 0x0a, 0x6c, 0x61, 0x73, 0x74, 0x5f, 0x63, 0x61, 0x75, 0x73, 0x65, 0x18, 0x08, + 0x20, 0x01, 0x28, 0x08, 0x52, 0x09, 0x6c, 0x61, 0x73, 0x74, 0x43, 0x61, 0x75, 0x73, 0x65, 0x22, + 0x30, 0x0a, 0x04, 0x43, 0x6f, 0x64, 0x65, 0x12, 0x28, 0x0a, 0x05, 0x6c, 0x69, 0x6e, 0x65, 0x73, + 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x74, 0x72, 0x69, 0x76, 0x79, 0x2e, 0x63, + 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x4c, 0x69, 0x6e, 0x65, 0x52, 0x05, 0x6c, 0x69, 0x6e, 0x65, + 0x73, 0x22, 0x9f, 0x02, 0x0a, 0x0d, 0x53, 0x65, 0x63, 0x72, 0x65, 0x74, 0x46, 0x69, 0x6e, 0x64, + 0x69, 0x6e, 0x67, 0x12, 0x17, 0x0a, 0x07, 0x72, 0x75, 0x6c, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x72, 0x75, 0x6c, 0x65, 0x49, 0x64, 0x12, 0x1a, 0x0a, 0x08, + 0x63, 0x61, 0x74, 0x65, 0x67, 0x6f, 0x72, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, + 0x63, 0x61, 0x74, 0x65, 0x67, 0x6f, 0x72, 0x79, 0x12, 0x1a, 0x0a, 0x08, 0x73, 0x65, 0x76, 0x65, + 0x72, 0x69, 0x74, 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x73, 0x65, 0x76, 0x65, + 0x72, 0x69, 0x74, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x18, 0x04, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x05, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x12, 0x1d, 0x0a, 0x0a, 0x73, 0x74, + 0x61, 0x72, 0x74, 0x5f, 0x6c, 0x69, 0x6e, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x05, 0x52, 0x09, + 0x73, 0x74, 0x61, 0x72, 0x74, 0x4c, 0x69, 0x6e, 0x65, 0x12, 0x19, 0x0a, 0x08, 0x65, 0x6e, 0x64, + 0x5f, 0x6c, 0x69, 0x6e, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x05, 0x52, 0x07, 0x65, 0x6e, 0x64, + 0x4c, 0x69, 0x6e, 0x65, 0x12, 0x26, 0x0a, 0x04, 0x63, 0x6f, 0x64, 0x65, 0x18, 0x07, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x74, 0x72, 0x69, 0x76, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, + 0x6e, 0x2e, 0x43, 0x6f, 0x64, 0x65, 0x52, 0x04, 0x63, 0x6f, 0x64, 0x65, 0x12, 0x14, 0x0a, 0x05, + 0x6d, 0x61, 0x74, 0x63, 0x68, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x6d, 0x61, 0x74, + 0x63, 0x68, 0x12, 0x29, 0x0a, 0x05, 0x6c, 0x61, 0x79, 0x65, 0x72, 0x18, 0x0a, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x13, 0x2e, 0x74, 0x72, 0x69, 0x76, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, + 0x2e, 0x4c, 0x61, 0x79, 0x65, 0x72, 0x52, 0x05, 0x6c, 0x61, 0x79, 0x65, 0x72, 0x4a, 0x04, 0x08, + 0x09, 0x10, 0x0a, 0x22, 0x5d, 0x0a, 0x06, 0x53, 0x65, 0x63, 0x72, 0x65, 0x74, 0x12, 0x1a, 0x0a, + 0x08, 0x66, 0x69, 0x6c, 0x65, 0x70, 0x61, 0x74, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x08, 0x66, 0x69, 0x6c, 0x65, 0x70, 0x61, 0x74, 0x68, 0x12, 0x37, 0x0a, 0x08, 0x66, 0x69, 0x6e, + 0x64, 0x69, 0x6e, 0x67, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x74, 0x72, + 0x69, 0x76, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x53, 0x65, 0x63, 0x72, 0x65, + 0x74, 0x46, 0x69, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x52, 0x08, 0x66, 0x69, 0x6e, 0x64, 0x69, 0x6e, + 0x67, 0x73, 0x22, 0x85, 0x02, 0x0a, 0x0f, 0x44, 0x65, 0x74, 0x65, 0x63, 0x74, 0x65, 0x64, 0x4c, + 0x69, 0x63, 0x65, 0x6e, 0x73, 0x65, 0x12, 0x32, 0x0a, 0x08, 0x73, 0x65, 0x76, 0x65, 0x72, 0x69, + 0x74, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x16, 0x2e, 0x74, 0x72, 0x69, 0x76, 0x79, + 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x53, 0x65, 0x76, 0x65, 0x72, 0x69, 0x74, 0x79, + 0x52, 0x08, 0x73, 0x65, 0x76, 0x65, 0x72, 0x69, 0x74, 0x79, 0x12, 0x3e, 0x0a, 0x08, 0x63, 0x61, + 0x74, 0x65, 0x67, 0x6f, 0x72, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x22, 0x2e, 0x74, + 0x72, 0x69, 0x76, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x4c, 0x69, 0x63, 0x65, + 0x6e, 0x73, 0x65, 0x43, 0x61, 0x74, 0x65, 0x67, 0x6f, 0x72, 0x79, 0x2e, 0x45, 0x6e, 0x75, 0x6d, + 0x52, 0x08, 0x63, 0x61, 0x74, 0x65, 0x67, 0x6f, 0x72, 0x79, 0x12, 0x19, 0x0a, 0x08, 0x70, 0x6b, + 0x67, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x70, 0x6b, + 0x67, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x1b, 0x0a, 0x09, 0x66, 0x69, 0x6c, 0x65, 0x5f, 0x70, 0x61, + 0x74, 0x68, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x66, 0x69, 0x6c, 0x65, 0x50, 0x61, + 0x74, 0x68, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x1e, 0x0a, 0x0a, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x64, + 0x65, 0x6e, 0x63, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x02, 0x52, 0x0a, 0x63, 0x6f, 0x6e, 0x66, + 0x69, 0x64, 0x65, 0x6e, 0x63, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x6c, 0x69, 0x6e, 0x6b, 0x18, 0x07, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6c, 0x69, 0x6e, 0x6b, 0x22, 0xed, 0x01, 0x0a, 0x0b, 0x4c, + 0x69, 0x63, 0x65, 0x6e, 0x73, 0x65, 0x46, 0x69, 0x6c, 0x65, 0x12, 0x41, 0x0a, 0x0c, 0x6c, 0x69, + 0x63, 0x65, 0x6e, 0x73, 0x65, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, + 0x32, 0x1e, 0x2e, 0x74, 0x72, 0x69, 0x76, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, + 0x4c, 0x69, 0x63, 0x65, 0x6e, 0x73, 0x65, 0x54, 0x79, 0x70, 0x65, 0x2e, 0x45, 0x6e, 0x75, 0x6d, + 0x52, 0x0b, 0x6c, 0x69, 0x63, 0x65, 0x6e, 0x73, 0x65, 0x54, 0x79, 0x70, 0x65, 0x12, 0x1b, 0x0a, + 0x09, 0x66, 0x69, 0x6c, 0x65, 0x5f, 0x70, 0x61, 0x74, 0x68, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x08, 0x66, 0x69, 0x6c, 0x65, 0x50, 0x61, 0x74, 0x68, 0x12, 0x19, 0x0a, 0x08, 0x70, 0x6b, + 0x67, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x70, 0x6b, + 0x67, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x38, 0x0a, 0x08, 0x66, 0x69, 0x6e, 0x67, 0x69, 0x6e, 0x67, + 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x74, 0x72, 0x69, 0x76, 0x79, 0x2e, + 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x4c, 0x69, 0x63, 0x65, 0x6e, 0x73, 0x65, 0x46, 0x69, + 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x52, 0x08, 0x66, 0x69, 0x6e, 0x67, 0x69, 0x6e, 0x67, 0x73, 0x12, + 0x29, 0x0a, 0x05, 0x6c, 0x61, 0x79, 0x65, 0x72, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x13, + 0x2e, 0x74, 0x72, 0x69, 0x76, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x4c, 0x61, + 0x79, 0x65, 0x72, 0x52, 0x05, 0x6c, 0x61, 0x79, 0x65, 0x72, 0x22, 0x98, 0x01, 0x0a, 0x0e, 0x4c, + 0x69, 0x63, 0x65, 0x6e, 0x73, 0x65, 0x46, 0x69, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x12, 0x3e, 0x0a, + 0x08, 0x63, 0x61, 0x74, 0x65, 0x67, 0x6f, 0x72, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, + 0x22, 0x2e, 0x74, 0x72, 0x69, 0x76, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x4c, + 0x69, 0x63, 0x65, 0x6e, 0x73, 0x65, 0x43, 0x61, 0x74, 0x65, 0x67, 0x6f, 0x72, 0x79, 0x2e, 0x45, + 0x6e, 0x75, 0x6d, 0x52, 0x08, 0x63, 0x61, 0x74, 0x65, 0x67, 0x6f, 0x72, 0x79, 0x12, 0x12, 0x0a, + 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, + 0x65, 0x12, 0x1e, 0x0a, 0x0a, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x64, 0x65, 0x6e, 0x63, 0x65, 0x18, + 0x03, 0x20, 0x01, 0x28, 0x02, 0x52, 0x0a, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x64, 0x65, 0x6e, 0x63, + 0x65, 0x12, 0x12, 0x0a, 0x04, 0x6c, 0x69, 0x6e, 0x6b, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x04, 0x6c, 0x69, 0x6e, 0x6b, 0x22, 0x95, 0x01, 0x0a, 0x0f, 0x4c, 0x69, 0x63, 0x65, 0x6e, 0x73, + 0x65, 0x43, 0x61, 0x74, 0x65, 0x67, 0x6f, 0x72, 0x79, 0x22, 0x81, 0x01, 0x0a, 0x04, 0x45, 0x6e, + 0x75, 0x6d, 0x12, 0x0f, 0x0a, 0x0b, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, + 0x44, 0x10, 0x00, 0x12, 0x0d, 0x0a, 0x09, 0x46, 0x4f, 0x52, 0x42, 0x49, 0x44, 0x44, 0x45, 0x4e, + 0x10, 0x01, 0x12, 0x0e, 0x0a, 0x0a, 0x52, 0x45, 0x53, 0x54, 0x52, 0x49, 0x43, 0x54, 0x45, 0x44, + 0x10, 0x02, 0x12, 0x0e, 0x0a, 0x0a, 0x52, 0x45, 0x43, 0x49, 0x50, 0x52, 0x4f, 0x43, 0x41, 0x4c, + 0x10, 0x03, 0x12, 0x0a, 0x0a, 0x06, 0x4e, 0x4f, 0x54, 0x49, 0x43, 0x45, 0x10, 0x04, 0x12, 0x0e, + 0x0a, 0x0a, 0x50, 0x45, 0x52, 0x4d, 0x49, 0x53, 0x53, 0x49, 0x56, 0x45, 0x10, 0x05, 0x12, 0x10, + 0x0a, 0x0c, 0x55, 0x4e, 0x45, 0x4e, 0x43, 0x55, 0x4d, 0x42, 0x45, 0x52, 0x45, 0x44, 0x10, 0x06, + 0x12, 0x0b, 0x0a, 0x07, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x10, 0x07, 0x22, 0x4e, 0x0a, + 0x0b, 0x4c, 0x69, 0x63, 0x65, 0x6e, 0x73, 0x65, 0x54, 0x79, 0x70, 0x65, 0x22, 0x3f, 0x0a, 0x04, 0x45, 0x6e, 0x75, 0x6d, 0x12, 0x0f, 0x0a, 0x0b, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, - 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x0d, 0x0a, 0x09, 0x46, 0x4f, 0x52, 0x42, 0x49, 0x44, 0x44, - 0x45, 0x4e, 0x10, 0x01, 0x12, 0x0e, 0x0a, 0x0a, 0x52, 0x45, 0x53, 0x54, 0x52, 0x49, 0x43, 0x54, - 0x45, 0x44, 0x10, 0x02, 0x12, 0x0e, 0x0a, 0x0a, 0x52, 0x45, 0x43, 0x49, 0x50, 0x52, 0x4f, 0x43, - 0x41, 0x4c, 0x10, 0x03, 0x12, 0x0a, 0x0a, 0x06, 0x4e, 0x4f, 0x54, 0x49, 0x43, 0x45, 0x10, 0x04, - 0x12, 0x0e, 0x0a, 0x0a, 0x50, 0x45, 0x52, 0x4d, 0x49, 0x53, 0x53, 0x49, 0x56, 0x45, 0x10, 0x05, - 0x12, 0x10, 0x0a, 0x0c, 0x55, 0x4e, 0x45, 0x4e, 0x43, 0x55, 0x4d, 0x42, 0x45, 0x52, 0x45, 0x44, - 0x10, 0x06, 0x12, 0x0b, 0x0a, 0x07, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x10, 0x07, 0x22, - 0x4e, 0x0a, 0x0b, 0x4c, 0x69, 0x63, 0x65, 0x6e, 0x73, 0x65, 0x54, 0x79, 0x70, 0x65, 0x22, 0x3f, - 0x0a, 0x04, 0x45, 0x6e, 0x75, 0x6d, 0x12, 0x0f, 0x0a, 0x0b, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, - 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x08, 0x0a, 0x04, 0x44, 0x50, 0x4b, 0x47, 0x10, - 0x01, 0x12, 0x0a, 0x0a, 0x06, 0x48, 0x45, 0x41, 0x44, 0x45, 0x52, 0x10, 0x02, 0x12, 0x10, 0x0a, - 0x0c, 0x4c, 0x49, 0x43, 0x45, 0x4e, 0x53, 0x45, 0x5f, 0x46, 0x49, 0x4c, 0x45, 0x10, 0x03, 0x2a, - 0x44, 0x0a, 0x08, 0x53, 0x65, 0x76, 0x65, 0x72, 0x69, 0x74, 0x79, 0x12, 0x0b, 0x0a, 0x07, 0x55, - 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x10, 0x00, 0x12, 0x07, 0x0a, 0x03, 0x4c, 0x4f, 0x57, 0x10, - 0x01, 0x12, 0x0a, 0x0a, 0x06, 0x4d, 0x45, 0x44, 0x49, 0x55, 0x4d, 0x10, 0x02, 0x12, 0x08, 0x0a, - 0x04, 0x48, 0x49, 0x47, 0x48, 0x10, 0x03, 0x12, 0x0c, 0x0a, 0x08, 0x43, 0x52, 0x49, 0x54, 0x49, - 0x43, 0x41, 0x4c, 0x10, 0x04, 0x42, 0x31, 0x5a, 0x2f, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, - 0x63, 0x6f, 0x6d, 0x2f, 0x61, 0x71, 0x75, 0x61, 0x73, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, - 0x2f, 0x74, 0x72, 0x69, 0x76, 0x79, 0x2f, 0x72, 0x70, 0x63, 0x2f, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, - 0x6e, 0x3b, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x08, 0x0a, 0x04, 0x44, 0x50, 0x4b, 0x47, 0x10, 0x01, 0x12, + 0x0a, 0x0a, 0x06, 0x48, 0x45, 0x41, 0x44, 0x45, 0x52, 0x10, 0x02, 0x12, 0x10, 0x0a, 0x0c, 0x4c, + 0x49, 0x43, 0x45, 0x4e, 0x53, 0x45, 0x5f, 0x46, 0x49, 0x4c, 0x45, 0x10, 0x03, 0x2a, 0x44, 0x0a, + 0x08, 0x53, 0x65, 0x76, 0x65, 0x72, 0x69, 0x74, 0x79, 0x12, 0x0b, 0x0a, 0x07, 0x55, 0x4e, 0x4b, + 0x4e, 0x4f, 0x57, 0x4e, 0x10, 0x00, 0x12, 0x07, 0x0a, 0x03, 0x4c, 0x4f, 0x57, 0x10, 0x01, 0x12, + 0x0a, 0x0a, 0x06, 0x4d, 0x45, 0x44, 0x49, 0x55, 0x4d, 0x10, 0x02, 0x12, 0x08, 0x0a, 0x04, 0x48, + 0x49, 0x47, 0x48, 0x10, 0x03, 0x12, 0x0c, 0x0a, 0x08, 0x43, 0x52, 0x49, 0x54, 0x49, 0x43, 0x41, + 0x4c, 0x10, 0x04, 0x42, 0x31, 0x5a, 0x2f, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, + 0x6d, 0x2f, 0x61, 0x71, 0x75, 0x61, 0x73, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x2f, 0x74, + 0x72, 0x69, 0x76, 0x79, 0x2f, 0x72, 0x70, 0x63, 0x2f, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x3b, + 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( @@ -2835,7 +2835,7 @@ var file_rpc_common_service_proto_goTypes = []interface{}{ } var file_rpc_common_service_proto_depIdxs = []int32{ 7, // 0: trivy.common.PackageInfo.packages:type_name -> trivy.common.Package - 7, // 1: trivy.common.Application.libraries:type_name -> trivy.common.Package + 7, // 1: trivy.common.Application.packages:type_name -> trivy.common.Package 8, // 2: trivy.common.Package.identifier:type_name -> trivy.common.PkgIdentifier 9, // 3: trivy.common.Package.locations:type_name -> trivy.common.Location 16, // 4: trivy.common.Package.layer:type_name -> trivy.common.Layer diff --git a/rpc/common/service.proto b/rpc/common/service.proto index 8882bbf20e39..91ed89dd534f 100644 --- a/rpc/common/service.proto +++ b/rpc/common/service.proto @@ -27,7 +27,7 @@ message PackageInfo { message Application { string type = 1; string file_path = 2; - repeated Package libraries = 3; + repeated Package packages = 3; } message Package {