mirror of
https://github.com/aquasecurity/trivy.git
synced 2025-12-12 15:50:15 -08:00
217 lines
5.4 KiB
Go
217 lines
5.4 KiB
Go
package vm_test
|
|
|
|
import (
|
|
"fmt"
|
|
"io"
|
|
"io/fs"
|
|
"os"
|
|
"path/filepath"
|
|
"strings"
|
|
"testing"
|
|
|
|
ebsfile "github.com/masahiro331/go-ebs-file"
|
|
"github.com/stretchr/testify/assert"
|
|
"github.com/stretchr/testify/require"
|
|
|
|
"github.com/aquasecurity/trivy/internal/cachetest"
|
|
"github.com/aquasecurity/trivy/pkg/fanal/analyzer"
|
|
"github.com/aquasecurity/trivy/pkg/fanal/artifact"
|
|
"github.com/aquasecurity/trivy/pkg/fanal/artifact/vm"
|
|
"github.com/aquasecurity/trivy/pkg/fanal/types"
|
|
"github.com/aquasecurity/trivy/pkg/fanal/walker"
|
|
"github.com/aquasecurity/trivy/pkg/misconf"
|
|
xio "github.com/aquasecurity/trivy/pkg/x/io"
|
|
|
|
_ "github.com/aquasecurity/trivy/pkg/fanal/analyzer/os/alpine"
|
|
_ "github.com/aquasecurity/trivy/pkg/fanal/analyzer/pkg/apk"
|
|
)
|
|
|
|
const (
|
|
ebsPrefix = string(vm.TypeEBS) + ":"
|
|
filePrefix = string(vm.TypeFile) + ":"
|
|
)
|
|
|
|
type mockWalker struct {
|
|
root string
|
|
}
|
|
|
|
func (m *mockWalker) Walk(_ *io.SectionReader, _ string, _ walker.Option, fn walker.WalkFunc) error {
|
|
return filepath.WalkDir(m.root, func(path string, d fs.DirEntry, err error) error {
|
|
if err != nil {
|
|
return err
|
|
} else if d.IsDir() {
|
|
return nil
|
|
}
|
|
|
|
info, err := d.Info()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
opener := func() (xio.ReadSeekCloserAt, error) {
|
|
return os.Open(path)
|
|
}
|
|
relPath, err := filepath.Rel(m.root, path)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
relPath = filepath.ToSlash(relPath)
|
|
return fn(relPath, info, opener)
|
|
})
|
|
}
|
|
|
|
func TestNewArtifact(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
target string
|
|
wantErr assert.ErrorAssertionFunc
|
|
}{
|
|
{
|
|
name: "happy path for file",
|
|
target: "testdata/mock.img",
|
|
wantErr: assert.NoError,
|
|
},
|
|
{
|
|
name: "happy path for EBS",
|
|
target: "ebs:ebs-012345",
|
|
wantErr: assert.NoError,
|
|
},
|
|
{
|
|
name: "sad path unsupported vm format",
|
|
target: "testdata/monolithicSparse.vmdk",
|
|
wantErr: func(t assert.TestingT, err error, _ ...any) bool {
|
|
return assert.ErrorContains(t, err, "unsupported type error")
|
|
},
|
|
},
|
|
{
|
|
name: "sad path file not found",
|
|
target: "testdata/no-file",
|
|
wantErr: func(t assert.TestingT, err error, _ ...any) bool {
|
|
return assert.ErrorContains(t, err, "file open error")
|
|
},
|
|
},
|
|
}
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
w := &mockWalker{root: "testdata"}
|
|
_, err := vm.NewArtifact(tt.target, nil, w, artifact.Option{Parallel: 3})
|
|
tt.wantErr(t, err, fmt.Sprintf("NewArtifact(%v, nil, nil)", tt.target))
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestArtifact_Inspect(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
target string
|
|
rootDir string
|
|
artifactOpt artifact.Option
|
|
scannerOpt misconf.ScannerOption
|
|
disabledAnalyzers []analyzer.Type
|
|
disabledHandlers []types.HandlerType
|
|
wantBlobs []cachetest.WantBlob
|
|
want artifact.Reference
|
|
wantErr string
|
|
}{
|
|
{
|
|
name: "happy path for raw image",
|
|
target: "testdata/mock.img",
|
|
rootDir: "testdata/alpine",
|
|
wantBlobs: []cachetest.WantBlob{
|
|
{
|
|
ID: "sha256:c2baf06cb25f7b62686b169df5729402f0c50420bfcbdce8347f84c4bf623ab9",
|
|
BlobInfo: expectedBlobInfo,
|
|
},
|
|
},
|
|
want: artifact.Reference{
|
|
Name: "rawdata.img",
|
|
Type: types.TypeVM,
|
|
ID: "sha256:c2baf06cb25f7b62686b169df5729402f0c50420bfcbdce8347f84c4bf623ab9",
|
|
BlobIDs: []string{
|
|
"sha256:c2baf06cb25f7b62686b169df5729402f0c50420bfcbdce8347f84c4bf623ab9",
|
|
},
|
|
},
|
|
},
|
|
{
|
|
name: "happy path for ebs",
|
|
target: "ebs:ebs-012345",
|
|
rootDir: "testdata/alpine",
|
|
wantBlobs: []cachetest.WantBlob{
|
|
{
|
|
ID: "sha256:d1690d3201420ddb690be85be011afd36be4c8bff47c474d7fcfe9c7efea9a3f",
|
|
BlobInfo: expectedBlobInfo,
|
|
},
|
|
},
|
|
want: artifact.Reference{
|
|
Name: "ebs-012345",
|
|
Type: types.TypeVM,
|
|
ID: "sha256:d1690d3201420ddb690be85be011afd36be4c8bff47c474d7fcfe9c7efea9a3f",
|
|
BlobIDs: []string{
|
|
"sha256:d1690d3201420ddb690be85be011afd36be4c8bff47c474d7fcfe9c7efea9a3f",
|
|
},
|
|
},
|
|
},
|
|
}
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
c := cachetest.NewCache(t, nil)
|
|
|
|
m := &mockWalker{root: tt.rootDir}
|
|
|
|
a, err := vm.NewArtifact(tt.target, c, m, tt.artifactOpt)
|
|
require.NoError(t, err)
|
|
|
|
if aa, ok := a.(*vm.EBS); ok {
|
|
ebs := ebsfile.NewMockEBS("testdata/mock.img", 1, 2)
|
|
aa.SetEBS(ebs)
|
|
}
|
|
|
|
got, err := a.Inspect(t.Context())
|
|
defer a.Clean(got)
|
|
if tt.wantErr != "" {
|
|
assert.ErrorContains(t, err, tt.wantErr)
|
|
return
|
|
}
|
|
tt.want.Name = trimPrefix(tt.target)
|
|
require.NoError(t, err)
|
|
assert.Equal(t, tt.want, got)
|
|
cachetest.AssertBlobs(t, c, tt.wantBlobs)
|
|
})
|
|
}
|
|
}
|
|
|
|
func trimPrefix(s string) string {
|
|
s = strings.TrimPrefix(s, ebsPrefix)
|
|
s = strings.TrimPrefix(s, filePrefix)
|
|
return s
|
|
}
|
|
|
|
var expectedBlobInfo = types.BlobInfo{
|
|
SchemaVersion: types.BlobJSONSchemaVersion,
|
|
OS: types.OS{
|
|
Family: "alpine",
|
|
Name: "3.17.5",
|
|
},
|
|
PackageInfos: []types.PackageInfo{
|
|
{
|
|
FilePath: "lib/apk/db/installed",
|
|
Packages: types.Packages{
|
|
{
|
|
ID: "musl@1.2.3-r5",
|
|
Name: "musl",
|
|
Version: "1.2.3-r5",
|
|
SrcName: "musl",
|
|
SrcVersion: "1.2.3-r5",
|
|
Licenses: []string{"MIT"},
|
|
Maintainer: "Timo Teräs <timo.teras@iki.fi>",
|
|
Arch: "aarch64",
|
|
Digest: "sha1:742b0a26f327c6da60d42a02c3eb6189a58e468f",
|
|
InstalledFiles: []string{
|
|
"lib/ld-musl-aarch64.so.1",
|
|
"lib/libc.musl-aarch64.so.1",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
}
|