github.com/in-toto/in-toto-golang@v0.9.1-0.20240517212500-990269f763cf/in_toto/util.go (about)

     1  package in_toto
     2  
     3  import (
     4  	"encoding/json"
     5  	"errors"
     6  	"fmt"
     7  	"reflect"
     8  	"strings"
     9  )
    10  
    11  var ErrUnknownMetadataType = errors.New("unknown metadata type encountered: not link or layout")
    12  
    13  /*
    14  Set represents a data structure for set operations. See `NewSet` for how to
    15  create a Set, and available Set receivers for useful set operations.
    16  
    17  Under the hood Set aliases map[string]struct{}, where the map keys are the set
    18  elements and the map values are a memory-efficient way of storing the keys.
    19  */
    20  type Set map[string]struct{}
    21  
    22  /*
    23  NewSet creates a new Set, assigns it the optionally passed variadic string
    24  elements, and returns it.
    25  */
    26  func NewSet(elems ...string) Set {
    27  	var s Set = make(map[string]struct{})
    28  	for _, elem := range elems {
    29  		s.Add(elem)
    30  	}
    31  	return s
    32  }
    33  
    34  /*
    35  Has returns True if the passed string is member of the set on which it was
    36  called and False otherwise.
    37  */
    38  func (s Set) Has(elem string) bool {
    39  	_, ok := s[elem]
    40  	return ok
    41  }
    42  
    43  /*
    44  Add adds the passed string to the set on which it was called, if the string is
    45  not a member of the set.
    46  */
    47  func (s Set) Add(elem string) {
    48  	s[elem] = struct{}{}
    49  }
    50  
    51  /*
    52  Remove removes the passed string from the set on which was is called, if the
    53  string is a member of the set.
    54  */
    55  func (s Set) Remove(elem string) {
    56  	delete(s, elem)
    57  }
    58  
    59  /*
    60  Intersection creates and returns a new Set with the elements of the set on
    61  which it was called that are also in the passed set.
    62  */
    63  func (s Set) Intersection(s2 Set) Set {
    64  	res := NewSet()
    65  	for elem := range s {
    66  		if !s2.Has(elem) {
    67  			continue
    68  		}
    69  		res.Add(elem)
    70  	}
    71  	return res
    72  }
    73  
    74  /*
    75  Difference creates and returns a new Set with the elements of the set on
    76  which it was called that are not in the passed set.
    77  */
    78  func (s Set) Difference(s2 Set) Set {
    79  	res := NewSet()
    80  	for elem := range s {
    81  		if s2.Has(elem) {
    82  			continue
    83  		}
    84  		res.Add(elem)
    85  	}
    86  	return res
    87  }
    88  
    89  /*
    90  Filter creates and returns a new Set with the elements of the set on which it
    91  was called that match the passed pattern. A matching error is treated like a
    92  non-match plus a warning is printed.
    93  */
    94  func (s Set) Filter(pattern string) Set {
    95  	res := NewSet()
    96  	for elem := range s {
    97  		matched, err := match(pattern, elem)
    98  		if err != nil {
    99  			fmt.Printf("WARNING: %s, pattern was '%s'\n", err, pattern)
   100  			continue
   101  		}
   102  		if !matched {
   103  			continue
   104  		}
   105  		res.Add(elem)
   106  	}
   107  	return res
   108  }
   109  
   110  /*
   111  Slice creates and returns an unordered string slice with the elements of the
   112  set on which it was called.
   113  */
   114  func (s Set) Slice() []string {
   115  	var res []string
   116  	res = make([]string, 0, len(s))
   117  	for elem := range s {
   118  		res = append(res, elem)
   119  	}
   120  	return res
   121  }
   122  
   123  /*
   124  artifactsDictKeyStrings returns string keys of passed HashObj map in an
   125  unordered string slice.
   126  */
   127  func artifactsDictKeyStrings(m map[string]HashObj) []string {
   128  	res := make([]string, len(m))
   129  	i := 0
   130  	for k := range m {
   131  		res[i] = k
   132  		i++
   133  	}
   134  	return res
   135  }
   136  
   137  /*
   138  IsSubSet checks if the parameter subset is a
   139  subset of the superset s.
   140  */
   141  func (s Set) IsSubSet(subset Set) bool {
   142  	if len(subset) > len(s) {
   143  		return false
   144  	}
   145  	for key := range subset {
   146  		if s.Has(key) {
   147  			continue
   148  		} else {
   149  			return false
   150  		}
   151  	}
   152  	return true
   153  }
   154  
   155  func loadPayload(payloadBytes []byte) (any, error) {
   156  	var payload map[string]any
   157  	if err := json.Unmarshal(payloadBytes, &payload); err != nil {
   158  		return nil, fmt.Errorf("error decoding payload: %w", err)
   159  	}
   160  
   161  	if payload["_type"] == "link" {
   162  		var link Link
   163  		if err := checkRequiredJSONFields(payload, reflect.TypeOf(link)); err != nil {
   164  			return nil, fmt.Errorf("error decoding payload: %w", err)
   165  		}
   166  
   167  		decoder := json.NewDecoder(strings.NewReader(string(payloadBytes)))
   168  		decoder.DisallowUnknownFields()
   169  		if err := decoder.Decode(&link); err != nil {
   170  			return nil, fmt.Errorf("error decoding payload: %w", err)
   171  		}
   172  
   173  		return link, nil
   174  	} else if payload["_type"] == "layout" {
   175  		var layout Layout
   176  		if err := checkRequiredJSONFields(payload, reflect.TypeOf(layout)); err != nil {
   177  			return nil, fmt.Errorf("error decoding payload: %w", err)
   178  		}
   179  
   180  		decoder := json.NewDecoder(strings.NewReader(string(payloadBytes)))
   181  		decoder.DisallowUnknownFields()
   182  		if err := decoder.Decode(&layout); err != nil {
   183  			return nil, fmt.Errorf("error decoding payload: %w", err)
   184  		}
   185  
   186  		return layout, nil
   187  	}
   188  
   189  	return nil, ErrUnknownMetadataType
   190  }