csprofiles_test.go 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220
  1. package csprofiles
  2. import (
  3. "fmt"
  4. "reflect"
  5. "testing"
  6. "github.com/stretchr/testify/require"
  7. "github.com/crowdsecurity/crowdsec/pkg/csconfig"
  8. "github.com/crowdsecurity/crowdsec/pkg/exprhelpers"
  9. "github.com/crowdsecurity/crowdsec/pkg/models"
  10. )
  11. var (
  12. scope = "Country"
  13. typ = "ban"
  14. boolFalse = false
  15. boolTrue = true
  16. duration = "1h"
  17. value = "CH"
  18. scenario = "ssh-bf"
  19. )
  20. func TestNewProfile(t *testing.T) {
  21. tests := []struct {
  22. name string
  23. profileCfg *csconfig.ProfileCfg
  24. expectedNbProfile int
  25. }{
  26. {
  27. name: "filter ok and duration_expr ok",
  28. profileCfg: &csconfig.ProfileCfg{
  29. Filters: []string{
  30. "1==1",
  31. },
  32. DurationExpr: "1==1",
  33. Debug: &boolFalse,
  34. Decisions: []models.Decision{
  35. {Type: &typ, Scope: &scope, Simulated: &boolTrue, Duration: &duration},
  36. },
  37. },
  38. expectedNbProfile: 1,
  39. },
  40. {
  41. name: "filter NOK and duration_expr ok",
  42. profileCfg: &csconfig.ProfileCfg{
  43. Filters: []string{
  44. "1==1",
  45. "unknownExprHelper() == 'foo'",
  46. },
  47. DurationExpr: "1==1",
  48. Debug: &boolFalse,
  49. Decisions: []models.Decision{
  50. {Type: &typ, Scope: &scope, Simulated: &boolFalse, Duration: &duration},
  51. },
  52. },
  53. expectedNbProfile: 0,
  54. },
  55. {
  56. name: "filter ok and duration_expr NOK",
  57. profileCfg: &csconfig.ProfileCfg{
  58. Filters: []string{
  59. "1==1",
  60. },
  61. DurationExpr: "unknownExprHelper() == 'foo'",
  62. Debug: &boolFalse,
  63. Decisions: []models.Decision{
  64. {Type: &typ, Scope: &scope, Simulated: &boolFalse, Duration: &duration},
  65. },
  66. },
  67. expectedNbProfile: 0,
  68. },
  69. {
  70. name: "filter ok and duration_expr ok + DEBUG",
  71. profileCfg: &csconfig.ProfileCfg{
  72. Filters: []string{
  73. "1==1",
  74. },
  75. DurationExpr: "1==1",
  76. Debug: &boolTrue,
  77. Decisions: []models.Decision{
  78. {Type: &typ, Scope: &scope, Simulated: &boolFalse, Duration: &duration},
  79. },
  80. },
  81. expectedNbProfile: 1,
  82. },
  83. {
  84. name: "filter ok and no duration",
  85. profileCfg: &csconfig.ProfileCfg{
  86. Filters: []string{
  87. "1==1",
  88. },
  89. Debug: &boolTrue,
  90. Decisions: []models.Decision{
  91. {Type: &typ, Scope: &scope, Simulated: &boolFalse},
  92. },
  93. },
  94. expectedNbProfile: 1,
  95. },
  96. }
  97. for _, test := range tests {
  98. test := test
  99. t.Run(test.name, func(t *testing.T) {
  100. profilesCfg := []*csconfig.ProfileCfg{
  101. test.profileCfg,
  102. }
  103. profile, _ := NewProfile(profilesCfg)
  104. fmt.Printf("expected : %+v | result : %+v", test.expectedNbProfile, len(profile))
  105. require.Len(t, profile, test.expectedNbProfile)
  106. })
  107. }
  108. }
  109. func TestEvaluateProfile(t *testing.T) {
  110. type args struct {
  111. profileCfg *csconfig.ProfileCfg
  112. Alert *models.Alert
  113. }
  114. exprhelpers.Init(nil)
  115. tests := []struct {
  116. name string
  117. args args
  118. expectedDecisionCount int // count of expected decisions
  119. expectedDuration string
  120. expectedMatchStatus bool
  121. }{
  122. {
  123. name: "simple pass single expr",
  124. args: args{
  125. profileCfg: &csconfig.ProfileCfg{
  126. Filters: []string{fmt.Sprintf("Alert.GetScenario() == \"%s\"", scenario)},
  127. Debug: &boolFalse,
  128. },
  129. Alert: &models.Alert{Remediation: true, Scenario: &scenario},
  130. },
  131. expectedDecisionCount: 0,
  132. expectedMatchStatus: true,
  133. },
  134. {
  135. name: "simple fail single expr",
  136. args: args{
  137. profileCfg: &csconfig.ProfileCfg{
  138. Filters: []string{"Alert.GetScenario() == \"Foo\""},
  139. },
  140. Alert: &models.Alert{Remediation: true},
  141. },
  142. expectedDecisionCount: 0,
  143. expectedMatchStatus: false,
  144. },
  145. {
  146. name: "1 expr fail 1 expr pass should still eval to match",
  147. args: args{
  148. profileCfg: &csconfig.ProfileCfg{
  149. Filters: []string{"1==1", "1!=1"},
  150. },
  151. Alert: &models.Alert{Remediation: true},
  152. },
  153. expectedDecisionCount: 0,
  154. expectedMatchStatus: true,
  155. },
  156. {
  157. name: "simple filter with 2 decision",
  158. args: args{
  159. profileCfg: &csconfig.ProfileCfg{
  160. Filters: []string{"1==1"},
  161. Decisions: []models.Decision{
  162. {Type: &typ, Scope: &scope, Simulated: &boolTrue, Duration: &duration},
  163. {Type: &typ, Scope: &scope, Simulated: &boolFalse, Duration: &duration},
  164. },
  165. },
  166. Alert: &models.Alert{Remediation: true, Scenario: &scenario, Source: &models.Source{Value: &value}},
  167. },
  168. expectedDecisionCount: 2,
  169. expectedMatchStatus: true,
  170. },
  171. {
  172. name: "simple filter with decision_expr",
  173. args: args{
  174. profileCfg: &csconfig.ProfileCfg{
  175. Filters: []string{"1==1"},
  176. Decisions: []models.Decision{
  177. {Type: &typ, Scope: &scope, Simulated: &boolFalse},
  178. },
  179. DurationExpr: "Sprintf('%dh', 4*4)",
  180. },
  181. Alert: &models.Alert{Remediation: true, Scenario: &scenario, Source: &models.Source{Value: &value}},
  182. },
  183. expectedDecisionCount: 1,
  184. expectedDuration: "16h",
  185. expectedMatchStatus: true,
  186. },
  187. }
  188. for _, tt := range tests {
  189. tt := tt
  190. t.Run(tt.name, func(t *testing.T) {
  191. profilesCfg := []*csconfig.ProfileCfg{
  192. tt.args.profileCfg,
  193. }
  194. profile, err := NewProfile(profilesCfg)
  195. if err != nil {
  196. t.Errorf("failed to get newProfile : %+v", err)
  197. }
  198. got, got1, _ := profile[0].EvaluateProfile(tt.args.Alert)
  199. if !reflect.DeepEqual(len(got), tt.expectedDecisionCount) {
  200. t.Errorf("EvaluateProfile() got = %+v, want %+v", got, tt.expectedDecisionCount)
  201. }
  202. if got1 != tt.expectedMatchStatus {
  203. t.Errorf("EvaluateProfile() got1 = %v, want %v", got1, tt.expectedMatchStatus)
  204. }
  205. if tt.expectedDuration != "" {
  206. require.Equal(t, tt.expectedDuration, *got[0].Duration, "The two durations should be the same")
  207. }
  208. })
  209. }
  210. }