github.com/aquasecurity/trivy-iac@v0.8.1-0.20240127024015-3d8e412cf0ab/pkg/scanners/kubernetes/parser/manifest_node.go (about)

     1  package parser
     2  
     3  import (
     4  	"fmt"
     5  	"strconv"
     6  
     7  	"gopkg.in/yaml.v3"
     8  )
     9  
    10  type TagType string
    11  
    12  const (
    13  	TagBool   TagType = "!!bool"
    14  	TagInt    TagType = "!!int"
    15  	TagFloat  TagType = "!!float"
    16  	TagStr    TagType = "!!str"
    17  	TagString TagType = "!!string"
    18  	TagSlice  TagType = "!!seq"
    19  	TagMap    TagType = "!!map"
    20  )
    21  
    22  type ManifestNode struct {
    23  	StartLine int
    24  	EndLine   int
    25  	Offset    int
    26  	Value     interface{}
    27  	Type      TagType
    28  	Path      string
    29  }
    30  
    31  func (r *ManifestNode) ToRego() interface{} {
    32  	if r == nil {
    33  		return nil
    34  	}
    35  	switch r.Type {
    36  	case TagBool, TagInt, TagString, TagStr:
    37  		return r.Value
    38  	case TagSlice:
    39  		var output []interface{}
    40  		for _, node := range r.Value.([]ManifestNode) {
    41  			output = append(output, node.ToRego())
    42  		}
    43  		return output
    44  	case TagMap:
    45  		output := make(map[string]interface{})
    46  		output["__defsec_metadata"] = map[string]interface{}{
    47  			"startline": r.StartLine,
    48  			"endline":   r.EndLine,
    49  			"filepath":  r.Path,
    50  			"offset":    r.Offset,
    51  		}
    52  		for key, node := range r.Value.(map[string]ManifestNode) {
    53  			output[key] = node.ToRego()
    54  		}
    55  		return output
    56  	}
    57  	return nil
    58  }
    59  
    60  func (r *ManifestNode) UnmarshalYAML(node *yaml.Node) error {
    61  
    62  	r.StartLine = node.Line
    63  	r.EndLine = node.Line
    64  	r.Type = TagType(node.Tag)
    65  
    66  	switch TagType(node.Tag) {
    67  	case TagString, TagStr:
    68  
    69  		r.Value = node.Value
    70  	case TagInt:
    71  		val, err := strconv.Atoi(node.Value)
    72  		if err != nil {
    73  			return err
    74  		}
    75  		r.Value = val
    76  	case TagFloat:
    77  		val, err := strconv.ParseFloat(node.Value, 64)
    78  		if err != nil {
    79  			return err
    80  		}
    81  		r.Value = val
    82  	case TagBool:
    83  		val, err := strconv.ParseBool(node.Value)
    84  		if err != nil {
    85  			return err
    86  		}
    87  		r.Value = val
    88  	case TagMap:
    89  		return r.handleMapTag(node)
    90  	case TagSlice:
    91  		return r.handleSliceTag(node)
    92  
    93  	default:
    94  		return fmt.Errorf("node tag is not supported %s", node.Tag)
    95  	}
    96  	return nil
    97  }
    98  
    99  func (r *ManifestNode) handleSliceTag(node *yaml.Node) error {
   100  	var nodes []ManifestNode
   101  	max := node.Line
   102  	for _, contentNode := range node.Content {
   103  		newNode := new(ManifestNode)
   104  		newNode.Path = r.Path
   105  		if err := contentNode.Decode(newNode); err != nil {
   106  			return err
   107  		}
   108  		if newNode.EndLine > max {
   109  			max = newNode.EndLine
   110  		}
   111  		nodes = append(nodes, *newNode)
   112  	}
   113  	r.EndLine = max
   114  	r.Value = nodes
   115  	return nil
   116  }
   117  
   118  func (r *ManifestNode) handleMapTag(node *yaml.Node) error {
   119  	output := make(map[string]ManifestNode)
   120  	var key string
   121  	max := node.Line
   122  	for i, contentNode := range node.Content {
   123  		if i == 0 || i%2 == 0 {
   124  			key = contentNode.Value
   125  		} else {
   126  			newNode := new(ManifestNode)
   127  			newNode.Path = r.Path
   128  			if err := contentNode.Decode(newNode); err != nil {
   129  				return err
   130  			}
   131  			output[key] = *newNode
   132  			if newNode.EndLine > max {
   133  				max = newNode.EndLine
   134  			}
   135  		}
   136  	}
   137  	r.EndLine = max
   138  	r.Value = output
   139  	return nil
   140  }