Browse Source

refact "cscli" root cmd (#2811)

* refact "cscli" root cmd
* lint (naming, imports, whitespace)
mmetc 1 year ago
parent
commit
4e724f6c0a

+ 1 - 1
.golangci.yml

@@ -53,7 +53,7 @@ linters-settings:
 
   nestif:
     # lower this after refactoring
-    min-complexity: 27
+    min-complexity: 28
 
   nlreturn:
     block-size: 4

+ 5 - 5
cmd/crowdsec-cli/bouncers.go

@@ -36,13 +36,13 @@ func askYesNo(message string, defaultAnswer bool) (bool, error) {
 }
 
 type cliBouncers struct {
-	db *database.Client
+	db  *database.Client
 	cfg configGetter
 }
 
-func NewCLIBouncers(getconfig configGetter) *cliBouncers {
+func NewCLIBouncers(cfg configGetter) *cliBouncers {
 	return &cliBouncers{
-		cfg: getconfig,
+		cfg: cfg,
 	}
 }
 
@@ -197,13 +197,13 @@ cscli bouncers add MyBouncerName --key <random-key>`,
 	return cmd
 }
 
-func (cli *cliBouncers) deleteValid(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
+func (cli *cliBouncers) deleteValid(_ *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
 	bouncers, err := cli.db.ListBouncers()
 	if err != nil {
 		cobra.CompError("unable to list bouncers " + err.Error())
 	}
 
-	ret :=[]string{}
+	ret := []string{}
 
 	for _, bouncer := range bouncers {
 		if strings.Contains(bouncer.Name, toComplete) && !slices.Contains(args, bouncer.Name) {

+ 7 - 2
cmd/crowdsec-cli/config_restore.go

@@ -146,7 +146,12 @@ func restoreConfigFromDirectory(dirPath string, oldBackup bool) error {
 		// Now we have config.yaml, we should regenerate config struct to have rights paths etc
 		ConfigFilePath = fmt.Sprintf("%s/config.yaml", csConfig.ConfigPaths.ConfigDir)
 
-		initConfig()
+		log.Debug("Reloading configuration")
+
+		csConfig, _, err = loadConfigFor("config")
+		if err != nil {
+			return fmt.Errorf("failed to reload configuration: %s", err)
+		}
 
 		backupCAPICreds := fmt.Sprintf("%s/online_api_credentials.yaml", dirPath)
 		if _, err = os.Stat(backupCAPICreds); err == nil {
@@ -227,7 +232,7 @@ func restoreConfigFromDirectory(dirPath string, oldBackup bool) error {
 		}
 	}
 
-	// if there is files in the acquis backup dir, restore them
+	// if there are files in the acquis backup dir, restore them
 	acquisBackupDir := filepath.Join(dirPath, "acquis", "*.yaml")
 	if acquisFiles, err := filepath.Glob(acquisBackupDir); err == nil {
 		for _, acquisFile := range acquisFiles {

+ 14 - 10
cmd/crowdsec-cli/dashboard.go

@@ -19,15 +19,14 @@ import (
 	log "github.com/sirupsen/logrus"
 	"github.com/spf13/cobra"
 
-	"github.com/crowdsecurity/crowdsec/pkg/metabase"
-
 	"github.com/crowdsecurity/crowdsec/cmd/crowdsec-cli/require"
+	"github.com/crowdsecurity/crowdsec/pkg/metabase"
 )
 
 var (
 	metabaseUser         = "crowdsec@crowdsec.net"
 	metabasePassword     string
-	metabaseDbPath       string
+	metabaseDBPath       string
 	metabaseConfigPath   string
 	metabaseConfigFolder = "metabase/"
 	metabaseConfigFile   = "metabase.yaml"
@@ -43,13 +42,13 @@ var (
 	// information needed to set up a random password on user's behalf
 )
 
-type cliDashboard struct{
+type cliDashboard struct {
 	cfg configGetter
 }
 
-func NewCLIDashboard(getconfig configGetter) *cliDashboard {
+func NewCLIDashboard(cfg configGetter) *cliDashboard {
 	return &cliDashboard{
-		cfg: getconfig,
+		cfg: cfg,
 	}
 }
 
@@ -99,6 +98,7 @@ cscli dashboard remove
 					metabaseContainerID = oldContainerID
 				}
 			}
+
 			return nil
 		},
 	}
@@ -127,8 +127,8 @@ cscli dashboard setup --listen 0.0.0.0
 cscli dashboard setup -l 0.0.0.0 -p 443 --password <password>
  `,
 		RunE: func(_ *cobra.Command, _ []string) error {
-			if metabaseDbPath == "" {
-				metabaseDbPath = cli.cfg().ConfigPaths.DataDir
+			if metabaseDBPath == "" {
+				metabaseDBPath = cli.cfg().ConfigPaths.DataDir
 			}
 
 			if metabasePassword == "" {
@@ -152,7 +152,7 @@ cscli dashboard setup -l 0.0.0.0 -p 443 --password <password>
 			if err = cli.chownDatabase(dockerGroup.Gid); err != nil {
 				return err
 			}
-			mb, err := metabase.SetupMetabase(cli.cfg().API.Server.DbConfig, metabaseListenAddress, metabaseListenPort, metabaseUser, metabasePassword, metabaseDbPath, dockerGroup.Gid, metabaseContainerID, metabaseImage)
+			mb, err := metabase.SetupMetabase(cli.cfg().API.Server.DbConfig, metabaseListenAddress, metabaseListenPort, metabaseUser, metabasePassword, metabaseDBPath, dockerGroup.Gid, metabaseContainerID, metabaseImage)
 			if err != nil {
 				return err
 			}
@@ -165,13 +165,14 @@ cscli dashboard setup -l 0.0.0.0 -p 443 --password <password>
 			fmt.Printf("\tURL       : '%s'\n", mb.Config.ListenURL)
 			fmt.Printf("\tusername  : '%s'\n", mb.Config.Username)
 			fmt.Printf("\tpassword  : '%s'\n", mb.Config.Password)
+
 			return nil
 		},
 	}
 
 	flags := cmd.Flags()
 	flags.BoolVarP(&force, "force", "f", false, "Force setup : override existing files")
-	flags.StringVarP(&metabaseDbPath, "dir", "d", "", "Shared directory with metabase container")
+	flags.StringVarP(&metabaseDBPath, "dir", "d", "", "Shared directory with metabase container")
 	flags.StringVarP(&metabaseListenAddress, "listen", "l", metabaseListenAddress, "Listen address of container")
 	flags.StringVar(&metabaseImage, "metabase-image", metabaseImage, "Metabase image to use")
 	flags.StringVarP(&metabaseListenPort, "port", "p", metabaseListenPort, "Listen port of container")
@@ -203,6 +204,7 @@ func (cli *cliDashboard) newStartCmd() *cobra.Command {
 			}
 			log.Infof("Started metabase")
 			log.Infof("url : http://%s:%s", mb.Config.ListenAddr, mb.Config.ListenPort)
+
 			return nil
 		},
 	}
@@ -241,6 +243,7 @@ func (cli *cliDashboard) newShowPasswordCmd() *cobra.Command {
 				return err
 			}
 			log.Printf("'%s'", m.Config.Password)
+
 			return nil
 		},
 	}
