Skip to content

Commit

Permalink
Centralized allowlists support
Browse files Browse the repository at this point in the history
  • Loading branch information
blotus committed Dec 9, 2024
1 parent b47bedf commit 8385b05
Show file tree
Hide file tree
Showing 79 changed files with 1,104 additions and 453 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/go-tests-windows.yml
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,6 @@ jobs:
- name: golangci-lint
uses: golangci/golangci-lint-action@v6
with:
version: v1.61
version: v1.62
args: --issues-exit-code=1 --timeout 10m
only-new-issues: false
2 changes: 1 addition & 1 deletion .github/workflows/go-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -190,6 +190,6 @@ jobs:
- name: golangci-lint
uses: golangci/golangci-lint-action@v6
with:
version: v1.61
version: v1.62
args: --issues-exit-code=1 --timeout 10m
only-new-issues: false
34 changes: 31 additions & 3 deletions .golangci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -183,7 +183,6 @@ linters-settings:
- ifElseChain
- importShadow
- hugeParam
- rangeValCopy
- commentedOutCode
- commentedOutImport
- unnamedResult
Expand Down Expand Up @@ -211,9 +210,7 @@ linters:
#
# DEPRECATED by golangi-lint
#
- execinquery
- exportloopref
- gomnd

#
# Redundant
Expand Down Expand Up @@ -456,3 +453,34 @@ issues:
- revive
path: "cmd/crowdsec/win_service.go"
text: "deep-exit: .*"

- linters:
- recvcheck
path: "pkg/csplugin/hclog_adapter.go"
text: 'the methods of "HCLogAdapter" use pointer receiver and non-pointer receiver.'

# encoding to json/yaml requires value receivers
- linters:
- recvcheck
path: "pkg/cwhub/item.go"
text: 'the methods of "Item" use pointer receiver and non-pointer receiver.'

- linters:
- gocritic
path: "cmd/crowdsec-cli"
text: "rangeValCopy: .*"

- linters:
- gocritic
path: "pkg/(cticlient|hubtest)"
text: "rangeValCopy: .*"

- linters:
- gocritic
path: "(.+)_test.go"
text: "rangeValCopy: .*"

- linters:
- gocritic
path: "pkg/(appsec|acquisition|dumps|alertcontext|leakybucket|exprhelpers)"
text: "rangeValCopy: .*"
139 changes: 83 additions & 56 deletions cmd/crowdsec-cli/cliallowlists/allowlists.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ import (
"fmt"
"io"
"net/url"
"slices"
"strings"
"time"

"github.com/crowdsecurity/crowdsec/cmd/crowdsec-cli/cstable"
Expand Down Expand Up @@ -35,6 +37,43 @@ func New(cfg configGetter) *cliAllowLists {
}
}

