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  }