mirror of
https://github.com/aquasecurity/trivy.git
synced 2025-12-05 20:40:16 -08:00
chore: implement process-safe temp file cleanup (#9241)
Signed-off-by: knqyf263 <knqyf263@gmail.com> Co-authored-by: knqyf263 <knqyf263@users.noreply.github.com>
This commit is contained in:
@@ -41,6 +41,9 @@ func run() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Ensure cleanup on exit
|
||||
defer commands.Cleanup()
|
||||
|
||||
// Set up signal handling for graceful shutdown
|
||||
ctx := commands.NotifyContext(context.Background())
|
||||
|
||||
|
||||
@@ -35,3 +35,16 @@ func mapSet(m dsl.Matcher) {
|
||||
m.Match(`map[$x]struct{}`).
|
||||
Report("use github.com/aquasecurity/trivy/pkg/set.Set instead of map.")
|
||||
}
|
||||
|
||||
// Enforce usage of x/os package for temporary file operations
|
||||
func tempFileOps(m dsl.Matcher) {
|
||||
m.Match(`os.CreateTemp($*args)`).
|
||||
Where(!m.File().Name.Matches(`.*_test\.go$`)).
|
||||
Suggest(`xos.CreateTemp($args)`).
|
||||
Report("use github.com/aquasecurity/trivy/pkg/x/os.CreateTemp instead of os.CreateTemp for process-safe temp file cleanup")
|
||||
|
||||
m.Match(`os.MkdirTemp($*args)`).
|
||||
Where(!m.File().Name.Matches(`.*_test\.go$`)).
|
||||
Suggest(`xos.MkdirTemp($args)`).
|
||||
Report("use github.com/aquasecurity/trivy/pkg/x/os.MkdirTemp instead of os.MkdirTemp for process-safe temp file cleanup")
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@ import (
|
||||
"syscall"
|
||||
|
||||
"github.com/aquasecurity/trivy/pkg/log"
|
||||
xos "github.com/aquasecurity/trivy/pkg/x/os"
|
||||
)
|
||||
|
||||
// NotifyContext returns a context that is canceled when SIGINT or SIGTERM is received.
|
||||
@@ -26,7 +27,10 @@ func NotifyContext(parent context.Context) context.Context {
|
||||
log.Info("Received signal, attempting graceful shutdown...")
|
||||
log.Info("Press Ctrl+C again to force exit")
|
||||
|
||||
// TODO: Add any necessary cleanup logic here
|
||||
// Perform cleanup
|
||||
if err := Cleanup(); err != nil {
|
||||
log.Debug("Failed to clean up temporary files", log.Err(err))
|
||||
}
|
||||
|
||||
// Clean up signal handling
|
||||
// After calling stop(), a second signal will cause immediate termination
|
||||
@@ -35,3 +39,8 @@ func NotifyContext(parent context.Context) context.Context {
|
||||
|
||||
return ctx
|
||||
}
|
||||
|
||||
// Cleanup performs cleanup tasks before Trivy exits
|
||||
func Cleanup() error {
|
||||
return xos.Cleanup()
|
||||
}
|
||||
|
||||
@@ -20,6 +20,7 @@ import (
|
||||
ftypes "github.com/aquasecurity/trivy/pkg/fanal/types"
|
||||
"github.com/aquasecurity/trivy/pkg/log"
|
||||
xio "github.com/aquasecurity/trivy/pkg/x/io"
|
||||
xos "github.com/aquasecurity/trivy/pkg/x/os"
|
||||
)
|
||||
|
||||
var (
|
||||
@@ -198,7 +199,7 @@ func (p *Parser) parseInnerJar(zf *zip.File, rootPath string) ([]ftypes.Package,
|
||||
return nil, nil, xerrors.Errorf("unable to open %s: %w", zf.Name, err)
|
||||
}
|
||||
|
||||
f, err := os.CreateTemp("", "inner")
|
||||
f, err := xos.CreateTemp("", "jar-inner-")
|
||||
if err != nil {
|
||||
return nil, nil, xerrors.Errorf("unable to create a temp file: %w", err)
|
||||
}
|
||||
|
||||
@@ -17,6 +17,7 @@ import (
|
||||
"golang.org/x/xerrors"
|
||||
|
||||
xhttp "github.com/aquasecurity/trivy/pkg/x/http"
|
||||
xos "github.com/aquasecurity/trivy/pkg/x/os"
|
||||
)
|
||||
|
||||
var ErrSkipDownload = errors.New("skip download")
|
||||
@@ -36,7 +37,7 @@ type Auth struct {
|
||||
|
||||
// DownloadToTempDir downloads the configured source to a temp dir.
|
||||
func DownloadToTempDir(ctx context.Context, src string, opts Options) (string, error) {
|
||||
tempDir, err := os.MkdirTemp("", "trivy-download")
|
||||
tempDir, err := xos.MkdirTemp("", "download-")
|
||||
if err != nil {
|
||||
return "", xerrors.Errorf("failed to create a temp dir: %w", err)
|
||||
}
|
||||
|
||||
@@ -10,6 +10,7 @@ import (
|
||||
"golang.org/x/xerrors"
|
||||
|
||||
"github.com/aquasecurity/trivy/pkg/mapfs"
|
||||
xos "github.com/aquasecurity/trivy/pkg/x/os"
|
||||
"github.com/aquasecurity/trivy/pkg/x/sync"
|
||||
)
|
||||
|
||||
@@ -20,7 +21,7 @@ type CompositeFS struct {
|
||||
}
|
||||
|
||||
func NewCompositeFS() (*CompositeFS, error) {
|
||||
tmpDir, err := os.MkdirTemp("", "analyzer-fs-*")
|
||||
tmpDir, err := xos.MkdirTemp("", "analyzer-composite-")
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("unable to create temporary directory: %w", err)
|
||||
}
|
||||
@@ -35,7 +36,7 @@ func NewCompositeFS() (*CompositeFS, error) {
|
||||
func (c *CompositeFS) CopyFileToTemp(opener Opener, _ os.FileInfo) (string, error) {
|
||||
// Create a temporary file to which the file in the layer will be copied
|
||||
// so that all the files will not be loaded into memory
|
||||
f, err := os.CreateTemp(c.dir, "file-*")
|
||||
f, err := xos.CreateTemp("", "analyzer-file-")
|
||||
if err != nil {
|
||||
return "", xerrors.Errorf("create temp error: %w", err)
|
||||
}
|
||||
|
||||
@@ -18,6 +18,7 @@ import (
|
||||
"github.com/aquasecurity/trivy/pkg/fanal/analyzer"
|
||||
"github.com/aquasecurity/trivy/pkg/fanal/types"
|
||||
"github.com/aquasecurity/trivy/pkg/log"
|
||||
xos "github.com/aquasecurity/trivy/pkg/x/os"
|
||||
)
|
||||
|
||||
func init() {
|
||||
@@ -261,7 +262,7 @@ func packageProvidedByVendor(pkg *rpmdb.PackageInfo) bool {
|
||||
}
|
||||
|
||||
func writeToTempFile(rc io.Reader) (string, error) {
|
||||
tmpDir, err := os.MkdirTemp("", "rpm")
|
||||
tmpDir, err := xos.MkdirTemp("", "rpmdb-")
|
||||
if err != nil {
|
||||
return "", xerrors.Errorf("failed to create a temp dir: %w", err)
|
||||
}
|
||||
|
||||
@@ -29,6 +29,7 @@ import (
|
||||
"github.com/aquasecurity/trivy/pkg/semaphore"
|
||||
trivyTypes "github.com/aquasecurity/trivy/pkg/types"
|
||||
xio "github.com/aquasecurity/trivy/pkg/x/io"
|
||||
xos "github.com/aquasecurity/trivy/pkg/x/os"
|
||||
)
|
||||
|
||||
const artifactVersion = 1
|
||||
@@ -64,7 +65,7 @@ func NewArtifact(img types.Image, c cache.ArtifactCache, opt artifact.Option) (a
|
||||
return nil, xerrors.Errorf("config analyzer group error: %w", err)
|
||||
}
|
||||
|
||||
cacheDir, err := os.MkdirTemp("", "layers")
|
||||
cacheDir, err := xos.MkdirTemp("", "image-layers-")
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("failed to create a cache layers temp dir: %w", err)
|
||||
}
|
||||
|
||||
@@ -21,6 +21,7 @@ import (
|
||||
"github.com/aquasecurity/trivy/pkg/oci"
|
||||
"github.com/aquasecurity/trivy/pkg/remote"
|
||||
"github.com/aquasecurity/trivy/pkg/types"
|
||||
xos "github.com/aquasecurity/trivy/pkg/x/os"
|
||||
)
|
||||
|
||||
var errNoSBOMFound = xerrors.New("remote SBOM not found")
|
||||
@@ -88,9 +89,9 @@ func (a Artifact) parseReferrer(ctx context.Context, repo string, desc v1.Descri
|
||||
const fileName string = "referrer.sbom"
|
||||
repoName := fmt.Sprintf("%s@%s", repo, desc.Digest)
|
||||
|
||||
tmpDir, err := os.MkdirTemp("", "trivy-sbom-*")
|
||||
tmpDir, err := xos.MkdirTemp("", "sbom-referrer-")
|
||||
if err != nil {
|
||||
return artifact.Reference{}, xerrors.Errorf("mkdir temp error: %w", err)
|
||||
return artifact.Reference{}, xerrors.Errorf("failed to create temp directory: %w", err)
|
||||
}
|
||||
defer os.RemoveAll(tmpDir)
|
||||
|
||||
@@ -133,7 +134,7 @@ func (a Artifact) inspectRekorSBOMAttestation(ctx context.Context) (artifact.Ref
|
||||
return artifact.Reference{}, xerrors.Errorf("failed to retrieve SBOM attestation: %w", err)
|
||||
}
|
||||
|
||||
f, err := os.CreateTemp("", "sbom-*")
|
||||
f, err := xos.CreateTemp("", "sbom-attestation-")
|
||||
if err != nil {
|
||||
return artifact.Reference{}, xerrors.Errorf("failed to create a temporary file: %w", err)
|
||||
}
|
||||
|
||||
@@ -16,6 +16,7 @@ import (
|
||||
"github.com/aquasecurity/trivy/pkg/fanal/artifact/local"
|
||||
"github.com/aquasecurity/trivy/pkg/fanal/types"
|
||||
"github.com/aquasecurity/trivy/pkg/fanal/walker"
|
||||
xos "github.com/aquasecurity/trivy/pkg/x/os"
|
||||
)
|
||||
|
||||
var (
|
||||
@@ -93,7 +94,7 @@ func tryRemoteRepo(target string, c cache.ArtifactCache, w Walker, artifactOpt a
|
||||
}
|
||||
|
||||
func cloneRepo(u *url.URL, artifactOpt artifact.Option) (string, error) {
|
||||
tmpDir, err := os.MkdirTemp("", "trivy-remote-repo")
|
||||
tmpDir, err := xos.MkdirTemp("", "git-clone-")
|
||||
if err != nil {
|
||||
return "", xerrors.Errorf("failed to create a temp dir: %w", err)
|
||||
}
|
||||
|
||||
@@ -29,6 +29,7 @@ import (
|
||||
"golang.org/x/xerrors"
|
||||
|
||||
"github.com/aquasecurity/trivy/pkg/fanal/types"
|
||||
xos "github.com/aquasecurity/trivy/pkg/x/os"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -130,7 +131,7 @@ func ContainerdImage(ctx context.Context, imageName string, opts types.ImageOpti
|
||||
|
||||
img := imgs[0]
|
||||
|
||||
f, err := os.CreateTemp("", "fanal-containerd-*")
|
||||
f, err := xos.CreateTemp("", "containerd-export-")
|
||||
if err != nil {
|
||||
return nil, cleanup, xerrors.Errorf("failed to create a temporary file: %w", err)
|
||||
}
|
||||
|
||||
@@ -2,8 +2,8 @@ package daemon
|
||||
|
||||
const (
|
||||
testContextHost = "npipe:////./pipe/test_docker_engine"
|
||||
|
||||
|
||||
// Test socket paths for Windows systems
|
||||
testFlagHost = "npipe:////./pipe/flag_docker"
|
||||
testEnvHost = "npipe:////./pipe/env_docker"
|
||||
)
|
||||
testFlagHost = "npipe:////./pipe/flag_docker"
|
||||
testEnvHost = "npipe:////./pipe/env_docker"
|
||||
)
|
||||
|
||||
@@ -7,6 +7,8 @@ import (
|
||||
"github.com/docker/docker/client"
|
||||
"github.com/google/go-containerregistry/pkg/name"
|
||||
"golang.org/x/xerrors"
|
||||
|
||||
xos "github.com/aquasecurity/trivy/pkg/x/os"
|
||||
)
|
||||
|
||||
// DockerImage implements v1.Image by extending daemon.Image.
|
||||
@@ -56,7 +58,7 @@ func DockerImage(ref name.Reference, host string) (Image, func(), error) {
|
||||
return nil, cleanup, xerrors.Errorf("unable to get history (%s): %w", imageID, err)
|
||||
}
|
||||
|
||||
f, err := os.CreateTemp("", "fanal-*")
|
||||
f, err := xos.CreateTemp("", "docker-export-")
|
||||
if err != nil {
|
||||
return nil, cleanup, xerrors.Errorf("failed to create a temporary file: %w", err)
|
||||
}
|
||||
|
||||
@@ -14,6 +14,8 @@ import (
|
||||
dimage "github.com/docker/docker/api/types/image"
|
||||
"github.com/docker/docker/client"
|
||||
"golang.org/x/xerrors"
|
||||
|
||||
xos "github.com/aquasecurity/trivy/pkg/x/os"
|
||||
)
|
||||
|
||||
var (
|
||||
@@ -130,7 +132,7 @@ func PodmanImage(ref, host string) (Image, func(), error) {
|
||||
return nil, cleanup, xerrors.Errorf("unable to inspect the image (%s): %w", ref, err)
|
||||
}
|
||||
|
||||
f, err := os.CreateTemp("", "fanal-*")
|
||||
f, err := xos.CreateTemp("", "podman-export-")
|
||||
if err != nil {
|
||||
return nil, cleanup, xerrors.Errorf("failed to create a temporary file: %w", err)
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@ import (
|
||||
"golang.org/x/xerrors"
|
||||
|
||||
xio "github.com/aquasecurity/trivy/pkg/x/io"
|
||||
xos "github.com/aquasecurity/trivy/pkg/x/os"
|
||||
)
|
||||
|
||||
// cachedFile represents a file cached in memory or storage according to the file size.
|
||||
@@ -37,7 +38,7 @@ func (o *cachedFile) Open() (xio.ReadSeekCloserAt, error) {
|
||||
o.once.Do(func() {
|
||||
// When the file is large, it will be written down to a temp file.
|
||||
if o.size >= defaultSizeThreshold {
|
||||
f, err := os.CreateTemp("", "fanal-*")
|
||||
f, err := xos.CreateTemp("", "cached-file-")
|
||||
if err != nil {
|
||||
o.err = xerrors.Errorf("failed to create the temp file: %w", err)
|
||||
return
|
||||
|
||||
@@ -12,6 +12,7 @@ import (
|
||||
|
||||
"github.com/aquasecurity/trivy-kubernetes/pkg/artifacts"
|
||||
"github.com/aquasecurity/trivy/pkg/log"
|
||||
xos "github.com/aquasecurity/trivy/pkg/x/os"
|
||||
)
|
||||
|
||||
var r = regexp.MustCompile("[\\\\/:*?<>]")
|
||||
@@ -22,7 +23,7 @@ func generateTempFileByArtifact(artifact *artifacts.Artifact, tempDir string) (s
|
||||
// removes characters not permitted in file/directory names on Windows
|
||||
filename = filenameWindowsFriendly(filename)
|
||||
}
|
||||
file, err := os.CreateTemp(tempDir, filename)
|
||||
file, err := xos.CreateTemp(tempDir, filename)
|
||||
if err != nil {
|
||||
return "", xerrors.Errorf("failed to create temporary file: %w", err)
|
||||
}
|
||||
@@ -45,7 +46,7 @@ func generateTempFileByArtifact(artifact *artifacts.Artifact, tempDir string) (s
|
||||
// generateTempDir creates a directory with yaml files generated from kubernetes artifacts
|
||||
// returns a directory name, a map for mapping a temp target file to k8s artifact and error
|
||||
func generateTempDir(arts []*artifacts.Artifact) (string, map[string]*artifacts.Artifact, error) {
|
||||
tempDir, err := os.MkdirTemp("", "trivyk8s*")
|
||||
tempDir, err := xos.MkdirTemp("", "k8s-scan-")
|
||||
if err != nil {
|
||||
return "", nil, xerrors.Errorf("failed to create temp directory: %w", err)
|
||||
}
|
||||
|
||||
@@ -22,6 +22,7 @@ import (
|
||||
"github.com/aquasecurity/trivy/pkg/remote"
|
||||
"github.com/aquasecurity/trivy/pkg/version/doc"
|
||||
xio "github.com/aquasecurity/trivy/pkg/x/io"
|
||||
xos "github.com/aquasecurity/trivy/pkg/x/os"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -174,7 +175,7 @@ func (a *Artifact) download(ctx context.Context, layer v1.Layer, fileName, dir s
|
||||
defer bar.Finish()
|
||||
|
||||
// https://github.com/hashicorp/go-getter/issues/326
|
||||
tempDir, err := os.MkdirTemp("", "trivy")
|
||||
tempDir, err := xos.MkdirTemp("", "oci-download-")
|
||||
if err != nil {
|
||||
return xerrors.Errorf("failed to create a temp dir: %w", err)
|
||||
}
|
||||
|
||||
@@ -22,6 +22,7 @@ import (
|
||||
"github.com/aquasecurity/trivy/pkg/log"
|
||||
"github.com/aquasecurity/trivy/pkg/utils/fsutils"
|
||||
"github.com/aquasecurity/trivy/pkg/version"
|
||||
xos "github.com/aquasecurity/trivy/pkg/x/os"
|
||||
rpcCache "github.com/aquasecurity/trivy/rpc/cache"
|
||||
rpcScanner "github.com/aquasecurity/trivy/rpc/scanner"
|
||||
)
|
||||
@@ -189,7 +190,7 @@ func (w dbWorker) update(ctx context.Context, appVersion, dbDir string,
|
||||
}
|
||||
|
||||
func (w dbWorker) hotUpdate(ctx context.Context, dbDir string, dbUpdateWg, requestWg *sync.WaitGroup, opt types.RegistryOptions) error {
|
||||
tmpDir, err := os.MkdirTemp("", "db")
|
||||
tmpDir, err := xos.MkdirTemp("", "db-worker-")
|
||||
if err != nil {
|
||||
return xerrors.Errorf("failed to create a temp dir: %w", err)
|
||||
}
|
||||
|
||||
88
pkg/x/os/os.go
Normal file
88
pkg/x/os/os.go
Normal file
@@ -0,0 +1,88 @@
|
||||
package os
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
|
||||
"golang.org/x/xerrors"
|
||||
|
||||
"github.com/aquasecurity/trivy/pkg/log"
|
||||
)
|
||||
|
||||
var (
|
||||
tempDirOnce = sync.OnceValues(initTempDir)
|
||||
// initialized tracks whether the temp directory has been created.
|
||||
// This is used by Cleanup() to avoid creating a directory just to delete it.
|
||||
initialized atomic.Bool
|
||||
)
|
||||
|
||||
// initTempDir initializes the process-specific temp directory
|
||||
func initTempDir() (string, error) {
|
||||
pid := os.Getpid()
|
||||
tempDir := filepath.Join(os.TempDir(), fmt.Sprintf("trivy-%d", pid))
|
||||
|
||||
if err := os.MkdirAll(tempDir, 0o755); err != nil {
|
||||
return "", xerrors.Errorf("failed to create temp dir: %w", err)
|
||||
}
|
||||
|
||||
log.Debug("Created process-specific temp directory", log.String("path", tempDir))
|
||||
initialized.Store(true)
|
||||
return tempDir, nil
|
||||
}
|
||||
|
||||
// CreateTemp creates a temporary file, using the process-specific directory when dir is empty
|
||||
func CreateTemp(dir, pattern string) (*os.File, error) {
|
||||
// If dir is empty, use our process-specific temp directory
|
||||
if dir == "" {
|
||||
tempDir, err := tempDirOnce()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
dir = tempDir
|
||||
}
|
||||
|
||||
return os.CreateTemp(dir, pattern) //nolint: gocritic
|
||||
}
|
||||
|
||||
// MkdirTemp creates a temporary directory, using the process-specific directory as base when dir is empty
|
||||
func MkdirTemp(dir, pattern string) (string, error) {
|
||||
// If dir is empty, use our process-specific temp directory
|
||||
if dir == "" {
|
||||
tempDir, err := tempDirOnce()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
dir = tempDir
|
||||
}
|
||||
|
||||
return os.MkdirTemp(dir, pattern) //nolint: gocritic
|
||||
}
|
||||
|
||||
// TempDir returns the process-specific temp directory path
|
||||
func TempDir() string {
|
||||
tempDir, err := tempDirOnce()
|
||||
if err != nil {
|
||||
log.Debug("Failed to get process-specific temp directory, falling back to system temp", log.Err(err))
|
||||
return os.TempDir() // fallback
|
||||
}
|
||||
return tempDir
|
||||
}
|
||||
|
||||
// Cleanup removes the entire process-specific temp directory
|
||||
// Note: On Windows, directory deletion may fail if files are still open
|
||||
func Cleanup() error {
|
||||
// If temp dir was never initialized, nothing to clean up
|
||||
if !initialized.Load() {
|
||||
return nil
|
||||
}
|
||||
|
||||
tempDir, err := tempDirOnce()
|
||||
if err != nil || tempDir == "" {
|
||||
return nil
|
||||
}
|
||||
log.Debug("Cleaning up temp directory", log.String("path", tempDir))
|
||||
return os.RemoveAll(tempDir)
|
||||
}
|
||||
175
pkg/x/os/os_test.go
Normal file
175
pkg/x/os/os_test.go
Normal file
@@ -0,0 +1,175 @@
|
||||
package os
|
||||
|
||||
import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
// resetForTest resets global variables for testing
|
||||
func resetForTest() {
|
||||
tempDirOnce = sync.OnceValues(initTempDir)
|
||||
}
|
||||
|
||||
func TestTempDir(t *testing.T) {
|
||||
resetForTest()
|
||||
t.Cleanup(func() {
|
||||
_ = Cleanup()
|
||||
resetForTest()
|
||||
})
|
||||
|
||||
got := TempDir()
|
||||
|
||||
// Should contain process ID
|
||||
pid := os.Getpid()
|
||||
want := filepath.Join(os.TempDir(), "trivy-"+strconv.Itoa(pid))
|
||||
assert.Equal(t, want, got)
|
||||
|
||||
// Directory should exist
|
||||
_, err := os.Stat(got)
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
func TestCreateTemp(t *testing.T) {
|
||||
resetForTest()
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
pattern string
|
||||
}{
|
||||
{
|
||||
name: "simple pattern",
|
||||
pattern: "test-",
|
||||
},
|
||||
{
|
||||
name: "empty pattern",
|
||||
pattern: "",
|
||||
},
|
||||
{
|
||||
name: "pattern with extension",
|
||||
pattern: "test-*.txt",
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
// Test with empty dir (should use process-specific dir)
|
||||
file, err := CreateTemp("", tt.pattern) //nolint: usetesting
|
||||
require.NoError(t, err)
|
||||
t.Cleanup(func() {
|
||||
_ = file.Close()
|
||||
_ = Cleanup()
|
||||
resetForTest()
|
||||
})
|
||||
|
||||
// File should exist
|
||||
_, err = os.Stat(file.Name())
|
||||
require.NoError(t, err)
|
||||
|
||||
// File should be in our temp directory
|
||||
pid := os.Getpid()
|
||||
expectedDir := filepath.Join(os.TempDir(), "trivy-"+strconv.Itoa(pid))
|
||||
assert.True(t, strings.HasPrefix(file.Name(), expectedDir))
|
||||
|
||||
// Test with specific dir
|
||||
customDir := t.TempDir()
|
||||
file2, err := CreateTemp(customDir, tt.pattern)
|
||||
require.NoError(t, err)
|
||||
defer file2.Close()
|
||||
|
||||
// File should exist and be in custom dir
|
||||
_, err = os.Stat(file2.Name())
|
||||
require.NoError(t, err)
|
||||
assert.True(t, strings.HasPrefix(file2.Name(), customDir))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestMkdirTemp(t *testing.T) {
|
||||
resetForTest()
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
pattern string
|
||||
}{
|
||||
{
|
||||
name: "simple pattern",
|
||||
pattern: "test-",
|
||||
},
|
||||
{
|
||||
name: "empty pattern",
|
||||
pattern: "",
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
t.Cleanup(func() {
|
||||
Cleanup()
|
||||
resetForTest()
|
||||
})
|
||||
|
||||
// Test with empty dir (should use process-specific dir)
|
||||
dir, err := MkdirTemp("", tt.pattern) //nolint:usetesting
|
||||
require.NoError(t, err)
|
||||
|
||||
// Directory should exist
|
||||
_, err = os.Stat(dir)
|
||||
require.NoError(t, err)
|
||||
|
||||
// Directory should be in our temp directory
|
||||
wantParent := filepath.Join(os.TempDir(), "trivy-"+strconv.Itoa(os.Getpid()))
|
||||
assert.True(t, strings.HasPrefix(dir, wantParent))
|
||||
|
||||
// Test with specific dir
|
||||
customParent := t.TempDir()
|
||||
dir2, err := MkdirTemp(customParent, tt.pattern) //nolint:usetesting
|
||||
require.NoError(t, err)
|
||||
|
||||
// Directory should exist and be in custom parent
|
||||
_, err = os.Stat(dir2)
|
||||
require.NoError(t, err)
|
||||
assert.True(t, strings.HasPrefix(dir2, customParent))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestCleanup(t *testing.T) {
|
||||
resetForTest()
|
||||
t.Cleanup(func() {
|
||||
resetForTest()
|
||||
})
|
||||
|
||||
// Create a temp file
|
||||
file, err := CreateTemp("", "test-") //nolint: usetesting
|
||||
require.NoError(t, err)
|
||||
filename := file.Name()
|
||||
require.NoError(t, file.Close())
|
||||
|
||||
// Directory should exist
|
||||
dir := filepath.Join(os.TempDir(), "trivy-"+strconv.Itoa(os.Getpid()))
|
||||
_, err = os.Stat(dir)
|
||||
require.NoError(t, err)
|
||||
|
||||
// File should exist
|
||||
_, err = os.Stat(filename)
|
||||
require.NoError(t, err)
|
||||
|
||||
// Cleanup
|
||||
err = Cleanup()
|
||||
require.NoError(t, err)
|
||||
|
||||
// File should be gone
|
||||
_, err = os.Stat(filename)
|
||||
require.ErrorIs(t, err, os.ErrNotExist)
|
||||
|
||||
// Directory should be gone
|
||||
_, err = os.Stat(dir)
|
||||
assert.ErrorIs(t, err, os.ErrNotExist)
|
||||
}
|
||||
Reference in New Issue
Block a user