mirror of
https://github.com/anchore/syft.git
synced 2026-02-13 02:56:42 +01:00
add a cataloger for binaries built with rust-audit (#1116)
* add a cataloger for binaries built with rust-audit Signed-off-by: Tom Fay <tomfay@microsoft.com>
This commit is contained in:
parent
62897fbc89
commit
9896ff1b1f
@ -412,6 +412,8 @@ platform: ""
|
|||||||
# - dartlang-lock
|
# - dartlang-lock
|
||||||
# - rust
|
# - rust
|
||||||
# - dotnet-deps
|
# - dotnet-deps
|
||||||
|
# rust-audit-binary scans Rust binaries built with https://github.com/Shnatsel/rust-audit
|
||||||
|
# - rust-audit-binary
|
||||||
catalogers:
|
catalogers:
|
||||||
|
|
||||||
# cataloging packages is exposed through the packages and power-user subcommands
|
# cataloging packages is exposed through the packages and power-user subcommands
|
||||||
|
|||||||
1
go.mod
1
go.mod
@ -26,6 +26,7 @@ require (
|
|||||||
github.com/jinzhu/copier v0.3.2
|
github.com/jinzhu/copier v0.3.2
|
||||||
github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d // indirect
|
github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d // indirect
|
||||||
github.com/mholt/archiver/v3 v3.5.1
|
github.com/mholt/archiver/v3 v3.5.1
|
||||||
|
github.com/microsoft/go-rustaudit v0.0.0-20220722052050-3b1735710a8e
|
||||||
github.com/mitchellh/go-homedir v1.1.0
|
github.com/mitchellh/go-homedir v1.1.0
|
||||||
github.com/mitchellh/hashstructure/v2 v2.0.2
|
github.com/mitchellh/hashstructure/v2 v2.0.2
|
||||||
github.com/mitchellh/mapstructure v1.5.0
|
github.com/mitchellh/mapstructure v1.5.0
|
||||||
|
|||||||
2
go.sum
2
go.sum
@ -1373,6 +1373,8 @@ github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d h1:5PJl274Y63IEHC+7izoQ
|
|||||||
github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE=
|
github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE=
|
||||||
github.com/mholt/archiver/v3 v3.5.1 h1:rDjOBX9JSF5BvoJGvjqK479aL70qh9DIpZCl+k7Clwo=
|
github.com/mholt/archiver/v3 v3.5.1 h1:rDjOBX9JSF5BvoJGvjqK479aL70qh9DIpZCl+k7Clwo=
|
||||||
github.com/mholt/archiver/v3 v3.5.1/go.mod h1:e3dqJ7H78uzsRSEACH1joayhuSyhnonssnDhppzS1L4=
|
github.com/mholt/archiver/v3 v3.5.1/go.mod h1:e3dqJ7H78uzsRSEACH1joayhuSyhnonssnDhppzS1L4=
|
||||||
|
github.com/microsoft/go-rustaudit v0.0.0-20220722052050-3b1735710a8e h1:dMQrsCOQEkVsvtzvg4jH0I/AN4+f14E5emA2BdUwy50=
|
||||||
|
github.com/microsoft/go-rustaudit v0.0.0-20220722052050-3b1735710a8e/go.mod h1:vYT9HE7WCvL64iVeZylKmCsWKfE+JZ8105iuh2Trk8g=
|
||||||
github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=
|
github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=
|
||||||
github.com/miekg/dns v1.1.26/go.mod h1:bPDLeHnStXmXAq1m/Ch/hvfNHr14JKNPMBo3VZKjuso=
|
github.com/miekg/dns v1.1.26/go.mod h1:bPDLeHnStXmXAq1m/Ch/hvfNHr14JKNPMBo3VZKjuso=
|
||||||
github.com/miekg/dns v1.1.35/go.mod h1:KNUDUusw/aVsxyTYZM1oqvCicbwhgbNgztCETuNZ7xM=
|
github.com/miekg/dns v1.1.35/go.mod h1:KNUDUusw/aVsxyTYZM1oqvCicbwhgbNgztCETuNZ7xM=
|
||||||
|
|||||||
@ -105,6 +105,7 @@ func AllCatalogers(cfg Config) []Cataloger {
|
|||||||
golang.NewGoModuleBinaryCataloger(),
|
golang.NewGoModuleBinaryCataloger(),
|
||||||
golang.NewGoModFileCataloger(),
|
golang.NewGoModFileCataloger(),
|
||||||
rust.NewCargoLockCataloger(),
|
rust.NewCargoLockCataloger(),
|
||||||
|
rust.NewRustAuditBinaryCataloger(),
|
||||||
dart.NewPubspecLockCataloger(),
|
dart.NewPubspecLockCataloger(),
|
||||||
dotnet.NewDotnetDepsCataloger(),
|
dotnet.NewDotnetDepsCataloger(),
|
||||||
php.NewPHPComposerInstalledCataloger(),
|
php.NewPHPComposerInstalledCataloger(),
|
||||||
|
|||||||
@ -4,15 +4,13 @@ Package golang provides a concrete Cataloger implementation for go.mod files.
|
|||||||
package golang
|
package golang
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
|
||||||
"io/ioutil"
|
|
||||||
|
|
||||||
"github.com/anchore/syft/internal"
|
"github.com/anchore/syft/internal"
|
||||||
"github.com/anchore/syft/internal/log"
|
"github.com/anchore/syft/internal/log"
|
||||||
"github.com/anchore/syft/syft/artifact"
|
"github.com/anchore/syft/syft/artifact"
|
||||||
"github.com/anchore/syft/syft/pkg"
|
"github.com/anchore/syft/syft/pkg"
|
||||||
|
"github.com/anchore/syft/syft/pkg/cataloger/internal/unionreader"
|
||||||
"github.com/anchore/syft/syft/source"
|
"github.com/anchore/syft/syft/source"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -46,7 +44,7 @@ func (c *Cataloger) Catalog(resolver source.FileResolver) ([]pkg.Package, []arti
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
reader, err := getUnionReader(readerCloser)
|
reader, err := unionreader.GetUnionReader(readerCloser)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
@ -61,30 +59,3 @@ func (c *Cataloger) Catalog(resolver source.FileResolver) ([]pkg.Package, []arti
|
|||||||
|
|
||||||
return pkgs, nil, nil
|
return pkgs, nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func getUnionReader(readerCloser io.ReadCloser) (unionReader, error) {
|
|
||||||
reader, ok := readerCloser.(unionReader)
|
|
||||||
if ok {
|
|
||||||
return reader, nil
|
|
||||||
}
|
|
||||||
log.Debugf("golang cataloger: unable to use stereoscope file, reading entire contents")
|
|
||||||
|
|
||||||
b, err := ioutil.ReadAll(readerCloser)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("unable to read contents from go binary: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
bytesReader := bytes.NewReader(b)
|
|
||||||
|
|
||||||
reader = struct {
|
|
||||||
io.ReadCloser
|
|
||||||
io.ReaderAt
|
|
||||||
io.Seeker
|
|
||||||
}{
|
|
||||||
ReadCloser: io.NopCloser(bytesReader),
|
|
||||||
ReaderAt: bytesReader,
|
|
||||||
Seeker: bytesReader,
|
|
||||||
}
|
|
||||||
|
|
||||||
return reader, nil
|
|
||||||
}
|
|
||||||
|
|||||||
@ -2,27 +2,17 @@ package golang
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"debug/buildinfo"
|
"debug/buildinfo"
|
||||||
"io"
|
|
||||||
"runtime/debug"
|
"runtime/debug"
|
||||||
|
|
||||||
macho "github.com/anchore/go-macholibre"
|
|
||||||
"github.com/anchore/syft/internal/log"
|
"github.com/anchore/syft/internal/log"
|
||||||
|
"github.com/anchore/syft/syft/pkg/cataloger/internal/unionreader"
|
||||||
)
|
)
|
||||||
|
|
||||||
// unionReader is a single interface with all reading functions used by golang bin
|
|
||||||
// cataloger.
|
|
||||||
type unionReader interface {
|
|
||||||
io.Reader
|
|
||||||
io.ReaderAt
|
|
||||||
io.Seeker
|
|
||||||
io.Closer
|
|
||||||
}
|
|
||||||
|
|
||||||
// scanFile scans file to try to report the Go and module versions.
|
// scanFile scans file to try to report the Go and module versions.
|
||||||
func scanFile(reader unionReader, filename string) ([]*debug.BuildInfo, []string) {
|
func scanFile(reader unionreader.UnionReader, filename string) ([]*debug.BuildInfo, []string) {
|
||||||
// NOTE: multiple readers are returned to cover universal binaries, which are files
|
// NOTE: multiple readers are returned to cover universal binaries, which are files
|
||||||
// with more than one binary
|
// with more than one binary
|
||||||
readers, err := getReaders(reader)
|
readers, err := unionreader.GetReaders(reader)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Warnf("golang cataloger: failed to open a binary: %v", err)
|
log.Warnf("golang cataloger: failed to open a binary: %v", err)
|
||||||
return nil, nil
|
return nil, nil
|
||||||
@ -56,23 +46,3 @@ func scanFile(reader unionReader, filename string) ([]*debug.BuildInfo, []string
|
|||||||
|
|
||||||
return builds, archs
|
return builds, archs
|
||||||
}
|
}
|
||||||
|
|
||||||
// getReaders extracts one or more io.ReaderAt objects representing binaries that can be processed (multiple binaries in the case for multi-architecture binaries).
|
|
||||||
func getReaders(f unionReader) ([]io.ReaderAt, error) {
|
|
||||||
if macho.IsUniversalMachoBinary(f) {
|
|
||||||
machoReaders, err := macho.ExtractReaders(f)
|
|
||||||
if err != nil {
|
|
||||||
log.Debugf("extracting readers: %v", err)
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
var readers []io.ReaderAt
|
|
||||||
for _, e := range machoReaders {
|
|
||||||
readers = append(readers, e.Reader)
|
|
||||||
}
|
|
||||||
|
|
||||||
return readers, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
return []io.ReaderAt{f}, nil
|
|
||||||
}
|
|
||||||
|
|||||||
66
syft/pkg/cataloger/internal/unionreader/union_reader.go
Normal file
66
syft/pkg/cataloger/internal/unionreader/union_reader.go
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
package unionreader
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"io/ioutil"
|
||||||
|
|
||||||
|
macho "github.com/anchore/go-macholibre"
|
||||||
|
"github.com/anchore/syft/internal/log"
|
||||||
|
)
|
||||||
|
|
||||||
|
// unionReader is a single interface with all reading functions needed by multi-arch binary catalogers
|
||||||
|
// cataloger.
|
||||||
|
type UnionReader interface {
|
||||||
|
io.Reader
|
||||||
|
io.ReaderAt
|
||||||
|
io.Seeker
|
||||||
|
io.Closer
|
||||||
|
}
|
||||||
|
|
||||||
|
// getReaders extracts one or more io.ReaderAt objects representing binaries that can be processed (multiple binaries in the case for multi-architecture binaries).
|
||||||
|
func GetReaders(f UnionReader) ([]io.ReaderAt, error) {
|
||||||
|
if macho.IsUniversalMachoBinary(f) {
|
||||||
|
machoReaders, err := macho.ExtractReaders(f)
|
||||||
|
if err != nil {
|
||||||
|
log.Debugf("extracting readers: %v", err)
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var readers []io.ReaderAt
|
||||||
|
for _, e := range machoReaders {
|
||||||
|
readers = append(readers, e.Reader)
|
||||||
|
}
|
||||||
|
|
||||||
|
return readers, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return []io.ReaderAt{f}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetUnionReader(readerCloser io.ReadCloser) (UnionReader, error) {
|
||||||
|
reader, ok := readerCloser.(UnionReader)
|
||||||
|
if ok {
|
||||||
|
return reader, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
b, err := ioutil.ReadAll(readerCloser)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("unable to read contents from binary: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
bytesReader := bytes.NewReader(b)
|
||||||
|
|
||||||
|
reader = struct {
|
||||||
|
io.ReadCloser
|
||||||
|
io.ReaderAt
|
||||||
|
io.Seeker
|
||||||
|
}{
|
||||||
|
ReadCloser: io.NopCloser(bytesReader),
|
||||||
|
ReaderAt: bytesReader,
|
||||||
|
Seeker: bytesReader,
|
||||||
|
}
|
||||||
|
|
||||||
|
return reader, nil
|
||||||
|
}
|
||||||
@ -1,4 +1,4 @@
|
|||||||
package golang
|
package unionreader
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"io"
|
"io"
|
||||||
@ -14,13 +14,13 @@ func Test_getUnionReader_notUnionReader(t *testing.T) {
|
|||||||
reader := io.NopCloser(strings.NewReader(expectedContents))
|
reader := io.NopCloser(strings.NewReader(expectedContents))
|
||||||
|
|
||||||
// make certain that the test fixture does not implement the union reader
|
// make certain that the test fixture does not implement the union reader
|
||||||
_, ok := reader.(unionReader)
|
_, ok := reader.(UnionReader)
|
||||||
require.False(t, ok)
|
require.False(t, ok)
|
||||||
|
|
||||||
actual, err := getUnionReader(reader)
|
actual, err := GetUnionReader(reader)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
_, ok = actual.(unionReader)
|
_, ok = actual.(UnionReader)
|
||||||
require.True(t, ok)
|
require.True(t, ok)
|
||||||
|
|
||||||
b, err := io.ReadAll(actual)
|
b, err := io.ReadAll(actual)
|
||||||
126
syft/pkg/cataloger/rust/audit_binary_cataloger.go
Normal file
126
syft/pkg/cataloger/rust/audit_binary_cataloger.go
Normal file
@ -0,0 +1,126 @@
|
|||||||
|
package rust
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/anchore/syft/internal"
|
||||||
|
"github.com/anchore/syft/internal/log"
|
||||||
|
"github.com/anchore/syft/syft/artifact"
|
||||||
|
"github.com/anchore/syft/syft/pkg"
|
||||||
|
"github.com/anchore/syft/syft/pkg/cataloger/internal/unionreader"
|
||||||
|
"github.com/anchore/syft/syft/source"
|
||||||
|
rustaudit "github.com/microsoft/go-rustaudit"
|
||||||
|
)
|
||||||
|
|
||||||
|
const catalogerName = "rust-audit-binary-cataloger"
|
||||||
|
|
||||||
|
type Cataloger struct{}
|
||||||
|
|
||||||
|
// NewRustAuditBinaryCataloger returns a new Rust auditable binary cataloger object that can detect dependencies
|
||||||
|
// in binaries produced with https://github.com/Shnatsel/rust-audit
|
||||||
|
func NewRustAuditBinaryCataloger() *Cataloger {
|
||||||
|
return &Cataloger{}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Name returns a string that uniquely describes a cataloger
|
||||||
|
func (c *Cataloger) Name() string {
|
||||||
|
return catalogerName
|
||||||
|
}
|
||||||
|
|
||||||
|
// Catalog identifies executables then attempts to read Rust dependency information from them
|
||||||
|
func (c *Cataloger) Catalog(resolver source.FileResolver) ([]pkg.Package, []artifact.Relationship, error) {
|
||||||
|
var pkgs []pkg.Package
|
||||||
|
|
||||||
|
fileMatches, err := resolver.FilesByMIMEType(internal.ExecutableMIMETypeSet.List()...)
|
||||||
|
if err != nil {
|
||||||
|
return pkgs, nil, fmt.Errorf("failed to find bin by mime types: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, location := range fileMatches {
|
||||||
|
readerCloser, err := resolver.FileContentsByLocation(location)
|
||||||
|
if err != nil {
|
||||||
|
log.Warnf("rust cataloger: opening file: %v", err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
reader, err := unionreader.GetUnionReader(readerCloser)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
versionInfos := scanFile(reader, location.RealPath)
|
||||||
|
internal.CloseAndLogError(readerCloser, location.RealPath)
|
||||||
|
|
||||||
|
for _, versionInfo := range versionInfos {
|
||||||
|
pkgs = append(pkgs, buildRustPkgInfo(location, versionInfo)...)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return pkgs, nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// scanFile scans file to try to report the Rust crate dependencies
|
||||||
|
func scanFile(reader unionreader.UnionReader, filename string) []rustaudit.VersionInfo {
|
||||||
|
// NOTE: multiple readers are returned to cover universal binaries, which are files
|
||||||
|
// with more than one binary
|
||||||
|
readers, err := unionreader.GetReaders(reader)
|
||||||
|
if err != nil {
|
||||||
|
log.Warnf("rust cataloger: failed to open a binary: %v", err)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
var versionInfos []rustaudit.VersionInfo
|
||||||
|
for _, r := range readers {
|
||||||
|
versionInfo, err := rustaudit.GetDependencyInfo(r)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
if err == rustaudit.ErrNoRustDepInfo {
|
||||||
|
// since the cataloger can only select executables and not distinguish if they are a Rust-compiled
|
||||||
|
// binary, we should not show warnings/logs in this case.
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
// Use an Info level log here like golang/scan_bin.go
|
||||||
|
log.Infof("rust cataloger: unable to read dependency information (file=%q): %v", filename, err)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
versionInfos = append(versionInfos, versionInfo)
|
||||||
|
}
|
||||||
|
|
||||||
|
return versionInfos
|
||||||
|
}
|
||||||
|
|
||||||
|
func buildRustPkgInfo(location source.Location, versionInfo rustaudit.VersionInfo) []pkg.Package {
|
||||||
|
var pkgs []pkg.Package
|
||||||
|
|
||||||
|
for _, dep := range versionInfo.Packages {
|
||||||
|
dep := dep
|
||||||
|
p := newRustPackage(&dep, location)
|
||||||
|
if pkg.IsValid(&p) && dep.Kind == rustaudit.Runtime {
|
||||||
|
pkgs = append(pkgs, p)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return pkgs
|
||||||
|
}
|
||||||
|
|
||||||
|
func newRustPackage(dep *rustaudit.Package, location source.Location) pkg.Package {
|
||||||
|
p := pkg.Package{
|
||||||
|
FoundBy: catalogerName,
|
||||||
|
Name: dep.Name,
|
||||||
|
Version: dep.Version,
|
||||||
|
Language: pkg.Rust,
|
||||||
|
Type: pkg.RustPkg,
|
||||||
|
Locations: source.NewLocationSet(location),
|
||||||
|
MetadataType: pkg.RustCargoPackageMetadataType,
|
||||||
|
Metadata: pkg.CargoPackageMetadata{
|
||||||
|
Name: dep.Name,
|
||||||
|
Version: dep.Version,
|
||||||
|
Source: dep.Source,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
p.SetID()
|
||||||
|
|
||||||
|
return p
|
||||||
|
}
|
||||||
@ -54,7 +54,7 @@ func BenchmarkImagePackageCatalogers(b *testing.B) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestPkgCoverageImage(t *testing.T) {
|
func TestPkgCoverageImage(t *testing.T) {
|
||||||
sbom, _ := catalogFixtureImage(t, "image-pkg-coverage", source.SquashedScope)
|
sbom, _ := catalogFixtureImage(t, "image-pkg-coverage", source.SquashedScope, false)
|
||||||
|
|
||||||
observedLanguages := internal.NewStringSet()
|
observedLanguages := internal.NewStringSet()
|
||||||
definedLanguages := internal.NewStringSet()
|
definedLanguages := internal.NewStringSet()
|
||||||
|
|||||||
@ -36,7 +36,7 @@ var convertibleFormats = []sbom.Format{
|
|||||||
func TestConvertCmd(t *testing.T) {
|
func TestConvertCmd(t *testing.T) {
|
||||||
for _, format := range convertibleFormats {
|
for _, format := range convertibleFormats {
|
||||||
t.Run(format.ID().String(), func(t *testing.T) {
|
t.Run(format.ID().String(), func(t *testing.T) {
|
||||||
sbom, _ := catalogFixtureImage(t, "image-pkg-coverage", source.SquashedScope)
|
sbom, _ := catalogFixtureImage(t, "image-pkg-coverage", source.SquashedScope, false)
|
||||||
format := syft.FormatByID(syftjson.ID)
|
format := syft.FormatByID(syftjson.ID)
|
||||||
|
|
||||||
f, err := ioutil.TempFile("", "test-convert-sbom-")
|
f, err := ioutil.TempFile("", "test-convert-sbom-")
|
||||||
|
|||||||
@ -10,7 +10,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func TestDistroImage(t *testing.T) {
|
func TestDistroImage(t *testing.T) {
|
||||||
sbom, _ := catalogFixtureImage(t, "image-distro-id", source.SquashedScope)
|
sbom, _ := catalogFixtureImage(t, "image-distro-id", source.SquashedScope, false)
|
||||||
|
|
||||||
expected := &linux.Release{
|
expected := &linux.Release{
|
||||||
PrettyName: "BusyBox v1.31.1",
|
PrettyName: "BusyBox v1.31.1",
|
||||||
|
|||||||
@ -64,7 +64,7 @@ func TestEncodeDecodeEncodeCycleComparison(t *testing.T) {
|
|||||||
for _, test := range tests {
|
for _, test := range tests {
|
||||||
t.Run(fmt.Sprintf("%s", test.formatOption), func(t *testing.T) {
|
t.Run(fmt.Sprintf("%s", test.formatOption), func(t *testing.T) {
|
||||||
for _, image := range images {
|
for _, image := range images {
|
||||||
originalSBOM, _ := catalogFixtureImage(t, image, source.SquashedScope)
|
originalSBOM, _ := catalogFixtureImage(t, image, source.SquashedScope, false)
|
||||||
|
|
||||||
format := syft.FormatByID(test.formatOption)
|
format := syft.FormatByID(test.formatOption)
|
||||||
require.NotNil(t, format)
|
require.NotNil(t, format)
|
||||||
|
|||||||
@ -8,7 +8,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func TestMarinerDistroless(t *testing.T) {
|
func TestMarinerDistroless(t *testing.T) {
|
||||||
sbom, _ := catalogFixtureImage(t, "image-mariner-distroless", source.SquashedScope)
|
sbom, _ := catalogFixtureImage(t, "image-mariner-distroless", source.SquashedScope, false)
|
||||||
|
|
||||||
expectedPkgs := 12
|
expectedPkgs := 12
|
||||||
actualPkgs := 0
|
actualPkgs := 0
|
||||||
|
|||||||
@ -56,7 +56,7 @@ func TestPackageDeduplication(t *testing.T) {
|
|||||||
|
|
||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
t.Run(string(tt.scope), func(t *testing.T) {
|
t.Run(string(tt.scope), func(t *testing.T) {
|
||||||
sbom, _ := catalogFixtureImage(t, "image-vertical-package-dups", tt.scope)
|
sbom, _ := catalogFixtureImage(t, "image-vertical-package-dups", tt.scope, false)
|
||||||
|
|
||||||
assert.Equal(t, tt.packageCount, sbom.Artifacts.PackageCatalog.PackageCount())
|
assert.Equal(t, tt.packageCount, sbom.Artifacts.PackageCatalog.PackageCount())
|
||||||
for name, expectedInstanceCount := range tt.instanceCount {
|
for name, expectedInstanceCount := range tt.instanceCount {
|
||||||
|
|||||||
@ -23,7 +23,7 @@ func TestPackageOwnershipRelationships(t *testing.T) {
|
|||||||
|
|
||||||
for _, test := range tests {
|
for _, test := range tests {
|
||||||
t.Run(test.fixture, func(t *testing.T) {
|
t.Run(test.fixture, func(t *testing.T) {
|
||||||
sbom, _ := catalogFixtureImage(t, test.fixture, source.SquashedScope)
|
sbom, _ := catalogFixtureImage(t, test.fixture, source.SquashedScope, false)
|
||||||
|
|
||||||
output := bytes.NewBufferString("")
|
output := bytes.NewBufferString("")
|
||||||
err := syftjson.Format().Encode(output, sbom)
|
err := syftjson.Format().Encode(output, sbom)
|
||||||
|
|||||||
@ -10,7 +10,7 @@ import (
|
|||||||
func TestRegression212ApkBufferSize(t *testing.T) {
|
func TestRegression212ApkBufferSize(t *testing.T) {
|
||||||
// This is a regression test for issue #212 (https://github.com/anchore/syft/issues/212) in which the apk db could
|
// This is a regression test for issue #212 (https://github.com/anchore/syft/issues/212) in which the apk db could
|
||||||
// not be processed due to a scanner buffer that was too small
|
// not be processed due to a scanner buffer that was too small
|
||||||
sbom, _ := catalogFixtureImage(t, "image-large-apk-data", source.SquashedScope)
|
sbom, _ := catalogFixtureImage(t, "image-large-apk-data", source.SquashedScope, false)
|
||||||
|
|
||||||
expectedPkgs := 58
|
expectedPkgs := 58
|
||||||
actualPkgs := 0
|
actualPkgs := 0
|
||||||
|
|||||||
@ -16,7 +16,7 @@ func TestRegressionGoArchDiscovery(t *testing.T) {
|
|||||||
)
|
)
|
||||||
// This is a regression test to make sure the way we detect go binary packages
|
// This is a regression test to make sure the way we detect go binary packages
|
||||||
// stays consistent and reproducible as the tool chain evolves
|
// stays consistent and reproducible as the tool chain evolves
|
||||||
sbom, _ := catalogFixtureImage(t, "image-go-bin-arch-coverage", source.SquashedScope)
|
sbom, _ := catalogFixtureImage(t, "image-go-bin-arch-coverage", source.SquashedScope, false)
|
||||||
|
|
||||||
var actualELF, actualWIN, actualMACOS int
|
var actualELF, actualWIN, actualMACOS int
|
||||||
|
|
||||||
|
|||||||
@ -6,5 +6,5 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func TestRegressionJavaNoMainPackage(t *testing.T) { // Regression: https://github.com/anchore/syft/issues/252
|
func TestRegressionJavaNoMainPackage(t *testing.T) { // Regression: https://github.com/anchore/syft/issues/252
|
||||||
catalogFixtureImage(t, "image-java-no-main-package", source.SquashedScope)
|
catalogFixtureImage(t, "image-java-no-main-package", source.SquashedScope, false)
|
||||||
}
|
}
|
||||||
|
|||||||
22
test/integration/rust_audit_binary_test.go
Normal file
22
test/integration/rust_audit_binary_test.go
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
package integration
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/anchore/syft/syft/pkg"
|
||||||
|
"github.com/anchore/syft/syft/source"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestRustAudit(t *testing.T) {
|
||||||
|
sbom, _ := catalogFixtureImage(t, "image-rust-auditable", source.SquashedScope, true)
|
||||||
|
|
||||||
|
expectedPkgs := 2
|
||||||
|
actualPkgs := 0
|
||||||
|
for range sbom.Artifacts.PackageCatalog.Enumerate(pkg.RustPkg) {
|
||||||
|
actualPkgs += 1
|
||||||
|
}
|
||||||
|
|
||||||
|
if actualPkgs != expectedPkgs {
|
||||||
|
t.Errorf("unexpected number of Rust packages: %d != %d", expectedPkgs, actualPkgs)
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -11,7 +11,7 @@ import (
|
|||||||
func TestSqliteRpm(t *testing.T) {
|
func TestSqliteRpm(t *testing.T) {
|
||||||
// This is a regression test for issue #469 (https://github.com/anchore/syft/issues/469). Recent RPM
|
// This is a regression test for issue #469 (https://github.com/anchore/syft/issues/469). Recent RPM
|
||||||
// based distribution store package data in an sqlite database
|
// based distribution store package data in an sqlite database
|
||||||
sbom, _ := catalogFixtureImage(t, "image-sqlite-rpmdb", source.SquashedScope)
|
sbom, _ := catalogFixtureImage(t, "image-sqlite-rpmdb", source.SquashedScope, false)
|
||||||
|
|
||||||
expectedPkgs := 139
|
expectedPkgs := 139
|
||||||
actualPkgs := 0
|
actualPkgs := 0
|
||||||
|
|||||||
@ -0,0 +1,2 @@
|
|||||||
|
# An image containing the example hello-auditable binary from https://github.com/Shnatsel/rust-audit/tree/master/hello-auditable
|
||||||
|
FROM docker.io/tofay/hello-rust-auditable:latest
|
||||||
@ -13,7 +13,7 @@ import (
|
|||||||
"github.com/anchore/syft/syft/source"
|
"github.com/anchore/syft/syft/source"
|
||||||
)
|
)
|
||||||
|
|
||||||
func catalogFixtureImage(t *testing.T, fixtureImageName string, scope source.Scope) (sbom.SBOM, *source.Source) {
|
func catalogFixtureImage(t *testing.T, fixtureImageName string, scope source.Scope, allCatalogers bool) (sbom.SBOM, *source.Source) {
|
||||||
imagetest.GetFixtureImage(t, "docker-archive", fixtureImageName)
|
imagetest.GetFixtureImage(t, "docker-archive", fixtureImageName)
|
||||||
tarPath := imagetest.GetFixtureImageTarPath(t, fixtureImageName)
|
tarPath := imagetest.GetFixtureImageTarPath(t, fixtureImageName)
|
||||||
userInput := "docker-archive:" + tarPath
|
userInput := "docker-archive:" + tarPath
|
||||||
@ -25,6 +25,9 @@ func catalogFixtureImage(t *testing.T, fixtureImageName string, scope source.Sco
|
|||||||
|
|
||||||
// TODO: this would be better with functional options (after/during API refactor)
|
// TODO: this would be better with functional options (after/during API refactor)
|
||||||
c := cataloger.DefaultConfig()
|
c := cataloger.DefaultConfig()
|
||||||
|
if allCatalogers {
|
||||||
|
c.Catalogers = []string{"all"}
|
||||||
|
}
|
||||||
c.Search.Scope = scope
|
c.Search.Scope = scope
|
||||||
pkgCatalog, relationships, actualDistro, err := syft.CatalogPackages(theSource, c)
|
pkgCatalog, relationships, actualDistro, err := syft.CatalogPackages(theSource, c)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user