mirror of
https://github.com/aquasecurity/trivy.git
synced 2025-12-05 20:40:16 -08:00
Signed-off-by: chenk <hen.keinan@gmail.com> Co-authored-by: knqyf263 <knqyf263@gmail.com>
215 lines
5.2 KiB
Go
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)
|
|
}
|