Parcourir la source

Refact cscli hub/item commands (#2536)

* log.Fatal -> fmt.Errorf
* lint cmd/crowdsec-cli hub items and split collection commands
* cscli collections: add examples
* cscli parsers: avoid globals
* cscli scenarios: avoid globals
* cscli collections, postoverflows: avoid globals
* cscli hub: avoid globals
* remove unused globals
mmetc il y a 1 an
Parent
commit
734ba46e6a

+ 218 - 93
cmd/crowdsec-cli/collections.go

@@ -12,11 +12,15 @@ import (
 )
 )
 
 
 func NewCollectionsCmd() *cobra.Command {
 func NewCollectionsCmd() *cobra.Command {
-	var cmdCollections = &cobra.Command{
+	cmdCollections := &cobra.Command{
 		Use:   "collections [action]",
 		Use:   "collections [action]",
-		Short: "Manage collections from hub",
-		Long:  `Install/Remove/Upgrade/Inspect collections from the CrowdSec Hub.`,
-		/*TBD fix help*/
+		Short: "Install/Remove/Upgrade/Inspect collections from the CrowdSec Hub.",
+		Example: `cscli collections install crowdsec/xxx crowdsec/xyz
+cscli collections inspect crowdsec/xxx crowdsec/xyz
+cscli collections upgrade crowdsec/xxx crowdsec/xyz
+cscli collections list
+cscli collections remove crowdsec/xxx crowdsec/xyz
+`,
 		Args:              cobra.MinimumNArgs(1),
 		Args:              cobra.MinimumNArgs(1),
 		Aliases:           []string{"collection"},
 		Aliases:           []string{"collection"},
 		DisableAutoGenTag: true,
 		DisableAutoGenTag: true,
@@ -35,42 +39,130 @@ func NewCollectionsCmd() *cobra.Command {
 		},
 		},
 	}
 	}
 
 
-	var ignoreError bool
+	cmdCollections.AddCommand(NewCollectionsInstallCmd())
+	cmdCollections.AddCommand(NewCollectionsRemoveCmd())
+	cmdCollections.AddCommand(NewCollectionsUpgradeCmd())
+	cmdCollections.AddCommand(NewCollectionsInspectCmd())
+	cmdCollections.AddCommand(NewCollectionsListCmd())
 
 
-	var cmdCollectionsInstall = &cobra.Command{
-		Use:     "install collection",
-		Short:   "Install given collection(s)",
-		Long:    `Fetch and install given collection(s) from hub`,
-		Example: `cscli collections install crowdsec/xxx crowdsec/xyz`,
-		Args:    cobra.MinimumNArgs(1),
+	return cmdCollections
+}
+
+func runCollectionsInstall(cmd *cobra.Command, args []string) error {
+	flags := cmd.Flags()
+
+	downloadOnly, err := flags.GetBool("download-only")
+	if err != nil {
+		return err
+	}
+
+	force, err := flags.GetBool("force")
+	if err != nil {
+		return err
+	}
+
+	ignoreError, err := flags.GetBool("ignore")
+	if err != nil {
+		return err
+	}
+
+	for _, name := range args {
+		t := cwhub.GetItem(cwhub.COLLECTIONS, name)
+		if t == nil {
+			nearestItem, score := GetDistance(cwhub.COLLECTIONS, name)
+			Suggest(cwhub.COLLECTIONS, name, nearestItem.Name, score, ignoreError)
+
+			continue
+		}
+
+		if err := cwhub.InstallItem(csConfig, name, cwhub.COLLECTIONS, force, downloadOnly); err != nil {
+			if !ignoreError {
+				return fmt.Errorf("error while installing '%s': %w", name, err)
+			}
+			log.Errorf("Error while installing '%s': %s", name, err)
+		}
+	}
+
+	return nil
+}
+
+func NewCollectionsInstallCmd() *cobra.Command {
+	cmdCollectionsInstall := &cobra.Command{
+		Use:               "install collection",
+		Short:             "Install given collection(s)",
+		Long:              `Fetch and install given collection(s) from hub`,
+		Example:           `cscli collections install crowdsec/xxx crowdsec/xyz`,
+		Args:              cobra.MinimumNArgs(1),
+		DisableAutoGenTag: true,
 		ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
 		ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
 			return compAllItems(cwhub.COLLECTIONS, args, toComplete)
 			return compAllItems(cwhub.COLLECTIONS, args, toComplete)
 		},
 		},
-		DisableAutoGenTag: true,
-		RunE: func(cmd *cobra.Command, args []string) error {
-			for _, name := range args {
-				t := cwhub.GetItem(cwhub.COLLECTIONS, name)
-				if t == nil {
-					nearestItem, score := GetDistance(cwhub.COLLECTIONS, name)
-					Suggest(cwhub.COLLECTIONS, name, nearestItem.Name, score, ignoreError)
-					continue
-				}
-				if err := cwhub.InstallItem(csConfig, name, cwhub.COLLECTIONS, forceAction, downloadOnly); err != nil {
-					if !ignoreError {
-						return fmt.Errorf("error while installing '%s': %w", name, err)
-					}
-					log.Errorf("Error while installing '%s': %s", name, err)
-				}
+		RunE: runCollectionsInstall,
+	}
+
+	flags := cmdCollectionsInstall.Flags()
+	flags.BoolP("download-only", "d", false, "Only download packages, don't enable")
+	flags.Bool("force", false, "Force install : Overwrite tainted and outdated files")
+	flags.Bool("ignore", false, "Ignore errors when installing multiple collections")
+
+	return cmdCollectionsInstall
+}
+
+func runCollectionsRemove(cmd *cobra.Command, args []string) error {
+	flags := cmd.Flags()
+
+	purge, err := flags.GetBool("purge")
+	if err != nil {
+		return err
+	}
+
+	force, err := flags.GetBool("force")
+	if err != nil {
+		return err
+	}
+
+	all, err := flags.GetBool("all")
+	if err != nil {
+		return err
+	}
+
+	if all {
+		err := cwhub.RemoveMany(csConfig, cwhub.COLLECTIONS, "", all, purge, force)
+		if err != nil {
+			return err
+		}
+
+		return nil
+	}
+
+	if len(args) == 0 {
+		return fmt.Errorf("specify at least one collection to remove or '--all'")
+	}
+
+	for _, name := range args {
+		if !force {
+			item := cwhub.GetItem(cwhub.COLLECTIONS, name)
+			if item == nil {
+				return fmt.Errorf("unable to retrieve: %s", name)
 			}
 			}
-			return nil
-		},
+			if len(item.BelongsToCollections) > 0 {
+				log.Warningf("%s belongs to other collections :\n%s\n", name, item.BelongsToCollections)
+				log.Printf("Run 'sudo cscli collections remove %s --force' if you want to force remove this sub collection\n", name)
+				continue
+			}
+		}
+
+		err := cwhub.RemoveMany(csConfig, cwhub.COLLECTIONS, name, all, purge, force)
+		if err != nil {
+			return err
+		}
 	}
 	}
-	cmdCollectionsInstall.PersistentFlags().BoolVarP(&downloadOnly, "download-only", "d", false, "Only download packages, don't enable")
-	cmdCollectionsInstall.PersistentFlags().BoolVar(&forceAction, "force", false, "Force install : Overwrite tainted and outdated files")
-	cmdCollectionsInstall.PersistentFlags().BoolVar(&ignoreError, "ignore", false, "Ignore errors when installing multiple collections")
-	cmdCollections.AddCommand(cmdCollectionsInstall)
 
 
-	var cmdCollectionsRemove = &cobra.Command{
+	return nil
+}
+
+func NewCollectionsRemoveCmd() *cobra.Command {
+	cmdCollectionsRemove := &cobra.Command{
 		Use:               "remove collection",
 		Use:               "remove collection",
 		Short:             "Remove given collection(s)",
 		Short:             "Remove given collection(s)",
 		Long:              `Remove given collection(s) from hub`,
 		Long:              `Remove given collection(s) from hub`,
@@ -80,39 +172,48 @@ func NewCollectionsCmd() *cobra.Command {
 		ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
 		ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
 			return compInstalledItems(cwhub.COLLECTIONS, args, toComplete)
 			return compInstalledItems(cwhub.COLLECTIONS, args, toComplete)
 		},
 		},
-		RunE: func(cmd *cobra.Command, args []string) error {
-			if all {
-				cwhub.RemoveMany(csConfig, cwhub.COLLECTIONS, "", all, purge, forceAction)
-				return nil
-			}
+		RunE: runCollectionsRemove,
+	}
 
 
-			if len(args) == 0 {
-				return fmt.Errorf("specify at least one collection to remove or '--all'")
-			}
+	flags := cmdCollectionsRemove.Flags()
+	flags.Bool("purge", false, "Delete source file too")
+	flags.Bool("force", false, "Force remove : Remove tainted and outdated files")
+	flags.Bool("all", false, "Delete all the collections")
 
 
-			for _, name := range args {
-				if !forceAction {
-					item := cwhub.GetItem(cwhub.COLLECTIONS, name)
-					if item == nil {
-						return fmt.Errorf("unable to retrieve: %s", name)
-					}
-					if len(item.BelongsToCollections) > 0 {
-						log.Warningf("%s belongs to other collections :\n%s\n", name, item.BelongsToCollections)
-						log.Printf("Run 'sudo cscli collections remove %s --force' if you want to force remove this sub collection\n", name)
-						continue
-					}
-				}
-				cwhub.RemoveMany(csConfig, cwhub.COLLECTIONS, name, all, purge, forceAction)
-			}
-			return nil
-		},
+	return cmdCollectionsRemove
+}
+
+func runCollectionsUpgrade(cmd *cobra.Command, args []string) error {
+	flags := cmd.Flags()
+
+	force, err := flags.GetBool("force")
+	if err != nil {
+		return err
+	}
+
+	all, err := flags.GetBool("all")
+	if err != nil {
+		return err
+	}
+
+	if all {
+		cwhub.UpgradeConfig(csConfig, cwhub.COLLECTIONS, "", force)
+		return nil
 	}
 	}
