github.com/DataDog/datadog-agent/pkg/security/secl@v0.55.0-devel.0.20240517055856-10c4965fea94/compiler/eval/macro.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 eval holds eval related files
     7  package eval
     8  
     9  import (
    10  	"fmt"
    11  
    12  	"github.com/DataDog/datadog-agent/pkg/security/secl/compiler/ast"
    13  )
    14  
    15  // MacroID - ID of a Macro
    16  type MacroID = string
    17  
    18  // Macro - Macro object identified by an `ID` containing a SECL `Expression`
    19  type Macro struct {
    20  	ID   MacroID
    21  	Opts *Opts
    22  
    23  	evaluator *MacroEvaluator
    24  	ast       *ast.Macro
    25  }
    26  
    27  // MacroEvaluator - Evaluation part of a Macro
    28  type MacroEvaluator struct {
    29  	Value      interface{}
    30  	EventTypes []EventType
    31  
    32  	fieldValues map[Field][]FieldValue
    33  	fields      []Field
    34  }
    35  
    36  // NewMacro parses an expression and returns a new macro
    37  func NewMacro(id, expression string, model Model, parsingContext *ast.ParsingContext, opts *Opts) (*Macro, error) {
    38  	macro := &Macro{
    39  		ID:   id,
    40  		Opts: opts,
    41  	}
    42  
    43  	if err := macro.Parse(parsingContext, expression); err != nil {
    44  		return nil, fmt.Errorf("syntax error: %w", err)
    45  	}
    46  
    47  	if err := macro.GenEvaluator(expression, model); err != nil {
    48  		return nil, fmt.Errorf("compilation error: %w", err)
    49  	}
    50  
    51  	return macro, nil
    52  }
    53  
    54  // NewStringValuesMacro returns a new macro from an array of strings
    55  func NewStringValuesMacro(id string, values []string, opts *Opts) (*Macro, error) {
    56  	var evaluator StringValuesEvaluator
    57  	for _, value := range values {
    58  		fieldValue := FieldValue{
    59  			Type:  ScalarValueType,
    60  			Value: value,
    61  		}
    62  
    63  		evaluator.Values.AppendFieldValue(fieldValue)
    64  	}
    65  
    66  	if err := evaluator.Compile(DefaultStringCmpOpts); err != nil {
    67  		return nil, err
    68  	}
    69  
    70  	return &Macro{
    71  		ID:        id,
    72  		Opts:      opts,
    73  		evaluator: &MacroEvaluator{Value: &evaluator},
    74  	}, nil
    75  }
    76  
    77  // GetEvaluator - Returns the MacroEvaluator of the Macro corresponding to the SECL `Expression`
    78  func (m *Macro) GetEvaluator() *MacroEvaluator {
    79  	return m.evaluator
    80  }
    81  
    82  // GetAst - Returns the representation of the SECL `Expression`
    83  func (m *Macro) GetAst() *ast.Macro {
    84  	return m.ast
    85  }
    86  
    87  // Parse - Transforms the SECL `Expression` into its AST representation
    88  func (m *Macro) Parse(parsingContext *ast.ParsingContext, expression string) error {
    89  	astMacro, err := parsingContext.ParseMacro(expression)
    90  	if err != nil {
    91  		return err
    92  	}
    93  	m.ast = astMacro
    94  	return nil
    95  }
    96  
    97  func macroToEvaluator(macro *ast.Macro, model Model, opts *Opts, field Field) (*MacroEvaluator, error) {
    98  	macros := make(map[MacroID]*MacroEvaluator)
    99  	for _, macro := range opts.MacroStore.List() {
   100  		macros[macro.ID] = macro.evaluator
   101  	}
   102  	state := NewState(model, field, macros)
   103  
   104  	var eval interface{}
   105  	var err error
   106  
   107  	switch {
   108  	case macro.Expression != nil:
   109  		eval, _, err = nodeToEvaluator(macro.Expression, opts, state)
   110  	case macro.Array != nil:
   111  		eval, _, err = nodeToEvaluator(macro.Array, opts, state)
   112  	case macro.Primary != nil:
   113  		eval, _, err = nodeToEvaluator(macro.Primary, opts, state)
   114  	}
   115  
   116  	if err != nil {
   117  		return nil, err
   118  	}
   119  
   120  	events, err := eventTypesFromFields(model, state)
   121  	if err != nil {
   122  		return nil, err
   123  	}
   124  
   125  	return &MacroEvaluator{
   126  		Value:      eval,
   127  		EventTypes: events,
   128  
   129  		fieldValues: state.fieldValues,
   130  		fields:      KeysOfMap(state.fieldValues),
   131  	}, nil
   132  }
   133  
   134  // GenEvaluator - Compiles and generates the evalutor
   135  func (m *Macro) GenEvaluator(expression string, model Model) error {
   136  	evaluator, err := macroToEvaluator(m.ast, model, m.Opts, "")
   137  	if err != nil {
   138  		if err, ok := err.(*ErrAstToEval); ok {
   139  			return fmt.Errorf("macro syntax error: %w", &ErrRuleParse{pos: err.Pos, expr: expression})
   140  		}
   141  		return fmt.Errorf("macro compilation error: %w", err)
   142  	}
   143  	m.evaluator = evaluator
   144  
   145  	return nil
   146  }
   147  
   148  // GetEventTypes - Returns a list of all the Event Type that the `Expression` handles
   149  func (m *Macro) GetEventTypes() []EventType {
   150  	eventTypes := m.evaluator.EventTypes
   151  
   152  	for _, macro := range m.Opts.MacroStore.List() {
   153  		eventTypes = append(eventTypes, macro.evaluator.EventTypes...)
   154  	}
   155  
   156  	return eventTypes
   157  }
   158  
   159  // GetFields - Returns all the Field that the Macro handles included sub-Macro
   160  func (m *Macro) GetFields() []Field {
   161  	fields := m.evaluator.GetFields()
   162  
   163  	for _, macro := range m.Opts.MacroStore.List() {
   164  		fields = append(fields, macro.evaluator.GetFields()...)
   165  	}
   166  
   167  	return fields
   168  }
   169  
   170  // GetFields - Returns all the Field that the MacroEvaluator handles
   171  func (m *MacroEvaluator) GetFields() []Field {
   172  	return m.fields
   173  }