Skip to content

Commit

Permalink
🐛 add builtin flags for cli pre-processing (#1780)
Browse files Browse the repository at this point in the history
This avoids an error-message which makes users think that recordings
were not loaded.

Before 

```bash
..go/src/go.mondoo.com/cnquery ±> go run apps/cnquery/cnquery.go run -c sshd.config.params --use-recording a.json
! pre-processing of cli had an error error="unknown flag: --use-recording"
→ no provider specified, defaulting to local. Use --help to see all providers.
→ loaded configuration from /home/zero/.config/mondoo/mondoo.yml using source default
```

After:

```bash
..go/src/go.mondoo.com/cnquery ±> go run apps/cnquery/cnquery.go run -c sshd.config.params --use-recording a.json
→ no provider specified, defaulting to local. Use --help to see all providers.
→ loaded configuration from /home/zero/.config/mondoo/mondoo.yml using source default
```

Signed-off-by: Dominik Richter <[email protected]>
  • Loading branch information
arlimus authored Sep 19, 2023
1 parent fd394aa commit 846c110
Show file tree
Hide file tree
Showing 4 changed files with 142 additions and 78 deletions.
143 changes: 101 additions & 42 deletions cli/providers/providers.go
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand All @@ -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")
Expand Down Expand Up @@ -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,
Expand All @@ -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) {
Expand Down Expand Up @@ -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]
Expand All @@ -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
}
}

Expand Down
38 changes: 38 additions & 0 deletions providers-sdk/v1/plugin/flag.go
Original file line number Diff line number Diff line change
@@ -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"`
}
34 changes: 0 additions & 34 deletions providers-sdk/v1/plugin/start.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
5 changes: 3 additions & 2 deletions providers/mock.go
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down

0 comments on commit 846c110

Please sign in to comment.