Skip to content

Commit

Permalink
fix(nodejs): add support for parsing workspaces from package.json
Browse files Browse the repository at this point in the history
… as an object (aquasecurity#6231)

Co-authored-by: Teppei Fukuda <knqyf263@gmail.com>
  • Loading branch information
DmitriyLewen and knqyf263 authored Mar 27, 2024
1 parent 9d7f5c9 commit f85c9fa
Show file tree
Hide file tree
Showing 3 changed files with 48 additions and 2 deletions.
28 changes: 26 additions & 2 deletions pkg/dependency/parser/nodejs/packagejson/parse.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"io"
"regexp"

"github.com/samber/lo"
"golang.org/x/xerrors"

"github.com/aquasecurity/trivy/pkg/dependency"
Expand All @@ -21,7 +22,7 @@ type packageJSON struct {
Dependencies map[string]string `json:"dependencies"`
OptionalDependencies map[string]string `json:"optionalDependencies"`
DevDependencies map[string]string `json:"devDependencies"`
Workspaces []string `json:"workspaces"`
Workspaces any `json:"workspaces"`
}

type Package struct {
Expand Down Expand Up @@ -65,7 +66,7 @@ func (p *Parser) Parse(r io.Reader) (Package, error) {
Dependencies: pkgJSON.Dependencies,
OptionalDependencies: pkgJSON.OptionalDependencies,
DevDependencies: pkgJSON.DevDependencies,
Workspaces: pkgJSON.Workspaces,
Workspaces: parseWorkspaces(pkgJSON.Workspaces),
}, nil
}

Expand All @@ -82,6 +83,29 @@ func parseLicense(val interface{}) string {
return ""
}

// parseWorkspaces returns slice of workspaces
func parseWorkspaces(val any) []string {
// Workspaces support 2 types - https://github.com/SchemaStore/schemastore/blob/d9516961f8a5b0e65a457808070147b5a866f60b/src/schemas/json/package.json#L777
switch ws := val.(type) {
// Workspace as object (map[string][]string)
// e.g. "workspaces": {"packages": ["packages/*", "plugins/*"]},
case map[string]interface{}:
// Take only workspaces for `packages` - https://classic.yarnpkg.com/blog/2018/02/15/nohoist/
if pkgsWorkspaces, ok := ws["packages"]; ok {
return lo.Map(pkgsWorkspaces.([]interface{}), func(workspace interface{}, _ int) string {
return workspace.(string)
})
}
// Workspace as string array
// e.g. "workspaces": ["packages/*", "backend"],
case []interface{}:
return lo.Map(ws, func(workspace interface{}, _ int) string {
return workspace.(string)
})
}
return nil
}

func IsValidName(name string) bool {
// Name is optional field
// https://docs.npmjs.com/cli/v9/configuring-npm/package-json#name
Expand Down
14 changes: 14 additions & 0 deletions pkg/dependency/parser/nodejs/packagejson/parse_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,20 @@ func TestParse(t *testing.T) {
},
},
},
{
name: "happy path - workspace as struct",
inputFile: "testdata/workspace_as_map_package.json",
want: packagejson.Package{
Library: types.Library{
ID: "example@1.0.0",
Name: "example",
Version: "1.0.0",
},
Workspaces: []string{
"packages/*",
},
},
},
{
name: "invalid package name",
inputFile: "testdata/invalid_name.json",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"name": "example",
"version": "1.0.0",
"workspaces": {
"packages": ["packages/*"],
"nohoist": ["**/react-native", "**/react-native/**"]
}
}

0 comments on commit f85c9fa

Please sign in to comment.