Identify Jenkins plugin upstream of CPE generation

Signed-off-by: Dan Luhring <dan.luhring@anchore.com>
This commit is contained in:
Dan Luhring 2021-04-20 19:25:19 -04:00
parent fa7fd718cb
commit 33e6be0b74
No known key found for this signature in database
GPG Key ID: 9CEE23D079426CEF
6 changed files with 176 additions and 32 deletions

View File

@ -54,9 +54,6 @@ func (s candidateStore) getCandidates(t pkg.Type, key string) []string {
return value
}
const pomPropertiesGroupIDJenkinsPlugins = "com.cloudbees.jenkins.plugins"
const pomPropertiesGroupIDJiraPlugins = "com.atlassian.jira.plugins"
func newCPE(product, vendor, version, targetSW string) wfn.Attributes {
cpe := *(wfn.NewAttributesWithAny())
cpe.Part = "a"
@ -115,22 +112,9 @@ func candidateTargetSoftwareAttrs(p pkg.Package) []string {
return targetSw
}
func isJenkinsPlugin(p pkg.Package) bool {
if p.Type == pkg.JenkinsPluginPkg {
return true
}
if groupID := groupIDFromPomProperties(p); groupID == pomPropertiesGroupIDJenkinsPlugins {
return true
}
return false
}
func candidateTargetSoftwareAttrsForJava(p pkg.Package) []string {
// Use the more specific indicator if available
if isJenkinsPlugin(p) {
if p.Type == pkg.JenkinsPluginPkg {
return []string{"jenkins", "cloudbees_jenkins"}
}
@ -217,8 +201,8 @@ func shouldConsiderGroupID(groupID string) bool {
}
excludedGroupIDs := []string{
pomPropertiesGroupIDJiraPlugins,
pomPropertiesGroupIDJenkinsPlugins,
pkg.PomPropertiesGroupIDJiraPlugins,
pkg.PomPropertiesGroupIDJenkinsPlugins,
}
for _, excludedGroupID := range excludedGroupIDs {

View File

@ -156,7 +156,7 @@ func TestGeneratePackageCPEs(t *testing.T) {
Version: "3.2",
FoundBy: "some-analyzer",
Language: pkg.Java,
Type: pkg.JavaPkg,
Type: pkg.JenkinsPluginPkg,
Metadata: pkg.JavaMetadata{
PomProperties: &pkg.PomProperties{
GroupID: "com.cloudbees.jenkins.plugins",

View File

@ -186,14 +186,14 @@ func (j *archiveParser) discoverPkgsFromAllPomProperties(parentPkg *pkg.Package)
continue
}
pkgs = append(pkgs, j.packagesFromPomProperties(pomProperties, parentPkg)...)
pkgs = append(pkgs, j.packagesFromPomProperties(*pomProperties, parentPkg)...)
}
return pkgs, nil
}
// packagesFromPomProperties processes a single Maven POM properties for a given parent package, returning all listed Java packages found and
// associating each discovered package to the given parent package.
func (j *archiveParser) packagesFromPomProperties(pomProperties *pkg.PomProperties, parentPkg *pkg.Package) []pkg.Package {
func (j *archiveParser) packagesFromPomProperties(pomProperties pkg.PomProperties, parentPkg *pkg.Package) []pkg.Package {
// keep the artifact name within the virtual path if this package does not match the parent package
vPathSuffix := ""
if !strings.HasPrefix(pomProperties.ArtifactID, parentPkg.Name) {
@ -206,11 +206,11 @@ func (j *archiveParser) packagesFromPomProperties(pomProperties *pkg.PomProperti
Name: pomProperties.ArtifactID,
Version: pomProperties.Version,
Language: pkg.Java,
Type: pkg.JavaPkg,
Type: pomProperties.PkgTypeIndicated(),
MetadataType: pkg.JavaMetadataType,
Metadata: pkg.JavaMetadata{
VirtualPath: virtualPath,
PomProperties: pomProperties,
PomProperties: &pomProperties,
Parent: parentPkg,
},
}
@ -243,10 +243,13 @@ func (j *archiveParser) packagesFromPomProperties(pomProperties *pkg.PomProperti
parentPkg.Version = p.Version
}
// We may have learned more about the type via data in the pom properties
parentPkg.Type = p.Type
// keep the pom properties, but don't overwrite existing pom properties
parentMetadata, ok := parentPkg.Metadata.(pkg.JavaMetadata)
if ok && parentMetadata.PomProperties == nil {
parentMetadata.PomProperties = pomProperties
parentMetadata.PomProperties = &pomProperties
parentPkg.Metadata = parentMetadata
}

View File

@ -629,12 +629,12 @@ func TestPackagesFromPomProperties(t *testing.T) {
},
},
{
name: "child matches parent by key",
name: "single package from pom properties that's a Jenkins plugin",
props: &pkg.PomProperties{
Name: "some-name",
GroupID: "some-group-id",
ArtifactID: "some-parent-name", // note: matches parent package
Version: "2.0", // note: matches parent package
GroupID: "com.cloudbees.jenkins.plugins",
ArtifactID: "some-artifact-id",
Version: "1.0",
},
parent: &pkg.Package{
Name: "some-parent-name",
@ -650,6 +650,66 @@ func TestPackagesFromPomProperties(t *testing.T) {
expectedParent: pkg.Package{
Name: "some-parent-name",
Version: "2.0",
Metadata: pkg.JavaMetadata{
VirtualPath: "some-parent-virtual-path",
Manifest: nil,
PomProperties: nil,
Parent: nil,
},
},
expectedPackages: []pkg.Package{
{
Name: "some-artifact-id",
Version: "1.0",
Language: pkg.Java,
Type: pkg.JenkinsPluginPkg,
MetadataType: pkg.JavaMetadataType,
Metadata: pkg.JavaMetadata{
VirtualPath: virtualPath + ":" + "some-artifact-id",
PomProperties: &pkg.PomProperties{
Name: "some-name",
GroupID: "com.cloudbees.jenkins.plugins",
ArtifactID: "some-artifact-id",
Version: "1.0",
},
Parent: &pkg.Package{
Name: "some-parent-name",
Version: "2.0",
Metadata: pkg.JavaMetadata{
VirtualPath: "some-parent-virtual-path",
Manifest: nil,
PomProperties: nil,
Parent: nil,
},
},
},
},
},
},
{
name: "child matches parent by key",
props: &pkg.PomProperties{
Name: "some-name",
GroupID: "some-group-id",
ArtifactID: "some-parent-name", // note: matches parent package
Version: "2.0", // note: matches parent package
},
parent: &pkg.Package{
Name: "some-parent-name",
Version: "2.0",
Type: pkg.JavaPkg,
Metadata: pkg.JavaMetadata{
VirtualPath: "some-parent-virtual-path",
Manifest: nil,
PomProperties: nil,
Parent: nil,
},
},
// note: the SAME as the original parent values
expectedParent: pkg.Package{
Name: "some-parent-name",
Version: "2.0",
Type: pkg.JavaPkg,
Metadata: pkg.JavaMetadata{
VirtualPath: "some-parent-virtual-path",
Manifest: nil,
@ -665,6 +725,44 @@ func TestPackagesFromPomProperties(t *testing.T) {
},
expectedPackages: nil,
},
{
name: "child matches parent by key and is Jenkins plugin",
props: &pkg.PomProperties{
Name: "some-name",
GroupID: "com.cloudbees.jenkins.plugins",
ArtifactID: "some-parent-name", // note: matches parent package
Version: "2.0", // note: matches parent package
},
parent: &pkg.Package{
Name: "some-parent-name",
Version: "2.0",
Type: pkg.JavaPkg,
Metadata: pkg.JavaMetadata{
VirtualPath: "some-parent-virtual-path",
Manifest: nil,
PomProperties: nil,
Parent: nil,
},
},
expectedParent: pkg.Package{
Name: "some-parent-name",
Version: "2.0",
Type: pkg.JenkinsPluginPkg,
Metadata: pkg.JavaMetadata{
VirtualPath: "some-parent-virtual-path",
Manifest: nil,
// note: we attach the discovered pom properties data
PomProperties: &pkg.PomProperties{
Name: "some-name",
GroupID: "com.cloudbees.jenkins.plugins",
ArtifactID: "some-parent-name", // note: matches parent package
Version: "2.0", // note: matches parent package
},
Parent: nil,
},
},
expectedPackages: nil,
},
{
name: "child matches parent by virtual path",
props: &pkg.PomProperties{
@ -676,6 +774,7 @@ func TestPackagesFromPomProperties(t *testing.T) {
parent: &pkg.Package{
Name: "some-parent-name",
Version: "2.0",
Type: pkg.JavaPkg,
Metadata: pkg.JavaMetadata{
VirtualPath: virtualPath + ":some-parent-name", // note: matching virtual path
Manifest: nil,
@ -686,6 +785,7 @@ func TestPackagesFromPomProperties(t *testing.T) {
expectedParent: pkg.Package{
Name: "some-parent-name",
Version: "2.0",
Type: pkg.JavaPkg,
Metadata: pkg.JavaMetadata{
VirtualPath: virtualPath + ":some-parent-name", // note: matching virtual path
Manifest: nil,
@ -712,6 +812,7 @@ func TestPackagesFromPomProperties(t *testing.T) {
parent: &pkg.Package{
Name: "", // note: empty
Version: "", // note: empty
Type: pkg.JavaPkg,
Metadata: pkg.JavaMetadata{
VirtualPath: virtualPath + ":some-parent-name", // note: matching virtual path
Manifest: nil,
@ -722,6 +823,7 @@ func TestPackagesFromPomProperties(t *testing.T) {
expectedParent: pkg.Package{
Name: "some-parent-name",
Version: "3.0",
Type: pkg.JavaPkg,
Metadata: pkg.JavaMetadata{
VirtualPath: virtualPath + ":some-parent-name", // note: matching virtual path
Manifest: nil,
@ -748,11 +850,12 @@ func TestPackagesFromPomProperties(t *testing.T) {
parent: &pkg.Package{
Name: "some-parent-name",
Version: "2.0",
Type: pkg.JavaPkg,
Metadata: pkg.JavaMetadata{
VirtualPath: virtualPath + ":some-parent-name", // note: matching virtual path
Manifest: nil,
PomProperties: &pkg.PomProperties{
Name: "EXISTS", //note: this already exists and should not be overridden
Name: "EXISTS", // note: this already exists and should not be overridden
},
Parent: nil,
},
@ -760,12 +863,13 @@ func TestPackagesFromPomProperties(t *testing.T) {
expectedParent: pkg.Package{
Name: "some-parent-name",
Version: "2.0",
Type: pkg.JavaPkg,
Metadata: pkg.JavaMetadata{
VirtualPath: virtualPath + ":some-parent-name", // note: matching virtual path
Manifest: nil,
// note: we attach the discovered pom properties data
PomProperties: &pkg.PomProperties{
Name: "EXISTS", //note: this already exists and should not be overridden
Name: "EXISTS", // note: this already exists and should not be overridden
},
Parent: nil,
},
@ -783,6 +887,7 @@ func TestPackagesFromPomProperties(t *testing.T) {
parent: &pkg.Package{
Name: "some-parent-name",
Version: "2.0",
Type: pkg.JavaPkg,
Metadata: pkg.JavaMetadata{
VirtualPath: virtualPath + ":NEW_VIRTUAL_PATH", // note: DOES NOT match the existing virtual path
Manifest: nil,
@ -794,6 +899,7 @@ func TestPackagesFromPomProperties(t *testing.T) {
expectedParent: pkg.Package{
Name: "some-parent-name",
Version: "2.0",
Type: pkg.JavaPkg,
Metadata: pkg.JavaMetadata{
VirtualPath: virtualPath + ":NEW_VIRTUAL_PATH",
Manifest: nil,
@ -823,7 +929,7 @@ func TestPackagesFromPomProperties(t *testing.T) {
t.Cleanup(cleanup)
// get the test data
actualPackages := parser.packagesFromPomProperties(test.props, test.parent)
actualPackages := parser.packagesFromPomProperties(*test.props, test.parent)
assert.Equal(t, test.expectedPackages, actualPackages)
assert.Equal(t, test.expectedParent, *test.parent)
})

View File

@ -20,6 +20,15 @@ type PomProperties struct {
Extra map[string]string `mapstructure:",remain" json:"extraFields"`
}
// PkgTypeIndicated returns the package Type indicated by the data contained in the PomProperties.
func (p PomProperties) PkgTypeIndicated() Type {
if p.GroupID == PomPropertiesGroupIDJenkinsPlugins {
return JenkinsPluginPkg
}
return JavaPkg
}
// JavaManifest represents the fields of interest extracted from a Java archive's META-INF/MANIFEST.MF file.
type JavaManifest struct {
Main map[string]string `json:"main,omitempty"`
@ -43,3 +52,6 @@ func (m JavaMetadata) PackageURL() string {
return ""
}
const PomPropertiesGroupIDJenkinsPlugins = "com.cloudbees.jenkins.plugins"
const PomPropertiesGroupIDJiraPlugins = "com.atlassian.jira.plugins"

View File

@ -2,9 +2,48 @@ package pkg
import (
"github.com/sergi/go-diff/diffmatchpatch"
"github.com/stretchr/testify/assert"
"testing"
)
func TestPomProperties_PkgTypeIndicated(t *testing.T) {
cases := []struct {
name string
pomProperties PomProperties
expectedType Type
}{
{
name: "regular Java package",
pomProperties: PomProperties{
Path: "some path",
Name: "some name",
GroupID: "some group ID",
ArtifactID: "some artifact ID",
Version: "1",
},
expectedType: JavaPkg,
},
{
name: "jenkins plugin",
pomProperties: PomProperties{
Path: "some path",
Name: "some name",
GroupID: "com.cloudbees.jenkins.plugins",
ArtifactID: "some artifact ID",
Version: "1",
},
expectedType: JenkinsPluginPkg,
},
}
for _, tc := range cases {
t.Run(tc.name, func(t *testing.T) {
actual := tc.pomProperties.PkgTypeIndicated()
assert.Equal(t, tc.expectedType, actual)
})
}
}
func TestJavaMetadata_pURL(t *testing.T) {
tests := []struct {
metadata JavaMetadata