github.com/panekj/cli@v0.0.0-20230304125325-467dd2f3797e/opts/secret.go (about) 1 package opts 2 3 import ( 4 "encoding/csv" 5 "fmt" 6 "os" 7 "strconv" 8 "strings" 9 10 swarmtypes "github.com/docker/docker/api/types/swarm" 11 ) 12 13 // SecretOpt is a Value type for parsing secrets 14 type SecretOpt struct { 15 values []*swarmtypes.SecretReference 16 } 17 18 // Set a new secret value 19 func (o *SecretOpt) Set(value string) error { 20 csvReader := csv.NewReader(strings.NewReader(value)) 21 fields, err := csvReader.Read() 22 if err != nil { 23 return err 24 } 25 26 options := &swarmtypes.SecretReference{ 27 File: &swarmtypes.SecretReferenceFileTarget{ 28 UID: "0", 29 GID: "0", 30 Mode: 0o444, 31 }, 32 } 33 34 // support a simple syntax of --secret foo 35 if len(fields) == 1 && !strings.Contains(fields[0], "=") { 36 options.File.Name = fields[0] 37 options.SecretName = fields[0] 38 o.values = append(o.values, options) 39 return nil 40 } 41 42 for _, field := range fields { 43 key, val, ok := strings.Cut(field, "=") 44 if !ok || key == "" { 45 return fmt.Errorf("invalid field '%s' must be a key=value pair", field) 46 } 47 // TODO(thaJeztah): these options should not be case-insensitive. 48 switch strings.ToLower(key) { 49 case "source", "src": 50 options.SecretName = val 51 case "target": 52 options.File.Name = val 53 case "uid": 54 options.File.UID = val 55 case "gid": 56 options.File.GID = val 57 case "mode": 58 m, err := strconv.ParseUint(val, 0, 32) 59 if err != nil { 60 return fmt.Errorf("invalid mode specified: %v", err) 61 } 62 63 options.File.Mode = os.FileMode(m) 64 default: 65 return fmt.Errorf("invalid field in secret request: %s", key) 66 } 67 } 68 69 if options.SecretName == "" { 70 return fmt.Errorf("source is required") 71 } 72 if options.File.Name == "" { 73 options.File.Name = options.SecretName 74 } 75 76 o.values = append(o.values, options) 77 return nil 78 } 79 80 // Type returns the type of this option 81 func (o *SecretOpt) Type() string { 82 return "secret" 83 } 84 85 // String returns a string repr of this option 86 func (o *SecretOpt) String() string { 87 secrets := []string{} 88 for _, secret := range o.values { 89 repr := fmt.Sprintf("%s -> %s", secret.SecretName, secret.File.Name) 90 secrets = append(secrets, repr) 91 } 92 return strings.Join(secrets, ", ") 93 } 94 95 // Value returns the secret requests 96 func (o *SecretOpt) Value() []*swarmtypes.SecretReference { 97 return o.values 98 }