Add JVM cataloger (#3217)

* add jvm cataloger

Signed-off-by: Alex Goodman <wagoodman@users.noreply.github.com>

* simplify version selection

Signed-off-by: Alex Goodman <wagoodman@users.noreply.github.com>

* CPEs from JVM cataloger should be declared

Signed-off-by: Alex Goodman <wagoodman@users.noreply.github.com>

* ensure package overlap is enabled for sensitive use cases

Signed-off-by: Alex Goodman <wagoodman@users.noreply.github.com>

* more permissive glob

Signed-off-by: Alex Goodman <wagoodman@users.noreply.github.com>

---------

Signed-off-by: Alex Goodman <wagoodman@users.noreply.github.com>
This commit is contained in:
Alex Goodman
2024-09-23 17:21:38 -04:00
committed by GitHub
parent 7815d8e4d9
commit 01de99b253
25 changed files with 4271 additions and 81 deletions
@@ -25,55 +25,102 @@ var (
binaryMetadataTypes = []string{
reflect.TypeOf(pkg.ELFBinaryPackageNoteJSONPayload{}).Name(),
reflect.TypeOf(pkg.BinarySignature{}).Name(),
reflect.TypeOf(pkg.JavaVMInstallation{}).Name(),
}
)
func ExcludeBinariesByFileOwnershipOverlap(accessor sbomsync.Accessor) {
accessor.WriteToSBOM(func(s *sbom.SBOM) {
for _, r := range s.Relationships {
if excludeBinaryByFileOwnershipOverlap(r, s.Artifacts.Packages) {
s.Artifacts.Packages.Delete(r.To.ID())
s.Relationships = RemoveRelationshipsByID(s.Relationships, r.To.ID())
if idToRemove := excludeByFileOwnershipOverlap(r, s.Artifacts.Packages); idToRemove != "" {
s.Artifacts.Packages.Delete(idToRemove)
s.Relationships = RemoveRelationshipsByID(s.Relationships, idToRemove)
}
}
})
}
// excludeBinaryByFileOwnershipOverlap will remove packages from a collection given the following properties are true
// 1) the relationship between packages is OwnershipByFileOverlap
// 2) the parent is an "os" package
// 3) the child is a synthetic package generated by the binary cataloger
// 4) the package names are identical
// This was implemented as a way to help resolve: https://github.com/anchore/syft/issues/931
func excludeBinaryByFileOwnershipOverlap(r artifact.Relationship, c *pkg.Collection) bool {
// excludeByFileOwnershipOverlap will remove packages that should be overridden by a more authoritative package,
// such as an OS package or a package from a cataloger with more specific information being raised up.
func excludeByFileOwnershipOverlap(r artifact.Relationship, c *pkg.Collection) artifact.ID {
if artifact.OwnershipByFileOverlapRelationship != r.Type {
return false
return ""
}
parent := c.Package(r.From.ID())
if parent == nil {
return false
}
parentInExclusion := slices.Contains(osCatalogerTypes, parent.Type)
if !parentInExclusion {
return false
return ""
}
child := c.Package(r.To.ID())
if child == nil {
return false
return ""
}
if slices.Contains(binaryCatalogerTypes, child.Type) {
return true
if idToRemove := identifyOverlappingOSRelationship(parent, child); idToRemove != "" {
return idToRemove
}
if idToRemove := identifyOverlappingJVMRelationship(parent, child); idToRemove != "" {
return idToRemove
}
return ""
}
// identifyOverlappingJVMRelationship indicates the package to remove if this is a binary -> binary pkg relationship
// with a java binary signature package and a more authoritative JVM release package.
func identifyOverlappingJVMRelationship(parent *pkg.Package, child *pkg.Package) artifact.ID {
if !slices.Contains(binaryCatalogerTypes, parent.Type) {
return ""
}
if !slices.Contains(binaryCatalogerTypes, child.Type) {
return ""
}
if child.Metadata == nil {
return false
return ""
}
childMetadataType := reflect.TypeOf(child.Metadata)
var (
foundJVM bool
idToRemove artifact.ID
)
for _, p := range []*pkg.Package{parent, child} {
switch p.Metadata.(type) {
case pkg.JavaVMInstallation:
foundJVM = true
default:
idToRemove = p.ID()
}
}
return slices.Contains(binaryMetadataTypes, childMetadataType.Name())
if foundJVM {
return idToRemove
}
return ""
}
// identifyOverlappingOSRelationship indicates the package ID to remove if this is an OS pkg -> bin pkg relationship.
// This was implemented as a way to help resolve: https://github.com/anchore/syft/issues/931
func identifyOverlappingOSRelationship(parent *pkg.Package, child *pkg.Package) artifact.ID {
if !slices.Contains(osCatalogerTypes, parent.Type) {
return ""
}
if slices.Contains(binaryCatalogerTypes, child.Type) {
return child.ID()
}
if child.Metadata == nil {
return ""
}
if !slices.Contains(binaryMetadataTypes, reflect.TypeOf(child.Metadata).Name()) {
return ""
}
return child.ID()
}