mirror of
https://github.com/anchore/syft.git
synced 2025-11-17 16:33:21 +01:00
Parse Python licenses from LicenseFile entry in the Wheel Metadata (#2331)
Signed-off-by: Colm O hEigeartaigh <coheigea@apache.org>
This commit is contained in:
parent
8bca0ac39e
commit
d39ef44e40
@ -4,6 +4,8 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"github.com/anchore/packageurl-go"
|
"github.com/anchore/packageurl-go"
|
||||||
|
"github.com/anchore/syft/internal/licenses"
|
||||||
|
"github.com/anchore/syft/internal/log"
|
||||||
"github.com/anchore/syft/syft/file"
|
"github.com/anchore/syft/syft/file"
|
||||||
"github.com/anchore/syft/syft/pkg"
|
"github.com/anchore/syft/syft/pkg"
|
||||||
)
|
)
|
||||||
@ -55,13 +57,37 @@ func newPackageForRequirementsWithMetadata(name, version string, metadata pkg.Py
|
|||||||
return p
|
return p
|
||||||
}
|
}
|
||||||
|
|
||||||
func newPackageForPackage(m parsedData, sources ...file.Location) pkg.Package {
|
func newPackageForPackage(resolver file.Resolver, m parsedData, sources ...file.Location) pkg.Package {
|
||||||
|
var licenseSet pkg.LicenseSet
|
||||||
|
if m.Licenses != "" {
|
||||||
|
licenseSet = pkg.NewLicenseSet(pkg.NewLicensesFromLocation(m.LicenseLocation, m.Licenses)...)
|
||||||
|
} else if m.LicenseLocation.Path() != "" {
|
||||||
|
// If we have a license file then resolve and parse it
|
||||||
|
found, err := resolver.FilesByPath(m.LicenseLocation.Path())
|
||||||
|
if err != nil {
|
||||||
|
log.WithFields("error", err).Tracef("unable to resolve python license path %s", m.LicenseLocation.Path())
|
||||||
|
}
|
||||||
|
if len(found) > 0 {
|
||||||
|
metadataContents, err := resolver.FileContentsByLocation(found[0])
|
||||||
|
if err == nil {
|
||||||
|
parsed, err := licenses.Parse(metadataContents, m.LicenseLocation)
|
||||||
|
if err != nil {
|
||||||
|
log.WithFields("error", err).Tracef("unable to parse a license from the file in %s", m.LicenseLocation.Path())
|
||||||
|
}
|
||||||
|
if len(parsed) > 0 {
|
||||||
|
licenseSet = pkg.NewLicenseSet(parsed...)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
log.WithFields("error", err).Tracef("unable to read file contents at %s", m.LicenseLocation.Path())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
p := pkg.Package{
|
p := pkg.Package{
|
||||||
Name: m.Name,
|
Name: m.Name,
|
||||||
Version: m.Version,
|
Version: m.Version,
|
||||||
PURL: packageURL(m.Name, m.Version, &m.PythonPackage),
|
PURL: packageURL(m.Name, m.Version, &m.PythonPackage),
|
||||||
Locations: file.NewLocationSet(sources...),
|
Locations: file.NewLocationSet(sources...),
|
||||||
Licenses: pkg.NewLicenseSet(pkg.NewLicensesFromLocation(m.LicenseLocation, m.Licenses)...),
|
Licenses: licenseSet,
|
||||||
Language: pkg.Python,
|
Language: pkg.Python,
|
||||||
Type: pkg.PythonPkg,
|
Type: pkg.PythonPkg,
|
||||||
Metadata: m.PythonPackage,
|
Metadata: m.PythonPackage,
|
||||||
|
|||||||
@ -32,7 +32,7 @@ func parseWheelOrEgg(resolver file.Resolver, _ *generic.Environment, reader file
|
|||||||
return nil, nil, nil
|
return nil, nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
pkgs := []pkg.Package{newPackageForPackage(*pd, sources...)}
|
pkgs := []pkg.Package{newPackageForPackage(resolver, *pd, sources...)}
|
||||||
|
|
||||||
return pkgs, nil, nil
|
return pkgs, nil, nil
|
||||||
}
|
}
|
||||||
|
|||||||
@ -17,6 +17,7 @@ import (
|
|||||||
|
|
||||||
type parsedData struct {
|
type parsedData struct {
|
||||||
Licenses string `mapstructure:"License"`
|
Licenses string `mapstructure:"License"`
|
||||||
|
LicenseFile string `mapstructure:"LicenseFile"`
|
||||||
LicenseLocation file.Location
|
LicenseLocation file.Location
|
||||||
pkg.PythonPackage `mapstructure:",squash"`
|
pkg.PythonPackage `mapstructure:",squash"`
|
||||||
}
|
}
|
||||||
@ -82,6 +83,8 @@ func parseWheelOrEggMetadata(path string, reader io.Reader) (parsedData, error)
|
|||||||
pd.SitePackagesRootPath = determineSitePackagesRootPath(path)
|
pd.SitePackagesRootPath = determineSitePackagesRootPath(path)
|
||||||
if pd.Licenses != "" {
|
if pd.Licenses != "" {
|
||||||
pd.LicenseLocation = file.NewLocation(path)
|
pd.LicenseLocation = file.NewLocation(path)
|
||||||
|
} else if pd.LicenseFile != "" {
|
||||||
|
pd.LicenseLocation = file.NewLocation(filepath.Join(filepath.Dir(path), pd.LicenseFile))
|
||||||
}
|
}
|
||||||
|
|
||||||
return pd, nil
|
return pd, nil
|
||||||
|
|||||||
@ -19,6 +19,7 @@ func TestParseWheelEggMetadata(t *testing.T) {
|
|||||||
Fixture: "test-fixtures/egg-info/PKG-INFO",
|
Fixture: "test-fixtures/egg-info/PKG-INFO",
|
||||||
ExpectedMetadata: parsedData{
|
ExpectedMetadata: parsedData{
|
||||||
"Apache 2.0",
|
"Apache 2.0",
|
||||||
|
"",
|
||||||
file.NewLocation("test-fixtures/egg-info/PKG-INFO"),
|
file.NewLocation("test-fixtures/egg-info/PKG-INFO"),
|
||||||
pkg.PythonPackage{
|
pkg.PythonPackage{
|
||||||
Name: "requests",
|
Name: "requests",
|
||||||
@ -34,6 +35,7 @@ func TestParseWheelEggMetadata(t *testing.T) {
|
|||||||
Fixture: "test-fixtures/dist-info/METADATA",
|
Fixture: "test-fixtures/dist-info/METADATA",
|
||||||
ExpectedMetadata: parsedData{
|
ExpectedMetadata: parsedData{
|
||||||
"BSD License",
|
"BSD License",
|
||||||
|
"",
|
||||||
file.NewLocation("test-fixtures/dist-info/METADATA"),
|
file.NewLocation("test-fixtures/dist-info/METADATA"),
|
||||||
pkg.PythonPackage{
|
pkg.PythonPackage{
|
||||||
Name: "Pygments",
|
Name: "Pygments",
|
||||||
@ -134,6 +136,7 @@ func TestParseWheelEggMetadataInvalid(t *testing.T) {
|
|||||||
{
|
{
|
||||||
Fixture: "test-fixtures/egg-info/PKG-INFO-INVALID",
|
Fixture: "test-fixtures/egg-info/PKG-INFO-INVALID",
|
||||||
ExpectedMetadata: parsedData{
|
ExpectedMetadata: parsedData{
|
||||||
|
"",
|
||||||
"",
|
"",
|
||||||
file.Location{},
|
file.Location{},
|
||||||
pkg.PythonPackage{
|
pkg.PythonPackage{
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user