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 }