bitbucket.org/Aishee/synsec@v0.0.0-20210414005726-236fc01a153d/pkg/csconfig/profiles.go (about)

     1  package csconfig
     2  
     3  import (
     4  	"fmt"
     5  	"io"
     6  	"os"
     7  
     8  	"github.com/antonmedv/expr"
     9  	"github.com/antonmedv/expr/vm"
    10  	"bitbucket.org/Aishee/synsec/pkg/exprhelpers"
    11  	"bitbucket.org/Aishee/synsec/pkg/models"
    12  	"github.com/pkg/errors"
    13  	log "github.com/sirupsen/logrus"
    14  	"gopkg.in/yaml.v2"
    15  )
    16  
    17  //Profile structure(s) are used by the local API to "decide" what kind of decision should be applied when a scenario with an active remediation has been triggered
    18  type ProfileCfg struct {
    19  	Name           string                      `yaml:"name,omitempty"`
    20  	Debug          *bool                       `yaml:"debug,omitempty"`
    21  	Filters        []string                    `yaml:"filters,omitempty"` //A list of OR'ed expressions. the models.Alert object
    22  	RuntimeFilters []*vm.Program               `json:"-"`
    23  	DebugFilters   []*exprhelpers.ExprDebugger `json:"-"`
    24  	Decisions      []models.Decision           `yaml:"decisions,omitempty"`
    25  	OnSuccess      string                      `yaml:"on_success,omitempty"` //continue or break
    26  	OnFailure      string                      `yaml:"on_failure,omitempty"` //continue or break
    27  }
    28  
    29  func (c *LocalApiServerCfg) LoadProfiles() error {
    30  	if c.ProfilesPath == "" {
    31  		return fmt.Errorf("empty profiles path")
    32  	}
    33  
    34  	yamlFile, err := os.Open(c.ProfilesPath)
    35  	if err != nil {
    36  		return errors.Wrapf(err, "while opening %s", c.ProfilesPath)
    37  	}
    38  
    39  	//process the yaml
    40  	dec := yaml.NewDecoder(yamlFile)
    41  	dec.SetStrict(true)
    42  	for {
    43  		t := ProfileCfg{}
    44  		err = dec.Decode(&t)
    45  		if err != nil {
    46  			if err == io.EOF {
    47  				break
    48  			}
    49  			return errors.Wrapf(err, "while decoding %s", c.ProfilesPath)
    50  		}
    51  		c.Profiles = append(c.Profiles, &t)
    52  	}
    53  
    54  	for pIdx, profile := range c.Profiles {
    55  		var runtimeFilter *vm.Program
    56  		var debugFilter *exprhelpers.ExprDebugger
    57  
    58  		c.Profiles[pIdx].RuntimeFilters = make([]*vm.Program, len(profile.Filters))
    59  		c.Profiles[pIdx].DebugFilters = make([]*exprhelpers.ExprDebugger, len(profile.Filters))
    60  
    61  		for fIdx, filter := range profile.Filters {
    62  			if runtimeFilter, err = expr.Compile(filter, expr.Env(exprhelpers.GetExprEnv(map[string]interface{}{"Alert": &models.Alert{}}))); err != nil {
    63  				return errors.Wrapf(err, "Error compiling filter of %s", profile.Name)
    64  			}
    65  			c.Profiles[pIdx].RuntimeFilters[fIdx] = runtimeFilter
    66  			if debugFilter, err = exprhelpers.NewDebugger(filter, expr.Env(exprhelpers.GetExprEnv(map[string]interface{}{"Alert": &models.Alert{}}))); err != nil {
    67  				log.Debugf("Error compiling debug filter of %s : %s", profile.Name, err)
    68  				// Don't fail if we can't compile the filter - for now
    69  				//	return errors.Wrapf(err, "Error compiling debug filter of %s", profile.Name)
    70  			}
    71  			c.Profiles[pIdx].DebugFilters[fIdx] = debugFilter
    72  		}
    73  	}
    74  	if len(c.Profiles) == 0 {
    75  		return fmt.Errorf("zero profiles loaded for LAPI")
    76  	}
    77  	return nil
    78  }