forked from zhanglimao/trivy
-
Notifications
You must be signed in to change notification settings - Fork 0
/
operation.go
217 lines (186 loc) · 5.81 KB
/
operation.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
package operation
import (
"context"
"crypto/tls"
"crypto/x509"
"os"
"strings"
"sync"
"github.com/go-redis/redis/v8"
"github.com/google/wire"
"github.com/samber/lo"
"golang.org/x/xerrors"
"github.com/aquasecurity/trivy-db/pkg/metadata"
"github.com/zhyocean/trivy/pkg/db"
"github.com/zhyocean/trivy/pkg/fanal/cache"
ftypes "github.com/zhyocean/trivy/pkg/fanal/types"
"github.com/zhyocean/trivy/pkg/flag"
"github.com/zhyocean/trivy/pkg/log"
"github.com/zhyocean/trivy/pkg/policy"
"github.com/zhyocean/trivy/pkg/types"
"github.com/zhyocean/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.Logger.Infof("Redis cache: %s", 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.Logger.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.Logger.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.Logger.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, dbRepository string, quiet, skipUpdate bool, opt ftypes.RegistryOptions) error {
mu.Lock()
defer mu.Unlock()
client := db.NewClient(cacheDir, quiet, db.WithDBRepository(dbRepository))
needsUpdate, err := client.NeedsUpdate(appVersion, skipUpdate)
if err != nil {
return xerrors.Errorf("database error: %w", err)
}
if needsUpdate {
log.Logger.Info("Need to update DB")
log.Logger.Infof("DB Repository: %s", dbRepository)
log.Logger.Info("Downloading DB...")
if err = client.Download(ctx, cacheDir, opt); err != nil {
return xerrors.Errorf("failed to download vulnerability DB: %w", err)
}
}
// for debug
if err = showDBInfo(cacheDir); err != nil {
return xerrors.Errorf("failed to show database info: %w", err)
}
return nil
}
func showDBInfo(cacheDir string) error {
m := metadata.NewClient(cacheDir)
meta, err := m.Get()
if err != nil {
return xerrors.Errorf("something wrong with DB: %w", err)
}
log.Logger.Debugf("DB Schema: %d, UpdatedAt: %s, NextUpdate: %s, DownloadedAt: %s",
meta.Version, meta.UpdatedAt, meta.NextUpdate, meta.DownloadedAt)
return nil
}
// InitBuiltinPolicies downloads the built-in policies and loads them
func InitBuiltinPolicies(ctx context.Context, cacheDir string, quiet, skipUpdate bool) ([]string, error) {
mu.Lock()
defer mu.Unlock()
client, err := policy.NewClient(cacheDir, quiet)
if err != nil {
return nil, xerrors.Errorf("policy client error: %w", err)
}
needsUpdate := false
if !skipUpdate {
needsUpdate, err = client.NeedsUpdate(ctx)
if err != nil {
return nil, xerrors.Errorf("unable to check if built-in policies need to be updated: %w", err)
}
}
if needsUpdate {
log.Logger.Info("Need to update the built-in policies")
log.Logger.Info("Downloading the built-in policies...")
if err = client.DownloadBuiltinPolicies(ctx); err != nil {
return nil, xerrors.Errorf("failed to download built-in policies: %w", err)
}
}
policyPaths, err := client.LoadBuiltinPolicies()
if err != nil {
if skipUpdate {
msg := "No downloadable policies were loaded as --skip-policy-update is enabled"
log.Logger.Info(msg)
return nil, xerrors.Errorf(msg)
}
return nil, xerrors.Errorf("policy load error: %w", err)
}
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) {
if opts.ExitCode != 0 && failedResults {
os.Exit(opts.ExitCode)
}
}
func ExitOnEOL(opts flag.Options, m types.Metadata) {
if opts.ExitOnEOL != 0 && m.OS != nil && m.OS.Eosl {
log.Logger.Errorf("Detected EOL OS: %s %s", m.OS.Family, m.OS.Name)
os.Exit(opts.ExitOnEOL)
}
}