mirror of
https://github.com/aquasecurity/trivy.git
synced 2025-12-12 15:50:15 -08:00
fix(vex): don't use reused BOM (#9604)
This commit is contained in:
@@ -56,8 +56,7 @@ func NewMarshaler(version string) Marshaler {
|
||||
// MarshalReport converts the Trivy report to the CycloneDX format
|
||||
func (m *Marshaler) MarshalReport(ctx context.Context, report types.Report) (*cdx.BOM, error) {
|
||||
// Convert into an intermediate representation
|
||||
opts := core.Options{GenerateBOMRef: true}
|
||||
bom, err := sbomio.NewEncoder(opts).Encode(report)
|
||||
bom, err := sbomio.NewEncoder(sbomio.WithBOMRef()).Encode(report)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("failed to marshal report: %w", err)
|
||||
}
|
||||
|
||||
@@ -19,21 +19,49 @@ import (
|
||||
"github.com/aquasecurity/trivy/pkg/types"
|
||||
)
|
||||
|
||||
type Encoder struct {
|
||||
bom *core.BOM
|
||||
opts core.Options
|
||||
type EncoderOption func(*Encoder)
|
||||
|
||||
// WithBOMRef enables BOM-Ref generation for CycloneDX components
|
||||
func WithBOMRef() EncoderOption {
|
||||
return func(e *Encoder) {
|
||||
e.bomOpts.GenerateBOMRef = true
|
||||
}
|
||||
}
|
||||
|
||||
func NewEncoder(opts core.Options) *Encoder {
|
||||
return &Encoder{opts: opts}
|
||||
// WithParents enables holding parent maps in the BOM structure
|
||||
func WithParents() EncoderOption {
|
||||
return func(e *Encoder) {
|
||||
e.bomOpts.Parents = true
|
||||
}
|
||||
}
|
||||
|
||||
// ForceRegenerate forces regeneration of BOM instead of reusing existing one
|
||||
func ForceRegenerate() EncoderOption {
|
||||
return func(e *Encoder) {
|
||||
e.forceRegenerate = true
|
||||
}
|
||||
}
|
||||
|
||||
type Encoder struct {
|
||||
bom *core.BOM
|
||||
bomOpts core.Options
|
||||
forceRegenerate bool
|
||||
}
|
||||
|
||||
func NewEncoder(opts ...EncoderOption) *Encoder {
|
||||
e := &Encoder{}
|
||||
for _, opt := range opts {
|
||||
opt(e)
|
||||
}
|
||||
return e
|
||||
}
|
||||
|
||||
func (e *Encoder) Encode(report types.Report) (*core.BOM, error) {
|
||||
// When report.BOM is not nil, reuse the existing BOM structure.
|
||||
// When report.BOM is not nil, reuse the existing BOM structure unless ForceRegenerate is set.
|
||||
// This happens in two scenarios:
|
||||
// 1. SBOM scanning: When scanning an existing SBOM file to refresh vulnerabilities
|
||||
// 2. Library usage: When using Trivy as a library with a custom BOM in the report
|
||||
if report.BOM != nil {
|
||||
if report.BOM != nil && !e.forceRegenerate {
|
||||
return e.reuseExistingBOM(report)
|
||||
}
|
||||
// Metadata component
|
||||
@@ -42,7 +70,7 @@ func (e *Encoder) Encode(report types.Report) (*core.BOM, error) {
|
||||
return nil, xerrors.Errorf("failed to create root component: %w", err)
|
||||
}
|
||||
|
||||
e.bom = core.NewBOM(e.opts)
|
||||
e.bom = core.NewBOM(e.bomOpts)
|
||||
if report.BOM != nil {
|
||||
e.bom.SerialNumber = report.BOM.SerialNumber
|
||||
e.bom.Version = report.BOM.Version
|
||||
|
||||
@@ -1466,8 +1466,7 @@ func TestEncoder_Encode(t *testing.T) {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
uuid.SetFakeUUID(t, "3ff14136-e09f-4df9-80ea-%012d")
|
||||
|
||||
opts := core.Options{GenerateBOMRef: true}
|
||||
got, err := sbomio.NewEncoder(opts).Encode(tt.report)
|
||||
got, err := sbomio.NewEncoder(sbomio.WithBOMRef()).Encode(tt.report)
|
||||
if tt.wantErr != "" {
|
||||
require.ErrorContains(t, err, tt.wantErr)
|
||||
return
|
||||
|
||||
@@ -115,7 +115,7 @@ func NewMarshaler(version string, opts ...marshalOption) *Marshaler {
|
||||
|
||||
func (m *Marshaler) MarshalReport(ctx context.Context, report types.Report) (*spdx.Document, error) {
|
||||
// Convert into an intermediate representation
|
||||
bom, err := sbomio.NewEncoder(core.Options{}).Encode(report)
|
||||
bom, err := sbomio.NewEncoder().Encode(report)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("failed to marshal report: %w", err)
|
||||
}
|
||||
|
||||
@@ -75,7 +75,7 @@ func Filter(ctx context.Context, report *types.Report, opts Options) error {
|
||||
}
|
||||
|
||||
// NOTE: This method call has a side effect on the report
|
||||
bom, err := sbomio.NewEncoder(core.Options{Parents: true}).Encode(*report)
|
||||
bom, err := sbomio.NewEncoder(sbomio.WithParents(), sbomio.ForceRegenerate()).Encode(*report)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("unable to encode the SBOM: %w", err)
|
||||
}
|
||||
|
||||
@@ -665,13 +665,18 @@ func createCycloneDXBOMWithSpringComponent() *core.BOM {
|
||||
bom := core.NewBOM(core.Options{})
|
||||
bom.SerialNumber = "urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79"
|
||||
bom.Version = 1
|
||||
pkgIdentifier := ftypes.PkgIdentifier{
|
||||
// Components got from scanned SBOM files don't have UID
|
||||
BOMRef: springPackage.Identifier.BOMRef,
|
||||
PURL: springPackage.Identifier.PURL,
|
||||
}
|
||||
// Add the spring component to match vuln1's BOM-Ref
|
||||
springComponent := &core.Component{
|
||||
Type: core.TypeLibrary,
|
||||
Name: springPackage.Identifier.PURL.Name,
|
||||
Group: springPackage.Identifier.PURL.Namespace,
|
||||
Version: springPackage.Version,
|
||||
PkgIdentifier: springPackage.Identifier,
|
||||
PkgIdentifier: pkgIdentifier,
|
||||
}
|
||||
bom.AddComponent(springComponent)
|
||||
return bom
|
||||
|
||||
Reference in New Issue
Block a user