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  }