diff --git a/.gitignore b/.gitignore index 2045d2b9671..2075ddf8f31 100644 --- a/.gitignore +++ b/.gitignore @@ -51,6 +51,9 @@ vendor.tgz cmd/crowdsec-cli/cscli cmd/crowdsec/crowdsec cmd/notification-*/notification-* +crowdsec +crowdsec-cli +cscli # Test cache (downloaded files) .cache diff --git a/cmd/crowdsec/main.go b/cmd/crowdsec/main.go index 6a5b7bc1120..2f7226b0085 100644 --- a/cmd/crowdsec/main.go +++ b/cmd/crowdsec/main.go @@ -66,16 +66,21 @@ func LoadBuckets(cConfig *csconfig.Config, hub *cwhub.Hub) error { } func LoadAcquisition(ctx context.Context, cConfig *csconfig.Config, hub *cwhub.Hub) ([]acquisitionTypes.DataSource, error) { + var clientConfig *csconfig.LocalApiClientCfg + if cConfig.API != nil { + clientConfig = cConfig.API.Client + } + if flags.SingleFileType != "" && flags.OneShotDSN != "" { flags.Labels["type"] = flags.SingleFileType - ds, err := acquisition.LoadAcquisitionFromDSN(ctx, flags.OneShotDSN, flags.Labels, flags.Transform, hub) + ds, err := acquisition.LoadAcquisitionFromDSN(ctx, flags.OneShotDSN, flags.Labels, flags.Transform, hub, clientConfig) if err != nil { return nil, err } dataSources = append(dataSources, ds) } else { - dss, err := acquisition.LoadAcquisitionFromFiles(ctx, cConfig.Crowdsec, cConfig.Prometheus, hub) + dss, err := acquisition.LoadAcquisitionFromFiles(ctx, cConfig.Crowdsec, cConfig.Prometheus, hub, clientConfig) if err != nil { return nil, err } diff --git a/pkg/acquisition/acquisition.go b/pkg/acquisition/acquisition.go index e19ac3c6c56..84da341eaf9 100644 --- a/pkg/acquisition/acquisition.go +++ b/pkg/acquisition/acquisition.go @@ -62,6 +62,7 @@ func DataSourceConfigure( yamlConfig []byte, metricsLevel metrics.AcquisitionMetricsLevel, hub *cwhub.Hub, + clientConfig *csconfig.LocalApiClientCfg, ) (types.DataSource, error) { factory, err := registry.LookupFactory(commonConfig.Source) if err != nil { @@ -89,11 +90,9 @@ func DataSourceConfigure( } if lapiClientAware, ok := dataSrc.(types.LAPIClientAware); ok { - cConfig := csconfig.GetConfig() - if cConfig.API == nil { - return nil, errors.New("crowdsec configuration not loaded while initializing appsec - this is a bug, plese report") + if clientConfig != nil { + lapiClientAware.SetClientConfig(clientConfig) } - lapiClientAware.SetClientConfig(cConfig.API.Client) } /* configure the actual datasource */ @@ -110,6 +109,7 @@ func LoadAcquisitionFromDSN( labels map[string]string, transformExpr string, hub *cwhub.Hub, + clientConfig *csconfig.LocalApiClientCfg, ) (types.DataSource, error) { frags := strings.Split(dsn, ":") if len(frags) == 1 { @@ -138,8 +138,9 @@ func LoadAcquisitionFromDSN( } if lapiClientAware, ok := dataSrc.(types.LAPIClientAware); ok { - cConfig := csconfig.GetConfig() - lapiClientAware.SetClientConfig(cConfig.API.Client) + if clientConfig != nil { + lapiClientAware.SetClientConfig(clientConfig) + } } dsnConf, ok := dataSrc.(types.DSNConfigurer) @@ -225,7 +226,7 @@ var ErrEmptyYAMLDocument = errors.New("empty yaml document") // - validate common fields // - delegate per-source config validation to the appropriate module // - compile transform expression -func ParseSourceConfig(ctx context.Context, yamlDoc []byte, metricsLevel metrics.AcquisitionMetricsLevel, hub *cwhub.Hub) (*ParsedSourceConfig, error) { +func ParseSourceConfig(ctx context.Context, yamlDoc []byte, metricsLevel metrics.AcquisitionMetricsLevel, hub *cwhub.Hub, clientConfig *csconfig.LocalApiClientCfg) (*ParsedSourceConfig, error) { detectedType, err := detectType(bytes.NewReader(yamlDoc)) if err != nil { return nil, err @@ -287,7 +288,7 @@ func ParseSourceConfig(ctx context.Context, yamlDoc []byte, metricsLevel metrics uniqueID := uuid.NewString() sub.UniqueId = uniqueID - src, err := DataSourceConfigure(ctx, sub, yamlDoc, metricsLevel, hub) + src, err := DataSourceConfigure(ctx, sub, yamlDoc, metricsLevel, hub, clientConfig) if err != nil { return nil, fmt.Errorf("datasource of type %s: %w", sub.Source, err) } @@ -321,6 +322,7 @@ func sourcesFromFile( acquisFile string, metricsLevel metrics.AcquisitionMetricsLevel, hub *cwhub.Hub, + clientConfig *csconfig.LocalApiClientCfg, ) ([]types.DataSource, error) { var sources []types.DataSource @@ -352,7 +354,7 @@ func sourcesFromFile( loc := formatConfigLocation(acquisFile, len(documents) > 1, idx) - parsed, err := ParseSourceConfig(ctx, yamlDoc, metricsLevel, hub) + parsed, err := ParseSourceConfig(ctx, yamlDoc, metricsLevel, hub, clientConfig) // report data source detection, it can be required to understand an error if parsed != nil { @@ -395,13 +397,14 @@ func LoadAcquisitionFromFiles( config *csconfig.CrowdsecServiceCfg, prom *csconfig.PrometheusCfg, hub *cwhub.Hub, + clientConfig *csconfig.LocalApiClientCfg, ) ([]types.DataSource, error) { var allSources []types.DataSource metricsLevel := GetMetricsLevelFromPromCfg(prom) for _, acquisFile := range config.AcquisitionFiles { - sources, err := sourcesFromFile(ctx, acquisFile, metricsLevel, hub) + sources, err := sourcesFromFile(ctx, acquisFile, metricsLevel, hub, clientConfig) if err != nil { return nil, err } diff --git a/pkg/acquisition/acquisition_test.go b/pkg/acquisition/acquisition_test.go index a5f1de7c446..d414590d4e1 100644 --- a/pkg/acquisition/acquisition_test.go +++ b/pkg/acquisition/acquisition_test.go @@ -190,7 +190,7 @@ filename: foo.log err := yaml.Unmarshal([]byte(tc.String), &common) require.NoError(t, err) hub := cwhub.Hub{} - ds, err := DataSourceConfigure(ctx, common, []byte(tc.String), metrics.AcquisitionMetricsLevelNone, &hub) + ds, err := DataSourceConfigure(ctx, common, []byte(tc.String), metrics.AcquisitionMetricsLevelNone, &hub, nil) cstest.RequireErrorContains(t, err, tc.ExpectedError) if tc.ExpectedError != "" { @@ -302,7 +302,7 @@ func TestLoadAcquisitionFromFiles(t *testing.T) { for _, tc := range tests { t.Run(tc.TestName, func(t *testing.T) { hub := cwhub.Hub{} - dss, err := LoadAcquisitionFromFiles(ctx, &tc.Config, nil, &hub) + dss, err := LoadAcquisitionFromFiles(ctx, &tc.Config, nil, &hub, nil) cstest.RequireErrorContains(t, err, tc.ExpectedError) if tc.ExpectedError != "" { @@ -564,7 +564,7 @@ func TestConfigureByDSN(t *testing.T) { for _, tc := range tests { t.Run(tc.dsn, func(t *testing.T) { hub := cwhub.Hub{} - source, err := LoadAcquisitionFromDSN(ctx, tc.dsn, map[string]string{"type": "test_label"}, "", &hub) + source, err := LoadAcquisitionFromDSN(ctx, tc.dsn, map[string]string{"type": "test_label"}, "", &hub, nil) cstest.RequireErrorContains(t, err, tc.ExpectedError) if tc.ExpectedError != "" { diff --git a/pkg/acquisition/config_test.go b/pkg/acquisition/config_test.go index 89c0827a881..2b23611ed93 100644 --- a/pkg/acquisition/config_test.go +++ b/pkg/acquisition/config_test.go @@ -137,7 +137,18 @@ func TestParseSourceConfig(t *testing.T) { if s.expectValid { require.False(t, hasWant, "valid config must not include # wantErr: directive") - parsed, err := ParseSourceConfig(ctx, fileContent, metrics.AcquisitionMetricsLevelNone, &hub) + + // Provide mock client config for appsec datasources + var clientConfig *csconfig.LocalApiClientCfg + if strings.Contains(path, "appsec") { + clientConfig = &csconfig.LocalApiClientCfg{ + Credentials: &csconfig.ApiCredentialsCfg{ + URL: "http://localhost:8080/", + }, + } + } + + parsed, err := ParseSourceConfig(ctx, fileContent, metrics.AcquisitionMetricsLevelNone, &hub, clientConfig) require.NoError(t, err) require.NotNil(t, parsed) if schema != "" { @@ -155,7 +166,23 @@ func TestParseSourceConfig(t *testing.T) { require.True(t, hasWant, "invalid config must include '# wantErr: '") require.NotEmpty(t, wantErr, "wantErr directive found but empty") - parsed, err := ParseSourceConfig(ctx, fileContent, metrics.AcquisitionMetricsLevelNone, &hub) + // Provide mock client config for appsec datasources that need it + var clientConfig *csconfig.LocalApiClientCfg + if strings.Contains(path, "appsec") { + if strings.Contains(wantErr, "missing lapi client credentials") { + // For this specific test, provide clientConfig but without Credentials + clientConfig = &csconfig.LocalApiClientCfg{} + } else { + // For other appsec tests, provide full mock config + clientConfig = &csconfig.LocalApiClientCfg{ + Credentials: &csconfig.ApiCredentialsCfg{ + URL: "http://localhost:8080/", + }, + } + } + } + + parsed, err := ParseSourceConfig(ctx, fileContent, metrics.AcquisitionMetricsLevelNone, &hub, clientConfig) require.Error(t, err, "got no error, expected %q", wantErr) require.Nil(t, parsed) assert.Equal(t, wantErr, err.Error()) diff --git a/pkg/apiserver/apic_metrics.go b/pkg/apiserver/apic_metrics.go index 6ad379c1d45..b76cec3ec8a 100644 --- a/pkg/apiserver/apic_metrics.go +++ b/pkg/apiserver/apic_metrics.go @@ -14,7 +14,6 @@ import ( "github.com/crowdsecurity/go-cs-lib/trace" "github.com/crowdsecurity/go-cs-lib/version" - "github.com/crowdsecurity/crowdsec/pkg/csconfig" "github.com/crowdsecurity/crowdsec/pkg/fflag" "github.com/crowdsecurity/crowdsec/pkg/models" ) @@ -145,7 +144,7 @@ func (a *apic) GetUsageMetrics(ctx context.Context) (*models.AllMetrics, []int, } // FIXME: all of this should only be done once on startup/reload - consoleOptions := strings.Join(csconfig.GetConfig().API.Server.ConsoleConfig.EnabledOptions(), ",") + consoleOptions := strings.Join(a.consoleConfig.EnabledOptions(), ",") allMetrics.Lapi = &models.LapiMetrics{ ConsoleOptions: models.ConsoleOptions{ consoleOptions, diff --git a/pkg/csconfig/config.go b/pkg/csconfig/config.go index 424036691f3..2a62613b526 100644 --- a/pkg/csconfig/config.go +++ b/pkg/csconfig/config.go @@ -25,8 +25,6 @@ var defaultConfigDir = "/etc/crowdsec" // defaultDataDir is the base path to all data files, to be overridden in the Makefile */ var defaultDataDir = "/var/lib/crowdsec/data/" -var globalConfig = Config{} - // Config contains top-level defaults -> overridden by configuration file -> overridden by CLI flags type Config struct { // just a path to ourselves :p @@ -97,15 +95,9 @@ func NewConfig(configFile string, disableAgent bool, disableAPI bool, quiet bool cfg.loadHub() cfg.loadCSCLI() - globalConfig = cfg - return &cfg, configData, nil } -func GetConfig() Config { - return globalConfig -} - func NewDefaultConfig() *Config { commonCfg := CommonCfg{ LogLevel: log.InfoLevel,