api_test.go 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312
  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: "failed to read api server credentials",
  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. },
  211. Common: &CommonCfg{
  212. LogDir: "./testdata/",
  213. LogMedia: "stdout",
  214. },
  215. DisableAPI: false,
  216. },
  217. expected: &LocalApiServerCfg{
  218. Enable: ptr.Of(true),
  219. PapiLogLevel: &logLevel,
  220. },
  221. expectedErr: "no database configuration provided",
  222. },
  223. }
  224. for _, tc := range tests {
  225. tc := tc
  226. t.Run(tc.name, func(t *testing.T) {
  227. err := tc.input.LoadAPIServer()
  228. cstest.RequireErrorContains(t, err, tc.expectedErr)
  229. if tc.expectedErr != "" {
  230. return
  231. }
  232. assert.Equal(t, tc.expected, tc.input.API.Server)
  233. })
  234. }
  235. }
  236. func mustParseCIDRNet(t *testing.T, s string) *net.IPNet {
  237. _, ipNet, err := net.ParseCIDR(s)
  238. require.NoError(t, err)
  239. return ipNet
  240. }
  241. func TestParseCapiWhitelists(t *testing.T) {
  242. tests := []struct {
  243. name string
  244. input string
  245. expected *CapiWhitelist
  246. expectedErr string
  247. }{
  248. {
  249. name: "empty file",
  250. input: "",
  251. expected: &CapiWhitelist{
  252. Ips: []net.IP{},
  253. Cidrs: []*net.IPNet{},
  254. },
  255. expectedErr: "empty file",
  256. },
  257. {
  258. name: "empty ip and cidr",
  259. input: `{"ips": [], "cidrs": []}`,
  260. expected: &CapiWhitelist{
  261. Ips: []net.IP{},
  262. Cidrs: []*net.IPNet{},
  263. },
  264. },
  265. {
  266. name: "some ip",
  267. input: `{"ips": ["1.2.3.4"]}`,
  268. expected: &CapiWhitelist{
  269. Ips: []net.IP{net.IPv4(1, 2, 3, 4)},
  270. Cidrs: []*net.IPNet{},
  271. },
  272. },
  273. {
  274. name: "some cidr",
  275. input: `{"cidrs": ["1.2.3.0/24"]}`,
  276. expected: &CapiWhitelist{
  277. Ips: []net.IP{},
  278. Cidrs: []*net.IPNet{mustParseCIDRNet(t, "1.2.3.0/24")},
  279. },
  280. },
  281. }
  282. for _, tc := range tests {
  283. tc := tc
  284. t.Run(tc.name, func(t *testing.T) {
  285. wl, err := parseCapiWhitelists(strings.NewReader(tc.input))
  286. cstest.RequireErrorContains(t, err, tc.expectedErr)
  287. if tc.expectedErr != "" {
  288. return
  289. }
  290. assert.Equal(t, tc.expected, wl)
  291. })
  292. }
  293. }