Files
trivy/integration/integration_test.go
chenk 16af41be15 test: k8s integration tests (#4423)
Signed-off-by: chenk <hen.keinan@gmail.com>
Co-authored-by: knqyf263 <knqyf263@gmail.com>
2023-05-18 22:41:22 +03:00

215 lines
5.2 KiB
Go

//go:build integration || vm_integration || module_integration || k8s_integration
package integration
import (
"context"
"encoding/json"
"flag"
"io"
"net"
"os"
"path/filepath"
"sort"
"testing"
"time"
cdx "github.com/CycloneDX/cyclonedx-go"
spdxjson "github.com/spdx/tools-golang/json"
"github.com/spdx/tools-golang/spdx"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/aquasecurity/trivy-db/pkg/db"
"github.com/aquasecurity/trivy-db/pkg/metadata"
"github.com/aquasecurity/trivy/pkg/commands"
"github.com/aquasecurity/trivy/pkg/dbtest"
"github.com/aquasecurity/trivy/pkg/types"
_ "modernc.org/sqlite"
)
var update = flag.Bool("update", false, "update golden files")
func initDB(t *testing.T) string {
fixtureDir := filepath.Join("testdata", "fixtures", "db")
entries, err := os.ReadDir(fixtureDir)
require.NoError(t, err)
var fixtures []string
for _, entry := range entries {
if entry.IsDir() {
continue
}
fixtures = append(fixtures, filepath.Join(fixtureDir, entry.Name()))
}
cacheDir := dbtest.InitDB(t, fixtures)
defer db.Close()
dbDir := filepath.Dir(db.Path(cacheDir))
metadataFile := filepath.Join(dbDir, "metadata.json")
f, err := os.Create(metadataFile)
require.NoError(t, err)
err = json.NewEncoder(f).Encode(metadata.Metadata{
Version: db.SchemaVersion,
NextUpdate: time.Now().Add(24 * time.Hour),
UpdatedAt: time.Now(),
})
require.NoError(t, err)
dbtest.InitJavaDB(t, cacheDir)
return cacheDir
}
func getFreePort() (int, error) {
addr, err := net.ResolveTCPAddr("tcp", "localhost:0")
if err != nil {
return 0, err
}
l, err := net.ListenTCP("tcp", addr)
if err != nil {
return 0, err
}
defer l.Close()
return l.Addr().(*net.TCPAddr).Port, nil
}
func waitPort(ctx context.Context, addr string) error {
for {
conn, err := net.Dial("tcp", addr)
if err == nil && conn != nil {
return nil
}
select {
case <-ctx.Done():
return err
default:
time.Sleep(1 * time.Second)
}
}
}
func readReport(t *testing.T, filePath string) types.Report {
t.Helper()
f, err := os.Open(filePath)
require.NoError(t, err, filePath)
defer f.Close()
var report types.Report
err = json.NewDecoder(f).Decode(&report)
require.NoError(t, err, filePath)
// We don't compare history because the nano-seconds in "created" don't match
report.Metadata.ImageConfig.History = nil
// We don't compare repo tags because the archive doesn't support it
report.Metadata.RepoTags = nil
report.Metadata.RepoDigests = nil
for i, result := range report.Results {
for j := range result.Vulnerabilities {
report.Results[i].Vulnerabilities[j].Layer.Digest = ""
}
sort.Slice(result.CustomResources, func(i, j int) bool {
if result.CustomResources[i].Type != result.CustomResources[j].Type {
return result.CustomResources[i].Type < result.CustomResources[j].Type
}
return result.CustomResources[i].FilePath < result.CustomResources[j].FilePath
})
}
return report
}
func readCycloneDX(t *testing.T, filePath string) *cdx.BOM {
f, err := os.Open(filePath)
require.NoError(t, err)
defer f.Close()
bom := cdx.NewBOM()
decoder := cdx.NewBOMDecoder(f, cdx.BOMFileFormatJSON)
err = decoder.Decode(bom)
require.NoError(t, err)
// We don't compare values which change each time an SBOM is generated
bom.Metadata.Timestamp = ""
bom.Metadata.Component.BOMRef = ""
bom.SerialNumber = ""
if bom.Components != nil {
sort.Slice(*bom.Components, func(i, j int) bool {
return (*bom.Components)[i].Name < (*bom.Components)[j].Name
})
for i := range *bom.Components {
(*bom.Components)[i].BOMRef = ""
sort.Slice(*(*bom.Components)[i].Properties, func(ii, jj int) bool {
return (*(*bom.Components)[i].Properties)[ii].Name < (*(*bom.Components)[i].Properties)[jj].Name
})
}
}
if bom.Dependencies != nil {
for j := range *bom.Dependencies {
(*bom.Dependencies)[j].Ref = ""
(*bom.Dependencies)[j].Dependencies = nil
}
}
return bom
}
func readSpdxJson(t *testing.T, filePath string) *spdx.Document {
f, err := os.Open(filePath)
require.NoError(t, err)
defer f.Close()
bom, err := spdxjson.Read(f)
require.NoError(t, err)
sort.Slice(bom.Relationships, func(i, j int) bool {
if bom.Relationships[i].RefA.ElementRefID != bom.Relationships[j].RefA.ElementRefID {
return bom.Relationships[i].RefA.ElementRefID < bom.Relationships[j].RefA.ElementRefID
}
return bom.Relationships[i].RefB.ElementRefID < bom.Relationships[j].RefB.ElementRefID
})
// We don't compare values which change each time an SBOM is generated
bom.CreationInfo.Created = ""
bom.DocumentNamespace = ""
return bom
}
func execute(osArgs []string) error {
// Setup CLI App
app := commands.NewApp("dev")
app.SetOut(io.Discard)
// Run Trivy
app.SetArgs(osArgs)
return app.Execute()
}
func compareReports(t *testing.T, wantFile, gotFile string) {
want := readReport(t, wantFile)
got := readReport(t, gotFile)
assert.Equal(t, want, got)
}
func compareCycloneDX(t *testing.T, wantFile, gotFile string) {
want := readCycloneDX(t, wantFile)
got := readCycloneDX(t, gotFile)
assert.Equal(t, want, got)
}
func compareSpdxJson(t *testing.T, wantFile, gotFile string) {
want := readSpdxJson(t, wantFile)
got := readSpdxJson(t, gotFile)
assert.Equal(t, want, got)
}