* chore(deps): bump github.com/aquasecurity/trivy from 0.52.2 to 0.53.0 Bumps [github.com/aquasecurity/trivy](https://github.com/aquasecurity/trivy) from 0.52.2 to 0.53.0. - [Release notes](https://github.com/aquasecurity/trivy/releases) - [Changelog](https://github.com/aquasecurity/trivy/blob/main/CHANGELOG.md) - [Commits](https://github.com/aquasecurity/trivy/compare/v0.52.2...v0.53.0) --- updated-dependencies: - dependency-name: github.com/aquasecurity/trivy dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] <support@github.com> * chore(deps): fixed for trivy update * fix windows --------- Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Shunichi Shinohara <shino.shun@gmail.com>
		
			
				
	
	
		
			286 lines
		
	
	
		
			8.5 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			286 lines
		
	
	
		
			8.5 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
//go:build !scanner
 | 
						|
// +build !scanner
 | 
						|
 | 
						|
package detector
 | 
						|
 | 
						|
import (
 | 
						|
	"context"
 | 
						|
	"errors"
 | 
						|
	"fmt"
 | 
						|
	"strings"
 | 
						|
	"time"
 | 
						|
 | 
						|
	trivydb "github.com/aquasecurity/trivy-db/pkg/db"
 | 
						|
	"github.com/aquasecurity/trivy-db/pkg/metadata"
 | 
						|
	trivydbTypes "github.com/aquasecurity/trivy-db/pkg/types"
 | 
						|
	"github.com/aquasecurity/trivy/pkg/db"
 | 
						|
	"github.com/aquasecurity/trivy/pkg/dependency/parser/java/jar"
 | 
						|
	"github.com/aquasecurity/trivy/pkg/detector/library"
 | 
						|
	ftypes "github.com/aquasecurity/trivy/pkg/fanal/types"
 | 
						|
	"github.com/aquasecurity/trivy/pkg/log"
 | 
						|
	"github.com/aquasecurity/trivy/pkg/types"
 | 
						|
	"github.com/samber/lo"
 | 
						|
	"golang.org/x/xerrors"
 | 
						|
 | 
						|
	"github.com/future-architect/vuls/config"
 | 
						|
	"github.com/future-architect/vuls/detector/javadb"
 | 
						|
	"github.com/future-architect/vuls/logging"
 | 
						|
	"github.com/future-architect/vuls/models"
 | 
						|
)
 | 
						|
 | 
						|
type libraryDetector struct {
 | 
						|
	scanner      models.LibraryScanner
 | 
						|
	javaDBClient *javadb.DBClient
 | 
						|
}
 | 
						|
 | 
						|
// DetectLibsCves fills LibraryScanner information
 | 
						|
func DetectLibsCves(r *models.ScanResult, trivyOpts config.TrivyOpts, logOpts logging.LogOpts, noProgress bool) (err error) {
 | 
						|
	totalCnt := 0
 | 
						|
	if len(r.LibraryScanners) == 0 {
 | 
						|
		return
 | 
						|
	}
 | 
						|
 | 
						|
	// initialize trivy's logger and db
 | 
						|
	log.InitLogger(logOpts.Debug, logOpts.Quiet)
 | 
						|
 | 
						|
	logging.Log.Info("Updating library db...")
 | 
						|
	if err := downloadDB("", trivyOpts, noProgress, false); err != nil {
 | 
						|
		return xerrors.Errorf("Failed to download trivy DB. err: %w", err)
 | 
						|
	}
 | 
						|
	if err := trivydb.Init(trivyOpts.TrivyCacheDBDir); err != nil {
 | 
						|
		return xerrors.Errorf("Failed to init trivy DB. err: %w", err)
 | 
						|
	}
 | 
						|
	defer trivydb.Close()
 | 
						|
 | 
						|
	var javaDBClient *javadb.DBClient
 | 
						|
	defer javaDBClient.Close()
 | 
						|
	for i, lib := range r.LibraryScanners {
 | 
						|
		d := libraryDetector{scanner: lib}
 | 
						|
		if lib.Type == ftypes.Jar {
 | 
						|
			if javaDBClient == nil {
 | 
						|
				if err := javadb.UpdateJavaDB(trivyOpts, noProgress); err != nil {
 | 
						|
					return xerrors.Errorf("Failed to update Trivy Java DB. err: %w", err)
 | 
						|
				}
 | 
						|
 | 
						|
				javaDBClient, err = javadb.NewClient(trivyOpts.TrivyCacheDBDir)
 | 
						|
				if err != nil {
 | 
						|
					return xerrors.Errorf("Failed to open Trivy Java DB. err: %w", err)
 | 
						|
				}
 | 
						|
			}
 | 
						|
			d.javaDBClient = javaDBClient
 | 
						|
		}
 | 
						|
 | 
						|
		vinfos, err := d.scan()
 | 
						|
		if err != nil {
 | 
						|
			return xerrors.Errorf("Failed to scan library. err: %w", err)
 | 
						|
		}
 | 
						|
		r.LibraryScanners[i] = d.scanner
 | 
						|
		for _, vinfo := range vinfos {
 | 
						|
			vinfo.Confidences.AppendIfMissing(models.TrivyMatch)
 | 
						|
			if v, ok := r.ScannedCves[vinfo.CveID]; !ok {
 | 
						|
				r.ScannedCves[vinfo.CveID] = vinfo
 | 
						|
			} else {
 | 
						|
				v.LibraryFixedIns = append(v.LibraryFixedIns, vinfo.LibraryFixedIns...)
 | 
						|
				r.ScannedCves[vinfo.CveID] = v
 | 
						|
			}
 | 
						|
		}
 | 
						|
		totalCnt += len(vinfos)
 | 
						|
	}
 | 
						|
 | 
						|
	logging.Log.Infof("%s: %d CVEs are detected with Library",
 | 
						|
		r.FormatServerName(), totalCnt)
 | 
						|
 | 
						|
	return nil
 | 
						|
}
 | 
						|
 | 
						|
func downloadDB(appVersion string, trivyOpts config.TrivyOpts, noProgress, skipUpdate bool) error {
 | 
						|
	client := db.NewClient(trivyOpts.TrivyCacheDBDir, noProgress)
 | 
						|
	ctx := context.Background()
 | 
						|
	needsUpdate, err := client.NeedsUpdate(context.TODO(), appVersion, skipUpdate)
 | 
						|
	if err != nil {
 | 
						|
		return xerrors.Errorf("database error: %w", err)
 | 
						|
	}
 | 
						|
 | 
						|
	if needsUpdate {
 | 
						|
		logging.Log.Info("Need to update DB")
 | 
						|
		logging.Log.Info("Downloading DB...")
 | 
						|
		if err := client.Download(ctx, trivyOpts.TrivyCacheDBDir, ftypes.RegistryOptions{}); err != nil {
 | 
						|
			return xerrors.Errorf("Failed to download vulnerability DB. err: %w", err)
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	// for debug
 | 
						|
	if err := showDBInfo(trivyOpts.TrivyCacheDBDir); err != nil {
 | 
						|
		return xerrors.Errorf("Failed to show database info. err: %w", err)
 | 
						|
	}
 | 
						|
	return nil
 | 
						|
}
 | 
						|
 | 
						|
func showDBInfo(cacheDir string) error {
 | 
						|
	m := metadata.NewClient(cacheDir)
 | 
						|
	meta, err := m.Get()
 | 
						|
	if err != nil {
 | 
						|
		return xerrors.Errorf("Failed to get DB metadata. err: %w", err)
 | 
						|
	}
 | 
						|
	logging.Log.Debugf("DB Schema: %d, UpdatedAt: %s, NextUpdate: %s, DownloadedAt: %s",
 | 
						|
		meta.Version, meta.UpdatedAt, meta.NextUpdate, meta.DownloadedAt)
 | 
						|
	return nil
 | 
						|
}
 | 
						|
 | 
						|
// Scan : scan target library
 | 
						|
func (d *libraryDetector) scan() ([]models.VulnInfo, error) {
 | 
						|
	if d.scanner.Type == ftypes.Jar {
 | 
						|
		if err := d.improveJARInfo(); err != nil {
 | 
						|
			return nil, xerrors.Errorf("Failed to improve JAR information by trivy Java DB. err: %w", err)
 | 
						|
		}
 | 
						|
	}
 | 
						|
	scanner, ok := library.NewDriver(d.scanner.Type)
 | 
						|
	if !ok {
 | 
						|
		return nil, xerrors.Errorf("Failed to new a library driver for %s", d.scanner.Type)
 | 
						|
	}
 | 
						|
	var vulnerabilities = []models.VulnInfo{}
 | 
						|
	for _, pkg := range d.scanner.Libs {
 | 
						|
		tvulns, err := scanner.DetectVulnerabilities("", pkg.Name, pkg.Version)
 | 
						|
		if err != nil {
 | 
						|
			return nil, xerrors.Errorf("Failed to detect %s vulnerabilities. err: %w", scanner.Type(), err)
 | 
						|
		}
 | 
						|
		if len(tvulns) == 0 {
 | 
						|
			continue
 | 
						|
		}
 | 
						|
 | 
						|
		vulns := d.convertFanalToVuln(tvulns)
 | 
						|
		vulnerabilities = append(vulnerabilities, vulns...)
 | 
						|
	}
 | 
						|
 | 
						|
	return vulnerabilities, nil
 | 
						|
}
 | 
						|
 | 
						|
func (d *libraryDetector) improveJARInfo() error {
 | 
						|
	libs := make([]models.Library, 0, len(d.scanner.Libs))
 | 
						|
	for _, l := range d.scanner.Libs {
 | 
						|
		if l.Digest == "" {
 | 
						|
			// This is the case from pom.properties, it should be respected as is.
 | 
						|
			libs = append(libs, l)
 | 
						|
			continue
 | 
						|
		}
 | 
						|
 | 
						|
		algorithm, sha1, found := strings.Cut(l.Digest, ":")
 | 
						|
		if !found || algorithm != "sha1" {
 | 
						|
			logging.Log.Debugf("No SHA1 hash found for %s in the digest: %q", l.FilePath, l.Digest)
 | 
						|
			libs = append(libs, l)
 | 
						|
			continue
 | 
						|
		}
 | 
						|
 | 
						|
		foundProps, err := d.javaDBClient.SearchBySHA1(sha1)
 | 
						|
		if err != nil {
 | 
						|
			if !errors.Is(err, jar.ArtifactNotFoundErr) {
 | 
						|
				return xerrors.Errorf("Failed to search trivy Java DB. err: %w", err)
 | 
						|
			}
 | 
						|
 | 
						|
			logging.Log.Debugf("No record in Java DB for %s by SHA1: %s", l.FilePath, sha1)
 | 
						|
			libs = append(libs, l)
 | 
						|
			continue
 | 
						|
		}
 | 
						|
 | 
						|
		foundLib := foundProps.Package()
 | 
						|
		l.Name = foundLib.Name
 | 
						|
		l.Version = foundLib.Version
 | 
						|
		libs = append(libs, l)
 | 
						|
	}
 | 
						|
 | 
						|
	d.scanner.Libs = lo.UniqBy(libs, func(lib models.Library) string {
 | 
						|
		return fmt.Sprintf("%s::%s::%s", lib.Name, lib.Version, lib.FilePath)
 | 
						|
	})
 | 
						|
	return nil
 | 
						|
}
 | 
						|
 | 
						|
func (d libraryDetector) convertFanalToVuln(tvulns []types.DetectedVulnerability) (vulns []models.VulnInfo) {
 | 
						|
	for _, tvuln := range tvulns {
 | 
						|
		vinfo, err := d.getVulnDetail(tvuln)
 | 
						|
		if err != nil {
 | 
						|
			logging.Log.Debugf("failed to getVulnDetail. err: %+v, tvuln: %#v", err, tvuln)
 | 
						|
			continue
 | 
						|
		}
 | 
						|
		vulns = append(vulns, vinfo)
 | 
						|
	}
 | 
						|
	return vulns
 | 
						|
}
 | 
						|
 | 
						|
func (d libraryDetector) getVulnDetail(tvuln types.DetectedVulnerability) (vinfo models.VulnInfo, err error) {
 | 
						|
	vul, err := trivydb.Config{}.GetVulnerability(tvuln.VulnerabilityID)
 | 
						|
	if err != nil {
 | 
						|
		return vinfo, err
 | 
						|
	}
 | 
						|
 | 
						|
	vinfo.CveID = tvuln.VulnerabilityID
 | 
						|
	vinfo.CveContents = getCveContents(tvuln.VulnerabilityID, vul)
 | 
						|
	vinfo.LibraryFixedIns = []models.LibraryFixedIn{
 | 
						|
		{
 | 
						|
			Key:     d.scanner.GetLibraryKey(),
 | 
						|
			Name:    tvuln.PkgName,
 | 
						|
			FixedIn: tvuln.FixedVersion,
 | 
						|
			Path:    d.scanner.LockfilePath,
 | 
						|
		},
 | 
						|
	}
 | 
						|
	return vinfo, nil
 | 
						|
}
 | 
						|
 | 
						|
func getCveContents(cveID string, vul trivydbTypes.Vulnerability) (contents map[models.CveContentType][]models.CveContent) {
 | 
						|
	contents = map[models.CveContentType][]models.CveContent{}
 | 
						|
	refs := make([]models.Reference, 0, len(vul.References))
 | 
						|
	for _, refURL := range vul.References {
 | 
						|
		refs = append(refs, models.Reference{Source: "trivy", Link: refURL})
 | 
						|
	}
 | 
						|
 | 
						|
	for source, severity := range vul.VendorSeverity {
 | 
						|
		contents[models.CveContentType(fmt.Sprintf("%s:%s", models.Trivy, source))] = append(contents[models.CveContentType(fmt.Sprintf("%s:%s", models.Trivy, source))], models.CveContent{
 | 
						|
			Type:          models.CveContentType(fmt.Sprintf("%s:%s", models.Trivy, source)),
 | 
						|
			CveID:         cveID,
 | 
						|
			Title:         vul.Title,
 | 
						|
			Summary:       vul.Description,
 | 
						|
			Cvss3Severity: trivydbTypes.SeverityNames[severity],
 | 
						|
			Published: func() time.Time {
 | 
						|
				if vul.PublishedDate != nil {
 | 
						|
					return *vul.PublishedDate
 | 
						|
				}
 | 
						|
				return time.Time{}
 | 
						|
			}(),
 | 
						|
			LastModified: func() time.Time {
 | 
						|
				if vul.LastModifiedDate != nil {
 | 
						|
					return *vul.LastModifiedDate
 | 
						|
				}
 | 
						|
				return time.Time{}
 | 
						|
			}(),
 | 
						|
			References: refs,
 | 
						|
		})
 | 
						|
	}
 | 
						|
 | 
						|
	for source, cvss := range vul.CVSS {
 | 
						|
		contents[models.CveContentType(fmt.Sprintf("%s:%s", models.Trivy, source))] = append(contents[models.CveContentType(fmt.Sprintf("%s:%s", models.Trivy, source))], models.CveContent{
 | 
						|
			Type:        models.CveContentType(fmt.Sprintf("%s:%s", models.Trivy, source)),
 | 
						|
			CveID:       cveID,
 | 
						|
			Title:       vul.Title,
 | 
						|
			Summary:     vul.Description,
 | 
						|
			Cvss2Score:  cvss.V2Score,
 | 
						|
			Cvss2Vector: cvss.V2Vector,
 | 
						|
			Cvss3Score:  cvss.V3Score,
 | 
						|
			Cvss3Vector: cvss.V3Vector,
 | 
						|
			Published: func() time.Time {
 | 
						|
				if vul.PublishedDate != nil {
 | 
						|
					return *vul.PublishedDate
 | 
						|
				}
 | 
						|
				return time.Time{}
 | 
						|
			}(),
 | 
						|
			LastModified: func() time.Time {
 | 
						|
				if vul.LastModifiedDate != nil {
 | 
						|
					return *vul.LastModifiedDate
 | 
						|
				}
 | 
						|
				return time.Time{}
 | 
						|
			}(),
 | 
						|
			References: refs,
 | 
						|
		})
 | 
						|
	}
 | 
						|
 | 
						|
	return contents
 | 
						|
}
 |