go.mondoo.com/cnquery@v0.0.0-20231005093811-59568235f6ea/llx/rawdata_deref.go (about) 1 // Copyright (c) Mondoo, Inc. 2 // SPDX-License-Identifier: BUSL-1.1 3 4 package llx 5 6 import ( 7 "errors" 8 "fmt" 9 "time" 10 11 "go.mondoo.com/cnquery/types" 12 ) 13 14 func dereferenceDict(raw interface{}) (*RawData, error) { 15 switch data := raw.(type) { 16 case bool: 17 return BoolData(data), nil 18 19 case int64: 20 return IntData(data), nil 21 22 case float64: 23 return FloatData(data), nil 24 25 case string: 26 return StringData(data), nil 27 28 case time.Time: 29 return TimeData(data), nil 30 31 case []interface{}: 32 // TODO: we'll need to go deeper here to figure out what it really is 33 return ArrayData(data, types.Array(types.Any)), nil 34 35 case map[string]interface{}: 36 // TODO: we'll need to go deeper here to figure out what it really is 37 return MapData(data, types.Map(types.String, types.Any)), nil 38 39 default: 40 return AnyData(data), nil 41 } 42 } 43 44 func dereferenceBlock(data map[string]interface{}, codeID string, bundle *CodeBundle) (*RawData, error) { 45 res := make(map[string]interface{}, len(data)) 46 47 for k := range data { 48 if k == "_" || k == "__t" || k == "__s" { 49 continue 50 } 51 52 v := data[k] 53 54 label := label(k, bundle, true) 55 val, err := v.(*RawData).Dereference(k, bundle) 56 if err != nil { 57 return nil, err 58 } 59 60 res[label] = val.Value 61 } 62 63 return MapData(res, types.Map(types.String, types.Any)), nil 64 } 65 66 func dereferenceArray(typ types.Type, data []interface{}, codeID string, bundle *CodeBundle) (*RawData, error) { 67 res := make([]interface{}, len(data)) 68 childType := typ.Child() 69 70 // TODO: detect any changes to the child type 71 for i := range data { 72 entry := &RawData{Value: data[i], Type: childType} 73 v, err := dereference(entry, codeID, bundle) 74 if err != nil { 75 return nil, err 76 } 77 res[i] = v.Value 78 } 79 80 return ArrayData(res, childType), nil 81 } 82 83 func dereferenceStringMap(typ types.Type, data map[string]interface{}, codeID string, bundle *CodeBundle) (*RawData, error) { 84 res := make(map[string]interface{}, len(data)) 85 childType := typ.Child() 86 87 // TODO: detect any changes to the child type 88 for key := range data { 89 entry := &RawData{Value: data[key], Type: childType} 90 v, err := dereference(entry, codeID, bundle) 91 if err != nil { 92 return nil, err 93 } 94 res[key] = v.Value 95 } 96 97 return MapData(res, childType), nil 98 } 99 100 func dereference(raw *RawData, codeID string, bundle *CodeBundle) (*RawData, error) { 101 if raw.Type.NotSet() || raw.Value == nil { 102 return raw, nil 103 } 104 105 typ := raw.Type 106 data := raw.Value 107 108 // we only handle types that might have reference data embedded 109 switch typ.Underlying() { 110 // case types.Ref: 111 // // TODO: needs work 112 case types.Dict: 113 return dereferenceDict(data) 114 115 case types.Block: 116 return dereferenceBlock(data.(map[string]interface{}), codeID, bundle) 117 118 case types.ArrayLike: 119 return dereferenceArray(typ, data.([]interface{}), codeID, bundle) 120 121 case types.MapLike: 122 if typ.Key() == types.String { 123 return dereferenceStringMap(typ, data.(map[string]interface{}), codeID, bundle) 124 } 125 // if typ.Key() == types.Int { 126 // return dereferenceIntMap(typ, data.(map[int]interface{}), codeID, bundle) 127 // } 128 return nil, errors.New("unable to dereference map, its type is not supported: " + typ.Label() + ", raw: " + fmt.Sprintf("%#v", data)) 129 130 default: 131 return raw, nil 132 } 133 } 134 135 // Dereference takes the raw data provided and finds any code references 136 // that it might contain. It resolves blocks back into regular string maps 137 // and converts Dicts into simple data structures. 138 func (r *RawData) Dereference(codeID string, bundle *CodeBundle) (*RawData, error) { 139 return dereference(r, codeID, bundle) 140 }