npm: package-lock license decoding to accept string or array (#1482)

Signed-off-by: mikcl <mikesmikes400@gmail.com>
This commit is contained in:
mikcl 2023-01-20 14:28:51 +00:00 committed by GitHub
parent 972e4cdaeb
commit 396441e921
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 123 additions and 7 deletions

View File

@ -78,8 +78,8 @@ func newPackageLockV1Package(resolver source.FileResolver, location source.Locat
func newPackageLockV2Package(resolver source.FileResolver, location source.Location, name string, u lockPackage) pkg.Package {
var licenses []string
if u.License != "" {
licenses = append(licenses, u.License)
if u.License != nil {
licenses = u.License
}
return finalizeLockPkg(

View File

@ -7,6 +7,7 @@ import (
"io"
"strings"
"github.com/anchore/syft/internal/log"
"github.com/anchore/syft/syft/artifact"
"github.com/anchore/syft/syft/pkg"
"github.com/anchore/syft/syft/pkg/cataloger/generic"
@ -24,6 +25,39 @@ type packageLock struct {
Packages map[string]lockPackage
}
// packageLockLicense
type packageLockLicense []string
func (licenses *packageLockLicense) UnmarshalJSON(data []byte) (err error) {
// The license field could be either a string or an array.
// 1. An array
var arr []string
if err := json.Unmarshal(data, &arr); err == nil {
*licenses = arr
return nil
}
// 2. A string
var str string
if err = json.Unmarshal(data, &str); err == nil {
*licenses = make([]string, 1)
(*licenses)[0] = str
return nil
}
// debug the content we did not expect
if len(data) > 0 {
log.WithFields("license", string(data)).Debug("Unable to parse the following `license` value in package-lock.json")
}
// 3. Unexpected
// In case we are unable to parse the license field,
// i.e if we have not covered the full specification,
// we do not want to throw an error, instead assign nil.
return nil
}
// lockDependency represents a single package dependency listed in the package.lock json file
type lockDependency struct {
Version string `json:"version"`
@ -32,11 +66,11 @@ type lockDependency struct {
}
type lockPackage struct {
Name string `json:"name"` // only present in the root package entry (named "")
Version string `json:"version"`
Resolved string `json:"resolved"`
Integrity string `json:"integrity"`
License string `json:"license"`
Name string `json:"name"` // only present in the root package entry (named "")
Version string `json:"version"`
Resolved string `json:"resolved"`
Integrity string `json:"integrity"`
License packageLockLicense `json:"license"`
}
// parsePackageLock parses a package-lock.json and returns the discovered JavaScript packages.

View File

@ -297,3 +297,44 @@ func TestParsePackageLockAlias(t *testing.T) {
pkgtest.TestFileParser(t, packageLock, parsePackageLock, expected, expectedRelationships)
}
}
func TestParsePackageLockLicenseWithArray(t *testing.T) {
fixture := "test-fixtures/pkg-lock/array-license-package-lock.json"
var expectedRelationships []artifact.Relationship
expectedPkgs := []pkg.Package{
{
Name: "tmp",
Version: "1.0.0",
Licenses: []string{"ISC"},
Language: pkg.JavaScript,
Type: pkg.NpmPkg,
PURL: "pkg:npm/tmp@1.0.0",
MetadataType: "NpmPackageLockJsonMetadata",
Metadata: pkg.NpmPackageLockJSONMetadata{},
},
{
Name: "pause-stream",
Version: "0.0.11",
Licenses: []string{"MIT", "Apache2"},
Language: pkg.JavaScript,
Type: pkg.NpmPkg,
PURL: "pkg:npm/pause-stream@0.0.11",
MetadataType: "NpmPackageLockJsonMetadata",
Metadata: pkg.NpmPackageLockJSONMetadata{},
},
{
Name: "through",
Version: "2.3.8",
Licenses: []string{"MIT"},
Language: pkg.JavaScript,
Type: pkg.NpmPkg,
PURL: "pkg:npm/through@2.3.8",
MetadataType: "NpmPackageLockJsonMetadata",
Metadata: pkg.NpmPackageLockJSONMetadata{},
},
}
for i := range expectedPkgs {
expectedPkgs[i].Locations.Add(source.NewLocation(fixture))
}
pkgtest.TestFileParser(t, fixture, parsePackageLock, expectedPkgs, expectedRelationships)
}

View File

@ -0,0 +1,41 @@
{
"name": "tmp",
"version": "1.0.0",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "tmp",
"version": "1.0.0",
"license": "ISC",
"dependencies": {
"pause-stream": "0.0.11"
}
},
"node_modules/pause-stream": {
"version": "0.0.11",
"license": [
"MIT",
"Apache2"
],
"dependencies": {
"through": "~2.3"
}
},
"node_modules/through": {
"version": "2.3.8",
"license": "MIT"
}
},
"dependencies": {
"pause-stream": {
"version": "0.0.11",
"requires": {
"through": "~2.3"
}
},
"through": {
"version": "2.3.8"
}
}
}