mirror of
https://github.com/anchore/syft.git
synced 2025-11-18 00:43:20 +01:00
Detect a license file in the root directory or META-INF of a jar (#2213)
Signed-off-by: Colm O hEigeartaigh <coheigea@apache.org>
This commit is contained in:
parent
fe7a417fb2
commit
2687100e6a
@ -8,6 +8,7 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
intFile "github.com/anchore/syft/internal/file"
|
intFile "github.com/anchore/syft/internal/file"
|
||||||
|
"github.com/anchore/syft/internal/licenses"
|
||||||
"github.com/anchore/syft/internal/log"
|
"github.com/anchore/syft/internal/log"
|
||||||
"github.com/anchore/syft/syft/artifact"
|
"github.com/anchore/syft/syft/artifact"
|
||||||
"github.com/anchore/syft/syft/file"
|
"github.com/anchore/syft/syft/file"
|
||||||
@ -177,6 +178,31 @@ func (j *archiveParser) discoverMainPackage() (*pkg.Package, error) {
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
licenses, name, version, err := j.parseLicenses(manifest)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return &pkg.Package{
|
||||||
|
// TODO: maybe select name should just have a pom properties in it?
|
||||||
|
Name: name,
|
||||||
|
Version: version,
|
||||||
|
Language: pkg.Java,
|
||||||
|
Licenses: pkg.NewLicenseSet(licenses...),
|
||||||
|
Locations: file.NewLocationSet(
|
||||||
|
j.location.WithAnnotation(pkg.EvidenceAnnotationKey, pkg.PrimaryEvidenceAnnotation),
|
||||||
|
),
|
||||||
|
Type: j.fileInfo.pkgType(),
|
||||||
|
MetadataType: pkg.JavaMetadataType,
|
||||||
|
Metadata: pkg.JavaMetadata{
|
||||||
|
VirtualPath: j.location.AccessPath(),
|
||||||
|
Manifest: manifest,
|
||||||
|
ArchiveDigests: digests,
|
||||||
|
},
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (j *archiveParser) parseLicenses(manifest *pkg.JavaManifest) ([]pkg.License, string, string, error) {
|
||||||
// we use j.location because we want to associate the license declaration with where we discovered the contents in the manifest
|
// we use j.location because we want to associate the license declaration with where we discovered the contents in the manifest
|
||||||
// TODO: when we support locations of paths within archives we should start passing the specific manifest location object instead of the top jar
|
// TODO: when we support locations of paths within archives we should start passing the specific manifest location object instead of the top jar
|
||||||
licenses := pkg.NewLicensesFromLocation(j.location, selectLicenses(manifest)...)
|
licenses := pkg.NewLicensesFromLocation(j.location, selectLicenses(manifest)...)
|
||||||
@ -201,23 +227,17 @@ func (j *archiveParser) discoverMainPackage() (*pkg.Package, error) {
|
|||||||
licenses = append(licenses, pomLicenses...)
|
licenses = append(licenses, pomLicenses...)
|
||||||
}
|
}
|
||||||
|
|
||||||
return &pkg.Package{
|
if len(licenses) == 0 {
|
||||||
// TODO: maybe select name should just have a pom properties in it?
|
fileLicenses, err := j.getLicenseFromFileInArchive()
|
||||||
Name: name,
|
if err != nil {
|
||||||
Version: version,
|
return nil, "", "", err
|
||||||
Language: pkg.Java,
|
}
|
||||||
Licenses: pkg.NewLicenseSet(licenses...),
|
if fileLicenses != nil {
|
||||||
Locations: file.NewLocationSet(
|
licenses = append(licenses, fileLicenses...)
|
||||||
j.location.WithAnnotation(pkg.EvidenceAnnotationKey, pkg.PrimaryEvidenceAnnotation),
|
}
|
||||||
),
|
}
|
||||||
Type: j.fileInfo.pkgType(),
|
|
||||||
MetadataType: pkg.JavaMetadataType,
|
return licenses, name, version, nil
|
||||||
Metadata: pkg.JavaMetadata{
|
|
||||||
VirtualPath: j.location.AccessPath(),
|
|
||||||
Manifest: manifest,
|
|
||||||
ArchiveDigests: digests,
|
|
||||||
},
|
|
||||||
}, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type parsedPomProject struct {
|
type parsedPomProject struct {
|
||||||
@ -310,6 +330,38 @@ func getDigestsFromArchive(archivePath string) ([]file.Digest, error) {
|
|||||||
return digests, nil
|
return digests, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (j *archiveParser) getLicenseFromFileInArchive() ([]pkg.License, error) {
|
||||||
|
var fileLicenses []pkg.License
|
||||||
|
for _, filename := range licenses.FileNames {
|
||||||
|
licenseMatches := j.fileManifest.GlobMatch("/META-INF/" + filename)
|
||||||
|
if len(licenseMatches) == 0 {
|
||||||
|
// Try the root directory if it's not in META-INF
|
||||||
|
licenseMatches = j.fileManifest.GlobMatch("/" + filename)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(licenseMatches) > 0 {
|
||||||
|
contents, err := intFile.ContentsFromZip(j.archivePath, licenseMatches...)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("unable to extract java license (%s): %w", j.location, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, licenseMatch := range licenseMatches {
|
||||||
|
licenseContents := contents[licenseMatch]
|
||||||
|
parsed, err := licenses.Parse(strings.NewReader(licenseContents), j.location)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(parsed) > 0 {
|
||||||
|
fileLicenses = append(fileLicenses, parsed...)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return fileLicenses, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (j *archiveParser) discoverPkgsFromNestedArchives(parentPkg *pkg.Package) ([]pkg.Package, []artifact.Relationship, error) {
|
func (j *archiveParser) discoverPkgsFromNestedArchives(parentPkg *pkg.Package) ([]pkg.Package, []artifact.Relationship, error) {
|
||||||
// we know that all java archives are zip formatted files, so we can use the shared zip helper
|
// we know that all java archives are zip formatted files, so we can use the shared zip helper
|
||||||
return discoverPkgsFromZip(j.location, j.archivePath, j.contentPath, j.fileManifest, parentPkg)
|
return discoverPkgsFromZip(j.location, j.archivePath, j.contentPath, j.fileManifest, parentPkg)
|
||||||
|
|||||||
@ -158,6 +158,15 @@ func TestParseJar(t *testing.T) {
|
|||||||
Language: pkg.Java,
|
Language: pkg.Java,
|
||||||
Type: pkg.JavaPkg,
|
Type: pkg.JavaPkg,
|
||||||
MetadataType: pkg.JavaMetadataType,
|
MetadataType: pkg.JavaMetadataType,
|
||||||
|
Licenses: pkg.NewLicenseSet(
|
||||||
|
pkg.License{
|
||||||
|
Value: "Apache-2.0",
|
||||||
|
SPDXExpression: "Apache-2.0",
|
||||||
|
Type: license.Concluded,
|
||||||
|
URLs: internal.NewStringSet(),
|
||||||
|
Locations: file.NewLocationSet(file.NewLocation("test-fixtures/java-builds/packages/example-java-app-gradle-0.1.0.jar")),
|
||||||
|
},
|
||||||
|
),
|
||||||
Metadata: pkg.JavaMetadata{
|
Metadata: pkg.JavaMetadata{
|
||||||
VirtualPath: "test-fixtures/java-builds/packages/example-java-app-gradle-0.1.0.jar",
|
VirtualPath: "test-fixtures/java-builds/packages/example-java-app-gradle-0.1.0.jar",
|
||||||
Manifest: &pkg.JavaManifest{
|
Manifest: &pkg.JavaManifest{
|
||||||
@ -223,6 +232,15 @@ func TestParseJar(t *testing.T) {
|
|||||||
Language: pkg.Java,
|
Language: pkg.Java,
|
||||||
Type: pkg.JavaPkg,
|
Type: pkg.JavaPkg,
|
||||||
MetadataType: pkg.JavaMetadataType,
|
MetadataType: pkg.JavaMetadataType,
|
||||||
|
Licenses: pkg.NewLicenseSet(
|
||||||
|
pkg.License{
|
||||||
|
Value: "Apache-2.0",
|
||||||
|
SPDXExpression: "Apache-2.0",
|
||||||
|
Type: license.Concluded,
|
||||||
|
URLs: internal.NewStringSet(),
|
||||||
|
Locations: file.NewLocationSet(file.NewLocation("test-fixtures/java-builds/packages/example-java-app-maven-0.1.0.jar")),
|
||||||
|
},
|
||||||
|
),
|
||||||
Metadata: pkg.JavaMetadata{
|
Metadata: pkg.JavaMetadata{
|
||||||
VirtualPath: "test-fixtures/java-builds/packages/example-java-app-maven-0.1.0.jar",
|
VirtualPath: "test-fixtures/java-builds/packages/example-java-app-maven-0.1.0.jar",
|
||||||
Manifest: &pkg.JavaManifest{
|
Manifest: &pkg.JavaManifest{
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user