Add pURL generation for java packages + fix NPM pURL generation (#812)

* enhance pURL generation for java packages

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>

* optionally split out npm namespaces for pURL generation

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>

* nit updates

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
This commit is contained in:
Alex Goodman
2022-02-10 13:46:38 -05:00
committed by GitHub
parent 5ab872c732
commit ca032434b3
13 changed files with 176 additions and 98 deletions
+3 -3
View File
@@ -40,11 +40,11 @@ var (
)
func candidateProductsForJava(p pkg.Package) []string {
return productsFromArtifactAndGroupIDs(artifactIDFromJavaPackage(p), groupIDsFromJavaPackage(p))
return productsFromArtifactAndGroupIDs(artifactIDFromJavaPackage(p), GroupIDsFromJavaPackage(p))
}
func candidateVendorsForJava(p pkg.Package) fieldCandidateSet {
gidVendors := vendorsFromGroupIDs(groupIDsFromJavaPackage(p))
gidVendors := vendorsFromGroupIDs(GroupIDsFromJavaPackage(p))
nameVendors := vendorsFromJavaManifestNames(p)
return newFieldCandidateSetFromSets(gidVendors, nameVendors)
}
@@ -173,7 +173,7 @@ func artifactIDFromJavaPackage(p pkg.Package) string {
return artifactID
}
func groupIDsFromJavaPackage(p pkg.Package) (groupIDs []string) {
func GroupIDsFromJavaPackage(p pkg.Package) (groupIDs []string) {
metadata, ok := p.Metadata.(pkg.JavaMetadata)
if !ok {
return nil
+1 -1
View File
@@ -333,7 +333,7 @@ func Test_groupIDsFromJavaPackage(t *testing.T) {
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
assert.ElementsMatch(t, test.expects, groupIDsFromJavaPackage(test.pkg))
assert.ElementsMatch(t, test.expects, GroupIDsFromJavaPackage(test.pkg))
})
}
}
+1 -16
View File
@@ -55,28 +55,13 @@ type archiveFilename struct {
version string
}
// TODO: Remove this method once we're using Go 1.15+.
//
// Go 1.15 introduces a `SubexpIndex` method for the Regexp type that would let
// this code be made more elegant. Once we've reached 1.15, we should eliminate
// this function in favor of that method.
func subexpIndex(re *regexp.Regexp, name string) int {
for i, subexpName := range re.SubexpNames() {
if subexpName == name {
return i
}
}
return -1
}
func getSubexp(matches []string, subexpName string, re *regexp.Regexp, raw string) string {
if len(matches) < 1 {
log.Warnf("unexpectedly empty matches for archive '%s'", raw)
return ""
}
index := subexpIndex(re, subexpName)
index := re.SubexpIndex(subexpName)
if index < 1 {
log.Warnf("unexpected index of '%s' capture group for Java archive '%s'", subexpName, raw)
return ""
+23 -2
View File
@@ -122,6 +122,13 @@ func (j *archiveParser) parse() ([]*pkg.Package, []artifact.Relationship, error)
pkgs = append([]*pkg.Package{parentPkg}, pkgs...)
}
// add pURLs to all packages found
// note: since package information may change after initial creation when parsing multiple locations within the
// jar, we wait until the conclusion of the parsing process before synthesizing pURLs.
for _, p := range pkgs {
addPURL(p)
}
return pkgs, relationships, nil
}
@@ -348,7 +355,7 @@ func newPackageFromMavenData(pomProperties pkg.PomProperties, pomProject *pkg.Po
}
if packageIdentitiesMatch(p, parentPkg) {
updatePackage(p, parentPkg)
updateParentPackage(p, parentPkg)
return nil
}
@@ -379,7 +386,7 @@ func packageIdentitiesMatch(p pkg.Package, parentPkg *pkg.Package) bool {
return false
}
func updatePackage(p pkg.Package, parentPkg *pkg.Package) {
func updateParentPackage(p pkg.Package, parentPkg *pkg.Package) {
// we've run across more information about our parent package, add this info to the parent package metadata
// the pom properties is typically a better source of information for name and version than the manifest
parentPkg.Name = p.Name
@@ -401,3 +408,17 @@ func updatePackage(p pkg.Package, parentPkg *pkg.Package) {
parentPkg.Metadata = parentMetadata
}
}
func addPURL(p *pkg.Package) {
purl := packageURL(*p)
if purl == "" {
return
}
metadata, ok := p.Metadata.(pkg.JavaMetadata)
if !ok {
return
}
metadata.PURL = purl
p.Metadata = metadata
}
@@ -134,6 +134,7 @@ func TestParseJar(t *testing.T) {
Version: "1.0-SNAPSHOT",
Extra: map[string]string{},
},
PURL: "pkg:maven/io.jenkins.plugins/example-jenkins-plugin@1.0-SNAPSHOT",
},
},
},
@@ -154,6 +155,7 @@ func TestParseJar(t *testing.T) {
"Manifest-Version": "1.0",
},
},
PURL: "pkg:maven/example-java-app-gradle/example-java-app-gradle@0.1.0",
},
},
},
@@ -191,6 +193,7 @@ func TestParseJar(t *testing.T) {
Version: "0.1.0",
Extra: map[string]string{},
},
PURL: "pkg:maven/org.anchore/example-java-app-maven@0.1.0",
},
},
"joda-time": {
@@ -219,6 +222,7 @@ func TestParseJar(t *testing.T) {
Description: "Date and time library to replace JDK date handling",
URL: "http://www.joda.org/joda-time/",
},
PURL: "pkg:maven/joda-time/joda-time@2.9.2",
},
},
},
+25
View File
@@ -0,0 +1,25 @@
package java
import (
"github.com/anchore/packageurl-go"
"github.com/anchore/syft/syft/pkg"
"github.com/anchore/syft/syft/pkg/cataloger/common/cpe"
)
// PackageURL returns the PURL for the specific java package (see https://github.com/package-url/purl-spec)
func packageURL(p pkg.Package) string {
var groupID = p.Name
groupIDs := cpe.GroupIDsFromJavaPackage(p)
if len(groupIDs) > 0 {
groupID = groupIDs[0]
}
pURL := packageurl.NewPackageURL(
packageurl.TypeMaven, // TODO: should we filter down by package types here?
groupID,
p.Name,
p.Version,
nil, // TODO: there are probably several qualifiers that can be specified here
"")
return pURL.ToString()
}
@@ -0,0 +1,45 @@
package java
import (
"github.com/anchore/syft/syft/pkg"
"github.com/stretchr/testify/assert"
"testing"
)
func Test_packageURL(t *testing.T) {
tests := []struct {
pkg pkg.Package
expect string
}{
{
pkg: pkg.Package{
Name: "example-java-app-maven",
Version: "0.1.0",
Language: pkg.Java,
Type: pkg.JavaPkg,
MetadataType: pkg.JavaMetadataType,
Metadata: pkg.JavaMetadata{
VirtualPath: "test-fixtures/java-builds/packages/example-java-app-maven-0.1.0.jar",
Manifest: &pkg.JavaManifest{
Main: map[string]string{
"Manifest-Version": "1.0",
},
},
PomProperties: &pkg.PomProperties{
Path: "META-INF/maven/org.anchore/example-java-app-maven/pom.properties",
GroupID: "org.anchore",
ArtifactID: "example-java-app-maven",
Version: "0.1.0",
Extra: make(map[string]string),
},
},
},
expect: "pkg:maven/org.anchore/example-java-app-maven@0.1.0",
},
}
for _, tt := range tests {
t.Run(tt.expect, func(t *testing.T) {
assert.Equal(t, tt.expect, packageURL(tt.pkg))
})
}
}