-	cmdCollectionsRemove.PersistentFlags().BoolVar(&purge, "purge", false, "Delete source file too")
-	cmdCollectionsRemove.PersistentFlags().BoolVar(&forceAction, "force", false, "Force remove : Remove tainted and outdated files")
-	cmdCollectionsRemove.PersistentFlags().BoolVar(&all, "all", false, "Delete all the collections")
-	cmdCollections.AddCommand(cmdCollectionsRemove)
 
 
-	var cmdCollectionsUpgrade = &cobra.Command{
+	if len(args) == 0 {
+		return fmt.Errorf("specify at least one collection to upgrade or '--all'")
+	}
+
+	for _, name := range args {
+		cwhub.UpgradeConfig(csConfig, cwhub.COLLECTIONS, name, force)
+	}
+
+	return nil
+}
+
+func NewCollectionsUpgradeCmd() *cobra.Command {
+	cmdCollectionsUpgrade := &cobra.Command{
 		Use:               "upgrade collection",
 		Use:               "upgrade collection",
 		Short:             "Upgrade given collection(s)",
 		Short:             "Upgrade given collection(s)",
 		Long:              `Fetch and upgrade given collection(s) from hub`,
 		Long:              `Fetch and upgrade given collection(s) from hub`,
@@ -121,25 +222,35 @@ func NewCollectionsCmd() *cobra.Command {
 		ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
 		ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
 			return compInstalledItems(cwhub.COLLECTIONS, args, toComplete)
 			return compInstalledItems(cwhub.COLLECTIONS, args, toComplete)
 		},
 		},
-		RunE: func(cmd *cobra.Command, args []string) error {
-			if all {
-				cwhub.UpgradeConfig(csConfig, cwhub.COLLECTIONS, "", forceAction)
-			} else {
-				if len(args) == 0 {
-					return fmt.Errorf("specify at least one collection to upgrade or '--all'")
-				}
-				for _, name := range args {
-					cwhub.UpgradeConfig(csConfig, cwhub.COLLECTIONS, name, forceAction)
-				}
-			}
-			return nil
-		},
+		RunE: runCollectionsUpgrade,
+	}
+
+	flags := cmdCollectionsUpgrade.Flags()
+	flags.BoolP("all", "a", false, "Upgrade all the collections")
+	flags.Bool("force", false, "Force upgrade : Overwrite tainted and outdated files")
+
+	return cmdCollectionsUpgrade
+}
+
+func runCollectionsInspect(cmd *cobra.Command, args []string) error {
+	flags := cmd.Flags()
+
+	var err error
+	// XXX: set global
+	prometheusURL, err = flags.GetString("url")
+	if err != nil {
+		return err
+	}
+
+	for _, name := range args {
+		InspectItem(name, cwhub.COLLECTIONS)
 	}
 	}
-	cmdCollectionsUpgrade.PersistentFlags().BoolVarP(&all, "all", "a", false, "Upgrade all the collections")
-	cmdCollectionsUpgrade.PersistentFlags().BoolVar(&forceAction, "force", false, "Force upgrade : Overwrite tainted and outdated files")
-	cmdCollections.AddCommand(cmdCollectionsUpgrade)
 
 
-	var cmdCollectionsInspect = &cobra.Command{
+	return nil
+}
+
+func NewCollectionsInspectCmd() *cobra.Command {
+	cmdCollectionsInspect := &cobra.Command{
 		Use:               "inspect collection",
 		Use:               "inspect collection",
 		Short:             "Inspect given collection",
 		Short:             "Inspect given collection",
 		Long:              `Inspect given collection`,
 		Long:              `Inspect given collection`,
@@ -149,28 +260,42 @@ func NewCollectionsCmd() *cobra.Command {
 		ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
 		ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
 			return compInstalledItems(cwhub.COLLECTIONS, args, toComplete)
 			return compInstalledItems(cwhub.COLLECTIONS, args, toComplete)
 		},
 		},
-		Run: func(cmd *cobra.Command, args []string) {
-			for _, name := range args {
-				InspectItem(name, cwhub.COLLECTIONS)
-			}
-		},
+		RunE: runCollectionsInspect,
+	}
+
+	flags := cmdCollectionsInspect.Flags()
+	flags.StringP("url", "u", "", "Prometheus url")
+
+	return cmdCollectionsInspect
+}
+
+func runCollectionsList(cmd *cobra.Command, args []string) error {
+	flags := cmd.Flags()
+
+	all, err := flags.GetBool("all")
+	if err != nil {
+		return err
 	}
 	}
-	cmdCollectionsInspect.PersistentFlags().StringVarP(&prometheusURL, "url", "u", "", "Prometheus url")
-	cmdCollections.AddCommand(cmdCollectionsInspect)
 
 
-	var cmdCollectionsList = &cobra.Command{
+	// XXX: will happily ignore missing collections
+	ListItems(color.Output, []string{cwhub.COLLECTIONS}, args, false, true, all)
+
+	return nil
+}
+
+func NewCollectionsListCmd() *cobra.Command {
+	cmdCollectionsList := &cobra.Command{
 		Use:               "list collection [-a]",
 		Use:               "list collection [-a]",
 		Short:             "List all collections",
 		Short:             "List all collections",
 		Long:              `List all collections`,
 		Long:              `List all collections`,
 		Example:           `cscli collections list`,
 		Example:           `cscli collections list`,
 		Args:              cobra.ExactArgs(0),
 		Args:              cobra.ExactArgs(0),
 		DisableAutoGenTag: true,
 		DisableAutoGenTag: true,
-		Run: func(cmd *cobra.Command, args []string) {
-			ListItems(color.Output, []string{cwhub.COLLECTIONS}, args, false, true, all)
-		},
+		RunE:              runCollectionsList,
 	}
 	}
-	cmdCollectionsList.PersistentFlags().BoolVarP(&all, "all", "a", false, "List disabled items as well")
-	cmdCollections.AddCommand(cmdCollectionsList)
 
 
-	return cmdCollections
+	flags := cmdCollectionsList.Flags()
+	flags.BoolP("all", "a", false, "List disabled items as well")
+
+	return cmdCollectionsList
 }
 }

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

@@ -27,10 +27,7 @@ func silentInstallItem(name string, obtype string) (string, error) {
 	if item == nil {
 	if item == nil {
 		return "", fmt.Errorf("error retrieving item")
 		return "", fmt.Errorf("error retrieving item")
 	}
 	}
-	if downloadOnly && item.Downloaded && item.UpToDate {
-		return fmt.Sprintf("%s is already downloaded and up-to-date", item.Name), nil
-	}
-	err := cwhub.DownloadLatest(csConfig.Hub, item, forceAction, false)
+	err := cwhub.DownloadLatest(csConfig.Hub, item, false, false)
 	if err != nil {
 	if err != nil {
 		return "", fmt.Errorf("error while downloading %s : %v", item.Name, err)
 		return "", fmt.Errorf("error while downloading %s : %v", item.Name, err)
 	}
 	}
@@ -38,9 +35,6 @@ func silentInstallItem(name string, obtype string) (string, error) {
 		return "", err
 		return "", err
 	}
 	}
 
 
-	if downloadOnly {
-		return fmt.Sprintf("Downloaded %s to %s", item.Name, csConfig.Cscli.HubDir+"/"+item.RemotePath), nil
-	}
 	err = cwhub.EnableItem(csConfig.Hub, item)
 	err = cwhub.EnableItem(csConfig.Hub, item)
 	if err != nil {
 	if err != nil {
 		return "", fmt.Errorf("error while enabling %s : %v", item.Name, err)
 		return "", fmt.Errorf("error while enabling %s : %v", item.Name, err)

+ 84 - 56
cmd/crowdsec-cli/hub.go

@@ -45,33 +45,71 @@ cscli hub update # Download list of available configurations from the hub
 	return cmdHub
 	return cmdHub
 }
 }
 
 
