From c0835e33dc19f456812a009b4cb3f7a4dca13ae1 Mon Sep 17 00:00:00 2001 From: DmitriyLewen Date: Tue, 5 Mar 2024 13:39:34 +0600 Subject: [PATCH 1/3] fix(packagejson): add name validation --- .../parser/nodejs/packagejson/parse.go | 16 +++++ .../parser/nodejs/packagejson/parse_test.go | 58 ++++++++++++++++++- .../packagejson/testdata/invalid_name.json | 11 ++++ 3 files changed, 83 insertions(+), 2 deletions(-) create mode 100644 pkg/dependency/parser/nodejs/packagejson/testdata/invalid_name.json diff --git a/pkg/dependency/parser/nodejs/packagejson/parse.go b/pkg/dependency/parser/nodejs/packagejson/parse.go index a9f4dea07a1a..e34c205cf73f 100644 --- a/pkg/dependency/parser/nodejs/packagejson/parse.go +++ b/pkg/dependency/parser/nodejs/packagejson/parse.go @@ -3,6 +3,7 @@ package packagejson import ( "encoding/json" "io" + "regexp" "golang.org/x/xerrors" @@ -10,6 +11,8 @@ import ( "github.com/aquasecurity/trivy/pkg/dependency/parser/utils" ) +var nameRegexp = regexp.MustCompile(`(?m)^(@[A-Za-z0-9-._]+/)?[A-Za-z0-9-._]+$`) + type packageJSON struct { Name string `json:"name"` Version string `json:"version"` @@ -40,6 +43,10 @@ func (p *Parser) Parse(r io.Reader) (Package, error) { return Package{}, xerrors.Errorf("JSON decode error: %w", err) } + if IsValidName(pkgJSON.Name) { + return Package{}, xerrors.Errorf("Name can only contain URL-friendly characters") + } + var id string // Name and version fields are optional // https://docs.npmjs.com/cli/v9/configuring-npm/package-json#name @@ -73,3 +80,12 @@ func parseLicense(val interface{}) string { } return "" } + +func IsValidName(name string) bool { + // Name is optional field + // https://docs.npmjs.com/cli/v9/configuring-npm/package-json#name + if name == "" { + return true + } + return nameRegexp.MatchString(name) +} diff --git a/pkg/dependency/parser/nodejs/packagejson/parse_test.go b/pkg/dependency/parser/nodejs/packagejson/parse_test.go index c90d37d6440e..9b925a525be3 100644 --- a/pkg/dependency/parser/nodejs/packagejson/parse_test.go +++ b/pkg/dependency/parser/nodejs/packagejson/parse_test.go @@ -2,7 +2,6 @@ package packagejson_test import ( "os" - "path" "testing" "github.com/stretchr/testify/assert" @@ -77,6 +76,11 @@ func TestParse(t *testing.T) { }, }, }, + { + name: "invalid package name", + inputFile: "testdata/invalid_name.json", + wantErr: "Name can only contain URL-friendly characters", + }, { name: "sad path", inputFile: "testdata/invalid_package.json", @@ -99,7 +103,7 @@ func TestParse(t *testing.T) { } for _, v := range vectors { - t.Run(path.Base(v.name), func(t *testing.T) { + t.Run(v.name, func(t *testing.T) { f, err := os.Open(v.inputFile) require.NoError(t, err) defer f.Close() @@ -115,3 +119,53 @@ func TestParse(t *testing.T) { }) } } + +func TestIsValidName(t *testing.T) { + tests := []struct { + name string + want bool + }{ + { + name: "", + want: true, + }, + { + name: "test_package", + want: true, + }, + { + name: "test.package", + want: true, + }, + { + name: "test-package", + want: true, + }, + { + name: "@test/package", + want: true, + }, + { + name: "test@package", + want: false, + }, { + name: "test?package", + want: false, + }, + { + name: "test/package", + want: false, + }, + { + name: "package/", + want: false, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + valid := packagejson.IsValidName(tt.name) + require.Equal(t, tt.want, valid) + }) + } +} diff --git a/pkg/dependency/parser/nodejs/packagejson/testdata/invalid_name.json b/pkg/dependency/parser/nodejs/packagejson/testdata/invalid_name.json new file mode 100644 index 000000000000..f97f91d2c852 --- /dev/null +++ b/pkg/dependency/parser/nodejs/packagejson/testdata/invalid_name.json @@ -0,0 +1,11 @@ +{ + "name": "@invalid/packageName/", + "version": "1.0.0", + "description": "", + "main": "index.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "author": "", + "license": "ISC" +} \ No newline at end of file From 9db40371f53f6f90d40122ff02cc28e4e16efb93 Mon Sep 17 00:00:00 2001 From: DmitriyLewen Date: Tue, 5 Mar 2024 13:49:03 +0600 Subject: [PATCH 2/3] fix mistake --- pkg/dependency/parser/nodejs/packagejson/parse.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/dependency/parser/nodejs/packagejson/parse.go b/pkg/dependency/parser/nodejs/packagejson/parse.go index e34c205cf73f..7bc3438ec996 100644 --- a/pkg/dependency/parser/nodejs/packagejson/parse.go +++ b/pkg/dependency/parser/nodejs/packagejson/parse.go @@ -43,7 +43,7 @@ func (p *Parser) Parse(r io.Reader) (Package, error) { return Package{}, xerrors.Errorf("JSON decode error: %w", err) } - if IsValidName(pkgJSON.Name) { + if !IsValidName(pkgJSON.Name) { return Package{}, xerrors.Errorf("Name can only contain URL-friendly characters") } From 0b78e31dbdceb0c5d614a6f5b9136b81f8d09c42 Mon Sep 17 00:00:00 2001 From: DmitriyLewen Date: Tue, 5 Mar 2024 13:54:00 +0600 Subject: [PATCH 3/3] refactor nameRegexp --- pkg/dependency/parser/nodejs/packagejson/parse.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/dependency/parser/nodejs/packagejson/parse.go b/pkg/dependency/parser/nodejs/packagejson/parse.go index 7bc3438ec996..f2558750c323 100644 --- a/pkg/dependency/parser/nodejs/packagejson/parse.go +++ b/pkg/dependency/parser/nodejs/packagejson/parse.go @@ -11,7 +11,7 @@ import ( "github.com/aquasecurity/trivy/pkg/dependency/parser/utils" ) -var nameRegexp = regexp.MustCompile(`(?m)^(@[A-Za-z0-9-._]+/)?[A-Za-z0-9-._]+$`) +var nameRegexp = regexp.MustCompile(`^(@[A-Za-z0-9-._]+/)?[A-Za-z0-9-._]+$`) type packageJSON struct { Name string `json:"name"`