@@ -313,6 +316,7 @@ cscli dashboard remove --force
 					}
 				}
 			}
+
 			return nil
 		},
 	}

+ 2 - 2
cmd/crowdsec-cli/dashboard_unsupported.go

@@ -13,9 +13,9 @@ type cliDashboard struct{
 	cfg configGetter
 }
 
-func NewCLIDashboard(getconfig configGetter) *cliDashboard {
+func NewCLIDashboard(cfg configGetter) *cliDashboard {
 	return &cliDashboard{
-		cfg: getconfig,
+		cfg: cfg,
 	}
 }
 

+ 5 - 3
cmd/crowdsec-cli/decisions.go

@@ -116,14 +116,13 @@ func (cli *cliDecisions) decisionsToTable(alerts *models.GetAlertsResponse, prin
 	return nil
 }
 
-
 type cliDecisions struct {
 	cfg configGetter
 }
 
-func NewCLIDecisions(getconfig configGetter) *cliDecisions {
+func NewCLIDecisions(cfg configGetter) *cliDecisions {
 	return &cliDecisions{
-		cfg: getconfig,
+		cfg: cfg,
 	}
 }
 
@@ -157,6 +156,7 @@ func (cli *cliDecisions) NewCommand() *cobra.Command {
 			if err != nil {
 				return fmt.Errorf("creating api client: %w", err)
 			}
+
 			return nil
 		},
 	}
@@ -393,6 +393,7 @@ cscli decisions add --scope username --value foobar
 			}
 
 			log.Info("Decision successfully added")
