diff --git a/cli/providers/providers.go b/cli/providers/providers.go index 01e10edacf..0b27ac3aac 100644 --- a/cli/providers/providers.go +++ b/cli/providers/providers.go @@ -56,6 +56,12 @@ func detectConnectorName(args []string, commands []*Command) (string, bool) { flags := pflag.NewFlagSet("set", pflag.ContinueOnError) flags.Bool("auto-update", true, "") flags.BoolP("help", "h", false, "") + + builtins := genBuiltinFlags() + for i := range builtins { + addFlagToSet(flags, builtins[i]) + } + for i := range commands { cmd := commands[i] cmd.Command.Flags().VisitAll(func(flag *pflag.Flag) { @@ -67,7 +73,7 @@ func detectConnectorName(args []string, commands []*Command) (string, bool) { err := flags.Parse(args) if err != nil { - log.Warn().Err(err).Msg("pre-processing of cli had an error") + log.Warn().Err(err).Msg("CLI pre-processing encountered an issue") } autoUpdate, _ = flags.GetBool("auto-update") @@ -178,18 +184,23 @@ func attachConnectorCmd(provider *plugin.Provider, connector *plugin.Connector, setConnector(provider, connector, cmd.Run, res) } -func setConnector(provider *plugin.Provider, connector *plugin.Connector, run func(*cobra.Command, *providers.Runtime, *plugin.ParseCLIRes), cmd *cobra.Command) { - oldRun := cmd.Run - oldPreRun := cmd.PreRun - - supportedDiscoveries := append([]string{"all", "auto"}, connector.Discovery...) +func genBuiltinFlags(discoveries ...string) []plugin.Flag { + supportedDiscoveries := append([]string{"all", "auto"}, discoveries...) - builtinFlags := []plugin.Flag{ + return []plugin.Flag{ + // flags for providers: { Long: "discover", Type: plugin.FlagType_List, Desc: "Enable the discovery of nested assets. Supports: " + strings.Join(supportedDiscoveries, ","), }, + { + Long: "pretty", + Type: plugin.FlagType_Bool, + Desc: "Pretty-print JSON", + Option: plugin.FlagOption_Hidden, + }, + // runtime-only flags: { Long: "record", Type: plugin.FlagType_String, @@ -200,14 +211,89 @@ func setConnector(provider *plugin.Provider, connector *plugin.Connector, run fu Type: plugin.FlagType_String, Desc: "Use a recording to inject resource data (read-only)", }, - { - Long: "pretty", - Type: plugin.FlagType_Bool, - Desc: "Pretty-print JSON", - Option: plugin.FlagOption_Hidden, - }, } +} +// the following flags are not processed by providers +var skipFlags = map[string]struct{}{ + "ask-pass": {}, + "record": {}, + "use-recording": {}, +} + +func addFlagToSet(set *pflag.FlagSet, flag plugin.Flag) { + switch flag.Type { + case plugin.FlagType_Bool: + if flag.Short != "" { + set.BoolP(flag.Long, flag.Short, false, flag.Desc) + } else { + set.Bool(flag.Long, false, flag.Desc) + } + case plugin.FlagType_Int: + if flag.Short != "" { + set.IntP(flag.Long, flag.Short, 0, flag.Desc) + } else { + set.Int(flag.Long, 0, flag.Desc) + } + case plugin.FlagType_String: + if flag.Short != "" { + set.StringP(flag.Long, flag.Short, "", flag.Desc) + } else { + set.String(flag.Long, "", flag.Desc) + } + case plugin.FlagType_List: + if flag.Short != "" { + set.StringArrayP(flag.Long, flag.Short, []string{}, flag.Desc) + } else { + set.StringArray(flag.Long, []string{}, flag.Desc) + } + case plugin.FlagType_KeyValue: + if flag.Short != "" { + set.StringToStringP(flag.Long, flag.Short, map[string]string{}, flag.Desc) + } else { + set.StringToString(flag.Long, map[string]string{}, flag.Desc) + } + default: + log.Warn().Msg("unknown flag type for " + flag.Long) + } +} + +func getFlagValue(flag plugin.Flag, cmd *cobra.Command) *llx.Primitive { + switch flag.Type { + case plugin.FlagType_Bool: + v, err := cmd.Flags().GetBool(flag.Long) + if err == nil { + return llx.BoolPrimitive(v) + } + log.Warn().Err(err).Msg("failed to get flag " + flag.Long) + case plugin.FlagType_Int: + if v, err := cmd.Flags().GetInt(flag.Long); err == nil { + return llx.IntPrimitive(int64(v)) + } + case plugin.FlagType_String: + if v, err := cmd.Flags().GetString(flag.Long); err == nil { + return llx.StringPrimitive(v) + } + case plugin.FlagType_List: + if v, err := cmd.Flags().GetStringSlice(flag.Long); err == nil { + return llx.ArrayPrimitiveT(v, llx.StringPrimitive, types.String) + } + case plugin.FlagType_KeyValue: + if v, err := cmd.Flags().GetStringToString(flag.Long); err == nil { + return llx.MapPrimitiveT(v, llx.StringPrimitive, types.String) + } + default: + log.Warn().Msg("unknown flag type for " + flag.Long) + return nil + } + return nil +} + +func setConnector(provider *plugin.Provider, connector *plugin.Connector, run func(*cobra.Command, *providers.Runtime, *plugin.ParseCLIRes), cmd *cobra.Command) { + oldRun := cmd.Run + oldPreRun := cmd.PreRun + + builtinFlags := genBuiltinFlags(connector.Discovery...) allFlags := append(connector.Flags, builtinFlags...) cmd.PreRun = func(cc *cobra.Command, args []string) { @@ -266,14 +352,6 @@ func setConnector(provider *plugin.Provider, connector *plugin.Connector, run fu log.Warn().Msg("failed to get flag --pretty") } - // the following flags are not processed by the provider; we handle them - // here instead - skipFlags := map[string]struct{}{ - "ask-pass": {}, - "record": {}, - "use-recording": {}, - } - flagVals := map[string]*llx.Primitive{} for i := range allFlags { flag := allFlags[i] @@ -283,27 +361,8 @@ func setConnector(provider *plugin.Provider, connector *plugin.Connector, run fu continue } - switch flag.Type { - case plugin.FlagType_Bool: - if v, err := cmd.Flags().GetBool(flag.Long); err == nil { - flagVals[flag.Long] = llx.BoolPrimitive(v) - } - case plugin.FlagType_Int: - if v, err := cmd.Flags().GetInt(flag.Long); err == nil { - flagVals[flag.Long] = llx.IntPrimitive(int64(v)) - } - case plugin.FlagType_String: - if v, err := cmd.Flags().GetString(flag.Long); err == nil { - flagVals[flag.Long] = llx.StringPrimitive(v) - } - case plugin.FlagType_List: - if v, err := cmd.Flags().GetStringSlice(flag.Long); err == nil { - flagVals[flag.Long] = llx.ArrayPrimitiveT(v, llx.StringPrimitive, types.String) - } - case plugin.FlagType_KeyValue: - if v, err := cmd.Flags().GetStringToString(flag.Long); err == nil { - flagVals[flag.Long] = llx.MapPrimitiveT(v, llx.StringPrimitive, types.String) - } + if v := getFlagValue(flag, cmd); v != nil { + flagVals[flag.Long] = v } } diff --git a/providers-sdk/v1/plugin/flag.go b/providers-sdk/v1/plugin/flag.go new file mode 100644 index 0000000000..f68b1d2f6b --- /dev/null +++ b/providers-sdk/v1/plugin/flag.go @@ -0,0 +1,38 @@ +// Copyright (c) Mondoo, Inc. +// SPDX-License-Identifier: BUSL-1.1 + +package plugin + +type FlagType byte + +const ( + FlagType_Bool FlagType = 1 + iota + FlagType_Int + FlagType_String + FlagType_List + FlagType_KeyValue +) + +type FlagOption byte + +const ( + FlagOption_Hidden FlagOption = 0x1 << iota + FlagOption_Deprecated + FlagOption_Required + FlagOption_Password + // max: 8 options! +) + +type Flag struct { + Long string `json:",omitempty"` + Short string `json:",omitempty"` + Default string `json:",omitempty"` + Desc string `json:",omitempty"` + Type FlagType `json:",omitempty"` + Option FlagOption `json:",omitempty"` + // ConfigEntry that is used for this flag: + // "" = use the same as Long + // "some.other" = map to some.other field + // "-" = do not read this from config + ConfigEntry string `json:",omitempty"` +} diff --git a/providers-sdk/v1/plugin/start.go b/providers-sdk/v1/plugin/start.go index b63c4ef16d..1ea689d325 100644 --- a/providers-sdk/v1/plugin/start.go +++ b/providers-sdk/v1/plugin/start.go @@ -32,40 +32,6 @@ type Connector struct { Discovery []string `json:",omitempty"` } -type FlagType byte - -const ( - FlagType_Bool FlagType = 1 + iota - FlagType_Int - FlagType_String - FlagType_List - FlagType_KeyValue -) - -type FlagOption byte - -const ( - FlagOption_Hidden FlagOption = 0x1 << iota - FlagOption_Deprecated - FlagOption_Required - FlagOption_Password - // max: 8 options! -) - -type Flag struct { - Long string `json:",omitempty"` - Short string `json:",omitempty"` - Default string `json:",omitempty"` - Desc string `json:",omitempty"` - Type FlagType `json:",omitempty"` - Option FlagOption `json:",omitempty"` - // ConfigEntry that is used for this flag: - // "" = use the same as Long - // "some.other" = map to some.other field - // "-" = do not read this from config - ConfigEntry string `json:",omitempty"` -} - func Start(args []string, impl ProviderPlugin) { logger.CliCompactLogger(logger.LogOutputWriter) zerolog.SetGlobalLevel(zerolog.WarnLevel) diff --git a/providers/mock.go b/providers/mock.go index 9afdcfdd59..55d56879e7 100644 --- a/providers/mock.go +++ b/providers/mock.go @@ -11,8 +11,9 @@ import ( var mockProvider = Provider{ Provider: &plugin.Provider{ - Name: "mock", - ID: "go.mondoo.com/cnquery/providers/mock", + Name: "mock", + ID: "go.mondoo.com/cnquery/providers/mock", + Version: "9.0.0", Connectors: []plugin.Connector{{ Name: "mock", Use: "mock",