github.com/DataDog/datadog-agent/pkg/security/secl@v0.55.0-devel.0.20240517055856-10c4965fea94/rules/evaluation_set.go (about)

     1  // Unless explicitly stated otherwise all files in this repository are licensed
     2  // under the Apache License Version 2.0.
     3  // This product includes software developed at Datadog (https://www.datadoghq.com/).
     4  // Copyright 2016-present Datadog, Inc.
     5  
     6  // Package rules holds rules related files
     7  package rules
     8  
     9  import (
    10  	"fmt"
    11  
    12  	"github.com/DataDog/datadog-agent/pkg/security/secl/compiler/ast"
    13  	"github.com/DataDog/datadog-agent/pkg/security/secl/compiler/eval"
    14  	"github.com/hashicorp/go-multierror"
    15  )
    16  
    17  // EvaluationSet defines an evalation set
    18  type EvaluationSet struct {
    19  	RuleSets map[eval.RuleSetTagValue]*RuleSet
    20  }
    21  
    22  // NewEvaluationSet returns a new policy set for the specified data model
    23  func NewEvaluationSet(ruleSetsToInclude []*RuleSet) (*EvaluationSet, error) {
    24  	ruleSets := make(map[string]*RuleSet)
    25  
    26  	if len(ruleSetsToInclude) == 0 {
    27  		return nil, ErrNoRuleSetsInEvaluationSet
    28  	}
    29  
    30  	for _, ruleSet := range ruleSetsToInclude {
    31  		if ruleSet != nil {
    32  			ruleSets[ruleSet.GetRuleSetTag()] = ruleSet
    33  		} else {
    34  			return nil, fmt.Errorf("nil rule set with tag value %s provided include in an evaluation set", ruleSet.GetRuleSetTag())
    35  		}
    36  	}
    37  
    38  	return &EvaluationSet{RuleSets: ruleSets}, nil
    39  }
    40  
    41  // GetPolicies returns the policies
    42  func (es *EvaluationSet) GetPolicies() []*Policy {
    43  	var policies []*Policy
    44  
    45  	seen := make(map[string]bool)
    46  
    47  	for _, rs := range es.RuleSets {
    48  		for _, policy := range rs.policies {
    49  			if _, ok := seen[policy.Name]; !ok {
    50  				seen[policy.Name] = true
    51  				policies = append(policies, policy)
    52  			}
    53  		}
    54  	}
    55  
    56  	return policies
    57  }
    58  
    59  type ruleIndexEntry struct {
    60  	value  eval.RuleSetTagValue
    61  	ruleID eval.RuleID
    62  }
    63  
    64  // LoadPolicies load policies
    65  func (es *EvaluationSet) LoadPolicies(loader *PolicyLoader, opts PolicyLoaderOpts) *multierror.Error {
    66  	var (
    67  		errs       *multierror.Error
    68  		rules      = make(map[eval.RuleSetTagValue][]*RuleDefinition)
    69  		allMacros  []*MacroDefinition
    70  		macroIndex = make(map[string]*MacroDefinition)
    71  		rulesIndex = make(map[ruleIndexEntry]*RuleDefinition)
    72  	)
    73  
    74  	parsingContext := ast.NewParsingContext()
    75  
    76  	policies, err := loader.LoadPolicies(opts)
    77  	if err != nil {
    78  		errs = multierror.Append(errs, err)
    79  	}
    80  	for _, rs := range es.RuleSets {
    81  		rs.policies = policies
    82  	}
    83  
    84  	for _, policy := range policies {
    85  		for _, macro := range policy.Macros {
    86  			if existingMacro := macroIndex[macro.ID]; existingMacro != nil {
    87  				if err := existingMacro.MergeWith(macro); err != nil {
    88  					errs = multierror.Append(errs, err)
    89  				}
    90  			} else {
    91  				macroIndex[macro.ID] = macro
    92  				allMacros = append(allMacros, macro)
    93  			}
    94  		}
    95  
    96  		for _, rule := range policy.Rules {
    97  			tagValue, _ := rule.GetTag("ruleset")
    98  			if tagValue == "" {
    99  				tagValue = DefaultRuleSetTagValue
   100  			}
   101  
   102  			if existingRule := rulesIndex[ruleIndexEntry{tagValue, rule.ID}]; existingRule != nil {
   103  				if err := existingRule.MergeWith(rule); err != nil {
   104  					errs = multierror.Append(errs, err)
   105  				}
   106  			} else {
   107  				rulesIndex[ruleIndexEntry{tagValue, rule.ID}] = rule
   108  				rules[tagValue] = append(rules[tagValue], rule)
   109  			}
   110  		}
   111  	}
   112  
   113  	for ruleSetTagValue, rs := range es.RuleSets {
   114  		for rulesIndexTagValue, ruleList := range rules {
   115  			if rulesIndexTagValue == ruleSetTagValue {
   116  				// Add the macros to the ruleset and generate macros evaluators
   117  				if err := rs.AddMacros(parsingContext, allMacros); err.ErrorOrNil() != nil {
   118  					errs = multierror.Append(errs, err)
   119  				}
   120  
   121  				if err := rs.populateFieldsWithRuleActionsData(ruleList, opts); err.ErrorOrNil() != nil {
   122  					errs = multierror.Append(errs, err)
   123  				}
   124  
   125  				// Add rules to the ruleset and generate rules evaluators
   126  				if err := rs.AddRules(parsingContext, ruleList); err.ErrorOrNil() != nil {
   127  					errs = multierror.Append(errs, err)
   128  				}
   129  			}
   130  		}
   131  	}
   132  
   133  	for ruleSetTag, ruleSet := range es.RuleSets {
   134  		if ruleSet == nil {
   135  			delete(es.RuleSets, ruleSetTag)
   136  		}
   137  	}
   138  
   139  	return errs
   140  }