+func runHubList(cmd *cobra.Command, args []string) error {
+	flags := cmd.Flags()
+
+	all, err := flags.GetBool("all")
+	if err != nil {
+		return err
+	}
+
+	if err := require.Hub(csConfig); err != nil {
+		return err
+	}
+
+	// use LocalSync to get warnings about tainted / outdated items
+	warn, _ := cwhub.LocalSync(csConfig.Hub)
+	for _, v := range warn {
+		log.Info(v)
+	}
+
+	cwhub.DisplaySummary()
+
+	ListItems(color.Output, []string{
+		cwhub.COLLECTIONS, cwhub.PARSERS, cwhub.SCENARIOS, cwhub.PARSERS_OVFLW,
+	}, args, true, false, all)
+
+	return nil
+}
+
 func NewHubListCmd() *cobra.Command {
 func NewHubListCmd() *cobra.Command {
 	var cmdHubList = &cobra.Command{
 	var cmdHubList = &cobra.Command{
 		Use:               "list [-a]",
 		Use:               "list [-a]",
 		Short:             "List installed configs",
 		Short:             "List installed configs",
 		Args:              cobra.ExactArgs(0),
 		Args:              cobra.ExactArgs(0),
 		DisableAutoGenTag: true,
 		DisableAutoGenTag: true,
-		RunE: func(cmd *cobra.Command, args []string) error {
-			if err := require.Hub(csConfig); err != nil {
-				return err
-			}
+		RunE: 	    runHubList,
+	}
 
 
-			// use LocalSync to get warnings about tainted / outdated items
-			warn, _ := cwhub.LocalSync(csConfig.Hub)
-			for _, v := range warn {
-				log.Info(v)
-			}
-			cwhub.DisplaySummary()
-			ListItems(color.Output, []string{
-				cwhub.COLLECTIONS, cwhub.PARSERS, cwhub.SCENARIOS, cwhub.PARSERS_OVFLW,
-			}, args, true, false, all)
+	flags := cmdHubList.Flags()
+	flags.BoolP("all", "a", false, "List disabled items as well")
 
 
-			return nil
-		},
+	return cmdHubList
+}
+
+func runHubUpdate(cmd *cobra.Command, args []string) error {
+	if err := csConfig.LoadHub(); err != nil {
+		return err
 	}
 	}
-	cmdHubList.PersistentFlags().BoolVarP(&all, "all", "a", false, "List disabled items as well")
 
 
-	return cmdHubList
+	if err := cwhub.UpdateHubIdx(csConfig.Hub); err != nil {
+		if !errors.Is(err, cwhub.ErrIndexNotFound) {
+			return fmt.Errorf("failed to get Hub index : %w", err)
+		}
+		log.Warnf("Could not find index file for branch '%s', using 'master'", cwhub.HubBranch)
+		cwhub.HubBranch = "master"
+		if err := cwhub.UpdateHubIdx(csConfig.Hub); err != nil {
+			return fmt.Errorf("failed to get Hub index after retry: %w", err)
+		}
+	}
+
+	// use LocalSync to get warnings about tainted / outdated items
+	warn, _ := cwhub.LocalSync(csConfig.Hub)
+	for _, v := range warn {
+		log.Info(v)
+	}
+
+	return nil
 }
 }
 
 
 func NewHubUpdateCmd() *cobra.Command {
 func NewHubUpdateCmd() *cobra.Command {
@@ -92,33 +130,36 @@ Fetches the [.index.json](https://github.com/crowdsecurity/hub/blob/master/.inde
 
 
 			return nil
 			return nil
 		},
 		},
-		RunE: func(cmd *cobra.Command, args []string) error {
-			if err := csConfig.LoadHub(); err != nil {
-				return err
-			}
-			if err := cwhub.UpdateHubIdx(csConfig.Hub); err != nil {
-				if !errors.Is(err, cwhub.ErrIndexNotFound) {
-					return fmt.Errorf("failed to get Hub index : %w", err)
-				}
-				log.Warnf("Could not find index file for branch '%s', using 'master'", cwhub.HubBranch)
-				cwhub.HubBranch = "master"
-				if err := cwhub.UpdateHubIdx(csConfig.Hub); err != nil {
-					return fmt.Errorf("failed to get Hub index after retry: %w", err)
-				}
-			}
-			// use LocalSync to get warnings about tainted / outdated items
-			warn, _ := cwhub.LocalSync(csConfig.Hub)
-			for _, v := range warn {
-				log.Info(v)
-			}
-
-			return nil
-		},
+		RunE: runHubUpdate,
 	}
 	}
 
 
 	return cmdHubUpdate
 	return cmdHubUpdate
 }
 }
 
 
+func runHubUpgrade(cmd *cobra.Command, args []string) error {
+	flags := cmd.Flags()
+
+	force, err := flags.GetBool("force")
+	if err != nil {
+		return err
+	}
+
+	if err := require.Hub(csConfig); err != nil {
+		return err
+	}
+
+	log.Infof("Upgrading collections")
+	cwhub.UpgradeConfig(csConfig, cwhub.COLLECTIONS, "", force)
+	log.Infof("Upgrading parsers")
+	cwhub.UpgradeConfig(csConfig, cwhub.PARSERS, "", force)
+	log.Infof("Upgrading scenarios")
+	cwhub.UpgradeConfig(csConfig, cwhub.SCENARIOS, "", force)
+	log.Infof("Upgrading postoverflows")
+	cwhub.UpgradeConfig(csConfig, cwhub.PARSERS_OVFLW, "", force)
+
+	return nil
+}
+
 func NewHubUpgradeCmd() *cobra.Command {
 func NewHubUpgradeCmd() *cobra.Command {
 	var cmdHubUpgrade = &cobra.Command{
 	var cmdHubUpgrade = &cobra.Command{
 		Use:   "upgrade",
 		Use:   "upgrade",
@@ -137,24 +178,11 @@ Upgrade all configs installed from Crowdsec Hub. Run 'sudo cscli hub update' if
 
 
 			return nil
 			return nil
 		},
 		},
-		RunE: func(cmd *cobra.Command, args []string) error {
-			if err := require.Hub(csConfig); err != nil {
-				return err
-			}
-
-			log.Infof("Upgrading collections")
-			cwhub.UpgradeConfig(csConfig, cwhub.COLLECTIONS, "", forceAction)
-			log.Infof("Upgrading parsers")
-			cwhub.UpgradeConfig(csConfig, cwhub.PARSERS, "", forceAction)
-			log.Infof("Upgrading scenarios")
-			cwhub.UpgradeConfig(csConfig, cwhub.SCENARIOS, "", forceAction)
-			log.Infof("Upgrading postoverflows")
-			cwhub.UpgradeConfig(csConfig, cwhub.PARSERS_OVFLW, "", forceAction)
-
-			return nil
-		},
+		RunE: runHubUpgrade,
 	}
 	}
-	cmdHubUpgrade.PersistentFlags().BoolVar(&forceAction, "force", false, "Force upgrade : Overwrite tainted and outdated files")
+
+	flags := cmdHubUpgrade.Flags()
+	flags.Bool("force", false, "Force upgrade : Overwrite tainted and outdated files")
 
 
 	return cmdHubUpgrade
 	return cmdHubUpgrade
 }
 }

+ 0 - 5
cmd/crowdsec-cli/main.go

@@ -29,11 +29,6 @@ var dbClient *database.Client
 var OutputFormat string
 var OutputFormat string
 var OutputColor string
 var OutputColor string
 
 
-var downloadOnly bool
-var forceAction bool
-var purge bool
-var all bool
-
 var prometheusURL string
 var prometheusURL string
 
 
 var mergedConfig string
 var mergedConfig string

+ 160 - 67
cmd/crowdsec-cli/parsers.go