// validAllowlists returns a list of valid allowlists name for command completion
func (cli *cliAllowLists) validAllowlists(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {

Check failure on line 41 in cmd/crowdsec-cli/cliallowlists/allowlists.go

View workflow job for this annotation

GitHub Actions / Build + tests

func `(*cliAllowLists).validAllowlists` is unused (unused)

Check failure on line 41 in cmd/crowdsec-cli/cliallowlists/allowlists.go

View workflow job for this annotation

GitHub Actions / Build + tests

func `(*cliAllowLists).validAllowlists` is unused (unused)
var err error

cfg := cli.cfg()
ctx := cmd.Context()

// need to load config and db because PersistentPreRunE is not called for completions

if err = require.LAPI(cfg); err != nil {
cobra.CompError("unable to load LAPI " + err.Error())
return nil, cobra.ShellCompDirectiveNoFileComp
}

cli.db, err = require.DBClient(ctx, cfg.DbConfig)
if err != nil {
cobra.CompError("unable to load dbclient " + err.Error())
return nil, cobra.ShellCompDirectiveNoFileComp
}

allowlists, err := cli.db.ListAllowLists(ctx, false)
if err != nil {
cobra.CompError("unable to list allowlists " + err.Error())
return nil, cobra.ShellCompDirectiveNoFileComp
}

ret := []string{}

for _, allowlist := range allowlists {
if strings.Contains(allowlist.Name, toComplete) && !slices.Contains(args, allowlist.Name) {
ret = append(ret, allowlist.Name)
}
}

return ret, cobra.ShellCompDirectiveNoFileComp
}

func (cli *cliAllowLists) listHuman(out io.Writer, allowlists *models.GetAllowlistsResponse) {
t := cstable.NewLight(out, cli.cfg().Cscli.Color).Writer
t.AppendHeader(table.Row{"Name", "Description", "Creation Date", "Updated at", "Managed by Console", "Size"})
Expand All @@ -48,14 +87,14 @@ func (cli *cliAllowLists) listHuman(out io.Writer, allowlists *models.GetAllowli

func (cli *cliAllowLists) listContentHuman(out io.Writer, allowlist *models.GetAllowlistResponse) {
t := cstable.NewLight(out, cli.cfg().Cscli.Color).Writer
t.AppendHeader(table.Row{"Value", "Comment", "Expiration", "Updated at"})
t.AppendHeader(table.Row{"Value", "Comment", "Expiration", "Created at"})

for _, content := range allowlist.Items {
expiration := "never"
if !time.Time(content.ExpiresAt).IsZero() {
expiration = content.ExpiresAt.String()
if !time.Time(content.Expiration).IsZero() {
expiration = content.Expiration.String()
}
t.AppendRow(table.Row{content.Value, content.Description, expiration, "FIXME"})
t.AppendRow(table.Row{content.Value, content.Description, expiration, allowlist.CreatedAt})
}

io.WriteString(out, t.Render()+"\n")
Expand All @@ -80,9 +119,10 @@ func (cli *cliAllowLists) NewCommand() *cobra.Command {

func (cli *cliAllowLists) newCreateCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "create",
Short: "Create a new allowlist",
Args: cobra.NoArgs,
Use: "create [allowlist_name]",
Example: "cscli allowlists create my_allowlist -d 'my allowlist description'",
Short: "Create a new allowlist",
Args: cobra.ExactArgs(1),
PersistentPreRunE: func(cmd *cobra.Command, _ []string) error {
var err error
cfg := cli.cfg()
Expand All @@ -100,20 +140,18 @@ func (cli *cliAllowLists) newCreateCmd() *cobra.Command {

flags := cmd.Flags()

flags.StringP("name", "n", "", "name of the allowlist")
flags.StringP("description", "d", "", "description of the allowlist")

cmd.MarkFlagRequired("name")
cmd.MarkFlagRequired("description")

return cmd
}

func (cli *cliAllowLists) create(cmd *cobra.Command, args []string) error {
name := cmd.Flag("name").Value.String()
name := args[0]
description := cmd.Flag("description").Value.String()

err := cli.db.CreateAllowList(cmd.Context(), name, description, false)
_, err := cli.db.CreateAllowList(cmd.Context(), name, description, false)

if err != nil {
return err
Expand All @@ -126,9 +164,10 @@ func (cli *cliAllowLists) create(cmd *cobra.Command, args []string) error {

func (cli *cliAllowLists) newListCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "list",
Short: "List all allowlists",
Args: cobra.NoArgs,
Use: "list",
Example: `cscli allowlists list`,
Short: "List all allowlists",
Args: cobra.NoArgs,
PersistentPreRunE: func(_ *cobra.Command, _ []string) error {
cfg := cli.cfg()
if err := cfg.LoadAPIClient(); err != nil {
Expand Down Expand Up @@ -186,9 +225,10 @@ func (cli *cliAllowLists) list(cmd *cobra.Command, out io.Writer) error {

func (cli *cliAllowLists) newDeleteCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "delete",
Short: "Delete an allowlist",
Args: cobra.NoArgs,
Use: "delete [allowlist_name]",
Short: "Delete an allowlist",
Example: `cscli allowlists delete my_allowlist`,
Args: cobra.ExactArgs(1),
PersistentPreRunE: func(cmd *cobra.Command, _ []string) error {
var err error
cfg := cli.cfg()
Expand All @@ -205,18 +245,11 @@ func (cli *cliAllowLists) newDeleteCmd() *cobra.Command {
RunE: cli.delete,
}

flags := cmd.Flags()

flags.StringP("name", "n", "", "name of the allowlist")

cmd.MarkFlagRequired("name")

return cmd
}

func (cli *cliAllowLists) delete(cmd *cobra.Command, args []string) error {
name := cmd.Flag("name").Value.String()

name := args[0]
list, err := cli.db.GetAllowList(cmd.Context(), name, false)

if err != nil {
Expand All @@ -231,7 +264,7 @@ func (cli *cliAllowLists) delete(cmd *cobra.Command, args []string) error {
return fmt.Errorf("allowlist %s is managed by console, cannot delete with cscli", name)
}

err = cli.db.DeleteAllowList(cmd.Context(), name)
err = cli.db.DeleteAllowList(cmd.Context(), name, false)
if err != nil {
return err
}
Expand All @@ -243,9 +276,10 @@ func (cli *cliAllowLists) delete(cmd *cobra.Command, args []string) error {

func (cli *cliAllowLists) newAddCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "add",
Short: "Add content an allowlist",
Args: cobra.NoArgs,
Use: "add [allowlist_name] --value [value] [-e expiration] [-d comment]",
Short: "Add content an allowlist",
Example: `cscli allowlists add my_allowlist --value 1.2.3.4 --value 2.3.4.5 -e 1h -d "my comment"`,
Args: cobra.ExactArgs(1),
PersistentPreRunE: func(cmd *cobra.Command, _ []string) error {
var err error
cfg := cli.cfg()
Expand All @@ -265,12 +299,10 @@ func (cli *cliAllowLists) newAddCmd() *cobra.Command {

flags := cmd.Flags()

flags.StringP("name", "n", "", "name of the allowlist")
flags.StringSliceP("value", "v", nil, "value to add to the allowlist")
flags.StringP("expiration", "e", "", "expiration duration")
flags.StringP("comment", "d", "", "comment for the value")

cmd.MarkFlagRequired("name")
cmd.MarkFlagRequired("value")

return cmd
Expand All @@ -280,7 +312,7 @@ func (cli *cliAllowLists) add(cmd *cobra.Command, args []string) error {

var expiration time.Duration

name := cmd.Flag("name").Value.String()
name := args[0]
values, err := cmd.Flags().GetStringSlice("value")
comment := cmd.Flag("comment").Value.String()

Expand Down Expand Up @@ -309,7 +341,7 @@ func (cli *cliAllowLists) add(cmd *cobra.Command, args []string) error {
return fmt.Errorf("allowlist %s is managed by console, cannot update with cscli", name)
}

toAdd := make([]string, 0)
toAdd := make([]*models.AllowlistItem, 0)

for _, v := range values {
found := false
Expand All @@ -321,7 +353,7 @@ func (cli *cliAllowLists) add(cmd *cobra.Command, args []string) error {
}
}
if !found {
toAdd = append(toAdd, v)
toAdd = append(toAdd, &models.AllowlistItem{Value: v, Description: comment, Expiration: strfmt.DateTime(time.Now().UTC().Add(expiration))})
}
}

Expand All @@ -332,7 +364,7 @@ func (cli *cliAllowLists) add(cmd *cobra.Command, args []string) error {

log.Debugf("adding %d values to allowlist %s", len(toAdd), name)

err = cli.db.AddToAllowlist(cmd.Context(), allowlist, expiration, comment, toAdd...)
err = cli.db.AddToAllowlist(cmd.Context(), allowlist, toAdd)

if err != nil {
return fmt.Errorf("unable to add values to allowlist: %w", err)
Expand All @@ -343,9 +375,10 @@ func (cli *cliAllowLists) add(cmd *cobra.Command, args []string) error {

func (cli *cliAllowLists) newInspectCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "inspect",
Short: "Inspect an allowlist",
Args: cobra.NoArgs,
Use: "inspect [allowlist_name]",
Example: `cscli allowlists inspect my_allowlist`,
Short: "Inspect an allowlist",
Args: cobra.ExactArgs(1),
PersistentPreRunE: func(_ *cobra.Command, _ []string) error {
cfg := cli.cfg()
if err := cfg.LoadAPIClient(); err != nil {
Expand All @@ -368,23 +401,16 @@ func (cli *cliAllowLists) newInspectCmd() *cobra.Command {

return nil
},
RunE: func(cmd *cobra.Command, _ []string) error {
return cli.inspect(cmd, color.Output)
RunE: func(cmd *cobra.Command, args []string) error {
return cli.inspect(cmd, args, color.Output)
},
}

flags := cmd.Flags()

flags.StringP("name", "n", "", "name of the allowlist")

cmd.MarkFlagRequired("name")

return cmd
}

func (cli *cliAllowLists) inspect(cmd *cobra.Command, out io.Writer) error {
name := cmd.Flag("name").Value.String()

func (cli *cliAllowLists) inspect(cmd *cobra.Command, args []string, out io.Writer) error {
name := args[0]
allowlist, _, err := cli.client.Allowlists.Get(cmd.Context(), name, apiclient.AllowlistGetOpts{WithContent: true})

if err != nil {
Expand Down Expand Up @@ -412,9 +438,10 @@ func (cli *cliAllowLists) inspect(cmd *cobra.Command, out io.Writer) error {

func (cli *cliAllowLists) newRemoveCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "remove",
Short: "remove content from an allowlist",
Args: cobra.NoArgs,
Use: "remove [allowlist_name] --value [value]",
Short: "remove content from an allowlist",
Example: `cscli allowlists remove my_allowlist --value 1.2.3.4 --value 2.3.4.5"`,
Args: cobra.ExactArgs(1),
PersistentPreRunE: func(cmd *cobra.Command, _ []string) error {
var err error
cfg := cli.cfg()
Expand All @@ -434,17 +461,15 @@ func (cli *cliAllowLists) newRemoveCmd() *cobra.Command {

flags := cmd.Flags()

flags.StringP("name", "n", "", "name of the allowlist")
flags.StringSliceP("value", "v", nil, "value to remove from the allowlist")

cmd.MarkFlagRequired("name")
cmd.MarkFlagRequired("value")

return cmd
}

func (cli *cliAllowLists) remove(cmd *cobra.Command, args []string) error {
name := cmd.Flag("name").Value.String()
name := args[0]
values, err := cmd.Flags().GetStringSlice("value")

if err != nil {
Expand Down Expand Up @@ -482,11 +507,13 @@ func (cli *cliAllowLists) remove(cmd *cobra.Command, args []string) error {

log.Debugf("removing %d values from allowlist %s", len(toRemove), name)

err = cli.db.RemoveFromAllowlist(cmd.Context(), allowlist, toRemove...)
nbDeleted, err := cli.db.RemoveFromAllowlist(cmd.Context(), allowlist, toRemove...)

if err != nil {
return fmt.Errorf("unable to remove values from allowlist: %w", err)
}

log.Infof("removed %d values from allowlist %s", nbDeleted, name)

return nil
}
2 changes: 1 addition & 1 deletion cmd/crowdsec-cli/clinotifications/notifications.go
Original file line number Diff line number Diff line change
Expand Up @@ -260,7 +260,7 @@ func (cli *cliNotifications) notificationConfigFilter(cmd *cobra.Command, args [
return ret, cobra.ShellCompDirectiveNoFileComp
}

func (cli cliNotifications) newTestCmd() *cobra.Command {
func (cli *cliNotifications) newTestCmd() *cobra.Command {
var (
pluginBroker csplugin.PluginBroker
pluginTomb tomb.Tomb
Expand Down
Loading

0 comments on commit 8385b05

Please sign in to comment.