Files
trivy/pkg/scanner/scan.go
Teppei Fukuda 4189855fc1 fix(cache): specify a directory to store image cache (#341)
* chore(mod): update dependencies

* fix(scanner): make scanner take a cache client as the argument

* refactor: sort imports

* refactor(cache): create a struct to clear cache

* fix(cache): use a struct to clear cache

* fix(wire): update constructor to take cache struct

* fix(cache): use the constructor generated by wire

* docs(cli): update the option description

* fix(cache): use the cache struct

* fix(cache): split Reset into ClearDB and ClearImages
2019-12-26 16:08:08 +02:00

157 lines
4.1 KiB
Go

package scanner
import (
"context"
"flag"
"fmt"
"os"
"sort"
"github.com/google/wire"
"golang.org/x/crypto/ssh/terminal"
"golang.org/x/xerrors"
"github.com/aquasecurity/fanal/analyzer"
"github.com/aquasecurity/fanal/cache"
"github.com/aquasecurity/fanal/extractor"
"github.com/aquasecurity/fanal/extractor/docker"
libDetector "github.com/aquasecurity/trivy/pkg/detector/library"
ospkgDetector "github.com/aquasecurity/trivy/pkg/detector/ospkg"
"github.com/aquasecurity/trivy/pkg/report"
rpcLibDetector "github.com/aquasecurity/trivy/pkg/rpc/client/library"
rpcOSDetector "github.com/aquasecurity/trivy/pkg/rpc/client/ospkg"
"github.com/aquasecurity/trivy/pkg/scanner/library"
libScanner "github.com/aquasecurity/trivy/pkg/scanner/library"
"github.com/aquasecurity/trivy/pkg/scanner/ospkg"
ospkgScanner "github.com/aquasecurity/trivy/pkg/scanner/ospkg"
"github.com/aquasecurity/trivy/pkg/types"
"github.com/aquasecurity/trivy/pkg/utils"
)
var StandaloneSet = wire.NewSet(
ospkgDetector.SuperSet,
ospkgScanner.NewScanner,
libDetector.SuperSet,
libScanner.NewScanner,
NewScanner,
)
var ClientSet = wire.NewSet(
rpcOSDetector.SuperSet,
ospkgScanner.NewScanner,
rpcLibDetector.SuperSet,
libScanner.NewScanner,
NewScanner,
)
type Scanner struct {
cacheClient cache.Cache
ospkgScanner ospkg.Scanner
libScanner library.Scanner
}
func NewScanner(cacheClient cache.Cache, ospkgScanner ospkg.Scanner, libScanner library.Scanner) Scanner {
return Scanner{cacheClient: cacheClient, ospkgScanner: ospkgScanner, libScanner: libScanner}
}
func (s Scanner) ScanImage(imageName, filePath string, scanOptions types.ScanOptions) (report.Results, error) {
results := report.Results{}
ctx := context.Background()
var target string
var files extractor.FileMap
var ac analyzer.Config
dockerOption, err := types.GetDockerOption()
if err != nil {
return nil, xerrors.Errorf("failed to get docker option: %w", err)
}
if imageName != "" {
dockerOption.Timeout = scanOptions.Timeout
}
ext, err := docker.NewDockerExtractor(dockerOption, s.cacheClient)
if err != nil {
return nil, err
}
ac = analyzer.Config{Extractor: ext}
if imageName != "" {
target = imageName
files, err = ac.Analyze(ctx, imageName, dockerOption)
if err != nil {
return nil, xerrors.Errorf("failed to analyze image: %w", err)
}
} else if filePath != "" {
target = filePath
rc, err := openStream(filePath)
if err != nil {
return nil, xerrors.Errorf("failed to open stream: %w", err)
}
files, err = ac.AnalyzeFile(ctx, rc)
if err != nil {
return nil, err
}
} else {
return nil, xerrors.New("image name or image file must be specified")
}
if utils.StringInSlice("os", scanOptions.VulnType) {
osFamily, osVersion, osVulns, err := s.ospkgScanner.Scan(files)
if err != nil && err != ospkgDetector.ErrUnsupportedOS {
return nil, xerrors.Errorf("failed to scan the image: %w", err)
}
if osFamily != "" {
imageDetail := fmt.Sprintf("%s (%s %s)", target, osFamily, osVersion)
results = append(results, report.Result{
Target: imageDetail,
Vulnerabilities: osVulns,
})
}
}
if utils.StringInSlice("library", scanOptions.VulnType) {
libVulns, err := s.libScanner.Scan(files)
if err != nil {
return nil, xerrors.Errorf("failed to scan libraries: %w", err)
}
var libResults report.Results
for path, vulns := range libVulns {
libResults = append(libResults, report.Result{
Target: path,
Vulnerabilities: vulns,
})
}
sort.Slice(libResults, func(i, j int) bool {
return libResults[i].Target < libResults[j].Target
})
results = append(results, libResults...)
}
return results, nil
}
func (s Scanner) ScanFile(f *os.File) (report.Results, error) {
vulns, err := s.libScanner.ScanFile(f)
if err != nil {
return nil, xerrors.Errorf("failed to scan libraries in file: %w", err)
}
results := report.Results{
{Target: f.Name(), Vulnerabilities: vulns},
}
return results, nil
}
func openStream(path string) (*os.File, error) {
if path == "-" {
if terminal.IsTerminal(0) {
flag.Usage()
os.Exit(64)
} else {
return os.Stdin, nil
}
}
return os.Open(path)
}