@@ -12,7 +12,7 @@ import (
 )
 )
 
 
 func NewParsersCmd() *cobra.Command {
 func NewParsersCmd() *cobra.Command {
-	var cmdParsers = &cobra.Command{
+	cmdParsers := &cobra.Command{
 		Use:   "parsers [action] [config]",
 		Use:   "parsers [action] [config]",
 		Short: "Install/Remove/Upgrade/Inspect parser(s) from hub",
 		Short: "Install/Remove/Upgrade/Inspect parser(s) from hub",
 		Example: `cscli parsers install crowdsecurity/sshd-logs
 		Example: `cscli parsers install crowdsecurity/sshd-logs
@@ -48,10 +48,46 @@ cscli parsers remove crowdsecurity/sshd-logs
 	return cmdParsers
 	return cmdParsers
 }
 }
 
 
-func NewParsersInstallCmd() *cobra.Command {
-	var ignoreError bool
+func runParsersInstall(cmd *cobra.Command, args []string) error {
+	flags := cmd.Flags()
+
+	downloadOnly, err := flags.GetBool("download-only")
+	if err != nil {
+		return err
+	}
+
+	force, err := flags.GetBool("force")
+	if err != nil {
+		return err
+	}
+
+	ignoreError, err := flags.GetBool("ignore")
+	if err != nil {
+		return err
+	}
+
+	for _, name := range args {
+		t := cwhub.GetItem(cwhub.PARSERS, name)
+		if t == nil {
+			nearestItem, score := GetDistance(cwhub.PARSERS, name)
+			Suggest(cwhub.PARSERS, name, nearestItem.Name, score, ignoreError)
+
+			continue
+		}
 
 
-	var cmdParsersInstall = &cobra.Command{
+		if err := cwhub.InstallItem(csConfig, name, cwhub.PARSERS, force, downloadOnly); err != nil {
+			if !ignoreError {
+				return fmt.Errorf("error while installing '%s': %w", name, err)
+			}
+			log.Errorf("Error while installing '%s': %s", name, err)
+		}
+	}
+
+	return nil
+}
+
+func NewParsersInstallCmd() *cobra.Command {
+	cmdParsersInstall := &cobra.Command{
 		Use:               "install [config]",
 		Use:               "install [config]",
 		Short:             "Install given parser(s)",
 		Short:             "Install given parser(s)",
 		Long:              `Fetch and install given parser(s) from hub`,
 		Long:              `Fetch and install given parser(s) from hub`,
@@ -61,32 +97,58 @@ func NewParsersInstallCmd() *cobra.Command {
 		ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
 		ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
 			return compAllItems(cwhub.PARSERS, args, toComplete)
 			return compAllItems(cwhub.PARSERS, args, toComplete)
 		},
 		},
-		RunE: func(cmd *cobra.Command, args []string) error {
-			for _, name := range args {
-				t := cwhub.GetItem(cwhub.PARSERS, name)
-				if t == nil {
-					nearestItem, score := GetDistance(cwhub.PARSERS, name)
-					Suggest(cwhub.PARSERS, name, nearestItem.Name, score, ignoreError)
-					continue
-				}
-				if err := cwhub.InstallItem(csConfig, name, cwhub.PARSERS, forceAction, downloadOnly); err != nil {
-					if !ignoreError {
-						return fmt.Errorf("error while installing '%s': %w", name, err)
-					}
-					log.Errorf("Error while installing '%s': %s", name, err)
-				}
-			}
-			return nil
-		},
+		RunE: runParsersInstall,
 	}
 	}
 
 
-	cmdParsersInstall.PersistentFlags().BoolVarP(&downloadOnly, "download-only", "d", false, "Only download packages, don't enable")
-	cmdParsersInstall.PersistentFlags().BoolVar(&forceAction, "force", false, "Force install : Overwrite tainted and outdated files")
-	cmdParsersInstall.PersistentFlags().BoolVar(&ignoreError, "ignore", false, "Ignore errors when installing multiple parsers")
+	flags := cmdParsersInstall.Flags()
+	flags.BoolP("download-only", "d", false, "Only download packages, don't enable")
+	flags.Bool("force", false, "Force install: Overwrite tainted and outdated files")
+	flags.Bool("ignore", false, "Ignore errors when installing multiple parsers")
 
 
 	return cmdParsersInstall
 	return cmdParsersInstall
 }
 }
 
 
+func runParsersRemove(cmd *cobra.Command, args []string) error {
+	flags := cmd.Flags()
+
+	purge, err := flags.GetBool("purge")
+	if err != nil {
+		return err
+	}
+
+	force, err := flags.GetBool("force")
+	if err != nil {
+		return err
+	}
+
+	all, err := flags.GetBool("all")
+	if err != nil {
+		return err
+	}
+
+	if all {
+		err := cwhub.RemoveMany(csConfig, cwhub.PARSERS, "", all, purge, force)
+		if err != nil {
+			return err
+		}
+
+		return nil
+	}
+
+	if len(args) == 0 {
+		return fmt.Errorf("specify at least one parser to remove or '--all'")
+	}
+
+	for _, name := range args {
+		err := cwhub.RemoveMany(csConfig, cwhub.PARSERS, name, all, purge, force)
+		if err != nil {
+			return err
+		}
+	}
+
+	return nil
+}
+
 func NewParsersRemoveCmd() *cobra.Command {
 func NewParsersRemoveCmd() *cobra.Command {
 	cmdParsersRemove := &cobra.Command{
 	cmdParsersRemove := &cobra.Command{
 		Use:               "remove [config]",
 		Use:               "remove [config]",
@@ -98,29 +160,44 @@ func NewParsersRemoveCmd() *cobra.Command {
 		ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
 		ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
 			return compInstalledItems(cwhub.PARSERS, args, toComplete)
 			return compInstalledItems(cwhub.PARSERS, args, toComplete)
 		},
 		},
-		RunE: func(cmd *cobra.Command, args []string) error {
-			if all {
-				cwhub.RemoveMany(csConfig, cwhub.PARSERS, "", all, purge, forceAction)
-				return nil
-			}
+		RunE: runParsersRemove,
+	}
 
 
-			if len(args) == 0 {
-				return fmt.Errorf("specify at least one parser to remove or '--all'")
-			}
+	flags := cmdParsersRemove.Flags()
+	flags.Bool("purge", false, "Delete source file too")
+	flags.Bool("force", false, "Force remove: Remove tainted and outdated files")
+	flags.Bool("all", false, "Delete all the parsers")
 
 
-			for _, name := range args {
-				cwhub.RemoveMany(csConfig, cwhub.PARSERS, name, all, purge, forceAction)
-			}
+	return cmdParsersRemove
+}
 
 
-			return nil
-		},
+func runParsersUpgrade(cmd *cobra.Command, args []string) error {
+	flags := cmd.Flags()
+
+	force, err := flags.GetBool("force")
+	if err != nil {
+		return err
+	}
+
+	all, err := flags.GetBool("all")
+	if err != nil {
+		return err
 	}
 	}
 
 
-	cmdParsersRemove.PersistentFlags().BoolVar(&purge, "purge", false, "Delete source file too")
-	cmdParsersRemove.PersistentFlags().BoolVar(&forceAction, "force", false, "Force remove : Remove tainted and outdated files")
-	cmdParsersRemove.PersistentFlags().BoolVar(&all, "all", false, "Delete all the parsers")
+	if all {
+		cwhub.UpgradeConfig(csConfig, cwhub.PARSERS, "", force)
+		return nil
+	}
 
 
-	return cmdParsersRemove
+	if len(args) == 0 {
+		return fmt.Errorf("specify at least one parser to upgrade or '--all'")
+	}
+
+	for _, name := range args {
+		cwhub.UpgradeConfig(csConfig, cwhub.PARSERS, name, force)
+	}
+
+	return nil
 }
 }
 
 
 func NewParsersUpgradeCmd() *cobra.Command {
 func NewParsersUpgradeCmd() *cobra.Command {
@@ -133,62 +210,78 @@ func NewParsersUpgradeCmd() *cobra.Command {
 		ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
 		ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
 			return compInstalledItems(cwhub.PARSERS, args, toComplete)
 			return compInstalledItems(cwhub.PARSERS, args, toComplete)
 		},
 		},
-		RunE: func(cmd *cobra.Command, args []string) error {
-			if all {
-				cwhub.UpgradeConfig(csConfig, cwhub.PARSERS, "", forceAction)
-			} else {
-				if len(args) == 0 {
-					return fmt.Errorf("specify at least one parser to upgrade or '--all'")
-				}
-				for _, name := range args {
-					cwhub.UpgradeConfig(csConfig, cwhub.PARSERS, name, forceAction)
-				}
-			}
-			return nil
-		},
+		RunE: runParsersUpgrade,
 	}
 	}
 
 
-	cmdParsersUpgrade.PersistentFlags().BoolVar(&all, "all", false, "Upgrade all the parsers")
-	cmdParsersUpgrade.PersistentFlags().BoolVar(&forceAction, "force", false, "Force upgrade : Overwrite tainted and outdated files")
+	flags := cmdParsersUpgrade.Flags()
+	flags.Bool("all", false, "Upgrade all the parsers")
+	flags.Bool("force", false, "Force upgrade : Overwrite tainted and outdated files")
 
 
 	return cmdParsersUpgrade
 	return cmdParsersUpgrade
 }
 }
 
 
+func runParsersInspect(cmd *cobra.Command, args []string) error {
+	flags := cmd.Flags()
+
+	var err error
+	// XXX: set global
+	prometheusURL, err = flags.GetString("url")
+	if err != nil {
+		return err
+	}
+
+	InspectItem(args[0], cwhub.PARSERS)
+
+	return nil
+}
+
 func NewParsersInspectCmd() *cobra.Command {
 func NewParsersInspectCmd() *cobra.Command {
-	var cmdParsersInspect = &cobra.Command{
+	cmdParsersInspect := &cobra.Command{
 		Use:               "inspect [name]",
 		Use:               "inspect [name]",
 		Short:             "Inspect given parser",
 		Short:             "Inspect given parser",
 		Long:              `Inspect given parser`,
 		Long:              `Inspect given parser`,
 		Example:           `cscli parsers inspect crowdsec/xxx`,
 		Example:           `cscli parsers inspect crowdsec/xxx`,
-		DisableAutoGenTag: true,
 		Args:              cobra.MinimumNArgs(1),
 		Args:              cobra.MinimumNArgs(1),
+		DisableAutoGenTag: true,
 		ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
 		ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
 			return compInstalledItems(cwhub.PARSERS, args, toComplete)
 			return compInstalledItems(cwhub.PARSERS, args, toComplete)
 		},
 		},
-		Run: func(cmd *cobra.Command, args []string) {
-			InspectItem(args[0], cwhub.PARSERS)
-		},
+		RunE: runParsersInspect,
 	}
 	}
 
 
-	cmdParsersInspect.PersistentFlags().StringVarP(&prometheusURL, "url", "u", "", "Prometheus url")
+	flags := cmdParsersInspect.Flags()
+	flags.StringP("url", "u", "", "Prometheus url")
 
 
 	return cmdParsersInspect
 	return cmdParsersInspect
 }
 }
 
 
+func runParsersList(cmd *cobra.Command, args []string) error {
+	flags := cmd.Flags()
+
+	all, err := flags.GetBool("all")
+	if err != nil {
+		return err
+	}
+
+	// XXX: will happily ignore missing parsers
+	ListItems(color.Output, []string{cwhub.PARSERS}, args, false, true, all)
+
+	return nil
+}
+
 func NewParsersListCmd() *cobra.Command {
 func NewParsersListCmd() *cobra.Command {
-	var cmdParsersList = &cobra.Command{
+	cmdParsersList := &cobra.Command{
 		Use:   "list [name]",
 		Use:   "list [name]",
 		Short: "List all parsers or given one",
 		Short: "List all parsers or given one",
 		Long:  `List all parsers or given one`,
 		Long:  `List all parsers or given one`,
 		Example: `cscli parsers list
 		Example: `cscli parsers list
 cscli parser list crowdsecurity/xxx`,
 cscli parser list crowdsecurity/xxx`,
 		DisableAutoGenTag: true,
 		DisableAutoGenTag: true,
-		Run: func(cmd *cobra.Command, args []string) {
-			ListItems(color.Output, []string{cwhub.PARSERS}, args, false, true, all)
-		},
+		RunE:              runParsersList,
 	}
 	}
 
 
-	cmdParsersList.PersistentFlags().BoolVarP(&all, "all", "a", false, "List disabled items as well")
+	flags := cmdParsersList.Flags()
+	flags.BoolP("all", "a", false, "List disabled items as well")
 
 
 	return cmdParsersList
 	return cmdParsersList
 }
 }

