api_test.go 7.5 KB

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