github.com/crowdsecurity/crowdsec@v1.6.1/pkg/csconfig/api_test.go (about)

     1  package csconfig
     2  
     3  import (
     4  	"net"
     5  	"os"
     6  	"strings"
     7  	"testing"
     8  
     9  	log "github.com/sirupsen/logrus"
    10  	"github.com/stretchr/testify/assert"
    11  	"github.com/stretchr/testify/require"
    12  	"gopkg.in/yaml.v3"
    13  
    14  	"github.com/crowdsecurity/go-cs-lib/cstest"
    15  	"github.com/crowdsecurity/go-cs-lib/ptr"
    16  )
    17  
    18  func TestLoadLocalApiClientCfg(t *testing.T) {
    19  	tests := []struct {
    20  		name        string
    21  		input       *LocalApiClientCfg
    22  		expected    *ApiCredentialsCfg
    23  		expectedErr string
    24  	}{
    25  		{
    26  			name: "basic valid configuration",
    27  			input: &LocalApiClientCfg{
    28  				CredentialsFilePath: "./testdata/lapi-secrets.yaml",
    29  			},
    30  			expected: &ApiCredentialsCfg{
    31  				URL:      "http://localhost:8080/",
    32  				Login:    "test",
    33  				Password: "testpassword",
    34  			},
    35  		},
    36  		{
    37  			name: "invalid configuration",
    38  			input: &LocalApiClientCfg{
    39  				CredentialsFilePath: "./testdata/bad_lapi-secrets.yaml",
    40  			},
    41  			expected:    &ApiCredentialsCfg{},
    42  			expectedErr: "field unknown_key not found in type csconfig.ApiCredentialsCfg",
    43  		},
    44  		{
    45  			name: "invalid configuration filepath",
    46  			input: &LocalApiClientCfg{
    47  				CredentialsFilePath: "./testdata/nonexist_lapi-secrets.yaml",
    48  			},
    49  			expected:    nil,
    50  			expectedErr: "open ./testdata/nonexist_lapi-secrets.yaml: " + cstest.FileNotFoundMessage,
    51  		},
    52  		{
    53  			name: "valid configuration with insecure skip verify",
    54  			input: &LocalApiClientCfg{
    55  				CredentialsFilePath: "./testdata/lapi-secrets.yaml",
    56  				InsecureSkipVerify:  ptr.Of(false),
    57  			},
    58  			expected: &ApiCredentialsCfg{
    59  				URL:      "http://localhost:8080/",
    60  				Login:    "test",
    61  				Password: "testpassword",
    62  			},
    63  		},
    64  	}
    65  
    66  	for _, tc := range tests {
    67  		tc := tc
    68  		t.Run(tc.name, func(t *testing.T) {
    69  			err := tc.input.Load()
    70  			cstest.RequireErrorContains(t, err, tc.expectedErr)
    71  
    72  			if tc.expectedErr != "" {
    73  				return
    74  			}
    75  
    76  			assert.Equal(t, tc.expected, tc.input.Credentials)
    77  		})
    78  	}
    79  }
    80  
    81  func TestLoadOnlineApiClientCfg(t *testing.T) {
    82  	tests := []struct {
    83  		name        string
    84  		input       *OnlineApiClientCfg
    85  		expected    *ApiCredentialsCfg
    86  		expectedErr string
    87  	}{
    88  		{
    89  			name: "basic valid configuration",
    90  			input: &OnlineApiClientCfg{
    91  				CredentialsFilePath: "./testdata/online-api-secrets.yaml",
    92  			},
    93  			expected: &ApiCredentialsCfg{
    94  				URL:      "http://crowdsec.api",
    95  				Login:    "test",
    96  				Password: "testpassword",
    97  			},
    98  		},
    99  		{
   100  			name: "invalid configuration",
   101  			input: &OnlineApiClientCfg{
   102  				CredentialsFilePath: "./testdata/bad_lapi-secrets.yaml",
   103  			},
   104  			expected:    &ApiCredentialsCfg{},
   105  			expectedErr: "failed unmarshaling api server credentials",
   106  		},
   107  		{
   108  			name: "missing field configuration",
   109  			input: &OnlineApiClientCfg{
   110  				CredentialsFilePath: "./testdata/bad_online-api-secrets.yaml",
   111  			},
   112  			expected: nil,
   113  		},
   114  		{
   115  			name: "invalid configuration filepath",
   116  			input: &OnlineApiClientCfg{
   117  				CredentialsFilePath: "./testdata/nonexist_online-api-secrets.yaml",
   118  			},
   119  			expected:    &ApiCredentialsCfg{},
   120  			expectedErr: "open ./testdata/nonexist_online-api-secrets.yaml: " + cstest.FileNotFoundMessage,
   121  		},
   122  	}
   123  
   124  	for _, tc := range tests {
   125  		tc := tc
   126  		t.Run(tc.name, func(t *testing.T) {
   127  			err := tc.input.Load()
   128  			cstest.RequireErrorContains(t, err, tc.expectedErr)
   129  
   130  			if tc.expectedErr != "" {
   131  				return
   132  			}
   133  
   134  			assert.Equal(t, tc.expected, tc.input.Credentials)
   135  		})
   136  	}
   137  }
   138  
   139  func TestLoadAPIServer(t *testing.T) {
   140  	tmpLAPI := &LocalApiServerCfg{
   141  		ProfilesPath: "./testdata/profiles.yaml",
   142  	}
   143  	err := tmpLAPI.LoadProfiles()
   144  	require.NoError(t, err)
   145  
   146  	logLevel := log.InfoLevel
   147  	config := &Config{}
   148  	fcontent, err := os.ReadFile("./testdata/config.yaml")
   149  	require.NoError(t, err)
   150  
   151  	configData := os.ExpandEnv(string(fcontent))
   152  
   153  	dec := yaml.NewDecoder(strings.NewReader(configData))
   154  	dec.KnownFields(true)
   155  
   156  	err = dec.Decode(&config)
   157  	require.NoError(t, err)
   158  
   159  	tests := []struct {
   160  		name        string
   161  		input       *Config
   162  		expected    *LocalApiServerCfg
   163  		expectedErr string
   164  	}{
   165  		{
   166  			name: "basic valid configuration",
   167  			input: &Config{
   168  				Self: []byte(configData),
   169  				API: &APICfg{
   170  					Server: &LocalApiServerCfg{
   171  						ListenURI: "http://crowdsec.api",
   172  						OnlineClient: &OnlineApiClientCfg{
   173  							CredentialsFilePath: "./testdata/online-api-secrets.yaml",
   174  						},
   175  						ProfilesPath: "./testdata/profiles.yaml",
   176  						PapiLogLevel: &logLevel,
   177  					},
   178  				},
   179  				DbConfig: &DatabaseCfg{
   180  					Type:   "sqlite",
   181  					DbPath: "./testdata/test.db",
   182  				},
   183  				Common: &CommonCfg{
   184  					LogDir:   "./testdata",
   185  					LogMedia: "stdout",
   186  				},
   187  				DisableAPI: false,
   188  			},
   189  			expected: &LocalApiServerCfg{
   190  				Enable:    ptr.Of(true),
   191  				ListenURI: "http://crowdsec.api",
   192  				TLS:       nil,
   193  				DbConfig: &DatabaseCfg{
   194  					DbPath:           "./testdata/test.db",
   195  					Type:             "sqlite",
   196  					MaxOpenConns:     ptr.Of(DEFAULT_MAX_OPEN_CONNS),
   197  					UseWal:           ptr.Of(true), // autodetected
   198  					DecisionBulkSize: defaultDecisionBulkSize,
   199  				},
   200  				ConsoleConfigPath: DefaultConfigPath("console.yaml"),
   201  				ConsoleConfig: &ConsoleConfig{
   202  					ShareManualDecisions:  ptr.Of(false),
   203  					ShareTaintedScenarios: ptr.Of(true),
   204  					ShareCustomScenarios:  ptr.Of(true),
   205  					ShareContext:          ptr.Of(false),
   206  					ConsoleManagement:     ptr.Of(false),
   207  				},
   208  				LogDir:   "./testdata",
   209  				LogMedia: "stdout",
   210  				OnlineClient: &OnlineApiClientCfg{
   211  					CredentialsFilePath: "./testdata/online-api-secrets.yaml",
   212  					Credentials: &ApiCredentialsCfg{
   213  						URL:      "http://crowdsec.api",
   214  						Login:    "test",
   215  						Password: "testpassword",
   216  					},
   217  				},
   218  				Profiles:               tmpLAPI.Profiles,
   219  				ProfilesPath:           "./testdata/profiles.yaml",
   220  				UseForwardedForHeaders: false,
   221  				PapiLogLevel:           &logLevel,
   222  			},
   223  		},
   224  		{
   225  			name: "basic invalid configuration",
   226  			input: &Config{
   227  				Self: []byte(configData),
   228  				API: &APICfg{
   229  					Server: &LocalApiServerCfg{
   230  						ListenURI: "http://crowdsec.api",
   231  					},
   232  				},
   233  				Common: &CommonCfg{
   234  					LogDir:   "./testdata/",
   235  					LogMedia: "stdout",
   236  				},
   237  				DisableAPI: false,
   238  			},
   239  			expected: &LocalApiServerCfg{
   240  				Enable:       ptr.Of(true),
   241  				PapiLogLevel: &logLevel,
   242  			},
   243  			expectedErr: "no database configuration provided",
   244  		},
   245  	}
   246  
   247  	for _, tc := range tests {
   248  		tc := tc
   249  		t.Run(tc.name, func(t *testing.T) {
   250  			err := tc.input.LoadAPIServer(false)
   251  			cstest.RequireErrorContains(t, err, tc.expectedErr)
   252  
   253  			if tc.expectedErr != "" {
   254  				return
   255  			}
   256  
   257  			assert.Equal(t, tc.expected, tc.input.API.Server)
   258  		})
   259  	}
   260  }
   261  
   262  func mustParseCIDRNet(t *testing.T, s string) *net.IPNet {
   263  	_, ipNet, err := net.ParseCIDR(s)
   264  	require.NoError(t, err)
   265  
   266  	return ipNet
   267  }
   268  
   269  func TestParseCapiWhitelists(t *testing.T) {
   270  	tests := []struct {
   271  		name        string
   272  		input       string
   273  		expected    *CapiWhitelist
   274  		expectedErr string
   275  	}{
   276  		{
   277  			name:  "empty file",
   278  			input: "",
   279  			expected: &CapiWhitelist{
   280  				Ips:   []net.IP{},
   281  				Cidrs: []*net.IPNet{},
   282  			},
   283  			expectedErr: "empty file",
   284  		},
   285  		{
   286  			name:  "empty ip and cidr",
   287  			input: `{"ips": [], "cidrs": []}`,
   288  			expected: &CapiWhitelist{
   289  				Ips:   []net.IP{},
   290  				Cidrs: []*net.IPNet{},
   291  			},
   292  		},
   293  		{
   294  			name:  "some ip",
   295  			input: `{"ips": ["1.2.3.4"]}`,
   296  			expected: &CapiWhitelist{
   297  				Ips:   []net.IP{net.IPv4(1, 2, 3, 4)},
   298  				Cidrs: []*net.IPNet{},
   299  			},
   300  		},
   301  		{
   302  			name:  "some cidr",
   303  			input: `{"cidrs": ["1.2.3.0/24"]}`,
   304  			expected: &CapiWhitelist{
   305  				Ips:   []net.IP{},
   306  				Cidrs: []*net.IPNet{mustParseCIDRNet(t, "1.2.3.0/24")},
   307  			},
   308  		},
   309  	}
   310  
   311  	for _, tc := range tests {
   312  		tc := tc
   313  		t.Run(tc.name, func(t *testing.T) {
   314  			wl, err := parseCapiWhitelists(strings.NewReader(tc.input))
   315  			cstest.RequireErrorContains(t, err, tc.expectedErr)
   316  
   317  			if tc.expectedErr != "" {
   318  				return
   319  			}
   320  
   321  			assert.Equal(t, tc.expected, wl)
   322  		})
   323  	}
   324  }