mirror of
https://github.com/aquasecurity/trivy.git
synced 2025-12-12 07:40:48 -08:00
refactor: unify cache implementations (#6977)
Signed-off-by: knqyf263 <knqyf263@gmail.com>
This commit is contained in:
23
go.mod
23
go.mod
@@ -30,13 +30,12 @@ require (
|
||||
github.com/aquasecurity/trivy-java-db v0.0.0-20240109071736-184bd7481d48
|
||||
github.com/aquasecurity/trivy-kubernetes v0.6.7-0.20240516051533-4c5a4aad13b7
|
||||
github.com/aws/aws-sdk-go-v2 v1.27.2
|
||||
github.com/aws/aws-sdk-go-v2/config v1.27.15
|
||||
github.com/aws/aws-sdk-go-v2/credentials v1.17.15
|
||||
github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.16.20
|
||||
github.com/aws/aws-sdk-go-v2/service/ec2 v1.161.3
|
||||
github.com/aws/aws-sdk-go-v2/service/ecr v1.28.2
|
||||
github.com/aws/aws-sdk-go-v2/service/s3 v1.54.2
|
||||
github.com/aws/aws-sdk-go-v2/service/sts v1.28.9 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/config v1.27.18
|
||||
github.com/aws/aws-sdk-go-v2/credentials v1.17.18
|
||||
github.com/aws/aws-sdk-go-v2/service/ec2 v1.163.1
|
||||
github.com/aws/aws-sdk-go-v2/service/ecr v1.28.5
|
||||
github.com/aws/aws-sdk-go-v2/service/s3 v1.55.1
|
||||
github.com/aws/aws-sdk-go-v2/service/sts v1.28.12 // indirect
|
||||
github.com/aws/smithy-go v1.20.2
|
||||
github.com/bitnami/go-version v0.0.0-20231130084017-bb00604d650c
|
||||
github.com/bmatcuk/doublestar/v4 v4.6.1
|
||||
@@ -169,19 +168,15 @@ require (
|
||||
github.com/apparentlymart/go-textseg/v15 v15.0.0 // indirect
|
||||
github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 // indirect
|
||||
github.com/aws/aws-sdk-go v1.53.0 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.6.2 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.5 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.9 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.9 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.0 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/internal/v4a v1.3.7 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/ebs v1.21.7 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.11.2 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.3.9 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.11.9 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.17.7 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/sso v1.20.8 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.24.2 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.11.11 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/sso v1.20.11 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.24.5 // indirect
|
||||
github.com/beorn7/perks v1.0.1 // indirect
|
||||
github.com/bgentry/go-netrc v0.0.0-20140422174119-9fd32a8b3d3d // indirect
|
||||
github.com/briandowns/spinner v1.23.0 // indirect
|
||||
|
||||
46
go.sum
46
go.sum
@@ -791,46 +791,36 @@ github.com/aws/aws-sdk-go v1.53.0 h1:MMo1x1ggPPxDfHMXJnQudTbGXYlD4UigUAud1DJxPVo
|
||||
github.com/aws/aws-sdk-go v1.53.0/go.mod h1:LF8svs817+Nz+DmiMQKTO3ubZ/6IaTpq3TjupRn3Eqk=
|
||||
github.com/aws/aws-sdk-go-v2 v1.27.2 h1:pLsTXqX93rimAOZG2FIYraDQstZaaGVVN4tNw65v0h8=
|
||||
github.com/aws/aws-sdk-go-v2 v1.27.2/go.mod h1:ffIFB97e2yNsv4aTSGkqtHnppsIJzw7G7BReUZ3jCXM=
|
||||
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.6.2 h1:x6xsQXGSmW6frevwDA+vi/wqhp1ct18mVXYN08/93to=
|
||||
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.6.2/go.mod h1:lPprDr1e6cJdyYeGXnRaJoP4Md+cDBvi2eOj00BlGmg=
|
||||
github.com/aws/aws-sdk-go-v2/config v1.27.15 h1:uNnGLZ+DutuNEkuPh6fwqK7LpEiPmzb7MIMA1mNWEUc=
|
||||
github.com/aws/aws-sdk-go-v2/config v1.27.15/go.mod h1:7j7Kxx9/7kTmL7z4LlhwQe63MYEE5vkVV6nWg4ZAI8M=
|
||||
github.com/aws/aws-sdk-go-v2/credentials v1.17.15 h1:YDexlvDRCA8ems2T5IP1xkMtOZ1uLJOCJdTr0igs5zo=
|
||||
github.com/aws/aws-sdk-go-v2/credentials v1.17.15/go.mod h1:vxHggqW6hFNaeNC0WyXS3VdyjcV0a4KMUY4dKJ96buU=
|
||||
github.com/aws/aws-sdk-go-v2/config v1.27.18 h1:wFvAnwOKKe7QAyIxziwSKjmer9JBMH1vzIL6W+fYuKk=
|
||||
github.com/aws/aws-sdk-go-v2/config v1.27.18/go.mod h1:0xz6cgdX55+kmppvPm2IaKzIXOheGJhAufacPJaXZ7c=
|
||||
github.com/aws/aws-sdk-go-v2/credentials v1.17.18 h1:D/ALDWqK4JdY3OFgA2thcPO1c9aYTT5STS/CvnkqY1c=
|
||||
github.com/aws/aws-sdk-go-v2/credentials v1.17.18/go.mod h1:JuitCWq+F5QGUrmMPsk945rop6bB57jdscu+Glozdnc=
|
||||
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.5 h1:dDgptDO9dxeFkXy+tEgVkzSClHZje/6JkPW5aZyEvrQ=
|
||||
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.5/go.mod h1:gjvE2KBUgUQhcv89jqxrIxH9GaKs1JbZzWejj/DaHGA=
|
||||
github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.16.20 h1:NCM9wYaJCmlIWZSO/JwUEveKf0NCvsSgo9V9BwOAolo=
|
||||
github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.16.20/go.mod h1:dmxIx3qriuepxqZgFeFMitFuftWPB94+MZv/6Btpth4=
|
||||
github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.9 h1:cy8ahBJuhtM8GTTSyOkfy6WVPV1IE+SS5/wfXUYuulw=
|
||||
github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.9/go.mod h1:CZBXGLaJnEZI6EVNcPd7a6B5IC5cA/GkRWtu9fp3S6Y=
|
||||
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.9 h1:A4SYk07ef04+vxZToz9LWvAXl9LW0NClpPpMsi31cz0=
|
||||
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.9/go.mod h1:5jJcHuwDagxN+ErjQ3PU3ocf6Ylc/p9x+BLO/+X4iXw=
|
||||
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.0 h1:hT8rVHwugYE2lEfdFE0QWVo81lF7jMrYJVDWI+f+VxU=
|
||||
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.0/go.mod h1:8tu/lYfQfFe6IGnaOdrpVgEL2IrrDOf6/m9RQum4NkY=
|
||||
github.com/aws/aws-sdk-go-v2/internal/v4a v1.3.7 h1:/FUtT3xsoHO3cfh+I/kCbcMCN98QZRsiFet/V8QkWSs=
|
||||
github.com/aws/aws-sdk-go-v2/internal/v4a v1.3.7/go.mod h1:MaCAgWpGooQoCWZnMur97rGn5dp350w2+CeiV5406wE=
|
||||
github.com/aws/aws-sdk-go-v2/service/ebs v1.21.7 h1:CRzzXjmgx9p362yO39D6hbZULdMI23gaKqSxijJCXHM=
|
||||
github.com/aws/aws-sdk-go-v2/service/ebs v1.21.7/go.mod h1:wnsHqpi3RgDwklS5SPHUgjcUUpontGPKJ+GJYOdV7pY=
|
||||
github.com/aws/aws-sdk-go-v2/service/ec2 v1.161.3 h1:l0mvKOGm25yo/Fy+Y/08Cm4aTA4XmnIuq4ppy+shfMI=
|
||||
github.com/aws/aws-sdk-go-v2/service/ec2 v1.161.3/go.mod h1:iJ2sQeUTkjNp3nL7kE/Bav0xXYhtiRCRP5ZXk4jFhCQ=
|
||||
github.com/aws/aws-sdk-go-v2/service/ecr v1.28.2 h1:xUpMnRZonKfrHaNLC77IMpWZSUMRRXIi6IU5EhAPsrM=
|
||||
github.com/aws/aws-sdk-go-v2/service/ecr v1.28.2/go.mod h1:X52zjAVRaXklEU1TE/wO8kyyJSr9cJx9ZsqliWbyRys=
|
||||
github.com/aws/aws-sdk-go-v2/service/ec2 v1.163.1 h1:0RiDkJO1veM6/FQ+GJcGiIhZgPwXlscX29B0zFE4Ulo=
|
||||
github.com/aws/aws-sdk-go-v2/service/ec2 v1.163.1/go.mod h1:gYk1NtyvkH1SxPcndDtfro3lwbiE5t0tW4eRki5YnOQ=
|
||||
github.com/aws/aws-sdk-go-v2/service/ecr v1.28.5 h1:dvvTFXpWSv9+8lTNPl1EPNZL6BCUV6MgVckEMvXaOgk=
|
||||
github.com/aws/aws-sdk-go-v2/service/ecr v1.28.5/go.mod h1:Ogt6AOZ/sPBlJZpVFJgOK+jGGREuo8DMjNg+O/7gpjI=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.11.2 h1:Ji0DY1xUsUr3I8cHps0G+XM3WWU16lP6yG8qu1GAZAs=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.11.2/go.mod h1:5CsjAbs3NlGQyZNFACh+zztPDI7fU6eW9QsxjfnuBKg=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.3.9 h1:UXqEWQI0n+q0QixzU0yUUQBZXRd5037qdInTIHFTl98=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.3.9/go.mod h1:xP6Gq6fzGZT8w/ZN+XvGMZ2RU1LeEs7b2yUP5DN8NY4=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.11.9 h1:Wx0rlZoEJR7JwlSZcHnEa7CNjrSIyVxMFWGAaXy4fJY=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.11.9/go.mod h1:aVMHdE0aHO3v+f/iw01fmXV/5DbfQ3Bi9nN7nd9bE9Y=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.17.7 h1:uO5XR6QGBcmPyo2gxofYJLFkcVQ4izOoGDNenlZhTEk=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.17.7/go.mod h1:feeeAYfAcwTReM6vbwjEyDmiGho+YgBhaFULuXDW8kc=
|
||||
github.com/aws/aws-sdk-go-v2/service/s3 v1.54.2 h1:gYSJhNiOF6J9xaYxu2NFNstoiNELwt0T9w29FxSfN+Y=
|
||||
github.com/aws/aws-sdk-go-v2/service/s3 v1.54.2/go.mod h1:739CllldowZiPPsDFcJHNF4FXrVxaSGVnZ9Ez9Iz9hc=
|
||||
github.com/aws/aws-sdk-go-v2/service/sso v1.20.8 h1:Kv1hwNG6jHC/sxMTe5saMjH6t6ZLkgfvVxyEjfWL1ks=
|
||||
github.com/aws/aws-sdk-go-v2/service/sso v1.20.8/go.mod h1:c1qtZUWtygI6ZdvKppzCSXsDOq5I4luJPZ0Ud3juFCA=
|
||||
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.24.2 h1:nWBZ1xHCF+A7vv9sDzJOq4NWIdzFYm0kH7Pr4OjHYsQ=
|
||||
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.24.2/go.mod h1:9lmoVDVLz/yUZwLaQ676TK02fhCu4+PgRSmMaKR1ozk=
|
||||
github.com/aws/aws-sdk-go-v2/service/sts v1.28.9 h1:Qp6Boy0cGDloOE3zI6XhNLNZgjNS8YmiFQFHe71SaW0=
|
||||
github.com/aws/aws-sdk-go-v2/service/sts v1.28.9/go.mod h1:0Aqn1MnEuitqfsCNyKsdKLhDUOr4txD/g19EfiUqgws=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.11.11 h1:o4T+fKxA3gTMcluBNZZXE9DNaMkJuUL1O3mffCUjoJo=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.11.11/go.mod h1:84oZdJ+VjuJKs9v1UTC9NaodRZRseOXCTgku+vQJWR8=
|
||||
github.com/aws/aws-sdk-go-v2/service/s3 v1.55.1 h1:UAxBuh0/8sFJk1qOkvOKewP5sWeWaTPDknbQz0ZkDm0=
|
||||
github.com/aws/aws-sdk-go-v2/service/s3 v1.55.1/go.mod h1:hWjsYGjVuqCgfoveVcVFPXIWgz0aByzwaxKlN1StKcM=
|
||||
github.com/aws/aws-sdk-go-v2/service/sso v1.20.11 h1:gEYM2GSpr4YNWc6hCd5nod4+d4kd9vWIAWrmGuLdlMw=
|
||||
github.com/aws/aws-sdk-go-v2/service/sso v1.20.11/go.mod h1:gVvwPdPNYehHSP9Rs7q27U1EU+3Or2ZpXvzAYJNh63w=
|
||||
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.24.5 h1:iXjh3uaH3vsVcnyZX7MqCoCfcyxIrVE9iOQruRaWPrQ=
|
||||
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.24.5/go.mod h1:5ZXesEuy/QcO0WUnt+4sDkxhdXRHTu2yG0uCSH8B6os=
|
||||
github.com/aws/aws-sdk-go-v2/service/sts v1.28.12 h1:M/1u4HBpwLuMtjlxuI2y6HoVLzF5e2mfxHCg7ZVMYmk=
|
||||
github.com/aws/aws-sdk-go-v2/service/sts v1.28.12/go.mod h1:kcfd+eTdEi/40FIbLq4Hif3XMXnl5b/+t/KTfLt9xIk=
|
||||
github.com/aws/smithy-go v1.20.2 h1:tbp628ireGtzcHDDmLT/6ADHidqnwgF57XOXZe6tp4Q=
|
||||
github.com/aws/smithy-go v1.20.2/go.mod h1:krry+ya/rV9RDcV/Q16kpu6ypI4K2czasz0NC3qS14E=
|
||||
github.com/beorn7/perks v0.0.0-20160804104726-4c0e84591b9a/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
|
||||
|
||||
200
pkg/cache/client.go
vendored
Normal file
200
pkg/cache/client.go
vendored
Normal file
@@ -0,0 +1,200 @@
|
||||
package cache
|
||||
|
||||
import (
|
||||
"crypto/tls"
|
||||
"crypto/x509"
|
||||
"fmt"
|
||||
"os"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/go-redis/redis/v8"
|
||||
"github.com/samber/lo"
|
||||
"golang.org/x/xerrors"
|
||||
|
||||
"github.com/aquasecurity/trivy/pkg/log"
|
||||
)
|
||||
|
||||
const (
|
||||
TypeFS Type = "fs"
|
||||
TypeRedis Type = "redis"
|
||||
)
|
||||
|
||||
type Client struct {
|
||||
Cache
|
||||
}
|
||||
|
||||
type Type string
|
||||
|
||||
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
|
||||
TLS bool
|
||||
TLSOptions RedisTLSOptions
|
||||
}
|
||||
|
||||
// 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
|
||||
}
|
||||
|
||||
func NewType(backend string) (Type, error) {
|
||||
// "redis://" or "fs" are allowed for now
|
||||
// An empty value is also allowed for testability
|
||||
switch {
|
||||
case strings.HasPrefix(backend, "redis://"):
|
||||
return TypeRedis, nil
|
||||
case backend == "fs", backend == "":
|
||||
return TypeFS, nil
|
||||
default:
|
||||
return "", xerrors.Errorf("unknown cache backend: %s", backend)
|
||||
}
|
||||
}
|
||||
|
||||
// NewClient returns a new cache client
|
||||
func NewClient(opts Options) (*Client, error) {
|
||||
if opts.Type == TypeRedis {
|
||||
log.Info("Redis cache", log.String("url", opts.Redis.BackendMasked()))
|
||||
options, err := redis.ParseURL(opts.Redis.Backend)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if tlsOpts := opts.Redis.TLSOptions; !lo.IsEmpty(tlsOpts) {
|
||||
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,
|
||||
}
|
||||
}
|
||||
|
||||
redisCache := NewRedisCache(options, opts.TTL)
|
||||
return &Client{Cache: redisCache}, nil
|
||||
}
|
||||
|
||||
// standalone mode
|
||||
fsCache, err := NewFSCache(Dir())
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("unable to initialize fs cache: %w", err)
|
||||
}
|
||||
return &Client{Cache: fsCache}, nil
|
||||
}
|
||||
|
||||
// Reset resets the cache
|
||||
func (c *Client) Reset() (err error) {
|
||||
if err := c.ClearDB(); err != nil {
|
||||
return xerrors.Errorf("failed to clear the database: %w", err)
|
||||
}
|
||||
if err := c.ClearArtifacts(); err != nil {
|
||||
return xerrors.Errorf("failed to clear the artifact cache: %w", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// ClearDB clears the DB cache
|
||||
func (c *Client) ClearDB() (err error) {
|
||||
log.Info("Removing DB file...")
|
||||
if err = os.RemoveAll(Dir()); err != nil {
|
||||
return xerrors.Errorf("failed to remove the directory (%s) : %w", Dir(), err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// ClearArtifacts clears the artifact cache
|
||||
func (c *Client) ClearArtifacts() error {
|
||||
log.Info("Removing artifact caches...")
|
||||
if err := c.Clear(); err != nil {
|
||||
return xerrors.Errorf("failed to remove the cache: %w", err)
|
||||
}
|
||||
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
|
||||
}
|
||||
129
pkg/cache/client_test.go
vendored
Normal file
129
pkg/cache/client_test.go
vendored
Normal file
@@ -0,0 +1,129 @@
|
||||
package cache_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/aquasecurity/trivy/pkg/cache"
|
||||
)
|
||||
|
||||
func TestNewOptions(t *testing.T) {
|
||||
type args struct {
|
||||
backend string
|
||||
redisCACert string
|
||||
redisCert string
|
||||
redisKey string
|
||||
redisTLS bool
|
||||
ttl time.Duration
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
want cache.Options
|
||||
assertion require.ErrorAssertionFunc
|
||||
}{
|
||||
{
|
||||
name: "fs",
|
||||
args: args{backend: "fs"},
|
||||
want: cache.Options{Type: cache.TypeFS},
|
||||
assertion: require.NoError,
|
||||
},
|
||||
{
|
||||
name: "redis",
|
||||
args: args{backend: "redis://localhost:6379"},
|
||||
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",
|
||||
TLSOptions: cache.RedisTLSOptions{
|
||||
CACert: "ca-cert.pem",
|
||||
Cert: "cert.pem",
|
||||
Key: "key.pem",
|
||||
},
|
||||
},
|
||||
},
|
||||
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",
|
||||
args: args{backend: "unknown"},
|
||||
assertion: func(t require.TestingT, err error, msgs ...any) {
|
||||
require.ErrorContains(t, err, "unknown cache backend")
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "sad redis tls",
|
||||
args: args{
|
||||
backend: "redis://localhost:6379",
|
||||
redisCACert: "ca-cert.pem",
|
||||
},
|
||||
assertion: func(t require.TestingT, err error, msgs ...any) {
|
||||
require.ErrorContains(t, err, "you must provide Redis CA, cert and key file path when using TLS")
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
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)
|
||||
tt.assertion(t, err)
|
||||
assert.Equal(t, tt.want, got)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
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())
|
||||
})
|
||||
}
|
||||
}
|
||||
30
pkg/cache/dir.go
vendored
Normal file
30
pkg/cache/dir.go
vendored
Normal file
@@ -0,0 +1,30 @@
|
||||
package cache
|
||||
|
||||
import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
)
|
||||
|
||||
var cacheDir string
|
||||
|
||||
// defaultDir returns/creates the cache-dir to be used for trivy operations
|
||||
func defaultDir() string {
|
||||
tmpDir, err := os.UserCacheDir()
|
||||
if err != nil {
|
||||
tmpDir = os.TempDir()
|
||||
}
|
||||
return filepath.Join(tmpDir, "trivy")
|
||||
}
|
||||
|
||||
// Dir returns the directory used for caching
|
||||
func Dir() string {
|
||||
if cacheDir == "" {
|
||||
return defaultDir()
|
||||
}
|
||||
return cacheDir
|
||||
}
|
||||
|
||||
// SetDir sets the trivy cache dir
|
||||
func SetDir(dir string) {
|
||||
cacheDir = dir
|
||||
}
|
||||
0
pkg/fanal/cache/fs.go → pkg/cache/fs.go
vendored
0
pkg/fanal/cache/fs.go → pkg/cache/fs.go
vendored
19
pkg/cache/nop.go
vendored
19
pkg/cache/nop.go
vendored
@@ -1,16 +1,11 @@
|
||||
package cache
|
||||
|
||||
import "github.com/aquasecurity/trivy/pkg/fanal/cache"
|
||||
import "github.com/aquasecurity/trivy/pkg/fanal/types"
|
||||
|
||||
func NopCache(ac cache.ArtifactCache) cache.Cache {
|
||||
return nopCache{ArtifactCache: ac}
|
||||
}
|
||||
type NopCache struct{}
|
||||
|
||||
type nopCache struct {
|
||||
cache.ArtifactCache
|
||||
cache.LocalArtifactCache
|
||||
}
|
||||
|
||||
func (nopCache) Close() error {
|
||||
return nil
|
||||
}
|
||||
func NewNopCache() NopCache { return NopCache{} }
|
||||
func (NopCache) GetArtifact(string) (types.ArtifactInfo, error) { return types.ArtifactInfo{}, nil }
|
||||
func (NopCache) GetBlob(string) (types.BlobInfo, error) { return types.BlobInfo{}, nil }
|
||||
func (NopCache) Close() error { return nil }
|
||||
func (NopCache) Clear() error { return nil }
|
||||
|
||||
@@ -11,7 +11,7 @@ import (
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/aquasecurity/trivy/pkg/fanal/cache"
|
||||
"github.com/aquasecurity/trivy/pkg/cache"
|
||||
"github.com/aquasecurity/trivy/pkg/fanal/types"
|
||||
)
|
||||
|
||||
8
pkg/cache/remote.go
vendored
8
pkg/cache/remote.go
vendored
@@ -7,7 +7,6 @@ import (
|
||||
|
||||
"golang.org/x/xerrors"
|
||||
|
||||
"github.com/aquasecurity/trivy/pkg/fanal/cache"
|
||||
"github.com/aquasecurity/trivy/pkg/fanal/types"
|
||||
"github.com/aquasecurity/trivy/pkg/rpc"
|
||||
"github.com/aquasecurity/trivy/pkg/rpc/client"
|
||||
@@ -21,7 +20,7 @@ type RemoteCache struct {
|
||||
}
|
||||
|
||||
// NewRemoteCache is the factory method for RemoteCache
|
||||
func NewRemoteCache(url string, customHeaders http.Header, insecure bool) cache.ArtifactCache {
|
||||
func NewRemoteCache(url string, customHeaders http.Header, insecure bool) ArtifactCache {
|
||||
ctx := client.WithCustomHeaders(context.Background(), customHeaders)
|
||||
|
||||
httpClient := &http.Client{
|
||||
@@ -33,7 +32,10 @@ func NewRemoteCache(url string, customHeaders http.Header, insecure bool) cache.
|
||||
},
|
||||
}
|
||||
c := rpcCache.NewCacheProtobufClient(url, httpClient)
|
||||
return &RemoteCache{ctx: ctx, client: c}
|
||||
return &RemoteCache{
|
||||
ctx: ctx,
|
||||
client: c,
|
||||
}
|
||||
}
|
||||
|
||||
// PutArtifact sends artifact to remote client
|
||||
|
||||
8
pkg/cache/remote_test.go
vendored
8
pkg/cache/remote_test.go
vendored
@@ -15,14 +15,13 @@ import (
|
||||
"google.golang.org/protobuf/types/known/emptypb"
|
||||
|
||||
"github.com/aquasecurity/trivy/pkg/cache"
|
||||
fcache "github.com/aquasecurity/trivy/pkg/fanal/cache"
|
||||
"github.com/aquasecurity/trivy/pkg/fanal/types"
|
||||
rpcCache "github.com/aquasecurity/trivy/rpc/cache"
|
||||
rpcScanner "github.com/aquasecurity/trivy/rpc/scanner"
|
||||
)
|
||||
|
||||
type mockCacheServer struct {
|
||||
cache fcache.Cache
|
||||
cache cache.Cache
|
||||
}
|
||||
|
||||
func (s *mockCacheServer) PutArtifact(_ context.Context, in *rpcCache.PutArtifactRequest) (*emptypb.Empty, error) {
|
||||
@@ -47,7 +46,10 @@ func (s *mockCacheServer) MissingBlobs(_ context.Context, in *rpcCache.MissingBl
|
||||
}
|
||||
layerIDs = append(layerIDs, layerID)
|
||||
}
|
||||
return &rpcCache.MissingBlobsResponse{MissingArtifact: true, MissingBlobIds: layerIDs}, nil
|
||||
return &rpcCache.MissingBlobsResponse{
|
||||
MissingArtifact: true,
|
||||
MissingBlobIds: layerIDs,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (s *mockCacheServer) DeleteBlobs(_ context.Context, in *rpcCache.DeleteBlobsRequest) (*emptypb.Empty, error) {
|
||||
|
||||
@@ -5,10 +5,11 @@ package artifact
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/google/wire"
|
||||
|
||||
"github.com/aquasecurity/trivy/pkg/cache"
|
||||
"github.com/aquasecurity/trivy/pkg/fanal/artifact"
|
||||
"github.com/aquasecurity/trivy/pkg/fanal/cache"
|
||||
"github.com/aquasecurity/trivy/pkg/fanal/types"
|
||||
"github.com/aquasecurity/trivy/pkg/rpc/client"
|
||||
"github.com/aquasecurity/trivy/pkg/scanner"
|
||||
|
||||
@@ -12,11 +12,10 @@ import (
|
||||
"golang.org/x/xerrors"
|
||||
|
||||
"github.com/aquasecurity/trivy-db/pkg/db"
|
||||
tcache "github.com/aquasecurity/trivy/pkg/cache"
|
||||
"github.com/aquasecurity/trivy/pkg/cache"
|
||||
"github.com/aquasecurity/trivy/pkg/commands/operation"
|
||||
"github.com/aquasecurity/trivy/pkg/fanal/analyzer"
|
||||
"github.com/aquasecurity/trivy/pkg/fanal/artifact"
|
||||
"github.com/aquasecurity/trivy/pkg/fanal/cache"
|
||||
ftypes "github.com/aquasecurity/trivy/pkg/fanal/types"
|
||||
"github.com/aquasecurity/trivy/pkg/fanal/walker"
|
||||
"github.com/aquasecurity/trivy/pkg/flag"
|
||||
@@ -31,7 +30,6 @@ import (
|
||||
"github.com/aquasecurity/trivy/pkg/rpc/client"
|
||||
"github.com/aquasecurity/trivy/pkg/scanner"
|
||||
"github.com/aquasecurity/trivy/pkg/types"
|
||||
"github.com/aquasecurity/trivy/pkg/utils/fsutils"
|
||||
"github.com/aquasecurity/trivy/pkg/version/doc"
|
||||
)
|
||||
|
||||
@@ -92,8 +90,9 @@ type Runner interface {
|
||||
}
|
||||
|
||||
type runner struct {
|
||||
cache cache.Cache
|
||||
dbOpen bool
|
||||
cache cache.ArtifactCache
|
||||
localCache cache.LocalArtifactCache
|
||||
dbOpen bool
|
||||
|
||||
// WASM modules
|
||||
module *module.Manager
|
||||
@@ -106,6 +105,7 @@ type runnerOption func(*runner)
|
||||
func WithCacheClient(c cache.Cache) runnerOption {
|
||||
return func(r *runner) {
|
||||
r.cache = c
|
||||
r.localCache = c
|
||||
}
|
||||
}
|
||||
|
||||
@@ -143,7 +143,7 @@ func NewRunner(ctx context.Context, cliOptions flag.Options, opts ...runnerOptio
|
||||
// Close closes everything
|
||||
func (r *runner) Close(ctx context.Context) error {
|
||||
var errs error
|
||||
if err := r.cache.Close(); err != nil {
|
||||
if err := r.localCache.Close(); err != nil {
|
||||
errs = multierror.Append(errs, err)
|
||||
}
|
||||
|
||||
@@ -259,7 +259,7 @@ 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) {
|
||||
report, err := scan(ctx, opts, initializeScanner, r.cache)
|
||||
report, err := r.scan(ctx, opts, initializeScanner)
|
||||
if err != nil {
|
||||
return types.Report{}, xerrors.Errorf("scan error: %w", err)
|
||||
}
|
||||
@@ -344,18 +344,18 @@ func (r *runner) initCache(opts flag.Options) error {
|
||||
|
||||
// client/server mode
|
||||
if opts.ServerAddr != "" {
|
||||
remoteCache := tcache.NewRemoteCache(opts.ServerAddr, opts.CustomHeaders, opts.Insecure)
|
||||
r.cache = tcache.NopCache(remoteCache)
|
||||
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
|
||||
fsutils.SetCacheDir(opts.CacheDir)
|
||||
cacheClient, err := operation.NewCache(opts.CacheOptions)
|
||||
cache.SetDir(opts.CacheDir)
|
||||
cacheClient, err := cache.NewClient(opts.CacheOptions.CacheBackendOptions)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("unable to initialize the cache: %w", err)
|
||||
}
|
||||
log.Debug("Cache dir", log.String("dir", fsutils.CacheDir()))
|
||||
log.Debug("Cache dir", log.String("dir", cache.Dir()))
|
||||
|
||||
if opts.Reset {
|
||||
defer cacheClient.Close()
|
||||
@@ -366,7 +366,7 @@ func (r *runner) initCache(opts flag.Options) error {
|
||||
}
|
||||
|
||||
if opts.ResetChecksBundle {
|
||||
c, err := policy.NewClient(fsutils.CacheDir(), true, opts.MisconfOptions.ChecksBundleRepository)
|
||||
c, err := policy.NewClient(cache.Dir(), true, opts.MisconfOptions.ChecksBundleRepository)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("failed to instantiate check client: %w", err)
|
||||
}
|
||||
@@ -384,7 +384,8 @@ func (r *runner) initCache(opts flag.Options) error {
|
||||
return SkipScan
|
||||
}
|
||||
|
||||
r.cache = cacheClient
|
||||
r.cache = cacheClient.Cache
|
||||
r.localCache = cacheClient.Cache
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -526,7 +527,7 @@ func filterMisconfigAnalyzers(included, all []analyzer.Type) ([]analyzer.Type, e
|
||||
return lo.Without(all, included...), nil
|
||||
}
|
||||
|
||||
func initScannerConfig(opts flag.Options, cacheClient cache.Cache) (ScannerConfig, types.ScanOptions, error) {
|
||||
func (r *runner) initScannerConfig(opts flag.Options) (ScannerConfig, types.ScanOptions, error) {
|
||||
target := opts.Target
|
||||
if opts.Input != "" {
|
||||
target = opts.Input
|
||||
@@ -616,8 +617,8 @@ func initScannerConfig(opts flag.Options, cacheClient cache.Cache) (ScannerConfi
|
||||
|
||||
return ScannerConfig{
|
||||
Target: target,
|
||||
ArtifactCache: cacheClient,
|
||||
LocalArtifactCache: cacheClient,
|
||||
ArtifactCache: r.cache,
|
||||
LocalArtifactCache: r.localCache,
|
||||
ServerOption: client.ScannerOption{
|
||||
RemoteURL: opts.ServerAddr,
|
||||
CustomHeaders: opts.CustomHeaders,
|
||||
@@ -675,9 +676,8 @@ func initScannerConfig(opts flag.Options, cacheClient cache.Cache) (ScannerConfi
|
||||
}, scanOptions, nil
|
||||
}
|
||||
|
||||
func scan(ctx context.Context, opts flag.Options, initializeScanner InitializeScanner, cacheClient cache.Cache) (
|
||||
types.Report, error) {
|
||||
scannerConfig, scanOptions, err := initScannerConfig(opts, cacheClient)
|
||||
func (r *runner) scan(ctx context.Context, opts flag.Options, initializeScanner InitializeScanner) (types.Report, error) {
|
||||
scannerConfig, scanOptions, err := r.initScannerConfig(opts)
|
||||
if err != nil {
|
||||
return types.Report{}, err
|
||||
}
|
||||
|
||||
@@ -16,7 +16,7 @@ import (
|
||||
"github.com/aquasecurity/trivy/pkg/fanal/artifact/repo"
|
||||
"github.com/aquasecurity/trivy/pkg/fanal/artifact/sbom"
|
||||
"github.com/aquasecurity/trivy/pkg/fanal/artifact/vm"
|
||||
"github.com/aquasecurity/trivy/pkg/fanal/cache"
|
||||
"github.com/aquasecurity/trivy/pkg/cache"
|
||||
"github.com/aquasecurity/trivy/pkg/fanal/image"
|
||||
"github.com/aquasecurity/trivy/pkg/fanal/types"
|
||||
"github.com/aquasecurity/trivy/pkg/fanal/walker"
|
||||
|
||||
@@ -2,114 +2,22 @@ package operation
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/tls"
|
||||
"crypto/x509"
|
||||
"os"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
"github.com/go-redis/redis/v8"
|
||||
"github.com/google/go-containerregistry/pkg/name"
|
||||
"github.com/google/wire"
|
||||
"github.com/samber/lo"
|
||||
"golang.org/x/xerrors"
|
||||
|
||||
"github.com/aquasecurity/trivy-db/pkg/metadata"
|
||||
"github.com/aquasecurity/trivy/pkg/db"
|
||||
"github.com/aquasecurity/trivy/pkg/fanal/cache"
|
||||
ftypes "github.com/aquasecurity/trivy/pkg/fanal/types"
|
||||
"github.com/aquasecurity/trivy/pkg/flag"
|
||||
"github.com/aquasecurity/trivy/pkg/log"
|
||||
"github.com/aquasecurity/trivy/pkg/policy"
|
||||
"github.com/aquasecurity/trivy/pkg/types"
|
||||
"github.com/aquasecurity/trivy/pkg/utils/fsutils"
|
||||
)
|
||||
|
||||
var mu sync.Mutex
|
||||
|
||||
// SuperSet binds cache dependencies
|
||||
var SuperSet = wire.NewSet(
|
||||
cache.NewFSCache,
|
||||
wire.Bind(new(cache.LocalArtifactCache), new(cache.FSCache)),
|
||||
NewCache,
|
||||
)
|
||||
|
||||
// Cache implements the local cache
|
||||
type Cache struct {
|
||||
cache.Cache
|
||||
}
|
||||
|
||||
// NewCache is the factory method for Cache
|
||||
func NewCache(c flag.CacheOptions) (Cache, error) {
|
||||
if strings.HasPrefix(c.CacheBackend, "redis://") {
|
||||
log.Info("Redis cache", log.String("url", c.CacheBackendMasked()))
|
||||
options, err := redis.ParseURL(c.CacheBackend)
|
||||
if err != nil {
|
||||
return Cache{}, err
|
||||
}
|
||||
|
||||
if !lo.IsEmpty(c.RedisOptions) {
|
||||
caCert, cert, err := GetTLSConfig(c.RedisCACert, c.RedisCert, c.RedisKey)
|
||||
if err != nil {
|
||||
return Cache{}, err
|
||||
}
|
||||
|
||||
options.TLSConfig = &tls.Config{
|
||||
RootCAs: caCert,
|
||||
Certificates: []tls.Certificate{cert},
|
||||
MinVersion: tls.VersionTLS12,
|
||||
}
|
||||
} else if c.RedisTLS {
|
||||
options.TLSConfig = &tls.Config{
|
||||
MinVersion: tls.VersionTLS12,
|
||||
}
|
||||
}
|
||||
|
||||
redisCache := cache.NewRedisCache(options, c.CacheTTL)
|
||||
return Cache{Cache: redisCache}, nil
|
||||
}
|
||||
|
||||
if c.CacheTTL != 0 {
|
||||
log.Warn("'--cache-ttl' is only available with Redis cache backend")
|
||||
}
|
||||
|
||||
// standalone mode
|
||||
fsCache, err := cache.NewFSCache(fsutils.CacheDir())
|
||||
if err != nil {
|
||||
return Cache{}, xerrors.Errorf("unable to initialize fs cache: %w", err)
|
||||
}
|
||||
return Cache{Cache: fsCache}, nil
|
||||
}
|
||||
|
||||
// Reset resets the cache
|
||||
func (c Cache) Reset() (err error) {
|
||||
if err := c.ClearDB(); err != nil {
|
||||
return xerrors.Errorf("failed to clear the database: %w", err)
|
||||
}
|
||||
if err := c.ClearArtifacts(); err != nil {
|
||||
return xerrors.Errorf("failed to clear the artifact cache: %w", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// ClearDB clears the DB cache
|
||||
func (c Cache) ClearDB() (err error) {
|
||||
log.Info("Removing DB file...")
|
||||
if err = os.RemoveAll(fsutils.CacheDir()); err != nil {
|
||||
return xerrors.Errorf("failed to remove the directory (%s) : %w", fsutils.CacheDir(), err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// ClearArtifacts clears the artifact cache
|
||||
func (c Cache) ClearArtifacts() error {
|
||||
log.Info("Removing artifact caches...")
|
||||
if err := c.Clear(); err != nil {
|
||||
return xerrors.Errorf("failed to remove the cache: %w", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// DownloadDB downloads the DB
|
||||
func DownloadDB(ctx context.Context, appVersion, cacheDir string, dbRepository name.Reference, quiet, skipUpdate bool,
|
||||
opt ftypes.RegistryOptions) error {
|
||||
@@ -186,24 +94,6 @@ func InitBuiltinPolicies(ctx context.Context, cacheDir string, quiet, skipUpdate
|
||||
return policyPaths, 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
|
||||
}
|
||||
|
||||
func Exit(opts flag.Options, failedResults bool, m types.Metadata) error {
|
||||
if opts.ExitOnEOL != 0 && m.OS != nil && m.OS.Eosl {
|
||||
log.Error("Detected EOL OS", log.String("family", string(m.OS.Family)),
|
||||
|
||||
@@ -6,12 +6,12 @@ import (
|
||||
"golang.org/x/xerrors"
|
||||
|
||||
"github.com/aquasecurity/trivy-db/pkg/db"
|
||||
"github.com/aquasecurity/trivy/pkg/cache"
|
||||
"github.com/aquasecurity/trivy/pkg/commands/operation"
|
||||
"github.com/aquasecurity/trivy/pkg/flag"
|
||||
"github.com/aquasecurity/trivy/pkg/log"
|
||||
"github.com/aquasecurity/trivy/pkg/module"
|
||||
rpcServer "github.com/aquasecurity/trivy/pkg/rpc/server"
|
||||
"github.com/aquasecurity/trivy/pkg/utils/fsutils"
|
||||
)
|
||||
|
||||
// Run runs the scan
|
||||
@@ -19,16 +19,16 @@ func Run(ctx context.Context, opts flag.Options) (err error) {
|
||||
log.InitLogger(opts.Debug, opts.Quiet)
|
||||
|
||||
// configure cache dir
|
||||
fsutils.SetCacheDir(opts.CacheDir)
|
||||
cache, err := operation.NewCache(opts.CacheOptions)
|
||||
cache.SetDir(opts.CacheDir)
|
||||
cacheClient, err := cache.NewClient(opts.CacheOptions.CacheBackendOptions)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("server cache error: %w", err)
|
||||
}
|
||||
defer cache.Close()
|
||||
log.Debug("Cache", log.String("dir", fsutils.CacheDir()))
|
||||
defer cacheClient.Close()
|
||||
log.Debug("Cache", log.String("dir", cache.Dir()))
|
||||
|
||||
if opts.Reset {
|
||||
return cache.ClearDB()
|
||||
return cacheClient.ClearDB()
|
||||
}
|
||||
|
||||
// download the database file
|
||||
@@ -57,5 +57,5 @@ func Run(ctx context.Context, opts flag.Options) (err error) {
|
||||
|
||||
server := rpcServer.NewServer(opts.AppVersion, opts.Listen, opts.CacheDir, opts.Token, opts.TokenHeader,
|
||||
opts.DBRepository, opts.RegistryOpts())
|
||||
return server.ListenAndServe(ctx, cache, opts.SkipDBUpdate)
|
||||
return server.ListenAndServe(ctx, cacheClient, opts.SkipDBUpdate)
|
||||
}
|
||||
|
||||
@@ -3,8 +3,8 @@ package applier
|
||||
import (
|
||||
"golang.org/x/xerrors"
|
||||
|
||||
"github.com/aquasecurity/trivy/pkg/cache"
|
||||
"github.com/aquasecurity/trivy/pkg/fanal/analyzer"
|
||||
"github.com/aquasecurity/trivy/pkg/fanal/cache"
|
||||
ftypes "github.com/aquasecurity/trivy/pkg/fanal/types"
|
||||
)
|
||||
|
||||
|
||||
@@ -8,8 +8,8 @@ import (
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/aquasecurity/trivy/pkg/cache"
|
||||
"github.com/aquasecurity/trivy/pkg/fanal/applier"
|
||||
"github.com/aquasecurity/trivy/pkg/fanal/cache"
|
||||
"github.com/aquasecurity/trivy/pkg/fanal/types"
|
||||
)
|
||||
|
||||
|
||||
@@ -14,9 +14,9 @@ import (
|
||||
"github.com/samber/lo"
|
||||
"golang.org/x/xerrors"
|
||||
|
||||
"github.com/aquasecurity/trivy/pkg/cache"
|
||||
"github.com/aquasecurity/trivy/pkg/fanal/analyzer"
|
||||
"github.com/aquasecurity/trivy/pkg/fanal/artifact"
|
||||
"github.com/aquasecurity/trivy/pkg/fanal/cache"
|
||||
"github.com/aquasecurity/trivy/pkg/fanal/handler"
|
||||
"github.com/aquasecurity/trivy/pkg/fanal/image"
|
||||
"github.com/aquasecurity/trivy/pkg/fanal/types"
|
||||
|
||||
@@ -11,10 +11,10 @@ import (
|
||||
"github.com/stretchr/testify/require"
|
||||
"golang.org/x/xerrors"
|
||||
|
||||
"github.com/aquasecurity/trivy/pkg/cache"
|
||||
"github.com/aquasecurity/trivy/pkg/fanal/analyzer"
|
||||
"github.com/aquasecurity/trivy/pkg/fanal/artifact"
|
||||
image2 "github.com/aquasecurity/trivy/pkg/fanal/artifact/image"
|
||||
"github.com/aquasecurity/trivy/pkg/fanal/cache"
|
||||
"github.com/aquasecurity/trivy/pkg/fanal/image"
|
||||
"github.com/aquasecurity/trivy/pkg/fanal/types"
|
||||
|
||||
|
||||
@@ -14,9 +14,9 @@ import (
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/aquasecurity/trivy/pkg/cache"
|
||||
"github.com/aquasecurity/trivy/pkg/fanal/artifact"
|
||||
image2 "github.com/aquasecurity/trivy/pkg/fanal/artifact/image"
|
||||
"github.com/aquasecurity/trivy/pkg/fanal/cache"
|
||||
"github.com/aquasecurity/trivy/pkg/fanal/types"
|
||||
"github.com/aquasecurity/trivy/pkg/log"
|
||||
"github.com/aquasecurity/trivy/pkg/rekortest"
|
||||
|
||||
@@ -14,9 +14,9 @@ import (
|
||||
"github.com/opencontainers/go-digest"
|
||||
"golang.org/x/xerrors"
|
||||
|
||||
"github.com/aquasecurity/trivy/pkg/cache"
|
||||
"github.com/aquasecurity/trivy/pkg/fanal/analyzer"
|
||||
"github.com/aquasecurity/trivy/pkg/fanal/artifact"
|
||||
"github.com/aquasecurity/trivy/pkg/fanal/cache"
|
||||
"github.com/aquasecurity/trivy/pkg/fanal/handler"
|
||||
"github.com/aquasecurity/trivy/pkg/fanal/types"
|
||||
"github.com/aquasecurity/trivy/pkg/fanal/walker"
|
||||
|
||||
@@ -10,9 +10,9 @@ import (
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/aquasecurity/trivy/pkg/cache"
|
||||
"github.com/aquasecurity/trivy/pkg/fanal/analyzer"
|
||||
"github.com/aquasecurity/trivy/pkg/fanal/artifact"
|
||||
"github.com/aquasecurity/trivy/pkg/fanal/cache"
|
||||
"github.com/aquasecurity/trivy/pkg/fanal/types"
|
||||
"github.com/aquasecurity/trivy/pkg/fanal/walker"
|
||||
"github.com/aquasecurity/trivy/pkg/misconf"
|
||||
|
||||
@@ -12,9 +12,9 @@ import (
|
||||
"github.com/hashicorp/go-multierror"
|
||||
"golang.org/x/xerrors"
|
||||
|
||||
"github.com/aquasecurity/trivy/pkg/cache"
|
||||
"github.com/aquasecurity/trivy/pkg/fanal/artifact"
|
||||
"github.com/aquasecurity/trivy/pkg/fanal/artifact/local"
|
||||
"github.com/aquasecurity/trivy/pkg/fanal/cache"
|
||||
"github.com/aquasecurity/trivy/pkg/fanal/walker"
|
||||
)
|
||||
|
||||
|
||||
@@ -12,8 +12,8 @@ import (
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/aquasecurity/trivy/internal/gittest"
|
||||
"github.com/aquasecurity/trivy/pkg/cache"
|
||||
"github.com/aquasecurity/trivy/pkg/fanal/artifact"
|
||||
"github.com/aquasecurity/trivy/pkg/fanal/cache"
|
||||
"github.com/aquasecurity/trivy/pkg/fanal/walker"
|
||||
|
||||
_ "github.com/aquasecurity/trivy/pkg/fanal/analyzer/config/all"
|
||||
|
||||
@@ -11,9 +11,9 @@ import (
|
||||
"github.com/samber/lo"
|
||||
"golang.org/x/xerrors"
|
||||
|
||||
"github.com/aquasecurity/trivy/pkg/cache"
|
||||
"github.com/aquasecurity/trivy/pkg/fanal/analyzer"
|
||||
"github.com/aquasecurity/trivy/pkg/fanal/artifact"
|
||||
"github.com/aquasecurity/trivy/pkg/fanal/cache"
|
||||
"github.com/aquasecurity/trivy/pkg/fanal/handler"
|
||||
"github.com/aquasecurity/trivy/pkg/fanal/types"
|
||||
"github.com/aquasecurity/trivy/pkg/log"
|
||||
|
||||
@@ -11,9 +11,9 @@ import (
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/aquasecurity/trivy/pkg/cache"
|
||||
"github.com/aquasecurity/trivy/pkg/fanal/artifact"
|
||||
"github.com/aquasecurity/trivy/pkg/fanal/artifact/sbom"
|
||||
"github.com/aquasecurity/trivy/pkg/fanal/cache"
|
||||
"github.com/aquasecurity/trivy/pkg/fanal/types"
|
||||
)
|
||||
|
||||
|
||||
@@ -8,9 +8,9 @@ import (
|
||||
ebsfile "github.com/masahiro331/go-ebs-file"
|
||||
"golang.org/x/xerrors"
|
||||
|
||||
"github.com/aquasecurity/trivy/pkg/cache"
|
||||
"github.com/aquasecurity/trivy/pkg/cloud/aws/config"
|
||||
"github.com/aquasecurity/trivy/pkg/fanal/artifact"
|
||||
"github.com/aquasecurity/trivy/pkg/fanal/cache"
|
||||
"github.com/aquasecurity/trivy/pkg/log"
|
||||
)
|
||||
|
||||
|
||||
@@ -12,8 +12,8 @@ import (
|
||||
"github.com/opencontainers/go-digest"
|
||||
"golang.org/x/xerrors"
|
||||
|
||||
"github.com/aquasecurity/trivy/pkg/cache"
|
||||
"github.com/aquasecurity/trivy/pkg/fanal/artifact"
|
||||
"github.com/aquasecurity/trivy/pkg/fanal/cache"
|
||||
"github.com/aquasecurity/trivy/pkg/fanal/types"
|
||||
"github.com/aquasecurity/trivy/pkg/fanal/vm"
|
||||
"github.com/aquasecurity/trivy/pkg/fanal/vm/disk"
|
||||
|
||||
@@ -10,9 +10,9 @@ import (
|
||||
"github.com/google/wire"
|
||||
"golang.org/x/xerrors"
|
||||
|
||||
"github.com/aquasecurity/trivy/pkg/cache"
|
||||
"github.com/aquasecurity/trivy/pkg/fanal/analyzer"
|
||||
"github.com/aquasecurity/trivy/pkg/fanal/artifact"
|
||||
"github.com/aquasecurity/trivy/pkg/fanal/cache"
|
||||
"github.com/aquasecurity/trivy/pkg/fanal/handler"
|
||||
"github.com/aquasecurity/trivy/pkg/fanal/types"
|
||||
"github.com/aquasecurity/trivy/pkg/fanal/walker"
|
||||
|
||||
@@ -14,10 +14,10 @@ import (
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/aquasecurity/trivy/pkg/cache"
|
||||
"github.com/aquasecurity/trivy/pkg/fanal/analyzer"
|
||||
"github.com/aquasecurity/trivy/pkg/fanal/artifact"
|
||||
"github.com/aquasecurity/trivy/pkg/fanal/artifact/vm"
|
||||
"github.com/aquasecurity/trivy/pkg/fanal/cache"
|
||||
"github.com/aquasecurity/trivy/pkg/fanal/types"
|
||||
"github.com/aquasecurity/trivy/pkg/fanal/walker"
|
||||
"github.com/aquasecurity/trivy/pkg/misconf"
|
||||
|
||||
180
pkg/fanal/cache/s3.go
vendored
180
pkg/fanal/cache/s3.go
vendored
@@ -1,180 +0,0 @@
|
||||
package cache
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
|
||||
"github.com/aws/aws-sdk-go-v2/aws"
|
||||
"github.com/aws/aws-sdk-go-v2/feature/s3/manager"
|
||||
"github.com/aws/aws-sdk-go-v2/service/s3"
|
||||
"github.com/hashicorp/go-multierror"
|
||||
"golang.org/x/xerrors"
|
||||
|
||||
"github.com/aquasecurity/trivy/pkg/fanal/types"
|
||||
)
|
||||
|
||||
var _ Cache = &S3Cache{}
|
||||
|
||||
type s3API interface {
|
||||
HeadObject(ctx context.Context, params *s3.HeadObjectInput, optFns ...func(*s3.Options)) (*s3.HeadObjectOutput, error)
|
||||
PutObject(ctx context.Context, params *s3.PutObjectInput, optFns ...func(*s3.Options)) (*s3.PutObjectOutput, error)
|
||||
DeleteBucket(ctx context.Context, params *s3.DeleteBucketInput, optFns ...func(*s3.Options)) (*s3.DeleteBucketOutput, error)
|
||||
}
|
||||
|
||||
type S3Cache struct {
|
||||
s3Client s3API
|
||||
downloader *manager.Downloader
|
||||
bucketName string
|
||||
prefix string
|
||||
}
|
||||
|
||||
func NewS3Cache(bucketName, prefix string, api s3API, downloaderAPI *manager.Downloader) S3Cache {
|
||||
return S3Cache{
|
||||
s3Client: api,
|
||||
downloader: downloaderAPI,
|
||||
bucketName: bucketName,
|
||||
prefix: prefix,
|
||||
}
|
||||
}
|
||||
|
||||
func (c S3Cache) PutArtifact(artifactID string, artifactConfig types.ArtifactInfo) (err error) {
|
||||
key := fmt.Sprintf("%s/%s/%s", artifactBucket, c.prefix, artifactID)
|
||||
if err := c.put(key, artifactConfig); err != nil {
|
||||
return xerrors.Errorf("unable to store artifact information in cache (%s): %w", artifactID, err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c S3Cache) DeleteBlobs(blobIDs []string) error {
|
||||
var errs error
|
||||
for _, blobID := range blobIDs {
|
||||
key := fmt.Sprintf("%s/%s/%s", blobBucket, c.prefix, blobID)
|
||||
input := &s3.DeleteBucketInput{Bucket: aws.String(key)}
|
||||
if _, err := c.s3Client.DeleteBucket(context.TODO(), input); err != nil {
|
||||
errs = multierror.Append(errs, err)
|
||||
}
|
||||
}
|
||||
return errs
|
||||
}
|
||||
|
||||
func (c S3Cache) PutBlob(blobID string, blobInfo types.BlobInfo) error {
|
||||
key := fmt.Sprintf("%s/%s/%s", blobBucket, c.prefix, blobID)
|
||||
if err := c.put(key, blobInfo); err != nil {
|
||||
return xerrors.Errorf("unable to store blob information in cache (%s): %w", blobID, err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c S3Cache) put(key string, body any) (err error) {
|
||||
b, err := json.Marshal(body)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
params := &s3.PutObjectInput{
|
||||
Bucket: aws.String(c.bucketName),
|
||||
Key: aws.String(key),
|
||||
Body: bytes.NewReader(b),
|
||||
}
|
||||
_, err = c.s3Client.PutObject(context.TODO(), params)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("unable to put object: %w", err)
|
||||
}
|
||||
// Index file due S3 caveat read after write consistency
|
||||
_, err = c.s3Client.PutObject(context.TODO(), &s3.PutObjectInput{
|
||||
Bucket: aws.String(c.bucketName),
|
||||
Key: aws.String(fmt.Sprintf("%s.index", key)),
|
||||
})
|
||||
if err != nil {
|
||||
return xerrors.Errorf("unable to put index object: %w", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c S3Cache) GetBlob(blobID string) (types.BlobInfo, error) {
|
||||
var blobInfo types.BlobInfo
|
||||
buf := manager.NewWriteAtBuffer([]byte{})
|
||||
_, err := c.downloader.Download(context.TODO(), buf, &s3.GetObjectInput{
|
||||
Bucket: aws.String(c.bucketName),
|
||||
Key: aws.String(fmt.Sprintf("%s/%s/%s", blobBucket, c.prefix, blobID)),
|
||||
})
|
||||
if err != nil {
|
||||
return types.BlobInfo{}, xerrors.Errorf("failed to get blob from the cache: %w", err)
|
||||
}
|
||||
err = json.Unmarshal(buf.Bytes(), &blobInfo)
|
||||
if err != nil {
|
||||
return types.BlobInfo{}, xerrors.Errorf("JSON unmarshal error: %w", err)
|
||||
}
|
||||
return blobInfo, nil
|
||||
}
|
||||
|
||||
func (c S3Cache) GetArtifact(artifactID string) (types.ArtifactInfo, error) {
|
||||
var info types.ArtifactInfo
|
||||
buf := manager.NewWriteAtBuffer([]byte{})
|
||||
_, err := c.downloader.Download(context.TODO(), buf, &s3.GetObjectInput{
|
||||
Bucket: aws.String(c.bucketName),
|
||||
Key: aws.String(fmt.Sprintf("%s/%s/%s", artifactBucket, c.prefix, artifactID)),
|
||||
})
|
||||
if err != nil {
|
||||
return types.ArtifactInfo{}, xerrors.Errorf("failed to get artifact from the cache: %w", err)
|
||||
}
|
||||
err = json.Unmarshal(buf.Bytes(), &info)
|
||||
if err != nil {
|
||||
return types.ArtifactInfo{}, xerrors.Errorf("JSON unmarshal error: %w", err)
|
||||
}
|
||||
return info, nil
|
||||
}
|
||||
|
||||
func (c S3Cache) getIndex(key, keyType string) error {
|
||||
_, err := c.s3Client.HeadObject(context.TODO(), &s3.HeadObjectInput{
|
||||
Key: aws.String(fmt.Sprintf("%s/%s/%s.index", keyType, c.prefix, key)),
|
||||
Bucket: &c.bucketName,
|
||||
})
|
||||
if err != nil {
|
||||
return xerrors.Errorf("failed to get index from the cache: %w", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c S3Cache) MissingBlobs(artifactID string, blobIDs []string) (bool, []string, error) {
|
||||
var missingArtifact bool
|
||||
var missingBlobIDs []string
|
||||
for _, blobID := range blobIDs {
|
||||
err := c.getIndex(blobID, blobBucket)
|
||||
if err != nil {
|
||||
// error means cache missed blob info
|
||||
missingBlobIDs = append(missingBlobIDs, blobID)
|
||||
continue
|
||||
}
|
||||
blobInfo, err := c.GetBlob(blobID)
|
||||
if err != nil {
|
||||
return true, missingBlobIDs, xerrors.Errorf("the blob object (%s) doesn't exist in S3 even though the index file exists: %w", blobID, err)
|
||||
}
|
||||
if blobInfo.SchemaVersion != types.BlobJSONSchemaVersion {
|
||||
missingBlobIDs = append(missingBlobIDs, blobID)
|
||||
}
|
||||
}
|
||||
// get artifact info
|
||||
err := c.getIndex(artifactID, artifactBucket)
|
||||
// error means cache missed artifact info
|
||||
if err != nil {
|
||||
return true, missingBlobIDs, nil
|
||||
}
|
||||
artifactInfo, err := c.GetArtifact(artifactID)
|
||||
if err != nil {
|
||||
return true, missingBlobIDs, xerrors.Errorf("the artifact object (%s) doesn't exist in S3 even though the index file exists: %w", artifactID, err)
|
||||
}
|
||||
if artifactInfo.SchemaVersion != types.ArtifactJSONSchemaVersion {
|
||||
missingArtifact = true
|
||||
}
|
||||
return missingArtifact, missingBlobIDs, nil
|
||||
}
|
||||
|
||||
func (c S3Cache) Close() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c S3Cache) Clear() error {
|
||||
return nil
|
||||
}
|
||||
312
pkg/fanal/cache/s3_test.go
vendored
312
pkg/fanal/cache/s3_test.go
vendored
@@ -1,312 +0,0 @@
|
||||
package cache
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"reflect"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/aws/aws-sdk-go-v2/feature/s3/manager"
|
||||
"github.com/aws/aws-sdk-go-v2/service/s3"
|
||||
"golang.org/x/xerrors"
|
||||
|
||||
"github.com/aquasecurity/trivy/pkg/fanal/types"
|
||||
)
|
||||
|
||||
type mockS3Client struct {
|
||||
s3API
|
||||
}
|
||||
|
||||
const (
|
||||
correctHash = "sha256:24df0d4e20c0f42d3703bf1f1db2bdd77346c7956f74f423603d651e8e5ae8a7"
|
||||
)
|
||||
|
||||
func (m *mockS3Client) PutObject(ctx context.Context, in *s3.PutObjectInput, optFns ...func(*s3.Options)) (*s3.PutObjectOutput, error) {
|
||||
return &s3.PutObjectOutput{}, nil
|
||||
}
|
||||
|
||||
func (m *mockS3Client) HeadObject(ctx context.Context, params *s3.HeadObjectInput, optFns ...func(*s3.Options)) (*s3.HeadObjectOutput, error) {
|
||||
return &s3.HeadObjectOutput{}, nil
|
||||
}
|
||||
|
||||
func (m *mockS3Client) DeleteBucket(ctx context.Context, in *s3.DeleteBucketInput, optFns ...func(*s3.Options)) (*s3.DeleteBucketOutput, error) {
|
||||
if in != nil && *in.Bucket == blobBucket+"/prefix/"+correctHash {
|
||||
return &s3.DeleteBucketOutput{}, nil
|
||||
}
|
||||
return nil, errors.New("unknown bucket")
|
||||
}
|
||||
|
||||
func TestS3Cache_PutBlob(t *testing.T) {
|
||||
mockSvc := &mockS3Client{}
|
||||
|
||||
type fields struct {
|
||||
S3 s3API
|
||||
Downloader *manager.Downloader
|
||||
BucketName string
|
||||
Prefix string
|
||||
}
|
||||
type args struct {
|
||||
blobID string
|
||||
blobInfo types.BlobInfo
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
fields fields
|
||||
args args
|
||||
wantErr bool
|
||||
}{
|
||||
{
|
||||
name: "happy path",
|
||||
fields: fields{
|
||||
S3: mockSvc,
|
||||
BucketName: "test",
|
||||
Prefix: "prefix",
|
||||
},
|
||||
args: args{
|
||||
blobID: "sha256:24df0d4e20c0f42d3703bf1f1db2bdd77346c7956f74f423603d651e8e5ae8a7",
|
||||
blobInfo: types.BlobInfo{
|
||||
SchemaVersion: 1,
|
||||
OS: types.OS{
|
||||
Family: "alpine",
|
||||
Name: "3.10",
|
||||
},
|
||||
}},
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
c := NewS3Cache(tt.fields.BucketName, tt.fields.Prefix, tt.fields.S3, tt.fields.Downloader)
|
||||
if err := c.PutBlob(tt.args.blobID, tt.args.blobInfo); (err != nil) != tt.wantErr {
|
||||
t.Errorf("S3Cache.PutBlob() error = %v, wantErr %v", err, tt.wantErr)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestS3Cache_PutArtifact(t *testing.T) {
|
||||
mockSvc := &mockS3Client{}
|
||||
|
||||
type fields struct {
|
||||
S3 s3API
|
||||
Downloader *manager.Downloader
|
||||
BucketName string
|
||||
Prefix string
|
||||
}
|
||||
type args struct {
|
||||
artifactID string
|
||||
artifactConfig types.ArtifactInfo
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
fields fields
|
||||
args args
|
||||
wantErr bool
|
||||
}{
|
||||
{
|
||||
name: "happy path",
|
||||
fields: fields{
|
||||
S3: mockSvc,
|
||||
BucketName: "test",
|
||||
Prefix: "prefix",
|
||||
},
|
||||
args: args{
|
||||
artifactID: "sha256:58701fd185bda36cab0557bb6438661831267aa4a9e0b54211c4d5317a48aff4",
|
||||
artifactConfig: types.ArtifactInfo{
|
||||
SchemaVersion: 1,
|
||||
Architecture: "amd64",
|
||||
Created: time.Date(2020, 1, 2, 3, 4, 5, 0, time.UTC),
|
||||
DockerVersion: "18.06.1-ce",
|
||||
OS: "linux",
|
||||
HistoryPackages: []types.Package{
|
||||
{
|
||||
Name: "musl",
|
||||
Version: "1.2.3",
|
||||
},
|
||||
},
|
||||
}},
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
c := NewS3Cache(tt.fields.BucketName, tt.fields.Prefix, tt.fields.S3, tt.fields.Downloader)
|
||||
if err := c.PutArtifact(tt.args.artifactID, tt.args.artifactConfig); (err != nil) != tt.wantErr {
|
||||
t.Errorf("S3Cache.PutArtifact() error = %v, wantErr %v", err, tt.wantErr)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestS3Cache_getIndex(t *testing.T) {
|
||||
mockSvc := &mockS3Client{}
|
||||
|
||||
type fields struct {
|
||||
S3 s3API
|
||||
Downloader *manager.Downloader
|
||||
BucketName string
|
||||
Prefix string
|
||||
}
|
||||
type args struct {
|
||||
key string
|
||||
keyType string
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
fields fields
|
||||
args args
|
||||
wantErr bool
|
||||
}{
|
||||
{
|
||||
name: "happy path",
|
||||
fields: fields{
|
||||
S3: mockSvc,
|
||||
BucketName: "test",
|
||||
Prefix: "prefix",
|
||||
},
|
||||
args: args{
|
||||
key: "key",
|
||||
keyType: "artifactBucket",
|
||||
},
|
||||
wantErr: false,
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
c := NewS3Cache(tt.fields.BucketName, tt.fields.Prefix, tt.fields.S3, tt.fields.Downloader)
|
||||
if err := c.getIndex(tt.args.key, tt.args.keyType); (err != nil) != tt.wantErr {
|
||||
t.Errorf("S3Cache.getIndex() error = %v, wantErr %v", err, tt.wantErr)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
type mockS3ClientMissingBlobs struct {
|
||||
s3API
|
||||
}
|
||||
|
||||
func (m *mockS3ClientMissingBlobs) PutObject(ctx context.Context, in *s3.PutObjectInput, optFns ...func(*s3.Options)) (*s3.PutObjectOutput, error) {
|
||||
return &s3.PutObjectOutput{}, nil
|
||||
}
|
||||
|
||||
func (m *mockS3ClientMissingBlobs) HeadObject(ctx context.Context, params *s3.HeadObjectInput, optFns ...func(*s3.Options)) (*s3.HeadObjectOutput, error) {
|
||||
return &s3.HeadObjectOutput{}, xerrors.Errorf("the object doesn't exist in S3")
|
||||
}
|
||||
|
||||
func TestS3Cache_MissingBlobs(t *testing.T) {
|
||||
mockSvc := &mockS3ClientMissingBlobs{}
|
||||
|
||||
type fields struct {
|
||||
S3 s3API
|
||||
Downloader *manager.Downloader
|
||||
BucketName string
|
||||
Prefix string
|
||||
}
|
||||
type args struct {
|
||||
artifactID string
|
||||
blobIDs []string
|
||||
analyzerVersions map[string]int
|
||||
configAnalyzerVersions map[string]int
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
fields fields
|
||||
args args
|
||||
want bool
|
||||
wantStringSlice []string
|
||||
wantErr bool
|
||||
}{{
|
||||
name: "happy path",
|
||||
fields: fields{
|
||||
S3: mockSvc,
|
||||
BucketName: "test",
|
||||
Prefix: "prefix",
|
||||
},
|
||||
args: args{
|
||||
artifactID: "sha256:58701fd185bda36cab0557bb6438661831267aa4a9e0b54211c4d5317a48aff4/1",
|
||||
blobIDs: []string{"sha256:24df0d4e20c0f42d3703bf1f1db2bdd77346c7956f74f423603d651e8e5ae8a7/10011"},
|
||||
},
|
||||
want: true,
|
||||
wantStringSlice: []string{"sha256:24df0d4e20c0f42d3703bf1f1db2bdd77346c7956f74f423603d651e8e5ae8a7/10011"},
|
||||
wantErr: false,
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
c := NewS3Cache(tt.fields.BucketName, tt.fields.Prefix, tt.fields.S3, tt.fields.Downloader)
|
||||
got, got1, err := c.MissingBlobs(tt.args.artifactID, tt.args.blobIDs)
|
||||
if (err != nil) != tt.wantErr {
|
||||
t.Errorf("S3Cache.MissingBlobs() error = %v, wantErr %v", err, tt.wantErr)
|
||||
return
|
||||
}
|
||||
if got != tt.want {
|
||||
t.Errorf("S3Cache.MissingBlobs() got = %v, want %v", got, tt.want)
|
||||
}
|
||||
if !reflect.DeepEqual(got1, tt.wantStringSlice) {
|
||||
t.Errorf("S3Cache.MissingBlobs() got1 = %v, want %v", got1, tt.wantStringSlice)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestS3Cache_DeleteBlobs(t *testing.T) {
|
||||
mockSvc := &mockS3Client{}
|
||||
|
||||
type fields struct {
|
||||
S3 s3API
|
||||
Downloader *manager.Downloader
|
||||
BucketName string
|
||||
Prefix string
|
||||
}
|
||||
type args struct {
|
||||
blobIDs []string
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
fields fields
|
||||
args args
|
||||
wantErr bool
|
||||
}{
|
||||
{
|
||||
name: "happy path",
|
||||
fields: fields{
|
||||
S3: mockSvc,
|
||||
BucketName: "test",
|
||||
Prefix: "prefix",
|
||||
},
|
||||
args: args{
|
||||
blobIDs: []string{correctHash},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "delete blob with bad ID",
|
||||
fields: fields{
|
||||
S3: mockSvc,
|
||||
BucketName: "test",
|
||||
Prefix: "prefix",
|
||||
},
|
||||
args: args{
|
||||
blobIDs: []string{"unde"},
|
||||
},
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
name: "delete blobs with bad ID",
|
||||
fields: fields{
|
||||
S3: mockSvc,
|
||||
BucketName: "test",
|
||||
Prefix: "prefix",
|
||||
},
|
||||
args: args{
|
||||
blobIDs: []string{correctHash},
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
c := NewS3Cache(tt.fields.BucketName, tt.fields.Prefix, tt.fields.S3, tt.fields.Downloader)
|
||||
if err := c.DeleteBlobs(tt.args.blobIDs); (err != nil) != tt.wantErr {
|
||||
t.Errorf("S3Cache.PutBlob() error = %v, wantErr %v", err, tt.wantErr)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -27,11 +27,11 @@ import (
|
||||
"github.com/testcontainers/testcontainers-go"
|
||||
"github.com/testcontainers/testcontainers-go/wait"
|
||||
|
||||
"github.com/aquasecurity/trivy/pkg/cache"
|
||||
"github.com/aquasecurity/trivy/pkg/fanal/analyzer"
|
||||
"github.com/aquasecurity/trivy/pkg/fanal/applier"
|
||||
"github.com/aquasecurity/trivy/pkg/fanal/artifact"
|
||||
aimage "github.com/aquasecurity/trivy/pkg/fanal/artifact/image"
|
||||
"github.com/aquasecurity/trivy/pkg/fanal/cache"
|
||||
"github.com/aquasecurity/trivy/pkg/fanal/image"
|
||||
"github.com/aquasecurity/trivy/pkg/fanal/types"
|
||||
)
|
||||
|
||||
@@ -20,11 +20,11 @@ import (
|
||||
|
||||
"github.com/aquasecurity/trivy/pkg/fanal/analyzer"
|
||||
|
||||
"github.com/aquasecurity/trivy/pkg/cache"
|
||||
_ "github.com/aquasecurity/trivy/pkg/fanal/analyzer/all"
|
||||
"github.com/aquasecurity/trivy/pkg/fanal/applier"
|
||||
"github.com/aquasecurity/trivy/pkg/fanal/artifact"
|
||||
aimage "github.com/aquasecurity/trivy/pkg/fanal/artifact/image"
|
||||
"github.com/aquasecurity/trivy/pkg/fanal/cache"
|
||||
_ "github.com/aquasecurity/trivy/pkg/fanal/handler/all"
|
||||
"github.com/aquasecurity/trivy/pkg/fanal/image"
|
||||
"github.com/aquasecurity/trivy/pkg/fanal/types"
|
||||
|
||||
@@ -20,12 +20,12 @@ import (
|
||||
testcontainers "github.com/testcontainers/testcontainers-go"
|
||||
"github.com/testcontainers/testcontainers-go/wait"
|
||||
|
||||
"github.com/aquasecurity/trivy/pkg/cache"
|
||||
"github.com/aquasecurity/trivy/pkg/fanal/analyzer"
|
||||
_ "github.com/aquasecurity/trivy/pkg/fanal/analyzer/all"
|
||||
"github.com/aquasecurity/trivy/pkg/fanal/applier"
|
||||
"github.com/aquasecurity/trivy/pkg/fanal/artifact"
|
||||
aimage "github.com/aquasecurity/trivy/pkg/fanal/artifact/image"
|
||||
"github.com/aquasecurity/trivy/pkg/fanal/cache"
|
||||
"github.com/aquasecurity/trivy/pkg/fanal/image"
|
||||
testdocker "github.com/aquasecurity/trivy/pkg/fanal/test/integration/docker"
|
||||
"github.com/aquasecurity/trivy/pkg/fanal/types"
|
||||
|
||||
@@ -1,12 +1,11 @@
|
||||
package flag
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/samber/lo"
|
||||
"golang.org/x/xerrors"
|
||||
|
||||
"github.com/aquasecurity/trivy/pkg/cache"
|
||||
)
|
||||
|
||||
// e.g. config yaml:
|
||||
@@ -70,18 +69,8 @@ type CacheFlagGroup struct {
|
||||
}
|
||||
|
||||
type CacheOptions struct {
|
||||
ClearCache bool
|
||||
CacheBackend string
|
||||
CacheTTL time.Duration
|
||||
RedisTLS bool
|
||||
RedisOptions
|
||||
}
|
||||
|
||||
// RedisOptions holds the options for redis cache
|
||||
type RedisOptions struct {
|
||||
RedisCACert string
|
||||
RedisCert string
|
||||
RedisKey string
|
||||
ClearCache bool
|
||||
CacheBackendOptions cache.Options
|
||||
}
|
||||
|
||||
// NewCacheFlagGroup returns a default CacheFlagGroup
|
||||
@@ -118,43 +107,14 @@ func (fg *CacheFlagGroup) ToOptions() (CacheOptions, error) {
|
||||
return CacheOptions{}, err
|
||||
}
|
||||
|
||||
cacheBackend := fg.CacheBackend.Value()
|
||||
redisOptions := RedisOptions{
|
||||
RedisCACert: fg.RedisCACert.Value(),
|
||||
RedisCert: fg.RedisCert.Value(),
|
||||
RedisKey: fg.RedisKey.Value(),
|
||||
}
|
||||
|
||||
// "redis://" or "fs" are allowed for now
|
||||
// An empty value is also allowed for testability
|
||||
if !strings.HasPrefix(cacheBackend, "redis://") &&
|
||||
cacheBackend != "fs" && cacheBackend != "" {
|
||||
return CacheOptions{}, xerrors.Errorf("unsupported cache backend: %s", cacheBackend)
|
||||
}
|
||||
// if one of redis option not nil, make sure CA, cert, and key provided
|
||||
if !lo.IsEmpty(redisOptions) {
|
||||
if redisOptions.RedisCACert == "" || redisOptions.RedisCert == "" || redisOptions.RedisKey == "" {
|
||||
return CacheOptions{}, xerrors.Errorf("you must provide Redis CA, cert and key file path when using TLS")
|
||||
}
|
||||
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{
|
||||
ClearCache: fg.ClearCache.Value(),
|
||||
CacheBackend: cacheBackend,
|
||||
CacheTTL: fg.CacheTTL.Value(),
|
||||
RedisTLS: fg.RedisTLS.Value(),
|
||||
RedisOptions: redisOptions,
|
||||
ClearCache: fg.ClearCache.Value(),
|
||||
CacheBackendOptions: backendOpts,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// CacheBackendMasked returns the redis connection string masking credentials
|
||||
func (o *CacheOptions) CacheBackendMasked() string {
|
||||
endIndex := strings.Index(o.CacheBackend, "@")
|
||||
if endIndex == -1 {
|
||||
return o.CacheBackend
|
||||
}
|
||||
|
||||
startIndex := strings.Index(o.CacheBackend, "//")
|
||||
|
||||
return fmt.Sprintf("%s****%s", o.CacheBackend[:startIndex+2], o.CacheBackend[endIndex:])
|
||||
}
|
||||
|
||||
@@ -1,160 +0,0 @@
|
||||
package flag_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/spf13/viper"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/aquasecurity/trivy/pkg/flag"
|
||||
)
|
||||
|
||||
func TestCacheFlagGroup_ToOptions(t *testing.T) {
|
||||
type fields struct {
|
||||
ClearCache bool
|
||||
CacheBackend string
|
||||
CacheTTL time.Duration
|
||||
RedisTLS bool
|
||||
RedisCACert string
|
||||
RedisCert string
|
||||
RedisKey string
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
fields fields
|
||||
want flag.CacheOptions
|
||||
assertion require.ErrorAssertionFunc
|
||||
}{
|
||||
{
|
||||
name: "fs",
|
||||
fields: fields{
|
||||
CacheBackend: "fs",
|
||||
},
|
||||
want: flag.CacheOptions{
|
||||
CacheBackend: "fs",
|
||||
},
|
||||
assertion: require.NoError,
|
||||
},
|
||||
{
|
||||
name: "redis",
|
||||
fields: fields{
|
||||
CacheBackend: "redis://localhost:6379",
|
||||
},
|
||||
want: flag.CacheOptions{
|
||||
CacheBackend: "redis://localhost:6379",
|
||||
},
|
||||
assertion: require.NoError,
|
||||
},
|
||||
{
|
||||
name: "redis tls",
|
||||
fields: fields{
|
||||
CacheBackend: "redis://localhost:6379",
|
||||
RedisCACert: "ca-cert.pem",
|
||||
RedisCert: "cert.pem",
|
||||
RedisKey: "key.pem",
|
||||
},
|
||||
want: flag.CacheOptions{
|
||||
CacheBackend: "redis://localhost:6379",
|
||||
RedisOptions: flag.RedisOptions{
|
||||
RedisCACert: "ca-cert.pem",
|
||||
RedisCert: "cert.pem",
|
||||
RedisKey: "key.pem",
|
||||
},
|
||||
},
|
||||
assertion: require.NoError,
|
||||
},
|
||||
{
|
||||
name: "redis tls with public certificates",
|
||||
fields: fields{
|
||||
CacheBackend: "redis://localhost:6379",
|
||||
RedisTLS: true,
|
||||
},
|
||||
want: flag.CacheOptions{
|
||||
CacheBackend: "redis://localhost:6379",
|
||||
RedisTLS: true,
|
||||
},
|
||||
assertion: require.NoError,
|
||||
},
|
||||
{
|
||||
name: "unknown backend",
|
||||
fields: fields{
|
||||
CacheBackend: "unknown",
|
||||
},
|
||||
assertion: func(t require.TestingT, err error, msgs ...any) {
|
||||
require.ErrorContains(t, err, "unsupported cache backend")
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "sad redis tls",
|
||||
fields: fields{
|
||||
CacheBackend: "redis://localhost:6379",
|
||||
RedisCACert: "ca-cert.pem",
|
||||
},
|
||||
assertion: func(t require.TestingT, err error, msgs ...any) {
|
||||
require.ErrorContains(t, err, "you must provide Redis CA")
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
viper.Set(flag.ClearCacheFlag.ConfigName, tt.fields.ClearCache)
|
||||
viper.Set(flag.CacheBackendFlag.ConfigName, tt.fields.CacheBackend)
|
||||
viper.Set(flag.CacheTTLFlag.ConfigName, tt.fields.CacheTTL)
|
||||
viper.Set(flag.RedisTLSFlag.ConfigName, tt.fields.RedisTLS)
|
||||
viper.Set(flag.RedisCACertFlag.ConfigName, tt.fields.RedisCACert)
|
||||
viper.Set(flag.RedisCertFlag.ConfigName, tt.fields.RedisCert)
|
||||
viper.Set(flag.RedisKeyFlag.ConfigName, tt.fields.RedisKey)
|
||||
|
||||
f := &flag.CacheFlagGroup{
|
||||
ClearCache: flag.ClearCacheFlag.Clone(),
|
||||
CacheBackend: flag.CacheBackendFlag.Clone(),
|
||||
CacheTTL: flag.CacheTTLFlag.Clone(),
|
||||
RedisTLS: flag.RedisTLSFlag.Clone(),
|
||||
RedisCACert: flag.RedisCACertFlag.Clone(),
|
||||
RedisCert: flag.RedisCertFlag.Clone(),
|
||||
RedisKey: flag.RedisKeyFlag.Clone(),
|
||||
}
|
||||
|
||||
got, err := f.ToOptions()
|
||||
tt.assertion(t, err)
|
||||
assert.Equalf(t, tt.want, got, "ToOptions()")
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestCacheOptions_CacheBackendMasked(t *testing.T) {
|
||||
type fields struct {
|
||||
backend string
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
fields fields
|
||||
want string
|
||||
}{
|
||||
{
|
||||
name: "redis cache backend masked",
|
||||
fields: fields{
|
||||
backend: "redis://root:password@localhost:6379",
|
||||
},
|
||||
want: "redis://****@localhost:6379",
|
||||
},
|
||||
{
|
||||
name: "redis cache backend masked does nothing",
|
||||
fields: fields{
|
||||
backend: "redis://localhost:6379",
|
||||
},
|
||||
want: "redis://localhost:6379",
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
c := &flag.CacheOptions{
|
||||
CacheBackend: tt.fields.backend,
|
||||
}
|
||||
|
||||
assert.Equal(t, tt.want, c.CacheBackendMasked())
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -6,7 +6,7 @@ import (
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
"github.com/aquasecurity/trivy/pkg/utils/fsutils"
|
||||
"github.com/aquasecurity/trivy/pkg/cache"
|
||||
)
|
||||
|
||||
var (
|
||||
@@ -55,7 +55,7 @@ var (
|
||||
CacheDirFlag = Flag[string]{
|
||||
Name: "cache-dir",
|
||||
ConfigName: "cache.dir",
|
||||
Default: fsutils.CacheDir(),
|
||||
Default: cache.Dir(),
|
||||
Usage: "cache directory",
|
||||
Persistent: true,
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@ package k8s
|
||||
import (
|
||||
"github.com/google/wire"
|
||||
|
||||
"github.com/aquasecurity/trivy/pkg/fanal/cache"
|
||||
"github.com/aquasecurity/trivy/pkg/cache"
|
||||
)
|
||||
|
||||
func initializeScanK8s(localArtifactCache cache.LocalArtifactCache) *ScanKubernetes {
|
||||
|
||||
@@ -9,7 +9,7 @@ package k8s
|
||||
import (
|
||||
"github.com/aquasecurity/trivy-db/pkg/db"
|
||||
"github.com/aquasecurity/trivy/pkg/fanal/applier"
|
||||
"github.com/aquasecurity/trivy/pkg/fanal/cache"
|
||||
"github.com/aquasecurity/trivy/pkg/cache"
|
||||
"github.com/aquasecurity/trivy/pkg/scanner/langpkg"
|
||||
"github.com/aquasecurity/trivy/pkg/scanner/local"
|
||||
"github.com/aquasecurity/trivy/pkg/scanner/ospkg"
|
||||
|
||||
@@ -14,9 +14,9 @@ import (
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/aquasecurity/trivy/pkg/cache"
|
||||
ftypes "github.com/aquasecurity/trivy/pkg/fanal/types"
|
||||
"github.com/aquasecurity/trivy/pkg/oci"
|
||||
"github.com/aquasecurity/trivy/pkg/utils/fsutils"
|
||||
)
|
||||
|
||||
type fakeLayer struct {
|
||||
@@ -97,7 +97,7 @@ func TestArtifact_Download(t *testing.T) {
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
tempDir := t.TempDir()
|
||||
fsutils.SetCacheDir(tempDir)
|
||||
cache.SetDir(tempDir)
|
||||
|
||||
// Mock image
|
||||
img := new(fakei.FakeImage)
|
||||
|
||||
@@ -12,13 +12,13 @@ import (
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/aquasecurity/trivy/pkg/cache"
|
||||
"github.com/aquasecurity/trivy/pkg/plugin"
|
||||
"github.com/aquasecurity/trivy/pkg/utils/fsutils"
|
||||
)
|
||||
|
||||
func TestManager_Update(t *testing.T) {
|
||||
tempDir := t.TempDir()
|
||||
fsutils.SetCacheDir(tempDir)
|
||||
cache.SetDir(tempDir)
|
||||
|
||||
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
_, err := w.Write([]byte(`this is index`))
|
||||
@@ -73,7 +73,7 @@ bar A bar plugin
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
fsutils.SetCacheDir(tt.dir)
|
||||
cache.SetDir(tt.dir)
|
||||
|
||||
var got bytes.Buffer
|
||||
m := plugin.NewManager(plugin.WithWriter(&got))
|
||||
|
||||
@@ -14,6 +14,7 @@ import (
|
||||
"gopkg.in/yaml.v3"
|
||||
|
||||
"github.com/aquasecurity/go-version/pkg/semver"
|
||||
"github.com/aquasecurity/trivy/pkg/cache"
|
||||
"github.com/aquasecurity/trivy/pkg/downloader"
|
||||
ftypes "github.com/aquasecurity/trivy/pkg/fanal/types"
|
||||
"github.com/aquasecurity/trivy/pkg/log"
|
||||
@@ -63,7 +64,7 @@ func NewManager(opts ...ManagerOption) *Manager {
|
||||
indexURL: indexURL,
|
||||
logger: log.WithPrefix("plugin"),
|
||||
pluginRoot: filepath.Join(fsutils.HomeDir(), pluginsRelativeDir),
|
||||
indexPath: filepath.Join(fsutils.CacheDir(), "plugin", "index.yaml"),
|
||||
indexPath: filepath.Join(cache.Dir(), "plugin", "index.yaml"),
|
||||
}
|
||||
for _, opt := range opts {
|
||||
opt(m)
|
||||
|
||||
@@ -20,11 +20,11 @@ import (
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/aquasecurity/trivy/internal/gittest"
|
||||
"github.com/aquasecurity/trivy/pkg/cache"
|
||||
"github.com/aquasecurity/trivy/pkg/clock"
|
||||
ftypes "github.com/aquasecurity/trivy/pkg/fanal/types"
|
||||
"github.com/aquasecurity/trivy/pkg/log"
|
||||
"github.com/aquasecurity/trivy/pkg/plugin"
|
||||
"github.com/aquasecurity/trivy/pkg/utils/fsutils"
|
||||
)
|
||||
|
||||
func setupGitRepository(t *testing.T, repo, dir string) *httptest.Server {
|
||||
@@ -200,7 +200,7 @@ func TestManager_Install(t *testing.T) {
|
||||
t.Setenv("XDG_DATA_HOME", dst)
|
||||
|
||||
// For plugin index
|
||||
fsutils.SetCacheDir("testdata")
|
||||
cache.SetDir("testdata")
|
||||
|
||||
if tt.installed != nil {
|
||||
setupInstalledPlugin(t, dst, *tt.installed)
|
||||
|
||||
@@ -6,7 +6,7 @@ package server
|
||||
import (
|
||||
"github.com/google/wire"
|
||||
|
||||
"github.com/aquasecurity/trivy/pkg/fanal/cache"
|
||||
"github.com/aquasecurity/trivy/pkg/cache"
|
||||
)
|
||||
|
||||
func initializeScanServer(localArtifactCache cache.LocalArtifactCache) *ScanServer {
|
||||
|
||||
@@ -15,8 +15,8 @@ import (
|
||||
|
||||
"github.com/aquasecurity/trivy-db/pkg/db"
|
||||
"github.com/aquasecurity/trivy-db/pkg/metadata"
|
||||
"github.com/aquasecurity/trivy/pkg/cache"
|
||||
dbc "github.com/aquasecurity/trivy/pkg/db"
|
||||
"github.com/aquasecurity/trivy/pkg/fanal/cache"
|
||||
"github.com/aquasecurity/trivy/pkg/fanal/types"
|
||||
"github.com/aquasecurity/trivy/pkg/log"
|
||||
"github.com/aquasecurity/trivy/pkg/utils/fsutils"
|
||||
|
||||
@@ -17,9 +17,9 @@ import (
|
||||
trivydb "github.com/aquasecurity/trivy-db/pkg/db"
|
||||
"github.com/aquasecurity/trivy-db/pkg/metadata"
|
||||
"github.com/aquasecurity/trivy/internal/dbtest"
|
||||
"github.com/aquasecurity/trivy/pkg/cache"
|
||||
"github.com/aquasecurity/trivy/pkg/clock"
|
||||
"github.com/aquasecurity/trivy/pkg/db"
|
||||
"github.com/aquasecurity/trivy/pkg/fanal/cache"
|
||||
ftypes "github.com/aquasecurity/trivy/pkg/fanal/types"
|
||||
"github.com/aquasecurity/trivy/pkg/policy"
|
||||
"github.com/aquasecurity/trivy/pkg/version"
|
||||
|
||||
@@ -8,7 +8,7 @@ import (
|
||||
"golang.org/x/xerrors"
|
||||
"google.golang.org/protobuf/types/known/emptypb"
|
||||
|
||||
"github.com/aquasecurity/trivy/pkg/fanal/cache"
|
||||
"github.com/aquasecurity/trivy/pkg/cache"
|
||||
"github.com/aquasecurity/trivy/pkg/log"
|
||||
"github.com/aquasecurity/trivy/pkg/rpc"
|
||||
"github.com/aquasecurity/trivy/pkg/scanner"
|
||||
|
||||
@@ -15,7 +15,7 @@ import (
|
||||
dbTypes "github.com/aquasecurity/trivy-db/pkg/types"
|
||||
"github.com/aquasecurity/trivy-db/pkg/utils"
|
||||
"github.com/aquasecurity/trivy-db/pkg/vulnsrc/vulnerability"
|
||||
"github.com/aquasecurity/trivy/pkg/fanal/cache"
|
||||
"github.com/aquasecurity/trivy/pkg/cache"
|
||||
ftypes "github.com/aquasecurity/trivy/pkg/fanal/types"
|
||||
"github.com/aquasecurity/trivy/pkg/scanner"
|
||||
"github.com/aquasecurity/trivy/pkg/types"
|
||||
|
||||
@@ -9,7 +9,7 @@ package server
|
||||
import (
|
||||
"github.com/aquasecurity/trivy-db/pkg/db"
|
||||
"github.com/aquasecurity/trivy/pkg/fanal/applier"
|
||||
"github.com/aquasecurity/trivy/pkg/fanal/cache"
|
||||
"github.com/aquasecurity/trivy/pkg/cache"
|
||||
"github.com/aquasecurity/trivy/pkg/scanner/langpkg"
|
||||
"github.com/aquasecurity/trivy/pkg/scanner/local"
|
||||
"github.com/aquasecurity/trivy/pkg/scanner/ospkg"
|
||||
|
||||
@@ -18,30 +18,6 @@ const (
|
||||
xdgDataHome = "XDG_DATA_HOME"
|
||||
)
|
||||
|
||||
var cacheDir string
|
||||
|
||||
// defaultCacheDir returns/creates the cache-dir to be used for trivy operations
|
||||
func defaultCacheDir() string {
|
||||
tmpDir, err := os.UserCacheDir()
|
||||
if err != nil {
|
||||
tmpDir = os.TempDir()
|
||||
}
|
||||
return filepath.Join(tmpDir, "trivy")
|
||||
}
|
||||
|
||||
// CacheDir returns the directory used for caching
|
||||
func CacheDir() string {
|
||||
if cacheDir == "" {
|
||||
return defaultCacheDir()
|
||||
}
|
||||
return cacheDir
|
||||
}
|
||||
|
||||
// SetCacheDir sets the trivy cacheDir
|
||||
func SetCacheDir(dir string) {
|
||||
cacheDir = dir
|
||||
}
|
||||
|
||||
func HomeDir() string {
|
||||
dataHome := os.Getenv(xdgDataHome)
|
||||
if dataHome != "" {
|
||||
|
||||
Reference in New Issue
Block a user