github.com/DataDog/datadog-agent/pkg/security/secl@v0.55.0-devel.0.20240517055856-10c4965fea94/compiler/eval/variables.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  	"errors"
    11  	"fmt"
    12  	"reflect"
    13  	"regexp"
    14  )
    15  
    16  var (
    17  	variableRegex         = regexp.MustCompile(`\${[^}]*}`)
    18  	errAppendNotSupported = errors.New("append is not supported")
    19  )
    20  
    21  // VariableValue describes a SECL variable value
    22  type VariableValue interface {
    23  	GetEvaluator() interface{}
    24  }
    25  
    26  // MutableVariable is the interface implemented by modifiable variables
    27  type MutableVariable interface {
    28  	Set(ctx *Context, value interface{}) error
    29  	Append(ctx *Context, value interface{}) error
    30  }
    31  
    32  // Variable describes a SECL variable
    33  type Variable struct {
    34  	setFnc func(ctx *Context, value interface{}) error
    35  }
    36  
    37  // Set the variable with the specified value
    38  func (v *Variable) Set(ctx *Context, value interface{}) error {
    39  	if v.setFnc == nil {
    40  		return errors.New("variable is not mutable")
    41  	}
    42  
    43  	return v.setFnc(ctx, value)
    44  }
    45  
    46  // Append a value to the variable
    47  func (v *Variable) Append(_ *Context, _ interface{}) error {
    48  	return errAppendNotSupported
    49  }
    50  
    51  // IntVariable describes an integer variable
    52  type IntVariable struct {
    53  	Variable
    54  	intFnc func(ctx *Context) int
    55  }
    56  
    57  // GetEvaluator returns the variable SECL evaluator
    58  func (i *IntVariable) GetEvaluator() interface{} {
    59  	return &IntEvaluator{
    60  		EvalFnc: func(ctx *Context) int {
    61  			return i.intFnc(ctx)
    62  		},
    63  	}
    64  }
    65  
    66  // NewIntVariable returns a new integer variable
    67  func NewIntVariable(intFnc func(ctx *Context) int, setFnc func(ctx *Context, value interface{}) error) *IntVariable {
    68  	return &IntVariable{
    69  		Variable: Variable{
    70  			setFnc: setFnc,
    71  		},
    72  		intFnc: intFnc,
    73  	}
    74  }
    75  
    76  // StringVariable describes a string variable
    77  type StringVariable struct {
    78  	Variable
    79  	strFnc func(ctx *Context) string
    80  }
    81  
    82  // GetEvaluator returns the variable SECL evaluator
    83  func (s *StringVariable) GetEvaluator() interface{} {
    84  	return &StringEvaluator{
    85  		ValueType: VariableValueType,
    86  		EvalFnc: func(ctx *Context) string {
    87  			return s.strFnc(ctx)
    88  		},
    89  	}
    90  }
    91  
    92  // NewStringVariable returns a new string variable
    93  func NewStringVariable(strFnc func(ctx *Context) string, setFnc func(ctx *Context, value interface{}) error) *StringVariable {
    94  	return &StringVariable{
    95  		strFnc: strFnc,
    96  		Variable: Variable{
    97  			setFnc: setFnc,
    98  		},
    99  	}
   100  }
   101  
   102  // BoolVariable describes a boolean variable
   103  type BoolVariable struct {
   104  	Variable
   105  	boolFnc func(ctx *Context) bool
   106  }
   107  
   108  // GetEvaluator returns the variable SECL evaluator
   109  func (b *BoolVariable) GetEvaluator() interface{} {
   110  	return &BoolEvaluator{
   111  		EvalFnc: func(ctx *Context) bool {
   112  			return b.boolFnc(ctx)
   113  		},
   114  	}
   115  }
   116  
   117  // NewBoolVariable returns a new boolean variable
   118  func NewBoolVariable(boolFnc func(ctx *Context) bool, setFnc func(ctx *Context, value interface{}) error) *BoolVariable {
   119  	return &BoolVariable{
   120  		boolFnc: boolFnc,
   121  		Variable: Variable{
   122  			setFnc: setFnc,
   123  		},
   124  	}
   125  }
   126  
   127  // StringArrayVariable describes a string array variable
   128  type StringArrayVariable struct {
   129  	Variable
   130  	strFnc func(ctx *Context) []string
   131  }
   132  
   133  // GetEvaluator returns the variable SECL evaluator
   134  func (s *StringArrayVariable) GetEvaluator() interface{} {
   135  	return &StringArrayEvaluator{
   136  		EvalFnc: s.strFnc,
   137  	}
   138  }
   139  
   140  // Set the array values
   141  func (s *StringArrayVariable) Set(ctx *Context, value interface{}) error {
   142  	if s, ok := value.(string); ok {
   143  		value = []string{s}
   144  	}
   145  	return s.Variable.Set(ctx, value)
   146  }
   147  
   148  // Append a value to the array
   149  func (s *StringArrayVariable) Append(ctx *Context, value interface{}) error {
   150  	return s.Set(ctx, append(s.strFnc(ctx), value.([]string)...))
   151  }
   152  
   153  // NewStringArrayVariable returns a new string array variable
   154  func NewStringArrayVariable(strFnc func(ctx *Context) []string, setFnc func(ctx *Context, value interface{}) error) *StringArrayVariable {
   155  	return &StringArrayVariable{
   156  		strFnc: strFnc,
   157  		Variable: Variable{
   158  			setFnc: setFnc,
   159  		},
   160  	}
   161  }
   162  
   163  // IntArrayVariable describes an integer array variable
   164  type IntArrayVariable struct {
   165  	Variable
   166  	intFnc func(ctx *Context) []int
   167  }
   168  
   169  // GetEvaluator returns the variable SECL evaluator
   170  func (s *IntArrayVariable) GetEvaluator() interface{} {
   171  	return &IntArrayEvaluator{
   172  		EvalFnc: s.intFnc,
   173  	}
   174  }
   175  
   176  // Set the array values
   177  func (s *IntArrayVariable) Set(ctx *Context, value interface{}) error {
   178  	if i, ok := value.(int); ok {
   179  		value = []int{i}
   180  	}
   181  	return s.Variable.Set(ctx, value)
   182  }
   183  
   184  // Append a value to the array
   185  func (s *IntArrayVariable) Append(ctx *Context, value interface{}) error {
   186  	return s.Set(ctx, append(s.intFnc(ctx), value.([]int)...))
   187  }
   188  
   189  // NewIntArrayVariable returns a new integer array variable
   190  func NewIntArrayVariable(intFnc func(ctx *Context) []int, setFnc func(ctx *Context, value interface{}) error) *IntArrayVariable {
   191  	return &IntArrayVariable{
   192  		intFnc: intFnc,
   193  		Variable: Variable{
   194  			setFnc: setFnc,
   195  		},
   196  	}
   197  }
   198  
   199  // MutableIntVariable describes a mutable integer variable
   200  type MutableIntVariable struct {
   201  	Value int
   202  }
   203  
   204  // Set the variable with the specified value
   205  func (m *MutableIntVariable) Set(_ *Context, value interface{}) error {
   206  	m.Value = value.(int)
   207  	return nil
   208  }
   209  
   210  // Append a value to the integer
   211  func (m *MutableIntVariable) Append(_ *Context, value interface{}) error {
   212  	switch value := value.(type) {
   213  	case int:
   214  		m.Value += value
   215  	default:
   216  		return errAppendNotSupported
   217  	}
   218  	return nil
   219  }
   220  
   221  // GetEvaluator returns the variable SECL evaluator
   222  func (m *MutableIntVariable) GetEvaluator() interface{} {
   223  	return &IntEvaluator{
   224  		EvalFnc: func(ctx *Context) int {
   225  			return m.Value
   226  		},
   227  	}
   228  }
   229  
   230  // NewMutableIntVariable returns a new mutable integer variable
   231  func NewMutableIntVariable() *MutableIntVariable {
   232  	return &MutableIntVariable{}
   233  }
   234  
   235  // MutableBoolVariable describes a mutable boolean variable
   236  type MutableBoolVariable struct {
   237  	Value bool
   238  }
   239  
   240  // GetEvaluator returns the variable SECL evaluator
   241  func (m *MutableBoolVariable) GetEvaluator() interface{} {
   242  	return &BoolEvaluator{
   243  		EvalFnc: func(ctx *Context) bool {
   244  			return m.Value
   245  		},
   246  	}
   247  }
   248  
   249  // Set the variable with the specified value
   250  func (m *MutableBoolVariable) Set(_ *Context, value interface{}) error {
   251  	m.Value = value.(bool)
   252  	return nil
   253  }
   254  
   255  // Append a value to the boolean
   256  func (m *MutableBoolVariable) Append(_ *Context, _ interface{}) error {
   257  	return errAppendNotSupported
   258  }
   259  
   260  // NewMutableBoolVariable returns a new mutable boolean variable
   261  func NewMutableBoolVariable() *MutableBoolVariable {
   262  	return &MutableBoolVariable{}
   263  }
   264  
   265  // MutableStringVariable describes a mutable string variable
   266  type MutableStringVariable struct {
   267  	Value string
   268  }
   269  
   270  // GetEvaluator returns the variable SECL evaluator
   271  func (m *MutableStringVariable) GetEvaluator() interface{} {
   272  	return &StringEvaluator{
   273  		ValueType: VariableValueType,
   274  		EvalFnc: func(ctx *Context) string {
   275  			return m.Value
   276  		},
   277  	}
   278  }
   279  
   280  // Append a value to the string
   281  func (m *MutableStringVariable) Append(_ *Context, value interface{}) error {
   282  	switch value := value.(type) {
   283  	case string:
   284  		m.Value += value
   285  	default:
   286  		return errAppendNotSupported
   287  	}
   288  	return nil
   289  }
   290  
   291  // Set the variable with the specified value
   292  func (m *MutableStringVariable) Set(_ *Context, value interface{}) error {
   293  	m.Value = value.(string)
   294  	return nil
   295  }
   296  
   297  // NewMutableStringVariable returns a new mutable string variable
   298  func NewMutableStringVariable() *MutableStringVariable {
   299  	return &MutableStringVariable{}
   300  }
   301  
   302  // MutableStringArrayVariable describes a mutable string array variable
   303  type MutableStringArrayVariable struct {
   304  	StringValues
   305  }
   306  
   307  // Set the variable with the specified value
   308  func (m *MutableStringArrayVariable) Set(_ *Context, values interface{}) error {
   309  	if s, ok := values.(string); ok {
   310  		values = []string{s}
   311  	}
   312  
   313  	m.StringValues = StringValues{}
   314  	for _, v := range values.([]string) {
   315  		m.AppendScalarValue(v)
   316  	}
   317  	return nil
   318  }
   319  
   320  // Append a value to the array
   321  func (m *MutableStringArrayVariable) Append(_ *Context, value interface{}) error {
   322  	switch value := value.(type) {
   323  	case string:
   324  		m.AppendScalarValue(value)
   325  	case []string:
   326  		for _, v := range value {
   327  			m.AppendScalarValue(v)
   328  		}
   329  	default:
   330  		return errAppendNotSupported
   331  	}
   332  	return nil
   333  }
   334  
   335  // GetEvaluator returns the variable SECL evaluator
   336  func (m *MutableStringArrayVariable) GetEvaluator() interface{} {
   337  	return &StringArrayEvaluator{
   338  		EvalFnc: func(ctx *Context) []string {
   339  			return m.GetScalarValues()
   340  		},
   341  	}
   342  }
   343  
   344  // NewMutableStringArrayVariable returns a new mutable string array variable
   345  func NewMutableStringArrayVariable() *MutableStringArrayVariable {
   346  	return &MutableStringArrayVariable{}
   347  }
   348  
   349  // MutableIntArrayVariable describes a mutable integer array variable
   350  type MutableIntArrayVariable struct {
   351  	Values []int
   352  }
   353  
   354  // Set the variable with the specified value
   355  func (m *MutableIntArrayVariable) Set(_ *Context, values interface{}) error {
   356  	if i, ok := values.(int); ok {
   357  		values = []int{i}
   358  	}
   359  	m.Values = values.([]int)
   360  	return nil
   361  }
   362  
   363  // Append a value to the array
   364  func (m *MutableIntArrayVariable) Append(_ *Context, value interface{}) error {
   365  	switch value := value.(type) {
   366  	case int:
   367  		m.Values = append(m.Values, value)
   368  	case []int:
   369  		m.Values = append(m.Values, value...)
   370  	default:
   371  		return errAppendNotSupported
   372  	}
   373  	return nil
   374  }
   375  
   376  // GetEvaluator returns the variable SECL evaluator
   377  func (m *MutableIntArrayVariable) GetEvaluator() interface{} {
   378  	return &IntArrayEvaluator{
   379  		EvalFnc: func(ctx *Context) []int {
   380  			return m.Values
   381  		},
   382  	}
   383  }
   384  
   385  // NewMutableIntArrayVariable returns a new mutable integer array variable
   386  func NewMutableIntArrayVariable() *MutableIntArrayVariable {
   387  	return &MutableIntArrayVariable{}
   388  }
   389  
   390  // ScopedVariable is the interface to be implemented by scoped variable in order to be released
   391  type ScopedVariable interface {
   392  	SetReleaseCallback(callback func())
   393  }
   394  
   395  // Scoper maps a variable to the entity its scoped to
   396  type Scoper func(ctx *Context) ScopedVariable
   397  
   398  // GlobalVariables holds a set of global variables
   399  type GlobalVariables struct{}
   400  
   401  // GetVariable returns new variable of the type of the specified value
   402  func (v *GlobalVariables) GetVariable(_ string, value interface{}) (VariableValue, error) {
   403  	switch value := value.(type) {
   404  	case bool:
   405  		return NewMutableBoolVariable(), nil
   406  	case int:
   407  		return NewMutableIntVariable(), nil
   408  	case string:
   409  		return NewMutableStringVariable(), nil
   410  	case []string:
   411  		return NewMutableStringArrayVariable(), nil
   412  	case []int:
   413  		return NewMutableIntArrayVariable(), nil
   414  	default:
   415  		return nil, fmt.Errorf("unsupported value type: %s", reflect.TypeOf(value))
   416  	}
   417  }
   418  
   419  // Variables holds a set of variables
   420  type Variables struct {
   421  	vars map[string]interface{}
   422  }
   423  
   424  // GetBool returns the boolean value of the specified variable
   425  func (v *Variables) GetBool(name string) bool {
   426  	if _, found := v.vars[name]; !found {
   427  		return false
   428  	}
   429  	return v.vars[name].(bool)
   430  }
   431  
   432  // GetInt returns the integer value of the specified variable
   433  func (v *Variables) GetInt(name string) int {
   434  	if _, found := v.vars[name]; !found {
   435  		return 0
   436  	}
   437  	return v.vars[name].(int)
   438  }
   439  
   440  // GetString returns the string value of the specified variable
   441  func (v *Variables) GetString(name string) string {
   442  	if _, found := v.vars[name]; !found {
   443  		return ""
   444  	}
   445  	return v.vars[name].(string)
   446  }
   447  
   448  // GetStringArray returns the string array value of the specified variable
   449  func (v *Variables) GetStringArray(name string) []string {
   450  	if _, found := v.vars[name]; !found {
   451  		return nil
   452  	}
   453  	return v.vars[name].([]string)
   454  }
   455  
   456  // GetIntArray returns the integer array value of the specified variable
   457  func (v *Variables) GetIntArray(name string) []int {
   458  	if _, found := v.vars[name]; !found {
   459  		return nil
   460  	}
   461  	return v.vars[name].([]int)
   462  }
   463  
   464  // Set the value of the specified variable
   465  func (v *Variables) Set(name string, value interface{}) bool {
   466  	existed := false
   467  	if v.vars == nil {
   468  		v.vars = make(map[string]interface{})
   469  	} else {
   470  		_, existed = v.vars[name]
   471  	}
   472  
   473  	v.vars[name] = value
   474  	return !existed
   475  }
   476  
   477  // ScopedVariables holds a set of scoped variables
   478  type ScopedVariables struct {
   479  	scoper Scoper
   480  	vars   map[ScopedVariable]*Variables
   481  }
   482  
   483  // Len returns the length of the variable map
   484  func (v *ScopedVariables) Len() int {
   485  	return len(v.vars)
   486  }
   487  
   488  // GetVariable returns new variable of the type of the specified value
   489  func (v *ScopedVariables) GetVariable(name string, value interface{}) (VariableValue, error) {
   490  	getVariables := func(ctx *Context) *Variables {
   491  		v := v.vars[v.scoper(ctx)]
   492  		return v
   493  	}
   494  
   495  	setVariable := func(ctx *Context, value interface{}) error {
   496  		key := v.scoper(ctx)
   497  		if key == nil {
   498  			return fmt.Errorf("failed to scope variable '%s'", name)
   499  		}
   500  		vars := v.vars[key]
   501  		if vars == nil {
   502  			key.SetReleaseCallback(func() {
   503  				v.ReleaseVariable(key)
   504  			})
   505  			vars = &Variables{}
   506  			v.vars[key] = vars
   507  		}
   508  		vars.Set(name, value)
   509  		return nil
   510  	}
   511  
   512  	switch value.(type) {
   513  	case int:
   514  		return NewIntVariable(func(ctx *Context) int {
   515  			if vars := getVariables(ctx); vars != nil {
   516  				return vars.GetInt(name)
   517  			}
   518  			return 0
   519  		}, setVariable), nil
   520  	case bool:
   521  		return NewBoolVariable(func(ctx *Context) bool {
   522  			if vars := getVariables(ctx); vars != nil {
   523  				return vars.GetBool(name)
   524  			}
   525  			return false
   526  		}, setVariable), nil
   527  	case string:
   528  		return NewStringVariable(func(ctx *Context) string {
   529  			if vars := getVariables(ctx); vars != nil {
   530  				return vars.GetString(name)
   531  			}
   532  			return ""
   533  		}, setVariable), nil
   534  	case []string:
   535  		return NewStringArrayVariable(func(ctx *Context) []string {
   536  			if vars := getVariables(ctx); vars != nil {
   537  				return vars.GetStringArray(name)
   538  			}
   539  			return nil
   540  		}, setVariable), nil
   541  	case []int:
   542  		return NewIntArrayVariable(func(ctx *Context) []int {
   543  			if vars := getVariables(ctx); vars != nil {
   544  				return vars.GetIntArray(name)
   545  			}
   546  			return nil
   547  
   548  		}, setVariable), nil
   549  	default:
   550  		return nil, fmt.Errorf("unsupported variable type %s for '%s'", reflect.TypeOf(value), name)
   551  	}
   552  }
   553  
   554  // ReleaseVariable releases a scoped variable
   555  func (v *ScopedVariables) ReleaseVariable(key ScopedVariable) {
   556  	delete(v.vars, key)
   557  }
   558  
   559  // NewScopedVariables returns a new set of scope variables
   560  func NewScopedVariables(scoper Scoper) *ScopedVariables {
   561  	return &ScopedVariables{
   562  		scoper: scoper,
   563  		vars:   make(map[ScopedVariable]*Variables),
   564  	}
   565  }