github.com/wolfi-dev/wolfictl@v0.16.11/pkg/configs/advisory/v2/yaml.go (about) 1 package v2 2 3 import ( 4 "bytes" 5 "fmt" 6 7 "gopkg.in/yaml.v3" 8 ) 9 10 // strictUnmarshal is a helper function that unmarshals a YAML node into a 11 // struct and returns an error if the node contains unknown fields. 12 // 13 // This function is useful because while the yaml.v3 package has a KnownFields 14 // option for its Decoder, this option doesn't cascade to nested nodes that have 15 // custom unmarshaling logic, which means the safety guaranteed at the root YAML 16 // node is not necessarily guaranteed at all children nodes. This is a known 17 // deficiency in the yaml.v3 library: 18 // https://github.com/go-yaml/yaml/issues/460. 19 // 20 // Note that this function will return an error if the node is empty. This is 21 // because the yaml.v3 library favors other unmarshal errors over unknown 22 // field errors, so there's no way to distinguish between an empty node and a 23 // node that contains unknown fields. 24 func strictUnmarshal[T any](n *yaml.Node) (*T, error) { 25 by, err := yaml.Marshal(n) 26 if err != nil { 27 return nil, fmt.Errorf("intermediate marshaling node to bytes failed: %w", err) 28 } 29 30 buf := bytes.NewBuffer(by) 31 dec := yaml.NewDecoder(buf) 32 dec.KnownFields(true) 33 34 data := new(T) 35 err = dec.Decode(data) 36 if err != nil { 37 return nil, fmt.Errorf( 38 "failed to decode to Go type %T: %w", 39 data, 40 err, 41 ) 42 } 43 44 return data, nil 45 }