diff --git a/pkg/dependency/parser/conda/meta/parse.go b/pkg/dependency/parser/conda/meta/parse.go index 08f5623fa052..2dd09d551def 100644 --- a/pkg/dependency/parser/conda/meta/parse.go +++ b/pkg/dependency/parser/conda/meta/parse.go @@ -3,10 +3,10 @@ package meta import ( "encoding/json" - "github.com/samber/lo" "golang.org/x/xerrors" ftypes "github.com/aquasecurity/trivy/pkg/fanal/types" + "github.com/aquasecurity/trivy/pkg/licensing" xio "github.com/aquasecurity/trivy/pkg/x/io" ) @@ -40,7 +40,7 @@ func (p *Parser) Parse(r xio.ReadSeekerAt) ([]ftypes.Package, []ftypes.Dependenc { Name: data.Name, Version: data.Version, - Licenses: lo.Ternary(data.License != "", []string{data.License}, nil), + Licenses: licensing.SplitLicenses(data.License), }, }, nil, nil } diff --git a/pkg/dependency/parser/php/composer/parse.go b/pkg/dependency/parser/php/composer/parse.go index 1b1e72bb7a10..c95901686ba0 100644 --- a/pkg/dependency/parser/php/composer/parse.go +++ b/pkg/dependency/parser/php/composer/parse.go @@ -11,6 +11,7 @@ import ( "github.com/aquasecurity/trivy/pkg/dependency" ftypes "github.com/aquasecurity/trivy/pkg/fanal/types" + "github.com/aquasecurity/trivy/pkg/licensing" "github.com/aquasecurity/trivy/pkg/log" xio "github.com/aquasecurity/trivy/pkg/x/io" ) @@ -22,7 +23,7 @@ type packageInfo struct { Name string `json:"name"` Version string `json:"version"` Require map[string]string `json:"require"` - License []string `json:"license"` + License any `json:"license"` StartLine int EndLine int } @@ -55,7 +56,7 @@ func (p *Parser) Parse(r xio.ReadSeekerAt) ([]ftypes.Package, []ftypes.Dependenc Name: lpkg.Name, Version: lpkg.Version, Relationship: ftypes.RelationshipUnknown, // composer.lock file doesn't have info about direct/indirect dependencies - Licenses: lpkg.License, + Licenses: licenses(lpkg.License), Locations: []ftypes.Location{ { StartLine: lpkg.StartLine, @@ -114,3 +115,23 @@ func (t *packageInfo) UnmarshalJSONWithMetadata(node jfather.Node) error { t.EndLine = node.Range().End.Line return nil } + +// licenses returns slice of licenses from string, string with separators (`or`, `and`, etc.) or string array +// cf. https://getcomposer.org/doc/04-schema.md#license +func licenses(val any) []string { + switch v := val.(type) { + case string: + if v != "" { + return licensing.SplitLicenses(v) + } + case []any: + var lics []string + for _, l := range v { + if lic, ok := l.(string); ok { + lics = append(lics, lic) + } + } + return lics + } + return nil +} diff --git a/pkg/dependency/parser/php/composer/parse_test.go b/pkg/dependency/parser/php/composer/parse_test.go index 58e19982720d..7a06ed87db4a 100644 --- a/pkg/dependency/parser/php/composer/parse_test.go +++ b/pkg/dependency/parser/php/composer/parse_test.go @@ -98,7 +98,7 @@ var ( Locations: []ftypes.Location{ { StartLine: 502, - EndLine: 585, + EndLine: 583, }, }, }, @@ -106,11 +106,11 @@ var ( ID: "symfony/polyfill-php72@v1.27.0", Name: "symfony/polyfill-php72", Version: "v1.27.0", - Licenses: []string{"MIT"}, + Licenses: []string{"MIT", "BSD-2-Clause"}, Locations: []ftypes.Location{ { - StartLine: 586, - EndLine: 661, + StartLine: 584, + EndLine: 657, }, }, }, diff --git a/pkg/dependency/parser/php/composer/testdata/composer_happy.lock b/pkg/dependency/parser/php/composer/testdata/composer_happy.lock index 2987ab8d58d9..832f35d854d1 100644 --- a/pkg/dependency/parser/php/composer/testdata/composer_happy.lock +++ b/pkg/dependency/parser/php/composer/testdata/composer_happy.lock @@ -541,9 +541,7 @@ ] }, "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], + "license": "MIT", "authors": [ { "name": "Nicolas Grekas", @@ -619,9 +617,7 @@ } }, "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], + "license": "MIT or BSD-2-Clause", "authors": [ { "name": "Nicolas Grekas", diff --git a/pkg/dependency/parser/python/packaging/parse.go b/pkg/dependency/parser/python/packaging/parse.go index c8376a8066f2..fa1758308860 100644 --- a/pkg/dependency/parser/python/packaging/parse.go +++ b/pkg/dependency/parser/python/packaging/parse.go @@ -7,10 +7,10 @@ import ( "net/textproto" "strings" - "github.com/samber/lo" "golang.org/x/xerrors" ftypes "github.com/aquasecurity/trivy/pkg/fanal/types" + "github.com/aquasecurity/trivy/pkg/licensing" "github.com/aquasecurity/trivy/pkg/log" xio "github.com/aquasecurity/trivy/pkg/x/io" ) @@ -87,7 +87,7 @@ func (p *Parser) Parse(r xio.ReadSeekerAt) ([]ftypes.Package, []ftypes.Dependenc { Name: name, Version: version, - Licenses: lo.Ternary(license != "", []string{license}, nil), + Licenses: licensing.SplitLicenses(license), }, }, nil, nil } diff --git a/pkg/dependency/parser/python/packaging/parse_test.go b/pkg/dependency/parser/python/packaging/parse_test.go index cde70dea19ce..2051762699b1 100644 --- a/pkg/dependency/parser/python/packaging/parse_test.go +++ b/pkg/dependency/parser/python/packaging/parse_test.go @@ -35,9 +35,11 @@ func TestParse(t *testing.T) { // tr "\n" "\t" | awk -F "\t" '{printf("\{\""$1"\", \""$2"\", \""$3"\"\}\n")}' want: []ftypes.Package{ { - Name: "setuptools", - Version: "51.3.3", - Licenses: []string{"UNKNOWN"}, + Name: "setuptools", + Version: "51.3.3", + Licenses: []string{ + "UNKNOWN", + }, }, }, }, @@ -46,9 +48,11 @@ func TestParse(t *testing.T) { input: "testdata/unidecode-egg-info.PKG-INFO", want: []ftypes.Package{ { - Name: "Unidecode", - Version: "0.4.1", - Licenses: []string{"UNKNOWN"}, + Name: "Unidecode", + Version: "0.4.1", + Licenses: []string{ + "UNKNOWN", + }, }, }, }, @@ -63,9 +67,11 @@ func TestParse(t *testing.T) { // tr "\n" "\t" | awk -F "\t" '{printf("\{\""$1"\", \""$2"\", \""$3"\"\}\n")}' want: []ftypes.Package{ { - Name: "distlib", - Version: "0.3.1", - Licenses: []string{"Python license"}, + Name: "distlib", + Version: "0.3.1", + Licenses: []string{ + "Python license", + }, }, }, }, @@ -96,9 +102,11 @@ func TestParse(t *testing.T) { input: "testdata/distlib-0.3.1.METADATA", want: []ftypes.Package{ { - Name: "distlib", - Version: "0.3.1", - Licenses: []string{"Python Software Foundation License"}, + Name: "distlib", + Version: "0.3.1", + Licenses: []string{ + "Python Software Foundation License", + }, }, }, }, @@ -109,9 +117,11 @@ func TestParse(t *testing.T) { want: []ftypes.Package{ { - Name: "asyncssh", - Version: "2.14.2", - Licenses: []string{"Eclipse Public License v2.0"}, + Name: "asyncssh", + Version: "2.14.2", + Licenses: []string{ + "Eclipse Public License v2.0", + }, }, }, }, @@ -122,9 +132,13 @@ func TestParse(t *testing.T) { want: []ftypes.Package{ { - Name: "pyphen", - Version: "0.14.0", - Licenses: []string{"GNU General Public License v2 or later (GPLv2+), GNU Lesser General Public License v2 or later (LGPLv2+), Mozilla Public License 1.1 (MPL 1.1)"}, + Name: "pyphen", + Version: "0.14.0", + Licenses: []string{ + "GNU General Public License v2 or later (GPLv2+)", + "GNU Lesser General Public License v2 or later (LGPLv2+)", + "Mozilla Public License 1.1 (MPL 1.1)", + }, }, }, }, @@ -138,9 +152,11 @@ func TestParse(t *testing.T) { input: "testdata/iniconfig-2.0.0.METADATA", want: []ftypes.Package{ { - Name: "iniconfig", - Version: "2.0.0", - Licenses: []string{"MIT"}, + Name: "iniconfig", + Version: "2.0.0", + Licenses: []string{ + "MIT", + }, }, }, }, @@ -149,9 +165,11 @@ func TestParse(t *testing.T) { input: "testdata/zipp-3.12.1.METADATA", want: []ftypes.Package{ { - Name: "zipp", - Version: "3.12.1", - Licenses: []string{"MIT License"}, + Name: "zipp", + Version: "3.12.1", + Licenses: []string{ + "MIT License", + }, }, }, }, @@ -160,9 +178,11 @@ func TestParse(t *testing.T) { input: "testdata/networkx-3.0.METADATA", want: []ftypes.Package{ { - Name: "networkx", - Version: "3.0", - Licenses: []string{"file://LICENSE.txt"}, + Name: "networkx", + Version: "3.0", + Licenses: []string{ + "file://LICENSE.txt", + }, }, }, },