mirror of
https://github.com/anchore/syft.git
synced 2026-10-12 06:07:20 +02:00
Compare commits
2
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a3bd5145d2 | ||
|
|
6a33b80048 |
@@ -6,6 +6,7 @@ import (
|
||||
"github.com/anchore/syft/syft/pkg/cataloger/alpine"
|
||||
"github.com/anchore/syft/syft/pkg/cataloger/arch"
|
||||
"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/dart"
|
||||
"github.com/anchore/syft/syft/pkg/cataloger/debian"
|
||||
@@ -150,6 +151,7 @@ func DefaultPackageTaskFactories() PackageTaskFactories {
|
||||
pkgcataloging.DeclaredTag, pkgcataloging.DirectoryTag, pkgcataloging.InstalledTag, pkgcataloging.ImageTag, "linux", "kernel",
|
||||
),
|
||||
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"),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,83 @@
|
||||
/*
|
||||
Package bitnami provides a concrete Cataloger implementation for capturing packages embedded within Bitnami SBOM files.
|
||||
*/
|
||||
package bitnami
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"fmt"
|
||||
"io"
|
||||
|
||||
"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",
|
||||
)
|
||||
}
|
||||
|
||||
// TODO: this is copied from the sbom-cataloger
|
||||
// it should probably be slimmed down so as not to duplicate
|
||||
// parts of the SBOM cataloger that it doesn't need.
|
||||
func parseSBOM(_ context.Context, _ file.Resolver, _ *generic.Environment, reader file.LocationReadCloser) ([]pkg.Package, []artifact.Relationship, error) {
|
||||
readSeeker, err := adaptToReadSeeker(reader)
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("unable to read SBOM file %q: %w", reader.Location.RealPath, err)
|
||||
}
|
||||
s, _, _, err := format.Decode(readSeeker)
|
||||
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
|
||||
}
|
||||
|
||||
var pkgs []pkg.Package
|
||||
relationships := s.Relationships
|
||||
for _, p := range s.Artifacts.Packages.Sorted() {
|
||||
// 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),
|
||||
)
|
||||
p.FoundBy = catalogerName
|
||||
|
||||
pkgs = append(pkgs, p)
|
||||
relationships = append(relationships, artifact.Relationship{
|
||||
From: p,
|
||||
To: reader.Location.Coordinates,
|
||||
Type: artifact.DescribedByRelationship,
|
||||
})
|
||||
}
|
||||
|
||||
return pkgs, relationships, nil
|
||||
}
|
||||
|
||||
func adaptToReadSeeker(reader io.Reader) (io.ReadSeeker, error) {
|
||||
// with the stereoscope API and default file.Resolver implementation here in syft, odds are very high that
|
||||
// the underlying reader is already a ReadSeeker, so we can just return it as-is. We still want to
|
||||
if rs, ok := reader.(io.ReadSeeker); ok {
|
||||
return rs, nil
|
||||
}
|
||||
|
||||
log.Debug("SBOM cataloger reader is not a ReadSeeker, reading entire SBOM into memory")
|
||||
|
||||
var buff bytes.Buffer
|
||||
_, err := io.Copy(&buff, reader)
|
||||
return bytes.NewReader(buff.Bytes()), err
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
package bitnami
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/anchore/syft/syft/artifact"
|
||||
"github.com/anchore/syft/syft/pkg"
|
||||
"github.com/anchore/syft/syft/pkg/cataloger/internal/pkgtest"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestBitnamiCataloger(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
fixture string
|
||||
wantPkgs []pkg.Package
|
||||
wantError require.ErrorAssertionFunc
|
||||
}{
|
||||
{
|
||||
name: "simple-redis-sbom",
|
||||
fixture: "test-fixtures",
|
||||
// TODO: add package assertions
|
||||
},
|
||||
// TODO: add another test case or too, maybe an error case
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
pkgtest.NewCatalogTester().
|
||||
FromDirectory(t, tt.fixture).
|
||||
ExpectsAssertion(func(t *testing.T, pkgs []pkg.Package, relationships []artifact.Relationship) {
|
||||
for i, p := range pkgs {
|
||||
assert.Equal(t, p.Name, tt.wantPkgs[i].Name)
|
||||
assert.Equal(t, p.Version, tt.wantPkgs[i].Version)
|
||||
}
|
||||
}).
|
||||
TestCataloger(t, NewCataloger())
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
{
|
||||
"SPDXID": "SPDXRef-redis",
|
||||
"spdxVersion": "SPDX-2.3",
|
||||
"creationInfo": {
|
||||
"created": "2024-08-08T11:12:35.680Z",
|
||||
"creators": [
|
||||
"Organization: VMware, Inc."
|
||||
]
|
||||
},
|
||||
"name": "SPDX document for Redis(R) 7.4.0",
|
||||
"dataLicense": "CC0-1.0",
|
||||
"documentDescribes": [
|
||||
"SPDXRef-redis"
|
||||
],
|
||||
"documentNamespace": "redis-7.4.0",
|
||||
"packages": [
|
||||
{
|
||||
"SPDXID": "SPDXRef-redis",
|
||||
"name": "redis",
|
||||
"versionInfo": "7.4.0-0",
|
||||
"downloadLocation": "http://download.redis.io/releases/redis-7.4.0.tar.gz",
|
||||
"licenseConcluded": "RSALv2",
|
||||
"licenseDeclared": "RSALv2",
|
||||
"filesAnalyzed": false,
|
||||
"externalRefs": [
|
||||
{
|
||||
"referenceCategory": "SECURITY",
|
||||
"referenceType": "cpe23Type",
|
||||
"referenceLocator": "cpe:2.3:*:redis:redis:7.4.0:*:*:*:*:*:*:*"
|
||||
},
|
||||
{
|
||||
"referenceCategory": "PACKAGE-MANAGER",
|
||||
"referenceType": "purl",
|
||||
"referenceLocator": "pkg:bitnami/redis@7.4.0-0?arch=arm64&distro=debian-12"
|
||||
}
|
||||
],
|
||||
"copyrightText": "NOASSERTION"
|
||||
}
|
||||
],
|
||||
"files": [],
|
||||
"relationships": []
|
||||
}
|
||||
Reference in New Issue
Block a user