Infer the package type from ELF package notes (#3008)

* fix ELF package types to be honored

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

* prefer OS packages over binary packages when there are duplicates

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-07-02 16:07:08 -04:00 committed by GitHub
parent c816039e91
commit 573440b7cf
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 62 additions and 8 deletions

View file

@ -10,7 +10,8 @@ import (
func TestMarinerDistroless(t *testing.T) {
sbom, _ := catalogFixtureImage(t, "image-mariner-distroless", source.SquashedScope)
expectedPkgs := 12
// 12 RPMs + 2 binaries with ELF package notes claiming to be RPMs
expectedPkgs := 14
actualPkgs := 0
for range sbom.Artifacts.Packages.Enumerate(pkg.RpmPkg) {
actualPkgs += 1

View file

@ -1,6 +1,7 @@
package relationship
import (
"reflect"
"slices"
"github.com/anchore/syft/internal/sbomsync"
@ -21,6 +22,10 @@ var (
binaryCatalogerTypes = []pkg.Type{
pkg.BinaryPkg,
}
binaryMetadataTypes = []string{
reflect.TypeOf(pkg.ELFBinaryPackageNoteJSONPayload{}).Name(),
reflect.TypeOf(pkg.BinarySignature{}).Name(),
}
)
func ExcludeBinariesByFileOwnershipOverlap(accessor sbomsync.Accessor) {
@ -60,5 +65,15 @@ func excludeBinaryByFileOwnershipOverlap(r artifact.Relationship, c *pkg.Collect
return false
}
return slices.Contains(binaryCatalogerTypes, child.Type)
if slices.Contains(binaryCatalogerTypes, child.Type) {
return true
}
if child.Metadata == nil {
return false
}
childMetadataType := reflect.TypeOf(child.Metadata)
return slices.Contains(binaryMetadataTypes, childMetadataType.Name())
}

View file

@ -12,7 +12,9 @@ func TestExclude(t *testing.T) {
packageB := pkg.Package{Name: "package-a", Type: pkg.PythonPkg}
packageC := pkg.Package{Name: "package-a", Type: pkg.BinaryPkg}
packageD := pkg.Package{Name: "package-d", Type: pkg.BinaryPkg}
for _, p := range []*pkg.Package{&packageA, &packageB, &packageC, &packageD} {
packageE := pkg.Package{Name: "package-e", Type: pkg.RpmPkg, Metadata: pkg.ELFBinaryPackageNoteJSONPayload{Type: "rpm"}}
packageF := pkg.Package{Name: "package-f", Type: pkg.RpmPkg, Metadata: pkg.BinarySignature{}}
for _, p := range []*pkg.Package{&packageA, &packageB, &packageC, &packageD, &packageE, &packageF} {
p := p
p.SetID()
}
@ -43,6 +45,26 @@ func TestExclude(t *testing.T) {
packages: pkg.NewCollection(packageA, packageC),
shouldExclude: true,
},
{
name: "exclusions from os -> elf binary (as RPM)",
relationship: artifact.Relationship{
Type: artifact.OwnershipByFileOverlapRelationship,
From: packageA,
To: packageE,
},
packages: pkg.NewCollection(packageA, packageE),
shouldExclude: true,
},
{
name: "exclusions from os -> binary (masquerading as RPM)",
relationship: artifact.Relationship{
Type: artifact.OwnershipByFileOverlapRelationship,
From: packageA,
To: packageF,
},
packages: pkg.NewCollection(packageA, packageF),
shouldExclude: true,
},
{
name: "no exclusions from python -> binary",
relationship: artifact.Relationship{

View file

@ -13,7 +13,7 @@ func newELFPackage(metadata elfBinaryPackageNotes, locations file.LocationSet) p
Version: metadata.Version,
Licenses: pkg.NewLicenseSet(pkg.NewLicense(metadata.License)),
PURL: packageURL(metadata),
Type: pkg.BinaryPkg,
Type: pkgType(metadata.Type),
Locations: locations,
Metadata: metadata.ELFBinaryPackageNoteJSONPayload,
}
@ -67,6 +67,8 @@ func packageURL(metadata elfBinaryPackageNotes) string {
).ToString()
}
const alpmType = "alpm"
func purlDistroType(ty string) string {
switch ty {
case "rpm":
@ -75,8 +77,22 @@ func purlDistroType(ty string) string {
return packageurl.TypeDebian
case "apk":
return packageurl.TypeAlpine
case "alpm":
return "alpm"
case alpmType:
return alpmType
}
return packageurl.TypeGeneric
}
func pkgType(ty string) pkg.Type {
switch ty {
case "rpm":
return pkg.RpmPkg
case "deb":
return pkg.DebPkg
case "apk":
return pkg.ApkPkg
case alpmType:
return pkg.AlpmPkg
}
return pkg.BinaryPkg
}

View file

@ -77,7 +77,7 @@ func Test_ELF_Package_Cataloger(t *testing.T) {
file.NewLocation("/sha1sum").WithAnnotation(pkg.EvidenceAnnotationKey, pkg.PrimaryEvidenceAnnotation),
),
Licenses: pkg.NewLicenseSet(),
Type: pkg.BinaryPkg,
Type: pkg.RpmPkg,
Metadata: pkg.ELFBinaryPackageNoteJSONPayload{
Type: "rpm",
Architecture: "x86_64",
@ -99,7 +99,7 @@ func Test_ELF_Package_Cataloger(t *testing.T) {
file.NewLocation("/sha1sum").WithAnnotation(pkg.EvidenceAnnotationKey, pkg.PrimaryEvidenceAnnotation),
),
Licenses: pkg.NewLicenseSet(),
Type: pkg.BinaryPkg,
Type: pkg.RpmPkg,
Metadata: pkg.ELFBinaryPackageNoteJSONPayload{
Type: "rpm",
Architecture: "arm",