github.com/devseccon/trivy@v0.47.1-0.20231123133102-bd902a0bd996/pkg/fanal/cache/key.go (about)

     1  package cache
     2  
     3  import (
     4  	"crypto/sha256"
     5  	"encoding/json"
     6  	"fmt"
     7  	"io"
     8  	"os"
     9  	"path/filepath"
    10  
    11  	"golang.org/x/mod/sumdb/dirhash"
    12  	"golang.org/x/xerrors"
    13  
    14  	"github.com/devseccon/trivy/pkg/fanal/analyzer"
    15  	"github.com/devseccon/trivy/pkg/fanal/artifact"
    16  )
    17  
    18  func CalcKey(id string, analyzerVersions analyzer.Versions, hookVersions map[string]int, artifactOpt artifact.Option) (string, error) {
    19  	// Sort options for consistent results
    20  	artifactOpt.Sort()
    21  	artifactOpt.MisconfScannerOption.Sort()
    22  
    23  	h := sha256.New()
    24  
    25  	// Write ID, analyzer/handler versions, skipped files/dirs and file patterns
    26  	keyBase := struct {
    27  		ID               string
    28  		AnalyzerVersions analyzer.Versions
    29  		HookVersions     map[string]int
    30  		SkipFiles        []string
    31  		SkipDirs         []string
    32  		FilePatterns     []string `json:",omitempty"`
    33  	}{id, analyzerVersions, hookVersions, artifactOpt.SkipFiles, artifactOpt.SkipDirs, artifactOpt.FilePatterns}
    34  
    35  	if err := json.NewEncoder(h).Encode(keyBase); err != nil {
    36  		return "", xerrors.Errorf("json encode error: %w", err)
    37  	}
    38  
    39  	// Write policy, data contents and secret config file
    40  	paths := append(artifactOpt.MisconfScannerOption.PolicyPaths, artifactOpt.MisconfScannerOption.DataPaths...)
    41  
    42  	// Check if the secret config exists.
    43  	if _, err := os.Stat(artifactOpt.SecretScannerOption.ConfigPath); err == nil {
    44  		paths = append(paths, artifactOpt.SecretScannerOption.ConfigPath)
    45  	}
    46  
    47  	for _, p := range paths {
    48  		hash, err := hashContents(p)
    49  		if err != nil {
    50  			return "", err
    51  		}
    52  
    53  		if _, err := h.Write([]byte(hash)); err != nil {
    54  			return "", xerrors.Errorf("sha256 write error: %w", err)
    55  		}
    56  	}
    57  
    58  	return fmt.Sprintf("sha256:%x", h.Sum(nil)), nil
    59  }
    60  
    61  func hashContents(path string) (string, error) {
    62  	fi, err := os.Stat(path)
    63  	if err != nil {
    64  		return "", xerrors.Errorf("file %q stat error: %w", path, err)
    65  	}
    66  
    67  	var hash string
    68  
    69  	if fi.IsDir() {
    70  		hash, err = dirhash.HashDir(path, "", dirhash.DefaultHash)
    71  		if err != nil {
    72  			return "", xerrors.Errorf("hash dir error (%s): %w", path, err)
    73  		}
    74  	} else {
    75  		hash, err = dirhash.DefaultHash([]string{filepath.Base(path)}, func(_ string) (io.ReadCloser, error) {
    76  			return os.Open(path)
    77  		})
    78  		if err != nil {
    79  			return "", xerrors.Errorf("hash file error (%s): %w", path, err)
    80  		}
    81  	}
    82  	return hash, nil
    83  }