mirror of
https://github.com/anchore/syft.git
synced 2025-11-17 08:23:15 +01:00
feat: add support for Bitnami cataloguer (#3341)
* 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>
This commit is contained in:
parent
869908ece1
commit
bffe26bcc5
@ -9,3 +9,7 @@ A cataloger contributed by Oracle Corporation that extracts packages given withi
|
|||||||
## Swift Package Manager
|
## Swift Package Manager
|
||||||
|
|
||||||
A cataloger contributed by Axis Communications that catalogs packages resolved by Swift Package Manager.
|
A cataloger contributed by Axis Communications that catalogs packages resolved by Swift Package Manager.
|
||||||
|
|
||||||
|
## Bitnami Packages
|
||||||
|
|
||||||
|
A cataloger contributed by Bitnami developer that catalogs packages described in Bitnami SBOMs.
|
||||||
|
|||||||
@ -123,6 +123,7 @@ Note that flags using the @<version> can be used for earlier versions of each sp
|
|||||||
### Supported Ecosystems
|
### Supported Ecosystems
|
||||||
|
|
||||||
- Alpine (apk)
|
- Alpine (apk)
|
||||||
|
- Bitnami packages
|
||||||
- C (conan)
|
- C (conan)
|
||||||
- C++ (conan)
|
- C++ (conan)
|
||||||
- Dart (pubs)
|
- Dart (pubs)
|
||||||
|
|||||||
@ -74,6 +74,8 @@ func TestPkgCoverageImage(t *testing.T) {
|
|||||||
definedPkgs.Remove(string(pkg.ConanPkg))
|
definedPkgs.Remove(string(pkg.ConanPkg))
|
||||||
definedPkgs.Remove(string(pkg.HackagePkg))
|
definedPkgs.Remove(string(pkg.HackagePkg))
|
||||||
definedPkgs.Remove(string(pkg.BinaryPkg))
|
definedPkgs.Remove(string(pkg.BinaryPkg))
|
||||||
|
definedPkgs.Remove(string(pkg.BitnamiPkg))
|
||||||
|
definedPkgs.Remove(string(pkg.GraalVMNativeImagePkg))
|
||||||
definedPkgs.Remove(string(pkg.HexPkg))
|
definedPkgs.Remove(string(pkg.HexPkg))
|
||||||
definedPkgs.Remove(string(pkg.LinuxKernelPkg))
|
definedPkgs.Remove(string(pkg.LinuxKernelPkg))
|
||||||
definedPkgs.Remove(string(pkg.LinuxKernelModulePkg))
|
definedPkgs.Remove(string(pkg.LinuxKernelModulePkg))
|
||||||
@ -219,6 +221,8 @@ func TestPkgCoverageDirectory(t *testing.T) {
|
|||||||
definedLanguages.Remove(pkg.R.String())
|
definedLanguages.Remove(pkg.R.String())
|
||||||
observedPkgs.Remove(string(pkg.UnknownPkg))
|
observedPkgs.Remove(string(pkg.UnknownPkg))
|
||||||
definedPkgs.Remove(string(pkg.BinaryPkg))
|
definedPkgs.Remove(string(pkg.BinaryPkg))
|
||||||
|
definedPkgs.Remove(string(pkg.BitnamiPkg))
|
||||||
|
definedPkgs.Remove(string(pkg.GraalVMNativeImagePkg))
|
||||||
definedPkgs.Remove(string(pkg.LinuxKernelPkg))
|
definedPkgs.Remove(string(pkg.LinuxKernelPkg))
|
||||||
definedPkgs.Remove(string(pkg.LinuxKernelModulePkg))
|
definedPkgs.Remove(string(pkg.LinuxKernelModulePkg))
|
||||||
definedPkgs.Remove(string(pkg.Rpkg))
|
definedPkgs.Remove(string(pkg.Rpkg))
|
||||||
|
|||||||
1
go.mod
1
go.mod
@ -90,6 +90,7 @@ require (
|
|||||||
github.com/OneOfOne/xxhash v1.2.8
|
github.com/OneOfOne/xxhash v1.2.8
|
||||||
github.com/adrg/xdg v0.5.3
|
github.com/adrg/xdg v0.5.3
|
||||||
github.com/anchore/archiver/v3 v3.5.3-0.20241210171143-5b1d8d1c7c51
|
github.com/anchore/archiver/v3 v3.5.3-0.20241210171143-5b1d8d1c7c51
|
||||||
|
github.com/bitnami/go-version v0.0.0-20250131085805-b1f57a8634ef
|
||||||
github.com/hashicorp/hcl/v2 v2.23.0
|
github.com/hashicorp/hcl/v2 v2.23.0
|
||||||
github.com/magiconair/properties v1.8.9
|
github.com/magiconair/properties v1.8.9
|
||||||
golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56
|
golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56
|
||||||
|
|||||||
2
go.sum
2
go.sum
@ -149,6 +149,8 @@ github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24
|
|||||||
github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
|
github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
|
||||||
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
|
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
|
||||||
github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs=
|
github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs=
|
||||||
|
github.com/bitnami/go-version v0.0.0-20250131085805-b1f57a8634ef h1:TSFnfbbu2oAOuWbeDDTtwXWE6z+PmpgbSsMBeV7l0ww=
|
||||||
|
github.com/bitnami/go-version v0.0.0-20250131085805-b1f57a8634ef/go.mod h1:9iglf1GG4oNRJ39bZ5AZrjgAFD2RwQbXw6Qf7Cs47wo=
|
||||||
github.com/bmatcuk/doublestar/v4 v4.8.1 h1:54Bopc5c2cAvhLRAzqOGCYHYyhcDHsFF4wWIR5wKP38=
|
github.com/bmatcuk/doublestar/v4 v4.8.1 h1:54Bopc5c2cAvhLRAzqOGCYHYyhcDHsFF4wWIR5wKP38=
|
||||||
github.com/bmatcuk/doublestar/v4 v4.8.1/go.mod h1:xBQ8jztBU6kakFMg+8WGxn0c6z1fTSPVIjEY1Wr7jzc=
|
github.com/bmatcuk/doublestar/v4 v4.8.1/go.mod h1:xBQ8jztBU6kakFMg+8WGxn0c6z1fTSPVIjEY1Wr7jzc=
|
||||||
github.com/bradleyjkemp/cupaloy/v2 v2.8.0 h1:any4BmKE+jGIaMpnU8YgH/I2LPiLBufr6oMMlVBbn9M=
|
github.com/bradleyjkemp/cupaloy/v2 v2.8.0 h1:any4BmKE+jGIaMpnU8YgH/I2LPiLBufr6oMMlVBbn9M=
|
||||||
|
|||||||
@ -3,5 +3,5 @@ package internal
|
|||||||
const (
|
const (
|
||||||
// JSONSchemaVersion is the current schema version output by the JSON encoder
|
// JSONSchemaVersion is the current schema version output by the JSON encoder
|
||||||
// This is roughly following the "SchemaVer" guidelines for versioning the JSON schema. Please see schema/json/README.md for details on how to increment.
|
// This is roughly following the "SchemaVer" guidelines for versioning the JSON schema. Please see schema/json/README.md for details on how to increment.
|
||||||
JSONSchemaVersion = "16.0.21"
|
JSONSchemaVersion = "16.0.22"
|
||||||
)
|
)
|
||||||
|
|||||||
@ -58,11 +58,10 @@ func generateRelationships(resolver file.Resolver, accessor sbomsync.Accessor, i
|
|||||||
|
|
||||||
// PackagesToRemove returns a list of binary packages (resolved by the ELF cataloger) that should be removed from the SBOM
|
// PackagesToRemove returns a list of binary packages (resolved by the ELF cataloger) that should be removed from the SBOM
|
||||||
// These packages are removed because they are already represented by a higher order packages in the SBOM.
|
// These packages are removed because they are already represented by a higher order packages in the SBOM.
|
||||||
func PackagesToRemove(resolver file.Resolver, accessor sbomsync.Accessor) []artifact.ID {
|
func PackagesToRemove(accessor sbomsync.Accessor) []artifact.ID {
|
||||||
pkgsToDelete := make([]artifact.ID, 0)
|
pkgsToDelete := make([]artifact.ID, 0)
|
||||||
accessor.ReadFromSBOM(func(s *sbom.SBOM) {
|
accessor.ReadFromSBOM(func(s *sbom.SBOM) {
|
||||||
// OTHER package type > ELF package type > Binary package type
|
// ELF package type > Binary package type
|
||||||
pkgsToDelete = append(pkgsToDelete, getBinaryPackagesToDelete(resolver, s)...)
|
|
||||||
pkgsToDelete = append(pkgsToDelete, compareElfBinaryPackages(s)...)
|
pkgsToDelete = append(pkgsToDelete, compareElfBinaryPackages(s)...)
|
||||||
})
|
})
|
||||||
return pkgsToDelete
|
return pkgsToDelete
|
||||||
@ -114,33 +113,6 @@ func isElfPackage(p pkg.Package) bool {
|
|||||||
return ok
|
return ok
|
||||||
}
|
}
|
||||||
|
|
||||||
func getBinaryPackagesToDelete(resolver file.Resolver, s *sbom.SBOM) []artifact.ID {
|
|
||||||
pkgsToDelete := make([]artifact.ID, 0)
|
|
||||||
for p := range s.Artifacts.Packages.Enumerate() {
|
|
||||||
if p.Type == pkg.BinaryPkg {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
fileOwner, ok := p.Metadata.(pkg.FileOwner)
|
|
||||||
if !ok {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
ownedFiles := fileOwner.OwnedFiles()
|
|
||||||
locations, err := resolver.FilesByPath(ownedFiles...)
|
|
||||||
if err != nil {
|
|
||||||
log.WithFields("error", err).Trace("unable to find path for owned file")
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
for _, loc := range locations {
|
|
||||||
for _, pathPkg := range s.Artifacts.Packages.PackagesByPath(loc.RealPath) {
|
|
||||||
if pathPkg.Type == pkg.BinaryPkg {
|
|
||||||
pkgsToDelete = append(pkgsToDelete, pathPkg.ID())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return pkgsToDelete
|
|
||||||
}
|
|
||||||
|
|
||||||
func populateRelationships(exec file.Executable, parentPkg pkg.Package, resolver file.Resolver, addRelationship func(artifact.Relationship), index *sharedLibraryIndex) {
|
func populateRelationships(exec file.Executable, parentPkg pkg.Package, resolver file.Resolver, addRelationship func(artifact.Relationship), index *sharedLibraryIndex) {
|
||||||
for _, libReference := range exec.ImportedLibraries {
|
for _, libReference := range exec.ImportedLibraries {
|
||||||
// for each library reference, check s.Artifacts.Packages.Sorted(pkg.BinaryPkg) for a binary package that represents that library
|
// for each library reference, check s.Artifacts.Packages.Sorted(pkg.BinaryPkg) for a binary package that represents that library
|
||||||
|
|||||||
@ -21,7 +21,7 @@ func TestPackagesToRemove(t *testing.T) {
|
|||||||
Name: "glibc",
|
Name: "glibc",
|
||||||
Version: "2.28-236.el8_9.12",
|
Version: "2.28-236.el8_9.12",
|
||||||
Locations: file.NewLocationSet(
|
Locations: file.NewLocationSet(
|
||||||
file.NewLocation(glibcCoordinate.RealPath),
|
file.NewLocation("path/to/rpmdb"),
|
||||||
),
|
),
|
||||||
Type: pkg.RpmPkg,
|
Type: pkg.RpmPkg,
|
||||||
Metadata: pkg.RpmDBEntry{
|
Metadata: pkg.RpmDBEntry{
|
||||||
@ -88,50 +88,45 @@ func TestPackagesToRemove(t *testing.T) {
|
|||||||
|
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
name string
|
name string
|
||||||
resolver file.Resolver
|
|
||||||
accessor sbomsync.Accessor
|
accessor sbomsync.Accessor
|
||||||
want []artifact.ID
|
want []artifact.ID
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
name: "remove packages that are overlapping rpm --> binary",
|
name: "remove packages that are overlapping rpm --> binary",
|
||||||
resolver: file.NewMockResolverForPaths(glibcCoordinate.RealPath),
|
|
||||||
accessor: newAccessor([]pkg.Package{glibCPackage, glibCBinaryELFPackage}, map[file.Coordinates]file.Executable{}, nil),
|
accessor: newAccessor([]pkg.Package{glibCPackage, glibCBinaryELFPackage}, map[file.Coordinates]file.Executable{}, nil),
|
||||||
want: []artifact.ID{glibCBinaryELFPackage.ID()},
|
// this is surprising, right? the calling function reasons about if any generic binary package (regardless of it being an ELF package or not)
|
||||||
|
// should be deleted or kept based on the user configuration to do so.
|
||||||
|
want: []artifact.ID{},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "keep packages that are overlapping rpm --> binary when the binary self identifies as an RPM",
|
name: "keep packages that are overlapping rpm --> binary when the binary self identifies as an RPM",
|
||||||
resolver: file.NewMockResolverForPaths(glibcCoordinate.RealPath),
|
|
||||||
accessor: newAccessor([]pkg.Package{glibCPackage, glibCBinaryELFPackageAsRPM}, map[file.Coordinates]file.Executable{}, nil),
|
accessor: newAccessor([]pkg.Package{glibCPackage, glibCBinaryELFPackageAsRPM}, map[file.Coordinates]file.Executable{}, nil),
|
||||||
want: []artifact.ID{},
|
want: []artifact.ID{},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "remove no packages when there is a single binary package (or self identifying RPM)",
|
name: "remove no packages when there is a single binary package (or self identifying RPM)",
|
||||||
resolver: file.NewMockResolverForPaths(glibcCoordinate.RealPath),
|
|
||||||
accessor: newAccessor([]pkg.Package{glibCBinaryELFPackage, glibCBinaryELFPackageAsRPM}, map[file.Coordinates]file.Executable{}, nil),
|
accessor: newAccessor([]pkg.Package{glibCBinaryELFPackage, glibCBinaryELFPackageAsRPM}, map[file.Coordinates]file.Executable{}, nil),
|
||||||
want: []artifact.ID{},
|
want: []artifact.ID{},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "remove packages when there is a single binary package and a classifier package",
|
name: "remove packages when there is a single binary package and a classifier package",
|
||||||
resolver: file.NewMockResolverForPaths(glibcCoordinate.RealPath),
|
|
||||||
accessor: newAccessor([]pkg.Package{glibCBinaryELFPackage, glibCBinaryClassifierPackage}, map[file.Coordinates]file.Executable{}, nil),
|
accessor: newAccessor([]pkg.Package{glibCBinaryELFPackage, glibCBinaryClassifierPackage}, map[file.Coordinates]file.Executable{}, nil),
|
||||||
want: []artifact.ID{glibCBinaryClassifierPackage.ID()},
|
want: []artifact.ID{glibCBinaryClassifierPackage.ID()},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "ensure we're considering ELF packages, not just binary packages (supporting evidence)",
|
name: "ensure we're considering ELF packages, not just binary packages (supporting evidence)",
|
||||||
resolver: file.NewMockResolverForPaths(glibcCoordinate.RealPath),
|
|
||||||
accessor: newAccessor([]pkg.Package{glibCBinaryClassifierPackage}, map[file.Coordinates]file.Executable{}, nil),
|
accessor: newAccessor([]pkg.Package{glibCBinaryClassifierPackage}, map[file.Coordinates]file.Executable{}, nil),
|
||||||
want: []artifact.ID{},
|
want: []artifact.ID{},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "ensure we're considering ELF packages, not just binary packages (primary evidence)",
|
name: "ensure we're considering ELF packages, not just binary packages (primary evidence)",
|
||||||
resolver: file.NewMockResolverForPaths(glibcCoordinate.RealPath),
|
|
||||||
accessor: newAccessor([]pkg.Package{libCBinaryClassifierPackage}, map[file.Coordinates]file.Executable{}, nil),
|
accessor: newAccessor([]pkg.Package{libCBinaryClassifierPackage}, map[file.Coordinates]file.Executable{}, nil),
|
||||||
want: []artifact.ID{},
|
want: []artifact.ID{},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
pkgsToDelete := PackagesToRemove(tt.resolver, tt.accessor)
|
pkgsToDelete := PackagesToRemove(tt.accessor)
|
||||||
if diff := cmp.Diff(tt.want, pkgsToDelete); diff != "" {
|
if diff := cmp.Diff(tt.want, pkgsToDelete); diff != "" {
|
||||||
t.Errorf("unexpected packages to delete (-want, +got): %s", diff)
|
t.Errorf("unexpected packages to delete (-want, +got): %s", diff)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -22,6 +22,9 @@ var (
|
|||||||
binaryCatalogerTypes = []pkg.Type{
|
binaryCatalogerTypes = []pkg.Type{
|
||||||
pkg.BinaryPkg,
|
pkg.BinaryPkg,
|
||||||
}
|
}
|
||||||
|
bitnamiCatalogerTypes = []pkg.Type{
|
||||||
|
pkg.BitnamiPkg,
|
||||||
|
}
|
||||||
binaryMetadataTypes = []string{
|
binaryMetadataTypes = []string{
|
||||||
reflect.TypeOf(pkg.ELFBinaryPackageNoteJSONPayload{}).Name(),
|
reflect.TypeOf(pkg.ELFBinaryPackageNoteJSONPayload{}).Name(),
|
||||||
reflect.TypeOf(pkg.BinarySignature{}).Name(),
|
reflect.TypeOf(pkg.BinarySignature{}).Name(),
|
||||||
@ -65,6 +68,10 @@ func excludeByFileOwnershipOverlap(r artifact.Relationship, c *pkg.Collection) a
|
|||||||
return idToRemove
|
return idToRemove
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if idToRemove := identifyOverlappingBitnamiRelationship(parent, child); idToRemove != "" {
|
||||||
|
return idToRemove
|
||||||
|
}
|
||||||
|
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -124,3 +131,24 @@ func identifyOverlappingOSRelationship(parent *pkg.Package, child *pkg.Package)
|
|||||||
|
|
||||||
return child.ID()
|
return child.ID()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// identifyOverlappingBitnamiRelationship indicates the package ID to remove if this is a Bitnami pkg -> bin pkg relationship.
|
||||||
|
func identifyOverlappingBitnamiRelationship(parent *pkg.Package, child *pkg.Package) artifact.ID {
|
||||||
|
if !slices.Contains(bitnamiCatalogerTypes, 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()
|
||||||
|
}
|
||||||
|
|||||||
@ -13,7 +13,8 @@ func TestExcludeByFileOwnershipOverlap(t *testing.T) {
|
|||||||
packageA := pkg.Package{Name: "package-a", Type: pkg.ApkPkg}
|
packageA := pkg.Package{Name: "package-a", Type: pkg.ApkPkg}
|
||||||
packageB := pkg.Package{Name: "package-b", Type: pkg.BinaryPkg, Metadata: pkg.JavaVMInstallation{}}
|
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"}}
|
packageC := pkg.Package{Name: "package-c", Type: pkg.BinaryPkg, Metadata: pkg.ELFBinaryPackageNoteJSONPayload{Type: "rpm"}}
|
||||||
for _, p := range []*pkg.Package{&packageA, &packageB, &packageC} {
|
packageD := pkg.Package{Name: "package-d", Type: pkg.BitnamiPkg}
|
||||||
|
for _, p := range []*pkg.Package{&packageA, &packageB, &packageC, &packageD} {
|
||||||
p := p
|
p := p
|
||||||
p.SetID()
|
p.SetID()
|
||||||
}
|
}
|
||||||
@ -46,6 +47,17 @@ func TestExcludeByFileOwnershipOverlap(t *testing.T) {
|
|||||||
packages: pkg.NewCollection(packageC, packageB),
|
packages: pkg.NewCollection(packageC, packageB),
|
||||||
shouldExclude: true,
|
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 {
|
for _, test := range tests {
|
||||||
@ -117,6 +129,63 @@ func TestIdentifyOverlappingOSRelationship(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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) {
|
func TestIdentifyOverlappingJVMRelationship(t *testing.T) {
|
||||||
|
|
||||||
packageA := pkg.Package{Name: "package-a", Type: pkg.BinaryPkg}
|
packageA := pkg.Package{Name: "package-a", Type: pkg.BinaryPkg}
|
||||||
|
|||||||
@ -6,6 +6,7 @@ import (
|
|||||||
"github.com/anchore/syft/syft/pkg/cataloger/alpine"
|
"github.com/anchore/syft/syft/pkg/cataloger/alpine"
|
||||||
"github.com/anchore/syft/syft/pkg/cataloger/arch"
|
"github.com/anchore/syft/syft/pkg/cataloger/arch"
|
||||||
"github.com/anchore/syft/syft/pkg/cataloger/binary"
|
"github.com/anchore/syft/syft/pkg/cataloger/binary"
|
||||||
|
bitnamiSbomCataloger "github.com/anchore/syft/syft/pkg/cataloger/bitnami"
|
||||||
"github.com/anchore/syft/syft/pkg/cataloger/cpp"
|
"github.com/anchore/syft/syft/pkg/cataloger/cpp"
|
||||||
"github.com/anchore/syft/syft/pkg/cataloger/dart"
|
"github.com/anchore/syft/syft/pkg/cataloger/dart"
|
||||||
"github.com/anchore/syft/syft/pkg/cataloger/debian"
|
"github.com/anchore/syft/syft/pkg/cataloger/debian"
|
||||||
@ -152,6 +153,7 @@ func DefaultPackageTaskFactories() Factories {
|
|||||||
pkgcataloging.DeclaredTag, pkgcataloging.DirectoryTag, pkgcataloging.InstalledTag, pkgcataloging.ImageTag, "linux", "kernel",
|
pkgcataloging.DeclaredTag, pkgcataloging.DirectoryTag, pkgcataloging.InstalledTag, pkgcataloging.ImageTag, "linux", "kernel",
|
||||||
),
|
),
|
||||||
newSimplePackageTaskFactory(sbomCataloger.NewCataloger, "sbom"), // note: not evidence of installed packages
|
newSimplePackageTaskFactory(sbomCataloger.NewCataloger, "sbom"), // note: not evidence of installed packages
|
||||||
|
newSimplePackageTaskFactory(bitnamiSbomCataloger.NewCataloger, "bitnami", pkgcataloging.InstalledTag, pkgcataloging.ImageTag),
|
||||||
newSimplePackageTaskFactory(wordpress.NewWordpressPluginCataloger, pkgcataloging.DirectoryTag, pkgcataloging.ImageTag, "wordpress"),
|
newSimplePackageTaskFactory(wordpress.NewWordpressPluginCataloger, pkgcataloging.DirectoryTag, pkgcataloging.ImageTag, "wordpress"),
|
||||||
newSimplePackageTaskFactory(terraform.NewLockCataloger, pkgcataloging.DeclaredTag, pkgcataloging.DirectoryTag, "terraform"),
|
newSimplePackageTaskFactory(terraform.NewLockCataloger, pkgcataloging.DeclaredTag, pkgcataloging.DirectoryTag, "terraform"),
|
||||||
}
|
}
|
||||||
|
|||||||
@ -42,7 +42,7 @@ func finalizeRelationships(resolver file.Resolver, builder sbomsync.Builder, cfg
|
|||||||
|
|
||||||
// remove ELF packages and Binary packages that are already
|
// remove ELF packages and Binary packages that are already
|
||||||
// represented by a source package (e.g. a package that is evident by some package manager)
|
// represented by a source package (e.g. a package that is evident by some package manager)
|
||||||
builder.DeletePackages(binary.PackagesToRemove(resolver, accessor)...)
|
builder.DeletePackages(binary.PackagesToRemove(accessor)...)
|
||||||
|
|
||||||
// add relationships showing packages that are evident by a file which is owned by another package (package-to-package)
|
// add relationships showing packages that are evident by a file which is owned by another package (package-to-package)
|
||||||
if cfg.PackageFileOwnershipOverlap {
|
if cfg.PackageFileOwnershipOverlap {
|
||||||
|
|||||||
2826
schema/json/schema-16.0.22.json
Normal file
2826
schema/json/schema-16.0.22.json
Normal file
File diff suppressed because it is too large
Load Diff
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||||
"$id": "anchore.io/schema/syft/json/16.0.21/document",
|
"$id": "anchore.io/schema/syft/json/16.0.22/document",
|
||||||
"$ref": "#/$defs/Document",
|
"$ref": "#/$defs/Document",
|
||||||
"$defs": {
|
"$defs": {
|
||||||
"AlpmDbEntry": {
|
"AlpmDbEntry": {
|
||||||
@ -218,6 +218,44 @@
|
|||||||
"matches"
|
"matches"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
"BitnamiSbomEntry": {
|
||||||
|
"properties": {
|
||||||
|
"name": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"arch": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"distro": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"revision": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"version": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"path": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"files": {
|
||||||
|
"items": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"type": "array"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"name",
|
||||||
|
"arch",
|
||||||
|
"distro",
|
||||||
|
"revision",
|
||||||
|
"version",
|
||||||
|
"path",
|
||||||
|
"files"
|
||||||
|
]
|
||||||
|
},
|
||||||
"CConanFileEntry": {
|
"CConanFileEntry": {
|
||||||
"properties": {
|
"properties": {
|
||||||
"ref": {
|
"ref": {
|
||||||
@ -1653,6 +1691,9 @@
|
|||||||
{
|
{
|
||||||
"$ref": "#/$defs/BinarySignature"
|
"$ref": "#/$defs/BinarySignature"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"$ref": "#/$defs/BitnamiSbomEntry"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"$ref": "#/$defs/CConanFileEntry"
|
"$ref": "#/$defs/CConanFileEntry"
|
||||||
},
|
},
|
||||||
|
|||||||
@ -43,6 +43,10 @@ func Originator(p pkg.Package) (typ string, author string) { //nolint: funlen
|
|||||||
case pkg.ApkDBEntry:
|
case pkg.ApkDBEntry:
|
||||||
author = metadata.Maintainer
|
author = metadata.Maintainer
|
||||||
|
|
||||||
|
case pkg.BitnamiSBOMEntry:
|
||||||
|
typ = orgType
|
||||||
|
author = "Bitnami"
|
||||||
|
|
||||||
case pkg.DotnetPortableExecutableEntry:
|
case pkg.DotnetPortableExecutableEntry:
|
||||||
typ = orgType
|
typ = orgType
|
||||||
author = metadata.CompanyName
|
author = metadata.CompanyName
|
||||||
|
|||||||
@ -12,6 +12,7 @@ import (
|
|||||||
func Test_OriginatorSupplier(t *testing.T) {
|
func Test_OriginatorSupplier(t *testing.T) {
|
||||||
completionTester := packagemetadata.NewCompletionTester(t,
|
completionTester := packagemetadata.NewCompletionTester(t,
|
||||||
pkg.BinarySignature{},
|
pkg.BinarySignature{},
|
||||||
|
pkg.BitnamiSBOMEntry{},
|
||||||
pkg.CocoaPodfileLockEntry{},
|
pkg.CocoaPodfileLockEntry{},
|
||||||
pkg.ConanV1LockEntry{},
|
pkg.ConanV1LockEntry{},
|
||||||
pkg.ConanV2LockEntry{}, // the field Username might be the username of either the package originator or the supplier (unclear currently)
|
pkg.ConanV2LockEntry{}, // the field Username might be the username of either the package originator or the supplier (unclear currently)
|
||||||
@ -89,6 +90,14 @@ func Test_OriginatorSupplier(t *testing.T) {
|
|||||||
originator: "",
|
originator: "",
|
||||||
supplier: "Person: someone",
|
supplier: "Person: someone",
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: "from bitnami",
|
||||||
|
input: pkg.Package{
|
||||||
|
Metadata: pkg.BitnamiSBOMEntry{},
|
||||||
|
},
|
||||||
|
originator: "Organization: Bitnami",
|
||||||
|
supplier: "Organization: Bitnami",
|
||||||
|
},
|
||||||
{
|
{
|
||||||
name: "from dotnet -- PE binary",
|
name: "from dotnet -- PE binary",
|
||||||
input: pkg.Package{
|
input: pkg.Package{
|
||||||
|
|||||||
@ -16,6 +16,8 @@ func SourceInfo(p pkg.Package) string {
|
|||||||
answer = "acquired package info from RPM DB"
|
answer = "acquired package info from RPM DB"
|
||||||
case pkg.ApkPkg:
|
case pkg.ApkPkg:
|
||||||
answer = "acquired package info from APK DB"
|
answer = "acquired package info from APK DB"
|
||||||
|
case pkg.BitnamiPkg:
|
||||||
|
answer = "acquired package info from a Bitnami SBOM"
|
||||||
case pkg.DartPubPkg:
|
case pkg.DartPubPkg:
|
||||||
answer = "acquired package info from pubspec manifest"
|
answer = "acquired package info from pubspec manifest"
|
||||||
case pkg.DebPkg:
|
case pkg.DebPkg:
|
||||||
@ -32,6 +34,8 @@ func SourceInfo(p pkg.Package) string {
|
|||||||
answer = "acquired package info from installed gem metadata file"
|
answer = "acquired package info from installed gem metadata file"
|
||||||
case pkg.GoModulePkg:
|
case pkg.GoModulePkg:
|
||||||
answer = "acquired package info from go module information"
|
answer = "acquired package info from go module information"
|
||||||
|
case pkg.GraalVMNativeImagePkg:
|
||||||
|
answer = "acquired package info from GraalVM native image"
|
||||||
case pkg.RustPkg:
|
case pkg.RustPkg:
|
||||||
answer = "acquired package info from rust cargo manifest"
|
answer = "acquired package info from rust cargo manifest"
|
||||||
case pkg.PhpComposerPkg:
|
case pkg.PhpComposerPkg:
|
||||||
|
|||||||
@ -111,6 +111,14 @@ func Test_SourceInfo(t *testing.T) {
|
|||||||
"from go module information",
|
"from go module information",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
input: pkg.Package{
|
||||||
|
Type: pkg.GraalVMNativeImagePkg,
|
||||||
|
},
|
||||||
|
expected: []string{
|
||||||
|
"from GraalVM native image",
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
input: pkg.Package{
|
input: pkg.Package{
|
||||||
Type: pkg.RustPkg,
|
Type: pkg.RustPkg,
|
||||||
@ -199,6 +207,14 @@ func Test_SourceInfo(t *testing.T) {
|
|||||||
"acquired package info from the following paths",
|
"acquired package info from the following paths",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
input: pkg.Package{
|
||||||
|
Type: pkg.BitnamiPkg,
|
||||||
|
},
|
||||||
|
expected: []string{
|
||||||
|
"acquired package info from a Bitnami SBOM",
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
input: pkg.Package{
|
input: pkg.Package{
|
||||||
Type: pkg.HexPkg,
|
Type: pkg.HexPkg,
|
||||||
|
|||||||
@ -10,6 +10,7 @@ func AllTypes() []any {
|
|||||||
pkg.AlpmDBEntry{},
|
pkg.AlpmDBEntry{},
|
||||||
pkg.ApkDBEntry{},
|
pkg.ApkDBEntry{},
|
||||||
pkg.BinarySignature{},
|
pkg.BinarySignature{},
|
||||||
|
pkg.BitnamiSBOMEntry{},
|
||||||
pkg.CocoaPodfileLockEntry{},
|
pkg.CocoaPodfileLockEntry{},
|
||||||
pkg.ConanV1LockEntry{},
|
pkg.ConanV1LockEntry{},
|
||||||
pkg.ConanV2LockEntry{},
|
pkg.ConanV2LockEntry{},
|
||||||
|
|||||||
@ -65,6 +65,7 @@ var jsonTypes = makeJSONTypes(
|
|||||||
jsonNames(pkg.AlpmDBEntry{}, "alpm-db-entry", "AlpmMetadata"),
|
jsonNames(pkg.AlpmDBEntry{}, "alpm-db-entry", "AlpmMetadata"),
|
||||||
jsonNames(pkg.ApkDBEntry{}, "apk-db-entry", "ApkMetadata"),
|
jsonNames(pkg.ApkDBEntry{}, "apk-db-entry", "ApkMetadata"),
|
||||||
jsonNames(pkg.BinarySignature{}, "binary-signature", "BinaryMetadata"),
|
jsonNames(pkg.BinarySignature{}, "binary-signature", "BinaryMetadata"),
|
||||||
|
jsonNames(pkg.BitnamiSBOMEntry{}, "bitnami-sbom-entry"),
|
||||||
jsonNames(pkg.CocoaPodfileLockEntry{}, "cocoa-podfile-lock-entry", "CocoapodsMetadataType"),
|
jsonNames(pkg.CocoaPodfileLockEntry{}, "cocoa-podfile-lock-entry", "CocoapodsMetadataType"),
|
||||||
jsonNames(pkg.ConanV1LockEntry{}, "c-conan-lock-entry", "ConanLockMetadataType"),
|
jsonNames(pkg.ConanV1LockEntry{}, "c-conan-lock-entry", "ConanLockMetadataType"),
|
||||||
jsonNames(pkg.ConanV2LockEntry{}, "c-conan-lock-v2-entry"),
|
jsonNames(pkg.ConanV2LockEntry{}, "c-conan-lock-v2-entry"),
|
||||||
|
|||||||
17
syft/pkg/bitnami.go
Normal file
17
syft/pkg/bitnami.go
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
package pkg
|
||||||
|
|
||||||
|
// BitnamiSBOMEntry represents all captured data from Bitnami packages
|
||||||
|
// described in Bitnami' SPDX files.
|
||||||
|
type BitnamiSBOMEntry struct {
|
||||||
|
Name string `mapstructure:"name" json:"name"`
|
||||||
|
Architecture string `mapstructure:"arch" json:"arch"`
|
||||||
|
Distro string `mapstructure:"distro" json:"distro"`
|
||||||
|
Revision string `mapstructure:"revision" json:"revision"`
|
||||||
|
Version string `mapstructure:"version" json:"version"`
|
||||||
|
Path string `mapstructure:"path" json:"path"`
|
||||||
|
Files []string `mapstructure:"files" json:"files"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b BitnamiSBOMEntry) OwnedFiles() (result []string) {
|
||||||
|
return b.Files
|
||||||
|
}
|
||||||
173
syft/pkg/cataloger/bitnami/cataloger.go
Normal file
173
syft/pkg/cataloger/bitnami/cataloger.go
Normal file
@ -0,0 +1,173 @@
|
|||||||
|
/*
|
||||||
|
Package bitnami provides a concrete Cataloger implementation for capturing packages embedded within Bitnami SBOM files.
|
||||||
|
*/
|
||||||
|
package bitnami
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"path/filepath"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/anchore/syft/internal/log"
|
||||||
|
"github.com/anchore/syft/syft/artifact"
|
||||||
|
"github.com/anchore/syft/syft/file"
|
||||||
|
"github.com/anchore/syft/syft/format"
|
||||||
|
"github.com/anchore/syft/syft/pkg"
|
||||||
|
"github.com/anchore/syft/syft/pkg/cataloger/generic"
|
||||||
|
)
|
||||||
|
|
||||||
|
const catalogerName = "bitnami-cataloger"
|
||||||
|
|
||||||
|
// NewCataloger returns a new SBOM cataloger object loaded from saved SBOM JSON.
|
||||||
|
func NewCataloger() pkg.Cataloger {
|
||||||
|
return generic.NewCataloger(catalogerName).
|
||||||
|
WithParserByGlobs(parseSBOM,
|
||||||
|
"/opt/bitnami/**/.spdx-*.spdx",
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
func parseSBOM(_ context.Context, resolver file.Resolver, _ *generic.Environment, reader file.LocationReadCloser) ([]pkg.Package, []artifact.Relationship, error) {
|
||||||
|
s, sFormat, _, err := format.Decode(reader)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if s == nil {
|
||||||
|
log.WithFields("path", reader.Location.RealPath).Trace("file is not an SBOM")
|
||||||
|
return nil, nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Bitnami exclusively uses SPDX JSON SBOMs
|
||||||
|
if sFormat != "spdx-json" {
|
||||||
|
log.WithFields("path", reader.Location.RealPath).Trace("file is not an SPDX JSON SBOM")
|
||||||
|
return nil, nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
var pkgs []pkg.Package
|
||||||
|
var secondaryPkgsFiles []string
|
||||||
|
mainPkgID := findMainPkgID(s.Relationships)
|
||||||
|
for _, p := range s.Artifacts.Packages.Sorted() {
|
||||||
|
// We only want to report Bitnami packages
|
||||||
|
if !strings.HasPrefix(p.PURL, "pkg:bitnami") {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
p.FoundBy = catalogerName
|
||||||
|
p.Type = pkg.BitnamiPkg
|
||||||
|
// replace all locations on the package with the location of the SBOM file.
|
||||||
|
// Why not keep the original list of locations? Since the "locations" field is meant to capture
|
||||||
|
// where there is evidence of this file, and the catalogers have not run against any file other than,
|
||||||
|
// the SBOM, this is the only location that is relevant for this cataloger.
|
||||||
|
p.Locations = file.NewLocationSet(
|
||||||
|
reader.Location.WithAnnotation(pkg.EvidenceAnnotationKey, pkg.PrimaryEvidenceAnnotation),
|
||||||
|
)
|
||||||
|
|
||||||
|
// Parse the Bitnami-specific metadata
|
||||||
|
metadata, err := parseBitnamiPURL(p.PURL)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Bitnami packages reported in a SPDX file are shipped under the same directory
|
||||||
|
// as the SPDX file itself.
|
||||||
|
metadata.Path = filepath.Dir(reader.Location.RealPath)
|
||||||
|
if p.ID() != mainPkgID {
|
||||||
|
metadata.Files = packageFiles(s.Relationships, p, metadata.Path)
|
||||||
|
secondaryPkgsFiles = append(secondaryPkgsFiles, metadata.Files...)
|
||||||
|
}
|
||||||
|
|
||||||
|
p.Metadata = metadata
|
||||||
|
|
||||||
|
pkgs = append(pkgs, p)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Resolve all files owned by the main package in the SBOM and update the metadata
|
||||||
|
if mainPkgFiles, err := mainPkgFiles(resolver, reader.Location.RealPath, secondaryPkgsFiles); err == nil {
|
||||||
|
for i, p := range pkgs {
|
||||||
|
if p.ID() == mainPkgID {
|
||||||
|
metadata, ok := p.Metadata.(*pkg.BitnamiSBOMEntry)
|
||||||
|
if !ok {
|
||||||
|
log.WithFields("spdx-filepath", reader.Location.RealPath).Trace("main package in SBOM does not have Bitnami metadata")
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
metadata.Files = mainPkgFiles
|
||||||
|
pkgs[i].Metadata = metadata
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
log.WithFields("spdx-filepath", reader.Location.RealPath, "error", err).Trace("unable to resolve owned files for main package in SBOM")
|
||||||
|
}
|
||||||
|
|
||||||
|
return pkgs, filterRelationships(s.Relationships, pkgs), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// filterRelationships filters out relationships that are not related to Bitnami packages
|
||||||
|
// and replaces the package information with the one with completed info
|
||||||
|
func filterRelationships(relationships []artifact.Relationship, pkgs []pkg.Package) []artifact.Relationship {
|
||||||
|
var result []artifact.Relationship
|
||||||
|
for _, r := range relationships {
|
||||||
|
if value, ok := r.From.(pkg.Package); ok {
|
||||||
|
found := false
|
||||||
|
for _, p := range pkgs {
|
||||||
|
if value.PURL == p.PURL {
|
||||||
|
r.From = p
|
||||||
|
found = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !found {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if value, ok := r.To.(pkg.Package); ok {
|
||||||
|
found := false
|
||||||
|
for _, p := range pkgs {
|
||||||
|
if value.PURL == p.PURL {
|
||||||
|
r.To = p
|
||||||
|
found = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !found {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
result = append(result, r)
|
||||||
|
}
|
||||||
|
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
// findMainPkgID goes through the list of relationships and finds the main package ID
|
||||||
|
// which is the one that contains other packages but is not contained by any other package
|
||||||
|
func findMainPkgID(relationships []artifact.Relationship) artifact.ID {
|
||||||
|
containedByAnother := func(candidateID artifact.ID) bool {
|
||||||
|
for _, r := range relationships {
|
||||||
|
if r.Type != artifact.ContainsRelationship {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if to, ok := r.To.(pkg.Package); ok {
|
||||||
|
if to.ID() == candidateID {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, r := range relationships {
|
||||||
|
if from, ok := r.From.(pkg.Package); ok {
|
||||||
|
if !strings.HasPrefix(from.PURL, "pkg:bitnami") {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if !containedByAnother(from.ID()) {
|
||||||
|
return from.ID()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ""
|
||||||
|
}
|
||||||
470
syft/pkg/cataloger/bitnami/cataloger_test.go
Normal file
470
syft/pkg/cataloger/bitnami/cataloger_test.go
Normal file
@ -0,0 +1,470 @@
|
|||||||
|
package bitnami
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
|
||||||
|
"github.com/anchore/syft/syft/artifact"
|
||||||
|
"github.com/anchore/syft/syft/cpe"
|
||||||
|
"github.com/anchore/syft/syft/file"
|
||||||
|
"github.com/anchore/syft/syft/license"
|
||||||
|
"github.com/anchore/syft/syft/pkg"
|
||||||
|
"github.com/anchore/syft/syft/pkg/cataloger/internal/pkgtest"
|
||||||
|
)
|
||||||
|
|
||||||
|
func mustCPEs(s ...string) (c []cpe.CPE) {
|
||||||
|
for _, i := range s {
|
||||||
|
newCPE := cpe.Must(i, "")
|
||||||
|
newCPE.Source = cpe.DeclaredSource
|
||||||
|
c = append(c, newCPE)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestBitnamiCataloger(t *testing.T) {
|
||||||
|
postgresqlMainPkg := pkg.Package{
|
||||||
|
Name: "postgresql",
|
||||||
|
Version: "17.2.0-8",
|
||||||
|
Type: pkg.BitnamiPkg,
|
||||||
|
Locations: file.NewLocationSet(file.NewLocation("opt/bitnami/postgresql/.spdx-postgresql.spdx")),
|
||||||
|
Licenses: pkg.NewLicenseSet(
|
||||||
|
pkg.NewLicenseFromType("PostgreSQL", license.Concluded),
|
||||||
|
pkg.NewLicenseFromType("PostgreSQL", license.Declared),
|
||||||
|
),
|
||||||
|
FoundBy: catalogerName,
|
||||||
|
PURL: "pkg:bitnami/postgresql@17.2.0-8?arch=arm64&distro=debian-12",
|
||||||
|
CPEs: mustCPEs(
|
||||||
|
"cpe:2.3:*:postgresql:postgresql:17.2.0:*:*:*:*:*:*:*",
|
||||||
|
),
|
||||||
|
Metadata: &pkg.BitnamiSBOMEntry{
|
||||||
|
Name: "postgresql",
|
||||||
|
Version: "17.2.0",
|
||||||
|
Revision: "8",
|
||||||
|
Architecture: "arm64",
|
||||||
|
Distro: "debian-12",
|
||||||
|
Path: "opt/bitnami/postgresql",
|
||||||
|
Files: []string{
|
||||||
|
"opt/bitnami/postgresql/readme.txt",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
postgresqlSecondaryPkgs := []pkg.Package{
|
||||||
|
{
|
||||||
|
Name: "geos",
|
||||||
|
Version: "3.13.0",
|
||||||
|
Type: pkg.BitnamiPkg,
|
||||||
|
Locations: file.NewLocationSet(file.NewLocation("opt/bitnami/postgresql/.spdx-postgresql.spdx")),
|
||||||
|
Licenses: pkg.NewLicenseSet(
|
||||||
|
pkg.NewLicenseFromType("LGPL-2.1-only", license.Concluded),
|
||||||
|
pkg.NewLicenseFromType("LGPL-2.1-only", license.Declared),
|
||||||
|
),
|
||||||
|
FoundBy: catalogerName,
|
||||||
|
PURL: "pkg:bitnami/geos@3.13.0?arch=arm64&distro=debian-12",
|
||||||
|
CPEs: mustCPEs(
|
||||||
|
"cpe:2.3:*:libgeos:geos:3.13.0:*:*:*:*:*:*:*",
|
||||||
|
),
|
||||||
|
Metadata: &pkg.BitnamiSBOMEntry{
|
||||||
|
Name: "geos",
|
||||||
|
Version: "3.13.0",
|
||||||
|
Architecture: "arm64",
|
||||||
|
Distro: "debian-12",
|
||||||
|
Path: "opt/bitnami/postgresql",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "proj",
|
||||||
|
Version: "6.3.2",
|
||||||
|
Type: pkg.BitnamiPkg,
|
||||||
|
Locations: file.NewLocationSet(file.NewLocation("opt/bitnami/postgresql/.spdx-postgresql.spdx")),
|
||||||
|
Licenses: pkg.NewLicenseSet(
|
||||||
|
pkg.NewLicenseFromType("MIT", license.Concluded),
|
||||||
|
pkg.NewLicenseFromType("MIT", license.Declared),
|
||||||
|
),
|
||||||
|
FoundBy: catalogerName,
|
||||||
|
PURL: "pkg:bitnami/proj@6.3.2?arch=arm64&distro=debian-12",
|
||||||
|
CPEs: mustCPEs(
|
||||||
|
"cpe:2.3:*:proj:proj:6.3.2:*:*:*:*:*:*:*",
|
||||||
|
),
|
||||||
|
Metadata: &pkg.BitnamiSBOMEntry{
|
||||||
|
Name: "proj",
|
||||||
|
Version: "6.3.2",
|
||||||
|
Architecture: "arm64",
|
||||||
|
Distro: "debian-12",
|
||||||
|
Path: "opt/bitnami/postgresql",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "gdal",
|
||||||
|
Version: "3.10.1",
|
||||||
|
Type: pkg.BitnamiPkg,
|
||||||
|
Locations: file.NewLocationSet(file.NewLocation("opt/bitnami/postgresql/.spdx-postgresql.spdx")),
|
||||||
|
Licenses: pkg.NewLicenseSet(
|
||||||
|
pkg.NewLicenseFromType("MIT", license.Concluded),
|
||||||
|
pkg.NewLicenseFromType("MIT", license.Declared),
|
||||||
|
),
|
||||||
|
FoundBy: catalogerName,
|
||||||
|
PURL: "pkg:bitnami/gdal@3.10.1?arch=arm64&distro=debian-12",
|
||||||
|
CPEs: mustCPEs(
|
||||||
|
"cpe:2.3:*:osgeo:gdal:3.10.1:*:*:*:*:*:*:*",
|
||||||
|
),
|
||||||
|
Metadata: &pkg.BitnamiSBOMEntry{
|
||||||
|
Name: "gdal",
|
||||||
|
Version: "3.10.1",
|
||||||
|
Architecture: "arm64",
|
||||||
|
Distro: "debian-12",
|
||||||
|
Path: "opt/bitnami/postgresql",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "json-c",
|
||||||
|
Version: "0.16.20220414",
|
||||||
|
Type: pkg.BitnamiPkg,
|
||||||
|
Locations: file.NewLocationSet(file.NewLocation("opt/bitnami/postgresql/.spdx-postgresql.spdx")),
|
||||||
|
Licenses: pkg.NewLicenseSet(
|
||||||
|
pkg.NewLicenseFromType("MIT", license.Concluded),
|
||||||
|
pkg.NewLicenseFromType("MIT", license.Declared),
|
||||||
|
),
|
||||||
|
FoundBy: catalogerName,
|
||||||
|
PURL: "pkg:bitnami/json-c@0.16.20220414?arch=arm64&distro=debian-12",
|
||||||
|
CPEs: mustCPEs(
|
||||||
|
"cpe:2.3:*:json-c_project:json-c:0.16.20220414:*:*:*:*:*:*:*",
|
||||||
|
),
|
||||||
|
Metadata: &pkg.BitnamiSBOMEntry{
|
||||||
|
Name: "json-c",
|
||||||
|
Version: "0.16.20220414",
|
||||||
|
Architecture: "arm64",
|
||||||
|
Distro: "debian-12",
|
||||||
|
Path: "opt/bitnami/postgresql",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "orafce",
|
||||||
|
Version: "4.14.1",
|
||||||
|
Type: pkg.BitnamiPkg,
|
||||||
|
Locations: file.NewLocationSet(file.NewLocation("opt/bitnami/postgresql/.spdx-postgresql.spdx")),
|
||||||
|
Licenses: pkg.NewLicenseSet(
|
||||||
|
pkg.NewLicenseFromType("0BSD", license.Concluded),
|
||||||
|
pkg.NewLicenseFromType("0BSD", license.Declared),
|
||||||
|
),
|
||||||
|
FoundBy: catalogerName,
|
||||||
|
PURL: "pkg:bitnami/orafce@4.14.1?arch=arm64&distro=debian-12",
|
||||||
|
CPEs: mustCPEs(
|
||||||
|
"cpe:2.3:*:orafce:orafce:4.14.1:*:*:*:*:*:*:*",
|
||||||
|
),
|
||||||
|
Metadata: &pkg.BitnamiSBOMEntry{
|
||||||
|
Name: "orafce",
|
||||||
|
Version: "4.14.1",
|
||||||
|
Architecture: "arm64",
|
||||||
|
Distro: "debian-12",
|
||||||
|
Path: "opt/bitnami/postgresql",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "pljava",
|
||||||
|
Version: "1.6.8",
|
||||||
|
Type: pkg.BitnamiPkg,
|
||||||
|
Locations: file.NewLocationSet(file.NewLocation("opt/bitnami/postgresql/.spdx-postgresql.spdx")),
|
||||||
|
Licenses: pkg.NewLicenseSet(
|
||||||
|
pkg.NewLicenseFromType("BSD-3-Clause", license.Concluded),
|
||||||
|
pkg.NewLicenseFromType("BSD-3-Clause", license.Declared),
|
||||||
|
),
|
||||||
|
FoundBy: catalogerName,
|
||||||
|
PURL: "pkg:bitnami/pljava@1.6.8?arch=arm64&distro=debian-12",
|
||||||
|
CPEs: mustCPEs(
|
||||||
|
"cpe:2.3:*:pl/java_project:pl/java:1.6.8:*:*:*:*:*:*:*",
|
||||||
|
),
|
||||||
|
Metadata: &pkg.BitnamiSBOMEntry{
|
||||||
|
Name: "pljava",
|
||||||
|
Version: "1.6.8",
|
||||||
|
Architecture: "arm64",
|
||||||
|
Distro: "debian-12",
|
||||||
|
Path: "opt/bitnami/postgresql",
|
||||||
|
Files: []string{
|
||||||
|
"opt/bitnami/postgresql/share/pljava/pljava-api-1.6.8.jar",
|
||||||
|
"opt/bitnami/postgresql/share/pljava/pljava-1.6.8.jar",
|
||||||
|
"opt/bitnami/postgresql/share/pljava/pljava-examples-1.6.8.jar",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "unixodbc",
|
||||||
|
Version: "2.3.12",
|
||||||
|
Type: pkg.BitnamiPkg,
|
||||||
|
Locations: file.NewLocationSet(file.NewLocation("opt/bitnami/postgresql/.spdx-postgresql.spdx")),
|
||||||
|
Licenses: pkg.NewLicenseSet(
|
||||||
|
pkg.NewLicenseFromType("LGPL-2.1-only", license.Concluded),
|
||||||
|
pkg.NewLicenseFromType("LGPL-2.1-only", license.Declared),
|
||||||
|
),
|
||||||
|
FoundBy: catalogerName,
|
||||||
|
PURL: "pkg:bitnami/unixodbc@2.3.12?arch=arm64&distro=debian-12",
|
||||||
|
CPEs: mustCPEs(
|
||||||
|
"cpe:2.3:*:unixodbc:unixodbc:2.3.12:*:*:*:*:*:*:*",
|
||||||
|
),
|
||||||
|
Metadata: &pkg.BitnamiSBOMEntry{
|
||||||
|
Name: "unixodbc",
|
||||||
|
Version: "2.3.12",
|
||||||
|
Architecture: "arm64",
|
||||||
|
Distro: "debian-12",
|
||||||
|
Path: "opt/bitnami/postgresql",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "psqlodbc",
|
||||||
|
Version: "16.0.0",
|
||||||
|
Type: pkg.BitnamiPkg,
|
||||||
|
Locations: file.NewLocationSet(file.NewLocation("opt/bitnami/postgresql/.spdx-postgresql.spdx")),
|
||||||
|
Licenses: pkg.NewLicenseSet(
|
||||||
|
pkg.NewLicenseFromType("LGPL-3.0-only", license.Concluded),
|
||||||
|
pkg.NewLicenseFromType("LGPL-3.0-only", license.Declared),
|
||||||
|
),
|
||||||
|
FoundBy: catalogerName,
|
||||||
|
PURL: "pkg:bitnami/psqlodbc@16.0.0?arch=arm64&distro=debian-12",
|
||||||
|
CPEs: mustCPEs(
|
||||||
|
"cpe:2.3:*:postgresql:psqlodbc:16.0.0:*:*:*:*:*:*:*",
|
||||||
|
),
|
||||||
|
Metadata: &pkg.BitnamiSBOMEntry{
|
||||||
|
Name: "psqlodbc",
|
||||||
|
Version: "16.0.0",
|
||||||
|
Architecture: "arm64",
|
||||||
|
Distro: "debian-12",
|
||||||
|
Path: "opt/bitnami/postgresql",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "protobuf",
|
||||||
|
Version: "3.21.12",
|
||||||
|
Type: pkg.BitnamiPkg,
|
||||||
|
Locations: file.NewLocationSet(file.NewLocation("opt/bitnami/postgresql/.spdx-postgresql.spdx")),
|
||||||
|
Licenses: pkg.NewLicenseSet(
|
||||||
|
pkg.NewLicenseFromType("BSD-3-Clause", license.Concluded),
|
||||||
|
pkg.NewLicenseFromType("BSD-3-Clause", license.Declared),
|
||||||
|
),
|
||||||
|
FoundBy: catalogerName,
|
||||||
|
PURL: "pkg:bitnami/protobuf@3.21.12?arch=arm64&distro=debian-12",
|
||||||
|
CPEs: mustCPEs(
|
||||||
|
"cpe:2.3:*:golang:protobuf:3.21.12:*:*:*:*:*:*:*",
|
||||||
|
),
|
||||||
|
Metadata: &pkg.BitnamiSBOMEntry{
|
||||||
|
Name: "protobuf",
|
||||||
|
Version: "3.21.12",
|
||||||
|
Architecture: "arm64",
|
||||||
|
Distro: "debian-12",
|
||||||
|
Path: "opt/bitnami/postgresql",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "protobuf-c",
|
||||||
|
Version: "1.5.1",
|
||||||
|
Type: pkg.BitnamiPkg,
|
||||||
|
Locations: file.NewLocationSet(file.NewLocation("opt/bitnami/postgresql/.spdx-postgresql.spdx")),
|
||||||
|
Licenses: pkg.NewLicenseSet(
|
||||||
|
pkg.NewLicenseFromType("BSD-2-Clause", license.Concluded),
|
||||||
|
pkg.NewLicenseFromType("BSD-2-Clause", license.Declared),
|
||||||
|
),
|
||||||
|
FoundBy: catalogerName,
|
||||||
|
PURL: "pkg:bitnami/protobuf-c@1.5.1?arch=arm64&distro=debian-12",
|
||||||
|
CPEs: mustCPEs(
|
||||||
|
"cpe:2.3:*:protobuf-c:protobuf-c:1.5.1:*:*:*:*:*:*:*",
|
||||||
|
),
|
||||||
|
Metadata: &pkg.BitnamiSBOMEntry{
|
||||||
|
Name: "protobuf-c",
|
||||||
|
Version: "1.5.1",
|
||||||
|
Architecture: "arm64",
|
||||||
|
Distro: "debian-12",
|
||||||
|
Path: "opt/bitnami/postgresql",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "postgis",
|
||||||
|
Version: "3.4.4",
|
||||||
|
Type: pkg.BitnamiPkg,
|
||||||
|
Locations: file.NewLocationSet(file.NewLocation("opt/bitnami/postgresql/.spdx-postgresql.spdx")),
|
||||||
|
Licenses: pkg.NewLicenseSet(
|
||||||
|
pkg.NewLicenseFromType("GPL-2.0-or-later", license.Concluded),
|
||||||
|
pkg.NewLicenseFromType("GPL-2.0-or-later", license.Declared),
|
||||||
|
),
|
||||||
|
FoundBy: catalogerName,
|
||||||
|
PURL: "pkg:bitnami/postgis@3.4.4?arch=arm64&distro=debian-12",
|
||||||
|
CPEs: mustCPEs(
|
||||||
|
"cpe:2.3:*:postgis:postgis:3.4.4:*:*:*:*:*:*:*",
|
||||||
|
),
|
||||||
|
Metadata: &pkg.BitnamiSBOMEntry{
|
||||||
|
Name: "postgis",
|
||||||
|
Version: "3.4.4",
|
||||||
|
Architecture: "arm64",
|
||||||
|
Distro: "debian-12",
|
||||||
|
Path: "opt/bitnami/postgresql",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "pgaudit",
|
||||||
|
Version: "17.0.0",
|
||||||
|
Type: pkg.BitnamiPkg,
|
||||||
|
Locations: file.NewLocationSet(file.NewLocation("opt/bitnami/postgresql/.spdx-postgresql.spdx")),
|
||||||
|
Licenses: pkg.NewLicenseSet(
|
||||||
|
pkg.NewLicenseFromType("PostgreSQL", license.Concluded),
|
||||||
|
pkg.NewLicenseFromType("PostgreSQL", license.Declared),
|
||||||
|
),
|
||||||
|
FoundBy: catalogerName,
|
||||||
|
PURL: "pkg:bitnami/pgaudit@17.0.0?arch=arm64&distro=debian-12",
|
||||||
|
Metadata: &pkg.BitnamiSBOMEntry{
|
||||||
|
Name: "pgaudit",
|
||||||
|
Version: "17.0.0",
|
||||||
|
Architecture: "arm64",
|
||||||
|
Distro: "debian-12",
|
||||||
|
Path: "opt/bitnami/postgresql",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "pgbackrest",
|
||||||
|
Version: "2.54.2",
|
||||||
|
Type: pkg.BitnamiPkg,
|
||||||
|
Locations: file.NewLocationSet(file.NewLocation("opt/bitnami/postgresql/.spdx-postgresql.spdx")),
|
||||||
|
Licenses: pkg.NewLicenseSet(
|
||||||
|
pkg.NewLicenseFromType("MIT", license.Concluded),
|
||||||
|
pkg.NewLicenseFromType("MIT", license.Declared),
|
||||||
|
),
|
||||||
|
FoundBy: catalogerName,
|
||||||
|
PURL: "pkg:bitnami/pgbackrest@2.54.2?arch=arm64&distro=debian-12",
|
||||||
|
CPEs: mustCPEs(
|
||||||
|
"cpe:2.3:*:pgbackrest:pgbackrest:2.54.2:*:*:*:*:*:*:*",
|
||||||
|
),
|
||||||
|
Metadata: &pkg.BitnamiSBOMEntry{
|
||||||
|
Name: "pgbackrest",
|
||||||
|
Version: "2.54.2",
|
||||||
|
Architecture: "arm64",
|
||||||
|
Distro: "debian-12",
|
||||||
|
Path: "opt/bitnami/postgresql",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "wal2json",
|
||||||
|
Version: "2.6.0",
|
||||||
|
Type: pkg.BitnamiPkg,
|
||||||
|
Locations: file.NewLocationSet(file.NewLocation("opt/bitnami/postgresql/.spdx-postgresql.spdx")),
|
||||||
|
Licenses: pkg.NewLicenseSet(
|
||||||
|
pkg.NewLicenseFromType("BSD-3-Clause", license.Concluded),
|
||||||
|
pkg.NewLicenseFromType("BSD-3-Clause", license.Declared),
|
||||||
|
),
|
||||||
|
FoundBy: catalogerName,
|
||||||
|
PURL: "pkg:bitnami/wal2json@2.6.0?arch=arm64&distro=debian-12",
|
||||||
|
CPEs: mustCPEs(
|
||||||
|
"cpe:2.3:*:wal2json:wal2json:2.6.0:*:*:*:*:*:*:*",
|
||||||
|
),
|
||||||
|
Metadata: &pkg.BitnamiSBOMEntry{
|
||||||
|
Name: "wal2json",
|
||||||
|
Version: "2.6.0",
|
||||||
|
Architecture: "arm64",
|
||||||
|
Distro: "debian-12",
|
||||||
|
Path: "opt/bitnami/postgresql",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "nss-wrapper",
|
||||||
|
Version: "1.1.16",
|
||||||
|
Type: pkg.BitnamiPkg,
|
||||||
|
Locations: file.NewLocationSet(file.NewLocation("opt/bitnami/postgresql/.spdx-postgresql.spdx")),
|
||||||
|
Licenses: pkg.NewLicenseSet(
|
||||||
|
pkg.NewLicenseFromType("BSD-3-Clause", license.Concluded),
|
||||||
|
pkg.NewLicenseFromType("BSD-3-Clause", license.Declared),
|
||||||
|
),
|
||||||
|
FoundBy: catalogerName,
|
||||||
|
PURL: "pkg:bitnami/nss_wrapper@1.1.16?arch=arm64&distro=debian-12",
|
||||||
|
CPEs: mustCPEs(
|
||||||
|
"cpe:2.3:*:nss_wrapper:nss_wrapper:1.1.16:*:*:*:*:*:*:*",
|
||||||
|
),
|
||||||
|
Metadata: &pkg.BitnamiSBOMEntry{
|
||||||
|
Name: "nss_wrapper",
|
||||||
|
Version: "1.1.16",
|
||||||
|
Architecture: "arm64",
|
||||||
|
Distro: "debian-12",
|
||||||
|
Path: "opt/bitnami/postgresql",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
postgresqlExpectedPkgs := []pkg.Package{postgresqlMainPkg}
|
||||||
|
postgresqlExpectedPkgs = append(postgresqlExpectedPkgs, postgresqlSecondaryPkgs...)
|
||||||
|
pkg.Sort(postgresqlExpectedPkgs)
|
||||||
|
var postgresqlExpectedRelationships []artifact.Relationship
|
||||||
|
for _, p := range postgresqlSecondaryPkgs {
|
||||||
|
postgresqlExpectedRelationships = append(postgresqlExpectedRelationships, artifact.Relationship{
|
||||||
|
From: postgresqlMainPkg,
|
||||||
|
To: p,
|
||||||
|
Type: artifact.ContainsRelationship,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
renderTemplateMainPkg := pkg.Package{
|
||||||
|
Name: "render-template",
|
||||||
|
Version: "1.0.7-4",
|
||||||
|
Type: pkg.BitnamiPkg,
|
||||||
|
Locations: file.NewLocationSet(file.NewLocation("opt/bitnami/render-template/.spdx-render-template.spdx")),
|
||||||
|
Licenses: pkg.NewLicenseSet(
|
||||||
|
pkg.NewLicenseFromType("Apache-2.0", license.Concluded),
|
||||||
|
pkg.NewLicenseFromType("Apache-2.0", license.Declared),
|
||||||
|
),
|
||||||
|
FoundBy: catalogerName,
|
||||||
|
PURL: "pkg:bitnami/render-template@1.0.7-4?arch=arm64&distro=debian-12",
|
||||||
|
CPEs: mustCPEs(
|
||||||
|
"cpe:2.3:*:render-template:render-template:1.0.7:*:*:*:*:*:*:*",
|
||||||
|
),
|
||||||
|
Metadata: &pkg.BitnamiSBOMEntry{
|
||||||
|
Name: "render-template",
|
||||||
|
Version: "1.0.7",
|
||||||
|
Revision: "4",
|
||||||
|
Architecture: "arm64",
|
||||||
|
Distro: "debian-12",
|
||||||
|
Path: "opt/bitnami/render-template",
|
||||||
|
Files: []string{},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
fixture string
|
||||||
|
wantPkgs []pkg.Package
|
||||||
|
wantRelationships []artifact.Relationship
|
||||||
|
wantErr require.ErrorAssertionFunc
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "parse valid PostgreSQL SBOM",
|
||||||
|
fixture: "test-fixtures/json",
|
||||||
|
wantPkgs: postgresqlExpectedPkgs,
|
||||||
|
wantRelationships: postgresqlExpectedRelationships,
|
||||||
|
wantErr: require.NoError,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "parse valid SBOM that includes both Bitnami and non-Bitnami packages",
|
||||||
|
fixture: "test-fixtures/mix",
|
||||||
|
wantPkgs: []pkg.Package{renderTemplateMainPkg},
|
||||||
|
wantRelationships: nil,
|
||||||
|
wantErr: require.NoError,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Redis SBOM with not allowed tag-value format",
|
||||||
|
fixture: "test-fixtures/tag-value",
|
||||||
|
wantPkgs: nil,
|
||||||
|
wantRelationships: nil,
|
||||||
|
wantErr: require.NoError,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Invalid SBOM",
|
||||||
|
fixture: "test-fixtures/invalid",
|
||||||
|
wantPkgs: nil,
|
||||||
|
wantRelationships: nil,
|
||||||
|
wantErr: require.Error,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
pkgtest.NewCatalogTester().
|
||||||
|
FromDirectory(t, tt.fixture).
|
||||||
|
Expects(tt.wantPkgs, tt.wantRelationships).
|
||||||
|
WithErrorAssertion(tt.wantErr).
|
||||||
|
TestCataloger(t, NewCataloger())
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
92
syft/pkg/cataloger/bitnami/package.go
Normal file
92
syft/pkg/cataloger/bitnami/package.go
Normal file
@ -0,0 +1,92 @@
|
|||||||
|
package bitnami
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"path"
|
||||||
|
"path/filepath"
|
||||||
|
"slices"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
version "github.com/bitnami/go-version/pkg/version"
|
||||||
|
|
||||||
|
"github.com/anchore/packageurl-go"
|
||||||
|
"github.com/anchore/syft/syft/artifact"
|
||||||
|
"github.com/anchore/syft/syft/file"
|
||||||
|
"github.com/anchore/syft/syft/pkg"
|
||||||
|
)
|
||||||
|
|
||||||
|
func parseBitnamiPURL(p string) (*pkg.BitnamiSBOMEntry, error) {
|
||||||
|
purl, err := packageurl.FromString(p)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
v, err := version.Parse(purl.Version)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
entry := pkg.BitnamiSBOMEntry{
|
||||||
|
Name: purl.Name,
|
||||||
|
Version: strings.TrimSuffix(v.String(), fmt.Sprintf("-%s", v.Revision().String())),
|
||||||
|
Revision: v.Revision().String(),
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, q := range purl.Qualifiers {
|
||||||
|
switch q.Key {
|
||||||
|
case "arch":
|
||||||
|
entry.Architecture = q.Value
|
||||||
|
case "distro":
|
||||||
|
entry.Distro = q.Value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return &entry, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// packageFiles goes through the list of relationships and finds the files that
|
||||||
|
// are owned by the given package
|
||||||
|
func packageFiles(relationships []artifact.Relationship, p pkg.Package, baseDirectory string) []string {
|
||||||
|
var result []string
|
||||||
|
for _, r := range relationships {
|
||||||
|
if r.Type != artifact.ContainsRelationship {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if from, ok := r.From.(pkg.Package); ok {
|
||||||
|
if from.PURL == p.PURL {
|
||||||
|
if to, ok := r.To.(pkg.Package); ok {
|
||||||
|
result = append(result, packageFiles(relationships, to, baseDirectory)...)
|
||||||
|
}
|
||||||
|
if value, ok := r.To.(file.Location); ok {
|
||||||
|
// note: the file.Location is from the SBOM, and all files within the Bitnami SBOM by convention
|
||||||
|
// are relative to the /opt/bitnami/PRODUCT directory, so we need to prepend the base directory
|
||||||
|
// so that it's relative to the path found within the container image.
|
||||||
|
result = append(result, path.Join(baseDirectory, value.RealPath))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
// mainPkgFiles returns the files owned by the main package in the SPDX file.
|
||||||
|
func mainPkgFiles(resolver file.Resolver, spdxFilePath string, secondaryPkgsFiles []string) ([]string, error) {
|
||||||
|
ownedPathGlob := fmt.Sprintf("%s/**", filepath.Dir(spdxFilePath))
|
||||||
|
ownedLocations, err := resolver.FilesByGlob(ownedPathGlob)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
ownedLocationSet := file.NewLocationSet(ownedLocations...)
|
||||||
|
ownedFiles := ownedLocationSet.CoordinateSet().Paths()
|
||||||
|
|
||||||
|
// Remove the SPDX file and the files already assigned to other packages
|
||||||
|
// from the list of owned files
|
||||||
|
files := slices.DeleteFunc(ownedFiles, func(f string) bool {
|
||||||
|
return f == spdxFilePath || slices.Contains(secondaryPkgsFiles, f)
|
||||||
|
})
|
||||||
|
|
||||||
|
return files, nil
|
||||||
|
}
|
||||||
57
syft/pkg/cataloger/bitnami/package_test.go
Normal file
57
syft/pkg/cataloger/bitnami/package_test.go
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
package bitnami
|
||||||
|
|
||||||
|
import (
|
||||||
|
"reflect"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/anchore/syft/syft/pkg"
|
||||||
|
)
|
||||||
|
|
||||||
|
func Test_parseBitnamiPURL(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
purl string
|
||||||
|
want *pkg.BitnamiSBOMEntry
|
||||||
|
wantErr bool
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "Valid Bitnami pURL",
|
||||||
|
purl: "pkg:bitnami/redis@7.4.1-0?arch=arm64&distro=debian-12",
|
||||||
|
want: &pkg.BitnamiSBOMEntry{
|
||||||
|
Name: "redis",
|
||||||
|
Version: "7.4.1",
|
||||||
|
Revision: "0",
|
||||||
|
Architecture: "arm64",
|
||||||
|
Distro: "debian-12",
|
||||||
|
},
|
||||||
|
wantErr: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Invalid pURL",
|
||||||
|
purl: "this/is/not/a/purl",
|
||||||
|
want: nil,
|
||||||
|
wantErr: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Invalid version",
|
||||||
|
purl: "pkg:bitnami/redis@7.4.1.0?arch=arm64&distro=debian-12",
|
||||||
|
want: nil,
|
||||||
|
wantErr: true,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
t.Parallel()
|
||||||
|
for _, testToRun := range tests {
|
||||||
|
test := testToRun
|
||||||
|
t.Run(test.name, func(tt *testing.T) {
|
||||||
|
tt.Parallel()
|
||||||
|
got, err := parseBitnamiPURL(test.purl)
|
||||||
|
if (err != nil) != test.wantErr {
|
||||||
|
tt.Errorf("parseBitnamiPURL() error = %v, wantErr %v", err, test.wantErr)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if !reflect.DeepEqual(got, test.want) {
|
||||||
|
tt.Errorf("parseBitnamiPURL() = %v, want %v", got, test.want)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,5 @@
|
|||||||
|
{
|
||||||
|
"id": "invalid-id",
|
||||||
|
"name": "invalid-name",
|
||||||
|
"description: "This is not a SPDX file"
|
||||||
|
}
|
||||||
@ -0,0 +1,573 @@
|
|||||||
|
{
|
||||||
|
"SPDXID": "SPDXRef-postgresql",
|
||||||
|
"spdxVersion": "SPDX-2.3",
|
||||||
|
"creationInfo": {
|
||||||
|
"created": "2025-02-02T05:18:41.934Z",
|
||||||
|
"creators": [
|
||||||
|
"Organization: Broadcom Inc. and/or its subsidiaries."
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"name": "SPDX document for PostgreSQL 17.2.0",
|
||||||
|
"dataLicense": "CC0-1.0",
|
||||||
|
"documentDescribes": [
|
||||||
|
"SPDXRef-postgresql"
|
||||||
|
],
|
||||||
|
"documentNamespace": "postgresql-17.2.0",
|
||||||
|
"packages": [
|
||||||
|
{
|
||||||
|
"SPDXID": "SPDXRef-postgresql",
|
||||||
|
"name": "postgresql",
|
||||||
|
"versionInfo": "17.2.0-8",
|
||||||
|
"downloadLocation": "https://ftp.postgresql.org/pub/source/v17.2/postgresql-17.2.tar.gz",
|
||||||
|
"licenseConcluded": "PostgreSQL",
|
||||||
|
"licenseDeclared": "PostgreSQL",
|
||||||
|
"filesAnalyzed": false,
|
||||||
|
"externalRefs": [
|
||||||
|
{
|
||||||
|
"referenceCategory": "SECURITY",
|
||||||
|
"referenceType": "cpe23Type",
|
||||||
|
"referenceLocator": "cpe:2.3:*:postgresql:postgresql:17.2.0:*:*:*:*:*:*:*"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"referenceCategory": "PACKAGE-MANAGER",
|
||||||
|
"referenceType": "purl",
|
||||||
|
"referenceLocator": "pkg:bitnami/postgresql@17.2.0-8?arch=arm64&distro=debian-12"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"copyrightText": "NOASSERTION"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"SPDXID": "SPDXRef-geos",
|
||||||
|
"name": "geos",
|
||||||
|
"versionInfo": "3.13.0",
|
||||||
|
"downloadLocation": "https://github.com/libgeos/geos/archive/3.13.0.tar.gz",
|
||||||
|
"licenseConcluded": "LGPL-2.1-only",
|
||||||
|
"licenseDeclared": "LGPL-2.1-only",
|
||||||
|
"filesAnalyzed": false,
|
||||||
|
"externalRefs": [
|
||||||
|
{
|
||||||
|
"referenceCategory": "SECURITY",
|
||||||
|
"referenceType": "cpe23Type",
|
||||||
|
"referenceLocator": "cpe:2.3:*:libgeos:geos:3.13.0:*:*:*:*:*:*:*"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"referenceCategory": "PACKAGE-MANAGER",
|
||||||
|
"referenceType": "purl",
|
||||||
|
"referenceLocator": "pkg:bitnami/geos@3.13.0?arch=arm64&distro=debian-12"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"copyrightText": "NOASSERTION"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"SPDXID": "SPDXRef-proj",
|
||||||
|
"name": "proj",
|
||||||
|
"versionInfo": "6.3.2",
|
||||||
|
"downloadLocation": "https://github.com/OSGeo/PROJ/archive/6.3.2.tar.gz",
|
||||||
|
"licenseConcluded": "MIT",
|
||||||
|
"licenseDeclared": "MIT",
|
||||||
|
"filesAnalyzed": false,
|
||||||
|
"externalRefs": [
|
||||||
|
{
|
||||||
|
"referenceCategory": "SECURITY",
|
||||||
|
"referenceType": "cpe23Type",
|
||||||
|
"referenceLocator": "cpe:2.3:*:proj:proj:6.3.2:*:*:*:*:*:*:*"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"referenceCategory": "PACKAGE-MANAGER",
|
||||||
|
"referenceType": "purl",
|
||||||
|
"referenceLocator": "pkg:bitnami/proj@6.3.2?arch=arm64&distro=debian-12"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"copyrightText": "NOASSERTION"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"SPDXID": "SPDXRef-gdal",
|
||||||
|
"name": "gdal",
|
||||||
|
"versionInfo": "3.10.1",
|
||||||
|
"downloadLocation": "https://github.com/OSGeo/gdal/releases/download/v3.10.1/gdal-3.10.1.tar.gz",
|
||||||
|
"licenseConcluded": "MIT",
|
||||||
|
"licenseDeclared": "MIT",
|
||||||
|
"filesAnalyzed": false,
|
||||||
|
"externalRefs": [
|
||||||
|
{
|
||||||
|
"referenceCategory": "SECURITY",
|
||||||
|
"referenceType": "cpe23Type",
|
||||||
|
"referenceLocator": "cpe:2.3:*:osgeo:gdal:3.10.1:*:*:*:*:*:*:*"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"referenceCategory": "PACKAGE-MANAGER",
|
||||||
|
"referenceType": "purl",
|
||||||
|
"referenceLocator": "pkg:bitnami/gdal@3.10.1?arch=arm64&distro=debian-12"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"copyrightText": "NOASSERTION"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"SPDXID": "SPDXRef-json-c",
|
||||||
|
"name": "json-c",
|
||||||
|
"versionInfo": "0.16.20220414",
|
||||||
|
"downloadLocation": "https://github.com/json-c/json-c/archive/refs/tags/json-c-0.16-20220414.tar.gz",
|
||||||
|
"licenseConcluded": "MIT",
|
||||||
|
"licenseDeclared": "MIT",
|
||||||
|
"filesAnalyzed": false,
|
||||||
|
"externalRefs": [
|
||||||
|
{
|
||||||
|
"referenceCategory": "SECURITY",
|
||||||
|
"referenceType": "cpe23Type",
|
||||||
|
"referenceLocator": "cpe:2.3:*:json-c_project:json-c:0.16.20220414:*:*:*:*:*:*:*"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"referenceCategory": "PACKAGE-MANAGER",
|
||||||
|
"referenceType": "purl",
|
||||||
|
"referenceLocator": "pkg:bitnami/json-c@0.16.20220414?arch=arm64&distro=debian-12"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"copyrightText": "NOASSERTION"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"SPDXID": "SPDXRef-orafce",
|
||||||
|
"name": "orafce",
|
||||||
|
"versionInfo": "4.14.1",
|
||||||
|
"downloadLocation": "https://github.com/orafce/orafce/archive/refs/tags/VERSION_4_14_1.tar.gz",
|
||||||
|
"licenseConcluded": "0BSD",
|
||||||
|
"licenseDeclared": "0BSD",
|
||||||
|
"filesAnalyzed": false,
|
||||||
|
"externalRefs": [
|
||||||
|
{
|
||||||
|
"referenceCategory": "SECURITY",
|
||||||
|
"referenceType": "cpe23Type",
|
||||||
|
"referenceLocator": "cpe:2.3:*:orafce:orafce:4.14.1:*:*:*:*:*:*:*"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"referenceCategory": "PACKAGE-MANAGER",
|
||||||
|
"referenceType": "purl",
|
||||||
|
"referenceLocator": "pkg:bitnami/orafce@4.14.1?arch=arm64&distro=debian-12"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"copyrightText": "NOASSERTION"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"SPDXID": "SPDXRef-pljava",
|
||||||
|
"name": "pljava",
|
||||||
|
"versionInfo": "1.6.8",
|
||||||
|
"downloadLocation": "https://github.com/tada/pljava/archive/V1_6_8.tar.gz",
|
||||||
|
"licenseConcluded": "BSD-3-Clause",
|
||||||
|
"licenseDeclared": "BSD-3-Clause",
|
||||||
|
"filesAnalyzed": false,
|
||||||
|
"externalRefs": [
|
||||||
|
{
|
||||||
|
"referenceCategory": "SECURITY",
|
||||||
|
"referenceType": "cpe23Type",
|
||||||
|
"referenceLocator": "cpe:2.3:*:pl/java_project:pl/java:1.6.8:*:*:*:*:*:*:*"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"referenceCategory": "PACKAGE-MANAGER",
|
||||||
|
"referenceType": "purl",
|
||||||
|
"referenceLocator": "pkg:bitnami/pljava@1.6.8?arch=arm64&distro=debian-12"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"copyrightText": "NOASSERTION"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "org.postgresql:pljava",
|
||||||
|
"SPDXID": "SPDXRef-Package-551f76fc50fc5735",
|
||||||
|
"versionInfo": "1.6.8",
|
||||||
|
"supplier": "NOASSERTION",
|
||||||
|
"downloadLocation": "NONE",
|
||||||
|
"filesAnalyzed": true,
|
||||||
|
"packageVerificationCode": {
|
||||||
|
"packageVerificationCodeValue": "8b35292054790088fc1f41fb696a993d584d17cd"
|
||||||
|
},
|
||||||
|
"licenseConcluded": "NONE",
|
||||||
|
"licenseDeclared": "NONE",
|
||||||
|
"externalRefs": [
|
||||||
|
{
|
||||||
|
"referenceCategory": "PACKAGE-MANAGER",
|
||||||
|
"referenceType": "purl",
|
||||||
|
"referenceLocator": "pkg:maven/org.postgresql/pljava@1.6.8"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"primaryPackagePurpose": "LIBRARY",
|
||||||
|
"copyrightText": "NOASSERTION"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "org.postgresql:pljava-api",
|
||||||
|
"SPDXID": "SPDXRef-Package-2dde48fd49927020",
|
||||||
|
"versionInfo": "1.6.8",
|
||||||
|
"supplier": "NOASSERTION",
|
||||||
|
"downloadLocation": "NONE",
|
||||||
|
"filesAnalyzed": true,
|
||||||
|
"packageVerificationCode": {
|
||||||
|
"packageVerificationCodeValue": "3aaf93e288e125481a250d50ab629d890f72e7b8"
|
||||||
|
},
|
||||||
|
"licenseConcluded": "NONE",
|
||||||
|
"licenseDeclared": "NONE",
|
||||||
|
"externalRefs": [
|
||||||
|
{
|
||||||
|
"referenceCategory": "PACKAGE-MANAGER",
|
||||||
|
"referenceType": "purl",
|
||||||
|
"referenceLocator": "pkg:maven/org.postgresql/pljava-api@1.6.8"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"primaryPackagePurpose": "LIBRARY",
|
||||||
|
"copyrightText": "NOASSERTION"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "org.postgresql:pljava-examples",
|
||||||
|
"SPDXID": "SPDXRef-Package-f13571c8a05828cc",
|
||||||
|
"versionInfo": "1.6.8",
|
||||||
|
"supplier": "NOASSERTION",
|
||||||
|
"downloadLocation": "NONE",
|
||||||
|
"filesAnalyzed": true,
|
||||||
|
"packageVerificationCode": {
|
||||||
|
"packageVerificationCodeValue": "6f126f1237ddd2be6196726130c014770864bcc9"
|
||||||
|
},
|
||||||
|
"licenseConcluded": "NONE",
|
||||||
|
"licenseDeclared": "NONE",
|
||||||
|
"externalRefs": [
|
||||||
|
{
|
||||||
|
"referenceCategory": "PACKAGE-MANAGER",
|
||||||
|
"referenceType": "purl",
|
||||||
|
"referenceLocator": "pkg:maven/org.postgresql/pljava-examples@1.6.8"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"primaryPackagePurpose": "LIBRARY",
|
||||||
|
"copyrightText": "NOASSERTION"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"SPDXID": "SPDXRef-unixodbc",
|
||||||
|
"name": "unixodbc",
|
||||||
|
"versionInfo": "2.3.12",
|
||||||
|
"downloadLocation": "http://www.unixodbc.org/unixODBC-2.3.12.tar.gz",
|
||||||
|
"licenseConcluded": "LGPL-2.1-only",
|
||||||
|
"licenseDeclared": "LGPL-2.1-only",
|
||||||
|
"filesAnalyzed": false,
|
||||||
|
"externalRefs": [
|
||||||
|
{
|
||||||
|
"referenceCategory": "SECURITY",
|
||||||
|
"referenceType": "cpe23Type",
|
||||||
|
"referenceLocator": "cpe:2.3:*:unixodbc:unixodbc:2.3.12:*:*:*:*:*:*:*"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"referenceCategory": "PACKAGE-MANAGER",
|
||||||
|
"referenceType": "purl",
|
||||||
|
"referenceLocator": "pkg:bitnami/unixodbc@2.3.12?arch=arm64&distro=debian-12"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"copyrightText": "NOASSERTION"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"SPDXID": "SPDXRef-psqlodbc",
|
||||||
|
"name": "psqlodbc",
|
||||||
|
"versionInfo": "16.0.0",
|
||||||
|
"downloadLocation": "https://ftp.postgresql.org/pub/odbc/versions/src/psqlodbc-16.00.0000.tar.gz",
|
||||||
|
"licenseConcluded": "LGPL-3.0-only",
|
||||||
|
"licenseDeclared": "LGPL-3.0-only",
|
||||||
|
"filesAnalyzed": false,
|
||||||
|
"externalRefs": [
|
||||||
|
{
|
||||||
|
"referenceCategory": "SECURITY",
|
||||||
|
"referenceType": "cpe23Type",
|
||||||
|
"referenceLocator": "cpe:2.3:*:postgresql:psqlodbc:16.0.0:*:*:*:*:*:*:*"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"referenceCategory": "PACKAGE-MANAGER",
|
||||||
|
"referenceType": "purl",
|
||||||
|
"referenceLocator": "pkg:bitnami/psqlodbc@16.0.0?arch=arm64&distro=debian-12"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"copyrightText": "NOASSERTION"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"SPDXID": "SPDXRef-protobuf",
|
||||||
|
"name": "protobuf",
|
||||||
|
"versionInfo": "3.21.12",
|
||||||
|
"downloadLocation": "https://github.com/protocolbuffers/protobuf/archive/refs/tags/v3.21.12.tar.gz",
|
||||||
|
"licenseConcluded": "BSD-3-Clause",
|
||||||
|
"licenseDeclared": "BSD-3-Clause",
|
||||||
|
"filesAnalyzed": false,
|
||||||
|
"externalRefs": [
|
||||||
|
{
|
||||||
|
"referenceCategory": "SECURITY",
|
||||||
|
"referenceType": "cpe23Type",
|
||||||
|
"referenceLocator": "cpe:2.3:*:golang:protobuf:3.21.12:*:*:*:*:*:*:*"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"referenceCategory": "PACKAGE-MANAGER",
|
||||||
|
"referenceType": "purl",
|
||||||
|
"referenceLocator": "pkg:bitnami/protobuf@3.21.12?arch=arm64&distro=debian-12"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"copyrightText": "NOASSERTION"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"SPDXID": "SPDXRef-protobuf-c",
|
||||||
|
"name": "protobuf-c",
|
||||||
|
"versionInfo": "1.5.1",
|
||||||
|
"downloadLocation": "https://github.com/protobuf-c/protobuf-c/releases/download/v1.5.1/protobuf-c-1.5.1.tar.gz",
|
||||||
|
"licenseConcluded": "BSD-2-Clause",
|
||||||
|
"licenseDeclared": "BSD-2-Clause",
|
||||||
|
"filesAnalyzed": false,
|
||||||
|
"externalRefs": [
|
||||||
|
{
|
||||||
|
"referenceCategory": "SECURITY",
|
||||||
|
"referenceType": "cpe23Type",
|
||||||
|
"referenceLocator": "cpe:2.3:*:protobuf-c:protobuf-c:1.5.1:*:*:*:*:*:*:*"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"referenceCategory": "PACKAGE-MANAGER",
|
||||||
|
"referenceType": "purl",
|
||||||
|
"referenceLocator": "pkg:bitnami/protobuf-c@1.5.1?arch=arm64&distro=debian-12"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"copyrightText": "NOASSERTION"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"SPDXID": "SPDXRef-postgis",
|
||||||
|
"name": "postgis",
|
||||||
|
"versionInfo": "3.4.4",
|
||||||
|
"downloadLocation": "http://download.osgeo.org/postgis/source/postgis-3.4.4.tar.gz",
|
||||||
|
"licenseConcluded": "GPL-2.0-or-later",
|
||||||
|
"licenseDeclared": "GPL-2.0-or-later",
|
||||||
|
"filesAnalyzed": false,
|
||||||
|
"externalRefs": [
|
||||||
|
{
|
||||||
|
"referenceCategory": "SECURITY",
|
||||||
|
"referenceType": "cpe23Type",
|
||||||
|
"referenceLocator": "cpe:2.3:*:postgis:postgis:3.4.4:*:*:*:*:*:*:*"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"referenceCategory": "PACKAGE-MANAGER",
|
||||||
|
"referenceType": "purl",
|
||||||
|
"referenceLocator": "pkg:bitnami/postgis@3.4.4?arch=arm64&distro=debian-12"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"copyrightText": "NOASSERTION"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"SPDXID": "SPDXRef-pgaudit",
|
||||||
|
"name": "pgaudit",
|
||||||
|
"versionInfo": "17.0.0",
|
||||||
|
"downloadLocation": "https://github.com/pgaudit/pgaudit/archive/17.0.tar.gz",
|
||||||
|
"licenseConcluded": "PostgreSQL",
|
||||||
|
"licenseDeclared": "PostgreSQL",
|
||||||
|
"filesAnalyzed": false,
|
||||||
|
"externalRefs": [
|
||||||
|
{
|
||||||
|
"referenceCategory": "PACKAGE-MANAGER",
|
||||||
|
"referenceType": "purl",
|
||||||
|
"referenceLocator": "pkg:bitnami/pgaudit@17.0.0?arch=arm64&distro=debian-12"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"copyrightText": "NOASSERTION"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"SPDXID": "SPDXRef-pgbackrest",
|
||||||
|
"name": "pgbackrest",
|
||||||
|
"versionInfo": "2.54.2",
|
||||||
|
"downloadLocation": "https://github.com/pgbackrest/pgbackrest/archive/release/2.54.2.tar.gz",
|
||||||
|
"licenseConcluded": "MIT",
|
||||||
|
"licenseDeclared": "MIT",
|
||||||
|
"filesAnalyzed": false,
|
||||||
|
"externalRefs": [
|
||||||
|
{
|
||||||
|
"referenceCategory": "SECURITY",
|
||||||
|
"referenceType": "cpe23Type",
|
||||||
|
"referenceLocator": "cpe:2.3:*:pgbackrest:pgbackrest:2.54.2:*:*:*:*:*:*:*"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"referenceCategory": "PACKAGE-MANAGER",
|
||||||
|
"referenceType": "purl",
|
||||||
|
"referenceLocator": "pkg:bitnami/pgbackrest@2.54.2?arch=arm64&distro=debian-12"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"copyrightText": "NOASSERTION"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"SPDXID": "SPDXRef-wal2json",
|
||||||
|
"name": "wal2json",
|
||||||
|
"versionInfo": "2.6.0",
|
||||||
|
"downloadLocation": "https://github.com/eulerto/wal2json/archive/refs/tags/wal2json_2_6.tar.gz",
|
||||||
|
"licenseConcluded": "BSD-3-Clause",
|
||||||
|
"licenseDeclared": "BSD-3-Clause",
|
||||||
|
"filesAnalyzed": false,
|
||||||
|
"externalRefs": [
|
||||||
|
{
|
||||||
|
"referenceCategory": "SECURITY",
|
||||||
|
"referenceType": "cpe23Type",
|
||||||
|
"referenceLocator": "cpe:2.3:*:wal2json:wal2json:2.6.0:*:*:*:*:*:*:*"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"referenceCategory": "PACKAGE-MANAGER",
|
||||||
|
"referenceType": "purl",
|
||||||
|
"referenceLocator": "pkg:bitnami/wal2json@2.6.0?arch=arm64&distro=debian-12"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"copyrightText": "NOASSERTION"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"SPDXID": "SPDXRef-nss-wrapper",
|
||||||
|
"name": "nss-wrapper",
|
||||||
|
"versionInfo": "1.1.16",
|
||||||
|
"downloadLocation": "https://ftp.samba.org/pub/cwrap/nss_wrapper-1.1.16.tar.gz",
|
||||||
|
"licenseConcluded": "BSD-3-Clause",
|
||||||
|
"licenseDeclared": "BSD-3-Clause",
|
||||||
|
"filesAnalyzed": false,
|
||||||
|
"externalRefs": [
|
||||||
|
{
|
||||||
|
"referenceCategory": "SECURITY",
|
||||||
|
"referenceType": "cpe23Type",
|
||||||
|
"referenceLocator": "cpe:2.3:*:nss_wrapper:nss_wrapper:1.1.16:*:*:*:*:*:*:*"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"referenceCategory": "PACKAGE-MANAGER",
|
||||||
|
"referenceType": "purl",
|
||||||
|
"referenceLocator": "pkg:bitnami/nss_wrapper@1.1.16?arch=arm64&distro=debian-12"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"copyrightText": "NOASSERTION"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"files": [
|
||||||
|
{
|
||||||
|
"fileName": "share/pljava/pljava-1.6.8.jar",
|
||||||
|
"SPDXID": "SPDXRef-File-28d7473df5d8af04-pljava",
|
||||||
|
"checksums": [
|
||||||
|
{
|
||||||
|
"algorithm": "SHA1",
|
||||||
|
"checksumValue": "b0b8f544ddefbc9ba47ed72ddce13627df919cc9"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"copyrightText": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fileName": "share/pljava/pljava-api-1.6.8.jar",
|
||||||
|
"SPDXID": "SPDXRef-File-3531f2e94fdf52e3-pljava",
|
||||||
|
"checksums": [
|
||||||
|
{
|
||||||
|
"algorithm": "SHA1",
|
||||||
|
"checksumValue": "a2013f3202afc8dc15a21ef7a796730df08d1a00"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"copyrightText": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fileName": "share/pljava/pljava-examples-1.6.8.jar",
|
||||||
|
"SPDXID": "SPDXRef-File-8f3dee04908d7a5a-pljava",
|
||||||
|
"checksums": [
|
||||||
|
{
|
||||||
|
"algorithm": "SHA1",
|
||||||
|
"checksumValue": "1c61bddc63ce4aaaa803d9c39f0740a15c19d300"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"copyrightText": ""
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"relationships": [
|
||||||
|
{
|
||||||
|
"spdxElementId": "SPDXRef-postgresql",
|
||||||
|
"relationshipType": "CONTAINS",
|
||||||
|
"relatedSpdxElement": "SPDXRef-geos"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"spdxElementId": "SPDXRef-postgresql",
|
||||||
|
"relationshipType": "CONTAINS",
|
||||||
|
"relatedSpdxElement": "SPDXRef-proj"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"spdxElementId": "SPDXRef-postgresql",
|
||||||
|
"relationshipType": "CONTAINS",
|
||||||
|
"relatedSpdxElement": "SPDXRef-gdal"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"spdxElementId": "SPDXRef-postgresql",
|
||||||
|
"relationshipType": "CONTAINS",
|
||||||
|
"relatedSpdxElement": "SPDXRef-json-c"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"spdxElementId": "SPDXRef-postgresql",
|
||||||
|
"relationshipType": "CONTAINS",
|
||||||
|
"relatedSpdxElement": "SPDXRef-orafce"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"spdxElementId": "SPDXRef-postgresql",
|
||||||
|
"relationshipType": "CONTAINS",
|
||||||
|
"relatedSpdxElement": "SPDXRef-pljava"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"spdxElementId": "SPDXRef-pljava",
|
||||||
|
"relatedSpdxElement": "SPDXRef-Package-2dde48fd49927020",
|
||||||
|
"relationshipType": "CONTAINS"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"spdxElementId": "SPDXRef-pljava",
|
||||||
|
"relatedSpdxElement": "SPDXRef-Package-551f76fc50fc5735",
|
||||||
|
"relationshipType": "CONTAINS"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"spdxElementId": "SPDXRef-pljava",
|
||||||
|
"relatedSpdxElement": "SPDXRef-Package-f13571c8a05828cc",
|
||||||
|
"relationshipType": "CONTAINS"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"spdxElementId": "SPDXRef-Package-2dde48fd49927020",
|
||||||
|
"relatedSpdxElement": "SPDXRef-File-3531f2e94fdf52e3-pljava",
|
||||||
|
"relationshipType": "CONTAINS"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"spdxElementId": "SPDXRef-Package-551f76fc50fc5735",
|
||||||
|
"relatedSpdxElement": "SPDXRef-File-28d7473df5d8af04-pljava",
|
||||||
|
"relationshipType": "CONTAINS"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"spdxElementId": "SPDXRef-Package-f13571c8a05828cc",
|
||||||
|
"relatedSpdxElement": "SPDXRef-File-8f3dee04908d7a5a-pljava",
|
||||||
|
"relationshipType": "CONTAINS"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"spdxElementId": "SPDXRef-postgresql",
|
||||||
|
"relationshipType": "CONTAINS",
|
||||||
|
"relatedSpdxElement": "SPDXRef-unixodbc"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"spdxElementId": "SPDXRef-postgresql",
|
||||||
|
"relationshipType": "CONTAINS",
|
||||||
|
"relatedSpdxElement": "SPDXRef-psqlodbc"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"spdxElementId": "SPDXRef-postgresql",
|
||||||
|
"relationshipType": "CONTAINS",
|
||||||
|
"relatedSpdxElement": "SPDXRef-protobuf"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"spdxElementId": "SPDXRef-postgresql",
|
||||||
|
"relationshipType": "CONTAINS",
|
||||||
|
"relatedSpdxElement": "SPDXRef-protobuf-c"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"spdxElementId": "SPDXRef-postgresql",
|
||||||
|
"relationshipType": "CONTAINS",
|
||||||
|
"relatedSpdxElement": "SPDXRef-postgis"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"spdxElementId": "SPDXRef-postgresql",
|
||||||
|
"relationshipType": "CONTAINS",
|
||||||
|
"relatedSpdxElement": "SPDXRef-pgaudit"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"spdxElementId": "SPDXRef-postgresql",
|
||||||
|
"relationshipType": "CONTAINS",
|
||||||
|
"relatedSpdxElement": "SPDXRef-pgbackrest"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"spdxElementId": "SPDXRef-postgresql",
|
||||||
|
"relationshipType": "CONTAINS",
|
||||||
|
"relatedSpdxElement": "SPDXRef-wal2json"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"spdxElementId": "SPDXRef-postgresql",
|
||||||
|
"relationshipType": "CONTAINS",
|
||||||
|
"relatedSpdxElement": "SPDXRef-nss-wrapper"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
@ -0,0 +1 @@
|
|||||||
|
This file should be reported as part of the Bitnami PostgreSQL package.
|
||||||
@ -0,0 +1,212 @@
|
|||||||
|
{
|
||||||
|
"SPDXID": "SPDXRef-render-template",
|
||||||
|
"spdxVersion": "SPDX-2.3",
|
||||||
|
"creationInfo": {
|
||||||
|
"created": "2024-09-05T18:51:42.225Z",
|
||||||
|
"creators": [
|
||||||
|
"Organization: VMware, Inc."
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"name": "SPDX document for render-template 1.0.7",
|
||||||
|
"dataLicense": "CC0-1.0",
|
||||||
|
"documentDescribes": [
|
||||||
|
"SPDXRef-render-template"
|
||||||
|
],
|
||||||
|
"documentNamespace": "render-template-1.0.7",
|
||||||
|
"packages": [
|
||||||
|
{
|
||||||
|
"SPDXID": "SPDXRef-render-template",
|
||||||
|
"name": "render-template",
|
||||||
|
"versionInfo": "1.0.7-4",
|
||||||
|
"downloadLocation": "https://github.com/bitnami/render-template/archive/refs/tags/v1.0.7.tar.gz",
|
||||||
|
"licenseConcluded": "Apache-2.0",
|
||||||
|
"licenseDeclared": "Apache-2.0",
|
||||||
|
"filesAnalyzed": false,
|
||||||
|
"externalRefs": [
|
||||||
|
{
|
||||||
|
"referenceCategory": "SECURITY",
|
||||||
|
"referenceType": "cpe23Type",
|
||||||
|
"referenceLocator": "cpe:2.3:*:render-template:render-template:1.0.7:*:*:*:*:*:*:*"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"referenceCategory": "PACKAGE-MANAGER",
|
||||||
|
"referenceType": "purl",
|
||||||
|
"referenceLocator": "pkg:bitnami/render-template@1.0.7-4?arch=arm64&distro=debian-12"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"copyrightText": "NOASSERTION"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "opt/bitnami/common/bin/render-template",
|
||||||
|
"SPDXID": "SPDXRef-Application-4b412cf3f25d2574-render-template",
|
||||||
|
"downloadLocation": "NONE",
|
||||||
|
"filesAnalyzed": false,
|
||||||
|
"primaryPackagePurpose": "APPLICATION",
|
||||||
|
"copyrightText": "NOASSERTION",
|
||||||
|
"licenseConcluded": "NOASSERTION",
|
||||||
|
"licenseDeclared": "NOASSERTION"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "github.com/aymerick/raymond",
|
||||||
|
"SPDXID": "SPDXRef-Package-c77f44f540ae92a0",
|
||||||
|
"versionInfo": "v2.0.2+incompatible",
|
||||||
|
"supplier": "NOASSERTION",
|
||||||
|
"downloadLocation": "NONE",
|
||||||
|
"filesAnalyzed": false,
|
||||||
|
"sourceInfo": "opt/bitnami/common/package found in: opt/bitnami/common/bin/render-template",
|
||||||
|
"licenseConcluded": "NONE",
|
||||||
|
"licenseDeclared": "NONE",
|
||||||
|
"externalRefs": [
|
||||||
|
{
|
||||||
|
"referenceCategory": "PACKAGE-MANAGER",
|
||||||
|
"referenceType": "purl",
|
||||||
|
"referenceLocator": "pkg:golang/github.com/aymerick/raymond@v2.0.2%2Bincompatible"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"primaryPackagePurpose": "LIBRARY",
|
||||||
|
"copyrightText": "NOASSERTION"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "github.com/bitnami/render-template",
|
||||||
|
"SPDXID": "SPDXRef-Package-8213648cad51225d",
|
||||||
|
"supplier": "NOASSERTION",
|
||||||
|
"downloadLocation": "NONE",
|
||||||
|
"filesAnalyzed": false,
|
||||||
|
"sourceInfo": "opt/bitnami/common/package found in: opt/bitnami/common/bin/render-template",
|
||||||
|
"licenseConcluded": "NONE",
|
||||||
|
"licenseDeclared": "NONE",
|
||||||
|
"externalRefs": [
|
||||||
|
{
|
||||||
|
"referenceCategory": "PACKAGE-MANAGER",
|
||||||
|
"referenceType": "purl",
|
||||||
|
"referenceLocator": "pkg:golang/github.com/bitnami/render-template"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"primaryPackagePurpose": "LIBRARY",
|
||||||
|
"copyrightText": "NOASSERTION"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "github.com/jessevdk/go-flags",
|
||||||
|
"SPDXID": "SPDXRef-Package-be6fde8a3edd7caf",
|
||||||
|
"versionInfo": "v1.6.1",
|
||||||
|
"supplier": "NOASSERTION",
|
||||||
|
"downloadLocation": "NONE",
|
||||||
|
"filesAnalyzed": false,
|
||||||
|
"sourceInfo": "opt/bitnami/common/package found in: opt/bitnami/common/bin/render-template",
|
||||||
|
"licenseConcluded": "NONE",
|
||||||
|
"licenseDeclared": "NONE",
|
||||||
|
"externalRefs": [
|
||||||
|
{
|
||||||
|
"referenceCategory": "PACKAGE-MANAGER",
|
||||||
|
"referenceType": "purl",
|
||||||
|
"referenceLocator": "pkg:golang/github.com/jessevdk/go-flags@v1.6.1"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"primaryPackagePurpose": "LIBRARY",
|
||||||
|
"copyrightText": "NOASSERTION"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "github.com/mmikulicic/multierror",
|
||||||
|
"SPDXID": "SPDXRef-Package-b08d834237b92fed",
|
||||||
|
"versionInfo": "v0.0.0-20170428094957-c1ad6b5ecd26",
|
||||||
|
"supplier": "NOASSERTION",
|
||||||
|
"downloadLocation": "NONE",
|
||||||
|
"filesAnalyzed": false,
|
||||||
|
"sourceInfo": "opt/bitnami/common/package found in: opt/bitnami/common/bin/render-template",
|
||||||
|
"licenseConcluded": "NONE",
|
||||||
|
"licenseDeclared": "NONE",
|
||||||
|
"externalRefs": [
|
||||||
|
{
|
||||||
|
"referenceCategory": "PACKAGE-MANAGER",
|
||||||
|
"referenceType": "purl",
|
||||||
|
"referenceLocator": "pkg:golang/github.com/mmikulicic/multierror@v0.0.0-20170428094957-c1ad6b5ecd26"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"primaryPackagePurpose": "LIBRARY",
|
||||||
|
"copyrightText": "NOASSERTION"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "golang.org/x/sys",
|
||||||
|
"SPDXID": "SPDXRef-Package-644a66965f04af7f",
|
||||||
|
"versionInfo": "v0.21.0",
|
||||||
|
"supplier": "NOASSERTION",
|
||||||
|
"downloadLocation": "NONE",
|
||||||
|
"filesAnalyzed": false,
|
||||||
|
"sourceInfo": "opt/bitnami/common/package found in: opt/bitnami/common/bin/render-template",
|
||||||
|
"licenseConcluded": "NONE",
|
||||||
|
"licenseDeclared": "NONE",
|
||||||
|
"externalRefs": [
|
||||||
|
{
|
||||||
|
"referenceCategory": "PACKAGE-MANAGER",
|
||||||
|
"referenceType": "purl",
|
||||||
|
"referenceLocator": "pkg:golang/golang.org/x/sys@v0.21.0"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"primaryPackagePurpose": "LIBRARY",
|
||||||
|
"copyrightText": "NOASSERTION"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "stdlib",
|
||||||
|
"SPDXID": "SPDXRef-Package-7d9b78ebb84f1578",
|
||||||
|
"versionInfo": "1.22.7",
|
||||||
|
"supplier": "NOASSERTION",
|
||||||
|
"downloadLocation": "NONE",
|
||||||
|
"filesAnalyzed": false,
|
||||||
|
"sourceInfo": "opt/bitnami/common/package found in: opt/bitnami/common/bin/render-template",
|
||||||
|
"licenseConcluded": "NONE",
|
||||||
|
"licenseDeclared": "NONE",
|
||||||
|
"externalRefs": [
|
||||||
|
{
|
||||||
|
"referenceCategory": "PACKAGE-MANAGER",
|
||||||
|
"referenceType": "purl",
|
||||||
|
"referenceLocator": "pkg:golang/stdlib@1.22.7"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"primaryPackagePurpose": "LIBRARY",
|
||||||
|
"copyrightText": "NOASSERTION"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"files": [],
|
||||||
|
"relationships": [
|
||||||
|
{
|
||||||
|
"spdxElementId": "SPDXRef-render-template",
|
||||||
|
"relationshipType": "CONTAINS",
|
||||||
|
"relatedSpdxElement": "SPDXRef-Application-4b412cf3f25d2574-render-template"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"spdxElementId": "SPDXRef-Application-4b412cf3f25d2574-render-template",
|
||||||
|
"relatedSpdxElement": "SPDXRef-Package-8213648cad51225d",
|
||||||
|
"relationshipType": "CONTAINS"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"spdxElementId": "SPDXRef-render-template",
|
||||||
|
"relatedSpdxElement": "SPDXRef-Application-4b412cf3f25d2574-render-template",
|
||||||
|
"relationshipType": "CONTAINS"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"spdxElementId": "SPDXRef-Package-8213648cad51225d",
|
||||||
|
"relatedSpdxElement": "SPDXRef-Package-644a66965f04af7f",
|
||||||
|
"relationshipType": "DEPENDS_ON"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"spdxElementId": "SPDXRef-Package-8213648cad51225d",
|
||||||
|
"relatedSpdxElement": "SPDXRef-Package-7d9b78ebb84f1578",
|
||||||
|
"relationshipType": "DEPENDS_ON"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"spdxElementId": "SPDXRef-Package-8213648cad51225d",
|
||||||
|
"relatedSpdxElement": "SPDXRef-Package-b08d834237b92fed",
|
||||||
|
"relationshipType": "DEPENDS_ON"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"spdxElementId": "SPDXRef-Package-8213648cad51225d",
|
||||||
|
"relatedSpdxElement": "SPDXRef-Package-be6fde8a3edd7caf",
|
||||||
|
"relationshipType": "DEPENDS_ON"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"spdxElementId": "SPDXRef-Package-8213648cad51225d",
|
||||||
|
"relatedSpdxElement": "SPDXRef-Package-c77f44f540ae92a0",
|
||||||
|
"relationshipType": "DEPENDS_ON"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
@ -0,0 +1,23 @@
|
|||||||
|
SPDXVersion: SPDX-2.3
|
||||||
|
DataLicense: CC0-1.0
|
||||||
|
DocumentNamespace: redis-7.4.1
|
||||||
|
DocumentName: SPDX document for Redis(R) 7.4.1
|
||||||
|
SPDXID: SPDXRef-DOCUMENT
|
||||||
|
|
||||||
|
## Creation Information
|
||||||
|
Creator: Organization: VMware, Inc.
|
||||||
|
Created: 2024-10-02T20:17:11.692Z
|
||||||
|
## Relationships
|
||||||
|
Relationship: SPDXRef-DOCUMENT DESCRIBES SPDXRef-redis
|
||||||
|
|
||||||
|
## Package Information
|
||||||
|
PackageName: redis
|
||||||
|
SPDXID: SPDXRef-redis
|
||||||
|
PackageVersion: 7.4.1-0
|
||||||
|
PackageDownloadLocation: http://download.redis.io/releases/redis-7.4.1.tar.gz
|
||||||
|
PackageLicenseConcluded: RSALv2
|
||||||
|
PackageLicenseDeclared: RSALv2
|
||||||
|
PackageCopyrightText: NOASSERTION
|
||||||
|
ExternalRef: SECURITY cpe23Type cpe:2.3:*:redis:redis:7.4.1:*:*:*:*:*:*:*
|
||||||
|
ExternalRef: PACKAGE-MANAGER purl pkg:bitnami/redis@7.4.1-0?arch=arm64&distro=debian-12
|
||||||
|
FilesAnalyzed: false
|
||||||
@ -13,6 +13,7 @@ const (
|
|||||||
AlpmPkg Type = "alpm"
|
AlpmPkg Type = "alpm"
|
||||||
ApkPkg Type = "apk"
|
ApkPkg Type = "apk"
|
||||||
BinaryPkg Type = "binary"
|
BinaryPkg Type = "binary"
|
||||||
|
BitnamiPkg Type = "bitnami"
|
||||||
CocoapodsPkg Type = "pod"
|
CocoapodsPkg Type = "pod"
|
||||||
ConanPkg Type = "conan"
|
ConanPkg Type = "conan"
|
||||||
DartPubPkg Type = "dart-pub"
|
DartPubPkg Type = "dart-pub"
|
||||||
@ -53,6 +54,7 @@ var AllPkgs = []Type{
|
|||||||
AlpmPkg,
|
AlpmPkg,
|
||||||
ApkPkg,
|
ApkPkg,
|
||||||
BinaryPkg,
|
BinaryPkg,
|
||||||
|
BitnamiPkg,
|
||||||
CocoapodsPkg,
|
CocoapodsPkg,
|
||||||
ConanPkg,
|
ConanPkg,
|
||||||
DartPubPkg,
|
DartPubPkg,
|
||||||
@ -62,6 +64,7 @@ var AllPkgs = []Type{
|
|||||||
GemPkg,
|
GemPkg,
|
||||||
GithubActionPkg,
|
GithubActionPkg,
|
||||||
GithubActionWorkflowPkg,
|
GithubActionWorkflowPkg,
|
||||||
|
GraalVMNativeImagePkg,
|
||||||
GoModulePkg,
|
GoModulePkg,
|
||||||
HackagePkg,
|
HackagePkg,
|
||||||
HexPkg,
|
HexPkg,
|
||||||
@ -96,6 +99,8 @@ func (t Type) PackageURLType() string {
|
|||||||
return "alpm"
|
return "alpm"
|
||||||
case ApkPkg:
|
case ApkPkg:
|
||||||
return packageurl.TypeAlpine
|
return packageurl.TypeAlpine
|
||||||
|
case BitnamiPkg:
|
||||||
|
return packageurl.TypeBitnami
|
||||||
case CocoapodsPkg:
|
case CocoapodsPkg:
|
||||||
return packageurl.TypeCocoapods
|
return packageurl.TypeCocoapods
|
||||||
case ConanPkg:
|
case ConanPkg:
|
||||||
@ -177,28 +182,20 @@ func TypeFromPURL(p string) Type {
|
|||||||
//nolint:funlen,gocyclo
|
//nolint:funlen,gocyclo
|
||||||
func TypeByName(name string) Type {
|
func TypeByName(name string) Type {
|
||||||
switch name {
|
switch name {
|
||||||
case packageurl.TypeDebian:
|
|
||||||
return DebPkg
|
|
||||||
case packageurl.TypeRPM:
|
|
||||||
return RpmPkg
|
|
||||||
case packageurl.TypeLuaRocks:
|
|
||||||
return LuaRocksPkg
|
|
||||||
case "alpm":
|
case "alpm":
|
||||||
return AlpmPkg
|
return AlpmPkg
|
||||||
case packageurl.TypeAlpine, "alpine":
|
case packageurl.TypeAlpine, "alpine":
|
||||||
return ApkPkg
|
return ApkPkg
|
||||||
case packageurl.TypeMaven:
|
case packageurl.TypeBitnami:
|
||||||
return JavaPkg
|
return BitnamiPkg
|
||||||
|
case packageurl.TypeDebian:
|
||||||
|
return DebPkg
|
||||||
case packageurl.TypeComposer:
|
case packageurl.TypeComposer:
|
||||||
return PhpComposerPkg
|
return PhpComposerPkg
|
||||||
case "pecl":
|
case "pecl":
|
||||||
return PhpPeclPkg
|
return PhpPeclPkg
|
||||||
case packageurl.TypeGolang:
|
case packageurl.TypeGolang:
|
||||||
return GoModulePkg
|
return GoModulePkg
|
||||||
case packageurl.TypeNPM:
|
|
||||||
return NpmPkg
|
|
||||||
case packageurl.TypePyPi:
|
|
||||||
return PythonPkg
|
|
||||||
case packageurl.TypeGem:
|
case packageurl.TypeGem:
|
||||||
return GemPkg
|
return GemPkg
|
||||||
case "cargo", "crate":
|
case "cargo", "crate":
|
||||||
@ -213,10 +210,18 @@ func TypeByName(name string) Type {
|
|||||||
return ConanPkg
|
return ConanPkg
|
||||||
case packageurl.TypeHackage:
|
case packageurl.TypeHackage:
|
||||||
return HackagePkg
|
return HackagePkg
|
||||||
case "portage":
|
|
||||||
return PortagePkg
|
|
||||||
case packageurl.TypeHex:
|
case packageurl.TypeHex:
|
||||||
return HexPkg
|
return HexPkg
|
||||||
|
case packageurl.TypeLuaRocks:
|
||||||
|
return LuaRocksPkg
|
||||||
|
case packageurl.TypeMaven:
|
||||||
|
return JavaPkg
|
||||||
|
case packageurl.TypeNPM:
|
||||||
|
return NpmPkg
|
||||||
|
case packageurl.TypePyPi:
|
||||||
|
return PythonPkg
|
||||||
|
case "portage":
|
||||||
|
return PortagePkg
|
||||||
case packageurl.TypeOTP:
|
case packageurl.TypeOTP:
|
||||||
return ErlangOTPPkg
|
return ErlangOTPPkg
|
||||||
case "linux-kernel":
|
case "linux-kernel":
|
||||||
@ -229,6 +234,8 @@ func TypeByName(name string) Type {
|
|||||||
return OpamPkg
|
return OpamPkg
|
||||||
case packageurl.TypeCran:
|
case packageurl.TypeCran:
|
||||||
return Rpkg
|
return Rpkg
|
||||||
|
case packageurl.TypeRPM:
|
||||||
|
return RpmPkg
|
||||||
case packageurl.TypeSwift:
|
case packageurl.TypeSwift:
|
||||||
return SwiftPkg
|
return SwiftPkg
|
||||||
case "swiplpack":
|
case "swiplpack":
|
||||||
|
|||||||
@ -22,6 +22,10 @@ func TestTypeFromPURL(t *testing.T) {
|
|||||||
purl: "pkg:apk/alpine/util-linux@2.32.1",
|
purl: "pkg:apk/alpine/util-linux@2.32.1",
|
||||||
expected: ApkPkg,
|
expected: ApkPkg,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
purl: "pkg:bitnami/apache@2.4.62-3?arch=arm64&distro=debian-12",
|
||||||
|
expected: BitnamiPkg,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
purl: "pkg:deb/debian/curl@7.50.3-1?arch=i386&distro=jessie",
|
purl: "pkg:deb/debian/curl@7.50.3-1?arch=i386&distro=jessie",
|
||||||
expected: DebPkg,
|
expected: DebPkg,
|
||||||
@ -50,7 +54,6 @@ func TestTypeFromPURL(t *testing.T) {
|
|||||||
purl: "pkg:pub/util@1.2.34?hosted_url=pub.hosted.org",
|
purl: "pkg:pub/util@1.2.34?hosted_url=pub.hosted.org",
|
||||||
expected: DartPubPkg,
|
expected: DartPubPkg,
|
||||||
},
|
},
|
||||||
|
|
||||||
{
|
{
|
||||||
purl: "pkg:dotnet/Microsoft.CodeAnalysis.Razor@2.2.0",
|
purl: "pkg:dotnet/Microsoft.CodeAnalysis.Razor@2.2.0",
|
||||||
expected: DotnetPkg,
|
expected: DotnetPkg,
|
||||||
@ -137,6 +140,7 @@ func TestTypeFromPURL(t *testing.T) {
|
|||||||
expectedTypes.Remove(string(GithubActionPkg), string(GithubActionWorkflowPkg))
|
expectedTypes.Remove(string(GithubActionPkg), string(GithubActionWorkflowPkg))
|
||||||
expectedTypes.Remove(string(WordpressPluginPkg))
|
expectedTypes.Remove(string(WordpressPluginPkg))
|
||||||
expectedTypes.Remove(string(TerraformPkg))
|
expectedTypes.Remove(string(TerraformPkg))
|
||||||
|
expectedTypes.Remove(string(GraalVMNativeImagePkg))
|
||||||
|
|
||||||
for _, test := range tests {
|
for _, test := range tests {
|
||||||
t.Run(string(test.expected), func(t *testing.T) {
|
t.Run(string(test.expected), func(t *testing.T) {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user