diff --git a/pkg/cache/client.go b/pkg/cache/client.go index fea9395770c7..7b18827016d5 100644 --- a/pkg/cache/client.go +++ b/pkg/cache/client.go @@ -21,6 +21,7 @@ const ( ) type Client struct { + dir string Cache } @@ -115,7 +116,8 @@ func NewType(backend string) (Type, error) { } // NewClient returns a new cache client -func NewClient(opts Options) (*Client, error) { +func NewClient(dir string, opts Options) (*Client, error) { + client := &Client{dir: dir} if opts.Type == TypeRedis { log.Info("Redis cache", log.String("url", opts.Redis.BackendMasked())) options, err := redis.ParseURL(opts.Redis.Backend) @@ -140,34 +142,27 @@ func NewClient(opts Options) (*Client, error) { } } - redisCache := NewRedisCache(options, opts.TTL) - return &Client{Cache: redisCache}, nil + client.Cache = NewRedisCache(options, opts.TTL) + return client, nil } // standalone mode - fsCache, err := NewFSCache(Dir()) + var err error + client.Cache, err = NewFSCache(dir) if err != nil { return nil, xerrors.Errorf("unable to initialize fs cache: %w", err) } - return &Client{Cache: fsCache}, nil + return client, 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) +func (c *Client) Reset() error { + log.Info("Removing all caches...") + if err := c.Clear(); err != nil { + return xerrors.Errorf("failed to remove the 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) + if err := os.RemoveAll(c.dir); err != nil { + return xerrors.Errorf("failed to remove the directory (%s) : %w", c.dir, err) } return nil } diff --git a/pkg/cache/client_test.go b/pkg/cache/client_test.go index f22ce4f93e2f..e41e84034a27 100644 --- a/pkg/cache/client_test.go +++ b/pkg/cache/client_test.go @@ -1,6 +1,8 @@ package cache_test import ( + "os" + "path/filepath" "testing" "time" @@ -127,3 +129,51 @@ func TestRedisOptions_BackendMasked(t *testing.T) { }) } } + +func TestClient_Reset(t *testing.T) { + // Create a temporary directory for testing + tempDir := t.TempDir() + + // Create test files and subdirectories + subDir := filepath.Join(tempDir, "subdir") + err := os.MkdirAll(subDir, 0755) + require.NoError(t, err) + + testFile := filepath.Join(tempDir, "testfile.txt") + err = os.WriteFile(testFile, []byte("test content"), 0644) + require.NoError(t, err) + + // Create a cache client + client, err := cache.NewClient(tempDir, cache.Options{Type: cache.TypeFS}) + require.NoError(t, err) + + // Call Reset method + err = client.Reset() + require.NoError(t, err) + + // Verify that the subdirectory no longer exists + require.NoDirExists(t, subDir, "Subdirectory should not exist after Reset") + + // Verify that the test file no longer exists + require.NoFileExists(t, testFile, "Test file should not exist after Reset") + + // Verify that the cache directory no longer exists + require.NoDirExists(t, tempDir, "Cache directory should not exist after Reset") +} + +func TestClient_ClearArtifacts(t *testing.T) { + // Create a temporary directory for testing + tempDir := t.TempDir() + + // Create a client + client, err := cache.NewClient(tempDir, cache.Options{Type: cache.TypeFS}) + require.NoError(t, err) + + require.FileExists(t, filepath.Join(tempDir, "fanal", "fanal.db"), "Database file should exist") + + // Call ClearArtifacts method + err = client.ClearArtifacts() + require.NoError(t, err) + + require.NoDirExists(t, filepath.Join(tempDir, "fanal"), "Artifact cache should not exist after ClearArtifacts") +} diff --git a/pkg/cache/dir.go b/pkg/cache/dir.go index b687017c9faf..2a67d269bdfe 100644 --- a/pkg/cache/dir.go +++ b/pkg/cache/dir.go @@ -5,26 +5,11 @@ import ( "path/filepath" ) -var cacheDir string - -// defaultDir returns/creates the cache-dir to be used for trivy operations -func defaultDir() 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 -} diff --git a/pkg/commands/app.go b/pkg/commands/app.go index e01bc53e1ea0..90c737a040bb 100644 --- a/pkg/commands/app.go +++ b/pkg/commands/app.go @@ -110,10 +110,9 @@ func NewApp() *cobra.Command { func loadPluginCommands() []*cobra.Command { ctx := context.Background() - manager := plugin.NewManager() var commands []*cobra.Command - plugins, err := manager.LoadAll(ctx) + plugins, err := plugin.NewManager().LoadAll(ctx) if err != nil { log.DebugContext(ctx, "No plugins loaded") return nil diff --git a/pkg/commands/artifact/run.go b/pkg/commands/artifact/run.go index 3a22f762c71c..65bfd455321b 100644 --- a/pkg/commands/artifact/run.go +++ b/pkg/commands/artifact/run.go @@ -350,12 +350,11 @@ func (r *runner) initCache(opts flag.Options) error { } // standalone mode - cache.SetDir(opts.CacheDir) - cacheClient, err := cache.NewClient(opts.CacheOptions.CacheBackendOptions) + cacheClient, err := cache.NewClient(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", cache.Dir())) + log.Debug("Cache dir", log.String("dir", opts.CacheDir)) if opts.Reset { defer cacheClient.Close() @@ -366,7 +365,7 @@ func (r *runner) initCache(opts flag.Options) error { } if opts.ResetChecksBundle { - c, err := policy.NewClient(cache.Dir(), true, opts.MisconfOptions.ChecksBundleRepository) + c, err := policy.NewClient(opts.CacheDir, true, opts.MisconfOptions.ChecksBundleRepository) if err != nil { return xerrors.Errorf("failed to instantiate check client: %w", err) } diff --git a/pkg/commands/server/run.go b/pkg/commands/server/run.go index eeef097990ce..f2957b75dbb6 100644 --- a/pkg/commands/server/run.go +++ b/pkg/commands/server/run.go @@ -19,16 +19,15 @@ func Run(ctx context.Context, opts flag.Options) (err error) { log.InitLogger(opts.Debug, opts.Quiet) // configure cache dir - cache.SetDir(opts.CacheDir) - cacheClient, err := cache.NewClient(opts.CacheOptions.CacheBackendOptions) + cacheClient, err := cache.NewClient(opts.CacheDir, opts.CacheOptions.CacheBackendOptions) if err != nil { return xerrors.Errorf("server cache error: %w", err) } defer cacheClient.Close() - log.Debug("Cache", log.String("dir", cache.Dir())) + log.Debug("Cache", log.String("dir", opts.CacheDir)) if opts.Reset { - return cacheClient.ClearDB() + return cacheClient.Reset() } // download the database file diff --git a/pkg/flag/global_flags.go b/pkg/flag/global_flags.go index eb34e2f589dc..ef19a09dd4e8 100644 --- a/pkg/flag/global_flags.go +++ b/pkg/flag/global_flags.go @@ -55,7 +55,7 @@ var ( CacheDirFlag = Flag[string]{ Name: "cache-dir", ConfigName: "cache.dir", - Default: cache.Dir(), + Default: cache.DefaultDir(), Usage: "cache directory", Persistent: true, } diff --git a/pkg/oci/artifact_test.go b/pkg/oci/artifact_test.go index 479c607af425..ddfe0304cc63 100644 --- a/pkg/oci/artifact_test.go +++ b/pkg/oci/artifact_test.go @@ -14,7 +14,6 @@ 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" ) @@ -97,7 +96,6 @@ func TestArtifact_Download(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { tempDir := t.TempDir() - cache.SetDir(tempDir) // Mock image img := new(fakei.FakeImage) diff --git a/pkg/plugin/index_test.go b/pkg/plugin/index_test.go index e420dfaa6d08..4fbd4c9411aa 100644 --- a/pkg/plugin/index_test.go +++ b/pkg/plugin/index_test.go @@ -12,13 +12,12 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - "github.com/aquasecurity/trivy/pkg/cache" "github.com/aquasecurity/trivy/pkg/plugin" ) func TestManager_Update(t *testing.T) { tempDir := t.TempDir() - cache.SetDir(tempDir) + t.Setenv("XDG_DATA_HOME", tempDir) ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { _, err := w.Write([]byte(`this is index`)) @@ -30,7 +29,7 @@ func TestManager_Update(t *testing.T) { err := manager.Update(context.Background()) require.NoError(t, err) - indexPath := filepath.Join(tempDir, "plugin", "index.yaml") + indexPath := filepath.Join(tempDir, ".trivy", "plugins", "index.yaml") assert.FileExists(t, indexPath) b, err := os.ReadFile(indexPath) @@ -73,7 +72,7 @@ bar A bar plugin } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - cache.SetDir(tt.dir) + t.Setenv("XDG_DATA_HOME", tt.dir) var got bytes.Buffer m := plugin.NewManager(plugin.WithWriter(&got)) diff --git a/pkg/plugin/manager.go b/pkg/plugin/manager.go index 70ae3758fbdc..a3a806f8f42b 100644 --- a/pkg/plugin/manager.go +++ b/pkg/plugin/manager.go @@ -14,7 +14,6 @@ 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" @@ -59,12 +58,13 @@ type Manager struct { } func NewManager(opts ...ManagerOption) *Manager { + root := filepath.Join(fsutils.HomeDir(), pluginsRelativeDir) m := &Manager{ w: os.Stdout, indexURL: indexURL, logger: log.WithPrefix("plugin"), - pluginRoot: filepath.Join(fsutils.HomeDir(), pluginsRelativeDir), - indexPath: filepath.Join(cache.Dir(), "plugin", "index.yaml"), + pluginRoot: root, + indexPath: filepath.Join(root, "index.yaml"), } for _, opt := range opts { opt(m) diff --git a/pkg/plugin/manager_unix_test.go b/pkg/plugin/manager_unix_test.go index dd59109f94ee..728d3c7cf041 100644 --- a/pkg/plugin/manager_unix_test.go +++ b/pkg/plugin/manager_unix_test.go @@ -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,11 @@ func TestManager_Install(t *testing.T) { t.Setenv("XDG_DATA_HOME", dst) // For plugin index - cache.SetDir("testdata") + pluginDir := filepath.Join(dst, ".trivy", "plugins") + err := os.MkdirAll(pluginDir, 0755) + require.NoError(t, err) + _, err = fsutils.CopyFile("testdata/.trivy/plugins/index.yaml", filepath.Join(pluginDir, "index.yaml")) + require.NoError(t, err) if tt.installed != nil { setupInstalledPlugin(t, dst, *tt.installed) diff --git a/pkg/plugin/testdata/plugin/index.yaml b/pkg/plugin/testdata/.trivy/plugins/index.yaml similarity index 100% rename from pkg/plugin/testdata/plugin/index.yaml rename to pkg/plugin/testdata/.trivy/plugins/index.yaml