Files
trivy/integration/sbom_test.go
2025-10-22 06:50:13 +00:00

229 lines
7.2 KiB
Go

//go:build integration
package integration
import (
"path/filepath"
"testing"
v1 "github.com/google/go-containerregistry/pkg/v1"
"github.com/stretchr/testify/require"
ftypes "github.com/aquasecurity/trivy/pkg/fanal/types"
"github.com/aquasecurity/trivy/pkg/types"
)
func TestSBOM(t *testing.T) {
type args struct {
input string
format string
artifactType string
scanners string
}
tests := []struct {
name string
args args
golden string
fakeUUID string
override OverrideFunc
}{
{
name: "centos7 cyclonedx",
args: args{
input: "testdata/fixtures/sbom/centos-7-cyclonedx.json",
format: "json",
artifactType: "cyclonedx",
},
golden: "testdata/centos-7.json.golden",
fakeUUID: "3ff14136-e09f-4df9-80ea-%012d",
override: func(t *testing.T, want, got *types.Report) {
want.ArtifactName = "testdata/fixtures/sbom/centos-7-cyclonedx.json"
want.ArtifactType = ftypes.TypeCycloneDX
require.Len(t, got.Results, 1)
want.Results[0].Target = "testdata/fixtures/sbom/centos-7-cyclonedx.json (centos 7.6.1810)"
require.Len(t, got.Results[0].Vulnerabilities, 3)
want.Results[0].Vulnerabilities[0].PkgIdentifier.BOMRef = "pkg:rpm/centos/bash@4.2.46-31.el7?arch=x86_64&distro=centos-7.6.1810"
want.Results[0].Vulnerabilities[1].PkgIdentifier.BOMRef = "pkg:rpm/centos/openssl-libs@1.0.2k-16.el7?arch=x86_64&epoch=1&distro=centos-7.6.1810"
want.Results[0].Vulnerabilities[2].PkgIdentifier.BOMRef = "pkg:rpm/centos/openssl-libs@1.0.2k-16.el7?arch=x86_64&epoch=1&distro=centos-7.6.1810"
// SBOM file doesn't contain info about layers
want.Metadata.Size = 0
want.Metadata.Layers = nil
// SBOM parsing consumes UUIDs #1-#4 for components, so ReportID becomes #5
want.ReportID = "3ff14136-e09f-4df9-80ea-000000000005"
},
},
{
name: "fluentd-multiple-lockfiles cyclonedx",
args: args{
input: "testdata/fixtures/sbom/fluentd-multiple-lockfiles-cyclonedx.json",
format: "json",
artifactType: "cyclonedx",
},
golden: "testdata/fluentd-multiple-lockfiles.json.golden",
fakeUUID: "3ff14136-e09f-4df9-80ea-%012d",
},
{
name: "scan SBOM into SBOM",
args: args{
input: "testdata/fixtures/sbom/fluentd-multiple-lockfiles-cyclonedx.json",
format: "cyclonedx",
artifactType: "cyclonedx",
},
fakeUUID: "3ff14136-e09f-4df9-80ea-%012d",
golden: "testdata/fluentd-multiple-lockfiles-short.cdx.json.golden",
},
{
name: "minikube KBOM",
args: args{
input: "testdata/fixtures/sbom/minikube-kbom.json",
format: "json",
artifactType: "cyclonedx",
},
golden: "testdata/minikube-kbom.json.golden",
fakeUUID: "3ff14136-e09f-4df9-80ea-%012d",
},
{
name: "centos7 in in-toto attestation",
args: args{
input: "testdata/fixtures/sbom/centos-7-cyclonedx.intoto.jsonl",
format: "json",
artifactType: "cyclonedx",
},
golden: "testdata/centos-7.json.golden",
fakeUUID: "3ff14136-e09f-4df9-80ea-%012d",
override: func(t *testing.T, want, got *types.Report) {
want.ArtifactName = "testdata/fixtures/sbom/centos-7-cyclonedx.intoto.jsonl"
want.ArtifactType = ftypes.TypeCycloneDX
require.Len(t, got.Results, 1)
want.Results[0].Target = "testdata/fixtures/sbom/centos-7-cyclonedx.intoto.jsonl (centos 7.6.1810)"
require.Len(t, got.Results[0].Vulnerabilities, 3)
want.Results[0].Vulnerabilities[0].PkgIdentifier.BOMRef = "pkg:rpm/centos/bash@4.2.46-31.el7?arch=x86_64&distro=centos-7.6.1810"
want.Results[0].Vulnerabilities[1].PkgIdentifier.BOMRef = "pkg:rpm/centos/openssl-libs@1.0.2k-16.el7?arch=x86_64&epoch=1&distro=centos-7.6.1810"
want.Results[0].Vulnerabilities[2].PkgIdentifier.BOMRef = "pkg:rpm/centos/openssl-libs@1.0.2k-16.el7?arch=x86_64&epoch=1&distro=centos-7.6.1810"
// SBOM file doesn't contain info about layers
want.Metadata.Size = 0
want.Metadata.Layers = nil
// SBOM parsing consumes UUIDs #1-#4 for components, so ReportID becomes #5
want.ReportID = "3ff14136-e09f-4df9-80ea-000000000005"
},
},
{
name: "centos7 spdx tag-value",
args: args{
input: "testdata/fixtures/sbom/centos-7-spdx.txt",
format: "json",
artifactType: "spdx",
},
golden: "testdata/centos-7.json.golden",
fakeUUID: "3ff14136-e09f-4df9-80ea-%012d",
override: func(t *testing.T, want, got *types.Report) {
want.ArtifactName = "testdata/fixtures/sbom/centos-7-spdx.txt"
want.ArtifactType = ftypes.TypeSPDX
require.Len(t, got.Results, 1)
want.Results[0].Target = "testdata/fixtures/sbom/centos-7-spdx.txt (centos 7.6.1810)"
// SBOM file doesn't contain info about layers
want.Metadata.Size = 0
want.Metadata.Layers = nil
// SBOM parsing consumes UUIDs #1-#4 for components, so ReportID becomes #5
want.ReportID = "3ff14136-e09f-4df9-80ea-000000000005"
},
},
{
name: "centos7 spdx json",
args: args{
input: "testdata/fixtures/sbom/centos-7-spdx.json",
format: "json",
artifactType: "spdx",
},
golden: "testdata/centos-7.json.golden",
fakeUUID: "3ff14136-e09f-4df9-80ea-%012d",
override: func(t *testing.T, want, got *types.Report) {
want.ArtifactName = "testdata/fixtures/sbom/centos-7-spdx.json"
want.ArtifactType = ftypes.TypeSPDX
require.Len(t, got.Results, 1)
want.Results[0].Target = "testdata/fixtures/sbom/centos-7-spdx.json (centos 7.6.1810)"
// SBOM file doesn't contain info about layers
want.Metadata.Size = 0
want.Metadata.Layers = nil
// SBOM parsing consumes UUIDs #1-#4 for components, so ReportID becomes #5
want.ReportID = "3ff14136-e09f-4df9-80ea-000000000005"
},
},
{
name: "license check cyclonedx json",
args: args{
input: "testdata/fixtures/sbom/license-cyclonedx.json",
format: "json",
artifactType: "cyclonedx",
scanners: "license",
},
golden: "testdata/license-cyclonedx.json.golden",
fakeUUID: "3ff14136-e09f-4df9-80ea-%012d",
},
}
// Set up testing DB
cacheDir := initDB(t)
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
scanners := "vuln"
if tt.args.scanners != "" {
scanners = tt.args.scanners
}
osArgs := []string{
"--cache-dir",
cacheDir,
"sbom",
"-q",
"--skip-db-update",
"--format",
tt.args.format,
"--scanners",
scanners,
"--list-all-pkgs=false",
}
// Set up the output file
outputFile := filepath.Join(t.TempDir(), "output.json")
if *update {
outputFile = tt.golden
}
osArgs = append(osArgs, "--output", outputFile, tt.args.input)
// Run "trivy sbom"
runTest(t, osArgs, tt.golden, outputFile, types.Format(tt.args.format), runOptions{
override: overrideFuncs(overrideSBOMReport, overrideUID, tt.override),
fakeUUID: tt.fakeUUID,
})
})
}
}
func overrideSBOMReport(_ *testing.T, want, got *types.Report) {
want.ArtifactID = ""
want.Metadata.ImageConfig = v1.ConfigFile{}
// when running on Windows FS
got.ArtifactName = filepath.ToSlash(filepath.Clean(got.ArtifactName))
for i, result := range got.Results {
got.Results[i].Target = filepath.ToSlash(filepath.Clean(result.Target))
}
}