From 3b9c55d28b3e16193bb3b4fe6ecaa6920e9f5ad0 Mon Sep 17 00:00:00 2001 From: Piotr Radkowski Date: Mon, 7 Oct 2024 16:26:04 +0200 Subject: [PATCH] Fix: Parse package.json with non-standard fields in 'author' section (#3300) * Improved parsing of package.json 'author' section Signed-off-by: Piotr Radkowski * test: parse 'package.json' files with non-standard fields in author section Signed-off-by: Piotr Radkowski --------- Signed-off-by: Piotr Radkowski Co-authored-by: Piotr Radkowski --- .../javascript/parse_package_json.go | 24 +++++++++---------- .../javascript/parse_package_json_test.go | 21 ++++++++++++++++ .../pkg-json/package-author-non-standard.json | 16 +++++++++++++ 3 files changed, 49 insertions(+), 12 deletions(-) create mode 100644 syft/pkg/cataloger/javascript/test-fixtures/pkg-json/package-author-non-standard.json diff --git a/syft/pkg/cataloger/javascript/parse_package_json.go b/syft/pkg/cataloger/javascript/parse_package_json.go index b1677ae8870..cc628c7724e 100644 --- a/syft/pkg/cataloger/javascript/parse_package_json.go +++ b/syft/pkg/cataloger/javascript/parse_package_json.go @@ -82,23 +82,23 @@ func parsePackageJSON(_ context.Context, _ file.Resolver, _ *generic.Environment func (a *author) UnmarshalJSON(b []byte) error { var authorStr string - var fields map[string]string var auth author - if err := json.Unmarshal(b, &authorStr); err != nil { - // string parsing did not work, assume a map was given - // for more information: https://docs.npmjs.com/files/package.json#people-fields-author-contributors + if err := json.Unmarshal(b, &authorStr); err == nil { + // successfully parsed as a string, now parse that string into fields + fields := internal.MatchNamedCaptureGroups(authorPattern, authorStr) + if err := mapstructure.Decode(fields, &auth); err != nil { + return fmt.Errorf("unable to decode package.json author: %w", err) + } + } else { + // it's a map that may contain fields of various data types (not just strings) + var fields map[string]interface{} if err := json.Unmarshal(b, &fields); err != nil { return fmt.Errorf("unable to parse package.json author: %w", err) } - } else { - // parse out "name (url)" into an author struct - fields = internal.MatchNamedCaptureGroups(authorPattern, authorStr) - } - - // translate the map into a structure - if err := mapstructure.Decode(fields, &auth); err != nil { - return fmt.Errorf("unable to decode package.json author: %w", err) + if err := mapstructure.Decode(fields, &auth); err != nil { + return fmt.Errorf("unable to decode package.json author: %w", err) + } } *a = auth diff --git a/syft/pkg/cataloger/javascript/parse_package_json_test.go b/syft/pkg/cataloger/javascript/parse_package_json_test.go index 5c544580a89..5d6ebaf4a7e 100644 --- a/syft/pkg/cataloger/javascript/parse_package_json_test.go +++ b/syft/pkg/cataloger/javascript/parse_package_json_test.go @@ -179,6 +179,27 @@ func TestParsePackageJSON(t *testing.T) { }, }, }, + { + Fixture: "test-fixtures/pkg-json/package-author-non-standard.json", + ExpectedPkg: pkg.Package{ + Name: "npm", + Version: "6.14.6", + PURL: "pkg:npm/npm@6.14.6", + Type: pkg.NpmPkg, + Licenses: pkg.NewLicenseSet( + pkg.NewLicenseFromLocations("Artistic-2.0", file.NewLocation("test-fixtures/pkg-json/package-author-non-standard.json")), + ), + Language: pkg.JavaScript, + Metadata: pkg.NpmPackage{ + Name: "npm", + Version: "6.14.6", + Author: "npm Inc. (https://www.npmjs.com/)", + Homepage: "https://docs.npmjs.com/", + URL: "https://github.com/npm/cli", + Description: "a package manager for JavaScript", + }, + }, + }, } for _, test := range tests { diff --git a/syft/pkg/cataloger/javascript/test-fixtures/pkg-json/package-author-non-standard.json b/syft/pkg/cataloger/javascript/test-fixtures/pkg-json/package-author-non-standard.json new file mode 100644 index 00000000000..a71cf820a4d --- /dev/null +++ b/syft/pkg/cataloger/javascript/test-fixtures/pkg-json/package-author-non-standard.json @@ -0,0 +1,16 @@ +{ + "version": "6.14.6", + "name": "npm", + "description": "a package manager for JavaScript", + "homepage": "https://docs.npmjs.com/", + "author": { + "name": "npm Inc.", + "url": "https://www.npmjs.com/", + "organization": true + }, + "repository": { + "type": "git", + "url": "https://github.com/npm/cli" + }, + "license": "Artistic-2.0" +} \ No newline at end of file