github.com/devseccon/trivy@v0.47.1-0.20231123133102-bd902a0bd996/pkg/fanal/analyzer/sbom/sbom.go (about)

     1  package sbom
     2  
     3  import (
     4  	"context"
     5  	"os"
     6  	"path"
     7  	"strings"
     8  
     9  	"golang.org/x/xerrors"
    10  
    11  	"github.com/devseccon/trivy/pkg/fanal/analyzer"
    12  	ftypes "github.com/devseccon/trivy/pkg/fanal/types"
    13  	"github.com/devseccon/trivy/pkg/sbom"
    14  	"github.com/devseccon/trivy/pkg/types"
    15  )
    16  
    17  func init() {
    18  	analyzer.RegisterAnalyzer(&sbomAnalyzer{})
    19  }
    20  
    21  const version = 1
    22  
    23  var requiredSuffixes = []string{
    24  	".spdx",
    25  	".spdx.json",
    26  	".cdx",
    27  	".cdx.json",
    28  }
    29  
    30  type sbomAnalyzer struct{}
    31  
    32  func (a sbomAnalyzer) Analyze(_ context.Context, input analyzer.AnalysisInput) (*analyzer.AnalysisResult, error) {
    33  	// Format auto-detection
    34  	format, err := sbom.DetectFormat(input.Content)
    35  	if err != nil {
    36  		return nil, xerrors.Errorf("failed to detect SBOM format: %w", err)
    37  	}
    38  
    39  	bom, err := sbom.Decode(input.Content, format)
    40  	if err != nil {
    41  		return nil, xerrors.Errorf("SBOM decode error: %w", err)
    42  	}
    43  
    44  	// Bitnami images
    45  	// SPDX files are located under the /opt/bitnami/<component> directory
    46  	// and named with the pattern .spdx-<component>.spdx
    47  	// ref: https://github.com/bitnami/vulndb#how-to-consume-this-cve-feed
    48  	if strings.HasPrefix(input.FilePath, "opt/bitnami/") {
    49  		handleBitnamiImages(path.Dir(input.FilePath), bom)
    50  	}
    51  
    52  	return &analyzer.AnalysisResult{
    53  		PackageInfos: bom.Packages,
    54  		Applications: bom.Applications,
    55  	}, nil
    56  }
    57  
    58  func (a sbomAnalyzer) Required(filePath string, _ os.FileInfo) bool {
    59  	for _, suffix := range requiredSuffixes {
    60  		if strings.HasSuffix(filePath, suffix) {
    61  			return true
    62  		}
    63  	}
    64  	return false
    65  }
    66  
    67  func (a sbomAnalyzer) Type() analyzer.Type {
    68  	return analyzer.TypeSBOM
    69  }
    70  
    71  func (a sbomAnalyzer) Version() int {
    72  	return version
    73  }
    74  
    75  func handleBitnamiImages(componentPath string, bom types.SBOM) {
    76  	for i, app := range bom.Applications {
    77  		if app.Type == ftypes.Bitnami {
    78  			// Set the component dir path to the application
    79  			bom.Applications[i].FilePath = componentPath
    80  			// Either Application.FilePath or Application.Libraries[].FilePath should be set
    81  			continue
    82  		}
    83  
    84  		for j, pkg := range app.Libraries {
    85  			// Set the absolute path since SBOM in Bitnami images contain a relative path
    86  			// e.g. modules/apm/elastic-apm-agent-1.36.0.jar
    87  			//      => opt/bitnami/elasticsearch/modules/apm/elastic-apm-agent-1.36.0.jar
    88  			// If the file path is empty, the file path will be set to the component dir path.
    89  			bom.Applications[i].Libraries[j].FilePath = path.Join(componentPath, pkg.FilePath)
    90  		}
    91  	}
    92  }