diff --git a/apps/cnquery/cmd/plugin.go b/apps/cnquery/cmd/plugin.go index e673d0a275..356e9b7b5f 100644 --- a/apps/cnquery/cmd/plugin.go +++ b/apps/cnquery/cmd/plugin.go @@ -81,6 +81,23 @@ func (c *cnqueryPlugin) RunQuery(conf *run.RunQueryConfig, runtime *providers.Ru return nil } + if conf.DoInfo { + ast, err := parser.Parse(mqlc.Dedent(conf.Command)) + if ast == nil { + return errors.Wrap(err, "failed to parse command") + } + + conf := mqlc.NewConfig(runtime.Schema(), conf.Features) + conf.EnableStats() + _, err = mqlc.CompileAST(ast, nil, conf) + if err != nil { + return errors.Wrap(err, "failed to compile command") + } + + out.WriteString(printer.DefaultPrinter.CompilerStats(conf.Stats)) + return nil + } + var upstreamConfig *upstream.UpstreamConfig serviceAccount := opts.GetServiceCredential() if serviceAccount != nil { diff --git a/apps/cnquery/cmd/run.go b/apps/cnquery/cmd/run.go index cb4222cfd9..b1f8274864 100644 --- a/apps/cnquery/cmd/run.go +++ b/apps/cnquery/cmd/run.go @@ -22,6 +22,7 @@ func init() { RunCmd.Flags().StringP("command", "c", "", "MQL query to executed in the shell.") RunCmd.Flags().Bool("parse", false, "Parse the query and return the logical structure.") RunCmd.Flags().Bool("ast", false, "Parse the query and return the abstract syntax tree (AST).") + RunCmd.Flags().Bool("info", false, "Parse the query and provide information about it.") RunCmd.Flags().BoolP("json", "j", false, "Run the query and return the object in a JSON structure.") RunCmd.Flags().String("platform-id", "", "Select a specific target asset by providing its platform ID.") @@ -47,6 +48,7 @@ var RunCmdRun = func(cmd *cobra.Command, runtime *providers.Runtime, cliRes *plu conf.Command, _ = cmd.Flags().GetString("command") conf.DoAst, _ = cmd.Flags().GetBool("ast") + conf.DoInfo, _ = cmd.Flags().GetBool("info") conf.DoParse, _ = cmd.Flags().GetBool("parse") if doJSON, _ := cmd.Flags().GetBool("json"); doJSON { conf.Format = "json" diff --git a/cli/printer/mql.go b/cli/printer/mql.go index 6234fd3dc7..fcf7f81dc9 100644 --- a/cli/printer/mql.go +++ b/cli/printer/mql.go @@ -11,6 +11,7 @@ import ( "time" "go.mondoo.com/cnquery/v9/llx" + "go.mondoo.com/cnquery/v9/mqlc" "go.mondoo.com/cnquery/v9/types" "go.mondoo.com/cnquery/v9/utils/sortx" "golang.org/x/exp/slices" @@ -747,7 +748,19 @@ func (print *Printer) DataWithLabel(r *llx.RawData, codeID string, bundle *llx.C return b.String() } -// CodeBundle prints a bundle to a string +func (print *Printer) CompilerStats(stats *mqlc.CompilerStats) string { + var res strings.Builder + res.WriteString("Resources and Fields used:\n") + for resource, fields := range stats.ResourceFields { + res.WriteString("- " + print.Yellow(resource) + "\n") + for field := range fields { + res.WriteString(" - " + print.Primary(field) + "\n") + } + } + return res.String() +} + +// CodeBundle prints the contents of the MQL query func (print *Printer) CodeBundle(bundle *llx.CodeBundle) string { var res strings.Builder diff --git a/mqlc/mqlc.go b/mqlc/mqlc.go index a98fbfcf20..20cd99ba5f 100644 --- a/mqlc/mqlc.go +++ b/mqlc/mqlc.go @@ -69,6 +69,28 @@ func (vm *varmap) len() int { type compilerConfig struct { Schema llx.Schema UseAssetContext bool + Stats *CompilerStats +} + +func (c *compilerConfig) EnableStats() { + c.Stats = &CompilerStats{ + ResourceFields: map[string]map[string]struct{}{}, + } +} + +type CompilerStats struct { + ResourceFields map[string]map[string]struct{} +} + +func (c *CompilerStats) calledResource(name string) { + if _, ok := c.ResourceFields[name]; !ok { + c.ResourceFields[name] = map[string]struct{}{} + } +} + +func (c *CompilerStats) calledField(resource string, field string) { + c.calledResource(resource) + c.ResourceFields[resource][field] = struct{}{} } func NewConfig(schema llx.Schema, features cnquery.Features) compilerConfig { @@ -956,12 +978,15 @@ func (c *compiler) compileBoundIdentifierWithMqlCtx(id string, binding *variable fieldPath, fieldinfos, ok := c.findField(resource, id) if ok { fieldinfo := fieldinfos[len(fieldinfos)-1] + if c.compilerConfig.Stats != nil { + c.compilerConfig.Stats.calledField(resource.Name, fieldinfo.Name) + } if call != nil && len(call.Function) > 0 && !fieldinfo.IsImplicitResource { return true, types.Nil, errors.New("cannot call resource field with arguments yet") } - c.Result.MinMondooVersion = getMinMondooVersion(c.Schema, c.Result.MinMondooVersion, typ.ResourceName(), id) + c.Result.MinMondooVersion = getMinMondooVersion(c.Schema, c.Result.MinMondooVersion, resource.Name, id) // this only happens when we call a field of a bridging resource, // in which case we don't call the field (since there is nothing to do) @@ -1049,6 +1074,10 @@ func (c *compiler) compileBoundIdentifierWithoutMqlCtx(id string, binding *varia } if fieldinfo != nil { + if c.compilerConfig.Stats != nil { + c.compilerConfig.Stats.calledField(resource.Name, fieldinfo.Name) + } + if call != nil && len(call.Function) > 0 { return true, types.Nil, errors.New("cannot call resource field with arguments yet") } @@ -1057,7 +1086,7 @@ func (c *compiler) compileBoundIdentifierWithoutMqlCtx(id string, binding *varia return true, types.Nil, fmt.Errorf("field '%s' on '%s' requires the MQLAssetContext feature", id, typ.Label()) } - c.Result.MinMondooVersion = getMinMondooVersion(c.Schema, c.Result.MinMondooVersion, typ.ResourceName(), id) + c.Result.MinMondooVersion = getMinMondooVersion(c.Schema, c.Result.MinMondooVersion, resource.Name, id) // this only happens when we call a field of a bridging resource, // in which case we don't call the field (since there is nothing to do) @@ -1117,6 +1146,10 @@ func (c *compiler) compileResource(id string, calls []*parser.Call) (bool, []*pa calls = calls[1:] } + if c.compilerConfig.Stats != nil { + c.compilerConfig.Stats.calledResource(resource.Name) + } + var call *parser.Call if len(calls) > 0 && calls[0].Function != nil { call = calls[0] diff --git a/shared/proto/cnquery.pb.go b/shared/proto/cnquery.pb.go index 1e7dd2bbf0..6baee8d050 100644 --- a/shared/proto/cnquery.pb.go +++ b/shared/proto/cnquery.pb.go @@ -35,6 +35,7 @@ type RunQueryConfig struct { Features []byte `protobuf:"bytes,4,opt,name=features,proto3" json:"features,omitempty"` DoParse bool `protobuf:"varint,5,opt,name=do_parse,json=doParse,proto3" json:"do_parse,omitempty"` DoAst bool `protobuf:"varint,6,opt,name=do_ast,json=doAst,proto3" json:"do_ast,omitempty"` + DoInfo bool `protobuf:"varint,13,opt,name=do_info,json=doInfo,proto3" json:"do_info,omitempty"` DoRecord bool `protobuf:"varint,7,opt,name=do_record,json=doRecord,proto3" json:"do_record,omitempty"` Format string `protobuf:"bytes,8,opt,name=format,proto3" json:"format,omitempty"` PlatformId string `protobuf:"bytes,9,opt,name=platform_id,json=platformId,proto3" json:"platform_id,omitempty"` @@ -117,6 +118,13 @@ func (x *RunQueryConfig) GetDoAst() bool { return false } +func (x *RunQueryConfig) GetDoInfo() bool { + if x != nil { + return x.DoInfo + } + return false +} + func (x *RunQueryConfig) GetDoRecord() bool { if x != nil { return x.DoRecord @@ -251,7 +259,7 @@ var file_cnquery_proto_rawDesc = []byte{ 0x05, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x2a, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x73, 0x2d, 0x73, 0x64, 0x6b, 0x2f, 0x76, 0x31, 0x2f, 0x69, 0x6e, 0x76, 0x65, 0x6e, 0x74, 0x6f, 0x72, 0x79, 0x2f, 0x69, 0x6e, 0x76, 0x65, 0x6e, 0x74, 0x6f, 0x72, 0x79, 0x2e, 0x70, 0x72, 0x6f, - 0x74, 0x6f, 0x22, 0x82, 0x03, 0x0a, 0x0e, 0x52, 0x75, 0x6e, 0x51, 0x75, 0x65, 0x72, 0x79, 0x43, + 0x74, 0x6f, 0x22, 0x9b, 0x03, 0x0a, 0x0e, 0x52, 0x75, 0x6e, 0x51, 0x75, 0x65, 0x72, 0x79, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x18, 0x0a, 0x07, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x12, 0x27, 0x0a, 0x0f, 0x63, 0x61, 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x5f, 0x73, 0x65, 0x72, 0x76, @@ -265,30 +273,31 @@ var file_cnquery_proto_rawDesc = []byte{ 0x72, 0x65, 0x73, 0x12, 0x19, 0x0a, 0x08, 0x64, 0x6f, 0x5f, 0x70, 0x61, 0x72, 0x73, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x64, 0x6f, 0x50, 0x61, 0x72, 0x73, 0x65, 0x12, 0x15, 0x0a, 0x06, 0x64, 0x6f, 0x5f, 0x61, 0x73, 0x74, 0x18, 0x06, 0x20, 0x01, 0x28, 0x08, 0x52, 0x05, - 0x64, 0x6f, 0x41, 0x73, 0x74, 0x12, 0x1b, 0x0a, 0x09, 0x64, 0x6f, 0x5f, 0x72, 0x65, 0x63, 0x6f, - 0x72, 0x64, 0x18, 0x07, 0x20, 0x01, 0x28, 0x08, 0x52, 0x08, 0x64, 0x6f, 0x52, 0x65, 0x63, 0x6f, - 0x72, 0x64, 0x12, 0x16, 0x0a, 0x06, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x18, 0x08, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x06, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x12, 0x1f, 0x0a, 0x0b, 0x70, 0x6c, - 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x5f, 0x69, 0x64, 0x18, 0x09, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x0a, 0x70, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x49, 0x64, 0x12, 0x1c, 0x0a, 0x09, 0x69, - 0x6e, 0x63, 0x6f, 0x67, 0x6e, 0x69, 0x74, 0x6f, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x08, 0x52, 0x09, - 0x69, 0x6e, 0x63, 0x6f, 0x67, 0x6e, 0x69, 0x74, 0x6f, 0x12, 0x16, 0x0a, 0x06, 0x6f, 0x75, 0x74, - 0x70, 0x75, 0x74, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x6f, 0x75, 0x74, 0x70, 0x75, - 0x74, 0x12, 0x14, 0x0a, 0x05, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x05, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x22, 0x07, 0x0a, 0x05, 0x45, 0x6d, 0x70, 0x74, 0x79, - 0x22, 0x1c, 0x0a, 0x06, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x12, 0x12, 0x0a, 0x04, 0x64, 0x61, - 0x74, 0x61, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x64, 0x61, 0x74, 0x61, 0x32, 0x3a, - 0x0a, 0x07, 0x43, 0x4e, 0x51, 0x75, 0x65, 0x72, 0x79, 0x12, 0x2f, 0x0a, 0x08, 0x52, 0x75, 0x6e, - 0x51, 0x75, 0x65, 0x72, 0x79, 0x12, 0x15, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x52, 0x75, - 0x6e, 0x51, 0x75, 0x65, 0x72, 0x79, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x1a, 0x0c, 0x2e, 0x70, - 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x32, 0x34, 0x0a, 0x0c, 0x4f, 0x75, - 0x74, 0x70, 0x75, 0x74, 0x48, 0x65, 0x6c, 0x70, 0x65, 0x72, 0x12, 0x24, 0x0a, 0x05, 0x57, 0x72, - 0x69, 0x74, 0x65, 0x12, 0x0d, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x53, 0x74, 0x72, 0x69, - 0x6e, 0x67, 0x1a, 0x0c, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, - 0x42, 0x27, 0x5a, 0x25, 0x67, 0x6f, 0x2e, 0x6d, 0x6f, 0x6e, 0x64, 0x6f, 0x6f, 0x2e, 0x63, 0x6f, - 0x6d, 0x2f, 0x63, 0x6e, 0x71, 0x75, 0x65, 0x72, 0x79, 0x2f, 0x76, 0x39, 0x2f, 0x73, 0x68, 0x61, - 0x72, 0x65, 0x64, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, - 0x33, + 0x64, 0x6f, 0x41, 0x73, 0x74, 0x12, 0x17, 0x0a, 0x07, 0x64, 0x6f, 0x5f, 0x69, 0x6e, 0x66, 0x6f, + 0x18, 0x0d, 0x20, 0x01, 0x28, 0x08, 0x52, 0x06, 0x64, 0x6f, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x1b, + 0x0a, 0x09, 0x64, 0x6f, 0x5f, 0x72, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x18, 0x07, 0x20, 0x01, 0x28, + 0x08, 0x52, 0x08, 0x64, 0x6f, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x12, 0x16, 0x0a, 0x06, 0x66, + 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x66, 0x6f, 0x72, + 0x6d, 0x61, 0x74, 0x12, 0x1f, 0x0a, 0x0b, 0x70, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x5f, + 0x69, 0x64, 0x18, 0x09, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x70, 0x6c, 0x61, 0x74, 0x66, 0x6f, + 0x72, 0x6d, 0x49, 0x64, 0x12, 0x1c, 0x0a, 0x09, 0x69, 0x6e, 0x63, 0x6f, 0x67, 0x6e, 0x69, 0x74, + 0x6f, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x08, 0x52, 0x09, 0x69, 0x6e, 0x63, 0x6f, 0x67, 0x6e, 0x69, + 0x74, 0x6f, 0x12, 0x16, 0x0a, 0x06, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x18, 0x0b, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x06, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x12, 0x14, 0x0a, 0x05, 0x69, 0x6e, + 0x70, 0x75, 0x74, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x69, 0x6e, 0x70, 0x75, 0x74, + 0x22, 0x07, 0x0a, 0x05, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x22, 0x1c, 0x0a, 0x06, 0x53, 0x74, 0x72, + 0x69, 0x6e, 0x67, 0x12, 0x12, 0x0a, 0x04, 0x64, 0x61, 0x74, 0x61, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x04, 0x64, 0x61, 0x74, 0x61, 0x32, 0x3a, 0x0a, 0x07, 0x43, 0x4e, 0x51, 0x75, 0x65, + 0x72, 0x79, 0x12, 0x2f, 0x0a, 0x08, 0x52, 0x75, 0x6e, 0x51, 0x75, 0x65, 0x72, 0x79, 0x12, 0x15, + 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x52, 0x75, 0x6e, 0x51, 0x75, 0x65, 0x72, 0x79, 0x43, + 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x1a, 0x0c, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x45, 0x6d, + 0x70, 0x74, 0x79, 0x32, 0x34, 0x0a, 0x0c, 0x4f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x48, 0x65, 0x6c, + 0x70, 0x65, 0x72, 0x12, 0x24, 0x0a, 0x05, 0x57, 0x72, 0x69, 0x74, 0x65, 0x12, 0x0d, 0x2e, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x1a, 0x0c, 0x2e, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x42, 0x27, 0x5a, 0x25, 0x67, 0x6f, 0x2e, + 0x6d, 0x6f, 0x6e, 0x64, 0x6f, 0x6f, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x63, 0x6e, 0x71, 0x75, 0x65, + 0x72, 0x79, 0x2f, 0x76, 0x39, 0x2f, 0x73, 0x68, 0x61, 0x72, 0x65, 0x64, 0x2f, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( diff --git a/shared/proto/cnquery.proto b/shared/proto/cnquery.proto index a8ce396013..cb927bc7fd 100644 --- a/shared/proto/cnquery.proto +++ b/shared/proto/cnquery.proto @@ -16,6 +16,7 @@ message RunQueryConfig { bool do_parse = 5; bool do_ast = 6; + bool do_info = 13; bool do_record = 7; string format = 8; string platform_id = 9;