fix(trivy): cleanup Trivy temporary directory (#3618)

This Trivy commit changed the way the cleanup is done for Trivy operations:
https://github.com/aquasecurity/trivy/commit/8f5b56005a4e8752976524750089dc9ea2c91e40

We need to start calling the APIs to create and cleanup the temp dir to ensure we don't leave around content in the /tmp folder

Signed-off-by: Andrei Aaron <andreifdaaron@gmail.com>
This commit is contained in:
Andrei Aaron
2025-12-03 10:11:32 +02:00
committed by GitHub
parent 8226b25509
commit edaef52d50
2 changed files with 173 additions and 14 deletions
+46 -14
View File
@@ -19,6 +19,7 @@ import (
"github.com/aquasecurity/trivy/pkg/flag"
"github.com/aquasecurity/trivy/pkg/javadb"
"github.com/aquasecurity/trivy/pkg/types"
xos "github.com/aquasecurity/trivy/pkg/x/os"
"github.com/google/go-containerregistry/pkg/name"
regTypes "github.com/google/go-containerregistry/pkg/v1/types"
godigest "github.com/opencontainers/go-digest"
@@ -193,29 +194,54 @@ func (scanner Scanner) getTrivyOptions(image string) flag.Options {
return opts
}
// withTempDir creates a temporary directory using xos.TempDir(), executes the provided function,
// and then calls xos.Cleanup() to clean up Trivy's process-specific temp directory.
func (scanner Scanner) withTempDir(wrappedFunc func() error) error {
// Ensure Trivy's process-specific temp directory is initialized,
// call TempDir() to get the path, then create it if it doesn't exist with MkdirAll.
tempDir := xos.TempDir()
if err := os.MkdirAll(tempDir, 0o755); err != nil {
scanner.log.Error().Err(err).Str("tempDir", tempDir).Msg("failed to create Trivy temp directory")
return err
}
defer func() {
// Clean up Trivy's process-specific temp directory (includes our tmpDir)
if err := xos.Cleanup(); err != nil {
scanner.log.Warn().Err(err).Str("tempDir", tempDir).Msg("failed to cleanup Trivy temp directory")
}
}()
return wrappedFunc()
}
func (scanner Scanner) runTrivy(ctx context.Context, opts flag.Options) (types.Report, error) {
err := scanner.checkDBPresence()
if err != nil {
return types.Report{}, err
}
runner, err := artifact.NewRunner(ctx, opts, artifact.TargetContainerImage)
if err != nil {
return types.Report{}, err
}
defer runner.Close(ctx)
report := types.Report{}
err = scanner.withTempDir(func() error {
runner, err := artifact.NewRunner(ctx, opts, artifact.TargetContainerImage)
if err != nil {
return err
}
defer runner.Close(ctx)
report, err := runner.ScanImage(ctx, opts)
if err != nil {
return types.Report{}, err
}
report, err = runner.ScanImage(ctx, opts)
if err != nil {
return err
}
report, err = runner.Filter(ctx, opts, report)
if err != nil {
return types.Report{}, err
}
report, err = runner.Filter(ctx, opts, report)
return report, nil
return err
})
return report, err
}
func (scanner Scanner) IsImageFormatScannable(repo, ref string) (bool, error) {
@@ -581,6 +607,12 @@ func (scanner Scanner) UpdateDB(ctx context.Context) error {
}
func (scanner Scanner) updateDB(ctx context.Context, dbDir string) error {
return scanner.withTempDir(func() error {
return scanner.updateDBInternal(ctx, dbDir)
})
}
func (scanner Scanner) updateDBInternal(ctx context.Context, dbDir string) error {
scanner.log.Debug().Str("dbDir", dbDir).Msg("download Trivy DB to destination dir")
registryOpts := fanalTypes.RegistryOptions{Insecure: false}
@@ -5,10 +5,12 @@ package trivy_test
import (
"context"
"errors"
"os"
"path/filepath"
"testing"
"time"
xos "github.com/aquasecurity/trivy/pkg/x/os"
godigest "github.com/opencontainers/go-digest"
ispec "github.com/opencontainers/image-spec/specs-go/v1"
. "github.com/smartystreets/goconvey/convey"
@@ -287,6 +289,131 @@ func TestVulnerableLayer(t *testing.T) {
})
}
func TestWithTempDirErrorHandling(t *testing.T) {
Convey("Temp Dir error handling", t, func() {
vulnerableLayer, err := GetLayerWithVulnerability()
So(err, ShouldBeNil)
created, err := time.Parse(time.RFC3339, "2023-03-29T18:19:24Z")
So(err, ShouldBeNil)
config := ispec.Image{
Created: &created,
Platform: ispec.Platform{
Architecture: "amd64",
OS: "linux",
},
Config: ispec.ImageConfig{
Env: []string{"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"},
Cmd: []string{"/bin/sh"},
},
RootFS: ispec.RootFS{
Type: "layers",
DiffIDs: []godigest.Digest{"sha256:f1417ff83b319fbdae6dd9cd6d8c9c88002dcd75ecf6ec201c8c6894681cf2b5"},
},
}
img := CreateImageWith().
LayerBlobs([][]byte{vulnerableLayer}).
ImageConfig(config).
Build()
tempDir := t.TempDir()
log := log.NewTestLogger()
imageStore := local.NewImageStore(tempDir, false, false,
log, monitoring.NewMetricsServer(false, log), nil, nil, nil, nil)
storeController := storage.StoreController{
DefaultStore: imageStore,
}
err = WriteImageToFileSystem(img, "repo", img.DigestStr(), storeController)
So(err, ShouldBeNil)
params := boltdb.DBParameters{
RootDir: tempDir,
}
boltDriver, err := boltdb.GetBoltDriver(params)
So(err, ShouldBeNil)
metaDB, err := boltdb.New(boltDriver, log)
So(err, ShouldBeNil)
err = meta.ParseStorage(metaDB, storeController, log)
So(err, ShouldBeNil)
scanner := trivy.NewScanner(storeController, metaDB, "ghcr.io/project-zot/trivy-db", "", log)
// Clean up any existing temp directory first
_ = xos.Cleanup()
// Get temp directory path (xos.TempDir() uses sync.OnceValues, so it won't recreate after cleanup)
tempDirPath := xos.TempDir()
// Manually create the directory since xos.Cleanup() removed it
err = os.MkdirAll(tempDirPath, 0o755)
So(err, ShouldBeNil)
// Change permissions to 0o000 to test error handling
err = os.Chmod(tempDirPath, 0o000)
So(err, ShouldBeNil)
defer func() {
// Clean up in case test fails
// Note: directory may have been cleaned up by withTempDir, so we just call xos.Cleanup()
_ = os.Chmod(tempDirPath, 0o755)
_ = xos.Cleanup()
}()
err = scanner.UpdateDB(context.Background())
So(err, ShouldNotBeNil)
// Verify temp directory no longer exists
_, err = os.Stat(tempDirPath)
So(err, ShouldNotBeNil)
err = scanner.UpdateDB(context.Background())
So(err, ShouldBeNil)
// Verify temp directory no longer exists
_, err = os.Stat(tempDirPath)
So(err, ShouldNotBeNil)
// Test scan with no permissions on temp directory
// Ensure directory exists again after cleanup (xos.Cleanup() removed it)
tempDirPath = xos.TempDir()
err = os.MkdirAll(tempDirPath, 0o755)
So(err, ShouldBeNil)
err = os.Chmod(tempDirPath, 0o000)
So(err, ShouldBeNil)
_, err = scanner.ScanImage(context.Background(), "repo@"+img.DigestStr())
So(err, ShouldNotBeNil)
// Verify temp directory no longer exists
_, err = os.Stat(tempDirPath)
So(err, ShouldNotBeNil)
cveMap, err := scanner.ScanImage(context.Background(), "repo@"+img.DigestStr())
So(err, ShouldBeNil)
t.Logf("cveMap: %v", cveMap)
// As of September 17 2023 there are 5 CVEs:
// CVE-2023-1255, CVE-2023-2650, CVE-2023-2975, CVE-2023-3817, CVE-2023-3446
// There may be more discovered in the future
So(len(cveMap), ShouldBeGreaterThanOrEqualTo, 5)
So(cveMap, ShouldContainKey, "CVE-2023-1255")
So(cveMap, ShouldContainKey, "CVE-2023-2650")
So(cveMap, ShouldContainKey, "CVE-2023-2975")
So(cveMap, ShouldContainKey, "CVE-2023-3817")
So(cveMap, ShouldContainKey, "CVE-2023-3446")
// Verify temp directory no longer exists
_, err = os.Stat(tempDirPath)
So(err, ShouldNotBeNil)
})
}
func TestScannerErrors(t *testing.T) {
Convey("Errors", t, func() {
storeController := storage.StoreController{}