get.porter.sh/porter@v1.3.0/pkg/secrets/strategy.go (about) 1 package secrets 2 3 import ( 4 "encoding/json" 5 "errors" 6 "fmt" 7 8 "gopkg.in/yaml.v3" 9 ) 10 11 // Set is an actual set of resolved values. 12 // This is the output of resolving a parameter or credential set file. 13 type Set map[string]string 14 15 // Merge merges a second Set into the base. 16 // 17 // Duplicate names are not allow and will result in an 18 // error, this is the case even if the values are identical. 19 func (s Set) Merge(s2 Set) error { 20 for k, v := range s2 { 21 if _, ok := s[k]; ok { 22 return fmt.Errorf("ambiguous value resolution: %q is already present in base sets, cannot merge", k) 23 } 24 s[k] = v 25 } 26 return nil 27 } 28 29 // SourceMap maps from a parameter or credential name to a source strategy for resolving its value. 30 type SourceMap struct { 31 // Name is the name of the parameter or credential. 32 Name string `json:"name" yaml:"name"` 33 34 // Source defines a strategy for resolving a value from the specified source. 35 Source Source `json:"source,omitempty" yaml:"source,omitempty"` 36 37 // ResolvedValue holds the resolved parameter or credential value. 38 // When a parameter or credential is resolved, it is loaded into this field. In all 39 // other cases, it is empty. This field is omitted during serialization. 40 ResolvedValue string `json:"-" yaml:"-"` 41 } 42 43 // Source specifies how to resolve a parameter or credential from an external 44 // source. 45 type Source struct { 46 // Strategy to resolve the source value, e.g. "secret" or "env". 47 Strategy string 48 49 // Hint to the strategy handler on how to resolve the value. 50 // For example the name of the secret in a secret store or name of an environment variable. 51 Hint string 52 } 53 54 func (s Source) MarshalRaw() interface{} { 55 if s.Strategy == "" { 56 return nil 57 } 58 return map[string]interface{}{s.Strategy: s.Hint} 59 } 60 61 func (s *Source) UnmarshalRaw(raw map[string]interface{}) error { 62 switch len(raw) { 63 case 0: 64 s.Strategy = "" 65 s.Hint = "" 66 return nil 67 case 1: 68 for k, v := range raw { 69 s.Strategy = k 70 if value, ok := v.(string); ok { 71 s.Hint = value 72 73 } else if s.Strategy == "value" { 74 value, err := unmarshalRawValue(v) 75 if err != nil { 76 return err 77 } 78 s.Hint = value 79 } else { 80 s.Hint = fmt.Sprintf("%v", s.Hint) 81 } 82 } 83 return nil 84 default: 85 return errors.New("multiple key/value pairs specified for source but only one may be defined") 86 } 87 } 88 89 func unmarshalRawValue(rawValue interface{}) (string, error) { 90 switch value := rawValue.(type) { 91 case []interface{}, map[string]interface{}: 92 encodedValue, err := json.Marshal(value) 93 if err != nil { 94 return "", fmt.Errorf("unable to convert %T into a string: %w", value, err) 95 } 96 return string(encodedValue), nil 97 case nil: 98 return "", nil 99 default: 100 return fmt.Sprintf("%v", value), nil 101 } 102 } 103 104 var ( 105 _ json.Marshaler = Source{} 106 _ json.Unmarshaler = &Source{} 107 _ yaml.Marshaler = Source{} 108 _ yaml.Unmarshaler = &Source{} 109 ) 110 111 func (s Source) MarshalJSON() ([]byte, error) { 112 raw := s.MarshalRaw() 113 return json.Marshal(raw) 114 } 115 116 func (s *Source) UnmarshalJSON(data []byte) error { 117 var raw map[string]interface{} 118 err := json.Unmarshal(data, &raw) 119 if err != nil { 120 return err 121 } 122 return s.UnmarshalRaw(raw) 123 } 124 125 func (s *Source) UnmarshalYAML(value *yaml.Node) error { 126 var raw map[string]interface{} 127 err := value.Decode(&raw) 128 if err != nil { 129 return err 130 } 131 return s.UnmarshalRaw(raw) 132 } 133 134 func (s Source) MarshalYAML() (interface{}, error) { 135 return s.MarshalRaw(), nil 136 } 137 138 type StrategyList []SourceMap 139 140 func (l StrategyList) Less(i, j int) bool { 141 return l[i].Name < l[j].Name 142 } 143 144 func (l StrategyList) Swap(i, j int) { 145 tmp := l[i] 146 l[i] = l[j] 147 l[j] = tmp 148 } 149 150 func (l StrategyList) Len() int { 151 return len(l) 152 } 153 154 func (l StrategyList) Contains(name string) bool { 155 for _, param := range l { 156 if param.Name == name { 157 return true 158 } 159 } 160 return false 161 }