mirror of
https://github.com/aquasecurity/trivy.git
synced 2025-12-22 07:10:41 -08:00
refactor: use google/wire for cache (#7024)
Signed-off-by: knqyf263 <knqyf263@gmail.com>
This commit is contained in:
2
pkg/cache/cache.go
vendored
2
pkg/cache/cache.go
vendored
@@ -5,7 +5,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
cacheDirName = "fanal"
|
scanCacheDirName = "fanal"
|
||||||
|
|
||||||
// artifactBucket stores artifact information with artifact ID such as image ID
|
// artifactBucket stores artifact information with artifact ID such as image ID
|
||||||
artifactBucket = "artifact"
|
artifactBucket = "artifact"
|
||||||
|
|||||||
157
pkg/cache/client.go
vendored
157
pkg/cache/client.go
vendored
@@ -1,21 +1,14 @@
|
|||||||
package cache
|
package cache
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"crypto/tls"
|
|
||||||
"crypto/x509"
|
|
||||||
"fmt"
|
|
||||||
"os"
|
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/go-redis/redis/v8"
|
|
||||||
"github.com/samber/lo"
|
|
||||||
"golang.org/x/xerrors"
|
"golang.org/x/xerrors"
|
||||||
|
|
||||||
"github.com/aquasecurity/trivy/pkg/log"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
TypeUnknown Type = "unknown"
|
||||||
TypeFS Type = "fs"
|
TypeFS Type = "fs"
|
||||||
TypeRedis Type = "redis"
|
TypeRedis Type = "redis"
|
||||||
)
|
)
|
||||||
@@ -23,144 +16,50 @@ const (
|
|||||||
type Type string
|
type Type string
|
||||||
|
|
||||||
type Options struct {
|
type Options struct {
|
||||||
Type Type
|
|
||||||
TTL time.Duration
|
|
||||||
Redis RedisOptions
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewOptions(backend, redisCACert, redisCert, redisKey string, redisTLS bool, ttl time.Duration) (Options, error) {
|
|
||||||
t, err := NewType(backend)
|
|
||||||
if err != nil {
|
|
||||||
return Options{}, xerrors.Errorf("cache type error: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
var redisOpts RedisOptions
|
|
||||||
if t == TypeRedis {
|
|
||||||
redisTLSOpts, err := NewRedisTLSOptions(redisCACert, redisCert, redisKey)
|
|
||||||
if err != nil {
|
|
||||||
return Options{}, xerrors.Errorf("redis TLS option error: %w", err)
|
|
||||||
}
|
|
||||||
redisOpts = RedisOptions{
|
|
||||||
Backend: backend,
|
|
||||||
TLS: redisTLS,
|
|
||||||
TLSOptions: redisTLSOpts,
|
|
||||||
}
|
|
||||||
} else if ttl != 0 {
|
|
||||||
log.Warn("'--cache-ttl' is only available with Redis cache backend")
|
|
||||||
}
|
|
||||||
|
|
||||||
return Options{
|
|
||||||
Type: t,
|
|
||||||
TTL: ttl,
|
|
||||||
Redis: redisOpts,
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
type RedisOptions struct {
|
|
||||||
Backend string
|
Backend string
|
||||||
TLS bool
|
CacheDir string
|
||||||
TLSOptions RedisTLSOptions
|
RedisCACert string
|
||||||
|
RedisCert string
|
||||||
|
RedisKey string
|
||||||
|
RedisTLS bool
|
||||||
|
TTL time.Duration
|
||||||
}
|
}
|
||||||
|
|
||||||
// BackendMasked returns the redis connection string masking credentials
|
func NewType(backend string) Type {
|
||||||
func (o *RedisOptions) BackendMasked() string {
|
|
||||||
endIndex := strings.Index(o.Backend, "@")
|
|
||||||
if endIndex == -1 {
|
|
||||||
return o.Backend
|
|
||||||
}
|
|
||||||
|
|
||||||
startIndex := strings.Index(o.Backend, "//")
|
|
||||||
|
|
||||||
return fmt.Sprintf("%s****%s", o.Backend[:startIndex+2], o.Backend[endIndex:])
|
|
||||||
}
|
|
||||||
|
|
||||||
// RedisTLSOptions holds the options for redis cache
|
|
||||||
type RedisTLSOptions struct {
|
|
||||||
CACert string
|
|
||||||
Cert string
|
|
||||||
Key string
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewRedisTLSOptions(caCert, cert, key string) (RedisTLSOptions, error) {
|
|
||||||
opts := RedisTLSOptions{
|
|
||||||
CACert: caCert,
|
|
||||||
Cert: cert,
|
|
||||||
Key: key,
|
|
||||||
}
|
|
||||||
|
|
||||||
// If one of redis option not nil, make sure CA, cert, and key provided
|
|
||||||
if !lo.IsEmpty(opts) {
|
|
||||||
if opts.CACert == "" || opts.Cert == "" || opts.Key == "" {
|
|
||||||
return RedisTLSOptions{}, xerrors.Errorf("you must provide Redis CA, cert and key file path when using TLS")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return opts, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewType(backend string) (Type, error) {
|
|
||||||
// "redis://" or "fs" are allowed for now
|
// "redis://" or "fs" are allowed for now
|
||||||
// An empty value is also allowed for testability
|
// An empty value is also allowed for testability
|
||||||
switch {
|
switch {
|
||||||
case strings.HasPrefix(backend, "redis://"):
|
case strings.HasPrefix(backend, "redis://"):
|
||||||
return TypeRedis, nil
|
return TypeRedis
|
||||||
case backend == "fs", backend == "":
|
case backend == "fs", backend == "":
|
||||||
return TypeFS, nil
|
return TypeFS
|
||||||
default:
|
default:
|
||||||
return "", xerrors.Errorf("unknown cache backend: %s", backend)
|
return TypeUnknown
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// New returns a new cache client
|
// New returns a new cache client
|
||||||
func New(dir string, opts Options) (Cache, error) {
|
func New(opts Options) (Cache, func(), error) {
|
||||||
if opts.Type == TypeRedis {
|
cleanup := func() {} // To avoid panic
|
||||||
log.Info("Redis cache", log.String("url", opts.Redis.BackendMasked()))
|
|
||||||
options, err := redis.ParseURL(opts.Redis.Backend)
|
var cache Cache
|
||||||
|
t := NewType(opts.Backend)
|
||||||
|
switch t {
|
||||||
|
case TypeRedis:
|
||||||
|
redisCache, err := NewRedisCache(opts.Backend, opts.RedisCACert, opts.RedisCert, opts.RedisKey, opts.RedisTLS, opts.TTL)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, cleanup, xerrors.Errorf("unable to initialize redis cache: %w", err)
|
||||||
}
|
}
|
||||||
|
cache = redisCache
|
||||||
if tlsOpts := opts.Redis.TLSOptions; !lo.IsEmpty(tlsOpts) {
|
case TypeFS:
|
||||||
caCert, cert, err := GetTLSConfig(tlsOpts.CACert, tlsOpts.Cert, tlsOpts.Key)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
options.TLSConfig = &tls.Config{
|
|
||||||
RootCAs: caCert,
|
|
||||||
Certificates: []tls.Certificate{cert},
|
|
||||||
MinVersion: tls.VersionTLS12,
|
|
||||||
}
|
|
||||||
} else if opts.Redis.TLS {
|
|
||||||
options.TLSConfig = &tls.Config{
|
|
||||||
MinVersion: tls.VersionTLS12,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return NewRedisCache(options, opts.TTL), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// standalone mode
|
// standalone mode
|
||||||
fsCache, err := NewFSCache(dir)
|
fsCache, err := NewFSCache(opts.CacheDir)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, xerrors.Errorf("unable to initialize fs cache: %w", err)
|
return nil, cleanup, xerrors.Errorf("unable to initialize fs cache: %w", err)
|
||||||
}
|
}
|
||||||
return fsCache, nil
|
cache = fsCache
|
||||||
|
default:
|
||||||
|
return nil, cleanup, xerrors.Errorf("unknown cache type: %s", t)
|
||||||
}
|
}
|
||||||
|
return cache, func() { _ = cache.Close() }, nil
|
||||||
// GetTLSConfig gets tls config from CA, Cert and Key file
|
|
||||||
func GetTLSConfig(caCertPath, certPath, keyPath string) (*x509.CertPool, tls.Certificate, error) {
|
|
||||||
cert, err := tls.LoadX509KeyPair(certPath, keyPath)
|
|
||||||
if err != nil {
|
|
||||||
return nil, tls.Certificate{}, err
|
|
||||||
}
|
|
||||||
|
|
||||||
caCert, err := os.ReadFile(caCertPath)
|
|
||||||
if err != nil {
|
|
||||||
return nil, tls.Certificate{}, err
|
|
||||||
}
|
|
||||||
|
|
||||||
caCertPool := x509.NewCertPool()
|
|
||||||
caCertPool.AppendCertsFromPEM(caCert)
|
|
||||||
|
|
||||||
return caCertPool, cert, nil
|
|
||||||
}
|
}
|
||||||
|
|||||||
152
pkg/cache/client_test.go
vendored
152
pkg/cache/client_test.go
vendored
@@ -2,7 +2,6 @@ package cache_test
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
@@ -10,120 +9,113 @@ import (
|
|||||||
"github.com/aquasecurity/trivy/pkg/cache"
|
"github.com/aquasecurity/trivy/pkg/cache"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestNewOptions(t *testing.T) {
|
func TestNew(t *testing.T) {
|
||||||
type args struct {
|
|
||||||
backend string
|
|
||||||
redisCACert string
|
|
||||||
redisCert string
|
|
||||||
redisKey string
|
|
||||||
redisTLS bool
|
|
||||||
ttl time.Duration
|
|
||||||
}
|
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
name string
|
name string
|
||||||
args args
|
opts cache.Options
|
||||||
want cache.Options
|
wantType any
|
||||||
assertion require.ErrorAssertionFunc
|
wantErr string
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
name: "fs",
|
name: "fs backend",
|
||||||
args: args{backend: "fs"},
|
opts: cache.Options{
|
||||||
want: cache.Options{Type: cache.TypeFS},
|
Backend: "fs",
|
||||||
assertion: require.NoError,
|
CacheDir: "/tmp/cache",
|
||||||
|
},
|
||||||
|
wantType: cache.FSCache{},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "redis",
|
name: "redis backend",
|
||||||
args: args{backend: "redis://localhost:6379"},
|
opts: cache.Options{
|
||||||
want: cache.Options{
|
|
||||||
Type: cache.TypeRedis,
|
|
||||||
Redis: cache.RedisOptions{Backend: "redis://localhost:6379"},
|
|
||||||
},
|
|
||||||
assertion: require.NoError,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "redis tls",
|
|
||||||
args: args{
|
|
||||||
backend: "redis://localhost:6379",
|
|
||||||
redisCACert: "ca-cert.pem",
|
|
||||||
redisCert: "cert.pem",
|
|
||||||
redisKey: "key.pem",
|
|
||||||
},
|
|
||||||
want: cache.Options{
|
|
||||||
Type: cache.TypeRedis,
|
|
||||||
Redis: cache.RedisOptions{
|
|
||||||
Backend: "redis://localhost:6379",
|
Backend: "redis://localhost:6379",
|
||||||
TLSOptions: cache.RedisTLSOptions{
|
|
||||||
CACert: "ca-cert.pem",
|
|
||||||
Cert: "cert.pem",
|
|
||||||
Key: "key.pem",
|
|
||||||
},
|
},
|
||||||
},
|
wantType: cache.RedisCache{},
|
||||||
},
|
|
||||||
assertion: require.NoError,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "redis tls with public certificates",
|
|
||||||
args: args{
|
|
||||||
backend: "redis://localhost:6379",
|
|
||||||
redisTLS: true,
|
|
||||||
},
|
|
||||||
want: cache.Options{
|
|
||||||
Type: cache.TypeRedis,
|
|
||||||
Redis: cache.RedisOptions{
|
|
||||||
Backend: "redis://localhost:6379",
|
|
||||||
TLS: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
assertion: require.NoError,
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "unknown backend",
|
name: "unknown backend",
|
||||||
args: args{backend: "unknown"},
|
opts: cache.Options{
|
||||||
assertion: func(t require.TestingT, err error, msgs ...any) {
|
Backend: "unknown",
|
||||||
require.ErrorContains(t, err, "unknown cache backend")
|
|
||||||
},
|
},
|
||||||
|
wantErr: "unknown cache type",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "sad redis tls",
|
name: "invalid redis URL",
|
||||||
args: args{
|
opts: cache.Options{
|
||||||
backend: "redis://localhost:6379",
|
Backend: "redis://invalid-url:foo/bar",
|
||||||
redisCACert: "ca-cert.pem",
|
|
||||||
},
|
},
|
||||||
assertion: func(t require.TestingT, err error, msgs ...any) {
|
wantErr: "failed to parse Redis URL",
|
||||||
require.ErrorContains(t, err, "you must provide Redis CA, cert and key file path when using TLS")
|
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: "incomplete TLS options",
|
||||||
|
opts: cache.Options{
|
||||||
|
Backend: "redis://localhost:6379",
|
||||||
|
RedisCACert: "testdata/ca-cert.pem",
|
||||||
|
RedisTLS: true,
|
||||||
|
},
|
||||||
|
wantErr: "you must provide Redis CA, cert and key file path when using TLS",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "invalid TLS file paths",
|
||||||
|
opts: cache.Options{
|
||||||
|
Backend: "redis://localhost:6379",
|
||||||
|
RedisCACert: "testdata/non-existent-ca-cert.pem",
|
||||||
|
RedisCert: "testdata/non-existent-cert.pem",
|
||||||
|
RedisKey: "testdata/non-existent-key.pem",
|
||||||
|
RedisTLS: true,
|
||||||
|
},
|
||||||
|
wantErr: "failed to get TLS config",
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
got, err := cache.NewOptions(tt.args.backend, tt.args.redisCACert, tt.args.redisCert, tt.args.redisKey, tt.args.redisTLS, tt.args.ttl)
|
c, cleanup, err := cache.New(tt.opts)
|
||||||
tt.assertion(t, err)
|
defer cleanup()
|
||||||
assert.Equal(t, tt.want, got)
|
|
||||||
|
if tt.wantErr != "" {
|
||||||
|
assert.ErrorContains(t, err, tt.wantErr)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
require.NoError(t, err)
|
||||||
|
assert.NotNil(t, c)
|
||||||
|
assert.IsType(t, tt.wantType, c)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestRedisOptions_BackendMasked(t *testing.T) {
|
func TestNewType(t *testing.T) {
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
name string
|
name string
|
||||||
fields cache.RedisOptions
|
backend string
|
||||||
want string
|
wantType cache.Type
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
name: "redis cache backend masked",
|
name: "redis backend",
|
||||||
fields: cache.RedisOptions{Backend: "redis://root:password@localhost:6379"},
|
backend: "redis://localhost:6379",
|
||||||
want: "redis://****@localhost:6379",
|
wantType: cache.TypeRedis,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "redis cache backend masked does nothing",
|
name: "fs backend",
|
||||||
fields: cache.RedisOptions{Backend: "redis://localhost:6379"},
|
backend: "fs",
|
||||||
want: "redis://localhost:6379",
|
wantType: cache.TypeFS,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "empty backend",
|
||||||
|
backend: "",
|
||||||
|
wantType: cache.TypeFS,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "unknown backend",
|
||||||
|
backend: "unknown",
|
||||||
|
wantType: cache.TypeUnknown,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
assert.Equal(t, tt.want, tt.fields.BackendMasked())
|
got := cache.NewType(tt.backend)
|
||||||
|
assert.Equal(t, tt.wantType, got)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
7
pkg/cache/fs.go
vendored
7
pkg/cache/fs.go
vendored
@@ -20,7 +20,7 @@ type FSCache struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func NewFSCache(cacheDir string) (FSCache, error) {
|
func NewFSCache(cacheDir string) (FSCache, error) {
|
||||||
dir := filepath.Join(cacheDir, cacheDirName)
|
dir := filepath.Join(cacheDir, scanCacheDirName)
|
||||||
if err := os.MkdirAll(dir, 0700); err != nil {
|
if err := os.MkdirAll(dir, 0700); err != nil {
|
||||||
return FSCache{}, xerrors.Errorf("failed to create cache dir: %w", err)
|
return FSCache{}, xerrors.Errorf("failed to create cache dir: %w", err)
|
||||||
}
|
}
|
||||||
@@ -31,7 +31,10 @@ func NewFSCache(cacheDir string) (FSCache, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
err = db.Update(func(tx *bolt.Tx) error {
|
err = db.Update(func(tx *bolt.Tx) error {
|
||||||
for _, bucket := range []string{artifactBucket, blobBucket} {
|
for _, bucket := range []string{
|
||||||
|
artifactBucket,
|
||||||
|
blobBucket,
|
||||||
|
} {
|
||||||
if _, err := tx.CreateBucketIfNotExists([]byte(bucket)); err != nil {
|
if _, err := tx.CreateBucketIfNotExists([]byte(bucket)); err != nil {
|
||||||
return xerrors.Errorf("unable to create %s bucket: %w", bucket, err)
|
return xerrors.Errorf("unable to create %s bucket: %w", bucket, err)
|
||||||
}
|
}
|
||||||
|
|||||||
3
pkg/cache/fs_test.go
vendored
3
pkg/cache/fs_test.go
vendored
@@ -373,7 +373,7 @@ func TestFSCache_PutArtifact(t *testing.T) {
|
|||||||
require.NoError(t, err, tt.name)
|
require.NoError(t, err, tt.name)
|
||||||
}
|
}
|
||||||
|
|
||||||
fs.db.View(func(tx *bolt.Tx) error {
|
err = fs.db.View(func(tx *bolt.Tx) error {
|
||||||
// check decompressedDigestBucket
|
// check decompressedDigestBucket
|
||||||
imageBucket := tx.Bucket([]byte(artifactBucket))
|
imageBucket := tx.Bucket([]byte(artifactBucket))
|
||||||
b := imageBucket.Get([]byte(tt.args.imageID))
|
b := imageBucket.Get([]byte(tt.args.imageID))
|
||||||
@@ -381,6 +381,7 @@ func TestFSCache_PutArtifact(t *testing.T) {
|
|||||||
|
|
||||||
return nil
|
return nil
|
||||||
})
|
})
|
||||||
|
require.NoError(t, err)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
117
pkg/cache/redis.go
vendored
117
pkg/cache/redis.go
vendored
@@ -2,33 +2,118 @@ package cache
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"crypto/tls"
|
||||||
|
"crypto/x509"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/go-redis/redis/v8"
|
"github.com/go-redis/redis/v8"
|
||||||
"github.com/hashicorp/go-multierror"
|
"github.com/hashicorp/go-multierror"
|
||||||
|
"github.com/samber/lo"
|
||||||
"golang.org/x/xerrors"
|
"golang.org/x/xerrors"
|
||||||
|
|
||||||
"github.com/aquasecurity/trivy/pkg/fanal/types"
|
"github.com/aquasecurity/trivy/pkg/fanal/types"
|
||||||
|
"github.com/aquasecurity/trivy/pkg/log"
|
||||||
)
|
)
|
||||||
|
|
||||||
var _ Cache = &RedisCache{}
|
var _ Cache = (*RedisCache)(nil)
|
||||||
|
|
||||||
const (
|
const redisPrefix = "fanal"
|
||||||
redisPrefix = "fanal"
|
|
||||||
)
|
type RedisOptions struct {
|
||||||
|
Backend string
|
||||||
|
TLS bool
|
||||||
|
TLSOptions RedisTLSOptions
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewRedisOptions(backend, caCert, cert, key string, enableTLS bool) (RedisOptions, error) {
|
||||||
|
tlsOpts, err := NewRedisTLSOptions(caCert, cert, key)
|
||||||
|
if err != nil {
|
||||||
|
return RedisOptions{}, xerrors.Errorf("redis TLS option error: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return RedisOptions{
|
||||||
|
Backend: backend,
|
||||||
|
TLS: enableTLS,
|
||||||
|
TLSOptions: tlsOpts,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// BackendMasked returns the redis connection string masking credentials
|
||||||
|
func (o *RedisOptions) BackendMasked() string {
|
||||||
|
endIndex := strings.Index(o.Backend, "@")
|
||||||
|
if endIndex == -1 {
|
||||||
|
return o.Backend
|
||||||
|
}
|
||||||
|
|
||||||
|
startIndex := strings.Index(o.Backend, "//")
|
||||||
|
|
||||||
|
return fmt.Sprintf("%s****%s", o.Backend[:startIndex+2], o.Backend[endIndex:])
|
||||||
|
}
|
||||||
|
|
||||||
|
// RedisTLSOptions holds the options for redis cache
|
||||||
|
type RedisTLSOptions struct {
|
||||||
|
CACert string
|
||||||
|
Cert string
|
||||||
|
Key string
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewRedisTLSOptions(caCert, cert, key string) (RedisTLSOptions, error) {
|
||||||
|
opts := RedisTLSOptions{
|
||||||
|
CACert: caCert,
|
||||||
|
Cert: cert,
|
||||||
|
Key: key,
|
||||||
|
}
|
||||||
|
|
||||||
|
// If one of redis option not nil, make sure CA, cert, and key provided
|
||||||
|
if !lo.IsEmpty(opts) {
|
||||||
|
if opts.CACert == "" || opts.Cert == "" || opts.Key == "" {
|
||||||
|
return RedisTLSOptions{}, xerrors.Errorf("you must provide Redis CA, cert and key file path when using TLS")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return opts, nil
|
||||||
|
}
|
||||||
|
|
||||||
type RedisCache struct {
|
type RedisCache struct {
|
||||||
client *redis.Client
|
client *redis.Client
|
||||||
expiration time.Duration
|
expiration time.Duration
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewRedisCache(options *redis.Options, expiration time.Duration) RedisCache {
|
func NewRedisCache(backend, caCertPath, certPath, keyPath string, enableTLS bool, ttl time.Duration) (RedisCache, error) {
|
||||||
|
opts, err := NewRedisOptions(backend, caCertPath, certPath, keyPath, enableTLS)
|
||||||
|
if err != nil {
|
||||||
|
return RedisCache{}, xerrors.Errorf("failed to create Redis options: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Info("Redis scan cache", log.String("url", opts.BackendMasked()))
|
||||||
|
options, err := redis.ParseURL(opts.Backend)
|
||||||
|
if err != nil {
|
||||||
|
return RedisCache{}, xerrors.Errorf("failed to parse Redis URL: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if tlsOpts := opts.TLSOptions; !lo.IsEmpty(tlsOpts) {
|
||||||
|
caCert, cert, err := GetTLSConfig(tlsOpts.CACert, tlsOpts.Cert, tlsOpts.Key)
|
||||||
|
if err != nil {
|
||||||
|
return RedisCache{}, xerrors.Errorf("failed to get TLS config: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
options.TLSConfig = &tls.Config{
|
||||||
|
RootCAs: caCert,
|
||||||
|
Certificates: []tls.Certificate{cert},
|
||||||
|
MinVersion: tls.VersionTLS12,
|
||||||
|
}
|
||||||
|
} else if opts.TLS {
|
||||||
|
options.TLSConfig = &tls.Config{
|
||||||
|
MinVersion: tls.VersionTLS12,
|
||||||
|
}
|
||||||
|
}
|
||||||
return RedisCache{
|
return RedisCache{
|
||||||
client: redis.NewClient(options),
|
client: redis.NewClient(options),
|
||||||
expiration: expiration,
|
expiration: ttl,
|
||||||
}
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c RedisCache) PutArtifact(artifactID string, artifactConfig types.ArtifactInfo) error {
|
func (c RedisCache) PutArtifact(artifactID string, artifactConfig types.ArtifactInfo) error {
|
||||||
@@ -145,3 +230,21 @@ func (c RedisCache) Clear() error {
|
|||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetTLSConfig gets tls config from CA, Cert and Key file
|
||||||
|
func GetTLSConfig(caCertPath, certPath, keyPath string) (*x509.CertPool, tls.Certificate, error) {
|
||||||
|
cert, err := tls.LoadX509KeyPair(certPath, keyPath)
|
||||||
|
if err != nil {
|
||||||
|
return nil, tls.Certificate{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
caCert, err := os.ReadFile(caCertPath)
|
||||||
|
if err != nil {
|
||||||
|
return nil, tls.Certificate{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
caCertPool := x509.NewCertPool()
|
||||||
|
caCertPool.AppendCertsFromPEM(caCert)
|
||||||
|
|
||||||
|
return caCertPool, cert, nil
|
||||||
|
}
|
||||||
|
|||||||
91
pkg/cache/redis_test.go
vendored
91
pkg/cache/redis_test.go
vendored
@@ -7,7 +7,6 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/alicebob/miniredis/v2"
|
"github.com/alicebob/miniredis/v2"
|
||||||
"github.com/go-redis/redis/v8"
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
|
|
||||||
@@ -67,18 +66,15 @@ func TestRedisCache_PutArtifact(t *testing.T) {
|
|||||||
addr = "dummy:16379"
|
addr = "dummy:16379"
|
||||||
}
|
}
|
||||||
|
|
||||||
c := cache.NewRedisCache(&redis.Options{
|
c, err := cache.NewRedisCache(fmt.Sprintf("redis://%s", addr), "", "", "", false, 0)
|
||||||
Addr: addr,
|
require.NoError(t, err)
|
||||||
}, 0)
|
|
||||||
|
|
||||||
err = c.PutArtifact(tt.args.artifactID, tt.args.artifactConfig)
|
err = c.PutArtifact(tt.args.artifactID, tt.args.artifactConfig)
|
||||||
if tt.wantErr != "" {
|
if tt.wantErr != "" {
|
||||||
require.Error(t, err)
|
require.ErrorContains(t, err, tt.wantErr)
|
||||||
assert.Contains(t, err.Error(), tt.wantErr)
|
|
||||||
return
|
return
|
||||||
} else {
|
|
||||||
require.NoError(t, err)
|
|
||||||
}
|
}
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
got, err := s.Get(tt.wantKey)
|
got, err := s.Get(tt.wantKey)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
@@ -156,18 +152,15 @@ func TestRedisCache_PutBlob(t *testing.T) {
|
|||||||
addr = "dummy:16379"
|
addr = "dummy:16379"
|
||||||
}
|
}
|
||||||
|
|
||||||
c := cache.NewRedisCache(&redis.Options{
|
c, err := cache.NewRedisCache(fmt.Sprintf("redis://%s", addr), "", "", "", false, 0)
|
||||||
Addr: addr,
|
require.NoError(t, err)
|
||||||
}, 0)
|
|
||||||
|
|
||||||
err = c.PutBlob(tt.args.blobID, tt.args.blobConfig)
|
err = c.PutBlob(tt.args.blobID, tt.args.blobConfig)
|
||||||
if tt.wantErr != "" {
|
if tt.wantErr != "" {
|
||||||
require.Error(t, err)
|
require.ErrorContains(t, err, tt.wantErr)
|
||||||
assert.Contains(t, err.Error(), tt.wantErr)
|
|
||||||
return
|
return
|
||||||
} else {
|
|
||||||
require.NoError(t, err)
|
|
||||||
}
|
}
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
got, err := s.Get(tt.wantKey)
|
got, err := s.Get(tt.wantKey)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
@@ -241,18 +234,15 @@ func TestRedisCache_GetArtifact(t *testing.T) {
|
|||||||
addr = "dummy:16379"
|
addr = "dummy:16379"
|
||||||
}
|
}
|
||||||
|
|
||||||
c := cache.NewRedisCache(&redis.Options{
|
c, err := cache.NewRedisCache(fmt.Sprintf("redis://%s", addr), "", "", "", false, 0)
|
||||||
Addr: addr,
|
require.NoError(t, err)
|
||||||
}, 0)
|
|
||||||
|
|
||||||
got, err := c.GetArtifact(tt.artifactID)
|
got, err := c.GetArtifact(tt.artifactID)
|
||||||
if tt.wantErr != "" {
|
if tt.wantErr != "" {
|
||||||
require.Error(t, err)
|
require.ErrorContains(t, err, tt.wantErr)
|
||||||
assert.Contains(t, err.Error(), tt.wantErr)
|
|
||||||
return
|
return
|
||||||
} else {
|
|
||||||
require.NoError(t, err)
|
|
||||||
}
|
}
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
assert.Equal(t, tt.want, got)
|
assert.Equal(t, tt.want, got)
|
||||||
})
|
})
|
||||||
@@ -334,14 +324,12 @@ func TestRedisCache_GetBlob(t *testing.T) {
|
|||||||
addr = "dummy:16379"
|
addr = "dummy:16379"
|
||||||
}
|
}
|
||||||
|
|
||||||
c := cache.NewRedisCache(&redis.Options{
|
c, err := cache.NewRedisCache(fmt.Sprintf("redis://%s", addr), "", "", "", false, 0)
|
||||||
Addr: addr,
|
require.NoError(t, err)
|
||||||
}, 0)
|
|
||||||
|
|
||||||
got, err := c.GetBlob(tt.blobID)
|
got, err := c.GetBlob(tt.blobID)
|
||||||
if tt.wantErr != "" {
|
if tt.wantErr != "" {
|
||||||
require.Error(t, err)
|
require.ErrorContains(t, err, tt.wantErr)
|
||||||
assert.Contains(t, err.Error(), tt.wantErr)
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -445,14 +433,12 @@ func TestRedisCache_MissingBlobs(t *testing.T) {
|
|||||||
addr = "dummy:6379"
|
addr = "dummy:6379"
|
||||||
}
|
}
|
||||||
|
|
||||||
c := cache.NewRedisCache(&redis.Options{
|
c, err := cache.NewRedisCache(fmt.Sprintf("redis://%s", addr), "", "", "", false, 0)
|
||||||
Addr: addr,
|
require.NoError(t, err)
|
||||||
}, 0)
|
|
||||||
|
|
||||||
missingArtifact, missingBlobIDs, err := c.MissingBlobs(tt.args.artifactID, tt.args.blobIDs)
|
missingArtifact, missingBlobIDs, err := c.MissingBlobs(tt.args.artifactID, tt.args.blobIDs)
|
||||||
if tt.wantErr != "" {
|
if tt.wantErr != "" {
|
||||||
require.Error(t, err)
|
require.ErrorContains(t, err, tt.wantErr)
|
||||||
assert.Contains(t, err.Error(), tt.wantErr)
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -470,9 +456,9 @@ func TestRedisCache_Close(t *testing.T) {
|
|||||||
defer s.Close()
|
defer s.Close()
|
||||||
|
|
||||||
t.Run("close", func(t *testing.T) {
|
t.Run("close", func(t *testing.T) {
|
||||||
c := cache.NewRedisCache(&redis.Options{
|
c, err := cache.NewRedisCache(fmt.Sprintf("redis://%s", s.Addr()), "", "", "", false, 0)
|
||||||
Addr: s.Addr(),
|
require.NoError(t, err)
|
||||||
}, 0)
|
|
||||||
closeErr := c.Close()
|
closeErr := c.Close()
|
||||||
require.NoError(t, closeErr)
|
require.NoError(t, closeErr)
|
||||||
time.Sleep(3 * time.Second) // give it some time
|
time.Sleep(3 * time.Second) // give it some time
|
||||||
@@ -492,9 +478,9 @@ func TestRedisCache_Clear(t *testing.T) {
|
|||||||
s.Set("foo", "bar")
|
s.Set("foo", "bar")
|
||||||
|
|
||||||
t.Run("clear", func(t *testing.T) {
|
t.Run("clear", func(t *testing.T) {
|
||||||
c := cache.NewRedisCache(&redis.Options{
|
c, err := cache.NewRedisCache(fmt.Sprintf("redis://%s", s.Addr()), "", "", "", false, 0)
|
||||||
Addr: s.Addr(),
|
require.NoError(t, err)
|
||||||
}, 0)
|
|
||||||
require.NoError(t, c.Clear())
|
require.NoError(t, c.Clear())
|
||||||
for i := 0; i < 200; i++ {
|
for i := 0; i < 200; i++ {
|
||||||
assert.False(t, s.Exists(fmt.Sprintf("fanal::key%d", i)))
|
assert.False(t, s.Exists(fmt.Sprintf("fanal::key%d", i)))
|
||||||
@@ -546,9 +532,8 @@ func TestRedisCache_DeleteBlobs(t *testing.T) {
|
|||||||
addr = "dummy:16379"
|
addr = "dummy:16379"
|
||||||
}
|
}
|
||||||
|
|
||||||
c := cache.NewRedisCache(&redis.Options{
|
c, err := cache.NewRedisCache(fmt.Sprintf("redis://%s", addr), "", "", "", false, 0)
|
||||||
Addr: addr,
|
require.NoError(t, err)
|
||||||
}, 0)
|
|
||||||
|
|
||||||
err = c.DeleteBlobs(tt.args.blobIDs)
|
err = c.DeleteBlobs(tt.args.blobIDs)
|
||||||
if tt.wantErr != "" {
|
if tt.wantErr != "" {
|
||||||
@@ -560,3 +545,27 @@ func TestRedisCache_DeleteBlobs(t *testing.T) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestRedisOptions_BackendMasked(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
fields cache.RedisOptions
|
||||||
|
want string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "redis cache backend masked",
|
||||||
|
fields: cache.RedisOptions{Backend: "redis://root:password@localhost:6379"},
|
||||||
|
want: "redis://****@localhost:6379",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "redis cache backend masked does nothing",
|
||||||
|
fields: cache.RedisOptions{Backend: "redis://localhost:6379"},
|
||||||
|
want: "redis://localhost:6379",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
assert.Equal(t, tt.want, tt.fields.BackendMasked())
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
16
pkg/cache/remote.go
vendored
16
pkg/cache/remote.go
vendored
@@ -13,6 +13,14 @@ import (
|
|||||||
rpcCache "github.com/aquasecurity/trivy/rpc/cache"
|
rpcCache "github.com/aquasecurity/trivy/rpc/cache"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var _ ArtifactCache = (*RemoteCache)(nil)
|
||||||
|
|
||||||
|
type RemoteOptions struct {
|
||||||
|
ServerAddr string
|
||||||
|
CustomHeaders http.Header
|
||||||
|
Insecure bool
|
||||||
|
}
|
||||||
|
|
||||||
// RemoteCache implements remote cache
|
// RemoteCache implements remote cache
|
||||||
type RemoteCache struct {
|
type RemoteCache struct {
|
||||||
ctx context.Context // for custom header
|
ctx context.Context // for custom header
|
||||||
@@ -20,18 +28,18 @@ type RemoteCache struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// NewRemoteCache is the factory method for RemoteCache
|
// NewRemoteCache is the factory method for RemoteCache
|
||||||
func NewRemoteCache(url string, customHeaders http.Header, insecure bool) ArtifactCache {
|
func NewRemoteCache(opts RemoteOptions) *RemoteCache {
|
||||||
ctx := client.WithCustomHeaders(context.Background(), customHeaders)
|
ctx := client.WithCustomHeaders(context.Background(), opts.CustomHeaders)
|
||||||
|
|
||||||
httpClient := &http.Client{
|
httpClient := &http.Client{
|
||||||
Transport: &http.Transport{
|
Transport: &http.Transport{
|
||||||
Proxy: http.ProxyFromEnvironment,
|
Proxy: http.ProxyFromEnvironment,
|
||||||
TLSClientConfig: &tls.Config{
|
TLSClientConfig: &tls.Config{
|
||||||
InsecureSkipVerify: insecure,
|
InsecureSkipVerify: opts.Insecure,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
c := rpcCache.NewCacheProtobufClient(url, httpClient)
|
c := rpcCache.NewCacheProtobufClient(opts.ServerAddr, httpClient)
|
||||||
return &RemoteCache{
|
return &RemoteCache{
|
||||||
ctx: ctx,
|
ctx: ctx,
|
||||||
client: c,
|
client: c,
|
||||||
|
|||||||
24
pkg/cache/remote_test.go
vendored
24
pkg/cache/remote_test.go
vendored
@@ -145,7 +145,11 @@ func TestRemoteCache_PutArtifact(t *testing.T) {
|
|||||||
}
|
}
|
||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
c := cache.NewRemoteCache(ts.URL, tt.args.customHeaders, false)
|
c := cache.NewRemoteCache(cache.RemoteOptions{
|
||||||
|
ServerAddr: ts.URL,
|
||||||
|
CustomHeaders: tt.args.customHeaders,
|
||||||
|
Insecure: false,
|
||||||
|
})
|
||||||
err := c.PutArtifact(tt.args.imageID, tt.args.imageInfo)
|
err := c.PutArtifact(tt.args.imageID, tt.args.imageInfo)
|
||||||
if tt.wantErr != "" {
|
if tt.wantErr != "" {
|
||||||
require.Error(t, err, tt.name)
|
require.Error(t, err, tt.name)
|
||||||
@@ -206,7 +210,11 @@ func TestRemoteCache_PutBlob(t *testing.T) {
|
|||||||
}
|
}
|
||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
c := cache.NewRemoteCache(ts.URL, tt.args.customHeaders, false)
|
c := cache.NewRemoteCache(cache.RemoteOptions{
|
||||||
|
ServerAddr: ts.URL,
|
||||||
|
CustomHeaders: tt.args.customHeaders,
|
||||||
|
Insecure: false,
|
||||||
|
})
|
||||||
err := c.PutBlob(tt.args.diffID, tt.args.layerInfo)
|
err := c.PutBlob(tt.args.diffID, tt.args.layerInfo)
|
||||||
if tt.wantErr != "" {
|
if tt.wantErr != "" {
|
||||||
require.Error(t, err, tt.name)
|
require.Error(t, err, tt.name)
|
||||||
@@ -284,7 +292,11 @@ func TestRemoteCache_MissingBlobs(t *testing.T) {
|
|||||||
}
|
}
|
||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
c := cache.NewRemoteCache(ts.URL, tt.args.customHeaders, false)
|
c := cache.NewRemoteCache(cache.RemoteOptions{
|
||||||
|
ServerAddr: ts.URL,
|
||||||
|
CustomHeaders: tt.args.customHeaders,
|
||||||
|
Insecure: false,
|
||||||
|
})
|
||||||
gotMissingImage, gotMissingLayerIDs, err := c.MissingBlobs(tt.args.imageID, tt.args.layerIDs)
|
gotMissingImage, gotMissingLayerIDs, err := c.MissingBlobs(tt.args.imageID, tt.args.layerIDs)
|
||||||
if tt.wantErr != "" {
|
if tt.wantErr != "" {
|
||||||
require.Error(t, err, tt.name)
|
require.Error(t, err, tt.name)
|
||||||
@@ -334,7 +346,11 @@ func TestRemoteCache_PutArtifactInsecure(t *testing.T) {
|
|||||||
}
|
}
|
||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
c := cache.NewRemoteCache(ts.URL, nil, tt.args.insecure)
|
c := cache.NewRemoteCache(cache.RemoteOptions{
|
||||||
|
ServerAddr: ts.URL,
|
||||||
|
CustomHeaders: nil,
|
||||||
|
Insecure: tt.args.insecure,
|
||||||
|
})
|
||||||
err := c.PutArtifact(tt.args.imageID, tt.args.imageInfo)
|
err := c.PutArtifact(tt.args.imageID, tt.args.imageInfo)
|
||||||
if tt.wantErr != "" {
|
if tt.wantErr != "" {
|
||||||
require.Error(t, err)
|
require.Error(t, err)
|
||||||
|
|||||||
@@ -21,8 +21,7 @@ import (
|
|||||||
|
|
||||||
// initializeImageScanner is for container image scanning in standalone mode
|
// initializeImageScanner is for container image scanning in standalone mode
|
||||||
// e.g. dockerd, container registry, podman, etc.
|
// e.g. dockerd, container registry, podman, etc.
|
||||||
func initializeImageScanner(ctx context.Context, imageName string, artifactCache cache.ArtifactCache,
|
func initializeImageScanner(ctx context.Context, imageName string, imageOpt types.ImageOptions, cacheOptions cache.Options, artifactOption artifact.Option) (
|
||||||
localArtifactCache cache.LocalArtifactCache, imageOpt types.ImageOptions, artifactOption artifact.Option) (
|
|
||||||
scanner.Scanner, func(), error) {
|
scanner.Scanner, func(), error) {
|
||||||
wire.Build(scanner.StandaloneDockerSet)
|
wire.Build(scanner.StandaloneDockerSet)
|
||||||
return scanner.Scanner{}, nil, nil
|
return scanner.Scanner{}, nil, nil
|
||||||
@@ -30,33 +29,29 @@ func initializeImageScanner(ctx context.Context, imageName string, artifactCache
|
|||||||
|
|
||||||
// initializeArchiveScanner is for container image archive scanning in standalone mode
|
// initializeArchiveScanner is for container image archive scanning in standalone mode
|
||||||
// e.g. docker save -o alpine.tar alpine:3.15
|
// e.g. docker save -o alpine.tar alpine:3.15
|
||||||
func initializeArchiveScanner(ctx context.Context, filePath string, artifactCache cache.ArtifactCache,
|
func initializeArchiveScanner(ctx context.Context, filePath string, cacheOptions cache.Options, artifactOption artifact.Option) (
|
||||||
localArtifactCache cache.LocalArtifactCache, artifactOption artifact.Option) (scanner.Scanner, error) {
|
scanner.Scanner, func(), error) {
|
||||||
wire.Build(scanner.StandaloneArchiveSet)
|
wire.Build(scanner.StandaloneArchiveSet)
|
||||||
return scanner.Scanner{}, nil
|
return scanner.Scanner{}, nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// initializeFilesystemScanner is for filesystem scanning in standalone mode
|
// initializeFilesystemScanner is for filesystem scanning in standalone mode
|
||||||
func initializeFilesystemScanner(ctx context.Context, path string, artifactCache cache.ArtifactCache,
|
func initializeFilesystemScanner(ctx context.Context, path string, cacheOptions cache.Options, artifactOption artifact.Option) (scanner.Scanner, func(), error) {
|
||||||
localArtifactCache cache.LocalArtifactCache, artifactOption artifact.Option) (scanner.Scanner, func(), error) {
|
|
||||||
wire.Build(scanner.StandaloneFilesystemSet)
|
wire.Build(scanner.StandaloneFilesystemSet)
|
||||||
return scanner.Scanner{}, nil, nil
|
return scanner.Scanner{}, nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func initializeRepositoryScanner(ctx context.Context, url string, artifactCache cache.ArtifactCache,
|
func initializeRepositoryScanner(ctx context.Context, url string, cacheOptions cache.Options, artifactOption artifact.Option) (scanner.Scanner, func(), error) {
|
||||||
localArtifactCache cache.LocalArtifactCache, artifactOption artifact.Option) (scanner.Scanner, func(), error) {
|
|
||||||
wire.Build(scanner.StandaloneRepositorySet)
|
wire.Build(scanner.StandaloneRepositorySet)
|
||||||
return scanner.Scanner{}, nil, nil
|
return scanner.Scanner{}, nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func initializeSBOMScanner(ctx context.Context, filePath string, artifactCache cache.ArtifactCache,
|
func initializeSBOMScanner(ctx context.Context, filePath string, cacheOptions cache.Options, artifactOption artifact.Option) (scanner.Scanner, func(), error) {
|
||||||
localArtifactCache cache.LocalArtifactCache, artifactOption artifact.Option) (scanner.Scanner, func(), error) {
|
|
||||||
wire.Build(scanner.StandaloneSBOMSet)
|
wire.Build(scanner.StandaloneSBOMSet)
|
||||||
return scanner.Scanner{}, nil, nil
|
return scanner.Scanner{}, nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func initializeVMScanner(ctx context.Context, filePath string, artifactCache cache.ArtifactCache,
|
func initializeVMScanner(ctx context.Context, filePath string, cacheOptions cache.Options, artifactOption artifact.Option) (
|
||||||
localArtifactCache cache.LocalArtifactCache, artifactOption artifact.Option) (
|
|
||||||
scanner.Scanner, func(), error) {
|
scanner.Scanner, func(), error) {
|
||||||
wire.Build(scanner.StandaloneVMSet)
|
wire.Build(scanner.StandaloneVMSet)
|
||||||
return scanner.Scanner{}, nil, nil
|
return scanner.Scanner{}, nil, nil
|
||||||
@@ -68,7 +63,7 @@ func initializeVMScanner(ctx context.Context, filePath string, artifactCache cac
|
|||||||
|
|
||||||
// initializeRemoteImageScanner is for container image scanning in client/server mode
|
// initializeRemoteImageScanner is for container image scanning in client/server mode
|
||||||
// e.g. dockerd, container registry, podman, etc.
|
// e.g. dockerd, container registry, podman, etc.
|
||||||
func initializeRemoteImageScanner(ctx context.Context, imageName string, artifactCache cache.ArtifactCache,
|
func initializeRemoteImageScanner(ctx context.Context, imageName string, remoteCacheOptions cache.RemoteOptions,
|
||||||
remoteScanOptions client.ScannerOption, imageOpt types.ImageOptions, artifactOption artifact.Option) (
|
remoteScanOptions client.ScannerOption, imageOpt types.ImageOptions, artifactOption artifact.Option) (
|
||||||
scanner.Scanner, func(), error) {
|
scanner.Scanner, func(), error) {
|
||||||
wire.Build(scanner.RemoteDockerSet)
|
wire.Build(scanner.RemoteDockerSet)
|
||||||
@@ -77,21 +72,21 @@ func initializeRemoteImageScanner(ctx context.Context, imageName string, artifac
|
|||||||
|
|
||||||
// initializeRemoteArchiveScanner is for container image archive scanning in client/server mode
|
// initializeRemoteArchiveScanner is for container image archive scanning in client/server mode
|
||||||
// e.g. docker save -o alpine.tar alpine:3.15
|
// e.g. docker save -o alpine.tar alpine:3.15
|
||||||
func initializeRemoteArchiveScanner(ctx context.Context, filePath string, artifactCache cache.ArtifactCache,
|
func initializeRemoteArchiveScanner(ctx context.Context, filePath string, remoteCacheOptions cache.RemoteOptions,
|
||||||
remoteScanOptions client.ScannerOption, artifactOption artifact.Option) (scanner.Scanner, error) {
|
remoteScanOptions client.ScannerOption, artifactOption artifact.Option) (scanner.Scanner, func(), error) {
|
||||||
wire.Build(scanner.RemoteArchiveSet)
|
wire.Build(scanner.RemoteArchiveSet)
|
||||||
return scanner.Scanner{}, nil
|
return scanner.Scanner{}, nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// initializeRemoteFilesystemScanner is for filesystem scanning in client/server mode
|
// initializeRemoteFilesystemScanner is for filesystem scanning in client/server mode
|
||||||
func initializeRemoteFilesystemScanner(ctx context.Context, path string, artifactCache cache.ArtifactCache,
|
func initializeRemoteFilesystemScanner(ctx context.Context, path string, remoteCacheOptions cache.RemoteOptions,
|
||||||
remoteScanOptions client.ScannerOption, artifactOption artifact.Option) (scanner.Scanner, func(), error) {
|
remoteScanOptions client.ScannerOption, artifactOption artifact.Option) (scanner.Scanner, func(), error) {
|
||||||
wire.Build(scanner.RemoteFilesystemSet)
|
wire.Build(scanner.RemoteFilesystemSet)
|
||||||
return scanner.Scanner{}, nil, nil
|
return scanner.Scanner{}, nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// initializeRemoteRepositoryScanner is for repository scanning in client/server mode
|
// initializeRemoteRepositoryScanner is for repository scanning in client/server mode
|
||||||
func initializeRemoteRepositoryScanner(ctx context.Context, url string, artifactCache cache.ArtifactCache,
|
func initializeRemoteRepositoryScanner(ctx context.Context, url string, remoteCacheOptions cache.RemoteOptions,
|
||||||
remoteScanOptions client.ScannerOption, artifactOption artifact.Option) (
|
remoteScanOptions client.ScannerOption, artifactOption artifact.Option) (
|
||||||
scanner.Scanner, func(), error) {
|
scanner.Scanner, func(), error) {
|
||||||
wire.Build(scanner.RemoteRepositorySet)
|
wire.Build(scanner.RemoteRepositorySet)
|
||||||
@@ -99,14 +94,14 @@ func initializeRemoteRepositoryScanner(ctx context.Context, url string, artifact
|
|||||||
}
|
}
|
||||||
|
|
||||||
// initializeRemoteSBOMScanner is for sbom scanning in client/server mode
|
// initializeRemoteSBOMScanner is for sbom scanning in client/server mode
|
||||||
func initializeRemoteSBOMScanner(ctx context.Context, path string, artifactCache cache.ArtifactCache,
|
func initializeRemoteSBOMScanner(ctx context.Context, path string, remoteCacheOptions cache.RemoteOptions,
|
||||||
remoteScanOptions client.ScannerOption, artifactOption artifact.Option) (scanner.Scanner, func(), error) {
|
remoteScanOptions client.ScannerOption, artifactOption artifact.Option) (scanner.Scanner, func(), error) {
|
||||||
wire.Build(scanner.RemoteSBOMSet)
|
wire.Build(scanner.RemoteSBOMSet)
|
||||||
return scanner.Scanner{}, nil, nil
|
return scanner.Scanner{}, nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// initializeRemoteVMScanner is for vm scanning in client/server mode
|
// initializeRemoteVMScanner is for vm scanning in client/server mode
|
||||||
func initializeRemoteVMScanner(ctx context.Context, path string, artifactCache cache.ArtifactCache,
|
func initializeRemoteVMScanner(ctx context.Context, path string, remoteCacheOptions cache.RemoteOptions,
|
||||||
remoteScanOptions client.ScannerOption, artifactOption artifact.Option) (scanner.Scanner, func(), error) {
|
remoteScanOptions client.ScannerOption, artifactOption artifact.Option) (scanner.Scanner, func(), error) {
|
||||||
wire.Build(scanner.RemoteVMSet)
|
wire.Build(scanner.RemoteVMSet)
|
||||||
return scanner.Scanner{}, nil, nil
|
return scanner.Scanner{}, nil, nil
|
||||||
|
|||||||
@@ -57,8 +57,8 @@ type ScannerConfig struct {
|
|||||||
Target string
|
Target string
|
||||||
|
|
||||||
// Cache
|
// Cache
|
||||||
ArtifactCache cache.ArtifactCache
|
CacheOptions cache.Options
|
||||||
LocalArtifactCache cache.LocalArtifactCache
|
RemoteCacheOptions cache.RemoteOptions
|
||||||
|
|
||||||
// Client/Server options
|
// Client/Server options
|
||||||
ServerOption client.ScannerOption
|
ServerOption client.ScannerOption
|
||||||
@@ -89,37 +89,31 @@ type Runner interface {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type runner struct {
|
type runner struct {
|
||||||
cache cache.ArtifactCache
|
initializeScanner InitializeScanner
|
||||||
localCache cache.LocalArtifactCache
|
|
||||||
dbOpen bool
|
dbOpen bool
|
||||||
|
|
||||||
// WASM modules
|
// WASM modules
|
||||||
module *module.Manager
|
module *module.Manager
|
||||||
}
|
}
|
||||||
|
|
||||||
type runnerOption func(*runner)
|
type RunnerOption func(*runner)
|
||||||
|
|
||||||
// WithCacheClient takes a custom cache implementation
|
// WithInitializeScanner takes a custom scanner initialization function.
|
||||||
// It is useful when Trivy is imported as a library.
|
// It is useful when Trivy is imported as a library.
|
||||||
func WithCacheClient(c cache.Cache) runnerOption {
|
func WithInitializeScanner(f InitializeScanner) RunnerOption {
|
||||||
return func(r *runner) {
|
return func(r *runner) {
|
||||||
r.cache = c
|
r.initializeScanner = f
|
||||||
r.localCache = c
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewRunner initializes Runner that provides scanning functionalities.
|
// NewRunner initializes Runner that provides scanning functionalities.
|
||||||
// It is possible to return SkipScan and it must be handled by caller.
|
// It is possible to return SkipScan and it must be handled by caller.
|
||||||
func NewRunner(ctx context.Context, cliOptions flag.Options, opts ...runnerOption) (Runner, error) {
|
func NewRunner(ctx context.Context, cliOptions flag.Options, opts ...RunnerOption) (Runner, error) {
|
||||||
r := &runner{}
|
r := &runner{}
|
||||||
for _, opt := range opts {
|
for _, opt := range opts {
|
||||||
opt(r)
|
opt(r)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := r.initCache(cliOptions); err != nil {
|
|
||||||
return nil, xerrors.Errorf("cache error: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update the vulnerability database if needed.
|
// Update the vulnerability database if needed.
|
||||||
if err := r.initDB(ctx, cliOptions); err != nil {
|
if err := r.initDB(ctx, cliOptions); err != nil {
|
||||||
return nil, xerrors.Errorf("DB error: %w", err)
|
return nil, xerrors.Errorf("DB error: %w", err)
|
||||||
@@ -142,10 +136,6 @@ func NewRunner(ctx context.Context, cliOptions flag.Options, opts ...runnerOptio
|
|||||||
// Close closes everything
|
// Close closes everything
|
||||||
func (r *runner) Close(ctx context.Context) error {
|
func (r *runner) Close(ctx context.Context) error {
|
||||||
var errs error
|
var errs error
|
||||||
if err := r.localCache.Close(); err != nil {
|
|
||||||
errs = multierror.Append(errs, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if r.dbOpen {
|
if r.dbOpen {
|
||||||
if err := db.Close(); err != nil {
|
if err := db.Close(); err != nil {
|
||||||
errs = multierror.Append(errs, err)
|
errs = multierror.Append(errs, err)
|
||||||
@@ -258,6 +248,9 @@ func (r *runner) ScanVM(ctx context.Context, opts flag.Options) (types.Report, e
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (r *runner) scanArtifact(ctx context.Context, opts flag.Options, initializeScanner InitializeScanner) (types.Report, error) {
|
func (r *runner) scanArtifact(ctx context.Context, opts flag.Options, initializeScanner InitializeScanner) (types.Report, error) {
|
||||||
|
if r.initializeScanner != nil {
|
||||||
|
initializeScanner = r.initializeScanner
|
||||||
|
}
|
||||||
report, err := r.scan(ctx, opts, initializeScanner)
|
report, err := r.scan(ctx, opts, initializeScanner)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return types.Report{}, xerrors.Errorf("scan error: %w", err)
|
return types.Report{}, xerrors.Errorf("scan error: %w", err)
|
||||||
@@ -335,31 +328,6 @@ func (r *runner) initJavaDB(opts flag.Options) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *runner) initCache(opts flag.Options) error {
|
|
||||||
// Skip initializing cache when custom cache is passed
|
|
||||||
if r.cache != nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// client/server mode
|
|
||||||
if opts.ServerAddr != "" {
|
|
||||||
r.cache = cache.NewRemoteCache(opts.ServerAddr, opts.CustomHeaders, opts.Insecure)
|
|
||||||
r.localCache = cache.NewNopCache() // No need to use local cache in client/server mode
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// standalone mode
|
|
||||||
cacheClient, err := cache.New(opts.CacheDir, opts.CacheOptions.CacheBackendOptions)
|
|
||||||
if err != nil {
|
|
||||||
return xerrors.Errorf("unable to initialize the cache: %w", err)
|
|
||||||
}
|
|
||||||
log.Debug("Cache dir", log.String("dir", opts.CacheDir))
|
|
||||||
|
|
||||||
r.cache = cacheClient
|
|
||||||
r.localCache = cacheClient
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Run performs artifact scanning
|
// Run performs artifact scanning
|
||||||
func Run(ctx context.Context, opts flag.Options, targetKind TargetKind) (err error) {
|
func Run(ctx context.Context, opts flag.Options, targetKind TargetKind) (err error) {
|
||||||
ctx, cancel := context.WithTimeout(ctx, opts.Timeout)
|
ctx, cancel := context.WithTimeout(ctx, opts.Timeout)
|
||||||
@@ -588,8 +556,8 @@ func (r *runner) initScannerConfig(opts flag.Options) (ScannerConfig, types.Scan
|
|||||||
|
|
||||||
return ScannerConfig{
|
return ScannerConfig{
|
||||||
Target: target,
|
Target: target,
|
||||||
ArtifactCache: r.cache,
|
CacheOptions: opts.CacheOpts(),
|
||||||
LocalArtifactCache: r.localCache,
|
RemoteCacheOptions: opts.RemoteCacheOpts(),
|
||||||
ServerOption: client.ScannerOption{
|
ServerOption: client.ScannerOption{
|
||||||
RemoteURL: opts.ServerAddr,
|
RemoteURL: opts.ServerAddr,
|
||||||
CustomHeaders: opts.CustomHeaders,
|
CustomHeaders: opts.CustomHeaders,
|
||||||
@@ -607,7 +575,6 @@ func (r *runner) initScannerConfig(opts flag.Options) (ScannerConfig, types.Scan
|
|||||||
RepoTag: opts.RepoTag,
|
RepoTag: opts.RepoTag,
|
||||||
SBOMSources: opts.SBOMSources,
|
SBOMSources: opts.SBOMSources,
|
||||||
RekorURL: opts.RekorURL,
|
RekorURL: opts.RekorURL,
|
||||||
//Platform: opts.Platform,
|
|
||||||
AWSRegion: opts.Region,
|
AWSRegion: opts.Region,
|
||||||
AWSEndpoint: opts.Endpoint,
|
AWSEndpoint: opts.Endpoint,
|
||||||
FileChecksum: fileChecksum,
|
FileChecksum: fileChecksum,
|
||||||
|
|||||||
@@ -11,8 +11,7 @@ import (
|
|||||||
// imageStandaloneScanner initializes a container image scanner in standalone mode
|
// imageStandaloneScanner initializes a container image scanner in standalone mode
|
||||||
// $ trivy image alpine:3.15
|
// $ trivy image alpine:3.15
|
||||||
func imageStandaloneScanner(ctx context.Context, conf ScannerConfig) (scanner.Scanner, func(), error) {
|
func imageStandaloneScanner(ctx context.Context, conf ScannerConfig) (scanner.Scanner, func(), error) {
|
||||||
s, cleanup, err := initializeImageScanner(ctx, conf.Target, conf.ArtifactCache, conf.LocalArtifactCache,
|
s, cleanup, err := initializeImageScanner(ctx, conf.Target, conf.ArtifactOption.ImageOption, conf.CacheOptions, conf.ArtifactOption)
|
||||||
conf.ArtifactOption.ImageOption, conf.ArtifactOption)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return scanner.Scanner{}, func() {}, xerrors.Errorf("unable to initialize an image scanner: %w", err)
|
return scanner.Scanner{}, func() {}, xerrors.Errorf("unable to initialize an image scanner: %w", err)
|
||||||
}
|
}
|
||||||
@@ -22,18 +21,18 @@ func imageStandaloneScanner(ctx context.Context, conf ScannerConfig) (scanner.Sc
|
|||||||
// archiveStandaloneScanner initializes an image archive scanner in standalone mode
|
// archiveStandaloneScanner initializes an image archive scanner in standalone mode
|
||||||
// $ trivy image --input alpine.tar
|
// $ trivy image --input alpine.tar
|
||||||
func archiveStandaloneScanner(ctx context.Context, conf ScannerConfig) (scanner.Scanner, func(), error) {
|
func archiveStandaloneScanner(ctx context.Context, conf ScannerConfig) (scanner.Scanner, func(), error) {
|
||||||
s, err := initializeArchiveScanner(ctx, conf.Target, conf.ArtifactCache, conf.LocalArtifactCache, conf.ArtifactOption)
|
s, cleanup, err := initializeArchiveScanner(ctx, conf.Target, conf.CacheOptions, conf.ArtifactOption)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return scanner.Scanner{}, func() {}, xerrors.Errorf("unable to initialize the archive scanner: %w", err)
|
return scanner.Scanner{}, func() {}, xerrors.Errorf("unable to initialize the archive scanner: %w", err)
|
||||||
}
|
}
|
||||||
return s, func() {}, nil
|
return s, cleanup, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// imageRemoteScanner initializes a container image scanner in client/server mode
|
// imageRemoteScanner initializes a container image scanner in client/server mode
|
||||||
// $ trivy image --server localhost:4954 alpine:3.15
|
// $ trivy image --server localhost:4954 alpine:3.15
|
||||||
func imageRemoteScanner(ctx context.Context, conf ScannerConfig) (
|
func imageRemoteScanner(ctx context.Context, conf ScannerConfig) (
|
||||||
scanner.Scanner, func(), error) {
|
scanner.Scanner, func(), error) {
|
||||||
s, cleanup, err := initializeRemoteImageScanner(ctx, conf.Target, conf.ArtifactCache, conf.ServerOption,
|
s, cleanup, err := initializeRemoteImageScanner(ctx, conf.Target, conf.RemoteCacheOptions, conf.ServerOption,
|
||||||
conf.ArtifactOption.ImageOption, conf.ArtifactOption)
|
conf.ArtifactOption.ImageOption, conf.ArtifactOption)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return scanner.Scanner{}, nil, xerrors.Errorf("unable to initialize a remote image scanner: %w", err)
|
return scanner.Scanner{}, nil, xerrors.Errorf("unable to initialize a remote image scanner: %w", err)
|
||||||
@@ -45,16 +44,16 @@ func imageRemoteScanner(ctx context.Context, conf ScannerConfig) (
|
|||||||
// $ trivy image --server localhost:4954 --input alpine.tar
|
// $ trivy image --server localhost:4954 --input alpine.tar
|
||||||
func archiveRemoteScanner(ctx context.Context, conf ScannerConfig) (scanner.Scanner, func(), error) {
|
func archiveRemoteScanner(ctx context.Context, conf ScannerConfig) (scanner.Scanner, func(), error) {
|
||||||
// Scan tar file
|
// Scan tar file
|
||||||
s, err := initializeRemoteArchiveScanner(ctx, conf.Target, conf.ArtifactCache, conf.ServerOption, conf.ArtifactOption)
|
s, cleanup, err := initializeRemoteArchiveScanner(ctx, conf.Target, conf.RemoteCacheOptions, conf.ServerOption, conf.ArtifactOption)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return scanner.Scanner{}, nil, xerrors.Errorf("unable to initialize the remote archive scanner: %w", err)
|
return scanner.Scanner{}, nil, xerrors.Errorf("unable to initialize the remote archive scanner: %w", err)
|
||||||
}
|
}
|
||||||
return s, func() {}, nil
|
return s, cleanup, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// filesystemStandaloneScanner initializes a filesystem scanner in standalone mode
|
// filesystemStandaloneScanner initializes a filesystem scanner in standalone mode
|
||||||
func filesystemStandaloneScanner(ctx context.Context, conf ScannerConfig) (scanner.Scanner, func(), error) {
|
func filesystemStandaloneScanner(ctx context.Context, conf ScannerConfig) (scanner.Scanner, func(), error) {
|
||||||
s, cleanup, err := initializeFilesystemScanner(ctx, conf.Target, conf.ArtifactCache, conf.LocalArtifactCache, conf.ArtifactOption)
|
s, cleanup, err := initializeFilesystemScanner(ctx, conf.Target, conf.CacheOptions, conf.ArtifactOption)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return scanner.Scanner{}, func() {}, xerrors.Errorf("unable to initialize a filesystem scanner: %w", err)
|
return scanner.Scanner{}, func() {}, xerrors.Errorf("unable to initialize a filesystem scanner: %w", err)
|
||||||
}
|
}
|
||||||
@@ -63,7 +62,7 @@ func filesystemStandaloneScanner(ctx context.Context, conf ScannerConfig) (scann
|
|||||||
|
|
||||||
// filesystemRemoteScanner initializes a filesystem scanner in client/server mode
|
// filesystemRemoteScanner initializes a filesystem scanner in client/server mode
|
||||||
func filesystemRemoteScanner(ctx context.Context, conf ScannerConfig) (scanner.Scanner, func(), error) {
|
func filesystemRemoteScanner(ctx context.Context, conf ScannerConfig) (scanner.Scanner, func(), error) {
|
||||||
s, cleanup, err := initializeRemoteFilesystemScanner(ctx, conf.Target, conf.ArtifactCache, conf.ServerOption, conf.ArtifactOption)
|
s, cleanup, err := initializeRemoteFilesystemScanner(ctx, conf.Target, conf.RemoteCacheOptions, conf.ServerOption, conf.ArtifactOption)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return scanner.Scanner{}, func() {}, xerrors.Errorf("unable to initialize a remote filesystem scanner: %w", err)
|
return scanner.Scanner{}, func() {}, xerrors.Errorf("unable to initialize a remote filesystem scanner: %w", err)
|
||||||
}
|
}
|
||||||
@@ -72,7 +71,7 @@ func filesystemRemoteScanner(ctx context.Context, conf ScannerConfig) (scanner.S
|
|||||||
|
|
||||||
// repositoryStandaloneScanner initializes a repository scanner in standalone mode
|
// repositoryStandaloneScanner initializes a repository scanner in standalone mode
|
||||||
func repositoryStandaloneScanner(ctx context.Context, conf ScannerConfig) (scanner.Scanner, func(), error) {
|
func repositoryStandaloneScanner(ctx context.Context, conf ScannerConfig) (scanner.Scanner, func(), error) {
|
||||||
s, cleanup, err := initializeRepositoryScanner(ctx, conf.Target, conf.ArtifactCache, conf.LocalArtifactCache, conf.ArtifactOption)
|
s, cleanup, err := initializeRepositoryScanner(ctx, conf.Target, conf.CacheOptions, conf.ArtifactOption)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return scanner.Scanner{}, func() {}, xerrors.Errorf("unable to initialize a repository scanner: %w", err)
|
return scanner.Scanner{}, func() {}, xerrors.Errorf("unable to initialize a repository scanner: %w", err)
|
||||||
}
|
}
|
||||||
@@ -81,7 +80,7 @@ func repositoryStandaloneScanner(ctx context.Context, conf ScannerConfig) (scann
|
|||||||
|
|
||||||
// repositoryRemoteScanner initializes a repository scanner in client/server mode
|
// repositoryRemoteScanner initializes a repository scanner in client/server mode
|
||||||
func repositoryRemoteScanner(ctx context.Context, conf ScannerConfig) (scanner.Scanner, func(), error) {
|
func repositoryRemoteScanner(ctx context.Context, conf ScannerConfig) (scanner.Scanner, func(), error) {
|
||||||
s, cleanup, err := initializeRemoteRepositoryScanner(ctx, conf.Target, conf.ArtifactCache, conf.ServerOption,
|
s, cleanup, err := initializeRemoteRepositoryScanner(ctx, conf.Target, conf.RemoteCacheOptions, conf.ServerOption,
|
||||||
conf.ArtifactOption)
|
conf.ArtifactOption)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return scanner.Scanner{}, func() {}, xerrors.Errorf("unable to initialize a remote repository scanner: %w", err)
|
return scanner.Scanner{}, func() {}, xerrors.Errorf("unable to initialize a remote repository scanner: %w", err)
|
||||||
@@ -91,7 +90,7 @@ func repositoryRemoteScanner(ctx context.Context, conf ScannerConfig) (scanner.S
|
|||||||
|
|
||||||
// sbomStandaloneScanner initializes a SBOM scanner in standalone mode
|
// sbomStandaloneScanner initializes a SBOM scanner in standalone mode
|
||||||
func sbomStandaloneScanner(ctx context.Context, conf ScannerConfig) (scanner.Scanner, func(), error) {
|
func sbomStandaloneScanner(ctx context.Context, conf ScannerConfig) (scanner.Scanner, func(), error) {
|
||||||
s, cleanup, err := initializeSBOMScanner(ctx, conf.Target, conf.ArtifactCache, conf.LocalArtifactCache, conf.ArtifactOption)
|
s, cleanup, err := initializeSBOMScanner(ctx, conf.Target, conf.CacheOptions, conf.ArtifactOption)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return scanner.Scanner{}, func() {}, xerrors.Errorf("unable to initialize a cycloneDX scanner: %w", err)
|
return scanner.Scanner{}, func() {}, xerrors.Errorf("unable to initialize a cycloneDX scanner: %w", err)
|
||||||
}
|
}
|
||||||
@@ -100,7 +99,7 @@ func sbomStandaloneScanner(ctx context.Context, conf ScannerConfig) (scanner.Sca
|
|||||||
|
|
||||||
// sbomRemoteScanner initializes a SBOM scanner in client/server mode
|
// sbomRemoteScanner initializes a SBOM scanner in client/server mode
|
||||||
func sbomRemoteScanner(ctx context.Context, conf ScannerConfig) (scanner.Scanner, func(), error) {
|
func sbomRemoteScanner(ctx context.Context, conf ScannerConfig) (scanner.Scanner, func(), error) {
|
||||||
s, cleanup, err := initializeRemoteSBOMScanner(ctx, conf.Target, conf.ArtifactCache, conf.ServerOption, conf.ArtifactOption)
|
s, cleanup, err := initializeRemoteSBOMScanner(ctx, conf.Target, conf.RemoteCacheOptions, conf.ServerOption, conf.ArtifactOption)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return scanner.Scanner{}, func() {}, xerrors.Errorf("unable to initialize a remote cycloneDX scanner: %w", err)
|
return scanner.Scanner{}, func() {}, xerrors.Errorf("unable to initialize a remote cycloneDX scanner: %w", err)
|
||||||
}
|
}
|
||||||
@@ -109,7 +108,7 @@ func sbomRemoteScanner(ctx context.Context, conf ScannerConfig) (scanner.Scanner
|
|||||||
|
|
||||||
// vmStandaloneScanner initializes a VM scanner in standalone mode
|
// vmStandaloneScanner initializes a VM scanner in standalone mode
|
||||||
func vmStandaloneScanner(ctx context.Context, conf ScannerConfig) (scanner.Scanner, func(), error) {
|
func vmStandaloneScanner(ctx context.Context, conf ScannerConfig) (scanner.Scanner, func(), error) {
|
||||||
s, cleanup, err := initializeVMScanner(ctx, conf.Target, conf.ArtifactCache, conf.LocalArtifactCache, conf.ArtifactOption)
|
s, cleanup, err := initializeVMScanner(ctx, conf.Target, conf.CacheOptions, conf.ArtifactOption)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return scanner.Scanner{}, func() {}, xerrors.Errorf("unable to initialize a vm scanner: %w", err)
|
return scanner.Scanner{}, func() {}, xerrors.Errorf("unable to initialize a vm scanner: %w", err)
|
||||||
}
|
}
|
||||||
@@ -118,7 +117,7 @@ func vmStandaloneScanner(ctx context.Context, conf ScannerConfig) (scanner.Scann
|
|||||||
|
|
||||||
// vmRemoteScanner initializes a VM scanner in client/server mode
|
// vmRemoteScanner initializes a VM scanner in client/server mode
|
||||||
func vmRemoteScanner(ctx context.Context, conf ScannerConfig) (scanner.Scanner, func(), error) {
|
func vmRemoteScanner(ctx context.Context, conf ScannerConfig) (scanner.Scanner, func(), error) {
|
||||||
s, cleanup, err := initializeRemoteVMScanner(ctx, conf.Target, conf.ArtifactCache, conf.ServerOption, conf.ArtifactOption)
|
s, cleanup, err := initializeRemoteVMScanner(ctx, conf.Target, conf.RemoteCacheOptions, conf.ServerOption, conf.ArtifactOption)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return scanner.Scanner{}, func() {}, xerrors.Errorf("unable to initialize a remote vm scanner: %w", err)
|
return scanner.Scanner{}, func() {}, xerrors.Errorf("unable to initialize a remote vm scanner: %w", err)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ package artifact
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"github.com/aquasecurity/trivy-db/pkg/db"
|
"github.com/aquasecurity/trivy-db/pkg/db"
|
||||||
|
"github.com/aquasecurity/trivy/pkg/cache"
|
||||||
"github.com/aquasecurity/trivy/pkg/fanal/applier"
|
"github.com/aquasecurity/trivy/pkg/fanal/applier"
|
||||||
"github.com/aquasecurity/trivy/pkg/fanal/artifact"
|
"github.com/aquasecurity/trivy/pkg/fanal/artifact"
|
||||||
image2 "github.com/aquasecurity/trivy/pkg/fanal/artifact/image"
|
image2 "github.com/aquasecurity/trivy/pkg/fanal/artifact/image"
|
||||||
@@ -16,7 +17,6 @@ import (
|
|||||||
"github.com/aquasecurity/trivy/pkg/fanal/artifact/repo"
|
"github.com/aquasecurity/trivy/pkg/fanal/artifact/repo"
|
||||||
"github.com/aquasecurity/trivy/pkg/fanal/artifact/sbom"
|
"github.com/aquasecurity/trivy/pkg/fanal/artifact/sbom"
|
||||||
"github.com/aquasecurity/trivy/pkg/fanal/artifact/vm"
|
"github.com/aquasecurity/trivy/pkg/fanal/artifact/vm"
|
||||||
"github.com/aquasecurity/trivy/pkg/cache"
|
|
||||||
"github.com/aquasecurity/trivy/pkg/fanal/image"
|
"github.com/aquasecurity/trivy/pkg/fanal/image"
|
||||||
"github.com/aquasecurity/trivy/pkg/fanal/types"
|
"github.com/aquasecurity/trivy/pkg/fanal/types"
|
||||||
"github.com/aquasecurity/trivy/pkg/fanal/walker"
|
"github.com/aquasecurity/trivy/pkg/fanal/walker"
|
||||||
@@ -32,32 +32,43 @@ import (
|
|||||||
|
|
||||||
// initializeImageScanner is for container image scanning in standalone mode
|
// initializeImageScanner is for container image scanning in standalone mode
|
||||||
// e.g. dockerd, container registry, podman, etc.
|
// e.g. dockerd, container registry, podman, etc.
|
||||||
func initializeImageScanner(ctx context.Context, imageName string, artifactCache cache.ArtifactCache, localArtifactCache cache.LocalArtifactCache, imageOpt types.ImageOptions, artifactOption artifact.Option) (scanner.Scanner, func(), error) {
|
func initializeImageScanner(ctx context.Context, imageName string, imageOpt types.ImageOptions, cacheOptions cache.Options, artifactOption artifact.Option) (scanner.Scanner, func(), error) {
|
||||||
applierApplier := applier.NewApplier(localArtifactCache)
|
cacheCache, cleanup, err := cache.New(cacheOptions)
|
||||||
|
if err != nil {
|
||||||
|
return scanner.Scanner{}, nil, err
|
||||||
|
}
|
||||||
|
applierApplier := applier.NewApplier(cacheCache)
|
||||||
ospkgScanner := ospkg.NewScanner()
|
ospkgScanner := ospkg.NewScanner()
|
||||||
langpkgScanner := langpkg.NewScanner()
|
langpkgScanner := langpkg.NewScanner()
|
||||||
config := db.Config{}
|
config := db.Config{}
|
||||||
client := vulnerability.NewClient(config)
|
client := vulnerability.NewClient(config)
|
||||||
localScanner := local.NewScanner(applierApplier, ospkgScanner, langpkgScanner, client)
|
localScanner := local.NewScanner(applierApplier, ospkgScanner, langpkgScanner, client)
|
||||||
typesImage, cleanup, err := image.NewContainerImage(ctx, imageName, imageOpt)
|
typesImage, cleanup2, err := image.NewContainerImage(ctx, imageName, imageOpt)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
cleanup()
|
||||||
return scanner.Scanner{}, nil, err
|
return scanner.Scanner{}, nil, err
|
||||||
}
|
}
|
||||||
artifactArtifact, err := image2.NewArtifact(typesImage, artifactCache, artifactOption)
|
artifactArtifact, err := image2.NewArtifact(typesImage, cacheCache, artifactOption)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
cleanup2()
|
||||||
cleanup()
|
cleanup()
|
||||||
return scanner.Scanner{}, nil, err
|
return scanner.Scanner{}, nil, err
|
||||||
}
|
}
|
||||||
scannerScanner := scanner.NewScanner(localScanner, artifactArtifact)
|
scannerScanner := scanner.NewScanner(localScanner, artifactArtifact)
|
||||||
return scannerScanner, func() {
|
return scannerScanner, func() {
|
||||||
|
cleanup2()
|
||||||
cleanup()
|
cleanup()
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// initializeArchiveScanner is for container image archive scanning in standalone mode
|
// initializeArchiveScanner is for container image archive scanning in standalone mode
|
||||||
// e.g. docker save -o alpine.tar alpine:3.15
|
// e.g. docker save -o alpine.tar alpine:3.15
|
||||||
func initializeArchiveScanner(ctx context.Context, filePath string, artifactCache cache.ArtifactCache, localArtifactCache cache.LocalArtifactCache, artifactOption artifact.Option) (scanner.Scanner, error) {
|
func initializeArchiveScanner(ctx context.Context, filePath string, cacheOptions cache.Options, artifactOption artifact.Option) (scanner.Scanner, func(), error) {
|
||||||
applierApplier := applier.NewApplier(localArtifactCache)
|
cacheCache, cleanup, err := cache.New(cacheOptions)
|
||||||
|
if err != nil {
|
||||||
|
return scanner.Scanner{}, nil, err
|
||||||
|
}
|
||||||
|
applierApplier := applier.NewApplier(cacheCache)
|
||||||
ospkgScanner := ospkg.NewScanner()
|
ospkgScanner := ospkg.NewScanner()
|
||||||
langpkgScanner := langpkg.NewScanner()
|
langpkgScanner := langpkg.NewScanner()
|
||||||
config := db.Config{}
|
config := db.Config{}
|
||||||
@@ -65,44 +76,12 @@ func initializeArchiveScanner(ctx context.Context, filePath string, artifactCach
|
|||||||
localScanner := local.NewScanner(applierApplier, ospkgScanner, langpkgScanner, client)
|
localScanner := local.NewScanner(applierApplier, ospkgScanner, langpkgScanner, client)
|
||||||
typesImage, err := image.NewArchiveImage(filePath)
|
typesImage, err := image.NewArchiveImage(filePath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return scanner.Scanner{}, err
|
cleanup()
|
||||||
}
|
|
||||||
artifactArtifact, err := image2.NewArtifact(typesImage, artifactCache, artifactOption)
|
|
||||||
if err != nil {
|
|
||||||
return scanner.Scanner{}, err
|
|
||||||
}
|
|
||||||
scannerScanner := scanner.NewScanner(localScanner, artifactArtifact)
|
|
||||||
return scannerScanner, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// initializeFilesystemScanner is for filesystem scanning in standalone mode
|
|
||||||
func initializeFilesystemScanner(ctx context.Context, path string, artifactCache cache.ArtifactCache, localArtifactCache cache.LocalArtifactCache, artifactOption artifact.Option) (scanner.Scanner, func(), error) {
|
|
||||||
applierApplier := applier.NewApplier(localArtifactCache)
|
|
||||||
ospkgScanner := ospkg.NewScanner()
|
|
||||||
langpkgScanner := langpkg.NewScanner()
|
|
||||||
config := db.Config{}
|
|
||||||
client := vulnerability.NewClient(config)
|
|
||||||
localScanner := local.NewScanner(applierApplier, ospkgScanner, langpkgScanner, client)
|
|
||||||
fs := walker.NewFS()
|
|
||||||
artifactArtifact, err := local2.NewArtifact(path, artifactCache, fs, artifactOption)
|
|
||||||
if err != nil {
|
|
||||||
return scanner.Scanner{}, nil, err
|
return scanner.Scanner{}, nil, err
|
||||||
}
|
}
|
||||||
scannerScanner := scanner.NewScanner(localScanner, artifactArtifact)
|
artifactArtifact, err := image2.NewArtifact(typesImage, cacheCache, artifactOption)
|
||||||
return scannerScanner, func() {
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func initializeRepositoryScanner(ctx context.Context, url string, artifactCache cache.ArtifactCache, localArtifactCache cache.LocalArtifactCache, artifactOption artifact.Option) (scanner.Scanner, func(), error) {
|
|
||||||
applierApplier := applier.NewApplier(localArtifactCache)
|
|
||||||
ospkgScanner := ospkg.NewScanner()
|
|
||||||
langpkgScanner := langpkg.NewScanner()
|
|
||||||
config := db.Config{}
|
|
||||||
client := vulnerability.NewClient(config)
|
|
||||||
localScanner := local.NewScanner(applierApplier, ospkgScanner, langpkgScanner, client)
|
|
||||||
fs := walker.NewFS()
|
|
||||||
artifactArtifact, cleanup, err := repo.NewArtifact(url, artifactCache, fs, artifactOption)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
cleanup()
|
||||||
return scanner.Scanner{}, nil, err
|
return scanner.Scanner{}, nil, err
|
||||||
}
|
}
|
||||||
scannerScanner := scanner.NewScanner(localScanner, artifactArtifact)
|
scannerScanner := scanner.NewScanner(localScanner, artifactArtifact)
|
||||||
@@ -111,49 +90,110 @@ func initializeRepositoryScanner(ctx context.Context, url string, artifactCache
|
|||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func initializeSBOMScanner(ctx context.Context, filePath string, artifactCache cache.ArtifactCache, localArtifactCache cache.LocalArtifactCache, artifactOption artifact.Option) (scanner.Scanner, func(), error) {
|
// initializeFilesystemScanner is for filesystem scanning in standalone mode
|
||||||
applierApplier := applier.NewApplier(localArtifactCache)
|
func initializeFilesystemScanner(ctx context.Context, path string, cacheOptions cache.Options, artifactOption artifact.Option) (scanner.Scanner, func(), error) {
|
||||||
|
cacheCache, cleanup, err := cache.New(cacheOptions)
|
||||||
|
if err != nil {
|
||||||
|
return scanner.Scanner{}, nil, err
|
||||||
|
}
|
||||||
|
applierApplier := applier.NewApplier(cacheCache)
|
||||||
ospkgScanner := ospkg.NewScanner()
|
ospkgScanner := ospkg.NewScanner()
|
||||||
langpkgScanner := langpkg.NewScanner()
|
langpkgScanner := langpkg.NewScanner()
|
||||||
config := db.Config{}
|
config := db.Config{}
|
||||||
client := vulnerability.NewClient(config)
|
client := vulnerability.NewClient(config)
|
||||||
localScanner := local.NewScanner(applierApplier, ospkgScanner, langpkgScanner, client)
|
localScanner := local.NewScanner(applierApplier, ospkgScanner, langpkgScanner, client)
|
||||||
artifactArtifact, err := sbom.NewArtifact(filePath, artifactCache, artifactOption)
|
fs := walker.NewFS()
|
||||||
|
artifactArtifact, err := local2.NewArtifact(path, cacheCache, fs, artifactOption)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
cleanup()
|
||||||
return scanner.Scanner{}, nil, err
|
return scanner.Scanner{}, nil, err
|
||||||
}
|
}
|
||||||
scannerScanner := scanner.NewScanner(localScanner, artifactArtifact)
|
scannerScanner := scanner.NewScanner(localScanner, artifactArtifact)
|
||||||
return scannerScanner, func() {
|
return scannerScanner, func() {
|
||||||
|
cleanup()
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func initializeVMScanner(ctx context.Context, filePath string, artifactCache cache.ArtifactCache, localArtifactCache cache.LocalArtifactCache, artifactOption artifact.Option) (scanner.Scanner, func(), error) {
|
func initializeRepositoryScanner(ctx context.Context, url string, cacheOptions cache.Options, artifactOption artifact.Option) (scanner.Scanner, func(), error) {
|
||||||
applierApplier := applier.NewApplier(localArtifactCache)
|
cacheCache, cleanup, err := cache.New(cacheOptions)
|
||||||
|
if err != nil {
|
||||||
|
return scanner.Scanner{}, nil, err
|
||||||
|
}
|
||||||
|
applierApplier := applier.NewApplier(cacheCache)
|
||||||
|
ospkgScanner := ospkg.NewScanner()
|
||||||
|
langpkgScanner := langpkg.NewScanner()
|
||||||
|
config := db.Config{}
|
||||||
|
client := vulnerability.NewClient(config)
|
||||||
|
localScanner := local.NewScanner(applierApplier, ospkgScanner, langpkgScanner, client)
|
||||||
|
fs := walker.NewFS()
|
||||||
|
artifactArtifact, cleanup2, err := repo.NewArtifact(url, cacheCache, fs, artifactOption)
|
||||||
|
if err != nil {
|
||||||
|
cleanup()
|
||||||
|
return scanner.Scanner{}, nil, err
|
||||||
|
}
|
||||||
|
scannerScanner := scanner.NewScanner(localScanner, artifactArtifact)
|
||||||
|
return scannerScanner, func() {
|
||||||
|
cleanup2()
|
||||||
|
cleanup()
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func initializeSBOMScanner(ctx context.Context, filePath string, cacheOptions cache.Options, artifactOption artifact.Option) (scanner.Scanner, func(), error) {
|
||||||
|
cacheCache, cleanup, err := cache.New(cacheOptions)
|
||||||
|
if err != nil {
|
||||||
|
return scanner.Scanner{}, nil, err
|
||||||
|
}
|
||||||
|
applierApplier := applier.NewApplier(cacheCache)
|
||||||
|
ospkgScanner := ospkg.NewScanner()
|
||||||
|
langpkgScanner := langpkg.NewScanner()
|
||||||
|
config := db.Config{}
|
||||||
|
client := vulnerability.NewClient(config)
|
||||||
|
localScanner := local.NewScanner(applierApplier, ospkgScanner, langpkgScanner, client)
|
||||||
|
artifactArtifact, err := sbom.NewArtifact(filePath, cacheCache, artifactOption)
|
||||||
|
if err != nil {
|
||||||
|
cleanup()
|
||||||
|
return scanner.Scanner{}, nil, err
|
||||||
|
}
|
||||||
|
scannerScanner := scanner.NewScanner(localScanner, artifactArtifact)
|
||||||
|
return scannerScanner, func() {
|
||||||
|
cleanup()
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func initializeVMScanner(ctx context.Context, filePath string, cacheOptions cache.Options, artifactOption artifact.Option) (scanner.Scanner, func(), error) {
|
||||||
|
cacheCache, cleanup, err := cache.New(cacheOptions)
|
||||||
|
if err != nil {
|
||||||
|
return scanner.Scanner{}, nil, err
|
||||||
|
}
|
||||||
|
applierApplier := applier.NewApplier(cacheCache)
|
||||||
ospkgScanner := ospkg.NewScanner()
|
ospkgScanner := ospkg.NewScanner()
|
||||||
langpkgScanner := langpkg.NewScanner()
|
langpkgScanner := langpkg.NewScanner()
|
||||||
config := db.Config{}
|
config := db.Config{}
|
||||||
client := vulnerability.NewClient(config)
|
client := vulnerability.NewClient(config)
|
||||||
localScanner := local.NewScanner(applierApplier, ospkgScanner, langpkgScanner, client)
|
localScanner := local.NewScanner(applierApplier, ospkgScanner, langpkgScanner, client)
|
||||||
walkerVM := walker.NewVM()
|
walkerVM := walker.NewVM()
|
||||||
artifactArtifact, err := vm.NewArtifact(filePath, artifactCache, walkerVM, artifactOption)
|
artifactArtifact, err := vm.NewArtifact(filePath, cacheCache, walkerVM, artifactOption)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
cleanup()
|
||||||
return scanner.Scanner{}, nil, err
|
return scanner.Scanner{}, nil, err
|
||||||
}
|
}
|
||||||
scannerScanner := scanner.NewScanner(localScanner, artifactArtifact)
|
scannerScanner := scanner.NewScanner(localScanner, artifactArtifact)
|
||||||
return scannerScanner, func() {
|
return scannerScanner, func() {
|
||||||
|
cleanup()
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// initializeRemoteImageScanner is for container image scanning in client/server mode
|
// initializeRemoteImageScanner is for container image scanning in client/server mode
|
||||||
// e.g. dockerd, container registry, podman, etc.
|
// e.g. dockerd, container registry, podman, etc.
|
||||||
func initializeRemoteImageScanner(ctx context.Context, imageName string, artifactCache cache.ArtifactCache, remoteScanOptions client.ScannerOption, imageOpt types.ImageOptions, artifactOption artifact.Option) (scanner.Scanner, func(), error) {
|
func initializeRemoteImageScanner(ctx context.Context, imageName string, remoteCacheOptions cache.RemoteOptions, remoteScanOptions client.ScannerOption, imageOpt types.ImageOptions, artifactOption artifact.Option) (scanner.Scanner, func(), error) {
|
||||||
v := _wireValue
|
v := _wireValue
|
||||||
clientScanner := client.NewScanner(remoteScanOptions, v...)
|
clientScanner := client.NewScanner(remoteScanOptions, v...)
|
||||||
typesImage, cleanup, err := image.NewContainerImage(ctx, imageName, imageOpt)
|
typesImage, cleanup, err := image.NewContainerImage(ctx, imageName, imageOpt)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return scanner.Scanner{}, nil, err
|
return scanner.Scanner{}, nil, err
|
||||||
}
|
}
|
||||||
artifactArtifact, err := image2.NewArtifact(typesImage, artifactCache, artifactOption)
|
remoteCache := cache.NewRemoteCache(remoteCacheOptions)
|
||||||
|
artifactArtifact, err := image2.NewArtifact(typesImage, remoteCache, artifactOption)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
cleanup()
|
cleanup()
|
||||||
return scanner.Scanner{}, nil, err
|
return scanner.Scanner{}, nil, err
|
||||||
@@ -170,27 +210,30 @@ var (
|
|||||||
|
|
||||||
// initializeRemoteArchiveScanner is for container image archive scanning in client/server mode
|
// initializeRemoteArchiveScanner is for container image archive scanning in client/server mode
|
||||||
// e.g. docker save -o alpine.tar alpine:3.15
|
// e.g. docker save -o alpine.tar alpine:3.15
|
||||||
func initializeRemoteArchiveScanner(ctx context.Context, filePath string, artifactCache cache.ArtifactCache, remoteScanOptions client.ScannerOption, artifactOption artifact.Option) (scanner.Scanner, error) {
|
func initializeRemoteArchiveScanner(ctx context.Context, filePath string, remoteCacheOptions cache.RemoteOptions, remoteScanOptions client.ScannerOption, artifactOption artifact.Option) (scanner.Scanner, func(), error) {
|
||||||
v := _wireValue
|
v := _wireValue
|
||||||
clientScanner := client.NewScanner(remoteScanOptions, v...)
|
clientScanner := client.NewScanner(remoteScanOptions, v...)
|
||||||
typesImage, err := image.NewArchiveImage(filePath)
|
typesImage, err := image.NewArchiveImage(filePath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return scanner.Scanner{}, err
|
return scanner.Scanner{}, nil, err
|
||||||
}
|
}
|
||||||
artifactArtifact, err := image2.NewArtifact(typesImage, artifactCache, artifactOption)
|
remoteCache := cache.NewRemoteCache(remoteCacheOptions)
|
||||||
|
artifactArtifact, err := image2.NewArtifact(typesImage, remoteCache, artifactOption)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return scanner.Scanner{}, err
|
return scanner.Scanner{}, nil, err
|
||||||
}
|
}
|
||||||
scannerScanner := scanner.NewScanner(clientScanner, artifactArtifact)
|
scannerScanner := scanner.NewScanner(clientScanner, artifactArtifact)
|
||||||
return scannerScanner, nil
|
return scannerScanner, func() {
|
||||||
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// initializeRemoteFilesystemScanner is for filesystem scanning in client/server mode
|
// initializeRemoteFilesystemScanner is for filesystem scanning in client/server mode
|
||||||
func initializeRemoteFilesystemScanner(ctx context.Context, path string, artifactCache cache.ArtifactCache, remoteScanOptions client.ScannerOption, artifactOption artifact.Option) (scanner.Scanner, func(), error) {
|
func initializeRemoteFilesystemScanner(ctx context.Context, path string, remoteCacheOptions cache.RemoteOptions, remoteScanOptions client.ScannerOption, artifactOption artifact.Option) (scanner.Scanner, func(), error) {
|
||||||
v := _wireValue
|
v := _wireValue
|
||||||
clientScanner := client.NewScanner(remoteScanOptions, v...)
|
clientScanner := client.NewScanner(remoteScanOptions, v...)
|
||||||
|
remoteCache := cache.NewRemoteCache(remoteCacheOptions)
|
||||||
fs := walker.NewFS()
|
fs := walker.NewFS()
|
||||||
artifactArtifact, err := local2.NewArtifact(path, artifactCache, fs, artifactOption)
|
artifactArtifact, err := local2.NewArtifact(path, remoteCache, fs, artifactOption)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return scanner.Scanner{}, nil, err
|
return scanner.Scanner{}, nil, err
|
||||||
}
|
}
|
||||||
@@ -200,11 +243,12 @@ func initializeRemoteFilesystemScanner(ctx context.Context, path string, artifac
|
|||||||
}
|
}
|
||||||
|
|
||||||
// initializeRemoteRepositoryScanner is for repository scanning in client/server mode
|
// initializeRemoteRepositoryScanner is for repository scanning in client/server mode
|
||||||
func initializeRemoteRepositoryScanner(ctx context.Context, url string, artifactCache cache.ArtifactCache, remoteScanOptions client.ScannerOption, artifactOption artifact.Option) (scanner.Scanner, func(), error) {
|
func initializeRemoteRepositoryScanner(ctx context.Context, url string, remoteCacheOptions cache.RemoteOptions, remoteScanOptions client.ScannerOption, artifactOption artifact.Option) (scanner.Scanner, func(), error) {
|
||||||
v := _wireValue
|
v := _wireValue
|
||||||
clientScanner := client.NewScanner(remoteScanOptions, v...)
|
clientScanner := client.NewScanner(remoteScanOptions, v...)
|
||||||
|
remoteCache := cache.NewRemoteCache(remoteCacheOptions)
|
||||||
fs := walker.NewFS()
|
fs := walker.NewFS()
|
||||||
artifactArtifact, cleanup, err := repo.NewArtifact(url, artifactCache, fs, artifactOption)
|
artifactArtifact, cleanup, err := repo.NewArtifact(url, remoteCache, fs, artifactOption)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return scanner.Scanner{}, nil, err
|
return scanner.Scanner{}, nil, err
|
||||||
}
|
}
|
||||||
@@ -215,10 +259,11 @@ func initializeRemoteRepositoryScanner(ctx context.Context, url string, artifact
|
|||||||
}
|
}
|
||||||
|
|
||||||
// initializeRemoteSBOMScanner is for sbom scanning in client/server mode
|
// initializeRemoteSBOMScanner is for sbom scanning in client/server mode
|
||||||
func initializeRemoteSBOMScanner(ctx context.Context, path string, artifactCache cache.ArtifactCache, remoteScanOptions client.ScannerOption, artifactOption artifact.Option) (scanner.Scanner, func(), error) {
|
func initializeRemoteSBOMScanner(ctx context.Context, path string, remoteCacheOptions cache.RemoteOptions, remoteScanOptions client.ScannerOption, artifactOption artifact.Option) (scanner.Scanner, func(), error) {
|
||||||
v := _wireValue
|
v := _wireValue
|
||||||
clientScanner := client.NewScanner(remoteScanOptions, v...)
|
clientScanner := client.NewScanner(remoteScanOptions, v...)
|
||||||
artifactArtifact, err := sbom.NewArtifact(path, artifactCache, artifactOption)
|
remoteCache := cache.NewRemoteCache(remoteCacheOptions)
|
||||||
|
artifactArtifact, err := sbom.NewArtifact(path, remoteCache, artifactOption)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return scanner.Scanner{}, nil, err
|
return scanner.Scanner{}, nil, err
|
||||||
}
|
}
|
||||||
@@ -228,11 +273,12 @@ func initializeRemoteSBOMScanner(ctx context.Context, path string, artifactCache
|
|||||||
}
|
}
|
||||||
|
|
||||||
// initializeRemoteVMScanner is for vm scanning in client/server mode
|
// initializeRemoteVMScanner is for vm scanning in client/server mode
|
||||||
func initializeRemoteVMScanner(ctx context.Context, path string, artifactCache cache.ArtifactCache, remoteScanOptions client.ScannerOption, artifactOption artifact.Option) (scanner.Scanner, func(), error) {
|
func initializeRemoteVMScanner(ctx context.Context, path string, remoteCacheOptions cache.RemoteOptions, remoteScanOptions client.ScannerOption, artifactOption artifact.Option) (scanner.Scanner, func(), error) {
|
||||||
v := _wireValue
|
v := _wireValue
|
||||||
clientScanner := client.NewScanner(remoteScanOptions, v...)
|
clientScanner := client.NewScanner(remoteScanOptions, v...)
|
||||||
|
remoteCache := cache.NewRemoteCache(remoteCacheOptions)
|
||||||
walkerVM := walker.NewVM()
|
walkerVM := walker.NewVM()
|
||||||
artifactArtifact, err := vm.NewArtifact(path, artifactCache, walkerVM, artifactOption)
|
artifactArtifact, err := vm.NewArtifact(path, remoteCache, walkerVM, artifactOption)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return scanner.Scanner{}, nil, err
|
return scanner.Scanner{}, nil, err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -62,10 +62,12 @@ func cleanAll(ctx context.Context, opts flag.Options) error {
|
|||||||
|
|
||||||
func cleanScanCache(ctx context.Context, opts flag.Options) error {
|
func cleanScanCache(ctx context.Context, opts flag.Options) error {
|
||||||
log.InfoContext(ctx, "Removing scan cache...")
|
log.InfoContext(ctx, "Removing scan cache...")
|
||||||
c, err := cache.New(opts.CacheDir, opts.CacheBackendOptions)
|
c, cleanup, err := cache.New(opts.CacheOpts())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return xerrors.Errorf("failed to instantiate cache client: %w", err)
|
return xerrors.Errorf("failed to instantiate cache client: %w", err)
|
||||||
}
|
}
|
||||||
|
defer cleanup()
|
||||||
|
|
||||||
if err = c.Clear(); err != nil {
|
if err = c.Clear(); err != nil {
|
||||||
return xerrors.Errorf("clear scan cache: %w", err)
|
return xerrors.Errorf("clear scan cache: %w", err)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import (
|
|||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
|
|
||||||
|
"github.com/aquasecurity/trivy/pkg/cache"
|
||||||
"github.com/aquasecurity/trivy/pkg/commands/clean"
|
"github.com/aquasecurity/trivy/pkg/commands/clean"
|
||||||
"github.com/aquasecurity/trivy/pkg/flag"
|
"github.com/aquasecurity/trivy/pkg/flag"
|
||||||
)
|
)
|
||||||
@@ -100,6 +101,9 @@ func TestRun(t *testing.T) {
|
|||||||
GlobalOptions: flag.GlobalOptions{
|
GlobalOptions: flag.GlobalOptions{
|
||||||
CacheDir: tempDir,
|
CacheDir: tempDir,
|
||||||
},
|
},
|
||||||
|
CacheOptions: flag.CacheOptions{
|
||||||
|
CacheBackend: string(cache.TypeFS),
|
||||||
|
},
|
||||||
CleanOptions: tt.cleanOpts,
|
CleanOptions: tt.cleanOpts,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -19,12 +19,11 @@ func Run(ctx context.Context, opts flag.Options) (err error) {
|
|||||||
log.InitLogger(opts.Debug, opts.Quiet)
|
log.InitLogger(opts.Debug, opts.Quiet)
|
||||||
|
|
||||||
// configure cache dir
|
// configure cache dir
|
||||||
cacheClient, err := cache.New(opts.CacheDir, opts.CacheOptions.CacheBackendOptions)
|
cacheClient, cleanup, err := cache.New(opts.CacheOpts())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return xerrors.Errorf("server cache error: %w", err)
|
return xerrors.Errorf("server cache error: %w", err)
|
||||||
}
|
}
|
||||||
defer cacheClient.Close()
|
defer cleanup()
|
||||||
log.Debug("Cache", log.String("dir", opts.CacheDir))
|
|
||||||
|
|
||||||
// download the database file
|
// download the database file
|
||||||
if err = operation.DownloadDB(ctx, opts.AppVersion, opts.CacheDir, opts.DBRepository,
|
if err = operation.DownloadDB(ctx, opts.AppVersion, opts.CacheDir, opts.DBRepository,
|
||||||
|
|||||||
@@ -2,10 +2,6 @@ package flag
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"golang.org/x/xerrors"
|
|
||||||
|
|
||||||
"github.com/aquasecurity/trivy/pkg/cache"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// e.g. config yaml:
|
// e.g. config yaml:
|
||||||
@@ -72,13 +68,18 @@ type CacheFlagGroup struct {
|
|||||||
|
|
||||||
type CacheOptions struct {
|
type CacheOptions struct {
|
||||||
ClearCache bool
|
ClearCache bool
|
||||||
CacheBackendOptions cache.Options
|
|
||||||
|
CacheBackend string
|
||||||
|
CacheTTL time.Duration
|
||||||
|
RedisTLS bool
|
||||||
|
RedisCACert string
|
||||||
|
RedisCert string
|
||||||
|
RedisKey string
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewCacheFlagGroup returns a default CacheFlagGroup
|
// NewCacheFlagGroup returns a default CacheFlagGroup
|
||||||
func NewCacheFlagGroup() *CacheFlagGroup {
|
func NewCacheFlagGroup() *CacheFlagGroup {
|
||||||
return &CacheFlagGroup{
|
return &CacheFlagGroup{
|
||||||
ClearCache: ClearCacheFlag.Clone(),
|
|
||||||
CacheBackend: CacheBackendFlag.Clone(),
|
CacheBackend: CacheBackendFlag.Clone(),
|
||||||
CacheTTL: CacheTTLFlag.Clone(),
|
CacheTTL: CacheTTLFlag.Clone(),
|
||||||
RedisTLS: RedisTLSFlag.Clone(),
|
RedisTLS: RedisTLSFlag.Clone(),
|
||||||
@@ -109,14 +110,12 @@ func (fg *CacheFlagGroup) ToOptions() (CacheOptions, error) {
|
|||||||
return CacheOptions{}, err
|
return CacheOptions{}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
backendOpts, err := cache.NewOptions(fg.CacheBackend.Value(), fg.RedisCACert.Value(), fg.RedisCert.Value(),
|
|
||||||
fg.RedisKey.Value(), fg.RedisTLS.Value(), fg.CacheTTL.Value())
|
|
||||||
if err != nil {
|
|
||||||
return CacheOptions{}, xerrors.Errorf("failed to initialize cache options: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return CacheOptions{
|
return CacheOptions{
|
||||||
ClearCache: fg.ClearCache.Value(),
|
CacheBackend: fg.CacheBackend.Value(),
|
||||||
CacheBackendOptions: backendOpts,
|
CacheTTL: fg.CacheTTL.Value(),
|
||||||
|
RedisTLS: fg.RedisTLS.Value(),
|
||||||
|
RedisCACert: fg.RedisCACert.Value(),
|
||||||
|
RedisCert: fg.RedisCert.Value(),
|
||||||
|
RedisKey: fg.RedisKey.Value(),
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import (
|
|||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
|
|
||||||
"github.com/aquasecurity/trivy/pkg/cache"
|
"github.com/aquasecurity/trivy/pkg/cache"
|
||||||
|
"github.com/aquasecurity/trivy/pkg/log"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@@ -144,6 +145,8 @@ func (f *GlobalFlagGroup) ToOptions() (GlobalOptions, error) {
|
|||||||
// Keep TRIVY_NON_SSL for backward compatibility
|
// Keep TRIVY_NON_SSL for backward compatibility
|
||||||
insecure := f.Insecure.Value() || os.Getenv("TRIVY_NON_SSL") != ""
|
insecure := f.Insecure.Value() || os.Getenv("TRIVY_NON_SSL") != ""
|
||||||
|
|
||||||
|
log.Debug("Cache dir", log.String("dir", f.CacheDir.Value()))
|
||||||
|
|
||||||
return GlobalOptions{
|
return GlobalOptions{
|
||||||
ConfigFile: f.ConfigFile.Value(),
|
ConfigFile: f.ConfigFile.Value(),
|
||||||
ShowVersion: f.ShowVersion.Value(),
|
ShowVersion: f.ShowVersion.Value(),
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ import (
|
|||||||
"github.com/spf13/viper"
|
"github.com/spf13/viper"
|
||||||
"golang.org/x/xerrors"
|
"golang.org/x/xerrors"
|
||||||
|
|
||||||
|
"github.com/aquasecurity/trivy/pkg/cache"
|
||||||
"github.com/aquasecurity/trivy/pkg/fanal/analyzer"
|
"github.com/aquasecurity/trivy/pkg/fanal/analyzer"
|
||||||
ftypes "github.com/aquasecurity/trivy/pkg/fanal/types"
|
ftypes "github.com/aquasecurity/trivy/pkg/fanal/types"
|
||||||
"github.com/aquasecurity/trivy/pkg/log"
|
"github.com/aquasecurity/trivy/pkg/log"
|
||||||
@@ -448,6 +449,28 @@ func (o *Options) FilterOpts() result.FilterOption {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// CacheOpts returns options for scan cache
|
||||||
|
func (o *Options) CacheOpts() cache.Options {
|
||||||
|
return cache.Options{
|
||||||
|
Backend: o.CacheBackend,
|
||||||
|
CacheDir: o.CacheDir,
|
||||||
|
RedisCACert: o.RedisCACert,
|
||||||
|
RedisCert: o.RedisCert,
|
||||||
|
RedisKey: o.RedisKey,
|
||||||
|
RedisTLS: o.RedisTLS,
|
||||||
|
TTL: o.CacheTTL,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// RemoteCacheOpts returns options for remote scan cache
|
||||||
|
func (o *Options) RemoteCacheOpts() cache.RemoteOptions {
|
||||||
|
return cache.RemoteOptions{
|
||||||
|
ServerAddr: o.ServerAddr,
|
||||||
|
CustomHeaders: o.CustomHeaders,
|
||||||
|
Insecure: o.Insecure,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// SetOutputWriter sets an output writer.
|
// SetOutputWriter sets an output writer.
|
||||||
func (o *Options) SetOutputWriter(w io.Writer) {
|
func (o *Options) SetOutputWriter(w io.Writer) {
|
||||||
o.outputWriter = w
|
o.outputWriter = w
|
||||||
|
|||||||
@@ -8,8 +8,8 @@ package k8s
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/aquasecurity/trivy-db/pkg/db"
|
"github.com/aquasecurity/trivy-db/pkg/db"
|
||||||
"github.com/aquasecurity/trivy/pkg/fanal/applier"
|
|
||||||
"github.com/aquasecurity/trivy/pkg/cache"
|
"github.com/aquasecurity/trivy/pkg/cache"
|
||||||
|
"github.com/aquasecurity/trivy/pkg/fanal/applier"
|
||||||
"github.com/aquasecurity/trivy/pkg/scanner/langpkg"
|
"github.com/aquasecurity/trivy/pkg/scanner/langpkg"
|
||||||
"github.com/aquasecurity/trivy/pkg/scanner/local"
|
"github.com/aquasecurity/trivy/pkg/scanner/local"
|
||||||
"github.com/aquasecurity/trivy/pkg/scanner/ospkg"
|
"github.com/aquasecurity/trivy/pkg/scanner/ospkg"
|
||||||
|
|||||||
@@ -8,8 +8,8 @@ package server
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/aquasecurity/trivy-db/pkg/db"
|
"github.com/aquasecurity/trivy-db/pkg/db"
|
||||||
"github.com/aquasecurity/trivy/pkg/fanal/applier"
|
|
||||||
"github.com/aquasecurity/trivy/pkg/cache"
|
"github.com/aquasecurity/trivy/pkg/cache"
|
||||||
|
"github.com/aquasecurity/trivy/pkg/fanal/applier"
|
||||||
"github.com/aquasecurity/trivy/pkg/scanner/langpkg"
|
"github.com/aquasecurity/trivy/pkg/scanner/langpkg"
|
||||||
"github.com/aquasecurity/trivy/pkg/scanner/local"
|
"github.com/aquasecurity/trivy/pkg/scanner/local"
|
||||||
"github.com/aquasecurity/trivy/pkg/scanner/ospkg"
|
"github.com/aquasecurity/trivy/pkg/scanner/ospkg"
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import (
|
|||||||
"github.com/google/wire"
|
"github.com/google/wire"
|
||||||
"golang.org/x/xerrors"
|
"golang.org/x/xerrors"
|
||||||
|
|
||||||
|
"github.com/aquasecurity/trivy/pkg/cache"
|
||||||
"github.com/aquasecurity/trivy/pkg/clock"
|
"github.com/aquasecurity/trivy/pkg/clock"
|
||||||
"github.com/aquasecurity/trivy/pkg/fanal/artifact"
|
"github.com/aquasecurity/trivy/pkg/fanal/artifact"
|
||||||
aimage "github.com/aquasecurity/trivy/pkg/fanal/artifact/image"
|
aimage "github.com/aquasecurity/trivy/pkg/fanal/artifact/image"
|
||||||
@@ -28,6 +29,11 @@ import (
|
|||||||
|
|
||||||
// StandaloneSuperSet is used in the standalone mode
|
// StandaloneSuperSet is used in the standalone mode
|
||||||
var StandaloneSuperSet = wire.NewSet(
|
var StandaloneSuperSet = wire.NewSet(
|
||||||
|
// Cache
|
||||||
|
cache.New,
|
||||||
|
wire.Bind(new(cache.ArtifactCache), new(cache.Cache)),
|
||||||
|
wire.Bind(new(cache.LocalArtifactCache), new(cache.Cache)),
|
||||||
|
|
||||||
local.SuperSet,
|
local.SuperSet,
|
||||||
wire.Bind(new(Driver), new(local.Scanner)),
|
wire.Bind(new(Driver), new(local.Scanner)),
|
||||||
NewScanner,
|
NewScanner,
|
||||||
@@ -77,6 +83,10 @@ var StandaloneVMSet = wire.NewSet(
|
|||||||
|
|
||||||
// RemoteSuperSet is used in the client mode
|
// RemoteSuperSet is used in the client mode
|
||||||
var RemoteSuperSet = wire.NewSet(
|
var RemoteSuperSet = wire.NewSet(
|
||||||
|
// Cache
|
||||||
|
cache.NewRemoteCache,
|
||||||
|
wire.Bind(new(cache.ArtifactCache), new(*cache.RemoteCache)), // No need for LocalArtifactCache
|
||||||
|
|
||||||
client.NewScanner,
|
client.NewScanner,
|
||||||
wire.Value([]client.Option(nil)),
|
wire.Value([]client.Option(nil)),
|
||||||
wire.Bind(new(Driver), new(client.Scanner)),
|
wire.Bind(new(Driver), new(client.Scanner)),
|
||||||
|
|||||||
Reference in New Issue
Block a user