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

     1  package azure
     2  
     3  import (
     4  	"strings"
     5  	"time"
     6  
     7  	"golang.org/x/exp/slices"
     8  
     9  	"github.com/aquasecurity/defsec/pkg/types"
    10  	"github.com/aquasecurity/trivy-iac/pkg/scanners/azure/arm/parser/armjson"
    11  )
    12  
    13  type EvalContext struct{}
    14  
    15  type Kind string
    16  
    17  const (
    18  	KindUnresolvable Kind = "unresolvable"
    19  	KindNull         Kind = "null"
    20  	KindBoolean      Kind = "boolean"
    21  	KindString       Kind = "string"
    22  	KindNumber       Kind = "number"
    23  	KindObject       Kind = "object"
    24  	KindArray        Kind = "array"
    25  	KindExpression   Kind = "expression"
    26  )
    27  
    28  type Value struct {
    29  	types.Metadata
    30  	rLit     interface{}
    31  	rMap     map[string]Value
    32  	rArr     []Value
    33  	Kind     Kind
    34  	Comments []string
    35  }
    36  
    37  var NullValue = Value{
    38  	Kind: KindNull,
    39  }
    40  
    41  func NewValue(value interface{}, metadata types.Metadata) Value {
    42  
    43  	v := Value{
    44  		Metadata: metadata,
    45  	}
    46  
    47  	switch ty := value.(type) {
    48  	case []interface{}:
    49  		v.Kind = KindArray
    50  		for _, child := range ty {
    51  			if internal, ok := child.(Value); ok {
    52  				v.rArr = append(v.rArr, internal)
    53  			} else {
    54  				v.rArr = append(v.rArr, NewValue(child, metadata))
    55  			}
    56  		}
    57  	case []Value:
    58  		v.Kind = KindArray
    59  		v.rArr = append(v.rArr, ty...)
    60  
    61  	case map[string]interface{}:
    62  		v.Kind = KindObject
    63  		v.rMap = make(map[string]Value)
    64  		for key, val := range ty {
    65  			if internal, ok := val.(Value); ok {
    66  				v.rMap[key] = internal
    67  			} else {
    68  				v.rMap[key] = NewValue(val, metadata)
    69  			}
    70  		}
    71  	case map[string]Value:
    72  		v.Kind = KindObject
    73  		v.rMap = make(map[string]Value)
    74  		for key, val := range ty {
    75  			v.rMap[key] = val
    76  		}
    77  	case string:
    78  		v.Kind = KindString
    79  		v.rLit = ty
    80  	case int, int64, int32, float32, float64, int8, int16, uint8, uint16, uint32, uint64:
    81  		v.Kind = KindNumber
    82  		v.rLit = ty
    83  	case bool:
    84  		v.Kind = KindBoolean
    85  		v.rLit = ty
    86  	case nil:
    87  		v.Kind = KindNull
    88  		v.rLit = ty
    89  	default:
    90  		v.Kind = KindUnresolvable
    91  		v.rLit = ty
    92  	}
    93  
    94  	return v
    95  }
    96  
    97  func (v *Value) GetMetadata() types.Metadata {
    98  	return v.Metadata
    99  }
   100  
   101  func (v *Value) UnmarshalJSONWithMetadata(node armjson.Node) error {
   102  
   103  	v.updateValueKind(node)
   104  
   105  	v.Metadata = node.Metadata()
   106  
   107  	switch node.Kind() {
   108  	case armjson.KindArray:
   109  		err := v.unmarshallArray(node)
   110  		if err != nil {
   111  			return err
   112  		}
   113  	case armjson.KindObject:
   114  		err := v.unmarshalObject(node)
   115  		if err != nil {
   116  			return err
   117  		}
   118  	case armjson.KindString:
   119  		err := v.unmarshalString(node)
   120  		if err != nil {
   121  			return err
   122  		}
   123  	default:
   124  		if err := node.Decode(&v.rLit); err != nil {
   125  			return err
   126  		}
   127  	}
   128  
   129  	for _, comment := range node.Comments() {
   130  		var str string
   131  		if err := comment.Decode(&str); err != nil {
   132  			return err
   133  		}
   134  		// remove `\r` from comment when running windows
   135  		str = strings.ReplaceAll(str, "\r", "")
   136  
   137  		v.Comments = append(v.Comments, str)
   138  	}
   139  	return nil
   140  }
   141  
   142  func (v *Value) unmarshalString(node armjson.Node) error {
   143  	var str string
   144  	if err := node.Decode(&str); err != nil {
   145  		return err
   146  	}
   147  	if strings.HasPrefix(str, "[") && !strings.HasPrefix(str, "[[") && strings.HasSuffix(str, "]") {
   148  		// function!
   149  		v.Kind = KindExpression
   150  		v.rLit = str[1 : len(str)-1]
   151  	} else {
   152  		v.rLit = str
   153  	}
   154  	return nil
   155  }
   156  
   157  func (v *Value) unmarshalObject(node armjson.Node) error {
   158  	obj := make(map[string]Value)
   159  	for i := 0; i < len(node.Content()); i += 2 {
   160  		var key string
   161  		if err := node.Content()[i].Decode(&key); err != nil {
   162  			return err
   163  		}
   164  		var val Value
   165  		if err := val.UnmarshalJSONWithMetadata(node.Content()[i+1]); err != nil {
   166  			return err
   167  		}
   168  		obj[key] = val
   169  	}
   170  	v.rMap = obj
   171  	return nil
   172  }
   173  
   174  func (v *Value) unmarshallArray(node armjson.Node) error {
   175  	var arr []Value
   176  	for _, child := range node.Content() {
   177  		var val Value
   178  		if err := val.UnmarshalJSONWithMetadata(child); err != nil {
   179  			return err
   180  		}
   181  		arr = append(arr, val)
   182  	}
   183  	v.rArr = arr
   184  	return nil
   185  }
   186  
   187  func (v *Value) updateValueKind(node armjson.Node) {
   188  	switch node.Kind() {
   189  	case armjson.KindString:
   190  		v.Kind = KindString
   191  	case armjson.KindNumber:
   192  		v.Kind = KindNumber
   193  	case armjson.KindBoolean:
   194  		v.Kind = KindBoolean
   195  	case armjson.KindObject:
   196  		v.Kind = KindObject
   197  	case armjson.KindNull:
   198  		v.Kind = KindNull
   199  	case armjson.KindArray:
   200  		v.Kind = KindArray
   201  	default:
   202  		panic(node.Kind())
   203  	}
   204  }
   205  
   206  func (v Value) AsString() string {
   207  	v.Resolve()
   208  
   209  	if v.Kind != KindString {
   210  		return ""
   211  	}
   212  
   213  	return v.rLit.(string)
   214  }
   215  
   216  func (v Value) AsBool() bool {
   217  	v.Resolve()
   218  	if v.Kind != KindBoolean {
   219  		return false
   220  	}
   221  	return v.rLit.(bool)
   222  }
   223  
   224  func (v Value) AsInt() int {
   225  	v.Resolve()
   226  	if v.Kind != KindNumber {
   227  		return 0
   228  	}
   229  	return int(v.rLit.(int64))
   230  }
   231  
   232  func (v Value) AsFloat() float64 {
   233  	v.Resolve()
   234  	if v.Kind != KindNumber {
   235  		return 0
   236  	}
   237  	return v.rLit.(float64)
   238  }
   239  
   240  func (v Value) AsIntValue(defaultValue int, metadata types.Metadata) types.IntValue {
   241  	v.Resolve()
   242  	if v.Kind != KindNumber {
   243  		return types.Int(defaultValue, metadata)
   244  	}
   245  	return types.Int(v.AsInt(), metadata)
   246  }
   247  
   248  func (v Value) AsBoolValue(defaultValue bool, metadata types.Metadata) types.BoolValue {
   249  	v.Resolve()
   250  	if v.Kind == KindString {
   251  		possibleValue := strings.ToLower(v.rLit.(string))
   252  		if slices.Contains([]string{"true", "1", "yes", "on", "enabled"}, possibleValue) {
   253  			return types.Bool(true, metadata)
   254  		}
   255  	}
   256  
   257  	if v.Kind != KindBoolean {
   258  		return types.Bool(defaultValue, metadata)
   259  	}
   260  
   261  	return types.Bool(v.rLit.(bool), v.GetMetadata())
   262  }
   263  
   264  func (v Value) EqualTo(value interface{}) bool {
   265  	switch ty := value.(type) {
   266  	case string:
   267  		return v.AsString() == ty
   268  	default:
   269  		panic("not supported")
   270  	}
   271  }
   272  
   273  func (v Value) AsStringValue(defaultValue string, metadata types.Metadata) types.StringValue {
   274  	v.Resolve()
   275  	if v.Kind != KindString {
   276  		return types.StringDefault(defaultValue, metadata)
   277  	}
   278  	return types.String(v.rLit.(string), v.Metadata)
   279  }
   280  
   281  func (v Value) GetMapValue(key string) Value {
   282  	v.Resolve()
   283  	if v.Kind != KindObject {
   284  		return NullValue
   285  	}
   286  	return v.rMap[key]
   287  }
   288  
   289  func (v Value) AsMap() map[string]Value {
   290  	v.Resolve()
   291  	if v.Kind != KindObject {
   292  		return nil
   293  	}
   294  	return v.rMap
   295  }
   296  
   297  func (v Value) AsList() []Value {
   298  	v.Resolve()
   299  	if v.Kind != KindArray {
   300  		return nil
   301  	}
   302  	return v.rArr
   303  }
   304  
   305  func (v Value) Raw() interface{} {
   306  	switch v.Kind {
   307  	case KindArray:
   308  		// TODO: recursively build raw array
   309  		return nil
   310  	case KindObject:
   311  		// TODO: recursively build raw object
   312  		return nil
   313  	default:
   314  		return v.rLit
   315  	}
   316  }
   317  
   318  func (v *Value) Resolve() {
   319  	if v.Kind != KindExpression {
   320  		return
   321  	}
   322  	// if resolver, ok := v.Metadata.Internal().(Resolver); ok {
   323  	// 	*v = resolver.ResolveExpression(*v)
   324  	// }
   325  }
   326  
   327  func (v Value) HasKey(key string) bool {
   328  	v.Resolve()
   329  	_, ok := v.rMap[key]
   330  	return ok
   331  }
   332  
   333  func (v Value) AsTimeValue(metadata types.Metadata) types.TimeValue {
   334  	v.Resolve()
   335  	if v.Kind != KindString {
   336  		return types.Time(time.Time{}, metadata)
   337  	}
   338  	if v.Kind == KindNumber {
   339  		return types.Time(time.Unix(int64(v.AsFloat()), 0), metadata)
   340  	}
   341  	t, err := time.Parse(time.RFC3339, v.rLit.(string))
   342  	if err != nil {
   343  		return types.Time(time.Time{}, metadata)
   344  	}
   345  	return types.Time(t, metadata)
   346  }
   347  
   348  func (v Value) AsStringValuesList(defaultValue string) (stringValues []types.StringValue) {
   349  	v.Resolve()
   350  	if v.Kind != KindArray {
   351  		return
   352  	}
   353  	for _, item := range v.rArr {
   354  		stringValues = append(stringValues, item.AsStringValue(defaultValue, item.Metadata))
   355  	}
   356  
   357  	return stringValues
   358  }