bitbucket.org/Aishee/synsec@v0.0.0-20210414005726-236fc01a153d/pkg/csprofiles/csprofiles.go (about) 1 package csprofiles 2 3 import ( 4 "fmt" 5 6 "github.com/antonmedv/expr" 7 "bitbucket.org/Aishee/synsec/pkg/csconfig" 8 "bitbucket.org/Aishee/synsec/pkg/exprhelpers" 9 "bitbucket.org/Aishee/synsec/pkg/models" 10 "bitbucket.org/Aishee/synsec/pkg/types" 11 "github.com/pkg/errors" 12 log "github.com/sirupsen/logrus" 13 ) 14 15 func GenerateDecisionFromProfile(Profile *csconfig.ProfileCfg, Alert *models.Alert) ([]*models.Decision, error) { 16 var decisions []*models.Decision 17 18 for _, refDecision := range Profile.Decisions { 19 decision := models.Decision{} 20 /*the reference decision from profile is in sumulated mode */ 21 if refDecision.Simulated != nil && *refDecision.Simulated { 22 decision.Simulated = new(bool) 23 *decision.Simulated = true 24 /*the event is already in simulation mode */ 25 } else if Alert.Simulated != nil && *Alert.Simulated { 26 decision.Simulated = new(bool) 27 *decision.Simulated = true 28 } 29 /*If the profile specifies a scope, this will prevail. 30 If not, we're going to get the scope from the source itself*/ 31 decision.Scope = new(string) 32 if refDecision.Scope != nil && *refDecision.Scope != "" { 33 *decision.Scope = *refDecision.Scope 34 } else { 35 *decision.Scope = *Alert.Source.Scope 36 } 37 /*some fields are populated from the reference object : duration, scope, type*/ 38 decision.Duration = new(string) 39 *decision.Duration = *refDecision.Duration 40 decision.Type = new(string) 41 *decision.Type = *refDecision.Type 42 43 /*for the others, let's populate it from the alert and its source*/ 44 decision.Value = new(string) 45 *decision.Value = *Alert.Source.Value 46 decision.Origin = new(string) 47 *decision.Origin = "synsec" 48 if refDecision.Origin != nil { 49 *decision.Origin = fmt.Sprintf("%s/%s", *decision.Origin, *refDecision.Origin) 50 } 51 decision.Scenario = new(string) 52 *decision.Scenario = *Alert.Scenario 53 decisions = append(decisions, &decision) 54 } 55 return decisions, nil 56 } 57 58 var clog *log.Entry 59 60 //EvaluateProfiles is going to evaluate an Alert against a set of profiles to generate Decisions 61 func EvaluateProfiles(Profiles []*csconfig.ProfileCfg, Alert *models.Alert) ([]*models.Decision, error) { 62 var decisions []*models.Decision 63 64 if clog == nil { 65 xlog := log.New() 66 if err := types.ConfigureLogger(xlog); err != nil { 67 log.Fatalf("While creating profiles-specific logger : %s", err) 68 } 69 xlog.SetLevel(log.TraceLevel) 70 clog = xlog.WithFields(log.Fields{ 71 "type": "profile", 72 }) 73 } 74 75 if !Alert.Remediation { 76 return nil, nil 77 } 78 PROFILE_LOOP: 79 for _, profile := range Profiles { 80 matched := false 81 for eIdx, expression := range profile.RuntimeFilters { 82 output, err := expr.Run(expression, exprhelpers.GetExprEnv(map[string]interface{}{"Alert": Alert})) 83 if err != nil { 84 log.Warningf("failed to run whitelist expr : %v", err) 85 return nil, errors.Wrapf(err, "while running expression %s", profile.Filters[eIdx]) 86 } 87 switch out := output.(type) { 88 case bool: 89 if out { 90 matched = true 91 /*the expression matched, create the associated decision*/ 92 subdecisions, err := GenerateDecisionFromProfile(profile, Alert) 93 if err != nil { 94 return nil, errors.Wrapf(err, "while generating decision from profile %s", profile.Name) 95 } 96 97 decisions = append(decisions, subdecisions...) 98 } else { 99 if profile.Debug != nil && *profile.Debug { 100 profile.DebugFilters[eIdx].Run(clog, false, exprhelpers.GetExprEnv(map[string]interface{}{"Alert": Alert})) 101 } 102 log.Debugf("Profile %s filter is unsuccessful", profile.Name) 103 if profile.OnFailure == "break" { 104 break PROFILE_LOOP 105 } 106 } 107 108 default: 109 return nil, fmt.Errorf("unexpected type %t (%v) while running '%s'", output, output, profile.Filters[eIdx]) 110 111 } 112 113 } 114 if matched { 115 if profile.OnSuccess == "break" { 116 break PROFILE_LOOP 117 } 118 } 119 } 120 return decisions, nil 121 }