+ 163 - 66
cmd/crowdsec-cli/postoverflows.go

@@ -16,10 +16,11 @@ func NewPostOverflowsCmd() *cobra.Command {
 		Use:   "postoverflows [action] [config]",
 		Use:   "postoverflows [action] [config]",
 		Short: "Install/Remove/Upgrade/Inspect postoverflow(s) from hub",
 		Short: "Install/Remove/Upgrade/Inspect postoverflow(s) from hub",
 		Example: `cscli postoverflows install crowdsecurity/cdn-whitelist
 		Example: `cscli postoverflows install crowdsecurity/cdn-whitelist
-		cscli postoverflows inspect crowdsecurity/cdn-whitelist
-		cscli postoverflows upgrade crowdsecurity/cdn-whitelist
-		cscli postoverflows list
-		cscli postoverflows remove crowdsecurity/cdn-whitelist`,
+cscli postoverflows inspect crowdsecurity/cdn-whitelist
+cscli postoverflows upgrade crowdsecurity/cdn-whitelist
+cscli postoverflows list
+cscli postoverflows remove crowdsecurity/cdn-whitelist
+`,
 		Args:              cobra.MinimumNArgs(1),
 		Args:              cobra.MinimumNArgs(1),
 		Aliases:           []string{"postoverflow"},
 		Aliases:           []string{"postoverflow"},
 		DisableAutoGenTag: true,
 		DisableAutoGenTag: true,
@@ -47,9 +48,45 @@ func NewPostOverflowsCmd() *cobra.Command {
 	return cmdPostOverflows
 	return cmdPostOverflows
 }
 }
 
 
-func NewPostOverflowsInstallCmd() *cobra.Command {
-	var ignoreError bool
+func runPostOverflowsInstall(cmd *cobra.Command, args []string) error {
+	flags := cmd.Flags()
+
+	downloadOnly, err := flags.GetBool("download-only")
+	if err != nil {
+		return err
+	}
+
+	force, err := flags.GetBool("force")
+	if err != nil {
+		return err
+	}
+
+	ignoreError, err := flags.GetBool("ignore")
+	if err != nil {
+		return err
+	}
+
+	for _, name := range args {
+		t := cwhub.GetItem(cwhub.PARSERS_OVFLW, name)
+		if t == nil {
+			nearestItem, score := GetDistance(cwhub.PARSERS_OVFLW, name)
+			Suggest(cwhub.PARSERS_OVFLW, name, nearestItem.Name, score, ignoreError)
+
+			continue
+		}
 
 
+		if err := cwhub.InstallItem(csConfig, name, cwhub.PARSERS_OVFLW, force, downloadOnly); err != nil {
+			if !ignoreError {
+				return fmt.Errorf("error while installing '%s': %w", name, err)
+			}
+			log.Errorf("Error while installing '%s': %s", name, err)
+		}
+	}
+
+	return nil
+}
+
+func NewPostOverflowsInstallCmd() *cobra.Command {
 	cmdPostOverflowsInstall := &cobra.Command{
 	cmdPostOverflowsInstall := &cobra.Command{
 		Use:               "install [config]",
 		Use:               "install [config]",
 		Short:             "Install given postoverflow(s)",
 		Short:             "Install given postoverflow(s)",
@@ -60,32 +97,58 @@ func NewPostOverflowsInstallCmd() *cobra.Command {
 		ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
 		ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
 			return compAllItems(cwhub.PARSERS_OVFLW, args, toComplete)
 			return compAllItems(cwhub.PARSERS_OVFLW, args, toComplete)
 		},
 		},
-		RunE: func(cmd *cobra.Command, args []string) error {
-			for _, name := range args {
-				t := cwhub.GetItem(cwhub.PARSERS_OVFLW, name)
-				if t == nil {
-					nearestItem, score := GetDistance(cwhub.PARSERS_OVFLW, name)
-					Suggest(cwhub.PARSERS_OVFLW, name, nearestItem.Name, score, ignoreError)
-					continue
-				}
-				if err := cwhub.InstallItem(csConfig, name, cwhub.PARSERS_OVFLW, forceAction, downloadOnly); err != nil {
-					if !ignoreError {
-						return fmt.Errorf("error while installing '%s': %w", name, err)
-					}
-					log.Errorf("Error while installing '%s': %s", name, err)
-				}
-			}
-			return nil
-		},
+		RunE: runPostOverflowsInstall,
 	}
 	}
 
 
-	cmdPostOverflowsInstall.PersistentFlags().BoolVarP(&downloadOnly, "download-only", "d", false, "Only download packages, don't enable")
-	cmdPostOverflowsInstall.PersistentFlags().BoolVar(&forceAction, "force", false, "Force install : Overwrite tainted and outdated files")
-	cmdPostOverflowsInstall.PersistentFlags().BoolVar(&ignoreError, "ignore", false, "Ignore errors when installing multiple postoverflows")
+	flags := cmdPostOverflowsInstall.Flags()
+	flags.BoolP("download-only", "d", false, "Only download packages, don't enable")
+	flags.Bool("force", false, "Force install : Overwrite tainted and outdated files")
+	flags.Bool("ignore", false, "Ignore errors when installing multiple postoverflows")
 
 
 	return cmdPostOverflowsInstall
 	return cmdPostOverflowsInstall
 }
 }
 
 
+func runPostOverflowsRemove(cmd *cobra.Command, args []string) error {
+	flags := cmd.Flags()
+
+	purge, err := flags.GetBool("purge")
+	if err != nil {
+		return err
+	}
+
+	force, err := flags.GetBool("force")
+	if err != nil {
+		return err
+	}
+
+	all, err := flags.GetBool("all")
+	if err != nil {
+		return err
+	}
+
+	if all {
+		err := cwhub.RemoveMany(csConfig, cwhub.PARSERS_OVFLW, "", all, purge, force)
+		if err != nil {
+			return err
+		}
+
+		return nil
+	}
+
+	if len(args) == 0 {
+		return fmt.Errorf("specify at least one postoverflow to remove or '--all'")
+	}
+
+	for _, name := range args {
+		err := cwhub.RemoveMany(csConfig, cwhub.PARSERS_OVFLW, name, all, purge, force)
+		if err != nil {
+			return err
+		}
+	}
+
+	return nil
+}
+
 func NewPostOverflowsRemoveCmd() *cobra.Command {
 func NewPostOverflowsRemoveCmd() *cobra.Command {
 	cmdPostOverflowsRemove := &cobra.Command{
 	cmdPostOverflowsRemove := &cobra.Command{
 		Use:               "remove [config]",
 		Use:               "remove [config]",
@@ -97,29 +160,44 @@ func NewPostOverflowsRemoveCmd() *cobra.Command {
 		ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
 		ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
 			return compInstalledItems(cwhub.PARSERS_OVFLW, args, toComplete)
 			return compInstalledItems(cwhub.PARSERS_OVFLW, args, toComplete)
 		},
 		},
-		RunE: func(cmd *cobra.Command, args []string) error {
-			if all {
-				cwhub.RemoveMany(csConfig, cwhub.PARSERS_OVFLW, "", all, purge, forceAction)
-				return nil
-			}
+		RunE: runPostOverflowsRemove,
+	}
 
 
-			if len(args) == 0 {
-				return fmt.Errorf("specify at least one postoverflow to remove or '--all'")
-			}
+	flags := cmdPostOverflowsRemove.Flags()
+	flags.Bool("purge", false, "Delete source file too")
+	flags.Bool("force", false, "Force remove : Remove tainted and outdated files")
+	flags.Bool("all", false, "Delete all the postoverflows")
 
 
-			for _, name := range args {
-				cwhub.RemoveMany(csConfig, cwhub.PARSERS_OVFLW, name, all, purge, forceAction)
-			}
+	return cmdPostOverflowsRemove
+}
 
 
-			return nil
-		},
+func runPostOverflowUpgrade(cmd *cobra.Command, args []string) error {
+	flags := cmd.Flags()
+
+	force, err := flags.GetBool("force")
+	if err != nil {
+		return err
 	}
 	}
 
 
-	cmdPostOverflowsRemove.PersistentFlags().BoolVar(&purge, "purge", false, "Delete source file too")
-	cmdPostOverflowsRemove.PersistentFlags().BoolVar(&forceAction, "force", false, "Force remove : Remove tainted and outdated files")
-	cmdPostOverflowsRemove.PersistentFlags().BoolVar(&all, "all", false, "Delete all the postoverflows")
+	all, err := flags.GetBool("all")
+	if err != nil {
+		return err
+	}
 
 
-	return cmdPostOverflowsRemove
+	if all {
+		cwhub.UpgradeConfig(csConfig, cwhub.PARSERS_OVFLW, "", force)
+		return nil
+	}
+
+	if len(args) == 0 {
+		return fmt.Errorf("specify at least one postoverflow to upgrade or '--all'")
+	}
+
+	for _, name := range args {
+		cwhub.UpgradeConfig(csConfig, cwhub.PARSERS_OVFLW, name, force)
+	}
+
+	return nil
 }
 }
 
 
 func NewPostOverflowsUpgradeCmd() *cobra.Command {
 func NewPostOverflowsUpgradeCmd() *cobra.Command {
@@ -132,46 +210,66 @@ func NewPostOverflowsUpgradeCmd() *cobra.Command {
 		ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
 		ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
 			return compInstalledItems(cwhub.PARSERS_OVFLW, args, toComplete)
 			return compInstalledItems(cwhub.PARSERS_OVFLW, args, toComplete)
 		},
 		},
-		RunE: func(cmd *cobra.Command, args []string) error {
-			if all {
-				cwhub.UpgradeConfig(csConfig, cwhub.PARSERS_OVFLW, "", forceAction)
-			} else {
-				if len(args) == 0 {
-					return fmt.Errorf("specify at least one postoverflow to upgrade or '--all'")
-				}
-				for _, name := range args {
-					cwhub.UpgradeConfig(csConfig, cwhub.PARSERS_OVFLW, name, forceAction)
-				}
-			}
-			return nil
-		},
+		RunE: runPostOverflowUpgrade,
 	}
 	}
 
 
