Browse Source

Allow crowdsec agent to read context configuration from folder

alteredCoder 1 năm trước cách đây
mục cha
commit
4932a832fa

+ 101 - 48
cmd/crowdsec-cli/lapi.go

@@ -2,6 +2,7 @@ package main
 
 import (
 	"context"
+	"encoding/json"
 	"fmt"
 	"net/url"
 	"os"
@@ -216,24 +217,29 @@ func NewLapiCmd() *cobra.Command {
 	return cmdLapi
 }
 
-func AddContext(key string, values []string) error {
+func AddContext(key string, values []string, targetFile string) error {
 	if err := alertcontext.ValidateContextExpr(key, values); err != nil {
 		return fmt.Errorf("invalid context configuration :%s", err)
 	}
-	if _, ok := csConfig.Crowdsec.ContextToSend[key]; !ok {
-		csConfig.Crowdsec.ContextToSend[key] = make([]string, 0)
-		log.Infof("key '%s' added", key)
-	}
-	data := csConfig.Crowdsec.ContextToSend[key]
-	for _, val := range values {
-		if !slices.Contains(data, val) {
-			log.Infof("value '%s' added to key '%s'", val, key)
-			data = append(data, val)
+
+	for _, ctx := range csConfig.Crowdsec.ContextToSend {
+		if ctx.SourceFile == targetFile {
+			if _, ok := ctx.Context[key]; !ok {
+				ctx.Context[key] = make([]string, 0)
+				log.Infof("key '%s' added", key)
+			}
+			data := ctx.Context[key]
+			for _, val := range values {
+				if !slices.Contains(data, val) {
+					log.Infof("value '%s' added to key '%s'", val, key)
+					data = append(data, val)
+				}
+				ctx.Context[key] = data
+			}
+			if err := csConfig.Crowdsec.DumpContextConfigFile(ctx); err != nil {
+				return err
+			}
 		}
-		csConfig.Crowdsec.ContextToSend[key] = data
-	}
-	if err := csConfig.Crowdsec.DumpContextConfigFile(); err != nil {
-		return err
 	}
 
 	return nil
@@ -246,7 +252,7 @@ func NewLapiContextCmd() *cobra.Command {
 		DisableAutoGenTag: true,
 		PersistentPreRunE: func(cmd *cobra.Command, args []string) error {
 			if err := csConfig.LoadCrowdsec(); err != nil {
-				fileNotFoundMessage := fmt.Sprintf("failed to open context file: open %s: no such file or directory", csConfig.Crowdsec.ConsoleContextPath)
+				fileNotFoundMessage := fmt.Sprintf("failed to open context file: open %s: no such file or directory", csConfig.Crowdsec.ContextPath)
 				if err.Error() != fileNotFoundMessage {
 					log.Fatalf("Unable to load CrowdSec Agent: %s", err)
 				}
@@ -264,6 +270,7 @@ func NewLapiContextCmd() *cobra.Command {
 
 	var keyToAdd string
 	var valuesToAdd []string
+	var filetoAdd string
 	cmdContextAdd := &cobra.Command{
 		Use:   "add",
 		Short: "Add context to send with alerts. You must specify the output key with the expr value you want",
@@ -273,8 +280,21 @@ cscli lapi context add --value evt.Meta.source_ip --value evt.Meta.target_user
 		`,
 		DisableAutoGenTag: true,
 		Run: func(cmd *cobra.Command, args []string) {
+			if filetoAdd == "" {
+				filetoAdd = csConfig.Crowdsec.ContextPath
+			}
+
+			// check if the provided file is the context path file or in the configured context directory
+			fileInFolder, err := isFilePathInFolder(csConfig.Crowdsec.ContextDir, filetoAdd)
+			if err != nil {
+				log.Fatalf("unable to get relative path from '%s' and '%s'", filetoAdd, csConfig.Crowdsec.ContextDir)
+			}
+			if filetoAdd != csConfig.Crowdsec.ContextPath && !fileInFolder {
+				log.Fatalf("file to edit ('%s') must be '%s' or in the folder '%s/'", filetoAdd, csConfig.Crowdsec.ContextPath, csConfig.Crowdsec.ContextDir)
+			}
+
 			if keyToAdd != "" {
-				if err := AddContext(keyToAdd, valuesToAdd); err != nil {
+				if err := AddContext(keyToAdd, valuesToAdd, filetoAdd); err != nil {
 					log.Fatalf(err.Error())
 				}
 				return
@@ -284,13 +304,14 @@ cscli lapi context add --value evt.Meta.source_ip --value evt.Meta.target_user
 				keySlice := strings.Split(v, ".")
 				key := keySlice[len(keySlice)-1]
 				value := []string{v}
-				if err := AddContext(key, value); err != nil {
+				if err := AddContext(key, value, filetoAdd); err != nil {
 					log.Fatalf(err.Error())
 				}
 			}
 		},
 	}
 	cmdContextAdd.Flags().StringVarP(&keyToAdd, "key", "k", "", "The key of the different values to send")
+	cmdContextAdd.Flags().StringVarP(&filetoAdd, "file", "f", "", "Filepath to add context")
 	cmdContextAdd.Flags().StringSliceVar(&valuesToAdd, "value", []string{}, "The expr fields to associate with the key")
 	cmdContextAdd.MarkFlagRequired("value")
 	cmdContext.AddCommand(cmdContextAdd)
@@ -300,18 +321,28 @@ cscli lapi context add --value evt.Meta.source_ip --value evt.Meta.target_user
 		Short:             "List context to send with alerts",
 		DisableAutoGenTag: true,
 		Run: func(cmd *cobra.Command, args []string) {
-			if len(csConfig.Crowdsec.ContextToSend) == 0 {
-				fmt.Println("No context found on this agent. You can use 'cscli lapi context add' to add context to your alerts.")
-				return
+			contextFound := false
+			for _, ctx := range csConfig.Crowdsec.ContextToSend {
+				if len(ctx.Context) == 0 {
+					continue
+				}
+				contextFound = true
+				var dump []byte
+				var err error
+				if csConfig.Cscli.Output == "json" {
+					dump, err = json.MarshalIndent(ctx, "", " ")
+				} else {
+					dump, err = yaml.Marshal(ctx)
+				}
+				if err != nil {
+					log.Fatalf("unable to show context status: %s", err)
+				}
+				fmt.Println(string(dump))
 			}
 
-			dump, err := yaml.Marshal(csConfig.Crowdsec.ContextToSend)
-			if err != nil {
-				log.Fatalf("unable to show context status: %s", err)
+			if !contextFound {
+				log.Fatalf("No context found for this agent.")
 			}
-
-			fmt.Println(string(dump))
-
 		},
 	}
 	cmdContext.AddCommand(cmdContextStatus)
@@ -407,6 +438,7 @@ cscli lapi context detect crowdsecurity/sshd-logs
 
 	var keysToDelete []string
 	var valuesToDelete []string
+	var fileToDelete string
 	cmdContextDelete := &cobra.Command{
 		Use:   "delete",
 		Short: "Delete context to send with alerts",
@@ -419,40 +451,61 @@ cscli lapi context delete --value evt.Line.Src
 				log.Fatalf("please provide at least a key or a value to delete")
 			}
 
-			for _, key := range keysToDelete {
-				if _, ok := csConfig.Crowdsec.ContextToSend[key]; ok {
-					delete(csConfig.Crowdsec.ContextToSend, key)
-					log.Infof("key '%s' has been removed", key)
-				} else {
-					log.Warningf("key '%s' doesn't exist", key)
-				}
+			if fileToDelete == "" {
+				fileToDelete = csConfig.Crowdsec.ContextPath
 			}
 
-			for _, value := range valuesToDelete {
-				valueFound := false
-				for key, context := range csConfig.Crowdsec.ContextToSend {
-					if slices.Contains(context, value) {
-						valueFound = true
-						csConfig.Crowdsec.ContextToSend[key] = removeFromSlice(value, context)
-						log.Infof("value '%s' has been removed from key '%s'", value, key)
+			// check if the provided file is the context path file or in the configured context directory
+			fileInFolder, err := isFilePathInFolder(csConfig.Crowdsec.ContextDir, fileToDelete)
+			if err != nil {
+				log.Fatalf("unable to get relative path from '%s' and '%s'", fileToDelete, csConfig.Crowdsec.ContextDir)
+			}
+			if fileToDelete != csConfig.Crowdsec.ContextPath && !fileInFolder {
+				log.Fatalf("file to edit ('%s') must be '%s' or in the folder '%s/'", fileToDelete, csConfig.Crowdsec.ContextPath, csConfig.Crowdsec.ContextDir)
+			}
+
+			for _, ctx := range csConfig.Crowdsec.ContextToSend {
+				if ctx.SourceFile != fileToDelete {
+					continue
+				}
+
+				for _, key := range keysToDelete {
+					if _, ok := ctx.Context[key]; ok {
+						delete(ctx.Context, key)
+						log.Infof("key '%s' has been removed", key)
+					} else {
+						log.Warningf("key '%s' doesn't exist", key)
+					}
+				}
+
+				for _, value := range valuesToDelete {
+					valueFound := false
+					for key, context := range ctx.Context {
+						if slices.Contains(context, value) {
+							valueFound = true
+							ctx.Context[key] = removeFromSlice(value, context)
+							log.Infof("value '%s' has been removed from key '%s'", value, key)
+						}
+						if len(ctx.Context[key]) == 0 {
+							delete(ctx.Context, key)
+						}
 					}
-					if len(csConfig.Crowdsec.ContextToSend[key]) == 0 {
-						delete(csConfig.Crowdsec.ContextToSend, key)
+					if !valueFound {
+						log.Warningf("value '%s' not found", value)
 					}
 				}
-				if !valueFound {
-					log.Warningf("value '%s' not found", value)
+
+				if err := csConfig.Crowdsec.DumpContextConfigFile(ctx); err != nil {
+					log.Fatalf(err.Error())
 				}
-			}
 
-			if err := csConfig.Crowdsec.DumpContextConfigFile(); err != nil {
-				log.Fatalf(err.Error())
+				break
 			}
-
 		},
 	}
 	cmdContextDelete.Flags().StringSliceVarP(&keysToDelete, "key", "k", []string{}, "The keys to delete")
 	cmdContextDelete.Flags().StringSliceVar(&valuesToDelete, "value", []string{}, "The expr fields to delete")
+	cmdContextDelete.Flags().StringVarP(&fileToDelete, "file", "f", "", "Filepath to add context")
 	cmdContext.AddCommand(cmdContextDelete)
 
 	return cmdContext

+ 21 - 5
cmd/crowdsec-cli/utils.go

@@ -9,16 +9,17 @@ import (
 	"net"
 	"net/http"
 	"os"
+	"path/filepath"
 	"strconv"
 	"strings"
 	"time"
 
+	"github.com/agext/levenshtein"
 	"github.com/fatih/color"
 	dto "github.com/prometheus/client_model/go"
 	"github.com/prometheus/prom2json"
 	log "github.com/sirupsen/logrus"
 	"github.com/spf13/cobra"
-	"github.com/agext/levenshtein"
 	"golang.org/x/exp/slices"
 	"gopkg.in/yaml.v2"
 
@@ -688,10 +689,10 @@ var ranges = []unit{
 	{value: 1e18, symbol: "E"},
 	{value: 1e15, symbol: "P"},
 	{value: 1e12, symbol: "T"},
-	{value: 1e9,  symbol: "G"},
-	{value: 1e6,  symbol: "M"},
-	{value: 1e3,  symbol: "k"},
-	{value: 1,    symbol: ""},
+	{value: 1e9, symbol: "G"},
+	{value: 1e6, symbol: "M"},
+	{value: 1e3, symbol: "k"},
+	{value: 1, symbol: ""},
 }
 
 func formatNumber(num int) string {
@@ -746,3 +747,18 @@ func removeFromSlice(val string, slice []string) []string {
 	return slice
 
 }
+
+/*
+isFilePathInFolder uses filepath.Rel() to obtain a relative path
+from basePath to targetPath. If the relative path contains "..",
+then targetPath is not a sub-path of basePath
+*/
+func isFilePathInFolder(folderpath string, targetFilepath string) (bool, error) {
+	relPath, err := filepath.Rel(folderpath, targetFilepath)
+	if err != nil {
+		return false, err
+	}
+	log.Infof("F: %+v | T: %+v", folderpath, targetFilepath)
+	log.Infof("REAL POATH: %+v", relPath)
+	return !strings.Contains(relPath, ".."), nil
+}

+ 22 - 9
pkg/alertcontext/alertcontext.go

@@ -5,6 +5,8 @@ import (
 	"fmt"
 	"strconv"
 
+	"github.com/crowdsecurity/crowdsec/pkg/csconfig"
+
 	"github.com/antonmedv/expr"
 	"github.com/antonmedv/expr/vm"
 	log "github.com/sirupsen/logrus"
@@ -40,7 +42,7 @@ func ValidateContextExpr(key string, expressions []string) error {
 	return nil
 }
 
-func NewAlertContext(contextToSend map[string][]string, valueLength int) error {
+func NewAlertContext(contextToSend []csconfig.ContextToSend, valueLength int) error {
 	var clog = log.New()
 	if err := types.ConfigureLogger(clog); err != nil {
 		return fmt.Errorf("couldn't create logger for alert context: %s", err)
@@ -56,20 +58,31 @@ func NewAlertContext(contextToSend map[string][]string, valueLength int) error {
 	}
 
 	alertContext = Context{
-		ContextToSend:         contextToSend,
+		ContextToSend:         make(map[string][]string),
 		ContextValueLen:       valueLength,
 		Log:                   clog,
 		ContextToSendCompiled: make(map[string][]*vm.Program),
 	}
 
-	for key, values := range contextToSend {
-		alertContext.ContextToSendCompiled[key] = make([]*vm.Program, 0)
-		for _, value := range values {
-			valueCompiled, err := expr.Compile(value, exprhelpers.GetExprOptions(map[string]interface{}{"evt": &types.Event{}})...)
-			if err != nil {
-				return fmt.Errorf("compilation of '%s' context value failed: %v", value, err)
+	for _, ctx := range contextToSend {
+		for key, values := range ctx.Context {
+			if _, ok := alertContext.ContextToSend[key]; !ok {
+				alertContext.ContextToSend[key] = make([]string, 0)
+			}
+
+			alertContext.ContextToSendCompiled[key] = make([]*vm.Program, 0)
+			for _, value := range values {
+				valueCompiled, err := expr.Compile(value, exprhelpers.GetExprOptions(map[string]interface{}{"evt": &types.Event{}})...)
+				if err != nil {
+					return fmt.Errorf("compilation of '%s' context value failed: %v", value, err)
+				}
+				alertContext.ContextToSendCompiled[key] = append(alertContext.ContextToSendCompiled[key], valueCompiled)
+				if slices.Contains(alertContext.ContextToSend[key], value) {
+					log.Debugf("value '%s' from '%s' already in context", value, ctx.SourceFile)
+					continue
+				}
+				alertContext.ContextToSend[key] = append(alertContext.ContextToSend[key], value)
 			}
-			alertContext.ContextToSendCompiled[key] = append(alertContext.ContextToSendCompiled[key], valueCompiled)
 		}
 	}
 

+ 92 - 36
pkg/csconfig/crowdsec_service.go

@@ -4,6 +4,7 @@ import (
 	"fmt"
 	"os"
 	"path/filepath"
+	"strings"
 
 	log "github.com/sirupsen/logrus"
 	"gopkg.in/yaml.v2"
@@ -11,29 +12,35 @@ import (
 	"github.com/crowdsecurity/go-cs-lib/ptr"
 )
 
+type ContextToSend struct {
+	SourceFile string              `yaml:"filepath" json:"filepath"`
+	Context    map[string][]string `yaml:"context" json:"context"`
+}
+
 // CrowdsecServiceCfg contains the location of parsers/scenarios/... and acquisition files
 type CrowdsecServiceCfg struct {
-	Enable                    *bool             `yaml:"enable"`
-	AcquisitionFilePath       string            `yaml:"acquisition_path,omitempty"`
-	AcquisitionDirPath        string            `yaml:"acquisition_dir,omitempty"`
-	ConsoleContextPath        string            `yaml:"console_context_path"`
-	ConsoleContextValueLength int               `yaml:"console_context_value_length"`
-	AcquisitionFiles          []string          `yaml:"-"`
-	ParserRoutinesCount       int               `yaml:"parser_routines"`
-	BucketsRoutinesCount      int               `yaml:"buckets_routines"`
-	OutputRoutinesCount       int               `yaml:"output_routines"`
-	SimulationConfig          *SimulationConfig `yaml:"-"`
-	LintOnly                  bool              `yaml:"-"`                          // if set to true, exit after loading configs
-	BucketStateFile           string            `yaml:"state_input_file,omitempty"` // if we need to unserialize buckets at start
-	BucketStateDumpDir        string            `yaml:"state_output_dir,omitempty"` // if we need to unserialize buckets on shutdown
-	BucketsGCEnabled          bool              `yaml:"-"`                          // we need to garbage collect buckets when in forensic mode
-
-	HubDir             string              `yaml:"-"`
-	DataDir            string              `yaml:"-"`
-	ConfigDir          string              `yaml:"-"`
-	HubIndexFile       string              `yaml:"-"`
-	SimulationFilePath string              `yaml:"-"`
-	ContextToSend      map[string][]string `yaml:"-"`
+	Enable               *bool             `yaml:"enable"`
+	AcquisitionFilePath  string            `yaml:"acquisition_path,omitempty"`
+	AcquisitionDirPath   string            `yaml:"acquisition_dir,omitempty"`
+	ContextPath          string            `yaml:"console_context_path"`
+	ContextDir           string            `yaml:"console_context_dir"`
+	ContextValueLength   int               `yaml:"console_context_value_length"`
+	AcquisitionFiles     []string          `yaml:"-"`
+	ParserRoutinesCount  int               `yaml:"parser_routines"`
+	BucketsRoutinesCount int               `yaml:"buckets_routines"`
+	OutputRoutinesCount  int               `yaml:"output_routines"`
+	SimulationConfig     *SimulationConfig `yaml:"-"`
+	LintOnly             bool              `yaml:"-"`                          // if set to true, exit after loading configs
+	BucketStateFile      string            `yaml:"state_input_file,omitempty"` // if we need to unserialize buckets at start
+	BucketStateDumpDir   string            `yaml:"state_output_dir,omitempty"` // if we need to unserialize buckets on shutdown
+	BucketsGCEnabled     bool              `yaml:"-"`                          // we need to garbage collect buckets when in forensic mode
+
+	HubDir             string          `yaml:"-"`
+	DataDir            string          `yaml:"-"`
+	ConfigDir          string          `yaml:"-"`
+	HubIndexFile       string          `yaml:"-"`
+	SimulationFilePath string          `yaml:"-"`
+	ContextToSend      []ContextToSend `yaml:"-"`
 }
 
 func (c *Config) LoadCrowdsec() error {
@@ -149,21 +156,21 @@ func (c *Config) LoadCrowdsec() error {
 		return fmt.Errorf("while loading hub: %w", err)
 	}
 
-	c.Crowdsec.ContextToSend = make(map[string][]string, 0)
+	c.Crowdsec.ContextToSend = make([]ContextToSend, 0)
 	fallback := false
-	if c.Crowdsec.ConsoleContextPath == "" {
+	if c.Crowdsec.ContextPath == "" {
 		// fallback to default config file
-		c.Crowdsec.ConsoleContextPath = filepath.Join(c.Crowdsec.ConfigDir, "console", "context.yaml")
+		c.Crowdsec.ContextPath = filepath.Join(c.Crowdsec.ConfigDir, "console", "context.yaml")
 		fallback = true
 	}
 
-	f, err := filepath.Abs(c.Crowdsec.ConsoleContextPath)
+	f, err := filepath.Abs(c.Crowdsec.ContextPath)
 	if err != nil {
-		return fmt.Errorf("fail to get absolute path of %s: %s", c.Crowdsec.ConsoleContextPath, err)
+		return fmt.Errorf("fail to get absolute path of %s: %s", c.Crowdsec.ContextPath, err)
 	}
 
-	c.Crowdsec.ConsoleContextPath = f
-	yamlFile, err := os.ReadFile(c.Crowdsec.ConsoleContextPath)
+	c.Crowdsec.ContextPath = f
+	yamlFile, err := os.ReadFile(c.Crowdsec.ContextPath)
 	if err != nil {
 		if fallback {
 			log.Debugf("Default context config file doesn't exist, will not use it")
@@ -171,28 +178,77 @@ func (c *Config) LoadCrowdsec() error {
 			return fmt.Errorf("failed to open context file: %s", err)
 		}
 	} else {
-		err = yaml.Unmarshal(yamlFile, c.Crowdsec.ContextToSend)
+		ctxToSend := ContextToSend{
+			SourceFile: c.Crowdsec.ContextPath,
+			Context:    make(map[string][]string),
+		}
+		err = yaml.Unmarshal(yamlFile, ctxToSend.Context)
+		if err != nil {
+			return fmt.Errorf("unmarshaling context config file '%s': %s", c.Crowdsec.ContextPath, err)
+		}
+		c.Crowdsec.ContextToSend = append(c.Crowdsec.ContextToSend, ctxToSend)
+	}
+
+	if c.Crowdsec.ContextDir == "" {
+		// fallback to default config file
+		c.Crowdsec.ContextDir = filepath.Join(c.Crowdsec.ConfigDir, "context")
+		fallback = true
+	}
+
+	// if context folder exist, try to read it
+	if _, err := os.Stat(c.Crowdsec.ContextDir); !os.IsNotExist(err) {
+		err := filepath.Walk(c.Crowdsec.ContextDir, func(path string, info os.FileInfo, err error) error {
+			if err != nil {
+				return err
+			}
+			if !strings.HasSuffix(path, ".yaml") && !strings.HasSuffix(path, ".yml") {
+				return nil
+			}
+
+			f, err := filepath.Abs(path)
+			if err != nil {
+				return fmt.Errorf("fail to get absolute path of %s: %s", path, err)
+			}
+
+			yamlFile, err := os.ReadFile(f)
+			if err != nil {
+				return fmt.Errorf("unable to read context file '%s': %s", f, err.Error())
+			}
+			ctxToSend := ContextToSend{
+				SourceFile: f,
+				Context:    make(map[string][]string),
+			}
+			err = yaml.Unmarshal(yamlFile, ctxToSend.Context)
+			if err != nil {
+				return fmt.Errorf("unable to unmarshal context file '%s': %s", f, err)
+			}
+			log.Debugf("Reading %s context file: %+v", f, string(yamlFile))
+
+			c.Crowdsec.ContextToSend = append(c.Crowdsec.ContextToSend, ctxToSend)
+
+			return nil
+		})
 		if err != nil {
-			return fmt.Errorf("unmarshaling labels console config file '%s': %s", c.Crowdsec.ConsoleContextPath, err)
+			return fmt.Errorf("unable to list context directory: %s", err.Error())
 		}
 	}
 
 	return nil
 }
 
-func (c *CrowdsecServiceCfg) DumpContextConfigFile() error {
+func (c *CrowdsecServiceCfg) DumpContextConfigFile(contextToSend ContextToSend) error {
 	var out []byte
 	var err error
 
-	if out, err = yaml.Marshal(c.ContextToSend); err != nil {
-		return fmt.Errorf("while marshaling ConsoleConfig (for %s): %w", c.ConsoleContextPath, err)
+	if out, err = yaml.Marshal(contextToSend.Context); err != nil {
+		return fmt.Errorf("while marshaling ConsoleConfig (for %s): %w", contextToSend.SourceFile, err)
 	}
 
-	if err := os.WriteFile(c.ConsoleContextPath, out, 0600); err != nil {
-		return fmt.Errorf("while dumping console config to %s: %w", c.ConsoleContextPath, err)
+	if err := os.WriteFile(contextToSend.SourceFile, out, 0600); err != nil {
+		return fmt.Errorf("while dumping console config to %s: %w", contextToSend.SourceFile, err)
 	}
 
-	log.Infof("%s file saved", c.ConsoleContextPath)
+	log.Infof("%s file saved", contextToSend.SourceFile)
 
 	return nil
 }

+ 70 - 55
pkg/csconfig/crowdsec_service_test.go

@@ -56,29 +56,34 @@ func TestLoadCrowdsec(t *testing.T) {
 					},
 				},
 				Crowdsec: &CrowdsecServiceCfg{
-					AcquisitionFilePath:       "./tests/acquis.yaml",
-					SimulationFilePath:        "./tests/simulation.yaml",
-					ConsoleContextPath:        "./tests/context.yaml",
-					ConsoleContextValueLength: 2500,
+					AcquisitionFilePath: "./tests/acquis.yaml",
+					SimulationFilePath:  "./tests/simulation.yaml",
+					ContextPath:         "./tests/context.yaml",
+					ContextValueLength:  2500,
 				},
 			},
 			expectedResult: &CrowdsecServiceCfg{
-				Enable:                    ptr.Of(true),
-				AcquisitionDirPath:        "",
-				ConsoleContextPath:        contextFileFullPath,
-				AcquisitionFilePath:       acquisFullPath,
-				ConfigDir:                 configDirFullPath,
-				DataDir:                   dataFullPath,
-				HubDir:                    hubFullPath,
-				HubIndexFile:              hubIndexFileFullPath,
-				BucketsRoutinesCount:      1,
-				ParserRoutinesCount:       1,
-				OutputRoutinesCount:       1,
-				ConsoleContextValueLength: 2500,
-				AcquisitionFiles:          []string{acquisFullPath},
-				SimulationFilePath:        "./tests/simulation.yaml",
-				ContextToSend: map[string][]string{
-					"source_ip": {"evt.Parsed.source_ip"},
+				Enable:               ptr.Of(true),
+				AcquisitionDirPath:   "",
+				ContextPath:          contextFileFullPath,
+				AcquisitionFilePath:  acquisFullPath,
+				ConfigDir:            configDirFullPath,
+				DataDir:              dataFullPath,
+				HubDir:               hubFullPath,
+				HubIndexFile:         hubIndexFileFullPath,
+				BucketsRoutinesCount: 1,
+				ParserRoutinesCount:  1,
+				OutputRoutinesCount:  1,
+				ContextValueLength:   2500,
+				AcquisitionFiles:     []string{acquisFullPath},
+				SimulationFilePath:   "./tests/simulation.yaml",
+				ContextToSend: []ContextToSend{
+					ContextToSend{
+						SourceFile: "./tests/context.yaml",
+						Context: map[string][]string{
+							"source_ip": {"evt.Parsed.source_ip"},
+						},
+					},
 				},
 				SimulationConfig: &SimulationConfig{
 					Simulation: ptr.Of(false),
@@ -102,25 +107,30 @@ func TestLoadCrowdsec(t *testing.T) {
 					AcquisitionFilePath: "./tests/acquis.yaml",
 					AcquisitionDirPath:  "./tests/acquis/",
 					SimulationFilePath:  "./tests/simulation.yaml",
-					ConsoleContextPath:  "./tests/context.yaml",
+					ContextPath:         "./tests/context.yaml",
 				},
 			},
 			expectedResult: &CrowdsecServiceCfg{
-				Enable:                    ptr.Of(true),
-				AcquisitionDirPath:        acquisDirFullPath,
-				AcquisitionFilePath:       acquisFullPath,
-				ConsoleContextPath:        contextFileFullPath,
-				ConfigDir:                 configDirFullPath,
-				HubIndexFile:              hubIndexFileFullPath,
-				DataDir:                   dataFullPath,
-				HubDir:                    hubFullPath,
-				BucketsRoutinesCount:      1,
-				ParserRoutinesCount:       1,
-				OutputRoutinesCount:       1,
-				ConsoleContextValueLength: 0,
-				AcquisitionFiles:          []string{acquisFullPath, acquisInDirFullPath},
-				ContextToSend: map[string][]string{
-					"source_ip": {"evt.Parsed.source_ip"},
+				Enable:               ptr.Of(true),
+				AcquisitionDirPath:   acquisDirFullPath,
+				AcquisitionFilePath:  acquisFullPath,
+				ContextPath:          contextFileFullPath,
+				ConfigDir:            configDirFullPath,
+				HubIndexFile:         hubIndexFileFullPath,
+				DataDir:              dataFullPath,
+				HubDir:               hubFullPath,
+				BucketsRoutinesCount: 1,
+				ParserRoutinesCount:  1,
+				OutputRoutinesCount:  1,
+				ContextValueLength:   0,
+				AcquisitionFiles:     []string{acquisFullPath, acquisInDirFullPath},
+				ContextToSend: []ContextToSend{
+					ContextToSend{
+						SourceFile: "./tests/context.yaml",
+						Context: map[string][]string{
+							"source_ip": {"evt.Parsed.source_ip"},
+						},
+					},
 				},
 				SimulationFilePath: "./tests/simulation.yaml",
 				SimulationConfig: &SimulationConfig{
@@ -142,27 +152,32 @@ func TestLoadCrowdsec(t *testing.T) {
 					},
 				},
 				Crowdsec: &CrowdsecServiceCfg{
-					ConsoleContextPath:        contextFileFullPath,
-					ConsoleContextValueLength: 10,
+					ContextPath:        contextFileFullPath,
+					ContextValueLength: 10,
 				},
 			},
 			expectedResult: &CrowdsecServiceCfg{
-				Enable:                    ptr.Of(true),
-				AcquisitionDirPath:        "",
-				AcquisitionFilePath:       "",
-				ConfigDir:                 configDirFullPath,
-				HubIndexFile:              hubIndexFileFullPath,
-				DataDir:                   dataFullPath,
-				HubDir:                    hubFullPath,
-				ConsoleContextPath:        contextFileFullPath,
-				BucketsRoutinesCount:      1,
-				ParserRoutinesCount:       1,
-				OutputRoutinesCount:       1,
-				ConsoleContextValueLength: 10,
-				AcquisitionFiles:          []string{},
-				SimulationFilePath:        "",
-				ContextToSend: map[string][]string{
-					"source_ip": {"evt.Parsed.source_ip"},
+				Enable:               ptr.Of(true),
+				AcquisitionDirPath:   "",
+				AcquisitionFilePath:  "",
+				ConfigDir:            configDirFullPath,
+				HubIndexFile:         hubIndexFileFullPath,
+				DataDir:              dataFullPath,
+				HubDir:               hubFullPath,
+				ContextPath:          contextFileFullPath,
+				BucketsRoutinesCount: 1,
+				ParserRoutinesCount:  1,
+				OutputRoutinesCount:  1,
+				ContextValueLength:   10,
+				AcquisitionFiles:     []string{},
+				SimulationFilePath:   "",
+				ContextToSend: []ContextToSend{
+					ContextToSend{
+						SourceFile: "./tests/context.yaml",
+						Context: map[string][]string{
+							"source_ip": {"evt.Parsed.source_ip"},
+						},
+					},
 				},
 				SimulationConfig: &SimulationConfig{
 					Simulation: ptr.Of(false),
@@ -183,7 +198,7 @@ func TestLoadCrowdsec(t *testing.T) {
 					},
 				},
 				Crowdsec: &CrowdsecServiceCfg{
-					ConsoleContextPath:  "",
+					ContextPath:         "",
 					AcquisitionFilePath: "./tests/acquis_not_exist.yaml",
 				},
 			},

+ 1 - 1
pkg/leakybucket/manager_load.go

@@ -264,7 +264,7 @@ func LoadBuckets(cscfg *csconfig.CrowdsecServiceCfg, files []string, tomb *tomb.
 		}
 	}
 
-	if err := alertcontext.NewAlertContext(cscfg.ContextToSend, cscfg.ConsoleContextValueLength); err != nil {
+	if err := alertcontext.NewAlertContext(cscfg.ContextToSend, cscfg.ContextValueLength); err != nil {
 		return nil, nil, fmt.Errorf("unable to load alert context: %s", err)
 	}