go.mondoo.com/cnquery@v0.0.0-20231005093811-59568235f6ea/mqlc/invariants.go (about) 1 // Copyright (c) Mondoo, Inc. 2 // SPDX-License-Identifier: BUSL-1.1 3 4 package mqlc 5 6 import ( 7 "fmt" 8 9 "go.mondoo.com/cnquery/llx" 10 "go.mondoo.com/cnquery/utils/multierr" 11 ) 12 13 // An Invariant is a condition that we expect compiled code to hold. 14 // This is used to find inconsistencies in our compiler and not for 15 // meant to be user facing 16 type Invariant struct { 17 ShortName string 18 Description string 19 Issues []string 20 // Checker returns true if the invariant holds 21 Checker func(*llx.CodeBundle) bool 22 } 23 24 type InvariantFailed struct { 25 ShortName string 26 Source string 27 } 28 29 func (e InvariantFailed) Error() string { 30 return fmt.Sprintf("Invariant %q failed: Source => \n%+v", e.ShortName, e.Source) 31 } 32 33 type InvariantList []Invariant 34 35 func (l InvariantList) Check(cb *llx.CodeBundle) error { 36 var err multierr.Errors 37 for _, i := range l { 38 if !i.Checker(cb) { 39 err.Add(InvariantFailed{ 40 ShortName: i.ShortName, 41 Source: cb.Source, 42 }) 43 } 44 } 45 46 return err.Deduplicate() 47 } 48 49 var Invariants = InvariantList{ 50 { 51 ShortName: "code is not nil", 52 Description: `Make sure any compiled code is never just nil`, 53 Checker: func(cb *llx.CodeBundle) bool { 54 return cb.CodeV2 != nil 55 }, 56 }, 57 { 58 ShortName: "return-entrypoints-singular", 59 Description: ` 60 The return statement indicates that the following expression 61 is to be used for the value of the block. Our execution code 62 assumes that only 1 value will be reported for the block. 63 64 This means that there can only be 1 entrypoint. Further, it 65 also means that num_entrypoints + num_datapoints == 1. The 66 restriction on datapoints is just an artifact of the way things 67 are written and can be changed, however the entrypoint should 68 be the return value. I mention this as a reminder that not all 69 parts of this invariant need to be this way forever and can be 70 changed 71 `, 72 Issues: []string{ 73 "https://gitlab.com/mondoolabs/mondoo/-/issues/716", 74 }, 75 Checker: func(cb *llx.CodeBundle) bool { 76 return checkReturnEntrypointsV2(cb.CodeV2) 77 }, 78 }, 79 } 80 81 func checkReturnEntrypointsV2(code *llx.CodeV2) bool { 82 for i := range code.Blocks { 83 block := code.Blocks[i] 84 85 if block.SingleValue { 86 if len(code.Entrypoints())+len(code.Datapoints()) != 1 { 87 return false 88 } 89 } 90 } 91 92 return true 93 } 94 95 func checkReturnEntrypointsV1(code *llx.CodeV1) bool { 96 if code.SingleValue { 97 if len(code.Entrypoints)+len(code.Datapoints) != 1 { 98 return false 99 } 100 } 101 102 for _, c := range code.Functions { 103 if checkReturnEntrypointsV1(c) == false { 104 return false 105 } 106 } 107 108 return true 109 }