From c10aad79d97706f3654f37e0427f6f666c181c6c Mon Sep 17 00:00:00 2001 From: mmetc <92726601+mmetc@users.noreply.github.com> Date: Mon, 11 Dec 2023 10:32:54 +0100 Subject: [PATCH] cscli refact / encapsulate methods for capi, hubtest, dashboard, alerts, decisions, simulation (#2650) --- cmd/crowdsec-cli/alerts.go | 106 +++---- cmd/crowdsec-cli/capi.go | 44 +-- cmd/crowdsec-cli/dashboard.go | 77 ++--- cmd/crowdsec-cli/dashboard_unsupported.go | 12 +- cmd/crowdsec-cli/decisions.go | 105 +++---- cmd/crowdsec-cli/decisions_import.go | 14 +- cmd/crowdsec-cli/hubappsec.go | 8 +- cmd/crowdsec-cli/hubcollection.go | 4 +- cmd/crowdsec-cli/hubcontext.go | 4 +- cmd/crowdsec-cli/hubparser.go | 4 +- cmd/crowdsec-cli/hubpostoverflow.go | 4 +- cmd/crowdsec-cli/hubscenario.go | 4 +- cmd/crowdsec-cli/hubtest.go | 112 ++++---- cmd/crowdsec-cli/itemcli.go | 24 +- cmd/crowdsec-cli/main.go | 26 +- cmd/crowdsec-cli/simulation.go | 329 +++++++++++----------- 16 files changed, 462 insertions(+), 415 deletions(-) diff --git a/cmd/crowdsec-cli/alerts.go b/cmd/crowdsec-cli/alerts.go index 8cee46ba3..a3736abd1 100644 --- a/cmd/crowdsec-cli/alerts.go +++ b/cmd/crowdsec-cli/alerts.go @@ -21,12 +21,11 @@ import ( "github.com/crowdsecurity/go-cs-lib/version" + "github.com/crowdsecurity/crowdsec/cmd/crowdsec-cli/require" "github.com/crowdsecurity/crowdsec/pkg/apiclient" "github.com/crowdsecurity/crowdsec/pkg/database" "github.com/crowdsecurity/crowdsec/pkg/models" "github.com/crowdsecurity/crowdsec/pkg/types" - - "github.com/crowdsecurity/crowdsec/cmd/crowdsec-cli/require" ) func DecisionsFromAlert(alert *models.Alert) string { @@ -208,8 +207,14 @@ func DisplayOneAlert(alert *models.Alert, withDetail bool) error { return nil } -func NewAlertsCmd() *cobra.Command { - var cmdAlerts = &cobra.Command{ +type cliAlerts struct{} + +func NewCLIAlerts() *cliAlerts { + return &cliAlerts{} +} + +func (cli cliAlerts) NewCommand() *cobra.Command { + cmd := &cobra.Command{ Use: "alerts [action]", Short: "Manage alerts", Args: cobra.MinimumNArgs(1), @@ -239,15 +244,15 @@ func NewAlertsCmd() *cobra.Command { }, } - cmdAlerts.AddCommand(NewAlertsListCmd()) - cmdAlerts.AddCommand(NewAlertsInspectCmd()) - cmdAlerts.AddCommand(NewAlertsFlushCmd()) - cmdAlerts.AddCommand(NewAlertsDeleteCmd()) + cmd.AddCommand(cli.NewListCmd()) + cmd.AddCommand(cli.NewInspectCmd()) + cmd.AddCommand(cli.NewFlushCmd()) + cmd.AddCommand(cli.NewDeleteCmd()) - return cmdAlerts + return cmd } -func NewAlertsListCmd() *cobra.Command { +func (cli cliAlerts) NewListCmd() *cobra.Command { var alertListFilter = apiclient.AlertsListOpts{ ScopeEquals: new(string), ValueEquals: new(string), @@ -260,10 +265,11 @@ func NewAlertsListCmd() *cobra.Command { IncludeCAPI: new(bool), OriginEquals: new(string), } - var limit = new(int) + limit := new(int) contained := new(bool) var printMachine bool - var cmdAlertsList = &cobra.Command{ + + cmd := &cobra.Command{ Use: "list [filters]", Short: "List alerts", Example: `cscli alerts list @@ -353,25 +359,25 @@ cscli alerts list --type ban`, return nil }, } - cmdAlertsList.Flags().SortFlags = false - cmdAlertsList.Flags().BoolVarP(alertListFilter.IncludeCAPI, "all", "a", false, "Include decisions from Central API") - cmdAlertsList.Flags().StringVar(alertListFilter.Until, "until", "", "restrict to alerts older than until (ie. 4h, 30d)") - cmdAlertsList.Flags().StringVar(alertListFilter.Since, "since", "", "restrict to alerts newer than since (ie. 4h, 30d)") - cmdAlertsList.Flags().StringVarP(alertListFilter.IPEquals, "ip", "i", "", "restrict to alerts from this source ip (shorthand for --scope ip --value )") - cmdAlertsList.Flags().StringVarP(alertListFilter.ScenarioEquals, "scenario", "s", "", "the scenario (ie. crowdsecurity/ssh-bf)") - cmdAlertsList.Flags().StringVarP(alertListFilter.RangeEquals, "range", "r", "", "restrict to alerts from this range (shorthand for --scope range --value )") - cmdAlertsList.Flags().StringVar(alertListFilter.TypeEquals, "type", "", "restrict to alerts with given decision type (ie. ban, captcha)") - cmdAlertsList.Flags().StringVar(alertListFilter.ScopeEquals, "scope", "", "restrict to alerts of this scope (ie. ip,range)") - cmdAlertsList.Flags().StringVarP(alertListFilter.ValueEquals, "value", "v", "", "the value to match for in the specified scope") - cmdAlertsList.Flags().StringVar(alertListFilter.OriginEquals, "origin", "", fmt.Sprintf("the value to match for the specified origin (%s ...)", strings.Join(types.GetOrigins(), ","))) - cmdAlertsList.Flags().BoolVar(contained, "contained", false, "query decisions contained by range") - cmdAlertsList.Flags().BoolVarP(&printMachine, "machine", "m", false, "print machines that sent alerts") - cmdAlertsList.Flags().IntVarP(limit, "limit", "l", 50, "limit size of alerts list table (0 to view all alerts)") + cmd.Flags().SortFlags = false + cmd.Flags().BoolVarP(alertListFilter.IncludeCAPI, "all", "a", false, "Include decisions from Central API") + cmd.Flags().StringVar(alertListFilter.Until, "until", "", "restrict to alerts older than until (ie. 4h, 30d)") + cmd.Flags().StringVar(alertListFilter.Since, "since", "", "restrict to alerts newer than since (ie. 4h, 30d)") + cmd.Flags().StringVarP(alertListFilter.IPEquals, "ip", "i", "", "restrict to alerts from this source ip (shorthand for --scope ip --value )") + cmd.Flags().StringVarP(alertListFilter.ScenarioEquals, "scenario", "s", "", "the scenario (ie. crowdsecurity/ssh-bf)") + cmd.Flags().StringVarP(alertListFilter.RangeEquals, "range", "r", "", "restrict to alerts from this range (shorthand for --scope range --value )") + cmd.Flags().StringVar(alertListFilter.TypeEquals, "type", "", "restrict to alerts with given decision type (ie. ban, captcha)") + cmd.Flags().StringVar(alertListFilter.ScopeEquals, "scope", "", "restrict to alerts of this scope (ie. ip,range)") + cmd.Flags().StringVarP(alertListFilter.ValueEquals, "value", "v", "", "the value to match for in the specified scope") + cmd.Flags().StringVar(alertListFilter.OriginEquals, "origin", "", fmt.Sprintf("the value to match for the specified origin (%s ...)", strings.Join(types.GetOrigins(), ","))) + cmd.Flags().BoolVar(contained, "contained", false, "query decisions contained by range") + cmd.Flags().BoolVarP(&printMachine, "machine", "m", false, "print machines that sent alerts") + cmd.Flags().IntVarP(limit, "limit", "l", 50, "limit size of alerts list table (0 to view all alerts)") - return cmdAlertsList + return cmd } -func NewAlertsDeleteCmd() *cobra.Command { +func (cli cliAlerts) NewDeleteCmd() *cobra.Command { var ActiveDecision *bool var AlertDeleteAll bool var delAlertByID string @@ -383,7 +389,7 @@ func NewAlertsDeleteCmd() *cobra.Command { IPEquals: new(string), RangeEquals: new(string), } - var cmdAlertsDelete = &cobra.Command{ + cmd := &cobra.Command{ Use: "delete [filters] [--all]", Short: `Delete alerts /!\ This command can be use only on the same machine than the local API.`, @@ -461,21 +467,21 @@ cscli alerts delete -s crowdsecurity/ssh-bf"`, return nil }, } - cmdAlertsDelete.Flags().SortFlags = false - cmdAlertsDelete.Flags().StringVar(alertDeleteFilter.ScopeEquals, "scope", "", "the scope (ie. ip,range)") - cmdAlertsDelete.Flags().StringVarP(alertDeleteFilter.ValueEquals, "value", "v", "", "the value to match for in the specified scope") - cmdAlertsDelete.Flags().StringVarP(alertDeleteFilter.ScenarioEquals, "scenario", "s", "", "the scenario (ie. crowdsecurity/ssh-bf)") - cmdAlertsDelete.Flags().StringVarP(alertDeleteFilter.IPEquals, "ip", "i", "", "Source ip (shorthand for --scope ip --value )") - cmdAlertsDelete.Flags().StringVarP(alertDeleteFilter.RangeEquals, "range", "r", "", "Range source ip (shorthand for --scope range --value )") - cmdAlertsDelete.Flags().StringVar(&delAlertByID, "id", "", "alert ID") - cmdAlertsDelete.Flags().BoolVarP(&AlertDeleteAll, "all", "a", false, "delete all alerts") - cmdAlertsDelete.Flags().BoolVar(contained, "contained", false, "query decisions contained by range") - return cmdAlertsDelete + cmd.Flags().SortFlags = false + cmd.Flags().StringVar(alertDeleteFilter.ScopeEquals, "scope", "", "the scope (ie. ip,range)") + cmd.Flags().StringVarP(alertDeleteFilter.ValueEquals, "value", "v", "", "the value to match for in the specified scope") + cmd.Flags().StringVarP(alertDeleteFilter.ScenarioEquals, "scenario", "s", "", "the scenario (ie. crowdsecurity/ssh-bf)") + cmd.Flags().StringVarP(alertDeleteFilter.IPEquals, "ip", "i", "", "Source ip (shorthand for --scope ip --value )") + cmd.Flags().StringVarP(alertDeleteFilter.RangeEquals, "range", "r", "", "Range source ip (shorthand for --scope range --value )") + cmd.Flags().StringVar(&delAlertByID, "id", "", "alert ID") + cmd.Flags().BoolVarP(&AlertDeleteAll, "all", "a", false, "delete all alerts") + cmd.Flags().BoolVar(contained, "contained", false, "query decisions contained by range") + return cmd } -func NewAlertsInspectCmd() *cobra.Command { +func (cli cliAlerts) NewInspectCmd() *cobra.Command { var details bool - var cmdAlertsInspect = &cobra.Command{ + cmd := &cobra.Command{ Use: `inspect "alert_id"`, Short: `Show info about an alert`, Example: `cscli alerts inspect 123`, @@ -517,16 +523,16 @@ func NewAlertsInspectCmd() *cobra.Command { return nil }, } - cmdAlertsInspect.Flags().SortFlags = false - cmdAlertsInspect.Flags().BoolVarP(&details, "details", "d", false, "show alerts with events") + cmd.Flags().SortFlags = false + cmd.Flags().BoolVarP(&details, "details", "d", false, "show alerts with events") - return cmdAlertsInspect + return cmd } -func NewAlertsFlushCmd() *cobra.Command { +func (cli cliAlerts) NewFlushCmd() *cobra.Command { var maxItems int var maxAge string - var cmdAlertsFlush = &cobra.Command{ + cmd := &cobra.Command{ Use: `flush`, Short: `Flush alerts /!\ This command can be used only on the same machine than the local API`, @@ -552,9 +558,9 @@ func NewAlertsFlushCmd() *cobra.Command { }, } - cmdAlertsFlush.Flags().SortFlags = false - cmdAlertsFlush.Flags().IntVar(&maxItems, "max-items", 5000, "Maximum number of alert items to keep in the database") - cmdAlertsFlush.Flags().StringVar(&maxAge, "max-age", "7d", "Maximum age of alert items to keep in the database") + cmd.Flags().SortFlags = false + cmd.Flags().IntVar(&maxItems, "max-items", 5000, "Maximum number of alert items to keep in the database") + cmd.Flags().StringVar(&maxAge, "max-age", "7d", "Maximum age of alert items to keep in the database") - return cmdAlertsFlush + return cmd } diff --git a/cmd/crowdsec-cli/capi.go b/cmd/crowdsec-cli/capi.go index 8a0ca6959..445b69f57 100644 --- a/cmd/crowdsec-cli/capi.go +++ b/cmd/crowdsec-cli/capi.go @@ -13,20 +13,27 @@ import ( "github.com/crowdsecurity/go-cs-lib/version" + "github.com/crowdsecurity/crowdsec/cmd/crowdsec-cli/require" "github.com/crowdsecurity/crowdsec/pkg/apiclient" "github.com/crowdsecurity/crowdsec/pkg/csconfig" "github.com/crowdsecurity/crowdsec/pkg/cwhub" "github.com/crowdsecurity/crowdsec/pkg/models" "github.com/crowdsecurity/crowdsec/pkg/types" - - "github.com/crowdsecurity/crowdsec/cmd/crowdsec-cli/require" ) -const CAPIBaseURL string = "https://api.crowdsec.net/" -const CAPIURLPrefix = "v3" +const ( + CAPIBaseURL = "https://api.crowdsec.net/" + CAPIURLPrefix = "v3" +) -func NewCapiCmd() *cobra.Command { - var cmdCapi = &cobra.Command{ +type cliCapi struct{} + +func NewCLICapi() *cliCapi { + return &cliCapi{} +} + +func (cli cliCapi) NewCommand() *cobra.Command { + var cmd = &cobra.Command{ Use: "capi [action]", Short: "Manage interaction with Central API (CAPI)", Args: cobra.MinimumNArgs(1), @@ -44,17 +51,17 @@ func NewCapiCmd() *cobra.Command { }, } - cmdCapi.AddCommand(NewCapiRegisterCmd()) - cmdCapi.AddCommand(NewCapiStatusCmd()) + cmd.AddCommand(cli.NewRegisterCmd()) + cmd.AddCommand(cli.NewStatusCmd()) - return cmdCapi + return cmd } -func NewCapiRegisterCmd() *cobra.Command { +func (cli cliCapi) NewRegisterCmd() *cobra.Command { var capiUserPrefix string var outputFile string - var cmdCapiRegister = &cobra.Command{ + var cmd = &cobra.Command{ Use: "register", Short: "Register to Central API (CAPI)", Args: cobra.MinimumNArgs(0), @@ -116,17 +123,18 @@ func NewCapiRegisterCmd() *cobra.Command { return nil }, } - cmdCapiRegister.Flags().StringVarP(&outputFile, "file", "f", "", "output file destination") - cmdCapiRegister.Flags().StringVar(&capiUserPrefix, "schmilblick", "", "set a schmilblick (use in tests only)") - if err := cmdCapiRegister.Flags().MarkHidden("schmilblick"); err != nil { + + cmd.Flags().StringVarP(&outputFile, "file", "f", "", "output file destination") + cmd.Flags().StringVar(&capiUserPrefix, "schmilblick", "", "set a schmilblick (use in tests only)") + if err := cmd.Flags().MarkHidden("schmilblick"); err != nil { log.Fatalf("failed to hide flag: %s", err) } - return cmdCapiRegister + return cmd } -func NewCapiStatusCmd() *cobra.Command { - var cmdCapiStatus = &cobra.Command{ +func (cli cliCapi) NewStatusCmd() *cobra.Command { + var cmd = &cobra.Command{ Use: "status", Short: "Check status with the Central API (CAPI)", Args: cobra.MinimumNArgs(0), @@ -185,5 +193,5 @@ func NewCapiStatusCmd() *cobra.Command { }, } - return cmdCapiStatus + return cmd } diff --git a/cmd/crowdsec-cli/dashboard.go b/cmd/crowdsec-cli/dashboard.go index a2d6c229a..bb7596741 100644 --- a/cmd/crowdsec-cli/dashboard.go +++ b/cmd/crowdsec-cli/dashboard.go @@ -43,9 +43,15 @@ var ( // information needed to set up a random password on user's behalf ) -func NewDashboardCmd() *cobra.Command { +type cliDashboard struct{} + +func NewCLIDashboard() *cliDashboard { + return &cliDashboard{} +} + +func (cli cliDashboard) NewCommand() *cobra.Command { /* ---- UPDATE COMMAND */ - var cmdDashboard = &cobra.Command{ + cmd := &cobra.Command{ Use: "dashboard [command]", Short: "Manage your metabase dashboard container [requires local API]", Long: `Install/Start/Stop/Remove a metabase container exposing dashboard and metrics. @@ -93,19 +99,19 @@ cscli dashboard remove }, } - cmdDashboard.AddCommand(NewDashboardSetupCmd()) - cmdDashboard.AddCommand(NewDashboardStartCmd()) - cmdDashboard.AddCommand(NewDashboardStopCmd()) - cmdDashboard.AddCommand(NewDashboardShowPasswordCmd()) - cmdDashboard.AddCommand(NewDashboardRemoveCmd()) + cmd.AddCommand(cli.NewSetupCmd()) + cmd.AddCommand(cli.NewStartCmd()) + cmd.AddCommand(cli.NewStopCmd()) + cmd.AddCommand(cli.NewShowPasswordCmd()) + cmd.AddCommand(cli.NewRemoveCmd()) - return cmdDashboard + return cmd } -func NewDashboardSetupCmd() *cobra.Command { +func (cli cliDashboard) NewSetupCmd() *cobra.Command { var force bool - var cmdDashSetup = &cobra.Command{ + cmd := &cobra.Command{ Use: "setup", Short: "Setup a metabase container.", Long: `Perform a metabase docker setup, download standard dashboards, create a fresh user and start the container`, @@ -158,20 +164,20 @@ cscli dashboard setup -l 0.0.0.0 -p 443 --password return nil }, } - cmdDashSetup.Flags().BoolVarP(&force, "force", "f", false, "Force setup : override existing files") - cmdDashSetup.Flags().StringVarP(&metabaseDbPath, "dir", "d", "", "Shared directory with metabase container") - cmdDashSetup.Flags().StringVarP(&metabaseListenAddress, "listen", "l", metabaseListenAddress, "Listen address of container") - cmdDashSetup.Flags().StringVar(&metabaseImage, "metabase-image", metabaseImage, "Metabase image to use") - cmdDashSetup.Flags().StringVarP(&metabaseListenPort, "port", "p", metabaseListenPort, "Listen port of container") - cmdDashSetup.Flags().BoolVarP(&forceYes, "yes", "y", false, "force yes") - //cmdDashSetup.Flags().StringVarP(&metabaseUser, "user", "u", "crowdsec@crowdsec.net", "metabase user") - cmdDashSetup.Flags().StringVar(&metabasePassword, "password", "", "metabase password") + cmd.Flags().BoolVarP(&force, "force", "f", false, "Force setup : override existing files") + cmd.Flags().StringVarP(&metabaseDbPath, "dir", "d", "", "Shared directory with metabase container") + cmd.Flags().StringVarP(&metabaseListenAddress, "listen", "l", metabaseListenAddress, "Listen address of container") + cmd.Flags().StringVar(&metabaseImage, "metabase-image", metabaseImage, "Metabase image to use") + cmd.Flags().StringVarP(&metabaseListenPort, "port", "p", metabaseListenPort, "Listen port of container") + cmd.Flags().BoolVarP(&forceYes, "yes", "y", false, "force yes") + //cmd.Flags().StringVarP(&metabaseUser, "user", "u", "crowdsec@crowdsec.net", "metabase user") + cmd.Flags().StringVar(&metabasePassword, "password", "", "metabase password") - return cmdDashSetup + return cmd } -func NewDashboardStartCmd() *cobra.Command { - var cmdDashStart = &cobra.Command{ +func (cli cliDashboard) NewStartCmd() *cobra.Command { + cmd := &cobra.Command{ Use: "start", Short: "Start the metabase container.", Long: `Stats the metabase container using docker.`, @@ -194,12 +200,12 @@ func NewDashboardStartCmd() *cobra.Command { return nil }, } - cmdDashStart.Flags().BoolVarP(&forceYes, "yes", "y", false, "force yes") - return cmdDashStart + cmd.Flags().BoolVarP(&forceYes, "yes", "y", false, "force yes") + return cmd } -func NewDashboardStopCmd() *cobra.Command { - var cmdDashStop = &cobra.Command{ +func (cli cliDashboard) NewStopCmd() *cobra.Command { + cmd := &cobra.Command{ Use: "stop", Short: "Stops the metabase container.", Long: `Stops the metabase container using docker.`, @@ -212,11 +218,11 @@ func NewDashboardStopCmd() *cobra.Command { return nil }, } - return cmdDashStop + return cmd } -func NewDashboardShowPasswordCmd() *cobra.Command { - var cmdDashShowPassword = &cobra.Command{Use: "show-password", +func (cli cliDashboard) NewShowPasswordCmd() *cobra.Command { + cmd := &cobra.Command{Use: "show-password", Short: "displays password of metabase.", Args: cobra.ExactArgs(0), DisableAutoGenTag: true, @@ -229,13 +235,13 @@ func NewDashboardShowPasswordCmd() *cobra.Command { return nil }, } - return cmdDashShowPassword + return cmd } -func NewDashboardRemoveCmd() *cobra.Command { +func (cli cliDashboard) NewRemoveCmd() *cobra.Command { var force bool - var cmdDashRemove = &cobra.Command{ + cmd := &cobra.Command{ Use: "remove", Short: "removes the metabase container.", Long: `removes the metabase container using docker.`, @@ -300,17 +306,19 @@ cscli dashboard remove --force return nil }, } - cmdDashRemove.Flags().BoolVarP(&force, "force", "f", false, "Remove also the metabase image") - cmdDashRemove.Flags().BoolVarP(&forceYes, "yes", "y", false, "force yes") + cmd.Flags().BoolVarP(&force, "force", "f", false, "Remove also the metabase image") + cmd.Flags().BoolVarP(&forceYes, "yes", "y", false, "force yes") - return cmdDashRemove + return cmd } func passwordIsValid(password string) bool { hasDigit := false + for _, j := range password { if unicode.IsDigit(j) { hasDigit = true + break } } @@ -319,7 +327,6 @@ func passwordIsValid(password string) bool { return false } return true - } func checkSystemMemory(forceYes *bool) error { diff --git a/cmd/crowdsec-cli/dashboard_unsupported.go b/cmd/crowdsec-cli/dashboard_unsupported.go index f2325ea07..072ff525b 100644 --- a/cmd/crowdsec-cli/dashboard_unsupported.go +++ b/cmd/crowdsec-cli/dashboard_unsupported.go @@ -9,8 +9,14 @@ import ( "github.com/spf13/cobra" ) -func NewDashboardCmd() *cobra.Command { - var cmdDashboard = &cobra.Command{ +type cliDashboard struct{} + +func NewCLIDashboard() *cliDashboard { + return &cliDashboard{} +} + +func (cli cliDashboard) NewCommand() *cobra.Command { + cmd := &cobra.Command{ Use: "dashboard", DisableAutoGenTag: true, Run: func(cmd *cobra.Command, args []string) { @@ -18,5 +24,5 @@ func NewDashboardCmd() *cobra.Command { }, } - return cmdDashboard + return cmd } diff --git a/cmd/crowdsec-cli/decisions.go b/cmd/crowdsec-cli/decisions.go index 985b4d2d8..05fbf15a5 100644 --- a/cmd/crowdsec-cli/decisions.go +++ b/cmd/crowdsec-cli/decisions.go @@ -102,8 +102,15 @@ func DecisionsToTable(alerts *models.GetAlertsResponse, printMachine bool) error return nil } -func NewDecisionsCmd() *cobra.Command { - var cmdDecisions = &cobra.Command{ + +type cliDecisions struct {} + +func NewCLIDecisions() *cliDecisions { + return &cliDecisions{} +} + +func (cli cliDecisions) NewCommand() *cobra.Command { + cmd := &cobra.Command{ Use: "decisions [action]", Short: "Manage decisions", Long: `Add/List/Delete/Import decisions from LAPI`, @@ -135,15 +142,15 @@ func NewDecisionsCmd() *cobra.Command { }, } - cmdDecisions.AddCommand(NewDecisionsListCmd()) - cmdDecisions.AddCommand(NewDecisionsAddCmd()) - cmdDecisions.AddCommand(NewDecisionsDeleteCmd()) - cmdDecisions.AddCommand(NewDecisionsImportCmd()) + cmd.AddCommand(cli.NewListCmd()) + cmd.AddCommand(cli.NewAddCmd()) + cmd.AddCommand(cli.NewDeleteCmd()) + cmd.AddCommand(cli.NewImportCmd()) - return cmdDecisions + return cmd } -func NewDecisionsListCmd() *cobra.Command { +func (cli cliDecisions) NewListCmd() *cobra.Command { var filter = apiclient.AlertsListOpts{ ValueEquals: new(string), ScopeEquals: new(string), @@ -161,7 +168,7 @@ func NewDecisionsListCmd() *cobra.Command { contained := new(bool) var printMachine bool - var cmdDecisionsList = &cobra.Command{ + cmd := &cobra.Command{ Use: "list [options]", Short: "List decisions from LAPI", Example: `cscli decisions list -i 1.2.3.4 @@ -251,26 +258,26 @@ cscli decisions list -t ban return nil }, } - cmdDecisionsList.Flags().SortFlags = false - cmdDecisionsList.Flags().BoolVarP(filter.IncludeCAPI, "all", "a", false, "Include decisions from Central API") - cmdDecisionsList.Flags().StringVar(filter.Since, "since", "", "restrict to alerts newer than since (ie. 4h, 30d)") - cmdDecisionsList.Flags().StringVar(filter.Until, "until", "", "restrict to alerts older than until (ie. 4h, 30d)") - cmdDecisionsList.Flags().StringVarP(filter.TypeEquals, "type", "t", "", "restrict to this decision type (ie. ban,captcha)") - cmdDecisionsList.Flags().StringVar(filter.ScopeEquals, "scope", "", "restrict to this scope (ie. ip,range,session)") - cmdDecisionsList.Flags().StringVar(filter.OriginEquals, "origin", "", fmt.Sprintf("the value to match for the specified origin (%s ...)", strings.Join(types.GetOrigins(), ","))) - cmdDecisionsList.Flags().StringVarP(filter.ValueEquals, "value", "v", "", "restrict to this value (ie. 1.2.3.4,userName)") - cmdDecisionsList.Flags().StringVarP(filter.ScenarioEquals, "scenario", "s", "", "restrict to this scenario (ie. crowdsecurity/ssh-bf)") - cmdDecisionsList.Flags().StringVarP(filter.IPEquals, "ip", "i", "", "restrict to alerts from this source ip (shorthand for --scope ip --value )") - cmdDecisionsList.Flags().StringVarP(filter.RangeEquals, "range", "r", "", "restrict to alerts from this source range (shorthand for --scope range --value )") - cmdDecisionsList.Flags().IntVarP(filter.Limit, "limit", "l", 100, "number of alerts to get (use 0 to remove the limit)") - cmdDecisionsList.Flags().BoolVar(NoSimu, "no-simu", false, "exclude decisions in simulation mode") - cmdDecisionsList.Flags().BoolVarP(&printMachine, "machine", "m", false, "print machines that triggered decisions") - cmdDecisionsList.Flags().BoolVar(contained, "contained", false, "query decisions contained by range") + cmd.Flags().SortFlags = false + cmd.Flags().BoolVarP(filter.IncludeCAPI, "all", "a", false, "Include decisions from Central API") + cmd.Flags().StringVar(filter.Since, "since", "", "restrict to alerts newer than since (ie. 4h, 30d)") + cmd.Flags().StringVar(filter.Until, "until", "", "restrict to alerts older than until (ie. 4h, 30d)") + cmd.Flags().StringVarP(filter.TypeEquals, "type", "t", "", "restrict to this decision type (ie. ban,captcha)") + cmd.Flags().StringVar(filter.ScopeEquals, "scope", "", "restrict to this scope (ie. ip,range,session)") + cmd.Flags().StringVar(filter.OriginEquals, "origin", "", fmt.Sprintf("the value to match for the specified origin (%s ...)", strings.Join(types.GetOrigins(), ","))) + cmd.Flags().StringVarP(filter.ValueEquals, "value", "v", "", "restrict to this value (ie. 1.2.3.4,userName)") + cmd.Flags().StringVarP(filter.ScenarioEquals, "scenario", "s", "", "restrict to this scenario (ie. crowdsecurity/ssh-bf)") + cmd.Flags().StringVarP(filter.IPEquals, "ip", "i", "", "restrict to alerts from this source ip (shorthand for --scope ip --value )") + cmd.Flags().StringVarP(filter.RangeEquals, "range", "r", "", "restrict to alerts from this source range (shorthand for --scope range --value )") + cmd.Flags().IntVarP(filter.Limit, "limit", "l", 100, "number of alerts to get (use 0 to remove the limit)") + cmd.Flags().BoolVar(NoSimu, "no-simu", false, "exclude decisions in simulation mode") + cmd.Flags().BoolVarP(&printMachine, "machine", "m", false, "print machines that triggered decisions") + cmd.Flags().BoolVar(contained, "contained", false, "query decisions contained by range") - return cmdDecisionsList + return cmd } -func NewDecisionsAddCmd() *cobra.Command { +func (cli cliDecisions) NewAddCmd() *cobra.Command { var ( addIP string addRange string @@ -281,7 +288,7 @@ func NewDecisionsAddCmd() *cobra.Command { addType string ) - var cmdDecisionsAdd = &cobra.Command{ + cmd := &cobra.Command{ Use: "add [options]", Short: "Add decision to LAPI", Example: `cscli decisions add --ip 1.2.3.4 @@ -369,19 +376,19 @@ cscli decisions add --scope username --value foobar }, } - cmdDecisionsAdd.Flags().SortFlags = false - cmdDecisionsAdd.Flags().StringVarP(&addIP, "ip", "i", "", "Source ip (shorthand for --scope ip --value )") - cmdDecisionsAdd.Flags().StringVarP(&addRange, "range", "r", "", "Range source ip (shorthand for --scope range --value )") - cmdDecisionsAdd.Flags().StringVarP(&addDuration, "duration", "d", "4h", "Decision duration (ie. 1h,4h,30m)") - cmdDecisionsAdd.Flags().StringVarP(&addValue, "value", "v", "", "The value (ie. --scope username --value foobar)") - cmdDecisionsAdd.Flags().StringVar(&addScope, "scope", types.Ip, "Decision scope (ie. ip,range,username)") - cmdDecisionsAdd.Flags().StringVarP(&addReason, "reason", "R", "", "Decision reason (ie. scenario-name)") - cmdDecisionsAdd.Flags().StringVarP(&addType, "type", "t", "ban", "Decision type (ie. ban,captcha,throttle)") + cmd.Flags().SortFlags = false + cmd.Flags().StringVarP(&addIP, "ip", "i", "", "Source ip (shorthand for --scope ip --value )") + cmd.Flags().StringVarP(&addRange, "range", "r", "", "Range source ip (shorthand for --scope range --value )") + cmd.Flags().StringVarP(&addDuration, "duration", "d", "4h", "Decision duration (ie. 1h,4h,30m)") + cmd.Flags().StringVarP(&addValue, "value", "v", "", "The value (ie. --scope username --value foobar)") + cmd.Flags().StringVar(&addScope, "scope", types.Ip, "Decision scope (ie. ip,range,username)") + cmd.Flags().StringVarP(&addReason, "reason", "R", "", "Decision reason (ie. scenario-name)") + cmd.Flags().StringVarP(&addType, "type", "t", "ban", "Decision type (ie. ban,captcha,throttle)") - return cmdDecisionsAdd + return cmd } -func NewDecisionsDeleteCmd() *cobra.Command { +func (cli cliDecisions) NewDeleteCmd() *cobra.Command { var delFilter = apiclient.DecisionsDeleteOpts{ ScopeEquals: new(string), ValueEquals: new(string), @@ -395,7 +402,7 @@ func NewDecisionsDeleteCmd() *cobra.Command { var delDecisionAll bool contained := new(bool) - var cmdDecisionsDelete = &cobra.Command{ + cmd := &cobra.Command{ Use: "delete [options]", Short: "Delete decisions", DisableAutoGenTag: true, @@ -472,17 +479,17 @@ cscli decisions delete --type captcha }, } - cmdDecisionsDelete.Flags().SortFlags = false - cmdDecisionsDelete.Flags().StringVarP(delFilter.IPEquals, "ip", "i", "", "Source ip (shorthand for --scope ip --value )") - cmdDecisionsDelete.Flags().StringVarP(delFilter.RangeEquals, "range", "r", "", "Range source ip (shorthand for --scope range --value )") - cmdDecisionsDelete.Flags().StringVarP(delFilter.TypeEquals, "type", "t", "", "the decision type (ie. ban,captcha)") - cmdDecisionsDelete.Flags().StringVarP(delFilter.ValueEquals, "value", "v", "", "the value to match for in the specified scope") - cmdDecisionsDelete.Flags().StringVarP(delFilter.ScenarioEquals, "scenario", "s", "", "the scenario name (ie. crowdsecurity/ssh-bf)") - cmdDecisionsDelete.Flags().StringVar(delFilter.OriginEquals, "origin", "", fmt.Sprintf("the value to match for the specified origin (%s ...)", strings.Join(types.GetOrigins(), ","))) + cmd.Flags().SortFlags = false + cmd.Flags().StringVarP(delFilter.IPEquals, "ip", "i", "", "Source ip (shorthand for --scope ip --value )") + cmd.Flags().StringVarP(delFilter.RangeEquals, "range", "r", "", "Range source ip (shorthand for --scope range --value )") + cmd.Flags().StringVarP(delFilter.TypeEquals, "type", "t", "", "the decision type (ie. ban,captcha)") + cmd.Flags().StringVarP(delFilter.ValueEquals, "value", "v", "", "the value to match for in the specified scope") + cmd.Flags().StringVarP(delFilter.ScenarioEquals, "scenario", "s", "", "the scenario name (ie. crowdsecurity/ssh-bf)") + cmd.Flags().StringVar(delFilter.OriginEquals, "origin", "", fmt.Sprintf("the value to match for the specified origin (%s ...)", strings.Join(types.GetOrigins(), ","))) - cmdDecisionsDelete.Flags().StringVar(&delDecisionId, "id", "", "decision id") - cmdDecisionsDelete.Flags().BoolVar(&delDecisionAll, "all", false, "delete all decisions") - cmdDecisionsDelete.Flags().BoolVar(contained, "contained", false, "query decisions contained by range") + cmd.Flags().StringVar(&delDecisionId, "id", "", "decision id") + cmd.Flags().BoolVar(&delDecisionAll, "all", false, "delete all decisions") + cmd.Flags().BoolVar(contained, "contained", false, "query decisions contained by range") - return cmdDecisionsDelete + return cmd } diff --git a/cmd/crowdsec-cli/decisions_import.go b/cmd/crowdsec-cli/decisions_import.go index 31dbc0ead..6c9b19d28 100644 --- a/cmd/crowdsec-cli/decisions_import.go +++ b/cmd/crowdsec-cli/decisions_import.go @@ -63,7 +63,7 @@ func parseDecisionList(content []byte, format string) ([]decisionRaw, error) { } -func runDecisionsImport(cmd *cobra.Command, args []string) error { +func (cli cliDecisions) runImport(cmd *cobra.Command, args []string) error { flags := cmd.Flags() input, err := flags.GetString("input") @@ -226,8 +226,8 @@ func runDecisionsImport(cmd *cobra.Command, args []string) error { } -func NewDecisionsImportCmd() *cobra.Command { - var cmdDecisionsImport = &cobra.Command{ +func (cli cliDecisions) NewImportCmd() *cobra.Command { + cmd := &cobra.Command{ Use: "import [options]", Short: "Import decisions from a file or pipe", Long: "expected format:\n" + @@ -250,10 +250,10 @@ Raw values, standard input: $ echo "1.2.3.4" | cscli decisions import -i - --format values `, - RunE: runDecisionsImport, + RunE: cli.runImport, } - flags := cmdDecisionsImport.Flags() + flags := cmd.Flags() flags.SortFlags = false flags.StringP("input", "i", "", "Input file") flags.StringP("duration", "d", "4h", "Decision duration: 1h,4h,30m") @@ -263,7 +263,7 @@ $ echo "1.2.3.4" | cscli decisions import -i - --format values flags.Int("batch", 0, "Split import in batches of N decisions") flags.String("format", "", "Input format: 'json', 'csv' or 'values' (each line is a value, no headers)") - cmdDecisionsImport.MarkFlagRequired("input") + cmd.MarkFlagRequired("input") - return cmdDecisionsImport + return cmd } diff --git a/cmd/crowdsec-cli/hubappsec.go b/cmd/crowdsec-cli/hubappsec.go index 1fc8b6c00..7c68d6f13 100644 --- a/cmd/crowdsec-cli/hubappsec.go +++ b/cmd/crowdsec-cli/hubappsec.go @@ -13,8 +13,8 @@ import ( "github.com/crowdsecurity/crowdsec/pkg/cwhub" ) -func NewAppsecConfigCLI() *itemCLI { - return &itemCLI{ +func NewCLIAppsecConfig() *cliItem { + return &cliItem{ name: cwhub.APPSEC_CONFIGS, singular: "appsec-config", oneOrMore: "appsec-config(s)", @@ -46,7 +46,7 @@ cscli appsec-configs list crowdsecurity/vpatch`, } } -func NewAppsecRuleCLI() *itemCLI { +func NewCLIAppsecRule() *cliItem { inspectDetail := func(item *cwhub.Item) error { appsecRule := appsec.AppsecCollectionConfig{} yamlContent, err := os.ReadFile(item.State.LocalPath) @@ -71,7 +71,7 @@ func NewAppsecRuleCLI() *itemCLI { return nil } - return &itemCLI{ + return &cliItem{ name: "appsec-rules", singular: "appsec-rule", oneOrMore: "appsec-rule(s)", diff --git a/cmd/crowdsec-cli/hubcollection.go b/cmd/crowdsec-cli/hubcollection.go index a86947975..dee9a0b9e 100644 --- a/cmd/crowdsec-cli/hubcollection.go +++ b/cmd/crowdsec-cli/hubcollection.go @@ -4,8 +4,8 @@ import ( "github.com/crowdsecurity/crowdsec/pkg/cwhub" ) -func NewCollectionCLI() *itemCLI { - return &itemCLI{ +func NewCLICollection() *cliItem { + return &cliItem{ name: cwhub.COLLECTIONS, singular: "collection", oneOrMore: "collection(s)", diff --git a/cmd/crowdsec-cli/hubcontext.go b/cmd/crowdsec-cli/hubcontext.go index 3fdd3aac5..630dbb2f7 100644 --- a/cmd/crowdsec-cli/hubcontext.go +++ b/cmd/crowdsec-cli/hubcontext.go @@ -4,8 +4,8 @@ import ( "github.com/crowdsecurity/crowdsec/pkg/cwhub" ) -func NewContextCLI() *itemCLI { - return &itemCLI{ +func NewCLIContext() *cliItem { + return &cliItem{ name: cwhub.CONTEXTS, singular: "context", oneOrMore: "context(s)", diff --git a/cmd/crowdsec-cli/hubparser.go b/cmd/crowdsec-cli/hubparser.go index d2af0b6fb..0b224c8a7 100644 --- a/cmd/crowdsec-cli/hubparser.go +++ b/cmd/crowdsec-cli/hubparser.go @@ -4,8 +4,8 @@ import ( "github.com/crowdsecurity/crowdsec/pkg/cwhub" ) -func NewParserCLI() *itemCLI { - return &itemCLI{ +func NewCLIParser() *cliItem { + return &cliItem{ name: cwhub.PARSERS, singular: "parser", oneOrMore: "parser(s)", diff --git a/cmd/crowdsec-cli/hubpostoverflow.go b/cmd/crowdsec-cli/hubpostoverflow.go index 326c3fec5..908ccbea0 100644 --- a/cmd/crowdsec-cli/hubpostoverflow.go +++ b/cmd/crowdsec-cli/hubpostoverflow.go @@ -4,8 +4,8 @@ import ( "github.com/crowdsecurity/crowdsec/pkg/cwhub" ) -func NewPostOverflowCLI() *itemCLI { - return &itemCLI{ +func NewCLIPostOverflow() *cliItem { + return &cliItem{ name: cwhub.POSTOVERFLOWS, singular: "postoverflow", oneOrMore: "postoverflow(s)", diff --git a/cmd/crowdsec-cli/hubscenario.go b/cmd/crowdsec-cli/hubscenario.go index 14b246f0f..1de2182bf 100644 --- a/cmd/crowdsec-cli/hubscenario.go +++ b/cmd/crowdsec-cli/hubscenario.go @@ -4,8 +4,8 @@ import ( "github.com/crowdsecurity/crowdsec/pkg/cwhub" ) -func NewScenarioCLI() *itemCLI { - return &itemCLI{ +func NewCLIScenario() *cliItem { + return &cliItem{ name: cwhub.SCENARIOS, singular: "scenario", oneOrMore: "scenario(s)", diff --git a/cmd/crowdsec-cli/hubtest.go b/cmd/crowdsec-cli/hubtest.go index 295a8f89d..d448c7cd2 100644 --- a/cmd/crowdsec-cli/hubtest.go +++ b/cmd/crowdsec-cli/hubtest.go @@ -23,12 +23,18 @@ var HubAppsecTests hubtest.HubTest var hubPtr *hubtest.HubTest var isAppsecTest bool -func NewHubTestCmd() *cobra.Command { +type cliHubTest struct{} + +func NewCLIHubTest() *cliHubTest { + return &cliHubTest{} +} + +func (cli cliHubTest) NewCommand() *cobra.Command { var hubPath string var crowdsecPath string var cscliPath string - var cmdHubTest = &cobra.Command{ + cmd := &cobra.Command{ Use: "hubtest", Short: "Run functional tests on hub configurations", Long: "Run functional tests on hub configurations (parsers, scenarios, collections...)", @@ -54,24 +60,24 @@ func NewHubTestCmd() *cobra.Command { }, } - cmdHubTest.PersistentFlags().StringVar(&hubPath, "hub", ".", "Path to hub folder") - cmdHubTest.PersistentFlags().StringVar(&crowdsecPath, "crowdsec", "crowdsec", "Path to crowdsec") - cmdHubTest.PersistentFlags().StringVar(&cscliPath, "cscli", "cscli", "Path to cscli") - cmdHubTest.PersistentFlags().BoolVar(&isAppsecTest, "appsec", false, "Command relates to appsec tests") + cmd.PersistentFlags().StringVar(&hubPath, "hub", ".", "Path to hub folder") + cmd.PersistentFlags().StringVar(&crowdsecPath, "crowdsec", "crowdsec", "Path to crowdsec") + cmd.PersistentFlags().StringVar(&cscliPath, "cscli", "cscli", "Path to cscli") + cmd.PersistentFlags().BoolVar(&isAppsecTest, "appsec", false, "Command relates to appsec tests") - cmdHubTest.AddCommand(NewHubTestCreateCmd()) - cmdHubTest.AddCommand(NewHubTestRunCmd()) - cmdHubTest.AddCommand(NewHubTestCleanCmd()) - cmdHubTest.AddCommand(NewHubTestInfoCmd()) - cmdHubTest.AddCommand(NewHubTestListCmd()) - cmdHubTest.AddCommand(NewHubTestCoverageCmd()) - cmdHubTest.AddCommand(NewHubTestEvalCmd()) - cmdHubTest.AddCommand(NewHubTestExplainCmd()) + cmd.AddCommand(cli.NewCreateCmd()) + cmd.AddCommand(cli.NewRunCmd()) + cmd.AddCommand(cli.NewCleanCmd()) + cmd.AddCommand(cli.NewInfoCmd()) + cmd.AddCommand(cli.NewListCmd()) + cmd.AddCommand(cli.NewCoverageCmd()) + cmd.AddCommand(cli.NewEvalCmd()) + cmd.AddCommand(cli.NewExplainCmd()) - return cmdHubTest + return cmd } -func NewHubTestCreateCmd() *cobra.Command { +func (cli cliHubTest) NewCreateCmd() *cobra.Command { parsers := []string{} postoverflows := []string{} scenarios := []string{} @@ -79,7 +85,7 @@ func NewHubTestCreateCmd() *cobra.Command { var labels map[string]string var logType string - var cmdHubTestCreate = &cobra.Command{ + cmd := &cobra.Command{ Use: "create", Short: "create [test_name]", Example: `cscli hubtest create my-awesome-test --type syslog @@ -191,21 +197,21 @@ cscli hubtest create my-scenario-test --parsers crowdsecurity/nginx --scenarios }, } - cmdHubTestCreate.PersistentFlags().StringVarP(&logType, "type", "t", "", "Log type of the test") - cmdHubTestCreate.Flags().StringSliceVarP(&parsers, "parsers", "p", parsers, "Parsers to add to test") - cmdHubTestCreate.Flags().StringSliceVar(&postoverflows, "postoverflows", postoverflows, "Postoverflows to add to test") - cmdHubTestCreate.Flags().StringSliceVarP(&scenarios, "scenarios", "s", scenarios, "Scenarios to add to test") - cmdHubTestCreate.PersistentFlags().BoolVar(&ignoreParsers, "ignore-parsers", false, "Don't run test on parsers") + cmd.PersistentFlags().StringVarP(&logType, "type", "t", "", "Log type of the test") + cmd.Flags().StringSliceVarP(&parsers, "parsers", "p", parsers, "Parsers to add to test") + cmd.Flags().StringSliceVar(&postoverflows, "postoverflows", postoverflows, "Postoverflows to add to test") + cmd.Flags().StringSliceVarP(&scenarios, "scenarios", "s", scenarios, "Scenarios to add to test") + cmd.PersistentFlags().BoolVar(&ignoreParsers, "ignore-parsers", false, "Don't run test on parsers") - return cmdHubTestCreate + return cmd } -func NewHubTestRunCmd() *cobra.Command { +func (cli cliHubTest) NewRunCmd() *cobra.Command { var noClean bool var runAll bool var forceClean bool - var cmdHubTestRun = &cobra.Command{ + var cmd = &cobra.Command{ Use: "run", Short: "run [test_name]", DisableAutoGenTag: true, @@ -353,15 +359,15 @@ func NewHubTestRunCmd() *cobra.Command { }, } - cmdHubTestRun.Flags().BoolVar(&noClean, "no-clean", false, "Don't clean runtime environment if test succeed") - cmdHubTestRun.Flags().BoolVar(&forceClean, "clean", false, "Clean runtime environment if test fail") - cmdHubTestRun.Flags().BoolVar(&runAll, "all", false, "Run all tests") + cmd.Flags().BoolVar(&noClean, "no-clean", false, "Don't clean runtime environment if test succeed") + cmd.Flags().BoolVar(&forceClean, "clean", false, "Clean runtime environment if test fail") + cmd.Flags().BoolVar(&runAll, "all", false, "Run all tests") - return cmdHubTestRun + return cmd } -func NewHubTestCleanCmd() *cobra.Command { - var cmdHubTestClean = &cobra.Command{ +func (cli cliHubTest) NewCleanCmd() *cobra.Command { + var cmd = &cobra.Command{ Use: "clean", Short: "clean [test_name]", Args: cobra.MinimumNArgs(1), @@ -381,17 +387,16 @@ func NewHubTestCleanCmd() *cobra.Command { }, } - return cmdHubTestClean + return cmd } -func NewHubTestInfoCmd() *cobra.Command { - var cmdHubTestInfo = &cobra.Command{ +func (cli cliHubTest) NewInfoCmd() *cobra.Command { + cmd := &cobra.Command{ Use: "info", Short: "info [test_name]", Args: cobra.MinimumNArgs(1), DisableAutoGenTag: true, RunE: func(cmd *cobra.Command, args []string) error { - for _, testName := range args { test, err := hubPtr.LoadTestItem(testName) if err != nil { @@ -415,11 +420,11 @@ func NewHubTestInfoCmd() *cobra.Command { }, } - return cmdHubTestInfo + return cmd } -func NewHubTestListCmd() *cobra.Command { - var cmdHubTestList = &cobra.Command{ +func (cli cliHubTest) NewListCmd() *cobra.Command { + cmd := &cobra.Command{ Use: "list", Short: "list", DisableAutoGenTag: true, @@ -445,16 +450,16 @@ func NewHubTestListCmd() *cobra.Command { }, } - return cmdHubTestList + return cmd } -func NewHubTestCoverageCmd() *cobra.Command { +func (cli cliHubTest) NewCoverageCmd() *cobra.Command { var showParserCov bool var showScenarioCov bool var showOnlyPercent bool var showAppsecCov bool - var cmdHubTestCoverage = &cobra.Command{ + cmd := &cobra.Command{ Use: "coverage", Short: "coverage", DisableAutoGenTag: true, @@ -580,17 +585,18 @@ func NewHubTestCoverageCmd() *cobra.Command { }, } - cmdHubTestCoverage.PersistentFlags().BoolVar(&showOnlyPercent, "percent", false, "Show only percentages of coverage") - cmdHubTestCoverage.PersistentFlags().BoolVar(&showParserCov, "parsers", false, "Show only parsers coverage") - cmdHubTestCoverage.PersistentFlags().BoolVar(&showScenarioCov, "scenarios", false, "Show only scenarios coverage") - cmdHubTestCoverage.PersistentFlags().BoolVar(&showAppsecCov, "appsec", false, "Show only appsec coverage") + cmd.PersistentFlags().BoolVar(&showOnlyPercent, "percent", false, "Show only percentages of coverage") + cmd.PersistentFlags().BoolVar(&showParserCov, "parsers", false, "Show only parsers coverage") + cmd.PersistentFlags().BoolVar(&showScenarioCov, "scenarios", false, "Show only scenarios coverage") + cmd.PersistentFlags().BoolVar(&showAppsecCov, "appsec", false, "Show only appsec coverage") - return cmdHubTestCoverage + return cmd } -func NewHubTestEvalCmd() *cobra.Command { +func (cli cliHubTest) NewEvalCmd() *cobra.Command { var evalExpression string - var cmdHubTestEval = &cobra.Command{ + + cmd := &cobra.Command{ Use: "eval", Short: "eval [test_name]", Args: cobra.ExactArgs(1), @@ -619,13 +625,13 @@ func NewHubTestEvalCmd() *cobra.Command { }, } - cmdHubTestEval.PersistentFlags().StringVarP(&evalExpression, "expr", "e", "", "Expression to eval") + cmd.PersistentFlags().StringVarP(&evalExpression, "expr", "e", "", "Expression to eval") - return cmdHubTestEval + return cmd } -func NewHubTestExplainCmd() *cobra.Command { - var cmdHubTestExplain = &cobra.Command{ +func (cli cliHubTest) NewExplainCmd() *cobra.Command { + cmd := &cobra.Command{ Use: "explain", Short: "explain [test_name]", Args: cobra.ExactArgs(1), @@ -665,5 +671,5 @@ func NewHubTestExplainCmd() *cobra.Command { }, } - return cmdHubTestExplain + return cmd } diff --git a/cmd/crowdsec-cli/itemcli.go b/cmd/crowdsec-cli/itemcli.go index 0870fdeb4..6dfdb5d1f 100644 --- a/cmd/crowdsec-cli/itemcli.go +++ b/cmd/crowdsec-cli/itemcli.go @@ -22,7 +22,7 @@ type cliHelp struct { example string } -type itemCLI struct { +type cliItem struct { name string // plural, as used in the hub index singular string oneOrMore string // parenthetical pluralizaion: "parser(s)" @@ -35,7 +35,7 @@ type itemCLI struct { listHelp cliHelp } -func (it itemCLI) NewCommand() *cobra.Command { +func (it cliItem) NewCommand() *cobra.Command { cmd := &cobra.Command{ Use: coalesce.String(it.help.use, fmt.Sprintf("%s [item]...", it.name)), Short: coalesce.String(it.help.short, fmt.Sprintf("Manage hub %s", it.name)), @@ -55,7 +55,7 @@ func (it itemCLI) NewCommand() *cobra.Command { return cmd } -func (it itemCLI) Install(cmd *cobra.Command, args []string) error { +func (it cliItem) Install(cmd *cobra.Command, args []string) error { flags := cmd.Flags() downloadOnly, err := flags.GetBool("download-only") @@ -103,7 +103,7 @@ func (it itemCLI) Install(cmd *cobra.Command, args []string) error { return nil } -func (it itemCLI) NewInstallCmd() *cobra.Command { +func (it cliItem) NewInstallCmd() *cobra.Command { cmd := &cobra.Command{ Use: coalesce.String(it.installHelp.use, "install [item]..."), Short: coalesce.String(it.installHelp.short, fmt.Sprintf("Install given %s", it.oneOrMore)), @@ -138,7 +138,7 @@ func istalledParentNames(item *cwhub.Item) []string { return ret } -func (it itemCLI) Remove(cmd *cobra.Command, args []string) error { +func (it cliItem) Remove(cmd *cobra.Command, args []string) error { flags := cmd.Flags() purge, err := flags.GetBool("purge") @@ -232,7 +232,7 @@ func (it itemCLI) Remove(cmd *cobra.Command, args []string) error { return nil } -func (it itemCLI) NewRemoveCmd() *cobra.Command { +func (it cliItem) NewRemoveCmd() *cobra.Command { cmd := &cobra.Command{ Use: coalesce.String(it.removeHelp.use, "remove [item]..."), Short: coalesce.String(it.removeHelp.short, fmt.Sprintf("Remove given %s", it.oneOrMore)), @@ -254,7 +254,7 @@ func (it itemCLI) NewRemoveCmd() *cobra.Command { return cmd } -func (it itemCLI) Upgrade(cmd *cobra.Command, args []string) error { +func (it cliItem) Upgrade(cmd *cobra.Command, args []string) error { flags := cmd.Flags() force, err := flags.GetBool("force") @@ -328,7 +328,7 @@ func (it itemCLI) Upgrade(cmd *cobra.Command, args []string) error { return nil } -func (it itemCLI) NewUpgradeCmd() *cobra.Command { +func (it cliItem) NewUpgradeCmd() *cobra.Command { cmd := &cobra.Command{ Use: coalesce.String(it.upgradeHelp.use, "upgrade [item]..."), Short: coalesce.String(it.upgradeHelp.short, fmt.Sprintf("Upgrade given %s", it.oneOrMore)), @@ -348,7 +348,7 @@ func (it itemCLI) NewUpgradeCmd() *cobra.Command { return cmd } -func (it itemCLI) Inspect(cmd *cobra.Command, args []string) error { +func (it cliItem) Inspect(cmd *cobra.Command, args []string) error { flags := cmd.Flags() url, err := flags.GetString("url") @@ -389,7 +389,7 @@ func (it itemCLI) Inspect(cmd *cobra.Command, args []string) error { return nil } -func (it itemCLI) NewInspectCmd() *cobra.Command { +func (it cliItem) NewInspectCmd() *cobra.Command { cmd := &cobra.Command{ Use: coalesce.String(it.inspectHelp.use, "inspect [item]..."), Short: coalesce.String(it.inspectHelp.short, fmt.Sprintf("Inspect given %s", it.oneOrMore)), @@ -410,7 +410,7 @@ func (it itemCLI) NewInspectCmd() *cobra.Command { return cmd } -func (it itemCLI) List(cmd *cobra.Command, args []string) error { +func (it cliItem) List(cmd *cobra.Command, args []string) error { flags := cmd.Flags() all, err := flags.GetBool("all") @@ -437,7 +437,7 @@ func (it itemCLI) List(cmd *cobra.Command, args []string) error { return nil } -func (it itemCLI) NewListCmd() *cobra.Command { +func (it cliItem) NewListCmd() *cobra.Command { cmd := &cobra.Command{ Use: coalesce.String(it.listHelp.use, "list [item... | -a]"), Short: coalesce.String(it.listHelp.short, fmt.Sprintf("List %s", it.oneOrMore)), diff --git a/cmd/crowdsec-cli/main.go b/cmd/crowdsec-cli/main.go index 0a6323fca..a187e432b 100644 --- a/cmd/crowdsec-cli/main.go +++ b/cmd/crowdsec-cli/main.go @@ -228,28 +228,28 @@ It is meant to allow you to manage bans, parsers/scenarios/etc, api and generall rootCmd.AddCommand(NewConfigCmd()) rootCmd.AddCommand(NewCLIHub().NewCommand()) rootCmd.AddCommand(NewMetricsCmd()) - rootCmd.AddCommand(NewDashboardCmd()) - rootCmd.AddCommand(NewDecisionsCmd()) - rootCmd.AddCommand(NewAlertsCmd()) - rootCmd.AddCommand(NewSimulationCmds()) + rootCmd.AddCommand(NewCLIDashboard().NewCommand()) + rootCmd.AddCommand(NewCLIDecisions().NewCommand()) + rootCmd.AddCommand(NewCLIAlerts().NewCommand()) + rootCmd.AddCommand(NewCLISimulation().NewCommand()) rootCmd.AddCommand(NewCLIBouncers().NewCommand()) rootCmd.AddCommand(NewCLIMachines().NewCommand()) - rootCmd.AddCommand(NewCapiCmd()) + rootCmd.AddCommand(NewCLICapi().NewCommand()) rootCmd.AddCommand(NewLapiCmd()) rootCmd.AddCommand(NewCompletionCmd()) rootCmd.AddCommand(NewConsoleCmd()) rootCmd.AddCommand(NewCLIExplain().NewCommand()) - rootCmd.AddCommand(NewHubTestCmd()) + rootCmd.AddCommand(NewCLIHubTest().NewCommand()) rootCmd.AddCommand(NewCLINotifications().NewCommand()) rootCmd.AddCommand(NewCLISupport().NewCommand()) rootCmd.AddCommand(NewCLIPapi().NewCommand()) - rootCmd.AddCommand(NewCollectionCLI().NewCommand()) - rootCmd.AddCommand(NewParserCLI().NewCommand()) - rootCmd.AddCommand(NewScenarioCLI().NewCommand()) - rootCmd.AddCommand(NewPostOverflowCLI().NewCommand()) - rootCmd.AddCommand(NewContextCLI().NewCommand()) - rootCmd.AddCommand(NewAppsecConfigCLI().NewCommand()) - rootCmd.AddCommand(NewAppsecRuleCLI().NewCommand()) + rootCmd.AddCommand(NewCLICollection().NewCommand()) + rootCmd.AddCommand(NewCLIParser().NewCommand()) + rootCmd.AddCommand(NewCLIScenario().NewCommand()) + rootCmd.AddCommand(NewCLIPostOverflow().NewCommand()) + rootCmd.AddCommand(NewCLIContext().NewCommand()) + rootCmd.AddCommand(NewCLIAppsecConfig().NewCommand()) + rootCmd.AddCommand(NewCLIAppsecRule().NewCommand()) if fflag.CscliSetup.IsEnabled() { rootCmd.AddCommand(NewSetupCmd()) diff --git a/cmd/crowdsec-cli/simulation.go b/cmd/crowdsec-cli/simulation.go index c4db03ca3..9ec297249 100644 --- a/cmd/crowdsec-cli/simulation.go +++ b/cmd/crowdsec-cli/simulation.go @@ -13,6 +13,174 @@ import ( "github.com/crowdsecurity/crowdsec/pkg/cwhub" ) +type cliSimulation struct {} + +func NewCLISimulation() *cliSimulation { + return &cliSimulation{} +} + +func (cli cliSimulation) NewCommand() *cobra.Command { + cmd := &cobra.Command{ + Use: "simulation [command]", + Short: "Manage simulation status of scenarios", + Example: `cscli simulation status +cscli simulation enable crowdsecurity/ssh-bf +cscli simulation disable crowdsecurity/ssh-bf`, + DisableAutoGenTag: true, + PersistentPreRunE: func(cmd *cobra.Command, args []string) error { + if err := csConfig.LoadSimulation(); err != nil { + log.Fatal(err) + } + if csConfig.Cscli.SimulationConfig == nil { + return fmt.Errorf("no simulation configured") + } + return nil + }, + PersistentPostRun: func(cmd *cobra.Command, args []string) { + if cmd.Name() != "status" { + log.Infof(ReloadMessage()) + } + }, + } + cmd.Flags().SortFlags = false + cmd.PersistentFlags().SortFlags = false + + cmd.AddCommand(cli.NewEnableCmd()) + cmd.AddCommand(cli.NewDisableCmd()) + cmd.AddCommand(cli.NewStatusCmd()) + + return cmd +} + +func (cli cliSimulation) NewEnableCmd() *cobra.Command { + var forceGlobalSimulation bool + + cmd := &cobra.Command{ + Use: "enable [scenario] [-global]", + Short: "Enable the simulation, globally or on specified scenarios", + Example: `cscli simulation enable`, + DisableAutoGenTag: true, + Run: func(cmd *cobra.Command, args []string) { + hub, err := require.Hub(csConfig, nil) + if err != nil { + log.Fatal(err) + } + + if len(args) > 0 { + for _, scenario := range args { + var item = hub.GetItem(cwhub.SCENARIOS, scenario) + if item == nil { + log.Errorf("'%s' doesn't exist or is not a scenario", scenario) + continue + } + if !item.State.Installed { + log.Warningf("'%s' isn't enabled", scenario) + } + isExcluded := slices.Contains(csConfig.Cscli.SimulationConfig.Exclusions, scenario) + if *csConfig.Cscli.SimulationConfig.Simulation && !isExcluded { + log.Warning("global simulation is already enabled") + continue + } + if !*csConfig.Cscli.SimulationConfig.Simulation && isExcluded { + log.Warningf("simulation for '%s' already enabled", scenario) + continue + } + if *csConfig.Cscli.SimulationConfig.Simulation && isExcluded { + if err := removeFromExclusion(scenario); err != nil { + log.Fatal(err) + } + log.Printf("simulation enabled for '%s'", scenario) + continue + } + if err := addToExclusion(scenario); err != nil { + log.Fatal(err) + } + log.Printf("simulation mode for '%s' enabled", scenario) + } + if err := dumpSimulationFile(); err != nil { + log.Fatalf("simulation enable: %s", err) + } + } else if forceGlobalSimulation { + if err := enableGlobalSimulation(); err != nil { + log.Fatalf("unable to enable global simulation mode : %s", err) + } + } else { + printHelp(cmd) + } + }, + } + cmd.Flags().BoolVarP(&forceGlobalSimulation, "global", "g", false, "Enable global simulation (reverse mode)") + + return cmd +} + +func (cli cliSimulation) NewDisableCmd() *cobra.Command { + var forceGlobalSimulation bool + + cmd := &cobra.Command{ + Use: "disable [scenario]", + Short: "Disable the simulation mode. Disable only specified scenarios", + Example: `cscli simulation disable`, + DisableAutoGenTag: true, + Run: func(cmd *cobra.Command, args []string) { + if len(args) > 0 { + for _, scenario := range args { + isExcluded := slices.Contains(csConfig.Cscli.SimulationConfig.Exclusions, scenario) + if !*csConfig.Cscli.SimulationConfig.Simulation && !isExcluded { + log.Warningf("%s isn't in simulation mode", scenario) + continue + } + if !*csConfig.Cscli.SimulationConfig.Simulation && isExcluded { + if err := removeFromExclusion(scenario); err != nil { + log.Fatal(err) + } + log.Printf("simulation mode for '%s' disabled", scenario) + continue + } + if isExcluded { + log.Warningf("simulation mode is enabled but is already disable for '%s'", scenario) + continue + } + if err := addToExclusion(scenario); err != nil { + log.Fatal(err) + } + log.Printf("simulation mode for '%s' disabled", scenario) + } + if err := dumpSimulationFile(); err != nil { + log.Fatalf("simulation disable: %s", err) + } + } else if forceGlobalSimulation { + if err := disableGlobalSimulation(); err != nil { + log.Fatalf("unable to disable global simulation mode : %s", err) + } + } else { + printHelp(cmd) + } + }, + } + cmd.Flags().BoolVarP(&forceGlobalSimulation, "global", "g", false, "Disable global simulation (reverse mode)") + + return cmd +} + +func (cli cliSimulation) NewStatusCmd() *cobra.Command { + cmd := &cobra.Command{ + Use: "status", + Short: "Show simulation mode status", + Example: `cscli simulation status`, + DisableAutoGenTag: true, + Run: func(cmd *cobra.Command, args []string) { + if err := simulationStatus(); err != nil { + log.Fatal(err) + } + }, + PersistentPostRun: func(cmd *cobra.Command, args []string) { + }, + } + + return cmd +} + func addToExclusion(name string) error { csConfig.Cscli.SimulationConfig.Exclusions = append(csConfig.Cscli.SimulationConfig.Exclusions, name) return nil @@ -100,164 +268,3 @@ func simulationStatus() error { return nil } -func NewSimulationCmds() *cobra.Command { - var cmdSimulation = &cobra.Command{ - Use: "simulation [command]", - Short: "Manage simulation status of scenarios", - Example: `cscli simulation status -cscli simulation enable crowdsecurity/ssh-bf -cscli simulation disable crowdsecurity/ssh-bf`, - DisableAutoGenTag: true, - PersistentPreRunE: func(cmd *cobra.Command, args []string) error { - if err := csConfig.LoadSimulation(); err != nil { - log.Fatal(err) - } - if csConfig.Cscli.SimulationConfig == nil { - return fmt.Errorf("no simulation configured") - } - return nil - }, - PersistentPostRun: func(cmd *cobra.Command, args []string) { - if cmd.Name() != "status" { - log.Infof(ReloadMessage()) - } - }, - } - cmdSimulation.Flags().SortFlags = false - cmdSimulation.PersistentFlags().SortFlags = false - - cmdSimulation.AddCommand(NewSimulationEnableCmd()) - cmdSimulation.AddCommand(NewSimulationDisableCmd()) - cmdSimulation.AddCommand(NewSimulationStatusCmd()) - - return cmdSimulation -} - -func NewSimulationEnableCmd() *cobra.Command { - var forceGlobalSimulation bool - - var cmdSimulationEnable = &cobra.Command{ - Use: "enable [scenario] [-global]", - Short: "Enable the simulation, globally or on specified scenarios", - Example: `cscli simulation enable`, - DisableAutoGenTag: true, - Run: func(cmd *cobra.Command, args []string) { - hub, err := require.Hub(csConfig, nil) - if err != nil { - log.Fatal(err) - } - - if len(args) > 0 { - for _, scenario := range args { - var item = hub.GetItem(cwhub.SCENARIOS, scenario) - if item == nil { - log.Errorf("'%s' doesn't exist or is not a scenario", scenario) - continue - } - if !item.State.Installed { - log.Warningf("'%s' isn't enabled", scenario) - } - isExcluded := slices.Contains(csConfig.Cscli.SimulationConfig.Exclusions, scenario) - if *csConfig.Cscli.SimulationConfig.Simulation && !isExcluded { - log.Warning("global simulation is already enabled") - continue - } - if !*csConfig.Cscli.SimulationConfig.Simulation && isExcluded { - log.Warningf("simulation for '%s' already enabled", scenario) - continue - } - if *csConfig.Cscli.SimulationConfig.Simulation && isExcluded { - if err := removeFromExclusion(scenario); err != nil { - log.Fatal(err) - } - log.Printf("simulation enabled for '%s'", scenario) - continue - } - if err := addToExclusion(scenario); err != nil { - log.Fatal(err) - } - log.Printf("simulation mode for '%s' enabled", scenario) - } - if err := dumpSimulationFile(); err != nil { - log.Fatalf("simulation enable: %s", err) - } - } else if forceGlobalSimulation { - if err := enableGlobalSimulation(); err != nil { - log.Fatalf("unable to enable global simulation mode : %s", err) - } - } else { - printHelp(cmd) - } - }, - } - cmdSimulationEnable.Flags().BoolVarP(&forceGlobalSimulation, "global", "g", false, "Enable global simulation (reverse mode)") - - return cmdSimulationEnable -} - -func NewSimulationDisableCmd() *cobra.Command { - var forceGlobalSimulation bool - - var cmdSimulationDisable = &cobra.Command{ - Use: "disable [scenario]", - Short: "Disable the simulation mode. Disable only specified scenarios", - Example: `cscli simulation disable`, - DisableAutoGenTag: true, - Run: func(cmd *cobra.Command, args []string) { - if len(args) > 0 { - for _, scenario := range args { - isExcluded := slices.Contains(csConfig.Cscli.SimulationConfig.Exclusions, scenario) - if !*csConfig.Cscli.SimulationConfig.Simulation && !isExcluded { - log.Warningf("%s isn't in simulation mode", scenario) - continue - } - if !*csConfig.Cscli.SimulationConfig.Simulation && isExcluded { - if err := removeFromExclusion(scenario); err != nil { - log.Fatal(err) - } - log.Printf("simulation mode for '%s' disabled", scenario) - continue - } - if isExcluded { - log.Warningf("simulation mode is enabled but is already disable for '%s'", scenario) - continue - } - if err := addToExclusion(scenario); err != nil { - log.Fatal(err) - } - log.Printf("simulation mode for '%s' disabled", scenario) - } - if err := dumpSimulationFile(); err != nil { - log.Fatalf("simulation disable: %s", err) - } - } else if forceGlobalSimulation { - if err := disableGlobalSimulation(); err != nil { - log.Fatalf("unable to disable global simulation mode : %s", err) - } - } else { - printHelp(cmd) - } - }, - } - cmdSimulationDisable.Flags().BoolVarP(&forceGlobalSimulation, "global", "g", false, "Disable global simulation (reverse mode)") - - return cmdSimulationDisable -} - -func NewSimulationStatusCmd() *cobra.Command { - var cmdSimulationStatus = &cobra.Command{ - Use: "status", - Short: "Show simulation mode status", - Example: `cscli simulation status`, - DisableAutoGenTag: true, - Run: func(cmd *cobra.Command, args []string) { - if err := simulationStatus(); err != nil { - log.Fatal(err) - } - }, - PersistentPostRun: func(cmd *cobra.Command, args []string) { - }, - } - - return cmdSimulationStatus -}