-	cmdPostOverflowsUpgrade.PersistentFlags().BoolVarP(&all, "all", "a", false, "Upgrade all the postoverflows")
-	cmdPostOverflowsUpgrade.PersistentFlags().BoolVar(&forceAction, "force", false, "Force upgrade : Overwrite tainted and outdated files")
+	flags := cmdPostOverflowsUpgrade.Flags()
+	flags.BoolP("all", "a", false, "Upgrade all the postoverflows")
+	flags.Bool("force", false, "Force upgrade : Overwrite tainted and outdated files")
 
 
 	return cmdPostOverflowsUpgrade
 	return cmdPostOverflowsUpgrade
 }
 }
 
 
+func runPostOverflowsInspect(cmd *cobra.Command, args []string) error {
+	flags := cmd.Flags()
+
+	var err error
+	// XXX: set global
+	prometheusURL, err = flags.GetString("url")
+	if err != nil {
+		return err
+	}
+
+	InspectItem(args[0], cwhub.PARSERS_OVFLW)
+
+	return nil
+}
+
 func NewPostOverflowsInspectCmd() *cobra.Command {
 func NewPostOverflowsInspectCmd() *cobra.Command {
 	cmdPostOverflowsInspect := &cobra.Command{
 	cmdPostOverflowsInspect := &cobra.Command{
 		Use:               "inspect [config]",
 		Use:               "inspect [config]",
 		Short:             "Inspect given postoverflow",
 		Short:             "Inspect given postoverflow",
 		Long:              `Inspect given postoverflow`,
 		Long:              `Inspect given postoverflow`,
 		Example:           `cscli postoverflows inspect crowdsec/xxx crowdsec/xyz`,
 		Example:           `cscli postoverflows inspect crowdsec/xxx crowdsec/xyz`,
-		DisableAutoGenTag: true,
 		Args:              cobra.MinimumNArgs(1),
 		Args:              cobra.MinimumNArgs(1),
+		DisableAutoGenTag: true,
 		ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
 		ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
 			return compInstalledItems(cwhub.PARSERS_OVFLW, args, toComplete)
 			return compInstalledItems(cwhub.PARSERS_OVFLW, args, toComplete)
 		},
 		},
-		Run: func(cmd *cobra.Command, args []string) {
-			InspectItem(args[0], cwhub.PARSERS_OVFLW)
-		},
+		RunE: runPostOverflowsInspect,
 	}
 	}
 
 
+	flags := cmdPostOverflowsInspect.Flags()
+	// XXX: is this needed for postoverflows?
+	flags.StringP("url", "u", "", "Prometheus url")
+
 	return cmdPostOverflowsInspect
 	return cmdPostOverflowsInspect
 }
 }
 
 
+func runPostOverflowsList(cmd *cobra.Command, args []string) error {
+	flags := cmd.Flags()
+
+	all, err := flags.GetBool("all")
+	if err != nil {
+		return err
+	}
+
+	// XXX: will happily ignore missing postoverflows
+	ListItems(color.Output, []string{cwhub.PARSERS_OVFLW}, args, false, true, all)
+
+	return nil
+}
+
 func NewPostOverflowsListCmd() *cobra.Command {
 func NewPostOverflowsListCmd() *cobra.Command {
 	cmdPostOverflowsList := &cobra.Command{
 	cmdPostOverflowsList := &cobra.Command{
 		Use:   "list [config]",
 		Use:   "list [config]",
@@ -180,12 +278,11 @@ func NewPostOverflowsListCmd() *cobra.Command {
 		Example: `cscli postoverflows list
 		Example: `cscli postoverflows list
 cscli postoverflows list crowdsecurity/xxx`,
 cscli postoverflows list crowdsecurity/xxx`,
 		DisableAutoGenTag: true,
 		DisableAutoGenTag: true,
-		Run: func(cmd *cobra.Command, args []string) {
-			ListItems(color.Output, []string{cwhub.PARSERS_OVFLW}, args, false, true, all)
-		},
+		RunE:              runPostOverflowsList,
 	}
 	}
 
 
-	cmdPostOverflowsList.PersistentFlags().BoolVarP(&all, "all", "a", false, "List disabled items as well")
+	flags := cmdPostOverflowsList.Flags()
+	flags.BoolP("all", "a", false, "List disabled items as well")
 
 
 	return cmdPostOverflowsList
 	return cmdPostOverflowsList
 }
 }

+ 190 - 91
cmd/crowdsec-cli/scenarios.go

@@ -12,7 +12,7 @@ import (
 )
 )
 
 
 func NewScenariosCmd() *cobra.Command {
 func NewScenariosCmd() *cobra.Command {
-	var cmdScenarios = &cobra.Command{
+	cmdScenarios := &cobra.Command{
 		Use:   "scenarios [action] [config]",
 		Use:   "scenarios [action] [config]",
 		Short: "Install/Remove/Upgrade/Inspect scenario(s) from hub",
 		Short: "Install/Remove/Upgrade/Inspect scenario(s) from hub",
 		Example: `cscli scenarios list [-a]
 		Example: `cscli scenarios list [-a]
@@ -48,141 +48,240 @@ cscli scenarios remove crowdsecurity/ssh-bf
 	return cmdScenarios
 	return cmdScenarios
 }
 }
 
 
+func runScenariosInstall(cmd *cobra.Command, args []string) error {
+	flags := cmd.Flags()
+
+	downloadOnly, err := flags.GetBool("download-only")
+	if err != nil {
+		return err
+	}
+
+	force, err := flags.GetBool("force")
+	if err != nil {
+		return err
+	}
+
+	ignoreError, err := flags.GetBool("ignore")
+	if err != nil {
+		return err
+	}
+
+	for _, name := range args {
+		t := cwhub.GetItem(cwhub.SCENARIOS, name)
+		if t == nil {
+			nearestItem, score := GetDistance(cwhub.SCENARIOS, name)
+			Suggest(cwhub.SCENARIOS, name, nearestItem.Name, score, ignoreError)
+
+			continue
+		}
+
+		if err := cwhub.InstallItem(csConfig, name, cwhub.SCENARIOS, force, downloadOnly); err != nil {
+			if !ignoreError {
+				return fmt.Errorf("error while installing '%s': %w", name, err)
+			}
+			log.Errorf("Error while installing '%s': %s", name, err)
+		}
+	}
+
+	return nil
+}
+
 func NewCmdScenariosInstall() *cobra.Command {
 func NewCmdScenariosInstall() *cobra.Command {
-	var ignoreError bool
-
-	var cmdScenariosInstall = &cobra.Command{
-		Use:     "install [config]",
-		Short:   "Install given scenario(s)",
-		Long:    `Fetch and install given scenario(s) from hub`,
-		Example: `cscli scenarios install crowdsec/xxx crowdsec/xyz`,
-		Args:    cobra.MinimumNArgs(1),
+	cmdScenariosInstall := &cobra.Command{
+		Use:               "install [config]",
+		Short:             "Install given scenario(s)",
+		Long:              `Fetch and install given scenario(s) from hub`,
+		Example:           `cscli scenarios install crowdsec/xxx crowdsec/xyz`,
+		Args:              cobra.MinimumNArgs(1),
+		DisableAutoGenTag: true,
 		ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
 		ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
 			return compAllItems(cwhub.SCENARIOS, args, toComplete)
 			return compAllItems(cwhub.SCENARIOS, args, toComplete)
 		},
 		},
-		DisableAutoGenTag: true,
-		RunE: func(cmd *cobra.Command, args []string) error {
-			for _, name := range args {
-				t := cwhub.GetItem(cwhub.SCENARIOS, name)
-				if t == nil {
-					nearestItem, score := GetDistance(cwhub.SCENARIOS, name)
-					Suggest(cwhub.SCENARIOS, name, nearestItem.Name, score, ignoreError)
-					continue
-				}
-				if err := cwhub.InstallItem(csConfig, name, cwhub.SCENARIOS, forceAction, downloadOnly); err != nil {
-					if !ignoreError {
-						return fmt.Errorf("error while installing '%s': %w", name, err)
-					}
-					log.Errorf("Error while installing '%s': %s", name, err)
-				}
-			}
-			return nil
-		},
+		RunE: runScenariosInstall,
 	}
 	}
-	cmdScenariosInstall.PersistentFlags().BoolVarP(&downloadOnly, "download-only", "d", false, "Only download packages, don't enable")
-	cmdScenariosInstall.PersistentFlags().BoolVar(&forceAction, "force", false, "Force install : Overwrite tainted and outdated files")
-	cmdScenariosInstall.PersistentFlags().BoolVar(&ignoreError, "ignore", false, "Ignore errors when installing multiple scenarios")
+
+	flags := cmdScenariosInstall.Flags()
+	flags.BoolP("download-only", "d", false, "Only download packages, don't enable")
+	flags.Bool("force", false, "Force install : Overwrite tainted and outdated files")
+	flags.Bool("ignore", false, "Ignore errors when installing multiple scenarios")
 
 
 	return cmdScenariosInstall
 	return cmdScenariosInstall
 }
 }
 
 
