Files
trivy/pkg/scanner/scan.go
Teppei Fukuda 74717b888e feat: support client/server mode (#295)
* chore(app): change dir

* feat(rpc): add a proto file and auto-generated files

* chore(dep): add dependencies

* fix(app): fix import path

* fix(integration): fix import path

* fix(protoc): use enum for severity

* chore(Makefile): add fmt andd protoc

* chore(clang): add .clang-format

* refactor: split functions for client/server (#296)

* refactor(db): split db.Download

* refactor(standalone): create a different package

* refactor(vulnerability): split FillAndFilter

* fix(protoc): use enum for severity

* chore(Makefile): add fmt andd protoc

* chore(clang): add .clang-format

* fix(db): remove an unused variable

* fix(db): expose the github client as an argument of constructor

* refactor(vulnerability): add the detail message

* feat(rpc): add rpc client (#302)

* fix(protoc): use enum for severity

* chore(Makefile): add fmt andd protoc

* chore(clang): add .clang-format

* feat(rpc): convert types

* feat(rpc): add rpc client

* token: Refactor to handle bad headers being set

Signed-off-by: Simarpreet Singh <simar@linux.com>

* feat(rpc): add rpc server (#303)

* feat(rpc): add rpc server

* feat(utils): add CopyFile

* feat(server/config): add config struct

* feat(detector): add detector

* feat(scanner): delegate procedures to detector

* fix(scanner): fix the interface

* test(mock): add mocks

* test(rpc/server): add tests

* test(rpc/ospkg/server): add tests

* tets(os/detector): add tests

* refactor(library): move directories

* chore(dependency): add google/wire

* refactor(library): introduce google/wire

* refactor(ospkg/detector): move directory

* feat(rpc): add eosl

* refactor(ospkg): introduce google/wire

* refactor(wire): bind an interface

* refactor(client): use wire.Struct

* chore(Makefile): fix wire

* test(server): add AssertExpectations

* test(server): add AssertExpectations

* refactor(server): remove debug log

* refactor(error): add more context messages

* test(server): fix error message

* refactor(test): create a constructor of mock

* refactor(config): remove an unused variable

* test(config): add an assertion to test the config struct

* feat(client/server): add sub commands (#304)

* feat(rpc): add rpc server

* feat(utils): add CopyFile

* feat(server/config): add config struct

* feat(detector): add detector

* feat(scanner): delegate procedures to detector

* fix(scanner): fix the interface

* feat(client/server): add sub commands

* merge(server3)

* test(scan): remove an unused mock

* refactor(client): generate the constructor by wire

* fix(cli): change the default port

* fix(server): use auto-generated constructor

* feat(ospkg): return eosl

* test(integration): add integration tests for client/server (#306)

* fix(server): remove unnecessary options

* test(integration): add integration tests for client/server

* fix(server): wrap an error

* fix(server): change the update interval

* fix(server): display the error detail

* test(config): add an assertion to test the config struct

* fix(client): returns an error when failing to initizlie a logger

* test(ospkg/server): add eosl

* Squashed commit of the following:

* test(server): refactor and add tests (#307)

* test(github): create a mock

* test(db): create a mock

* test(server): add tests for DB hot update

* chore(db): add a log message

* refactor(db): introduce google/wire

* refactor(rpc): move directory

* refactor(injector): fix import name

* refactor(import): remove new lines

* fix(server): display the error detail

* fix(server): change the update interval

* fix(server): wrap an error

* test(integration): add integration tests for client/server

* fix(server): remove unnecessary options

* refactor(server): return an error when failing to initialize a logger

* refactor(server): remove unused error

* fix(client/server): fix default port

* chore(README): add client/server

* chore(README): update
2019-12-13 15:00:11 +02:00

146 lines
3.8 KiB
Go

package scanner
import (
"context"
"flag"
"fmt"
"os"
"sort"
"github.com/google/wire"
"github.com/aquasecurity/trivy/pkg/report"
"github.com/aquasecurity/fanal/analyzer"
"github.com/aquasecurity/fanal/extractor"
libDetector "github.com/aquasecurity/trivy/pkg/detector/library"
ospkgDetector "github.com/aquasecurity/trivy/pkg/detector/ospkg"
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"
"golang.org/x/crypto/ssh/terminal"
"golang.org/x/xerrors"
)
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 {
ospkgScanner ospkg.Scanner
libScanner library.Scanner
}
func NewScanner(ospkgScanner ospkg.Scanner, libScanner library.Scanner) Scanner {
return Scanner{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
if imageName != "" {
target = imageName
dockerOption, err := types.GetDockerOption()
if err != nil {
return nil, xerrors.Errorf("failed to get docker option: %w", err)
}
dockerOption.Timeout = scanOptions.Timeout
files, err = analyzer.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 = analyzer.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{
FileName: 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{
FileName: path,
Vulnerabilities: vulns,
})
}
sort.Slice(libResults, func(i, j int) bool {
return libResults[i].FileName < libResults[j].FileName
})
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{
{FileName: 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)
}