mirror of
https://github.com/anchore/syft.git
synced 2025-11-18 00:43:20 +01:00
* prototype: start bitnami cataloger Bitnami images have spdx SBOMs at predictable paths, and Syft could more accurately identify the software in these images by scanning those SBOMs. Start work on this by forking the sbom-cataloger as a new bitnami-cataloger. Signed-off-by: Will Murphy <willmurphyscode@users.noreply.github.com> * wire up bitnami cataloger to run on images by default Signed-off-by: Will Murphy <willmurphyscode@users.noreply.github.com> * feat: add support for Bitnami cataloguer Signed-off-by: juan131 <jariza@vmware.com> * feat: use a better SPDX sample for unit tests Signed-off-by: juan131 <jariza@vmware.com> * bugfix: only report bitnami pkgs Signed-off-by: juan131 <jariza@vmware.com> * feat: adapt JSON schema, spdxutil and packagemetadata Signed-off-by: juan131 <jariza@vmware.com> * bugfix: integration tests Signed-off-by: juan131 <jariza@vmware.com> * feat: implement FileOwner interface Signed-off-by: juan131 <jariza@vmware.com> * bugfix: update json schema Signed-off-by: juan131 <jariza@vmware.com> * [wip] add bitnami owned files and fix binary package ownership filtering Signed-off-by: Alex Goodman <wagoodman@users.noreply.github.com> * feat: obtain bitnami pkg files based on SPDX relationships tree Signed-off-by: juan131 <jariza@vmware.com> * preserve type switches Signed-off-by: Alex Goodman <wagoodman@users.noreply.github.com> * rename bitnami entry metadata type Signed-off-by: Alex Goodman <wagoodman@users.noreply.github.com> * restrict find main pkg logic Signed-off-by: Alex Goodman <wagoodman@users.noreply.github.com> * add missing graalvm source info Signed-off-by: Alex Goodman <wagoodman@users.noreply.github.com> * bugfix: integration tests Signed-off-by: juan131 <jariza@vmware.com> * bugfix: mod tidy Signed-off-by: juan131 <jariza@vmware.com> --------- Signed-off-by: Will Murphy <willmurphyscode@users.noreply.github.com> Signed-off-by: juan131 <jariza@vmware.com> Signed-off-by: Alex Goodman <wagoodman@users.noreply.github.com> Co-authored-by: Will Murphy <willmurphyscode@users.noreply.github.com> Co-authored-by: Alex Goodman <wagoodman@users.noreply.github.com>
246 lines
7.6 KiB
Go
246 lines
7.6 KiB
Go
package relationship
|
|
|
|
import (
|
|
"testing"
|
|
|
|
"github.com/stretchr/testify/assert"
|
|
|
|
"github.com/anchore/syft/syft/artifact"
|
|
"github.com/anchore/syft/syft/pkg"
|
|
)
|
|
|
|
func TestExcludeByFileOwnershipOverlap(t *testing.T) {
|
|
packageA := pkg.Package{Name: "package-a", Type: pkg.ApkPkg}
|
|
packageB := pkg.Package{Name: "package-b", Type: pkg.BinaryPkg, Metadata: pkg.JavaVMInstallation{}}
|
|
packageC := pkg.Package{Name: "package-c", Type: pkg.BinaryPkg, Metadata: pkg.ELFBinaryPackageNoteJSONPayload{Type: "rpm"}}
|
|
packageD := pkg.Package{Name: "package-d", Type: pkg.BitnamiPkg}
|
|
for _, p := range []*pkg.Package{&packageA, &packageB, &packageC, &packageD} {
|
|
p := p
|
|
p.SetID()
|
|
}
|
|
|
|
tests := []struct {
|
|
name string
|
|
relationship artifact.Relationship
|
|
packages *pkg.Collection
|
|
shouldExclude bool
|
|
}{
|
|
{
|
|
// prove that OS -> bin exclusions are wired
|
|
name: "exclusions from os -> elf binary (as RPM)",
|
|
relationship: artifact.Relationship{
|
|
Type: artifact.OwnershipByFileOverlapRelationship,
|
|
From: packageA, // OS
|
|
To: packageC, // ELF binary
|
|
},
|
|
packages: pkg.NewCollection(packageA, packageC),
|
|
shouldExclude: true,
|
|
},
|
|
{
|
|
// prove that bin -> JVM exclusions are wired
|
|
name: "exclusions from binary -> binary with JVM metadata",
|
|
relationship: artifact.Relationship{
|
|
Type: artifact.OwnershipByFileOverlapRelationship,
|
|
From: packageB, // binary with JVM metadata
|
|
To: packageC, // binary
|
|
},
|
|
packages: pkg.NewCollection(packageC, packageB),
|
|
shouldExclude: true,
|
|
},
|
|
{
|
|
// prove that Bitnami -> bin exclusions are wired
|
|
name: "exclusions from bitnami -> binary",
|
|
relationship: artifact.Relationship{
|
|
Type: artifact.OwnershipByFileOverlapRelationship,
|
|
From: packageD, // Bitnami
|
|
To: packageC, // ELF binary
|
|
},
|
|
packages: pkg.NewCollection(packageD, packageC),
|
|
shouldExclude: true,
|
|
},
|
|
}
|
|
|
|
for _, test := range tests {
|
|
t.Run(test.name, func(t *testing.T) {
|
|
actualExclude := excludeByFileOwnershipOverlap(test.relationship, test.packages)
|
|
didExclude := actualExclude != ""
|
|
if !didExclude && test.shouldExclude {
|
|
t.Errorf("expected to exclude relationship %+v", test.relationship)
|
|
}
|
|
})
|
|
|
|
}
|
|
}
|
|
|
|
func TestIdentifyOverlappingOSRelationship(t *testing.T) {
|
|
packageA := pkg.Package{Name: "package-a", Type: pkg.ApkPkg} // OS package
|
|
packageB := pkg.Package{Name: "package-b", Type: pkg.BinaryPkg}
|
|
packageC := pkg.Package{Name: "package-c", Type: pkg.BinaryPkg, Metadata: pkg.BinarySignature{}}
|
|
packageD := pkg.Package{Name: "package-d", Type: pkg.PythonPkg} // Language package
|
|
packageE := pkg.Package{Name: "package-e", Type: pkg.BinaryPkg, Metadata: pkg.ELFBinaryPackageNoteJSONPayload{}}
|
|
|
|
for _, p := range []*pkg.Package{&packageA, &packageB, &packageC, &packageD, &packageE} {
|
|
p.SetID()
|
|
}
|
|
|
|
tests := []struct {
|
|
name string
|
|
parent *pkg.Package
|
|
child *pkg.Package
|
|
expectedID artifact.ID
|
|
}{
|
|
{
|
|
name: "OS -> binary without metadata",
|
|
parent: &packageA,
|
|
child: &packageB,
|
|
expectedID: packageB.ID(), // OS package to binary package, should return child ID
|
|
},
|
|
{
|
|
name: "OS -> binary with binary metadata",
|
|
parent: &packageA,
|
|
child: &packageC,
|
|
expectedID: packageC.ID(), // OS package to binary package with binary metadata, should return child ID
|
|
},
|
|
{
|
|
name: "OS -> non-binary package",
|
|
parent: &packageA,
|
|
child: &packageD,
|
|
expectedID: "", // OS package to non-binary package, no exclusion
|
|
},
|
|
{
|
|
name: "OS -> binary with ELF metadata",
|
|
parent: &packageA,
|
|
child: &packageE,
|
|
expectedID: packageE.ID(), // OS package to binary package with ELF metadata, should return child ID
|
|
},
|
|
{
|
|
name: "non-OS parent",
|
|
parent: &packageD, // non-OS package
|
|
child: &packageC,
|
|
expectedID: "", // non-OS parent, no exclusion
|
|
},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
resultID := identifyOverlappingOSRelationship(tt.parent, tt.child)
|
|
assert.Equal(t, tt.expectedID, resultID)
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestIdentifyOverlappingBitnamiRelationship(t *testing.T) {
|
|
packageA := pkg.Package{Name: "package-a", Type: pkg.BitnamiPkg} // Bitnami package
|
|
packageB := pkg.Package{Name: "package-b", Type: pkg.BinaryPkg}
|
|
packageC := pkg.Package{Name: "package-c", Type: pkg.BinaryPkg, Metadata: pkg.BinarySignature{}}
|
|
packageD := pkg.Package{Name: "package-d", Type: pkg.PythonPkg} // Language package
|
|
packageE := pkg.Package{Name: "package-e", Type: pkg.BinaryPkg, Metadata: pkg.ELFBinaryPackageNoteJSONPayload{}}
|
|
|
|
for _, p := range []*pkg.Package{&packageA, &packageB, &packageC, &packageD, &packageE} {
|
|
p.SetID()
|
|
}
|
|
|
|
tests := []struct {
|
|
name string
|
|
parent *pkg.Package
|
|
child *pkg.Package
|
|
expectedID artifact.ID
|
|
}{
|
|
{
|
|
name: "Bitnami -> binary without metadata",
|
|
parent: &packageA,
|
|
child: &packageB,
|
|
expectedID: packageB.ID(), // Bitnami package to binary package, should return child ID
|
|
},
|
|
{
|
|
name: "Bitnami -> binary with binary metadata",
|
|
parent: &packageA,
|
|
child: &packageC,
|
|
expectedID: packageC.ID(), // Bitnami package to binary package with binary metadata, should return child ID
|
|
},
|
|
{
|
|
name: "Bitnami -> non-binary package",
|
|
parent: &packageA,
|
|
child: &packageD,
|
|
expectedID: "", // Bitnami package to non-binary package, no exclusion
|
|
},
|
|
{
|
|
name: "Bitnami -> binary with ELF metadata",
|
|
parent: &packageA,
|
|
child: &packageE,
|
|
expectedID: packageE.ID(), // Bitnami package to binary package with ELF metadata, should return child ID
|
|
},
|
|
{
|
|
name: "non-Bitnami parent",
|
|
parent: &packageD, // non-Bitnami package
|
|
child: &packageC,
|
|
expectedID: "", // non-Bitnami parent, no exclusion
|
|
},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
resultID := identifyOverlappingBitnamiRelationship(tt.parent, tt.child)
|
|
assert.Equal(t, tt.expectedID, resultID)
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestIdentifyOverlappingJVMRelationship(t *testing.T) {
|
|
|
|
packageA := pkg.Package{Name: "package-a", Type: pkg.BinaryPkg}
|
|
packageB := pkg.Package{Name: "package-b", Type: pkg.BinaryPkg, Metadata: pkg.BinarySignature{}}
|
|
packageC := pkg.Package{Name: "package-c", Type: pkg.BinaryPkg, Metadata: pkg.JavaVMInstallation{}}
|
|
packageD := pkg.Package{Name: "package-d", Type: pkg.PythonPkg}
|
|
packageE := pkg.Package{Name: "package-e", Type: pkg.BinaryPkg}
|
|
|
|
for _, p := range []*pkg.Package{&packageA, &packageB, &packageC, &packageD, &packageE} {
|
|
p.SetID()
|
|
}
|
|
|
|
tests := []struct {
|
|
name string
|
|
parent *pkg.Package
|
|
child *pkg.Package
|
|
expectedID artifact.ID
|
|
}{
|
|
{
|
|
name: "binary -> binary with JVM installation",
|
|
parent: &packageA,
|
|
child: &packageC,
|
|
expectedID: packageA.ID(), // JVM found, return BinaryPkg ID
|
|
},
|
|
{
|
|
name: "binary -> binary with binary signature",
|
|
parent: &packageA,
|
|
child: &packageB,
|
|
expectedID: "", // binary signatures only found, no exclusion
|
|
},
|
|
{
|
|
name: "binary -> python (non-binary child)",
|
|
parent: &packageA,
|
|
child: &packageD,
|
|
expectedID: "", // non-binary child, no exclusion
|
|
},
|
|
{
|
|
name: "no JVM or signature in binary -> binary",
|
|
parent: &packageA,
|
|
child: &packageE,
|
|
expectedID: "", // no JVM or binary signature, no exclusion
|
|
},
|
|
{
|
|
name: "non-binary parent",
|
|
parent: &packageD,
|
|
child: &packageC,
|
|
expectedID: "", // non-binary parent, no exclusion
|
|
},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
resultID := identifyOverlappingJVMRelationship(tt.parent, tt.child)
|
|
assert.Equal(t, tt.expectedID, resultID)
|
|
})
|
|
}
|
|
}
|