From ba8112eb824045734700de48e373fd3802f9a053 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafael=20Cort=C3=AAs?= Date: Thu, 26 Oct 2023 10:35:45 +0100 Subject: [PATCH 1/6] feat(gomod): add line locations --- pkg/golang/mod/parse.go | 6 ++ pkg/golang/mod/parse_testcase.go | 114 +++++++++++++++++++++++++++++++ 2 files changed, 120 insertions(+) diff --git a/pkg/golang/mod/parse.go b/pkg/golang/mod/parse.go index 90725fd7..a61aaf3c 100644 --- a/pkg/golang/mod/parse.go +++ b/pkg/golang/mod/parse.go @@ -94,6 +94,12 @@ func (p *Parser) Parse(r dio.ReadSeekerAt) ([]types.Library, []types.Dependency, Version: require.Mod.Version[1:], Indirect: require.Indirect, ExternalReferences: p.GetExternalRefs(require.Mod.Path), + Locations: []types.Location{ + { + StartLine: require.Syntax.Start.Line, + EndLine: require.Syntax.End.Line, + }, + }, } } diff --git a/pkg/golang/mod/parse_testcase.go b/pkg/golang/mod/parse_testcase.go index b7d02f4c..cabf8fbf 100644 --- a/pkg/golang/mod/parse_testcase.go +++ b/pkg/golang/mod/parse_testcase.go @@ -16,12 +16,24 @@ var ( URL: "https://github.com/aquasecurity/go-dep-parser", }, }, + Locations: []types.Location{ + { + StartLine: 5, + EndLine: 5, + }, + }, }, { ID: "golang.org/x/xerrors@v0.0.0-20200804184101-5ec99f83aff1", Name: "golang.org/x/xerrors", Version: "0.0.0-20200804184101-5ec99f83aff1", Indirect: true, + Locations: []types.Location{ + { + StartLine: 8, + EndLine: 8, + }, + }, }, { ID: "gopkg.in/yaml.v3@v3.0.0-20210107192922-496545a6307b", @@ -34,6 +46,12 @@ var ( URL: "https://github.com/go-yaml/yaml", }, }, + Locations: []types.Location{ + { + StartLine: 9, + EndLine: 9, + }, + }, }, } @@ -56,6 +74,12 @@ var ( Name: "golang.org/x/xerrors", Version: "0.0.0-20200804184101-5ec99f83aff1", Indirect: true, + Locations: []types.Location{ + { + StartLine: 7, + EndLine: 7, + }, + }, }, } @@ -72,12 +96,24 @@ var ( URL: "https://github.com/aquasecurity/go-dep-parser", }, }, + Locations: []types.Location{ + { + StartLine: 5, + EndLine: 5, + }, + }, }, { ID: "golang.org/x/xerrors@v0.0.0-20200804184101-5ec99f83aff1", Name: "golang.org/x/xerrors", Version: "0.0.0-20200804184101-5ec99f83aff1", Indirect: true, + Locations: []types.Location{ + { + StartLine: 7, + EndLine: 7, + }, + }, }, } @@ -100,6 +136,12 @@ var ( Name: "golang.org/x/xerrors", Version: "0.0.0-20200804184101-5ec99f83aff1", Indirect: true, + Locations: []types.Location{ + { + StartLine: 7, + EndLine: 7, + }, + }, }, } @@ -116,12 +158,24 @@ var ( URL: "https://github.com/aquasecurity/go-dep-parser", }, }, + Locations: []types.Location{ + { + StartLine: 5, + EndLine: 5, + }, + }, }, { ID: "golang.org/x/xerrors@v0.0.0-20200804184101-5ec99f83aff1", Name: "golang.org/x/xerrors", Version: "0.0.0-20200804184101-5ec99f83aff1", Indirect: true, + Locations: []types.Location{ + { + StartLine: 8, + EndLine: 8, + }, + }, }, { ID: "gopkg.in/yaml.v3@v3.0.0-20210107192922-496545a6307b", @@ -134,6 +188,12 @@ var ( URL: "https://github.com/go-yaml/yaml", }, }, + Locations: []types.Location{ + { + StartLine: 9, + EndLine: 9, + }, + }, }, } @@ -150,6 +210,12 @@ var ( URL: "https://github.com/aquasecurity/go-dep-parser", }, }, + Locations: []types.Location{ + { + StartLine: 5, + EndLine: 5, + }, + }, }, { ID: "gopkg.in/yaml.v3@v3.0.0-20210107192922-496545a6307b", @@ -162,6 +228,12 @@ var ( URL: "https://github.com/go-yaml/yaml", }, }, + Locations: []types.Location{ + { + StartLine: 9, + EndLine: 9, + }, + }, }, } @@ -178,6 +250,12 @@ var ( URL: "https://github.com/aquasecurity/go-dep-parser", }, }, + Locations: []types.Location{ + { + StartLine: 5, + EndLine: 5, + }, + }, }, { ID: "gopkg.in/yaml.v3@v3.0.0-20210107192922-496545a6307b", @@ -190,6 +268,12 @@ var ( URL: "https://github.com/go-yaml/yaml", }, }, + Locations: []types.Location{ + { + StartLine: 9, + EndLine: 9, + }, + }, }, } @@ -206,12 +290,24 @@ var ( URL: "https://github.com/aquasecurity/go-dep-parser", }, }, + Locations: []types.Location{ + { + StartLine: 5, + EndLine: 5, + }, + }, }, { ID: "golang.org/x/xerrors@v0.0.0-20200804184101-5ec99f83aff1", Name: "golang.org/x/xerrors", Version: "0.0.0-20200804184101-5ec99f83aff1", Indirect: true, + Locations: []types.Location{ + { + StartLine: 8, + EndLine: 8, + }, + }, }, { ID: "gopkg.in/yaml.v3@v3.0.0-20210107192922-496545a6307b", @@ -224,6 +320,12 @@ var ( URL: "https://github.com/go-yaml/yaml", }, }, + Locations: []types.Location{ + { + StartLine: 9, + EndLine: 9, + }, + }, }, } @@ -240,6 +342,12 @@ var ( URL: "https://github.com/aquasecurity/go-dep-parser", }, }, + Locations: []types.Location{ + { + StartLine: 5, + EndLine: 5, + }, + }, }, } @@ -256,6 +364,12 @@ var ( URL: "https://github.com/aquasecurity/go-dep-parser", }, }, + Locations: []types.Location{ + { + StartLine: 3, + EndLine: 3, + }, + }, }, } ) From bc1d6c06fa9755ebf3952828a56bd719c9cedfe5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafael=20Cort=C3=AAs?= Date: Sun, 19 Nov 2023 08:38:12 +0000 Subject: [PATCH 2/6] feat(pip): add line locations --- pkg/python/pip/parse.go | 12 +++++--- pkg/python/pip/parse_testcase.go | 48 ++++++++++++++++---------------- 2 files changed, 32 insertions(+), 28 deletions(-) diff --git a/pkg/python/pip/parse.go b/pkg/python/pip/parse.go index 4907e7cf..7ac76c2e 100644 --- a/pkg/python/pip/parse.go +++ b/pkg/python/pip/parse.go @@ -2,14 +2,15 @@ package pip import ( "bufio" + "strings" + "unicode" + dio "github.com/aquasecurity/go-dep-parser/pkg/io" "github.com/aquasecurity/go-dep-parser/pkg/types" "golang.org/x/text/encoding" u "golang.org/x/text/encoding/unicode" "golang.org/x/text/transform" "golang.org/x/xerrors" - "strings" - "unicode" ) const ( @@ -35,7 +36,9 @@ func (p *Parser) Parse(r dio.ReadSeekerAt) ([]types.Library, []types.Dependency, scanner := bufio.NewScanner(decodedReader) var libs []types.Library + var lineNumber int // It is used to save dependency location for scanner.Scan() { + lineNumber++ line := scanner.Text() line = strings.ReplaceAll(line, " ", "") line = strings.ReplaceAll(line, `\`, "") @@ -48,8 +51,9 @@ func (p *Parser) Parse(r dio.ReadSeekerAt) ([]types.Library, []types.Dependency, continue } libs = append(libs, types.Library{ - Name: s[0], - Version: s[1], + Name: s[0], + Version: s[1], + Locations: []types.Location{{StartLine: lineNumber, EndLine: lineNumber}}, }) } if err := scanner.Err(); err != nil { diff --git a/pkg/python/pip/parse_testcase.go b/pkg/python/pip/parse_testcase.go index 63f8c2f3..6090c53c 100644 --- a/pkg/python/pip/parse_testcase.go +++ b/pkg/python/pip/parse_testcase.go @@ -4,53 +4,53 @@ import "github.com/aquasecurity/go-dep-parser/pkg/types" var ( requirementsFlask = []types.Library{ - {Name: "click", Version: "8.0.0"}, - {Name: "Flask", Version: "2.0.0"}, - {Name: "itsdangerous", Version: "2.0.0"}, - {Name: "Jinja2", Version: "3.0.0"}, - {Name: "MarkupSafe", Version: "2.0.0"}, - {Name: "Werkzeug", Version: "2.0.0"}, + {Name: "click", Version: "8.0.0", Locations: []types.Location{{StartLine: 1, EndLine: 1}}}, + {Name: "Flask", Version: "2.0.0", Locations: []types.Location{{StartLine: 2, EndLine: 2}}}, + {Name: "itsdangerous", Version: "2.0.0", Locations: []types.Location{{StartLine: 3, EndLine: 3}}}, + {Name: "Jinja2", Version: "3.0.0", Locations: []types.Location{{StartLine: 4, EndLine: 4}}}, + {Name: "MarkupSafe", Version: "2.0.0", Locations: []types.Location{{StartLine: 5, EndLine: 5}}}, + {Name: "Werkzeug", Version: "2.0.0", Locations: []types.Location{{StartLine: 6, EndLine: 6}}}, } requirementsComments = []types.Library{ - {Name: "click", Version: "8.0.0"}, - {Name: "Flask", Version: "2.0.0"}, - {Name: "Jinja2", Version: "3.0.0"}, - {Name: "MarkupSafe", Version: "2.0.0"}, + {Name: "click", Version: "8.0.0", Locations: []types.Location{{StartLine: 4, EndLine: 4}}}, + {Name: "Flask", Version: "2.0.0", Locations: []types.Location{{StartLine: 5, EndLine: 5}}}, + {Name: "Jinja2", Version: "3.0.0", Locations: []types.Location{{StartLine: 6, EndLine: 6}}}, + {Name: "MarkupSafe", Version: "2.0.0", Locations: []types.Location{{StartLine: 7, EndLine: 7}}}, } requirementsSpaces = []types.Library{ - {Name: "click", Version: "8.0.0"}, - {Name: "Flask", Version: "2.0.0"}, - {Name: "itsdangerous", Version: "2.0.0"}, - {Name: "Jinja2", Version: "3.0.0"}, + {Name: "click", Version: "8.0.0", Locations: []types.Location{{StartLine: 1, EndLine: 1}}}, + {Name: "Flask", Version: "2.0.0", Locations: []types.Location{{StartLine: 2, EndLine: 2}}}, + {Name: "itsdangerous", Version: "2.0.0", Locations: []types.Location{{StartLine: 3, EndLine: 3}}}, + {Name: "Jinja2", Version: "3.0.0", Locations: []types.Location{{StartLine: 5, EndLine: 5}}}, } requirementsNoVersion = []types.Library{ - {Name: "Flask", Version: "2.0.0"}, + {Name: "Flask", Version: "2.0.0", Locations: []types.Location{{StartLine: 1, EndLine: 1}}}, } requirementsOperator = []types.Library{ - {Name: "Django", Version: "2.3.4"}, - {Name: "SomeProject", Version: "5.4"}, + {Name: "Django", Version: "2.3.4", Locations: []types.Location{{StartLine: 4, EndLine: 4}}}, + {Name: "SomeProject", Version: "5.4", Locations: []types.Location{{StartLine: 5, EndLine: 5}}}, } requirementsHash = []types.Library{ - {Name: "FooProject", Version: "1.2"}, - {Name: "Jinja2", Version: "3.0.0"}, + {Name: "FooProject", Version: "1.2", Locations: []types.Location{{StartLine: 1, EndLine: 1}}}, + {Name: "Jinja2", Version: "3.0.0", Locations: []types.Location{{StartLine: 4, EndLine: 4}}}, } requirementsHyphens = []types.Library{ - {Name: "oauth2-client", Version: "4.0.0"}, - {Name: "python-gitlab", Version: "2.0.0"}, + {Name: "oauth2-client", Version: "4.0.0", Locations: []types.Location{{StartLine: 1, EndLine: 1}}}, + {Name: "python-gitlab", Version: "2.0.0", Locations: []types.Location{{StartLine: 2, EndLine: 2}}}, } requirementsExtras = []types.Library{ - {Name: "pyjwt", Version: "2.1.0"}, - {Name: "celery", Version: "4.4.7"}, + {Name: "pyjwt", Version: "2.1.0", Locations: []types.Location{{StartLine: 1, EndLine: 1}}}, + {Name: "celery", Version: "4.4.7", Locations: []types.Location{{StartLine: 2, EndLine: 2}}}, } requirementsUtf16le = []types.Library{ - {Name: "attrs", Version: "20.3.0"}, + {Name: "attrs", Version: "20.3.0", Locations: []types.Location{{StartLine: 1, EndLine: 1}}}, } ) From b717cae54a8cdc4101bd546631f4218f22adcf90 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafael=20Cort=C3=AAs?= Date: Sun, 19 Nov 2023 08:55:30 +0000 Subject: [PATCH 3/6] feat(dart): add line locations --- pkg/dart/pub/parse.go | 28 +++++++++++++++++++++++----- pkg/dart/pub/parse_test.go | 23 +++++++++++++---------- 2 files changed, 36 insertions(+), 15 deletions(-) diff --git a/pkg/dart/pub/parse.go b/pkg/dart/pub/parse.go index 78838d26..08590873 100644 --- a/pkg/dart/pub/parse.go +++ b/pkg/dart/pub/parse.go @@ -2,6 +2,7 @@ package pub import ( "fmt" + "golang.org/x/xerrors" "gopkg.in/yaml.v3" @@ -22,7 +23,12 @@ func NewParser() types.Parser { } type lock struct { - Packages map[string]Dep `yaml:"packages"` + Packages map[string]DepWithMetadata `yaml:"packages"` +} + +type DepWithMetadata struct { + Dep Dep + Line int } type Dep struct { @@ -43,10 +49,11 @@ func (Parser) Parse(r dio.ReadSeekerAt) ([]types.Library, []types.Dependency, er // 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{ - ID: pkgID(name, dep.Version), - Name: name, - Version: dep.Version, - Indirect: dep.Dependency == transitiveDep, + ID: pkgID(name, dep.Dep.Version), + Name: name, + Version: dep.Dep.Version, + Indirect: dep.Dep.Dependency == transitiveDep, + Locations: []types.Location{{StartLine: dep.Line, EndLine: dep.Line}}, } libs = append(libs, lib) } @@ -57,3 +64,14 @@ func (Parser) Parse(r dio.ReadSeekerAt) ([]types.Library, []types.Dependency, er func pkgID(name, version string) string { return fmt.Sprintf(idFormat, name, version) } + +func (dep *DepWithMetadata) UnmarshalYAML(value *yaml.Node) error { + err := value.Decode(&dep.Dep) + if err != nil { + return err + } + + dep.Line = value.Line - 1 + + return nil +} diff --git a/pkg/dart/pub/parse_test.go b/pkg/dart/pub/parse_test.go index 5929fcf4..177c05f3 100644 --- a/pkg/dart/pub/parse_test.go +++ b/pkg/dart/pub/parse_test.go @@ -25,20 +25,23 @@ func TestParser_Parse(t *testing.T) { inputFile: "testdata/happy.lock", want: []types.Library{ { - ID: "crypto@3.0.2", - Name: "crypto", - Version: "3.0.2", + ID: "crypto@3.0.2", + Name: "crypto", + Version: "3.0.2", + Locations: []types.Location{{StartLine: 4, EndLine: 4}}, }, { - ID: "flutter_test@0.0.0", - Name: "flutter_test", - Version: "0.0.0", + ID: "flutter_test@0.0.0", + Name: "flutter_test", + Version: "0.0.0", + Locations: []types.Location{{StartLine: 11, EndLine: 11}}, }, { - ID: "uuid@3.0.6", - Name: "uuid", - Version: "3.0.6", - Indirect: true, + ID: "uuid@3.0.6", + Name: "uuid", + Version: "3.0.6", + Indirect: true, + Locations: []types.Location{{StartLine: 16, EndLine: 16}}, }, }, wantErr: assert.NoError, From 802b36a65d227efd1d12f543e95efb9b803a8512 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafael=20Cort=C3=AAs?= Date: Sun, 19 Nov 2023 08:58:10 +0000 Subject: [PATCH 4/6] feat(wordpress): add line locations --- pkg/frameworks/wordpress/parse.go | 7 +++++-- pkg/frameworks/wordpress/parse_test.go | 5 +++-- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/pkg/frameworks/wordpress/parse.go b/pkg/frameworks/wordpress/parse.go index 3d32f2fc..ab54a071 100644 --- a/pkg/frameworks/wordpress/parse.go +++ b/pkg/frameworks/wordpress/parse.go @@ -19,7 +19,9 @@ func Parse(r io.Reader) (lib types.Library, err error) { var version string isComment := false scanner := bufio.NewScanner(r) + var lineNumber int // It is used to save dependency location for scanner.Scan() { + lineNumber++ line := scanner.Text() // Remove comment @@ -72,7 +74,8 @@ func Parse(r io.Reader) (lib types.Library, err error) { } return types.Library{ - Name: "wordpress", - Version: version, + Name: "wordpress", + Version: version, + Locations: []types.Location{{StartLine: lineNumber, EndLine: lineNumber}}, }, nil } diff --git a/pkg/frameworks/wordpress/parse_test.go b/pkg/frameworks/wordpress/parse_test.go index 6faf8120..aefbf5ef 100644 --- a/pkg/frameworks/wordpress/parse_test.go +++ b/pkg/frameworks/wordpress/parse_test.go @@ -20,8 +20,9 @@ func TestParseWordPress(t *testing.T) { { file: "testdata/version.php", want: types.Library{ - Name: "wordpress", - Version: "4.9.4-alpha", + Name: "wordpress", + Version: "4.9.4-alpha", + Locations: []types.Location{{StartLine: 22, EndLine: 22}}, }, }, { From 847eb60fb5730beb14a3b40c6c0e8aa9102e3696 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafael=20Cort=C3=AAs?= Date: Sun, 19 Nov 2023 09:07:45 +0000 Subject: [PATCH 5/6] feat(sum): add line locations --- pkg/golang/sum/parse.go | 21 ++++++++++++++++----- pkg/golang/sum/parse_test.go | 3 ++- 2 files changed, 18 insertions(+), 6 deletions(-) diff --git a/pkg/golang/sum/parse.go b/pkg/golang/sum/parse.go index 544f59e4..2f52dca2 100644 --- a/pkg/golang/sum/parse.go +++ b/pkg/golang/sum/parse.go @@ -17,13 +17,20 @@ func NewParser() types.Parser { return &Parser{} } +type VersionWithMetadata struct { + Version string + LineNumber int +} + // Parse parses a go.sum file func (p *Parser) Parse(r dio.ReadSeekerAt) ([]types.Library, []types.Dependency, error) { var libs []types.Library - uniqueLibs := make(map[string]string) + uniqueLibs := make(map[string]VersionWithMetadata) scanner := bufio.NewScanner(r) + var lineNumber int // It is used to save dependency location for scanner.Scan() { + lineNumber++ line := strings.TrimSpace(scanner.Text()) s := strings.Fields(line) if len(s) < 2 { @@ -32,7 +39,10 @@ func (p *Parser) Parse(r dio.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") + uniqueLibs[s[0]] = VersionWithMetadata{ + Version: strings.TrimSuffix(strings.TrimPrefix(s[1], "v"), "/go.mod"), + LineNumber: lineNumber, + } } if err := scanner.Err(); err != nil { return nil, nil, xerrors.Errorf("scan error: %w", err) @@ -40,9 +50,10 @@ func (p *Parser) Parse(r dio.ReadSeekerAt) ([]types.Library, []types.Dependency, for k, v := range uniqueLibs { libs = append(libs, types.Library{ - ID: mod.ModuleID(k, v), - Name: k, - Version: v, + ID: mod.ModuleID(k, v.Version), + Name: k, + Version: v.Version, + Locations: []types.Location{{StartLine: v.LineNumber, EndLine: v.LineNumber}}, }) } diff --git a/pkg/golang/sum/parse_test.go b/pkg/golang/sum/parse_test.go index 425a78e3..44a18f8e 100644 --- a/pkg/golang/sum/parse_test.go +++ b/pkg/golang/sum/parse_test.go @@ -45,7 +45,8 @@ func TestParse(t *testing.T) { require.NoError(t, err) for i := range got { - got[i].ID = "" // Not compare IDs, tested in mod.TestModuleID() + got[i].ID = "" // Not compare IDs, tested in mod.TestModuleID() + got[i].Locations = nil // Not compare Locations } sort.Slice(got, func(i, j int) bool { From 11b39bc24bb461366691bd1e1464adf494487b48 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafael=20Cort=C3=AAs?= Date: Sun, 19 Nov 2023 09:09:56 +0000 Subject: [PATCH 6/6] feat(gradle/lockfile): add line locations --- pkg/gradle/lockfile/parse.go | 7 +++++-- pkg/gradle/lockfile/parse_test.go | 15 +++++++++------ 2 files changed, 14 insertions(+), 8 deletions(-) diff --git a/pkg/gradle/lockfile/parse.go b/pkg/gradle/lockfile/parse.go index 9d535960..548923a6 100644 --- a/pkg/gradle/lockfile/parse.go +++ b/pkg/gradle/lockfile/parse.go @@ -18,7 +18,9 @@ func NewParser() types.Parser { func (Parser) Parse(r dio.ReadSeekerAt) ([]types.Library, []types.Dependency, error) { var libs []types.Library scanner := bufio.NewScanner(r) + var lineNumber int // It is used to save dependency location for scanner.Scan() { + lineNumber++ line := strings.TrimSpace(scanner.Text()) if strings.HasPrefix(line, "#") { // skip comments continue @@ -30,8 +32,9 @@ func (Parser) Parse(r dio.ReadSeekerAt) ([]types.Library, []types.Dependency, er continue } libs = append(libs, types.Library{ - Name: strings.Join(dep[:2], ":"), - Version: strings.Split(dep[2], "=")[0], // remove classPaths + Name: strings.Join(dep[:2], ":"), + Version: strings.Split(dep[2], "=")[0], // remove classPaths + Locations: []types.Location{{StartLine: lineNumber, EndLine: lineNumber}}, }) } diff --git a/pkg/gradle/lockfile/parse_test.go b/pkg/gradle/lockfile/parse_test.go index 8528c7a5..f354cca8 100644 --- a/pkg/gradle/lockfile/parse_test.go +++ b/pkg/gradle/lockfile/parse_test.go @@ -21,16 +21,19 @@ func TestParser_Parse(t *testing.T) { inputFile: "testdata/happy.lockfile", want: []types.Library{ { - Name: "cglib:cglib-nodep", - Version: "2.1.2", + Name: "cglib:cglib-nodep", + Version: "2.1.2", + Locations: []types.Location{{StartLine: 4, EndLine: 4}}, }, { - Name: "org.springframework:spring-asm", - Version: "3.1.3.RELEASE", + Name: "org.springframework:spring-asm", + Version: "3.1.3.RELEASE", + Locations: []types.Location{{StartLine: 5, EndLine: 5}}, }, { - Name: "org.springframework:spring-beans", - Version: "5.0.5.RELEASE", + Name: "org.springframework:spring-beans", + Version: "5.0.5.RELEASE", + Locations: []types.Location{{StartLine: 6, EndLine: 6}}, }, }, },