mirror of
https://github.com/aquasecurity/trivy.git
synced 2025-12-12 15:50:15 -08:00
feat: support repository and filesystem scan (#503)
* refactor: embed config * refactor: replace image and layer with artifact and blob * feat(config): add ArtifactConfig * fix(scanner): use Artifact * test(scanner): update mocks * feat: add repo and fs subcommands * chore(mod): update * refactor: fix warn message * feat(cli): add --no-progress to repo and fs * mod: Update fanal dependency Signed-off-by: Simarpreet Singh <simar@linux.com> Co-authored-by: Simarpreet Singh <simar@linux.com>
This commit is contained in:
@@ -12,9 +12,9 @@ import (
|
||||
|
||||
"github.com/aquasecurity/trivy-db/pkg/db"
|
||||
"github.com/aquasecurity/trivy-db/pkg/types"
|
||||
"github.com/aquasecurity/trivy/internal/artifact"
|
||||
"github.com/aquasecurity/trivy/internal/client"
|
||||
"github.com/aquasecurity/trivy/internal/server"
|
||||
"github.com/aquasecurity/trivy/internal/standalone"
|
||||
tdb "github.com/aquasecurity/trivy/pkg/db"
|
||||
"github.com/aquasecurity/trivy/pkg/utils"
|
||||
"github.com/aquasecurity/trivy/pkg/vulnerability"
|
||||
@@ -240,10 +240,12 @@ func NewApp(version string) *cli.App {
|
||||
app.Flags = flags
|
||||
app.Commands = []*cli.Command{
|
||||
NewImageCommand(),
|
||||
NewFilesystemCommand(),
|
||||
NewRepositoryCommand(),
|
||||
NewClientCommand(),
|
||||
NewServerCommand(),
|
||||
}
|
||||
app.Action = standalone.Run
|
||||
app.Action = artifact.ImageRun
|
||||
return app
|
||||
}
|
||||
|
||||
@@ -320,11 +322,65 @@ func NewImageCommand() *cli.Command {
|
||||
Name: "image",
|
||||
Aliases: []string{"i"},
|
||||
Usage: "scan an image",
|
||||
Action: standalone.Run,
|
||||
Action: artifact.ImageRun,
|
||||
Flags: imageFlags,
|
||||
}
|
||||
}
|
||||
|
||||
func NewFilesystemCommand() *cli.Command {
|
||||
return &cli.Command{
|
||||
Name: "filesystem",
|
||||
Aliases: []string{"fs"},
|
||||
Usage: "scan local filesystem",
|
||||
Action: artifact.FilesystemRun,
|
||||
Flags: []cli.Flag{
|
||||
&templateFlag,
|
||||
&formatFlag,
|
||||
&inputFlag,
|
||||
&severityFlag,
|
||||
&outputFlag,
|
||||
&exitCodeFlag,
|
||||
&clearCacheFlag,
|
||||
&quietFlag,
|
||||
&ignoreUnfixedFlag,
|
||||
&debugFlag,
|
||||
&removedPkgsFlag,
|
||||
&vulnTypeFlag,
|
||||
&ignoreFileFlag,
|
||||
&cacheDirFlag,
|
||||
&timeoutFlag,
|
||||
&noProgressFlag,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func NewRepositoryCommand() *cli.Command {
|
||||
return &cli.Command{
|
||||
Name: "repository",
|
||||
Aliases: []string{"repo"},
|
||||
Usage: "scan remote repository",
|
||||
Action: artifact.RepositoryRun,
|
||||
Flags: []cli.Flag{
|
||||
&templateFlag,
|
||||
&formatFlag,
|
||||
&inputFlag,
|
||||
&severityFlag,
|
||||
&outputFlag,
|
||||
&exitCodeFlag,
|
||||
&clearCacheFlag,
|
||||
&quietFlag,
|
||||
&ignoreUnfixedFlag,
|
||||
&debugFlag,
|
||||
&removedPkgsFlag,
|
||||
&vulnTypeFlag,
|
||||
&ignoreFileFlag,
|
||||
&cacheDirFlag,
|
||||
&timeoutFlag,
|
||||
&noProgressFlag,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func NewClientCommand() *cli.Command {
|
||||
return &cli.Command{
|
||||
Name: "client",
|
||||
|
||||
@@ -9,12 +9,11 @@ import (
|
||||
|
||||
type Config struct {
|
||||
config.GlobalConfig
|
||||
config.ArtifactConfig
|
||||
config.DBConfig
|
||||
config.ImageConfig
|
||||
config.ReportConfig
|
||||
|
||||
NoProgress bool
|
||||
|
||||
// deprecated
|
||||
onlyUpdate string
|
||||
// deprecated
|
||||
@@ -30,12 +29,11 @@ func New(c *cli.Context) (Config, error) {
|
||||
}
|
||||
|
||||
return Config{
|
||||
GlobalConfig: gc,
|
||||
DBConfig: config.NewDBConfig(c),
|
||||
ImageConfig: config.NewImageConfig(c),
|
||||
ReportConfig: config.NewReportConfig(c),
|
||||
|
||||
NoProgress: c.Bool("no-progress"),
|
||||
GlobalConfig: gc,
|
||||
ArtifactConfig: config.NewArtifactConfig(c),
|
||||
DBConfig: config.NewDBConfig(c),
|
||||
ImageConfig: config.NewImageConfig(c),
|
||||
ReportConfig: config.NewReportConfig(c),
|
||||
|
||||
onlyUpdate: c.String("only-update"),
|
||||
refresh: c.Bool("refresh"),
|
||||
@@ -43,7 +41,7 @@ func New(c *cli.Context) (Config, error) {
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (c *Config) Init() error {
|
||||
func (c *Config) Init(image bool) error {
|
||||
if err := c.ReportConfig.Init(c.Logger); err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -59,10 +57,16 @@ func (c *Config) Init() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
if err := c.ImageConfig.Init(c.Context.Args(), c.Logger); err != nil {
|
||||
if err := c.ArtifactConfig.Init(c.Context.Args(), c.Logger); err != nil {
|
||||
cli.ShowAppHelp(c.Context)
|
||||
return err
|
||||
}
|
||||
|
||||
if image {
|
||||
if err := c.ImageConfig.Init(c.Context.Args(), c.Logger); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -38,8 +38,8 @@ func TestConfig_Init(t *testing.T) {
|
||||
GlobalConfig: config.GlobalConfig{
|
||||
Quiet: true,
|
||||
},
|
||||
ImageConfig: config.ImageConfig{
|
||||
ImageName: "alpine:3.10",
|
||||
ArtifactConfig: config.ArtifactConfig{
|
||||
Target: "alpine:3.10",
|
||||
},
|
||||
ReportConfig: config.ReportConfig{
|
||||
Severities: []dbTypes.Severity{dbTypes.SeverityCritical},
|
||||
@@ -74,8 +74,8 @@ func TestConfig_Init(t *testing.T) {
|
||||
Output: os.Stdout,
|
||||
VulnType: []string{"os", "library"},
|
||||
},
|
||||
ImageConfig: config.ImageConfig{
|
||||
ImageName: "centos:7",
|
||||
ArtifactConfig: config.ArtifactConfig{
|
||||
Target: "centos:7",
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -91,8 +91,8 @@ func TestConfig_Init(t *testing.T) {
|
||||
Output: os.Stdout,
|
||||
VulnType: []string{"os", "library"},
|
||||
},
|
||||
ImageConfig: config.ImageConfig{
|
||||
ImageName: "debian:buster",
|
||||
ArtifactConfig: config.ArtifactConfig{
|
||||
Target: "debian:buster",
|
||||
},
|
||||
onlyUpdate: "alpine",
|
||||
},
|
||||
@@ -110,8 +110,8 @@ func TestConfig_Init(t *testing.T) {
|
||||
VulnType: []string{"os", "library"},
|
||||
Template: "@contrib/gitlab.tpl",
|
||||
},
|
||||
ImageConfig: config.ImageConfig{
|
||||
ImageName: "gitlab/gitlab-ce:12.7.2-ce.0",
|
||||
ArtifactConfig: config.ArtifactConfig{
|
||||
Target: "gitlab/gitlab-ce:12.7.2-ce.0",
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -129,8 +129,8 @@ func TestConfig_Init(t *testing.T) {
|
||||
Template: "@contrib/gitlab.tpl",
|
||||
Format: "json",
|
||||
},
|
||||
ImageConfig: config.ImageConfig{
|
||||
ImageName: "gitlab/gitlab-ce:12.7.2-ce.0",
|
||||
ArtifactConfig: config.ArtifactConfig{
|
||||
Target: "gitlab/gitlab-ce:12.7.2-ce.0",
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -147,8 +147,8 @@ func TestConfig_Init(t *testing.T) {
|
||||
VulnType: []string{"os", "library"},
|
||||
Format: "template",
|
||||
},
|
||||
ImageConfig: config.ImageConfig{
|
||||
ImageName: "gitlab/gitlab-ce:12.7.2-ce.0",
|
||||
ArtifactConfig: config.ArtifactConfig{
|
||||
Target: "gitlab/gitlab-ce:12.7.2-ce.0",
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -165,8 +165,8 @@ func TestConfig_Init(t *testing.T) {
|
||||
Output: os.Stdout,
|
||||
VulnType: []string{"os", "library"},
|
||||
},
|
||||
ImageConfig: config.ImageConfig{
|
||||
ImageName: "gcr.io/distroless/base",
|
||||
ArtifactConfig: config.ArtifactConfig{
|
||||
Target: "gcr.io/distroless/base",
|
||||
},
|
||||
autoRefresh: true,
|
||||
},
|
||||
@@ -180,7 +180,7 @@ func TestConfig_Init(t *testing.T) {
|
||||
name: "sad: multiple image names",
|
||||
args: []string{"centos:7", "alpine:3.10"},
|
||||
logs: []string{
|
||||
"multiple images cannot be specified",
|
||||
"multiple targets cannot be specified",
|
||||
},
|
||||
wantErr: "arguments error",
|
||||
},
|
||||
@@ -223,7 +223,7 @@ func TestConfig_Init(t *testing.T) {
|
||||
require.NoError(t, err, err)
|
||||
|
||||
c.GlobalConfig.Logger = logger.Sugar()
|
||||
err = c.Init()
|
||||
err = c.Init(true)
|
||||
|
||||
// tests log messages
|
||||
var gotMessages []string
|
||||
36
internal/artifact/fs.go
Normal file
36
internal/artifact/fs.go
Normal file
@@ -0,0 +1,36 @@
|
||||
package artifact
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"github.com/urfave/cli/v2"
|
||||
"golang.org/x/xerrors"
|
||||
|
||||
"github.com/aquasecurity/fanal/cache"
|
||||
"github.com/aquasecurity/trivy/internal/artifact/config"
|
||||
"github.com/aquasecurity/trivy/pkg/scanner"
|
||||
)
|
||||
|
||||
func filesystemScanner(ctx context.Context, dir string, ac cache.ArtifactCache, lac cache.LocalArtifactCache, timeout time.Duration) (
|
||||
scanner.Scanner, func(), error) {
|
||||
s, cleanup, err := initializeFilesystemScanner(ctx, dir, ac, lac)
|
||||
if err != nil {
|
||||
return scanner.Scanner{}, func() {}, xerrors.Errorf("unable to initialize a filesystem scanner: %w", err)
|
||||
}
|
||||
return s, cleanup, nil
|
||||
}
|
||||
|
||||
func FilesystemRun(cliCtx *cli.Context) error {
|
||||
c, err := config.New(cliCtx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// initialize config
|
||||
if err = c.Init(false); err != nil {
|
||||
return xerrors.Errorf("failed to initialize options: %w", err)
|
||||
}
|
||||
|
||||
return run(c, filesystemScanner)
|
||||
}
|
||||
50
internal/artifact/image.go
Normal file
50
internal/artifact/image.go
Normal file
@@ -0,0 +1,50 @@
|
||||
package artifact
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"github.com/urfave/cli/v2"
|
||||
"golang.org/x/xerrors"
|
||||
|
||||
"github.com/aquasecurity/fanal/cache"
|
||||
"github.com/aquasecurity/trivy/internal/artifact/config"
|
||||
"github.com/aquasecurity/trivy/pkg/scanner"
|
||||
)
|
||||
|
||||
func archiveScanner(ctx context.Context, input string, ac cache.ArtifactCache, lac cache.LocalArtifactCache, timeout time.Duration) (
|
||||
scanner.Scanner, func(), error) {
|
||||
s, err := initializeArchiveScanner(ctx, input, ac, lac, timeout)
|
||||
if err != nil {
|
||||
return scanner.Scanner{}, func() {}, xerrors.Errorf("unable to initialize the archive scanner: %w", err)
|
||||
}
|
||||
return s, func() {}, nil
|
||||
}
|
||||
|
||||
func dockerScanner(ctx context.Context, imageName string, ac cache.ArtifactCache, lac cache.LocalArtifactCache, timeout time.Duration) (
|
||||
scanner.Scanner, func(), error) {
|
||||
s, cleanup, err := initializeDockerScanner(ctx, imageName, ac, lac, timeout)
|
||||
if err != nil {
|
||||
return scanner.Scanner{}, func() {}, xerrors.Errorf("unable to initialize a docker scanner: %w", err)
|
||||
}
|
||||
return s, cleanup, nil
|
||||
}
|
||||
|
||||
func ImageRun(cliCtx *cli.Context) error {
|
||||
c, err := config.New(cliCtx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// initialize config
|
||||
if err = c.Init(true); err != nil {
|
||||
return xerrors.Errorf("failed to initialize options: %w", err)
|
||||
}
|
||||
|
||||
if c.Input != "" {
|
||||
// scan tar file
|
||||
return run(c, archiveScanner)
|
||||
}
|
||||
|
||||
return run(c, dockerScanner)
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
// +build wireinject
|
||||
|
||||
package standalone
|
||||
package artifact
|
||||
|
||||
import (
|
||||
"context"
|
||||
@@ -12,18 +12,28 @@ import (
|
||||
"github.com/google/wire"
|
||||
)
|
||||
|
||||
func initializeDockerScanner(ctx context.Context, imageName string, layerCache cache.ImageCache, localImageCache cache.LocalImageCache,
|
||||
func initializeDockerScanner(ctx context.Context, imageName string, artifactCache cache.ArtifactCache, localArtifactCache cache.LocalArtifactCache,
|
||||
timeout time.Duration) (scanner.Scanner, func(), error) {
|
||||
wire.Build(scanner.StandaloneDockerSet)
|
||||
return scanner.Scanner{}, nil, nil
|
||||
}
|
||||
|
||||
func initializeArchiveScanner(ctx context.Context, filePath string, layerCache cache.ImageCache, localImageCache cache.LocalImageCache,
|
||||
func initializeArchiveScanner(ctx context.Context, filePath string, artifactCache cache.ArtifactCache, localArtifactCache cache.LocalArtifactCache,
|
||||
timeout time.Duration) (scanner.Scanner, error) {
|
||||
wire.Build(scanner.StandaloneArchiveSet)
|
||||
return scanner.Scanner{}, nil
|
||||
}
|
||||
|
||||
func initializeFilesystemScanner(ctx context.Context, dir string, artifactCache cache.ArtifactCache, localArtifactCache cache.LocalArtifactCache) (scanner.Scanner, func(), error) {
|
||||
wire.Build(scanner.StandaloneFilesystemSet)
|
||||
return scanner.Scanner{}, nil, nil
|
||||
}
|
||||
|
||||
func initializeRepositoryScanner(ctx context.Context, url string, artifactCache cache.ArtifactCache, localArtifactCache cache.LocalArtifactCache) (scanner.Scanner, func(), error) {
|
||||
wire.Build(scanner.StandaloneRepositorySet)
|
||||
return scanner.Scanner{}, nil, nil
|
||||
}
|
||||
|
||||
func initializeVulnerabilityClient() vulnerability.Client {
|
||||
wire.Build(vulnerability.SuperSet)
|
||||
return vulnerability.Client{}
|
||||
36
internal/artifact/repository.go
Normal file
36
internal/artifact/repository.go
Normal file
@@ -0,0 +1,36 @@
|
||||
package artifact
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"github.com/urfave/cli/v2"
|
||||
"golang.org/x/xerrors"
|
||||
|
||||
"github.com/aquasecurity/fanal/cache"
|
||||
"github.com/aquasecurity/trivy/internal/artifact/config"
|
||||
"github.com/aquasecurity/trivy/pkg/scanner"
|
||||
)
|
||||
|
||||
func repositoryScanner(ctx context.Context, dir string, ac cache.ArtifactCache, lac cache.LocalArtifactCache, timeout time.Duration) (
|
||||
scanner.Scanner, func(), error) {
|
||||
s, cleanup, err := initializeRepositoryScanner(ctx, dir, ac, lac)
|
||||
if err != nil {
|
||||
return scanner.Scanner{}, func() {}, xerrors.Errorf("unable to initialize a filesystem scanner: %w", err)
|
||||
}
|
||||
return s, cleanup, nil
|
||||
}
|
||||
|
||||
func RepositoryRun(cliCtx *cli.Context) error {
|
||||
c, err := config.New(cliCtx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// initialize config
|
||||
if err = c.Init(false); err != nil {
|
||||
return xerrors.Errorf("failed to initialize options: %w", err)
|
||||
}
|
||||
|
||||
return run(c, repositoryScanner)
|
||||
}
|
||||
@@ -1,17 +1,17 @@
|
||||
package standalone
|
||||
package artifact
|
||||
|
||||
import (
|
||||
"context"
|
||||
l "log"
|
||||
"os"
|
||||
"time"
|
||||
|
||||
"github.com/urfave/cli/v2"
|
||||
"golang.org/x/xerrors"
|
||||
|
||||
"github.com/aquasecurity/fanal/cache"
|
||||
"github.com/aquasecurity/trivy-db/pkg/db"
|
||||
"github.com/aquasecurity/trivy/internal/artifact/config"
|
||||
"github.com/aquasecurity/trivy/internal/operation"
|
||||
"github.com/aquasecurity/trivy/internal/standalone/config"
|
||||
"github.com/aquasecurity/trivy/pkg/log"
|
||||
"github.com/aquasecurity/trivy/pkg/report"
|
||||
"github.com/aquasecurity/trivy/pkg/scanner"
|
||||
@@ -19,24 +19,14 @@ import (
|
||||
"github.com/aquasecurity/trivy/pkg/utils"
|
||||
)
|
||||
|
||||
func Run(cliCtx *cli.Context) error {
|
||||
c, err := config.New(cliCtx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return run(c)
|
||||
}
|
||||
type InitializeScanner func(context.Context, string, cache.ArtifactCache, cache.LocalArtifactCache, time.Duration) (
|
||||
scanner.Scanner, func(), error)
|
||||
|
||||
func run(c config.Config) (err error) {
|
||||
if err = log.InitLogger(c.Debug, c.Quiet); err != nil {
|
||||
func run(c config.Config, initializeScanner InitializeScanner) error {
|
||||
if err := log.InitLogger(c.Debug, c.Quiet); err != nil {
|
||||
l.Fatal(err)
|
||||
}
|
||||
|
||||
// initialize config
|
||||
if err = c.Init(); err != nil {
|
||||
return xerrors.Errorf("failed to initialize options: %w", err)
|
||||
}
|
||||
|
||||
// configure cache dir
|
||||
utils.SetCacheDir(c.CacheDir)
|
||||
cacheClient, err := cache.NewFSCache(c.CacheDir)
|
||||
@@ -70,32 +60,25 @@ func run(c config.Config) (err error) {
|
||||
}
|
||||
defer db.Close()
|
||||
|
||||
var scanner scanner.Scanner
|
||||
ctx := context.Background()
|
||||
|
||||
cleanup := func() {}
|
||||
target := c.Target
|
||||
if c.Input != "" {
|
||||
// scan tar file
|
||||
scanner, err = initializeArchiveScanner(ctx, c.Input, cacheClient, cacheClient, c.Timeout)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("unable to initialize the archive scanner: %w", err)
|
||||
}
|
||||
} else {
|
||||
// scan an image in Docker Engine or Docker Registry
|
||||
scanner, cleanup, err = initializeDockerScanner(ctx, c.ImageName, cacheClient, cacheClient, c.Timeout)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("unable to initialize the docker scanner: %w", err)
|
||||
}
|
||||
target = c.Input
|
||||
}
|
||||
|
||||
ctx := context.Background()
|
||||
scanner, cleanup, err := initializeScanner(ctx, target, cacheClient, cacheClient, c.Timeout)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("unable to initialize a scanner: %w", err)
|
||||
}
|
||||
defer cleanup()
|
||||
|
||||
scanOptions := types.ScanOptions{
|
||||
VulnType: c.VulnType,
|
||||
ScanRemovedPackages: c.ScanRemovedPkgs,
|
||||
ScanRemovedPackages: c.ScanRemovedPkgs, // this is valid only for image subcommand
|
||||
}
|
||||
log.Logger.Debugf("Vulnerability type: %s", scanOptions.VulnType)
|
||||
|
||||
results, err := scanner.ScanImage(scanOptions)
|
||||
results, err := scanner.ScanArtifact(ctx, scanOptions)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("error in image scan: %w", err)
|
||||
}
|
||||
96
internal/artifact/wire_gen.go
Normal file
96
internal/artifact/wire_gen.go
Normal file
@@ -0,0 +1,96 @@
|
||||
// Code generated by Wire. DO NOT EDIT.
|
||||
|
||||
//go:generate wire
|
||||
//+build !wireinject
|
||||
|
||||
package artifact
|
||||
|
||||
import (
|
||||
"context"
|
||||
"github.com/aquasecurity/fanal/applier"
|
||||
image2 "github.com/aquasecurity/fanal/artifact/image"
|
||||
local2 "github.com/aquasecurity/fanal/artifact/local"
|
||||
"github.com/aquasecurity/fanal/artifact/remote"
|
||||
"github.com/aquasecurity/fanal/cache"
|
||||
"github.com/aquasecurity/fanal/image"
|
||||
"github.com/aquasecurity/trivy-db/pkg/db"
|
||||
"github.com/aquasecurity/trivy/pkg/detector/library"
|
||||
"github.com/aquasecurity/trivy/pkg/detector/ospkg"
|
||||
"github.com/aquasecurity/trivy/pkg/scanner"
|
||||
"github.com/aquasecurity/trivy/pkg/scanner/local"
|
||||
"github.com/aquasecurity/trivy/pkg/types"
|
||||
"github.com/aquasecurity/trivy/pkg/vulnerability"
|
||||
"time"
|
||||
)
|
||||
|
||||
// Injectors from inject.go:
|
||||
|
||||
func initializeDockerScanner(ctx context.Context, imageName string, artifactCache cache.ArtifactCache, localArtifactCache cache.LocalArtifactCache, timeout time.Duration) (scanner.Scanner, func(), error) {
|
||||
applierApplier := applier.NewApplier(localArtifactCache)
|
||||
detector := ospkg.Detector{}
|
||||
driverFactory := library.DriverFactory{}
|
||||
libraryDetector := library.NewDetector(driverFactory)
|
||||
localScanner := local.NewScanner(applierApplier, detector, libraryDetector)
|
||||
dockerOption, err := types.GetDockerOption(timeout)
|
||||
if err != nil {
|
||||
return scanner.Scanner{}, nil, err
|
||||
}
|
||||
imageImage, cleanup, err := image.NewDockerImage(ctx, imageName, dockerOption)
|
||||
if err != nil {
|
||||
return scanner.Scanner{}, nil, err
|
||||
}
|
||||
artifact := image2.NewArtifact(imageImage, artifactCache)
|
||||
scannerScanner := scanner.NewScanner(localScanner, artifact)
|
||||
return scannerScanner, func() {
|
||||
cleanup()
|
||||
}, nil
|
||||
}
|
||||
|
||||
func initializeArchiveScanner(ctx context.Context, filePath string, artifactCache cache.ArtifactCache, localArtifactCache cache.LocalArtifactCache, timeout time.Duration) (scanner.Scanner, error) {
|
||||
applierApplier := applier.NewApplier(localArtifactCache)
|
||||
detector := ospkg.Detector{}
|
||||
driverFactory := library.DriverFactory{}
|
||||
libraryDetector := library.NewDetector(driverFactory)
|
||||
localScanner := local.NewScanner(applierApplier, detector, libraryDetector)
|
||||
imageImage, err := image.NewArchiveImage(filePath)
|
||||
if err != nil {
|
||||
return scanner.Scanner{}, err
|
||||
}
|
||||
artifact := image2.NewArtifact(imageImage, artifactCache)
|
||||
scannerScanner := scanner.NewScanner(localScanner, artifact)
|
||||
return scannerScanner, nil
|
||||
}
|
||||
|
||||
func initializeFilesystemScanner(ctx context.Context, dir string, artifactCache cache.ArtifactCache, localArtifactCache cache.LocalArtifactCache) (scanner.Scanner, func(), error) {
|
||||
applierApplier := applier.NewApplier(localArtifactCache)
|
||||
detector := ospkg.Detector{}
|
||||
driverFactory := library.DriverFactory{}
|
||||
libraryDetector := library.NewDetector(driverFactory)
|
||||
localScanner := local.NewScanner(applierApplier, detector, libraryDetector)
|
||||
artifact := local2.NewArtifact(dir, artifactCache)
|
||||
scannerScanner := scanner.NewScanner(localScanner, artifact)
|
||||
return scannerScanner, func() {
|
||||
}, nil
|
||||
}
|
||||
|
||||
func initializeRepositoryScanner(ctx context.Context, url string, artifactCache cache.ArtifactCache, localArtifactCache cache.LocalArtifactCache) (scanner.Scanner, func(), error) {
|
||||
applierApplier := applier.NewApplier(localArtifactCache)
|
||||
detector := ospkg.Detector{}
|
||||
driverFactory := library.DriverFactory{}
|
||||
libraryDetector := library.NewDetector(driverFactory)
|
||||
localScanner := local.NewScanner(applierApplier, detector, libraryDetector)
|
||||
artifact, cleanup, err := remote.NewArtifact(url, artifactCache)
|
||||
if err != nil {
|
||||
return scanner.Scanner{}, nil, err
|
||||
}
|
||||
scannerScanner := scanner.NewScanner(localScanner, artifact)
|
||||
return scannerScanner, func() {
|
||||
cleanup()
|
||||
}, nil
|
||||
}
|
||||
|
||||
func initializeVulnerabilityClient() vulnerability.Client {
|
||||
config := db.Config{}
|
||||
client := vulnerability.NewClient(config)
|
||||
return client
|
||||
}
|
||||
@@ -12,6 +12,7 @@ import (
|
||||
|
||||
type Config struct {
|
||||
config.GlobalConfig
|
||||
config.ArtifactConfig
|
||||
config.ImageConfig
|
||||
config.ReportConfig
|
||||
|
||||
@@ -31,14 +32,14 @@ func New(c *cli.Context) (Config, error) {
|
||||
}
|
||||
|
||||
return Config{
|
||||
GlobalConfig: gc,
|
||||
ImageConfig: config.NewImageConfig(c),
|
||||
ReportConfig: config.NewReportConfig(c),
|
||||
|
||||
RemoteAddr: c.String("remote"),
|
||||
token: c.String("token"),
|
||||
tokenHeader: c.String("token-header"),
|
||||
customHeaders: c.StringSlice("custom-headers"),
|
||||
GlobalConfig: gc,
|
||||
ArtifactConfig: config.NewArtifactConfig(c),
|
||||
ImageConfig: config.NewImageConfig(c),
|
||||
ReportConfig: config.NewReportConfig(c),
|
||||
RemoteAddr: c.String("remote"),
|
||||
token: c.String("token"),
|
||||
tokenHeader: c.String("token-header"),
|
||||
customHeaders: c.StringSlice("custom-headers"),
|
||||
}, nil
|
||||
}
|
||||
|
||||
@@ -59,6 +60,10 @@ func (c *Config) Init() (err error) {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := c.ArtifactConfig.Init(c.Context.Args(), c.Logger); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := c.ImageConfig.Init(c.Context.Args(), c.Logger); err != nil {
|
||||
cli.ShowAppHelp(c.Context)
|
||||
return err
|
||||
|
||||
@@ -39,8 +39,8 @@ func TestConfig_Init(t *testing.T) {
|
||||
GlobalConfig: config.GlobalConfig{
|
||||
Quiet: true,
|
||||
},
|
||||
ImageConfig: config.ImageConfig{
|
||||
ImageName: "alpine:3.10",
|
||||
ArtifactConfig: config.ArtifactConfig{
|
||||
Target: "alpine:3.10",
|
||||
},
|
||||
ReportConfig: config.ReportConfig{
|
||||
Severities: []dbTypes.Severity{dbTypes.SeverityCritical},
|
||||
@@ -59,8 +59,8 @@ func TestConfig_Init(t *testing.T) {
|
||||
Output: os.Stdout,
|
||||
VulnType: []string{"os", "library"},
|
||||
},
|
||||
ImageConfig: config.ImageConfig{
|
||||
ImageName: "alpine:3.11",
|
||||
ArtifactConfig: config.ArtifactConfig{
|
||||
Target: "alpine:3.11",
|
||||
},
|
||||
token: "secret",
|
||||
tokenHeader: "X-Trivy-Token",
|
||||
@@ -78,8 +78,8 @@ func TestConfig_Init(t *testing.T) {
|
||||
Output: os.Stdout,
|
||||
VulnType: []string{"os", "library"},
|
||||
},
|
||||
ImageConfig: config.ImageConfig{
|
||||
ImageName: "alpine:3.11",
|
||||
ArtifactConfig: config.ArtifactConfig{
|
||||
Target: "alpine:3.11",
|
||||
},
|
||||
customHeaders: []string{"foo:bar"},
|
||||
CustomHeaders: http.Header{
|
||||
@@ -96,8 +96,8 @@ func TestConfig_Init(t *testing.T) {
|
||||
Output: os.Stdout,
|
||||
VulnType: []string{"os", "library"},
|
||||
},
|
||||
ImageConfig: config.ImageConfig{
|
||||
ImageName: "alpine:3.11",
|
||||
ArtifactConfig: config.ArtifactConfig{
|
||||
Target: "alpine:3.11",
|
||||
},
|
||||
customHeaders: []string{"foobaz"},
|
||||
CustomHeaders: http.Header{},
|
||||
@@ -115,8 +115,8 @@ func TestConfig_Init(t *testing.T) {
|
||||
Output: os.Stdout,
|
||||
VulnType: []string{"os", "library"},
|
||||
},
|
||||
ImageConfig: config.ImageConfig{
|
||||
ImageName: "centos:7",
|
||||
ArtifactConfig: config.ArtifactConfig{
|
||||
Target: "centos:7",
|
||||
},
|
||||
CustomHeaders: http.Header{},
|
||||
},
|
||||
@@ -134,8 +134,8 @@ func TestConfig_Init(t *testing.T) {
|
||||
VulnType: []string{"os", "library"},
|
||||
Template: "@contrib/gitlab.tpl",
|
||||
},
|
||||
ImageConfig: config.ImageConfig{
|
||||
ImageName: "gitlab/gitlab-ce:12.7.2-ce.0",
|
||||
ArtifactConfig: config.ArtifactConfig{
|
||||
Target: "gitlab/gitlab-ce:12.7.2-ce.0",
|
||||
},
|
||||
CustomHeaders: http.Header{},
|
||||
},
|
||||
@@ -154,8 +154,8 @@ func TestConfig_Init(t *testing.T) {
|
||||
Template: "@contrib/gitlab.tpl",
|
||||
Format: "json",
|
||||
},
|
||||
ImageConfig: config.ImageConfig{
|
||||
ImageName: "gitlab/gitlab-ce:12.7.2-ce.0",
|
||||
ArtifactConfig: config.ArtifactConfig{
|
||||
Target: "gitlab/gitlab-ce:12.7.2-ce.0",
|
||||
},
|
||||
CustomHeaders: http.Header{},
|
||||
},
|
||||
@@ -173,8 +173,27 @@ func TestConfig_Init(t *testing.T) {
|
||||
VulnType: []string{"os", "library"},
|
||||
Format: "template",
|
||||
},
|
||||
ImageConfig: config.ImageConfig{
|
||||
ImageName: "gitlab/gitlab-ce:12.7.2-ce.0",
|
||||
ArtifactConfig: config.ArtifactConfig{
|
||||
Target: "gitlab/gitlab-ce:12.7.2-ce.0",
|
||||
},
|
||||
CustomHeaders: http.Header{},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "invalid option combination: --format template without --template",
|
||||
args: []string{"--format", "template", "--severity", "MEDIUM", "gitlab/gitlab-ce:12.7.2-ce.0"},
|
||||
logs: []string{
|
||||
"--format template is ignored because --template not is specified. Specify --template option when you use --format template.",
|
||||
},
|
||||
want: Config{
|
||||
ReportConfig: config.ReportConfig{
|
||||
Severities: []dbTypes.Severity{dbTypes.SeverityMedium},
|
||||
Output: os.Stdout,
|
||||
VulnType: []string{"os", "library"},
|
||||
Format: "template",
|
||||
},
|
||||
ArtifactConfig: config.ArtifactConfig{
|
||||
Target: "gitlab/gitlab-ce:12.7.2-ce.0",
|
||||
},
|
||||
CustomHeaders: http.Header{},
|
||||
},
|
||||
@@ -191,8 +210,8 @@ func TestConfig_Init(t *testing.T) {
|
||||
Output: os.Stdout,
|
||||
VulnType: []string{"os", "library"},
|
||||
},
|
||||
ImageConfig: config.ImageConfig{
|
||||
ImageName: "gcr.io/distroless/base",
|
||||
ArtifactConfig: config.ArtifactConfig{
|
||||
Target: "gcr.io/distroless/base",
|
||||
},
|
||||
CustomHeaders: http.Header{},
|
||||
},
|
||||
@@ -201,7 +220,7 @@ func TestConfig_Init(t *testing.T) {
|
||||
name: "sad: multiple image names",
|
||||
args: []string{"centos:7", "alpine:3.10"},
|
||||
logs: []string{
|
||||
"multiple images cannot be specified",
|
||||
"multiple targets cannot be specified",
|
||||
},
|
||||
wantErr: "arguments error",
|
||||
},
|
||||
@@ -234,11 +253,7 @@ func TestConfig_Init(t *testing.T) {
|
||||
set.String("format", "", "")
|
||||
set.String("token", "", "")
|
||||
set.String("token-header", "", "")
|
||||
//set.String("custom-headers", "", "")
|
||||
set.Var(&cli.StringSlice{}, "custom-headers", "")
|
||||
//cli.StringSliceFlag{
|
||||
// Name: "custom-headers",
|
||||
//}
|
||||
|
||||
ctx := cli.NewContext(app, set, nil)
|
||||
_ = set.Parse(tt.args)
|
||||
|
||||
@@ -13,13 +13,13 @@ import (
|
||||
"github.com/google/wire"
|
||||
)
|
||||
|
||||
func initializeDockerScanner(ctx context.Context, imageName string, layerCache cache.ImageCache, customHeaders client.CustomHeaders,
|
||||
func initializeDockerScanner(ctx context.Context, imageName string, artifactCache cache.ArtifactCache, customHeaders client.CustomHeaders,
|
||||
url client.RemoteURL, timeout time.Duration) (scanner.Scanner, func(), error) {
|
||||
wire.Build(scanner.RemoteDockerSet)
|
||||
return scanner.Scanner{}, nil, nil
|
||||
}
|
||||
|
||||
func initializeArchiveScanner(ctx context.Context, filePath string, layerCache cache.ImageCache, customHeaders client.CustomHeaders,
|
||||
func initializeArchiveScanner(ctx context.Context, filePath string, artifactCache cache.ArtifactCache, customHeaders client.CustomHeaders,
|
||||
url client.RemoteURL, timeout time.Duration) (scanner.Scanner, error) {
|
||||
wire.Build(scanner.RemoteArchiveSet)
|
||||
return scanner.Scanner{}, nil
|
||||
|
||||
@@ -58,7 +58,7 @@ func run(c config.Config) (err error) {
|
||||
}
|
||||
} else {
|
||||
// scan an image in Docker Engine or Docker Registry
|
||||
scanner, cleanup, err = initializeDockerScanner(ctx, c.ImageName, remoteCache,
|
||||
scanner, cleanup, err = initializeDockerScanner(ctx, c.Target, remoteCache,
|
||||
client.CustomHeaders(c.CustomHeaders), client.RemoteURL(c.RemoteAddr), c.Timeout)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("unable to initialize the docker scanner: %w", err)
|
||||
@@ -72,7 +72,7 @@ func run(c config.Config) (err error) {
|
||||
}
|
||||
log.Logger.Debugf("Vulnerability type: %s", scanOptions.VulnType)
|
||||
|
||||
results, err := scanner.ScanImage(scanOptions)
|
||||
results, err := scanner.ScanArtifact(ctx, scanOptions)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("error in image scan: %w", err)
|
||||
}
|
||||
|
||||
@@ -7,9 +7,9 @@ package client
|
||||
|
||||
import (
|
||||
"context"
|
||||
"github.com/aquasecurity/fanal/analyzer"
|
||||
image2 "github.com/aquasecurity/fanal/artifact/image"
|
||||
"github.com/aquasecurity/fanal/cache"
|
||||
"github.com/aquasecurity/fanal/extractor/docker"
|
||||
"github.com/aquasecurity/fanal/image"
|
||||
"github.com/aquasecurity/trivy-db/pkg/db"
|
||||
"github.com/aquasecurity/trivy/pkg/rpc/client"
|
||||
"github.com/aquasecurity/trivy/pkg/scanner"
|
||||
@@ -20,33 +20,33 @@ import (
|
||||
|
||||
// Injectors from inject.go:
|
||||
|
||||
func initializeDockerScanner(ctx context.Context, imageName string, layerCache cache.ImageCache, customHeaders client.CustomHeaders, url client.RemoteURL, timeout time.Duration) (scanner.Scanner, func(), error) {
|
||||
func initializeDockerScanner(ctx context.Context, imageName string, artifactCache cache.ArtifactCache, customHeaders client.CustomHeaders, url client.RemoteURL, timeout time.Duration) (scanner.Scanner, func(), error) {
|
||||
scannerScanner := client.NewProtobufClient(url)
|
||||
clientScanner := client.NewScanner(customHeaders, scannerScanner)
|
||||
dockerOption, err := types.GetDockerOption(timeout)
|
||||
if err != nil {
|
||||
return scanner.Scanner{}, nil, err
|
||||
}
|
||||
extractor, cleanup, err := docker.NewDockerExtractor(ctx, imageName, dockerOption)
|
||||
imageImage, cleanup, err := image.NewDockerImage(ctx, imageName, dockerOption)
|
||||
if err != nil {
|
||||
return scanner.Scanner{}, nil, err
|
||||
}
|
||||
config := analyzer.New(extractor, layerCache)
|
||||
scanner2 := scanner.NewScanner(clientScanner, config)
|
||||
artifact := image2.NewArtifact(imageImage, artifactCache)
|
||||
scanner2 := scanner.NewScanner(clientScanner, artifact)
|
||||
return scanner2, func() {
|
||||
cleanup()
|
||||
}, nil
|
||||
}
|
||||
|
||||
func initializeArchiveScanner(ctx context.Context, filePath string, layerCache cache.ImageCache, customHeaders client.CustomHeaders, url client.RemoteURL, timeout time.Duration) (scanner.Scanner, error) {
|
||||
func initializeArchiveScanner(ctx context.Context, filePath string, artifactCache cache.ArtifactCache, customHeaders client.CustomHeaders, url client.RemoteURL, timeout time.Duration) (scanner.Scanner, error) {
|
||||
scannerScanner := client.NewProtobufClient(url)
|
||||
clientScanner := client.NewScanner(customHeaders, scannerScanner)
|
||||
extractor, err := docker.NewArchiveImageExtractor(filePath)
|
||||
imageImage, err := image.NewArchiveImage(filePath)
|
||||
if err != nil {
|
||||
return scanner.Scanner{}, err
|
||||
}
|
||||
config := analyzer.New(extractor, layerCache)
|
||||
scanner2 := scanner.NewScanner(clientScanner, config)
|
||||
artifact := image2.NewArtifact(imageImage, artifactCache)
|
||||
scanner2 := scanner.NewScanner(clientScanner, artifact)
|
||||
return scanner2, nil
|
||||
}
|
||||
|
||||
|
||||
42
internal/config/artifact.go
Normal file
42
internal/config/artifact.go
Normal file
@@ -0,0 +1,42 @@
|
||||
package config
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/urfave/cli/v2"
|
||||
"go.uber.org/zap"
|
||||
"golang.org/x/xerrors"
|
||||
)
|
||||
|
||||
type ArtifactConfig struct {
|
||||
Input string
|
||||
Timeout time.Duration
|
||||
ClearCache bool
|
||||
|
||||
// this field is populated in Init()
|
||||
Target string
|
||||
}
|
||||
|
||||
func NewArtifactConfig(c *cli.Context) ArtifactConfig {
|
||||
return ArtifactConfig{
|
||||
Input: c.String("input"),
|
||||
Timeout: c.Duration("timeout"),
|
||||
ClearCache: c.Bool("clear-cache"),
|
||||
}
|
||||
}
|
||||
|
||||
func (c *ArtifactConfig) Init(args cli.Args, logger *zap.SugaredLogger) (err error) {
|
||||
if c.Input == "" && args.Len() == 0 {
|
||||
logger.Error(`trivy requires at least 1 argument or --input option`)
|
||||
return xerrors.New("arguments error")
|
||||
} else if args.Len() > 1 {
|
||||
logger.Error(`multiple targets cannot be specified`)
|
||||
return xerrors.New("arguments error")
|
||||
}
|
||||
|
||||
if c.Input == "" {
|
||||
c.Target = args.First()
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
80
internal/config/artifact_test.go
Normal file
80
internal/config/artifact_test.go
Normal file
@@ -0,0 +1,80 @@
|
||||
package config_test
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"testing"
|
||||
|
||||
"github.com/aquasecurity/trivy/internal/config"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
"github.com/urfave/cli/v2"
|
||||
"go.uber.org/zap"
|
||||
"go.uber.org/zap/zaptest/observer"
|
||||
)
|
||||
|
||||
func TestArtifactConfig_Init(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
args []string
|
||||
logs []string
|
||||
want config.ArtifactConfig
|
||||
wantErr string
|
||||
}{
|
||||
{
|
||||
name: "happy path",
|
||||
args: []string{"alpine:3.10"},
|
||||
want: config.ArtifactConfig{
|
||||
Target: "alpine:3.10",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "sad: multiple image names",
|
||||
args: []string{"centos:7", "alpine:3.10"},
|
||||
logs: []string{
|
||||
"multiple targets cannot be specified",
|
||||
},
|
||||
wantErr: "arguments error",
|
||||
},
|
||||
{
|
||||
name: "sad: no image name",
|
||||
logs: []string{
|
||||
"trivy requires at least 1 argument or --input option",
|
||||
},
|
||||
wantErr: "arguments error",
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
core, obs := observer.New(zap.InfoLevel)
|
||||
logger := zap.New(core)
|
||||
|
||||
app := cli.NewApp()
|
||||
set := flag.NewFlagSet("test", 0)
|
||||
ctx := cli.NewContext(app, set, nil)
|
||||
_ = set.Parse(tt.args)
|
||||
|
||||
c := config.NewArtifactConfig(ctx)
|
||||
|
||||
err := c.Init(ctx.Args(), logger.Sugar())
|
||||
|
||||
// tests log messages
|
||||
var gotMessages []string
|
||||
for _, entry := range obs.AllUntimed() {
|
||||
gotMessages = append(gotMessages, entry.Message)
|
||||
}
|
||||
assert.Equal(t, tt.logs, gotMessages, tt.name)
|
||||
|
||||
// test the error
|
||||
switch {
|
||||
case tt.wantErr != "":
|
||||
require.NotNil(t, err)
|
||||
assert.Contains(t, err.Error(), tt.wantErr, tt.name)
|
||||
return
|
||||
default:
|
||||
assert.NoError(t, err, tt.name)
|
||||
}
|
||||
|
||||
assert.Equal(t, tt.want, c, tt.name)
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -10,6 +10,7 @@ type DBConfig struct {
|
||||
DownloadDBOnly bool
|
||||
SkipUpdate bool
|
||||
Light bool
|
||||
NoProgress bool
|
||||
}
|
||||
|
||||
func NewDBConfig(c *cli.Context) DBConfig {
|
||||
@@ -18,6 +19,7 @@ func NewDBConfig(c *cli.Context) DBConfig {
|
||||
DownloadDBOnly: c.Bool("download-db-only"),
|
||||
SkipUpdate: c.Bool("skip-update"),
|
||||
Light: c.Bool("light"),
|
||||
NoProgress: c.Bool("no-progress"),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
package config
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/google/go-containerregistry/pkg/name"
|
||||
"github.com/urfave/cli/v2"
|
||||
"go.uber.org/zap"
|
||||
@@ -10,40 +8,21 @@ import (
|
||||
)
|
||||
|
||||
type ImageConfig struct {
|
||||
Input string
|
||||
ScanRemovedPkgs bool
|
||||
Timeout time.Duration
|
||||
ClearCache bool
|
||||
|
||||
// this field is populated in Init()
|
||||
ImageName string
|
||||
}
|
||||
|
||||
func NewImageConfig(c *cli.Context) ImageConfig {
|
||||
return ImageConfig{
|
||||
Input: c.String("input"),
|
||||
ScanRemovedPkgs: c.Bool("removed-pkgs"),
|
||||
Timeout: c.Duration("timeout"),
|
||||
ClearCache: c.Bool("clear-cache"),
|
||||
}
|
||||
}
|
||||
|
||||
func (c *ImageConfig) Init(args cli.Args, logger *zap.SugaredLogger) (err error) {
|
||||
if c.Input == "" && args.Len() == 0 {
|
||||
logger.Error(`trivy requires at least 1 argument or --input option`)
|
||||
return xerrors.New("arguments error")
|
||||
} else if args.Len() > 1 {
|
||||
logger.Error(`multiple images cannot be specified`)
|
||||
return xerrors.New("arguments error")
|
||||
}
|
||||
|
||||
if c.Input == "" {
|
||||
c.ImageName = args.First()
|
||||
}
|
||||
imageName := args.First()
|
||||
|
||||
// Check whether 'latest' tag is used
|
||||
if c.ImageName != "" {
|
||||
ref, err := name.ParseReference(c.ImageName)
|
||||
if imageName != "" {
|
||||
ref, err := name.ParseReference(imageName)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("invalid image: %w", err)
|
||||
}
|
||||
|
||||
@@ -13,51 +13,16 @@ import (
|
||||
"github.com/aquasecurity/trivy/internal/config"
|
||||
)
|
||||
|
||||
func TestNewImageConfig(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
args []string
|
||||
want config.ImageConfig
|
||||
}{
|
||||
{
|
||||
name: "happy path",
|
||||
args: []string{"--clear-cache", "--input", "/tmp/alpine.tar"},
|
||||
want: config.ImageConfig{
|
||||
Input: "/tmp/alpine.tar",
|
||||
ClearCache: true,
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
app := &cli.App{}
|
||||
set := flag.NewFlagSet("test", 0)
|
||||
set.Bool("clear-cache", false, "")
|
||||
set.String("input", "", "")
|
||||
|
||||
c := cli.NewContext(app, set, nil)
|
||||
_ = set.Parse(tt.args)
|
||||
|
||||
got := config.NewImageConfig(c)
|
||||
assert.Equal(t, tt.want, got, tt.name)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestImageConfig_Init(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
args []string
|
||||
logs []string
|
||||
want config.ImageConfig
|
||||
wantErr string
|
||||
}{
|
||||
{
|
||||
name: "happy path",
|
||||
args: []string{"alpine:3.10"},
|
||||
want: config.ImageConfig{
|
||||
ImageName: "alpine:3.10",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "with latest tag",
|
||||
@@ -65,24 +30,6 @@ func TestImageConfig_Init(t *testing.T) {
|
||||
logs: []string{
|
||||
"You should avoid using the :latest tag as it is cached. You need to specify '--clear-cache' option when :latest image is changed",
|
||||
},
|
||||
want: config.ImageConfig{
|
||||
ImageName: "gcr.io/distroless/base",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "sad: multiple image names",
|
||||
args: []string{"centos:7", "alpine:3.10"},
|
||||
logs: []string{
|
||||
"multiple images cannot be specified",
|
||||
},
|
||||
wantErr: "arguments error",
|
||||
},
|
||||
{
|
||||
name: "sad: no image name",
|
||||
logs: []string{
|
||||
"trivy requires at least 1 argument or --input option",
|
||||
},
|
||||
wantErr: "arguments error",
|
||||
},
|
||||
{
|
||||
name: "sad: invalid image name",
|
||||
@@ -100,7 +47,7 @@ func TestImageConfig_Init(t *testing.T) {
|
||||
ctx := cli.NewContext(app, set, nil)
|
||||
_ = set.Parse(tt.args)
|
||||
|
||||
c := &config.ImageConfig{}
|
||||
c := config.NewImageConfig(ctx)
|
||||
|
||||
err := c.Init(ctx.Args(), logger.Sugar())
|
||||
|
||||
@@ -120,8 +67,6 @@ func TestImageConfig_Init(t *testing.T) {
|
||||
default:
|
||||
assert.NoError(t, err, tt.name)
|
||||
}
|
||||
|
||||
assert.Equal(t, &tt.want, c, tt.name)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,15 +17,15 @@ import (
|
||||
|
||||
var SuperSet = wire.NewSet(
|
||||
cache.NewFSCache,
|
||||
wire.Bind(new(cache.LocalImageCache), new(cache.FSCache)),
|
||||
wire.Bind(new(cache.LocalArtifactCache), new(cache.FSCache)),
|
||||
NewCache,
|
||||
)
|
||||
|
||||
type Cache struct {
|
||||
client cache.LocalImageCache
|
||||
client cache.LocalArtifactCache
|
||||
}
|
||||
|
||||
func NewCache(client cache.LocalImageCache) Cache {
|
||||
func NewCache(client cache.LocalArtifactCache) Cache {
|
||||
return Cache{client: client}
|
||||
}
|
||||
|
||||
|
||||
@@ -28,6 +28,7 @@ func TestNew(t *testing.T) {
|
||||
DBConfig: config.DBConfig{
|
||||
Reset: true,
|
||||
SkipUpdate: true,
|
||||
NoProgress: true,
|
||||
},
|
||||
Listen: "localhost:8080",
|
||||
},
|
||||
|
||||
@@ -1,65 +0,0 @@
|
||||
// Code generated by Wire. DO NOT EDIT.
|
||||
|
||||
//go:generate wire
|
||||
//+build !wireinject
|
||||
|
||||
package standalone
|
||||
|
||||
import (
|
||||
"context"
|
||||
"github.com/aquasecurity/fanal/analyzer"
|
||||
"github.com/aquasecurity/fanal/cache"
|
||||
"github.com/aquasecurity/fanal/extractor/docker"
|
||||
"github.com/aquasecurity/trivy-db/pkg/db"
|
||||
"github.com/aquasecurity/trivy/pkg/detector/library"
|
||||
"github.com/aquasecurity/trivy/pkg/detector/ospkg"
|
||||
"github.com/aquasecurity/trivy/pkg/scanner"
|
||||
"github.com/aquasecurity/trivy/pkg/scanner/local"
|
||||
"github.com/aquasecurity/trivy/pkg/types"
|
||||
"github.com/aquasecurity/trivy/pkg/vulnerability"
|
||||
"time"
|
||||
)
|
||||
|
||||
// Injectors from inject.go:
|
||||
|
||||
func initializeDockerScanner(ctx context.Context, imageName string, layerCache cache.ImageCache, localImageCache cache.LocalImageCache, timeout time.Duration) (scanner.Scanner, func(), error) {
|
||||
applier := analyzer.NewApplier(localImageCache)
|
||||
detector := ospkg.Detector{}
|
||||
driverFactory := library.DriverFactory{}
|
||||
libraryDetector := library.NewDetector(driverFactory)
|
||||
localScanner := local.NewScanner(applier, detector, libraryDetector)
|
||||
dockerOption, err := types.GetDockerOption(timeout)
|
||||
if err != nil {
|
||||
return scanner.Scanner{}, nil, err
|
||||
}
|
||||
extractor, cleanup, err := docker.NewDockerExtractor(ctx, imageName, dockerOption)
|
||||
if err != nil {
|
||||
return scanner.Scanner{}, nil, err
|
||||
}
|
||||
config := analyzer.New(extractor, layerCache)
|
||||
scannerScanner := scanner.NewScanner(localScanner, config)
|
||||
return scannerScanner, func() {
|
||||
cleanup()
|
||||
}, nil
|
||||
}
|
||||
|
||||
func initializeArchiveScanner(ctx context.Context, filePath string, layerCache cache.ImageCache, localImageCache cache.LocalImageCache, timeout time.Duration) (scanner.Scanner, error) {
|
||||
applier := analyzer.NewApplier(localImageCache)
|
||||
detector := ospkg.Detector{}
|
||||
driverFactory := library.DriverFactory{}
|
||||
libraryDetector := library.NewDetector(driverFactory)
|
||||
localScanner := local.NewScanner(applier, detector, libraryDetector)
|
||||
extractor, err := docker.NewArchiveImageExtractor(filePath)
|
||||
if err != nil {
|
||||
return scanner.Scanner{}, err
|
||||
}
|
||||
config := analyzer.New(extractor, layerCache)
|
||||
scannerScanner := scanner.NewScanner(localScanner, config)
|
||||
return scannerScanner, nil
|
||||
}
|
||||
|
||||
func initializeVulnerabilityClient() vulnerability.Client {
|
||||
config := db.Config{}
|
||||
client := vulnerability.NewClient(config)
|
||||
return client
|
||||
}
|
||||
Reference in New Issue
Block a user