+func runScenariosRemove(cmd *cobra.Command, args []string) error {
+	flags := cmd.Flags()
+
+	purge, err := flags.GetBool("purge")
+	if err != nil {
+		return err
+	}
+
+	force, err := flags.GetBool("force")
+	if err != nil {
+		return err
+	}
+
+	all, err := flags.GetBool("all")
+	if err != nil {
+		return err
+	}
+
+	if all {
+		err := cwhub.RemoveMany(csConfig, cwhub.SCENARIOS, "", all, purge, force)
+		if err != nil {
+			return err
+		}
+
+		return nil
+	}
+
+	if len(args) == 0 {
+		return fmt.Errorf("specify at least one scenario to remove or '--all'")
+	}
+
+	for _, name := range args {
+		err := cwhub.RemoveMany(csConfig, cwhub.SCENARIOS, name, all, purge, force)
+		if err != nil {
+			return err
+		}
+	}
+
+	return nil
+}
+
 func NewCmdScenariosRemove() *cobra.Command {
 func NewCmdScenariosRemove() *cobra.Command {
-	var cmdScenariosRemove = &cobra.Command{
-		Use:     "remove [config]",
-		Short:   "Remove given scenario(s)",
-		Long:    `remove given scenario(s)`,
-		Example: `cscli scenarios remove crowdsec/xxx crowdsec/xyz`,
-		Aliases: []string{"delete"},
+	cmdScenariosRemove := &cobra.Command{
+		Use:               "remove [config]",
+		Short:             "Remove given scenario(s)",
+		Long:              `remove given scenario(s)`,
+		Example:           `cscli scenarios remove crowdsec/xxx crowdsec/xyz`,
+		Aliases:           []string{"delete"},
+		DisableAutoGenTag: true,
 		ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
 		ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
 			return compInstalledItems(cwhub.SCENARIOS, args, toComplete)
 			return compInstalledItems(cwhub.SCENARIOS, args, toComplete)
 		},
 		},
-		DisableAutoGenTag: true,
-		RunE: func(cmd *cobra.Command, args []string) error {
-			if all {
-				cwhub.RemoveMany(csConfig, cwhub.SCENARIOS, "", all, purge, forceAction)
-				return nil
-			}
+		RunE: runScenariosRemove,
+	}
 
 
-			if len(args) == 0 {
-				return fmt.Errorf("specify at least one scenario to remove or '--all'")
-			}
+	flags := cmdScenariosRemove.Flags()
+	flags.Bool("purge", false, "Delete source file too")
+	flags.Bool("force", false, "Force remove: Remove tainted and outdated files")
+	flags.Bool("all", false, "Delete all the scenarios")
 
 
-			for _, name := range args {
-				cwhub.RemoveMany(csConfig, cwhub.SCENARIOS, name, all, purge, forceAction)
-			}
-			return nil
-		},
+	return cmdScenariosRemove
+}
+
+func runScenariosUpgrade(cmd *cobra.Command, args []string) error {
+	flags := cmd.Flags()
+
+	force, err := flags.GetBool("force")
+	if err != nil {
+		return err
 	}
 	}
-	cmdScenariosRemove.PersistentFlags().BoolVar(&purge, "purge", false, "Delete source file too")
-	cmdScenariosRemove.PersistentFlags().BoolVar(&forceAction, "force", false, "Force remove : Remove tainted and outdated files")
-	cmdScenariosRemove.PersistentFlags().BoolVar(&all, "all", false, "Delete all the scenarios")
 
 
-	return cmdScenariosRemove
+	all, err := flags.GetBool("all")
+	if err != nil {
+		return err
+	}
+
+	if all {
+		cwhub.UpgradeConfig(csConfig, cwhub.SCENARIOS, "", force)
+		return nil
+	}
+
+	if len(args) == 0 {
+		return fmt.Errorf("specify at least one scenario to upgrade or '--all'")
+	}
+
+	for _, name := range args {
+		cwhub.UpgradeConfig(csConfig, cwhub.SCENARIOS, name, force)
+	}
+
+	return nil
 }
 }
 
 
 func NewCmdScenariosUpgrade() *cobra.Command {
 func NewCmdScenariosUpgrade() *cobra.Command {
-	var cmdScenariosUpgrade = &cobra.Command{
-		Use:     "upgrade [config]",
-		Short:   "Upgrade given scenario(s)",
-		Long:    `Fetch and Upgrade given scenario(s) from hub`,
-		Example: `cscli scenarios upgrade crowdsec/xxx crowdsec/xyz`,
+	cmdScenariosUpgrade := &cobra.Command{
+		Use:               "upgrade [config]",
+		Short:             "Upgrade given scenario(s)",
+		Long:              `Fetch and Upgrade given scenario(s) from hub`,
+		Example:           `cscli scenarios upgrade crowdsec/xxx crowdsec/xyz`,
+		DisableAutoGenTag: true,
 		ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
 		ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
 			return compInstalledItems(cwhub.SCENARIOS, args, toComplete)
 			return compInstalledItems(cwhub.SCENARIOS, args, toComplete)
 		},
 		},
-		DisableAutoGenTag: true,
-		RunE: func(cmd *cobra.Command, args []string) error {
-			if all {
-				cwhub.UpgradeConfig(csConfig, cwhub.SCENARIOS, "", forceAction)
-			} else {
-				if len(args) == 0 {
-					return fmt.Errorf("specify at least one scenario to upgrade or '--all'")
-				}
-				for _, name := range args {
-					cwhub.UpgradeConfig(csConfig, cwhub.SCENARIOS, name, forceAction)
-				}
-			}
-			return nil
-		},
+		RunE: runScenariosUpgrade,
 	}
 	}
-	cmdScenariosUpgrade.PersistentFlags().BoolVarP(&all, "all", "a", false, "Upgrade all the scenarios")
-	cmdScenariosUpgrade.PersistentFlags().BoolVar(&forceAction, "force", false, "Force upgrade : Overwrite tainted and outdated files")
+
+	flags := cmdScenariosUpgrade.Flags()
+	flags.BoolP("all", "a", false, "Upgrade all the scenarios")
+	flags.Bool("force", false, "Force upgrade : Overwrite tainted and outdated files")
 
 
 	return cmdScenariosUpgrade
 	return cmdScenariosUpgrade
 }
 }
 
 
+func runScenariosInspect(cmd *cobra.Command, args []string) error {
+	flags := cmd.Flags()
+
+	var err error
+	// XXX: set global
+	prometheusURL, err = flags.GetString("url")
+	if err != nil {
+		return err
+	}
+
+	InspectItem(args[0], cwhub.SCENARIOS)
+
+	return nil
+}
+
 func NewCmdScenariosInspect() *cobra.Command {
 func NewCmdScenariosInspect() *cobra.Command {
-	var cmdScenariosInspect = &cobra.Command{
-		Use:     "inspect [config]",
-		Short:   "Inspect given scenario",
-		Long:    `Inspect given scenario`,
-		Example: `cscli scenarios inspect crowdsec/xxx`,
-		Args:    cobra.MinimumNArgs(1),
+	cmdScenariosInspect := &cobra.Command{
+		Use:               "inspect [config]",
+		Short:             "Inspect given scenario",
+		Long:              `Inspect given scenario`,
+		Example:           `cscli scenarios inspect crowdsec/xxx`,
+		Args:              cobra.MinimumNArgs(1),
+		DisableAutoGenTag: true,
 		ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
 		ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
 			return compInstalledItems(cwhub.SCENARIOS, args, toComplete)
 			return compInstalledItems(cwhub.SCENARIOS, args, toComplete)
 		},
 		},
-		DisableAutoGenTag: true,
-		Run: func(cmd *cobra.Command, args []string) {
-			InspectItem(args[0], cwhub.SCENARIOS)
-		},
+		RunE: runScenariosInspect,
 	}
 	}
-	cmdScenariosInspect.PersistentFlags().StringVarP(&prometheusURL, "url", "u", "", "Prometheus url")
+
+	flags := cmdScenariosInspect.Flags()
+	flags.StringP("url", "u", "", "Prometheus url")
 
 
 	return cmdScenariosInspect
 	return cmdScenariosInspect
 }
 }
 
 
