github.com/khulnasoft-lab/defsec@v1.0.5-0.20230827010352-5e9f46893d95/pkg/scanners/terraform/parser/resolvers/cache.go (about) 1 package resolvers 2 3 import ( 4 "context" 5 "crypto/md5" // nolint 6 "fmt" 7 "io/fs" 8 "os" 9 "path/filepath" 10 ) 11 12 type cacheResolver struct{} 13 14 var Cache = &cacheResolver{} 15 16 const tempDirName = ".khulnasoft" 17 18 func locateCacheFS() (fs.FS, error) { 19 dir, err := locateCacheDir() 20 if err != nil { 21 return nil, err 22 } 23 return os.DirFS(dir), nil 24 } 25 26 func locateCacheDir() (string, error) { 27 cacheDir := filepath.Join(os.TempDir(), tempDirName, "cache") 28 if err := os.MkdirAll(cacheDir, 0o755); err != nil { 29 return "", err 30 } 31 if !isWritable(cacheDir) { 32 return "", fmt.Errorf("cache directory is not writable") 33 } 34 return cacheDir, nil 35 } 36 37 func (r *cacheResolver) Resolve(_ context.Context, _ fs.FS, opt Options) (filesystem fs.FS, prefix string, downloadPath string, applies bool, err error) { 38 if !opt.AllowCache { 39 opt.Debug("Cache is disabled.") 40 return nil, "", "", false, nil 41 } 42 cacheFS, err := locateCacheFS() 43 if err != nil { 44 opt.Debug("No cache filesystem is available on this machine.") 45 return nil, "", "", false, nil 46 } 47 key := cacheKey(opt.Source, opt.Version, opt.RelativePath) 48 opt.Debug("Trying to resolve: %s", key) 49 if info, err := fs.Stat(cacheFS, filepath.ToSlash(key)); err == nil && info.IsDir() { 50 opt.Debug("Module '%s' resolving via cache...", opt.Name) 51 cacheDir, err := locateCacheDir() 52 if err != nil { 53 return nil, "", "", true, err 54 } 55 return os.DirFS(filepath.Join(cacheDir, key)), opt.OriginalSource, ".", true, nil 56 } 57 return nil, "", "", false, nil 58 } 59 60 func cacheKey(source, version, relativePath string) string { 61 return fmt.Sprintf("%x", md5.Sum([]byte(fmt.Sprintf("%s:%s:%s", source, version, relativePath)))) // nolint 62 }