mirror of
https://github.com/anchore/syft.git
synced 2026-10-30 22:12:28 +01:00
feat: update syft license concept to complex struct (#1743)
this PR makes the following changes to update the underlying license model to have more expressive capabilities it also provides some guarantee's surrounding the license values themselves - Licenses are updated from string -> pkg.LicenseSet which contain pkg.License with the following fields: - original `Value` read by syft - If it's possible to construct licenses will always have a valid SPDX expression for downstream consumption - the above is run against a generated list of SPDX license ID to try and find the correct ID - SPDX concluded vs declared is added to the new struct - URL source for license is added to the new struct - Location source is added to the new struct to show where the expression was pulled from
This commit is contained in:
@@ -8,23 +8,24 @@ import (
|
||||
"github.com/anchore/syft/syft/source"
|
||||
)
|
||||
|
||||
func newComposerLockPackage(m pkg.PhpComposerJSONMetadata, location ...source.Location) pkg.Package {
|
||||
func newComposerLockPackage(m parsedData, indexLocation source.Location) pkg.Package {
|
||||
p := pkg.Package{
|
||||
Name: m.Name,
|
||||
Version: m.Version,
|
||||
Locations: source.NewLocationSet(location...),
|
||||
Locations: source.NewLocationSet(indexLocation),
|
||||
Licenses: pkg.NewLicenseSet(pkg.NewLicensesFromLocation(indexLocation, m.License...)...),
|
||||
PURL: packageURL(m),
|
||||
Language: pkg.PHP,
|
||||
Type: pkg.PhpComposerPkg,
|
||||
MetadataType: pkg.PhpComposerJSONMetadataType,
|
||||
Metadata: m,
|
||||
Metadata: m.PhpComposerJSONMetadata,
|
||||
}
|
||||
|
||||
p.SetID()
|
||||
return p
|
||||
}
|
||||
|
||||
func packageURL(m pkg.PhpComposerJSONMetadata) string {
|
||||
func packageURL(m parsedData) string {
|
||||
var name, vendor string
|
||||
fields := strings.Split(m.Name, "/")
|
||||
switch len(fields) {
|
||||
|
||||
@@ -11,30 +11,39 @@ import (
|
||||
func Test_packageURL(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
metadata pkg.PhpComposerJSONMetadata
|
||||
metadata parsedData
|
||||
expected string
|
||||
}{
|
||||
{
|
||||
name: "with extractable vendor",
|
||||
metadata: pkg.PhpComposerJSONMetadata{
|
||||
Name: "ven/name",
|
||||
Version: "1.0.1",
|
||||
metadata: parsedData{
|
||||
[]string{},
|
||||
pkg.PhpComposerJSONMetadata{
|
||||
Version: "1.0.1",
|
||||
Name: "ven/name",
|
||||
},
|
||||
},
|
||||
expected: "pkg:composer/ven/name@1.0.1",
|
||||
},
|
||||
{
|
||||
name: "name with slashes (invalid)",
|
||||
metadata: pkg.PhpComposerJSONMetadata{
|
||||
Name: "ven/name/component",
|
||||
Version: "1.0.1",
|
||||
metadata: parsedData{
|
||||
[]string{},
|
||||
pkg.PhpComposerJSONMetadata{
|
||||
Name: "ven/name/component",
|
||||
Version: "1.0.1",
|
||||
},
|
||||
},
|
||||
expected: "pkg:composer/ven/name-component@1.0.1",
|
||||
},
|
||||
{
|
||||
name: "unknown vendor",
|
||||
metadata: pkg.PhpComposerJSONMetadata{
|
||||
Name: "name",
|
||||
Version: "1.0.1",
|
||||
metadata: parsedData{
|
||||
[]string{},
|
||||
pkg.PhpComposerJSONMetadata{
|
||||
Name: "name",
|
||||
Version: "1.0.1",
|
||||
},
|
||||
},
|
||||
expected: "pkg:composer/name@1.0.1",
|
||||
},
|
||||
|
||||
@@ -14,9 +14,14 @@ import (
|
||||
|
||||
var _ generic.Parser = parseComposerLock
|
||||
|
||||
type parsedData struct {
|
||||
License []string `json:"license"`
|
||||
pkg.PhpComposerJSONMetadata
|
||||
}
|
||||
|
||||
type composerLock struct {
|
||||
Packages []pkg.PhpComposerJSONMetadata `json:"packages"`
|
||||
PackageDev []pkg.PhpComposerJSONMetadata `json:"packages-dev"`
|
||||
Packages []parsedData `json:"packages"`
|
||||
PackageDev []parsedData `json:"packages-dev"`
|
||||
}
|
||||
|
||||
// parseComposerLock is a parser function for Composer.lock contents, returning "Default" php packages discovered.
|
||||
@@ -40,6 +45,11 @@ func parseComposerLock(_ source.FileResolver, _ *generic.Environment, reader sou
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
// TODO: did we omit this on purpose?
|
||||
// for _, m := range lock.PackageDev {
|
||||
// pkgs = append(pkgs, newComposerLockPackage(m, reader.Location))
|
||||
//}
|
||||
}
|
||||
|
||||
return pkgs, nil, nil
|
||||
|
||||
@@ -15,10 +15,13 @@ func TestParseComposerFileLock(t *testing.T) {
|
||||
locations := source.NewLocationSet(source.NewLocation(fixture))
|
||||
expectedPkgs := []pkg.Package{
|
||||
{
|
||||
Name: "adoy/fastcgi-client",
|
||||
Version: "1.0.2",
|
||||
PURL: "pkg:composer/adoy/fastcgi-client@1.0.2",
|
||||
Locations: locations,
|
||||
Name: "adoy/fastcgi-client",
|
||||
Version: "1.0.2",
|
||||
PURL: "pkg:composer/adoy/fastcgi-client@1.0.2",
|
||||
Locations: locations,
|
||||
Licenses: pkg.NewLicenseSet(
|
||||
pkg.NewLicenseFromLocations("MIT", source.NewLocation(fixture)),
|
||||
),
|
||||
Language: pkg.PHP,
|
||||
Type: pkg.PhpComposerPkg,
|
||||
MetadataType: pkg.PhpComposerJSONMetadataType,
|
||||
@@ -37,9 +40,6 @@ func TestParseComposerFileLock(t *testing.T) {
|
||||
},
|
||||
Type: "library",
|
||||
NotificationURL: "https://packagist.org/downloads/",
|
||||
License: []string{
|
||||
"MIT",
|
||||
},
|
||||
Authors: []pkg.PhpComposerAuthors{
|
||||
{
|
||||
Name: "Pierrick Charron",
|
||||
@@ -55,11 +55,14 @@ func TestParseComposerFileLock(t *testing.T) {
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "alcaeus/mongo-php-adapter",
|
||||
Version: "1.1.11",
|
||||
Locations: locations,
|
||||
PURL: "pkg:composer/alcaeus/mongo-php-adapter@1.1.11",
|
||||
Language: pkg.PHP,
|
||||
Name: "alcaeus/mongo-php-adapter",
|
||||
Version: "1.1.11",
|
||||
Locations: locations,
|
||||
PURL: "pkg:composer/alcaeus/mongo-php-adapter@1.1.11",
|
||||
Language: pkg.PHP,
|
||||
Licenses: pkg.NewLicenseSet(
|
||||
pkg.NewLicenseFromLocations("MIT", source.NewLocation(fixture)),
|
||||
),
|
||||
Type: pkg.PhpComposerPkg,
|
||||
MetadataType: pkg.PhpComposerJSONMetadataType,
|
||||
Metadata: pkg.PhpComposerJSONMetadata{
|
||||
@@ -91,9 +94,6 @@ func TestParseComposerFileLock(t *testing.T) {
|
||||
},
|
||||
Type: "library",
|
||||
NotificationURL: "https://packagist.org/downloads/",
|
||||
License: []string{
|
||||
"MIT",
|
||||
},
|
||||
Authors: []pkg.PhpComposerAuthors{
|
||||
{
|
||||
Name: "alcaeus",
|
||||
|
||||
@@ -16,19 +16,19 @@ var _ generic.Parser = parseComposerLock
|
||||
|
||||
// Note: composer version 2 introduced a new structure for the installed.json file, so we support both
|
||||
type installedJSONComposerV2 struct {
|
||||
Packages []pkg.PhpComposerJSONMetadata `json:"packages"`
|
||||
Packages []parsedData `json:"packages"`
|
||||
}
|
||||
|
||||
func (w *installedJSONComposerV2) UnmarshalJSON(data []byte) error {
|
||||
type compv2 struct {
|
||||
Packages []pkg.PhpComposerJSONMetadata `json:"packages"`
|
||||
Packages []parsedData `json:"packages"`
|
||||
}
|
||||
compv2er := new(compv2)
|
||||
err := json.Unmarshal(data, &compv2er)
|
||||
if err != nil {
|
||||
// If we had an err or, we may be dealing with a composer v.1 installed.json
|
||||
// which should be all arrays
|
||||
var packages []pkg.PhpComposerJSONMetadata
|
||||
var packages []parsedData
|
||||
err := json.Unmarshal(data, &packages)
|
||||
if err != nil {
|
||||
return err
|
||||
|
||||
@@ -24,6 +24,9 @@ func TestParseInstalledJsonComposerV1(t *testing.T) {
|
||||
Language: pkg.PHP,
|
||||
Type: pkg.PhpComposerPkg,
|
||||
MetadataType: pkg.PhpComposerJSONMetadataType,
|
||||
Licenses: pkg.NewLicenseSet(
|
||||
pkg.NewLicense("MIT"),
|
||||
),
|
||||
Metadata: pkg.PhpComposerJSONMetadata{
|
||||
Name: "asm89/stack-cors",
|
||||
Version: "1.3.0",
|
||||
@@ -49,9 +52,6 @@ func TestParseInstalledJsonComposerV1(t *testing.T) {
|
||||
Time: "2019-12-24T22:41:47+00:00",
|
||||
Type: "library",
|
||||
NotificationURL: "https://packagist.org/downloads/",
|
||||
License: []string{
|
||||
"MIT",
|
||||
},
|
||||
Authors: []pkg.PhpComposerAuthors{
|
||||
{
|
||||
Name: "Alexander",
|
||||
@@ -68,11 +68,14 @@ func TestParseInstalledJsonComposerV1(t *testing.T) {
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "behat/mink",
|
||||
Version: "v1.8.1",
|
||||
PURL: "pkg:composer/behat/mink@v1.8.1",
|
||||
Language: pkg.PHP,
|
||||
Type: pkg.PhpComposerPkg,
|
||||
Name: "behat/mink",
|
||||
Version: "v1.8.1",
|
||||
PURL: "pkg:composer/behat/mink@v1.8.1",
|
||||
Language: pkg.PHP,
|
||||
Type: pkg.PhpComposerPkg,
|
||||
Licenses: pkg.NewLicenseSet(
|
||||
pkg.NewLicense("MIT"),
|
||||
),
|
||||
MetadataType: pkg.PhpComposerJSONMetadataType,
|
||||
Metadata: pkg.PhpComposerJSONMetadata{
|
||||
Name: "behat/mink",
|
||||
@@ -106,9 +109,6 @@ func TestParseInstalledJsonComposerV1(t *testing.T) {
|
||||
Time: "2020-03-11T15:45:53+00:00",
|
||||
Type: "library",
|
||||
NotificationURL: "https://packagist.org/downloads/",
|
||||
License: []string{
|
||||
"MIT",
|
||||
},
|
||||
Authors: []pkg.PhpComposerAuthors{
|
||||
{
|
||||
Name: "Konstantin Kudryashov",
|
||||
@@ -133,9 +133,14 @@ func TestParseInstalledJsonComposerV1(t *testing.T) {
|
||||
locations := source.NewLocationSet(source.NewLocation(fixture))
|
||||
for i := range expectedPkgs {
|
||||
expectedPkgs[i].Locations = locations
|
||||
locationLicenses := pkg.NewLicenseSet()
|
||||
for _, license := range expectedPkgs[i].Licenses.ToSlice() {
|
||||
license.Location = locations
|
||||
locationLicenses.Add(license)
|
||||
}
|
||||
expectedPkgs[i].Licenses = locationLicenses
|
||||
}
|
||||
pkgtest.TestFileParser(t, fixture, parseInstalledJSON, expectedPkgs, expectedRelationships)
|
||||
})
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user