github.com/devseccon/trivy@v0.47.1-0.20231123133102-bd902a0bd996/pkg/flag/cache_flags.go (about)

     1  package flag
     2  
     3  import (
     4  	"fmt"
     5  	"strings"
     6  	"time"
     7  
     8  	"github.com/samber/lo"
     9  	"golang.org/x/xerrors"
    10  )
    11  
    12  // e.g. config yaml:
    13  //
    14  //	cache:
    15  //	  clear: true
    16  //	  backend: "redis://localhost:6379"
    17  //	redis:
    18  //	  ca: ca-cert.pem
    19  //	  cert: cert.pem
    20  //	  key: key.pem
    21  var (
    22  	ClearCacheFlag = Flag{
    23  		Name:       "clear-cache",
    24  		ConfigName: "cache.clear",
    25  		Default:    false,
    26  		Usage:      "clear image caches without scanning",
    27  	}
    28  	CacheBackendFlag = Flag{
    29  		Name:       "cache-backend",
    30  		ConfigName: "cache.backend",
    31  		Default:    "fs",
    32  		Usage:      "cache backend (e.g. redis://localhost:6379)",
    33  	}
    34  	CacheTTLFlag = Flag{
    35  		Name:       "cache-ttl",
    36  		ConfigName: "cache.ttl",
    37  		Default:    time.Duration(0),
    38  		Usage:      "cache TTL when using redis as cache backend",
    39  	}
    40  	RedisTLSFlag = Flag{
    41  		Name:       "redis-tls",
    42  		ConfigName: "cache.redis.tls",
    43  		Default:    false,
    44  		Usage:      "enable redis TLS with public certificates, if using redis as cache backend",
    45  	}
    46  	RedisCACertFlag = Flag{
    47  		Name:       "redis-ca",
    48  		ConfigName: "cache.redis.ca",
    49  		Default:    "",
    50  		Usage:      "redis ca file location, if using redis as cache backend",
    51  	}
    52  	RedisCertFlag = Flag{
    53  		Name:       "redis-cert",
    54  		ConfigName: "cache.redis.cert",
    55  		Default:    "",
    56  		Usage:      "redis certificate file location, if using redis as cache backend",
    57  	}
    58  	RedisKeyFlag = Flag{
    59  		Name:       "redis-key",
    60  		ConfigName: "cache.redis.key",
    61  		Default:    "",
    62  		Usage:      "redis key file location, if using redis as cache backend",
    63  	}
    64  )
    65  
    66  // CacheFlagGroup composes common printer flag structs used for commands requiring cache logic.
    67  type CacheFlagGroup struct {
    68  	ClearCache   *Flag
    69  	CacheBackend *Flag
    70  	CacheTTL     *Flag
    71  
    72  	RedisTLS    *Flag
    73  	RedisCACert *Flag
    74  	RedisCert   *Flag
    75  	RedisKey    *Flag
    76  }
    77  
    78  type CacheOptions struct {
    79  	ClearCache   bool
    80  	CacheBackend string
    81  	CacheTTL     time.Duration
    82  	RedisTLS     bool
    83  	RedisOptions
    84  }
    85  
    86  // RedisOptions holds the options for redis cache
    87  type RedisOptions struct {
    88  	RedisCACert string
    89  	RedisCert   string
    90  	RedisKey    string
    91  }
    92  
    93  // NewCacheFlagGroup returns a default CacheFlagGroup
    94  func NewCacheFlagGroup() *CacheFlagGroup {
    95  	return &CacheFlagGroup{
    96  		ClearCache:   &ClearCacheFlag,
    97  		CacheBackend: &CacheBackendFlag,
    98  		CacheTTL:     &CacheTTLFlag,
    99  		RedisTLS:     &RedisTLSFlag,
   100  		RedisCACert:  &RedisCACertFlag,
   101  		RedisCert:    &RedisCertFlag,
   102  		RedisKey:     &RedisKeyFlag,
   103  	}
   104  }
   105  
   106  func (fg *CacheFlagGroup) Name() string {
   107  	return "Cache"
   108  }
   109  
   110  func (fg *CacheFlagGroup) Flags() []*Flag {
   111  	return []*Flag{fg.ClearCache, fg.CacheBackend, fg.CacheTTL, fg.RedisTLS, fg.RedisCACert, fg.RedisCert, fg.RedisKey}
   112  }
   113  
   114  func (fg *CacheFlagGroup) ToOptions() (CacheOptions, error) {
   115  	cacheBackend := getString(fg.CacheBackend)
   116  	redisOptions := RedisOptions{
   117  		RedisCACert: getString(fg.RedisCACert),
   118  		RedisCert:   getString(fg.RedisCert),
   119  		RedisKey:    getString(fg.RedisKey),
   120  	}
   121  
   122  	// "redis://" or "fs" are allowed for now
   123  	// An empty value is also allowed for testability
   124  	if !strings.HasPrefix(cacheBackend, "redis://") &&
   125  		cacheBackend != "fs" && cacheBackend != "" {
   126  		return CacheOptions{}, xerrors.Errorf("unsupported cache backend: %s", cacheBackend)
   127  	}
   128  	// if one of redis option not nil, make sure CA, cert, and key provided
   129  	if !lo.IsEmpty(redisOptions) {
   130  		if redisOptions.RedisCACert == "" || redisOptions.RedisCert == "" || redisOptions.RedisKey == "" {
   131  			return CacheOptions{}, xerrors.Errorf("you must provide Redis CA, cert and key file path when using TLS")
   132  		}
   133  	}
   134  
   135  	return CacheOptions{
   136  		ClearCache:   getBool(fg.ClearCache),
   137  		CacheBackend: cacheBackend,
   138  		CacheTTL:     getDuration(fg.CacheTTL),
   139  		RedisTLS:     getBool(fg.RedisTLS),
   140  		RedisOptions: redisOptions,
   141  	}, nil
   142  }
   143  
   144  // CacheBackendMasked returns the redis connection string masking credentials
   145  func (o *CacheOptions) CacheBackendMasked() string {
   146  	endIndex := strings.Index(o.CacheBackend, "@")
   147  	if endIndex == -1 {
   148  		return o.CacheBackend
   149  	}
   150  
   151  	startIndex := strings.Index(o.CacheBackend, "//")
   152  
   153  	return fmt.Sprintf("%s****%s", o.CacheBackend[:startIndex+2], o.CacheBackend[endIndex:])
   154  }