* Avoid to use once inside trivy javadb Updater Because detector package may be used as library-like way * Update detector/javadb/javadb.go Co-authored-by: MaineK00n <mainek00n.1229@gmail.com> * Update detector/javadb/javadb.go Co-authored-by: MaineK00n <mainek00n.1229@gmail.com> * Update detector/javadb/javadb.go Co-authored-by: MaineK00n <mainek00n.1229@gmail.com> * Update detector/javadb/javadb.go Co-authored-by: MaineK00n <mainek00n.1229@gmail.com> * Update detector/javadb/javadb.go Co-authored-by: MaineK00n <mainek00n.1229@gmail.com> * Update detector/javadb/javadb.go Co-authored-by: MaineK00n <mainek00n.1229@gmail.com> * Update detector/javadb/javadb.go Co-authored-by: MaineK00n <mainek00n.1229@gmail.com> * Update detector/javadb/javadb.go Co-authored-by: MaineK00n <mainek00n.1229@gmail.com> * Update detector/javadb/javadb.go Co-authored-by: MaineK00n <mainek00n.1229@gmail.com> * Update detector/javadb/javadb.go Co-authored-by: MaineK00n <mainek00n.1229@gmail.com> * Avoid else if, unless necessary * go mod tidy * Add package comment --------- Co-authored-by: MaineK00n <mainek00n.1229@gmail.com>
253 lines
6.5 KiB
Go
253 lines
6.5 KiB
Go
package models
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
"strings"
|
|
|
|
"github.com/aquasecurity/go-dep-parser/pkg/java/jar"
|
|
"github.com/aquasecurity/trivy-db/pkg/db"
|
|
trivyDBTypes "github.com/aquasecurity/trivy-db/pkg/types"
|
|
"github.com/aquasecurity/trivy/pkg/detector/library"
|
|
ftypes "github.com/aquasecurity/trivy/pkg/fanal/types"
|
|
"github.com/aquasecurity/trivy/pkg/types"
|
|
"github.com/samber/lo"
|
|
"golang.org/x/xerrors"
|
|
|
|
"github.com/future-architect/vuls/detector/javadb"
|
|
"github.com/future-architect/vuls/logging"
|
|
)
|
|
|
|
// LibraryScanners is an array of LibraryScanner
|
|
type LibraryScanners []LibraryScanner
|
|
|
|
// Find : find by name
|
|
func (lss LibraryScanners) Find(path, name string) map[string]Library {
|
|
filtered := map[string]Library{}
|
|
for _, ls := range lss {
|
|
for _, lib := range ls.Libs {
|
|
if ls.LockfilePath == path && lib.Name == name {
|
|
filtered[ls.LockfilePath] = lib
|
|
break
|
|
}
|
|
}
|
|
}
|
|
return filtered
|
|
}
|
|
|
|
// Total returns total count of pkgs
|
|
func (lss LibraryScanners) Total() (total int) {
|
|
for _, lib := range lss {
|
|
total += len(lib.Libs)
|
|
}
|
|
return
|
|
}
|
|
|
|
// LibraryScanner has libraries information
|
|
type LibraryScanner struct {
|
|
Type ftypes.LangType
|
|
Libs []Library
|
|
|
|
// The path to the Lockfile is stored.
|
|
LockfilePath string `json:"path,omitempty"`
|
|
|
|
JavaDBClient *javadb.DBClient `json:"-"`
|
|
}
|
|
|
|
// Library holds the attribute of a package library
|
|
type Library struct {
|
|
Name string
|
|
Version string
|
|
|
|
// The Path to the library in the container image. Empty string when Lockfile scan.
|
|
// This field is used to convert the result JSON of a `trivy image` using trivy-to-vuls.
|
|
FilePath string
|
|
Digest string
|
|
}
|
|
|
|
// Scan : scan target library
|
|
func (s LibraryScanner) Scan() ([]VulnInfo, error) {
|
|
if s.Type == ftypes.Jar {
|
|
if err := s.improveJARInfo(); err != nil {
|
|
return nil, xerrors.Errorf("Failed to improve JAR information by trivy Java DB. err: %w", err)
|
|
}
|
|
}
|
|
scanner, ok := library.NewDriver(s.Type)
|
|
if !ok {
|
|
return nil, xerrors.Errorf("Failed to new a library driver for %s", s.Type)
|
|
}
|
|
var vulnerabilities = []VulnInfo{}
|
|
for _, pkg := range s.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 := s.convertFanalToVuln(tvulns)
|
|
vulnerabilities = append(vulnerabilities, vulns...)
|
|
}
|
|
|
|
return vulnerabilities, nil
|
|
}
|
|
|
|
func (s *LibraryScanner) improveJARInfo() error {
|
|
libs := make([]Library, 0, len(s.Libs))
|
|
for _, l := range s.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 := s.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.Library()
|
|
l.Name = foundLib.Name
|
|
l.Version = foundLib.Version
|
|
libs = append(libs, l)
|
|
}
|
|
|
|
s.Libs = lo.UniqBy(libs, func(lib Library) string {
|
|
return fmt.Sprintf("%s::%s::%s", lib.Name, lib.Version, lib.FilePath)
|
|
})
|
|
return nil
|
|
}
|
|
|
|
func (s LibraryScanner) convertFanalToVuln(tvulns []types.DetectedVulnerability) (vulns []VulnInfo) {
|
|
for _, tvuln := range tvulns {
|
|
vinfo, err := s.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 (s LibraryScanner) getVulnDetail(tvuln types.DetectedVulnerability) (vinfo VulnInfo, err error) {
|
|
vul, err := db.Config{}.GetVulnerability(tvuln.VulnerabilityID)
|
|
if err != nil {
|
|
return vinfo, err
|
|
}
|
|
|
|
vinfo.CveID = tvuln.VulnerabilityID
|
|
vinfo.CveContents = getCveContents(tvuln.VulnerabilityID, vul)
|
|
vinfo.LibraryFixedIns = []LibraryFixedIn{
|
|
{
|
|
Key: s.GetLibraryKey(),
|
|
Name: tvuln.PkgName,
|
|
FixedIn: tvuln.FixedVersion,
|
|
Path: s.LockfilePath,
|
|
},
|
|
}
|
|
return vinfo, nil
|
|
}
|
|
|
|
func getCveContents(cveID string, vul trivyDBTypes.Vulnerability) (contents map[CveContentType][]CveContent) {
|
|
contents = map[CveContentType][]CveContent{}
|
|
refs := []Reference{}
|
|
for _, refURL := range vul.References {
|
|
refs = append(refs, Reference{Source: "trivy", Link: refURL})
|
|
}
|
|
|
|
contents[Trivy] = []CveContent{
|
|
{
|
|
Type: Trivy,
|
|
CveID: cveID,
|
|
Title: vul.Title,
|
|
Summary: vul.Description,
|
|
Cvss3Severity: string(vul.Severity),
|
|
References: refs,
|
|
},
|
|
}
|
|
return contents
|
|
}
|
|
|
|
// FindLockFiles is a list of filenames that is the target of findLock
|
|
var FindLockFiles = []string{
|
|
// dart/pub
|
|
ftypes.PubSpecLock,
|
|
// elixir/mix
|
|
ftypes.MixLock,
|
|
// node
|
|
ftypes.NpmPkgLock, ftypes.YarnLock, ftypes.PnpmLock,
|
|
// ruby
|
|
ftypes.GemfileLock, "*.gemspec",
|
|
// rust
|
|
ftypes.CargoLock,
|
|
// php
|
|
ftypes.ComposerLock,
|
|
// python
|
|
ftypes.PipRequirements, ftypes.PipfileLock, ftypes.PoetryLock,
|
|
// .net
|
|
ftypes.NuGetPkgsLock, ftypes.NuGetPkgsConfig, "*.deps.json", "*Packages.props",
|
|
// gomod
|
|
ftypes.GoMod, ftypes.GoSum,
|
|
// java
|
|
ftypes.MavenPom, "*.jar", "*.war", "*.ear", "*.par", "*gradle.lockfile",
|
|
// C / C++
|
|
ftypes.ConanLock,
|
|
// Swift
|
|
ftypes.CocoaPodsLock, ftypes.SwiftResolved,
|
|
}
|
|
|
|
// GetLibraryKey returns target library key
|
|
func (s LibraryScanner) GetLibraryKey() string {
|
|
switch s.Type {
|
|
case ftypes.Bundler, ftypes.GemSpec:
|
|
return "ruby"
|
|
case ftypes.Cargo, ftypes.RustBinary:
|
|
return "rust"
|
|
case ftypes.Composer:
|
|
return "php"
|
|
case ftypes.GoBinary, ftypes.GoModule:
|
|
return "gomod"
|
|
case ftypes.Jar, ftypes.Pom, ftypes.Gradle:
|
|
return "java"
|
|
case ftypes.Npm, ftypes.Yarn, ftypes.Pnpm, ftypes.NodePkg, ftypes.JavaScript:
|
|
return "node"
|
|
case ftypes.NuGet, ftypes.DotNetCore:
|
|
return ".net"
|
|
case ftypes.Pipenv, ftypes.Poetry, ftypes.Pip, ftypes.PythonPkg:
|
|
return "python"
|
|
case ftypes.Conan:
|
|
return "c"
|
|
case ftypes.Pub:
|
|
return "dart"
|
|
case ftypes.Hex:
|
|
return "elixir"
|
|
case ftypes.Swift, ftypes.Cocoapods:
|
|
return "swift"
|
|
default:
|
|
return ""
|
|
}
|
|
}
|
|
|
|
// LibraryFixedIn has library fixed information
|
|
type LibraryFixedIn struct {
|
|
Key string `json:"key,omitempty"`
|
|
Name string `json:"name,omitempty"`
|
|
FixedIn string `json:"fixedIn,omitempty"`
|
|
Path string `json:"path,omitempty"`
|
|
}
|