github.com/adevinta/lava@v0.7.2/cmd/lava/internal/run/runflag.go (about)

     1  // Copyright 2024 Adevinta
     2  
     3  package run
     4  
     5  import (
     6  	"errors"
     7  	"fmt"
     8  	"io"
     9  	"log/slog"
    10  	"os"
    11  	"strings"
    12  	"time"
    13  
    14  	agentconfig "github.com/adevinta/vulcan-agent/config"
    15  	types "github.com/adevinta/vulcan-types"
    16  
    17  	"github.com/adevinta/lava/internal/assettypes"
    18  	"github.com/adevinta/lava/internal/config"
    19  )
    20  
    21  // typeFlag represents the asset type provided with the -type flag.
    22  type typeFlag types.AssetType
    23  
    24  // Set parses the value provided with the -type flag. It returns error
    25  // if it is not a know asset type.
    26  func (typ *typeFlag) Set(s string) error {
    27  	if s == "" {
    28  		return errors.New("empty asset type")
    29  	}
    30  
    31  	at := types.AssetType(s)
    32  	if !at.IsValid() && !assettypes.IsValid(at) {
    33  		return fmt.Errorf("invalid asset type: %v", s)
    34  	}
    35  	*typ = typeFlag(at)
    36  	return nil
    37  }
    38  
    39  // String returns the string representation of a -type flag value.
    40  func (typ typeFlag) String() string {
    41  	return types.AssetType(typ).String()
    42  }
    43  
    44  // varFlag represents the environment variables provided with the -var
    45  // flag.
    46  type varFlag map[string]string
    47  
    48  // Set parses the values provided with the -var flag. The environment
    49  // variable must follow the format "name[=value]". If there is no
    50  // equal sign, the value of the variable is got from the environment.
    51  func (envvar *varFlag) Set(s string) error {
    52  	if *envvar == nil {
    53  		*envvar = make(map[string]string)
    54  	}
    55  
    56  	if s == "" {
    57  		return errors.New("empty environment variable")
    58  	}
    59  
    60  	name, value, found := strings.Cut(s, "=")
    61  	if !found {
    62  		value = os.Getenv(name)
    63  	}
    64  
    65  	if name == "" {
    66  		return errors.New("empty envvar name")
    67  	}
    68  
    69  	(*envvar)[name] = value
    70  	return nil
    71  }
    72  
    73  // String returns the string representation of the provided
    74  // environment variables.
    75  func (envvar varFlag) String() string {
    76  	var vars []string
    77  	for k, v := range envvar {
    78  		vars = append(vars, fmt.Sprintf("%v=%v", k, v))
    79  	}
    80  	return strings.Join(vars, ":")
    81  }
    82  
    83  // authFlag represents the container registry credentials provided
    84  // with the -user flag.
    85  type userFlag struct {
    86  	Username string
    87  	Password string
    88  }
    89  
    90  // osStdin is used to read the container registry password. It is used
    91  // by tests.
    92  var osStdin io.Reader = os.Stdin
    93  
    94  // Set parses the values provided with the -user flag. The container
    95  // registry credentials must follow the format
    96  // "username[:[password]]". The username and password are split around
    97  // the first instance of the colon. So the username cannot contain a
    98  // colon. If there is no colon, the password is read from the standard
    99  // input.
   100  func (userinfo *userFlag) Set(s string) error {
   101  	if s == "" {
   102  		return errors.New("empty registry credentials")
   103  	}
   104  
   105  	username, password, found := strings.Cut(s, ":")
   106  	if !found {
   107  		b, err := io.ReadAll(osStdin)
   108  		if err != nil {
   109  			return fmt.Errorf("read password: %w", err)
   110  		}
   111  		password = string(b)
   112  	}
   113  
   114  	*userinfo = userFlag{
   115  		Username: username,
   116  		Password: password,
   117  	}
   118  	return nil
   119  }
   120  
   121  // String returns the string representation of the provided container
   122  // registry credentials. The password is masked.
   123  func (userinfo userFlag) String() string {
   124  	return userinfo.Username + ":****"
   125  }
   126  
   127  func init() {
   128  	CmdRun.Flag.Var(&runType, "type", "target type")
   129  	CmdRun.Flag.DurationVar(&runTimeout, "timeout", 600*time.Second, "checktype timeout")
   130  	CmdRun.Flag.StringVar(&runOpt, "opt", "", "checktype options")
   131  	CmdRun.Flag.StringVar(&runOptfile, "optfile", "", "checktype options file")
   132  	CmdRun.Flag.Var(&runVar, "var", "checktype environment variable")
   133  	CmdRun.Flag.TextVar(&runPull, "pull", agentconfig.PullPolicyIfNotPresent, "container image pull policy")
   134  	CmdRun.Flag.StringVar(&runRegistry, "registry", "", "container registry")
   135  	CmdRun.Flag.Var(&runUser, "user", "container registry credentials")
   136  	CmdRun.Flag.TextVar(&runSeverity, "severity", config.SeverityHigh, "minimum severity required to report a finding")
   137  	CmdRun.Flag.StringVar(&runO, "o", "", "output file")
   138  	CmdRun.Flag.TextVar(&runFmt, "fmt", config.OutputFormatHuman, "output format")
   139  	CmdRun.Flag.StringVar(&runMetrics, "metrics", "", "metrics file")
   140  	CmdRun.Flag.TextVar(&runLog, "log", slog.LevelInfo, "log level")
   141  }