+func runScenariosList(cmd *cobra.Command, args []string) error {
+	flags := cmd.Flags()
+
+	all, err := flags.GetBool("all")
+	if err != nil {
+		return err
+	}
+
+	// XXX: will happily ignore missing scenarios
+	ListItems(color.Output, []string{cwhub.SCENARIOS}, args, false, true, all)
+
+	return nil
+}
+
 func NewCmdScenariosList() *cobra.Command {
 func NewCmdScenariosList() *cobra.Command {
-	var cmdScenariosList = &cobra.Command{
+	cmdScenariosList := &cobra.Command{
 		Use:   "list [config]",
 		Use:   "list [config]",
 		Short: "List all scenario(s) or given one",
 		Short: "List all scenario(s) or given one",
 		Long:  `List all scenario(s) or given one`,
 		Long:  `List all scenario(s) or given one`,
 		Example: `cscli scenarios list
 		Example: `cscli scenarios list
 cscli scenarios list crowdsecurity/xxx`,
 cscli scenarios list crowdsecurity/xxx`,
 		DisableAutoGenTag: true,
 		DisableAutoGenTag: true,
-		Run: func(cmd *cobra.Command, args []string) {
-			ListItems(color.Output, []string{cwhub.SCENARIOS}, args, false, true, all)
-		},
+		RunE:              runScenariosList,
 	}
 	}
-	cmdScenariosList.PersistentFlags().BoolVarP(&all, "all", "a", false, "List disabled items as well")
+
+	flags := cmdScenariosList.Flags()
+	flags.BoolP("all", "a", false, "List disabled items as well")
 
 
 	return cmdScenariosList
 	return cmdScenariosList
 }
 }

+ 1 - 1
cmd/crowdsec-cli/support.go

@@ -135,7 +135,7 @@ func collectOSInfo() ([]byte, error) {
 func collectHubItems(itemType string) []byte {
 func collectHubItems(itemType string) []byte {
 	out := bytes.NewBuffer(nil)
 	out := bytes.NewBuffer(nil)
 	log.Infof("Collecting %s list", itemType)
 	log.Infof("Collecting %s list", itemType)
-	ListItems(out, []string{itemType}, []string{}, false, true, all)
+	ListItems(out, []string{itemType}, []string{}, false, true, false)
 	return out.Bytes()
 	return out.Bytes()
 }
 }
 
 

+ 10 - 9
pkg/cwhub/helpers.go

@@ -103,29 +103,28 @@ func InstallItem(csConfig *csconfig.Config, name string, obtype string, force bo
 	return nil
 	return nil
 }
 }
 
 
-// XXX this must return errors instead of log.Fatal
-func RemoveMany(csConfig *csconfig.Config, itemType string, name string, all bool, purge bool, forceAction bool) {
+func RemoveMany(csConfig *csconfig.Config, itemType string, name string, all bool, purge bool, forceAction bool) error {
 	if name != "" {
 	if name != "" {
 		item := GetItem(itemType, name)
 		item := GetItem(itemType, name)
 		if item == nil {
 		if item == nil {
-			log.Fatalf("unable to retrieve: %s", name)
+			return fmt.Errorf("unable to retrieve: %s", name)
 		}
 		}
 
 
 		err := DisableItem(csConfig.Hub, item, purge, forceAction)
 		err := DisableItem(csConfig.Hub, item, purge, forceAction)
 
 
 		if err != nil {
 		if err != nil {
-			log.Fatalf("unable to disable %s : %v", item.Name, err)
+			return fmt.Errorf("unable to disable %s: %w", item.Name, err)
 		}
 		}
 
 
 		if err = AddItem(itemType, *item); err != nil {
 		if err = AddItem(itemType, *item); err != nil {
-			log.Fatalf("unable to add %s: %v", item.Name, err)
+			return fmt.Errorf("unable to add %s: %w", item.Name, err)
 		}
 		}
 
 
-		return
+		return nil
 	}
 	}
 
 
 	if !all {
 	if !all {
-		log.Fatal("removing item: no item specified")
+		return fmt.Errorf("removing item: no item specified")
 	}
 	}
 
 
 	disabled := 0
 	disabled := 0
@@ -138,16 +137,18 @@ func RemoveMany(csConfig *csconfig.Config, itemType string, name string, all boo
 
 
 		err := DisableItem(csConfig.Hub, &v, purge, forceAction)
 		err := DisableItem(csConfig.Hub, &v, purge, forceAction)
 		if err != nil {
 		if err != nil {
-			log.Fatalf("unable to disable %s : %v", v.Name, err)
+			return fmt.Errorf("unable to disable %s: %w", v.Name, err)
 		}
 		}
 
 
 		if err := AddItem(itemType, v); err != nil {
 		if err := AddItem(itemType, v); err != nil {
-			log.Fatalf("unable to add %s: %v", v.Name, err)
+			return fmt.Errorf("unable to add %s: %w", v.Name, err)
 		}
 		}
 		disabled++
 		disabled++
 	}
 	}
 
 
 	log.Infof("Disabled %d items", disabled)
 	log.Infof("Disabled %d items", disabled)
+
+	return nil
 }
 }
 
 
 func UpgradeConfig(csConfig *csconfig.Config, itemType string, name string, force bool) {
 func UpgradeConfig(csConfig *csconfig.Config, itemType string, name string, force bool) {

+ 6 - 2
pkg/cwhub/helpers_test.go

@@ -74,7 +74,9 @@ func TestUpgradeConfigInDisabledScenarioShouldNotBeInstalled(t *testing.T) {
 	require.True(t, hubIdx[SCENARIOS]["crowdsecurity/foobar_scenario"].Installed)
 	require.True(t, hubIdx[SCENARIOS]["crowdsecurity/foobar_scenario"].Installed)
 	assertCollectionDepsInstalled(t, "crowdsecurity/test_collection")
 	assertCollectionDepsInstalled(t, "crowdsecurity/test_collection")
 
 
-	RemoveMany(cfg, SCENARIOS, "crowdsecurity/foobar_scenario", false, false, false)
+	err := RemoveMany(cfg, SCENARIOS, "crowdsecurity/foobar_scenario", false, false, false)
+	require.NoError(t, err)
+
 	getHubIdxOrFail(t)
 	getHubIdxOrFail(t)
 	// scenario referenced by collection  was deleted hence, collection should be tainted
 	// scenario referenced by collection  was deleted hence, collection should be tainted
 	require.False(t, hubIdx[SCENARIOS]["crowdsecurity/foobar_scenario"].Installed)
 	require.False(t, hubIdx[SCENARIOS]["crowdsecurity/foobar_scenario"].Installed)
@@ -122,7 +124,9 @@ func TestUpgradeConfigNewScenarioIsInstalledWhenReferencedScenarioIsDisabled(t *
 	require.True(t, hubIdx[SCENARIOS]["crowdsecurity/foobar_scenario"].Installed)
 	require.True(t, hubIdx[SCENARIOS]["crowdsecurity/foobar_scenario"].Installed)
 	assertCollectionDepsInstalled(t, "crowdsecurity/test_collection")
 	assertCollectionDepsInstalled(t, "crowdsecurity/test_collection")
 
 
-	RemoveMany(cfg, SCENARIOS, "crowdsecurity/foobar_scenario", false, false, false)
+	err := RemoveMany(cfg, SCENARIOS, "crowdsecurity/foobar_scenario", false, false, false)
+	require.NoError(t, err)
+
 	getHubIdxOrFail(t)
 	getHubIdxOrFail(t)
 	// scenario referenced by collection  was deleted hence, collection should be tainted
 	// scenario referenced by collection  was deleted hence, collection should be tainted
 	require.False(t, hubIdx[SCENARIOS]["crowdsecurity/foobar_scenario"].Installed)
 	require.False(t, hubIdx[SCENARIOS]["crowdsecurity/foobar_scenario"].Installed)

+ 3 - 3
pkg/cwhub/loader.go

@@ -98,7 +98,7 @@ func (w Walker) getItemInfo(path string) (itemFileInfo, bool, error) {
 		//.../hub/scenarios/crowdsec/ssh_bf.yaml
 		//.../hub/scenarios/crowdsec/ssh_bf.yaml
 		//.../hub/profiles/crowdsec/linux.yaml
 		//.../hub/profiles/crowdsec/linux.yaml
 		if len(subs) < 4 {
 		if len(subs) < 4 {
-			log.Fatalf("path is too short : %s (%d)", path, len(subs))
+			return itemFileInfo{}, false, fmt.Errorf("path is too short : %s (%d)", path, len(subs))
 		}
 		}
 
 
 		ret.fname = subs[len(subs)-1]
 		ret.fname = subs[len(subs)-1]
@@ -108,7 +108,7 @@ func (w Walker) getItemInfo(path string) (itemFileInfo, bool, error) {
 	} else if strings.HasPrefix(path, w.installdir) { // we're in install /etc/crowdsec/<type>/...
 	} else if strings.HasPrefix(path, w.installdir) { // we're in install /etc/crowdsec/<type>/...
 		log.Tracef("in install dir")
 		log.Tracef("in install dir")
 		if len(subs) < 3 {
 		if len(subs) < 3 {
-			log.Fatalf("path is too short : %s (%d)", path, len(subs))
+			return itemFileInfo{}, false, fmt.Errorf("path is too short: %s (%d)", path, len(subs))
 		}
 		}
 		///.../config/parser/stage/file.yaml
 		///.../config/parser/stage/file.yaml
 		///.../config/postoverflow/stage/file.yaml
 		///.../config/postoverflow/stage/file.yaml
@@ -352,7 +352,7 @@ func CollecDepsCheck(v *Item) error {
 		for _, subName := range itemSlice {
 		for _, subName := range itemSlice {
 			subItem, ok := hubIdx[sliceType][subName]
 			subItem, ok := hubIdx[sliceType][subName]
 			if !ok {
 			if !ok {
-				log.Fatalf("Referred %s %s in collection %s doesn't exist.", sliceType, subName, v.Name)
+				return fmt.Errorf("referred %s %s in collection %s doesn't exist", sliceType, subName, v.Name)
 			}
 			}
 
 
 			log.Tracef("check %s installed:%t", subItem.Name, subItem.Installed)
 			log.Tracef("check %s installed:%t", subItem.Name, subItem.Installed)