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  }