mirror of
https://github.com/anchore/syft.git
synced 2026-05-20 12:15:27 +02:00
fix(javascript): accept scalar people fields in package.json (#4779)
Signed-off-by: Yoav Alon <yoav@orca.security>
This commit is contained in:
parent
952469f0f0
commit
30fe53e629
@ -215,48 +215,25 @@ func pathContainsNodeModulesDirectory(p string) bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (p *people) UnmarshalJSON(b []byte) error {
|
func (p *people) UnmarshalJSON(b []byte) error {
|
||||||
// Try to unmarshal as an array of strings
|
// Accept either a JSON array of authors, or a single author as a string or
|
||||||
var authorStrings []string
|
// object — the latter is used in the wild (e.g. ghost@5.98.1) and dropping
|
||||||
if err := json.Unmarshal(b, &authorStrings); err == nil {
|
// the whole package.json on those was https://github.com/anchore/syft/issues/4778.
|
||||||
// Successfully parsed as an array of strings
|
var elements []json.RawMessage
|
||||||
auths := make([]person, len(authorStrings))
|
if err := json.Unmarshal(b, &elements); err != nil {
|
||||||
for i, authorStr := range authorStrings {
|
// not an array — treat the whole payload as a single element
|
||||||
// Parse each string into author fields
|
elements = []json.RawMessage{b}
|
||||||
fields := internal.MatchNamedCaptureGroups(authorPattern, authorStr)
|
|
||||||
var auth person
|
|
||||||
if err := mapstructure.Decode(fields, &auth); err != nil {
|
|
||||||
return fmt.Errorf("unable to decode package.json author: %w", err)
|
|
||||||
}
|
}
|
||||||
// Trim whitespace from name if it was parsed
|
|
||||||
if auth.Name != "" {
|
auths := make([]person, len(elements))
|
||||||
auth.Name = strings.TrimSpace(auth.Name)
|
for i, e := range elements {
|
||||||
|
if err := json.Unmarshal(e, &auths[i]); err != nil {
|
||||||
|
return fmt.Errorf("unable to parse package.json author: %w", err)
|
||||||
}
|
}
|
||||||
auths[i] = auth
|
|
||||||
}
|
}
|
||||||
*p = auths
|
*p = auths
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Try to unmarshal as an array of objects
|
|
||||||
var authorObjs []map[string]any
|
|
||||||
if err := json.Unmarshal(b, &authorObjs); err == nil {
|
|
||||||
// Successfully parsed as an array of objects
|
|
||||||
auths := make([]person, len(authorObjs))
|
|
||||||
for i, fields := range authorObjs {
|
|
||||||
var auth person
|
|
||||||
if err := mapstructure.Decode(fields, &auth); err != nil {
|
|
||||||
return fmt.Errorf("unable to decode package.json author object: %w", err)
|
|
||||||
}
|
|
||||||
auths[i] = auth
|
|
||||||
}
|
|
||||||
*p = auths
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// If we get here, it means neither format matched
|
|
||||||
return fmt.Errorf("unable to parse package.json authors field: expected array of strings or array of objects")
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p people) String() string {
|
func (p people) String() string {
|
||||||
if len(p) == 0 {
|
if len(p) == 0 {
|
||||||
return ""
|
return ""
|
||||||
|
|||||||
@ -307,6 +307,71 @@ func TestParsePackageJSON(t *testing.T) {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
// see https://github.com/anchore/syft/issues/4778
|
||||||
|
// Ghost CMS publishes package.json with contributors as a single string
|
||||||
|
Fixture: "testdata/pkg-json/package-contributors-string.json",
|
||||||
|
ExpectedPkg: pkg.Package{
|
||||||
|
Name: "ghost",
|
||||||
|
Version: "5.98.1",
|
||||||
|
PURL: "pkg:npm/ghost@5.98.1",
|
||||||
|
Type: pkg.NpmPkg,
|
||||||
|
Licenses: pkg.NewLicenseSet(
|
||||||
|
pkg.NewLicenseFromLocationsWithContext(ctx, "Artistic-2.0", file.NewLocation("testdata/pkg-json/package-contributors-string.json")),
|
||||||
|
),
|
||||||
|
Language: pkg.JavaScript,
|
||||||
|
Metadata: pkg.NpmPackage{
|
||||||
|
Name: "ghost",
|
||||||
|
Version: "5.98.1",
|
||||||
|
Author: "https://github.com/TryGhost/Ghost/graphs/contributors",
|
||||||
|
Homepage: "https://docs.npmjs.com/",
|
||||||
|
URL: "https://github.com/npm/cli",
|
||||||
|
Description: "a package manager for JavaScript",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Fixture: "testdata/pkg-json/package-authors-string.json",
|
||||||
|
ExpectedPkg: pkg.Package{
|
||||||
|
Name: "npm",
|
||||||
|
Version: "6.14.6",
|
||||||
|
PURL: "pkg:npm/npm@6.14.6",
|
||||||
|
Type: pkg.NpmPkg,
|
||||||
|
Licenses: pkg.NewLicenseSet(
|
||||||
|
pkg.NewLicenseFromLocationsWithContext(ctx, "Artistic-2.0", file.NewLocation("testdata/pkg-json/package-authors-string.json")),
|
||||||
|
),
|
||||||
|
Language: pkg.JavaScript,
|
||||||
|
Metadata: pkg.NpmPackage{
|
||||||
|
Name: "npm",
|
||||||
|
Version: "6.14.6",
|
||||||
|
Author: "Harry Potter <hp@hogwards.com> (http://youknowwho.com/)",
|
||||||
|
Homepage: "https://docs.npmjs.com/",
|
||||||
|
URL: "https://github.com/npm/cli",
|
||||||
|
Description: "a package manager for JavaScript",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Fixture: "testdata/pkg-json/package-maintainers-object.json",
|
||||||
|
ExpectedPkg: pkg.Package{
|
||||||
|
Name: "npm",
|
||||||
|
Version: "6.14.6",
|
||||||
|
PURL: "pkg:npm/npm@6.14.6",
|
||||||
|
Type: pkg.NpmPkg,
|
||||||
|
Licenses: pkg.NewLicenseSet(
|
||||||
|
pkg.NewLicenseFromLocationsWithContext(ctx, "Artistic-2.0", file.NewLocation("testdata/pkg-json/package-maintainers-object.json")),
|
||||||
|
),
|
||||||
|
Language: pkg.JavaScript,
|
||||||
|
Metadata: pkg.NpmPackage{
|
||||||
|
Name: "npm",
|
||||||
|
Version: "6.14.6",
|
||||||
|
Author: "Charlie Maintainer <charlie@example.com>",
|
||||||
|
Homepage: "https://docs.npmjs.com/",
|
||||||
|
URL: "https://github.com/npm/cli",
|
||||||
|
Description: "a package manager for JavaScript",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
Fixture: "testdata/pkg-json/package-all-author-fields.json",
|
Fixture: "testdata/pkg-json/package-all-author-fields.json",
|
||||||
ExpectedPkg: pkg.Package{
|
ExpectedPkg: pkg.Package{
|
||||||
|
|||||||
12
syft/pkg/cataloger/javascript/testdata/pkg-json/package-authors-string.json
vendored
Normal file
12
syft/pkg/cataloger/javascript/testdata/pkg-json/package-authors-string.json
vendored
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
{
|
||||||
|
"version": "6.14.6",
|
||||||
|
"name": "npm",
|
||||||
|
"description": "a package manager for JavaScript",
|
||||||
|
"homepage": "https://docs.npmjs.com/",
|
||||||
|
"authors": "Harry Potter <hp@hogwards.com> (http://youknowwho.com/)",
|
||||||
|
"repository": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/npm/cli"
|
||||||
|
},
|
||||||
|
"license": "Artistic-2.0"
|
||||||
|
}
|
||||||
12
syft/pkg/cataloger/javascript/testdata/pkg-json/package-contributors-string.json
vendored
Normal file
12
syft/pkg/cataloger/javascript/testdata/pkg-json/package-contributors-string.json
vendored
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
{
|
||||||
|
"version": "5.98.1",
|
||||||
|
"name": "ghost",
|
||||||
|
"description": "a package manager for JavaScript",
|
||||||
|
"homepage": "https://docs.npmjs.com/",
|
||||||
|
"contributors": "https://github.com/TryGhost/Ghost/graphs/contributors",
|
||||||
|
"repository": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/npm/cli"
|
||||||
|
},
|
||||||
|
"license": "Artistic-2.0"
|
||||||
|
}
|
||||||
15
syft/pkg/cataloger/javascript/testdata/pkg-json/package-maintainers-object.json
vendored
Normal file
15
syft/pkg/cataloger/javascript/testdata/pkg-json/package-maintainers-object.json
vendored
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
{
|
||||||
|
"version": "6.14.6",
|
||||||
|
"name": "npm",
|
||||||
|
"description": "a package manager for JavaScript",
|
||||||
|
"homepage": "https://docs.npmjs.com/",
|
||||||
|
"maintainers": {
|
||||||
|
"name": "Charlie Maintainer",
|
||||||
|
"email": "charlie@example.com"
|
||||||
|
},
|
||||||
|
"repository": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/npm/cli"
|
||||||
|
},
|
||||||
|
"license": "Artistic-2.0"
|
||||||
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user