go.mondoo.com/cnquery@v0.0.0-20231005093811-59568235f6ea/llx/builtin_global.go (about) 1 // Copyright (c) Mondoo, Inc. 2 // SPDX-License-Identifier: BUSL-1.1 3 4 package llx 5 6 import ( 7 "errors" 8 "strconv" 9 10 "go.mondoo.com/cnquery/types" 11 ) 12 13 // handleGlobal takes a global function and returns a handler if found. 14 // this is not exported as it is only used internally. it exposes everything 15 // below this function 16 func handleGlobalV2(op string) (handleFunctionV2, bool) { 17 f, ok := globalFunctionsV2[op] 18 if !ok { 19 return nil, false 20 } 21 return f, true 22 } 23 24 // DEFINITIONS 25 26 type handleFunctionV2 func(*blockExecutor, *Function, uint64) (*RawData, uint64, error) 27 28 var globalFunctionsV2 map[string]handleFunctionV2 29 30 func init() { 31 globalFunctionsV2 = map[string]handleFunctionV2{ 32 "expect": expectV2, 33 "if": ifCallV2, 34 "switch": switchCallV2, 35 "score": scoreCallV2, 36 "typeof": typeofCallV2, 37 "{}": blockV2, 38 "return": returnCallV2, 39 "createResource": globalCreateResource, 40 } 41 } 42 43 func globalCreateResource(e *blockExecutor, f *Function, ref uint64) (*RawData, uint64, error) { 44 if l := len(f.Args); l%2 != 1 || l == 0 { 45 return nil, 0, errors.New("Called `createResource` with invalid number of arguments") 46 } 47 48 binding, ok := f.Args[0].RefV2() 49 if !ok { 50 return nil, 0, errors.New("Called `createResource` with invalid arguments: expected ref") 51 } 52 53 t := types.Type(f.Type) 54 return e.createResource(t.ResourceName(), binding, &Function{ 55 Type: f.Type, 56 Args: f.Args[1:], 57 }, ref) 58 } 59 60 func ifCallV2(e *blockExecutor, f *Function, ref uint64) (*RawData, uint64, error) { 61 if len(f.Args) < 3 { 62 return nil, 0, errors.New("Called if with " + strconv.Itoa(len(f.Args)) + " arguments, expected at least 3") 63 } 64 65 var idx int 66 max := len(f.Args) 67 for idx+2 < max { 68 res, dref, err := e.resolveValue(f.Args[idx], ref) 69 if err != nil || dref != 0 || res == nil { 70 return res, dref, err 71 } 72 73 if truthy, _ := res.IsTruthy(); truthy { 74 depArgs := f.Args[idx+2] 75 res, dref, err = e.runBlock(nil, f.Args[idx+1], depArgs.Array, ref) 76 return res, dref, err 77 } 78 79 idx += 3 80 } 81 82 if idx < max { 83 depArgs := f.Args[idx+1] 84 res, dref, err := e.runBlock(nil, f.Args[idx], depArgs.Array, ref) 85 return res, dref, err 86 } 87 88 return NilData, 0, nil 89 } 90 91 func switchCallV2(e *blockExecutor, f *Function, ref uint64) (*RawData, uint64, error) { 92 // very similar to the if-call above; minor differences: 93 // - we have an optional reference value (which is in the function call) 94 // - default is translated to `true` in its condition; everything else is a function 95 96 if len(f.Args) < 2 { 97 return nil, 0, errors.New("Called switch with no arguments, expected at least one case statement") 98 } 99 100 var bind *RawData 101 if types.Type(f.Args[0].Type) != types.Unset { 102 var dref uint64 103 var err error 104 bind, dref, err = e.resolveValue(f.Args[0], ref) 105 if err != nil || dref != 0 || bind == nil { 106 return bind, dref, err 107 } 108 } 109 110 // ignore the first argument, it's just the reference value 111 idx := 1 112 max := len(f.Args) 113 defaultCaseIdx := -1 114 for idx+2 < max { 115 if types.Type(f.Args[idx].Type) == types.Bool { 116 defaultCaseIdx = idx 117 idx += 3 118 continue 119 } 120 121 res, dref, err := e.resolveValue(f.Args[idx], ref) 122 if err != nil || dref != 0 || res == nil { 123 return res, dref, err 124 } 125 126 if truthy, _ := res.IsTruthy(); truthy { 127 depArgs := f.Args[idx+2] 128 res, dref, err = e.runBlock(bind, f.Args[idx+1], depArgs.Array, ref) 129 return res, dref, err 130 } 131 132 idx += 3 133 } 134 135 if defaultCaseIdx != -1 { 136 res, dref, err := e.runBlock(nil, f.Args[defaultCaseIdx+1], f.Args[defaultCaseIdx+2].Array, ref) 137 return res, dref, err 138 } 139 140 return NilData, 0, nil 141 } 142 143 func scoreCallV2(e *blockExecutor, f *Function, ref uint64) (*RawData, uint64, error) { 144 if len(f.Args) != 1 { 145 return nil, 0, errors.New("Called `score` with " + strconv.Itoa(len(f.Args)) + " arguments, expected one") 146 } 147 148 res, dref, err := e.resolveValue(f.Args[0], ref) 149 if err != nil || dref != 0 || res == nil { 150 return res, dref, err 151 } 152 153 var b []byte 154 switch res.Type { 155 case types.Int: 156 b, err = scoreVector(int32(res.Value.(int64))) 157 158 case types.Float: 159 b, err = scoreVector(int32(res.Value.(float64))) 160 161 case types.String: 162 b, err = scoreString(res.Value.(string)) 163 } 164 165 if err != nil { 166 return nil, 0, err 167 } 168 169 return ScoreData(b), 0, nil 170 } 171 172 func typeofCallV2(e *blockExecutor, f *Function, ref uint64) (*RawData, uint64, error) { 173 if len(f.Args) != 1 { 174 return nil, 0, errors.New("Called `typeof` with " + strconv.Itoa(len(f.Args)) + " arguments, expected one") 175 } 176 177 res, dref, err := e.resolveValue(f.Args[0], ref) 178 if err != nil || dref != 0 || res == nil { 179 return res, dref, err 180 } 181 182 return StringData(res.Type.Label()), 0, nil 183 } 184 185 func expectV2(e *blockExecutor, f *Function, ref uint64) (*RawData, uint64, error) { 186 if len(f.Args) != 1 { 187 return nil, 0, errors.New("Called expect with " + strconv.Itoa(len(f.Args)) + " arguments, expected 1") 188 } 189 res, dref, err := e.resolveValue(f.Args[0], ref) 190 if res != nil && res.Type != types.Bool { 191 return nil, 0, errors.New("Called expect body with wrong type, it should be a boolean (type mismatch)") 192 } 193 return res, dref, err 194 } 195 196 func blockV2(e *blockExecutor, f *Function, ref uint64) (*RawData, uint64, error) { 197 if len(f.Args) != 1 { 198 return nil, 0, errors.New("Called block with " + strconv.Itoa(len(f.Args)) + " arguments, expected 1") 199 } 200 panic("NOT YET BLOCK CALL") 201 // res, dref, err := c.resolveValue(f.Args[0], ref) 202 // if res != nil && res.Type[0] != types.Bool { 203 // return nil, 0, errors.New("Called expect body with wrong type, it should be a boolean (type mismatch)") 204 // } 205 // return res, dref, err 206 } 207 208 func returnCallV2(e *blockExecutor, f *Function, ref uint64) (*RawData, uint64, error) { 209 arg := f.Args[0] 210 return e.resolveValue(arg, ref) 211 }