+
 			return nil
 		},
 	}
@@ -499,6 +500,7 @@ cscli decisions delete --type captcha
 				}
 			}
 			log.Infof("%s decision(s) deleted", decisions.NbDeleted)
+
 			return nil
 		},
 	}

+ 3 - 3
cmd/crowdsec-cli/hub.go

@@ -13,13 +13,13 @@ import (
 	"github.com/crowdsecurity/crowdsec/pkg/cwhub"
 )
 
-type cliHub struct{
+type cliHub struct {
 	cfg configGetter
 }
 
-func NewCLIHub(getconfig configGetter) *cliHub {
+func NewCLIHub(cfg configGetter) *cliHub {
 	return &cliHub{
-		cfg: getconfig,
+		cfg: cfg,
 	}
 }
 

+ 11 - 10
cmd/crowdsec-cli/machines.go

@@ -7,6 +7,7 @@ import (
 	"fmt"
 	"math/big"
 	"os"
+	"slices"
 	"strings"
 	"time"
 
@@ -17,7 +18,6 @@ import (
 	log "github.com/sirupsen/logrus"
 	"github.com/spf13/cobra"
 	"gopkg.in/yaml.v3"
-	"slices"
 
 	"github.com/crowdsecurity/machineid"
 
@@ -106,14 +106,14 @@ func getLastHeartbeat(m *ent.Machine) (string, bool) {
 	return hb, true
 }
 
-type cliMachines struct{
-	db *database.Client
+type cliMachines struct {
+	db  *database.Client
 	cfg configGetter
 }
 
-func NewCLIMachines(getconfig configGetter) *cliMachines {
+func NewCLIMachines(cfg configGetter) *cliMachines {
 	return &cliMachines{
-		cfg: getconfig,
+		cfg: cfg,
 	}
 }
 
@@ -136,6 +136,7 @@ Note: This command requires database direct access, so is intended to be run on
 			if err != nil {
 				return fmt.Errorf("unable to create new database client: %s", err)
 			}
+
 			return nil
 		},
 	}
@@ -249,7 +250,7 @@ cscli machines add -f- --auto > /tmp/mycreds.yaml`,
 
 func (cli *cliMachines) add(args []string, machinePassword string, dumpFile string, apiURL string, interactive bool, autoAdd bool, force bool) error {
 	var (
-		err error
+		err       error
 		machineID string
 	)
 
@@ -347,7 +348,7 @@ func (cli *cliMachines) add(args []string, machinePassword string, dumpFile stri
 	return nil
 }
 
-func (cli *cliMachines) deleteValid(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
+func (cli *cliMachines) deleteValid(_ *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
 	machines, err := cli.db.ListMachines()
 	if err != nil {
 		cobra.CompError("unable to list machines " + err.Error())
@@ -447,9 +448,9 @@ func (cli *cliMachines) prune(duration time.Duration, notValidOnly bool, force b
 
 func (cli *cliMachines) newPruneCmd() *cobra.Command {
 	var (
-		duration       time.Duration
-		notValidOnly   bool
-		force          bool
+		duration     time.Duration
+		notValidOnly bool
+		force        bool
 	)
 
 	const defaultDuration = 10 * time.Minute

+ 124 - 83
cmd/crowdsec-cli/main.go

@@ -15,45 +15,88 @@ import (
 	"github.com/crowdsecurity/crowdsec/pkg/fflag"
 )
 
-var trace_lvl, dbg_lvl, nfo_lvl, wrn_lvl, err_lvl bool
-
 var ConfigFilePath string
 var csConfig *csconfig.Config
 var dbClient *database.Client
 
-var outputFormat string
-var OutputColor string
+type configGetter func() *csconfig.Config
 
 var mergedConfig string
 
-// flagBranch overrides the value in csConfig.Cscli.HubBranch
-var flagBranch = ""
+type cliRoot struct {
+	logTrace     bool
+	logDebug     bool
+	logInfo      bool
+	logWarn      bool
+	logErr       bool
+	outputColor  string
+	outputFormat string
+	// flagBranch overrides the value in csConfig.Cscli.HubBranch
+	flagBranch string
+}
 
-type configGetter func() *csconfig.Config
+func newCliRoot() *cliRoot {
+	return &cliRoot{}
+}
 
-func initConfig() {
-	var err error
+// cfg() is a helper function to get the configuration loaded from config.yaml,
+// we pass it to subcommands because the file is not read until the Execute() call
+func (cli *cliRoot) cfg() *csconfig.Config {
+	return csConfig
+}
 
-	if trace_lvl {
-		log.SetLevel(log.TraceLevel)
-	} else if dbg_lvl {
-		log.SetLevel(log.DebugLevel)
-	} else if nfo_lvl {
-		log.SetLevel(log.InfoLevel)
-	} else if wrn_lvl {
-		log.SetLevel(log.WarnLevel)
-	} else if err_lvl {
-		log.SetLevel(log.ErrorLevel)
+// wantedLogLevel returns the log level requested in the command line flags.
+func (cli *cliRoot) wantedLogLevel() log.Level {
+	switch {
+	case cli.logTrace:
+		return log.TraceLevel
+	case cli.logDebug:
+		return log.DebugLevel
+	case cli.logInfo:
+		return log.InfoLevel
+	case cli.logWarn:
+		return log.WarnLevel
+	case cli.logErr:
+		return log.ErrorLevel
+	default:
+		return log.InfoLevel
+	}
+}
+
+// loadConfigFor loads the configuration file for the given sub-command.
+// If the sub-command does not need it, it returns a default configuration.
+func loadConfigFor(command string) (*csconfig.Config, string, error) {
+	noNeedConfig := []string{
+		"doc",
+		"help",
+		"completion",
+		"version",
+		"hubtest",
 	}
 
-	if !slices.Contains(NoNeedConfig, os.Args[1]) {
+	if !slices.Contains(noNeedConfig, command) {
 		log.Debugf("Using %s as configuration file", ConfigFilePath)
-		csConfig, mergedConfig, err = csconfig.NewConfig(ConfigFilePath, false, false, true)
+
+		config, merged, err := csconfig.NewConfig(ConfigFilePath, false, false, true)
 		if err != nil {
-			log.Fatal(err)
+			return nil, "", err
 		}
-	} else {
-		csConfig = csconfig.NewDefaultConfig()
+
+		return config, merged, nil
+	}
+
+	return csconfig.NewDefaultConfig(), "", nil
+}
+
+// initialize is called before the subcommand is executed.
+func (cli *cliRoot) initialize() {
+	var err error
+
+	log.SetLevel(cli.wantedLogLevel())
+
+	csConfig, mergedConfig, err = loadConfigFor(os.Args[1])
+	if err != nil {
+		log.Fatal(err)
 	}
 
 	// recap of the enabled feature flags, because logging
@@ -62,12 +105,12 @@ func initConfig() {
 		log.Debugf("Enabled feature flags: %s", fflist)
 	}
 
-	if flagBranch != "" {
-		csConfig.Cscli.HubBranch = flagBranch
+	if cli.flagBranch != "" {
+		csConfig.Cscli.HubBranch = cli.flagBranch
 	}
 
-	if outputFormat != "" {
-		csConfig.Cscli.Output = outputFormat
+	if cli.outputFormat != "" {
+		csConfig.Cscli.Output = cli.outputFormat
 	}
 
 	if csConfig.Cscli.Output == "" {
@@ -85,11 +128,11 @@ func initConfig() {
 		log.SetLevel(log.ErrorLevel)
 	}
 
-	if OutputColor != "" {
-		csConfig.Cscli.Color = OutputColor
+	if cli.outputColor != "" {
+		csConfig.Cscli.Color = cli.outputColor
 
-		if OutputColor != "yes" && OutputColor != "no" && OutputColor != "auto" {
-			log.Fatalf("output color %s unknown", OutputColor)
+		if cli.outputColor != "yes" && cli.outputColor != "no" && cli.outputColor != "auto" {
+			log.Fatalf("output color %s unknown", cli.outputColor)
 		}
 	}
 }
@@ -102,15 +145,25 @@ var validArgs = []string{
 	"postoverflows", "scenarios", "simulation", "support", "version",
 }
 
-var NoNeedConfig = []string{
-	"doc",
-	"help",
-	"completion",
-	"version",
-	"hubtest",
+func (cli *cliRoot) colorize(cmd *cobra.Command) {
+	cc.Init(&cc.Config{
+		RootCmd:         cmd,
+		Headings:        cc.Yellow,
+		Commands:        cc.Green + cc.Bold,
+		CmdShortDescr:   cc.Cyan,
+		Example:         cc.Italic,
+		ExecName:        cc.Bold,
+		Aliases:         cc.Bold + cc.Italic,
+		FlagsDataType:   cc.White,
+		Flags:           cc.Green,
+		FlagsDescr:      cc.Cyan,
+		NoExtraNewlines: true,
+		NoBottomNewline: true,
+	})
+	cmd.SetOut(color.Output)
 }
 
-func main() {
+func (cli *cliRoot) NewCommand() *cobra.Command {
 	// set the formatter asap and worry about level later
 	logFormatter := &log.TextFormatter{TimestampFormat: time.RFC3339, FullTimestamp: true}
 	log.SetFormatter(logFormatter)
@@ -135,33 +188,25 @@ It is meant to allow you to manage bans, parsers/scenarios/etc, api and generall
 		/*TBD examples*/
 	}
 
-	cc.Init(&cc.Config{
-		RootCmd:       cmd,
-		Headings:      cc.Yellow,
-		Commands:      cc.Green + cc.Bold,
-		CmdShortDescr: cc.Cyan,
-		Example:       cc.Italic,
-		ExecName:      cc.Bold,
-		Aliases:       cc.Bold + cc.Italic,
-		FlagsDataType: cc.White,
-		Flags:         cc.Green,
-		FlagsDescr:    cc.Cyan,
-		NoExtraNewlines: true,
-		NoBottomNewline: true,
-	})
-	cmd.SetOut(color.Output)
+	cli.colorize(cmd)
+
+	/*don't sort flags so we can enforce order*/
+	cmd.Flags().SortFlags = false
+
+	pflags := cmd.PersistentFlags()
+	pflags.SortFlags = false
+
+	pflags.StringVarP(&ConfigFilePath, "config", "c", csconfig.DefaultConfigPath("config.yaml"), "path to crowdsec config file")
+	pflags.StringVarP(&cli.outputFormat, "output", "o", "", "Output format: human, json, raw")
+	pflags.StringVarP(&cli.outputColor, "color", "", "auto", "Output color: yes, no, auto")
+	pflags.BoolVar(&cli.logDebug, "debug", false, "Set logging to debug")
+	pflags.BoolVar(&cli.logInfo, "info", false, "Set logging to info")
+	pflags.BoolVar(&cli.logWarn, "warning", false, "Set logging to warning")
+	pflags.BoolVar(&cli.logErr, "error", false, "Set logging to error")
+	pflags.BoolVar(&cli.logTrace, "trace", false, "Set logging to trace")
+	pflags.StringVar(&cli.flagBranch, "branch", "", "Override hub branch on github")
 
-	cmd.PersistentFlags().StringVarP(&ConfigFilePath, "config", "c", csconfig.DefaultConfigPath("config.yaml"), "path to crowdsec config file")
-	cmd.PersistentFlags().StringVarP(&outputFormat, "output", "o", "", "Output format: human, json, raw")
-	cmd.PersistentFlags().StringVarP(&OutputColor, "color", "", "auto", "Output color: yes, no, auto")
-	cmd.PersistentFlags().BoolVar(&dbg_lvl, "debug", false, "Set logging to debug")
-	cmd.PersistentFlags().BoolVar(&nfo_lvl, "info", false, "Set logging to info")
-	cmd.PersistentFlags().BoolVar(&wrn_lvl, "warning", false, "Set logging to warning")
-	cmd.PersistentFlags().BoolVar(&err_lvl, "error", false, "Set logging to error")
-	cmd.PersistentFlags().BoolVar(&trace_lvl, "trace", false, "Set logging to trace")
-	cmd.PersistentFlags().StringVar(&flagBranch, "branch", "", "Override hub branch on github")
-
-	if err := cmd.PersistentFlags().MarkHidden("branch"); err != nil {
+	if err := pflags.MarkHidden("branch"); err != nil {
 		log.Fatalf("failed to hide flag: %s", err)
 	}
 
@@ -181,29 +226,20 @@ It is meant to allow you to manage bans, parsers/scenarios/etc, api and generall
 	}
 
 	if len(os.Args) > 1 {
-		cobra.OnInitialize(initConfig)
-	}
-
-	/*don't sort flags so we can enforce order*/
-	cmd.Flags().SortFlags = false
-	cmd.PersistentFlags().SortFlags = false
-
-	// we use a getter because the config is not initialized until the Execute() call
-	getconfig := func() *csconfig.Config {
-		return csConfig
+		cobra.OnInitialize(cli.initialize)
 	}
 
 	cmd.AddCommand(NewCLIDoc().NewCommand(cmd))
 	cmd.AddCommand(NewCLIVersion().NewCommand())
 	cmd.AddCommand(NewConfigCmd())
-	cmd.AddCommand(NewCLIHub(getconfig).NewCommand())
-	cmd.AddCommand(NewCLIMetrics(getconfig).NewCommand())
-	cmd.AddCommand(NewCLIDashboard(getconfig).NewCommand())
-	cmd.AddCommand(NewCLIDecisions(getconfig).NewCommand())
+	cmd.AddCommand(NewCLIHub(cli.cfg).NewCommand())
+	cmd.AddCommand(NewCLIMetrics(cli.cfg).NewCommand())
+	cmd.AddCommand(NewCLIDashboard(cli.cfg).NewCommand())
+	cmd.AddCommand(NewCLIDecisions(cli.cfg).NewCommand())
 	cmd.AddCommand(NewCLIAlerts().NewCommand())
-	cmd.AddCommand(NewCLISimulation(getconfig).NewCommand())
-	cmd.AddCommand(NewCLIBouncers(getconfig).NewCommand())
-	cmd.AddCommand(NewCLIMachines(getconfig).NewCommand())
+	cmd.AddCommand(NewCLISimulation(cli.cfg).NewCommand())
+	cmd.AddCommand(NewCLIBouncers(cli.cfg).NewCommand())
+	cmd.AddCommand(NewCLIMachines(cli.cfg).NewCommand())
 	cmd.AddCommand(NewCLICapi().NewCommand())
 	cmd.AddCommand(NewLapiCmd())
 	cmd.AddCommand(NewCompletionCmd())
@@ -212,7 +248,7 @@ It is meant to allow you to manage bans, parsers/scenarios/etc, api and generall
 	cmd.AddCommand(NewCLIHubTest().NewCommand())
 	cmd.AddCommand(NewCLINotifications().NewCommand())
 	cmd.AddCommand(NewCLISupport().NewCommand())
-	cmd.AddCommand(NewCLIPapi(getconfig).NewCommand())
+	cmd.AddCommand(NewCLIPapi(cli.cfg).NewCommand())
 	cmd.AddCommand(NewCLICollection().NewCommand())
 	cmd.AddCommand(NewCLIParser().NewCommand())
 	cmd.AddCommand(NewCLIScenario().NewCommand())
@@ -225,6 +261,11 @@ It is meant to allow you to manage bans, parsers/scenarios/etc, api and generall
 		cmd.AddCommand(NewSetupCmd())
 	}
 
+	return cmd
+}
+
+func main() {
+	cmd := newCliRoot().NewCommand()
 	if err := cmd.Execute(); err != nil {
 		log.Fatal(err)
 	}

+ 18 - 13
cmd/crowdsec-cli/metrics.go

@@ -50,18 +50,18 @@ type metricStore map[string]metricSection
 
 func NewMetricStore() metricStore {
 	return metricStore{
-		"acquisition": statAcquis{},
-		"buckets": statBucket{},
-		"parsers": statParser{},
-		"lapi": statLapi{},
-		"lapi-machine": statLapiMachine{},
-		"lapi-bouncer": statLapiBouncer{},
+		"acquisition":    statAcquis{},
+		"buckets":        statBucket{},
+		"parsers":        statParser{},
+		"lapi":           statLapi{},
+		"lapi-machine":   statLapiMachine{},
+		"lapi-bouncer":   statLapiBouncer{},
 		"lapi-decisions": statLapiDecision{},
-		"decisions": statDecision{},
-		"alerts": statAlert{},
-		"stash": statStash{},
-		"appsec-engine": statAppsecEngine{},
-		"appsec-rule": statAppsecRule{},
+		"decisions":      statDecision{},
+		"alerts":         statAlert{},
+		"stash":          statStash{},
+		"appsec-engine":  statAppsecEngine{},
+		"appsec-rule":    statAppsecRule{},
 	}
 }
 
@@ -116,17 +116,21 @@ func (ms metricStore) Fetch(url string) error {
 		if !strings.HasPrefix(fam.Name, "cs_") {
 			continue
 		}
+
 		log.Tracef("round %d", idx)
+
 		for _, m := range fam.Metrics {
 			metric, ok := m.(prom2json.Metric)
 			if !ok {
 				log.Debugf("failed to convert metric to prom2json.Metric")
 				continue
 			}
+
 			name, ok := metric.Labels["name"]
 			if !ok {
 				log.Debugf("no name in Metric %v", metric.Labels)
 			}
+
 			source, ok := metric.Labels["source"]
 			if !ok {
 				log.Debugf("no source in Metric %v for %s", metric.Labels, fam.Name)
@@ -153,6 +157,7 @@ func (ms metricStore) Fetch(url string) error {
 			if err != nil {
 				log.Errorf("Unexpected int value %s : %s", value, err)
 			}
+
 			ival := int(fval)
 			switch fam.Name {
 			/*buckets*/
@@ -303,9 +308,9 @@ type cliMetrics struct {
 	cfg configGetter
 }
 
-func NewCLIMetrics(getconfig configGetter) *cliMetrics {
+func NewCLIMetrics(cfg configGetter) *cliMetrics {
 	return &cliMetrics{
-		cfg: getconfig,
+		cfg: cfg,
 	}
 }
 

+ 4 - 4
cmd/crowdsec-cli/papi.go

@@ -10,19 +10,18 @@ import (
 
 	"github.com/crowdsecurity/go-cs-lib/ptr"
 
+	"github.com/crowdsecurity/crowdsec/cmd/crowdsec-cli/require"
 	"github.com/crowdsecurity/crowdsec/pkg/apiserver"
 	"github.com/crowdsecurity/crowdsec/pkg/database"
-
-	"github.com/crowdsecurity/crowdsec/cmd/crowdsec-cli/require"
 )
 
 type cliPapi struct {
 	cfg configGetter
 }
 
-func NewCLIPapi(getconfig configGetter) *cliPapi {
+func NewCLIPapi(cfg configGetter) *cliPapi {
 	return &cliPapi{
-		cfg: getconfig,
+		cfg: cfg,
 	}
 }
 
@@ -43,6 +42,7 @@ func (cli *cliPapi) NewCommand() *cobra.Command {
 			if err := require.PAPI(cfg); err != nil {
 				return err
 			}
+
 			return nil
 		},
 	}

+ 5 - 4
cmd/crowdsec-cli/simulation.go

@@ -3,23 +3,23 @@ package main
 import (
 	"fmt"
 	"os"
+	"slices"
 
 	log "github.com/sirupsen/logrus"
 	"github.com/spf13/cobra"
 	"gopkg.in/yaml.v2"
-	"slices"
 
 	"github.com/crowdsecurity/crowdsec/cmd/crowdsec-cli/require"
 	"github.com/crowdsecurity/crowdsec/pkg/cwhub"
 )
 
-type cliSimulation struct{
+type cliSimulation struct {
 	cfg configGetter
 }
 
-func NewCLISimulation(getconfig configGetter) *cliSimulation {
+func NewCLISimulation(cfg configGetter) *cliSimulation {
 	return &cliSimulation{
-		cfg: getconfig,
+		cfg: cfg,
 	}
 }
 
@@ -38,6 +38,7 @@ cscli simulation disable crowdsecurity/ssh-bf`,
 			if cli.cfg().Cscli.SimulationConfig == nil {
 				return fmt.Errorf("no simulation configured")
 			}
+
 			return nil
 		},
 		PersistentPostRun: func(cmd *cobra.Command, _ []string) {