github.com/DataDog/datadog-agent/pkg/security/secl@v0.55.0-devel.0.20240517055856-10c4965fea94/compiler/ast/secl_test.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 ast holds ast related files
     7  package ast
     8  
     9  import (
    10  	"encoding/json"
    11  	"testing"
    12  )
    13  
    14  func parseRule(rule string) (*Rule, error) {
    15  	pc := NewParsingContext()
    16  	return pc.ParseRule(rule)
    17  }
    18  
    19  func parseMacro(macro string) (*Macro, error) {
    20  	pc := NewParsingContext()
    21  	return pc.ParseMacro(macro)
    22  }
    23  
    24  func printJSON(t *testing.T, i interface{}) {
    25  	b, err := json.MarshalIndent(i, "", "  ")
    26  	if err != nil {
    27  		t.Error(err)
    28  	}
    29  
    30  	t.Log(string(b))
    31  }
    32  
    33  func TestEmptyRule(t *testing.T) {
    34  	_, err := parseRule(``)
    35  	if err == nil {
    36  		t.Error("Empty expression should not be valid")
    37  	}
    38  }
    39  
    40  func TestCompareNumbers(t *testing.T) {
    41  	rule, err := parseRule(`-3 > 1`)
    42  	if err != nil {
    43  		t.Error(err)
    44  	}
    45  
    46  	printJSON(t, rule)
    47  }
    48  
    49  func TestCompareSimpleIdent(t *testing.T) {
    50  	rule, err := parseRule(`process > 1`)
    51  	if err != nil {
    52  		t.Error(err)
    53  	}
    54  
    55  	printJSON(t, rule)
    56  }
    57  
    58  func TestCompareCompositeIdent(t *testing.T) {
    59  	rule, err := parseRule(`process.pid > 1`)
    60  	if err != nil {
    61  		t.Error(err)
    62  	}
    63  
    64  	printJSON(t, rule)
    65  }
    66  
    67  func TestCompareString(t *testing.T) {
    68  	rule, err := parseRule(`process.name == "/usr/bin/ls"`)
    69  	if err != nil {
    70  		t.Error(err)
    71  	}
    72  
    73  	printJSON(t, rule)
    74  }
    75  
    76  func TestCompareComplex(t *testing.T) {
    77  	rule, err := parseRule(`process.name != "/usr/bin/vipw" && open.pathname == "/etc/passwd" && (open.mode == O_TRUNC || open.mode == O_CREAT || open.mode == O_WRONLY)`)
    78  	if err != nil {
    79  		t.Error(err)
    80  	}
    81  
    82  	printJSON(t, rule)
    83  }
    84  
    85  func TestRegister(t *testing.T) {
    86  	rule, err := parseRule(`process.ancestors[A].filename == "/usr/bin/vipw" && process.ancestors[A].pid == 44`)
    87  	if err != nil {
    88  		t.Error(err)
    89  	}
    90  
    91  	printJSON(t, rule)
    92  }
    93  
    94  func TestIntAnd(t *testing.T) {
    95  	rule, err := parseRule(`3 & 3`)
    96  	if err != nil {
    97  		t.Error(err)
    98  	}
    99  
   100  	printJSON(t, rule)
   101  }
   102  
   103  func TestBoolAnd(t *testing.T) {
   104  	rule, err := parseRule(`true and true`)
   105  	if err != nil {
   106  		t.Error(err)
   107  	}
   108  
   109  	printJSON(t, rule)
   110  }
   111  
   112  func TestInArrayString(t *testing.T) {
   113  	rule, err := parseRule(`"a" in [ "a", "b", "c" ]`)
   114  	if err != nil {
   115  		t.Error(err)
   116  	}
   117  
   118  	printJSON(t, rule)
   119  }
   120  
   121  func TestInArrayInteger(t *testing.T) {
   122  	rule, err := parseRule(`1 in [ 1, 2, 3 ]`)
   123  	if err != nil {
   124  		t.Error(err)
   125  	}
   126  
   127  	printJSON(t, rule)
   128  }
   129  
   130  func TestMacroList(t *testing.T) {
   131  	macro, err := parseMacro(`[ 1, 2, 3 ]`)
   132  	if err != nil {
   133  		t.Error(err)
   134  	}
   135  
   136  	printJSON(t, macro)
   137  }
   138  
   139  func TestMacroPrimary(t *testing.T) {
   140  	macro, err := parseMacro(`true`)
   141  	if err != nil {
   142  		t.Error(err)
   143  	}
   144  
   145  	printJSON(t, macro)
   146  }
   147  
   148  func TestMacroExpression(t *testing.T) {
   149  	macro, err := parseMacro(`1 in [ 1, 2, 3 ]`)
   150  	if err != nil {
   151  		t.Error(err)
   152  	}
   153  
   154  	printJSON(t, macro)
   155  }
   156  
   157  func TestMultiline(t *testing.T) {
   158  	expr := `process.filename == "/usr/bin/vipw" &&
   159  	process.pid == 44`
   160  
   161  	if _, err := parseRule(expr); err != nil {
   162  		t.Error(err)
   163  	}
   164  
   165  	expr = `process.filename in ["/usr/bin/vipw",
   166  	"/usr/bin/test"]`
   167  
   168  	if _, err := parseRule(expr); err != nil {
   169  		t.Error(err)
   170  	}
   171  
   172  	expr = `process.filename == "/usr/bin/vipw" && (
   173  	process.filename == "/usr/bin/test" || # blah blah
   174  	# blah blah
   175  	process.filename == "/ust/bin/false"
   176  	)`
   177  
   178  	if _, err := parseRule(expr); err != nil {
   179  		t.Error(err)
   180  	}
   181  }
   182  
   183  func TestPattern(t *testing.T) {
   184  	rule, err := parseRule(`process.name == ~"/usr/bin/ls"`)
   185  	if err != nil {
   186  		t.Error(err)
   187  	}
   188  
   189  	printJSON(t, rule)
   190  }
   191  
   192  func TestArrayPattern(t *testing.T) {
   193  	rule, err := parseRule(`process.name in [~"/usr/bin/ls", "/usr/sbin/ls"]`)
   194  	if err != nil {
   195  		t.Error(err)
   196  	}
   197  
   198  	printJSON(t, rule)
   199  }
   200  
   201  func TestRegexp(t *testing.T) {
   202  	rule, err := parseRule(`process.name == r"/usr/bin/ls"`)
   203  	if err != nil {
   204  		t.Error(err)
   205  	}
   206  
   207  	printJSON(t, rule)
   208  
   209  	rule, err = parseRule(`process.name == r"^((?:[A-Za-z\d+]{4})*(?:[A-Za-z\d+]{3}=|[A-Za-z\d+]{2}==)\.)*(([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]*[a-zA-Z0-9])\.)*([A-Za-z0-9]|[A-Za-z0-9][A-Za-z0-9\-]*[A-Za-z1-9])$" `)
   210  	if err != nil {
   211  		t.Error(err)
   212  	}
   213  
   214  	printJSON(t, rule)
   215  }
   216  
   217  func TestArrayRegexp(t *testing.T) {
   218  	rule, err := parseRule(`process.name in [r"/usr/bin/ls", "/usr/sbin/ls"]`)
   219  	if err != nil {
   220  		t.Error(err)
   221  	}
   222  
   223  	printJSON(t, rule)
   224  }
   225  
   226  func TestDuration(t *testing.T) {
   227  	rule, err := parseRule(`process.start > 10s`)
   228  	if err != nil {
   229  		t.Error(err)
   230  	}
   231  
   232  	printJSON(t, rule)
   233  }
   234  
   235  func TestNumberVariable(t *testing.T) {
   236  	rule, err := parseRule(`process.pid == ${pid}`)
   237  	if err != nil {
   238  		t.Error(err)
   239  	}
   240  
   241  	printJSON(t, rule)
   242  }
   243  
   244  func TestIPv4(t *testing.T) {
   245  	rule, err := parseRule(`network.source.ip == 127.0.0.1`)
   246  	if err != nil {
   247  		t.Error(err)
   248  	}
   249  
   250  	printJSON(t, rule)
   251  }
   252  
   253  func TestIPv4Raw(t *testing.T) {
   254  	rule, err := parseRule(`127.0.0.2 == 127.0.0.1`)
   255  	if err != nil {
   256  		t.Error(err)
   257  	}
   258  
   259  	printJSON(t, rule)
   260  }
   261  
   262  func TestIPv6Localhost(t *testing.T) {
   263  	rule, err := parseRule(`network.source.ip == ::1`)
   264  	if err != nil {
   265  		t.Error(err)
   266  	}
   267  
   268  	printJSON(t, rule)
   269  }
   270  
   271  func TestIPv6(t *testing.T) {
   272  	rule, err := parseRule(`network.source.ip == 2001:0000:0eab:DEAD:0000:00A0:ABCD:004E`)
   273  	if err != nil {
   274  		t.Error(err)
   275  	}
   276  
   277  	printJSON(t, rule)
   278  }
   279  
   280  func TestIPv6Short(t *testing.T) {
   281  	rule, err := parseRule(`network.source.ip == 2001:0:0eab:dead::a0:abcd:4e`)
   282  	if err != nil {
   283  		t.Error(err)
   284  	}
   285  
   286  	printJSON(t, rule)
   287  }
   288  
   289  func TestIPArray(t *testing.T) {
   290  	rule, err := parseRule(`network.source.ip in [ ::1, 2001:0:0eab:dead::a0:abcd:4e, 127.0.0.1 ]`)
   291  	if err != nil {
   292  		t.Error(err)
   293  	}
   294  
   295  	printJSON(t, rule)
   296  }
   297  
   298  func TestIPv4CIDR(t *testing.T) {
   299  	rule, err := parseRule(`network.source.ip in 192.168.0.0/24`)
   300  	if err != nil {
   301  		t.Error(err)
   302  	}
   303  
   304  	printJSON(t, rule)
   305  }
   306  
   307  func TestIPv6CIDR(t *testing.T) {
   308  	rule, err := parseRule(`network.source.ip in ::1/128`)
   309  	if err != nil {
   310  		t.Error(err)
   311  	}
   312  
   313  	printJSON(t, rule)
   314  }
   315  
   316  func TestCIDRArray(t *testing.T) {
   317  	rule, err := parseRule(`network.source.ip in [ ::1/128, 2001:0:0eab:dead::a0:abcd:4e/24, 127.0.0.1/32 ]`)
   318  	if err != nil {
   319  		t.Error(err)
   320  	}
   321  
   322  	printJSON(t, rule)
   323  }
   324  
   325  func TestIPAndCIDRArray(t *testing.T) {
   326  	rule, err := parseRule(`network.source.ip in [ ::1, 2001:0:0eab:dead::a0:abcd:4e, 127.0.0.1, ::1/128, 2001:0:0eab:dead::a0:abcd:4e/24, 127.0.0.1/32 ]`)
   327  	if err != nil {
   328  		t.Error(err)
   329  	}
   330  
   331  	printJSON(t, rule)
   332  }
   333  
   334  func TestCIDRMatches(t *testing.T) {
   335  	rule, err := parseRule(`network.source.cidr allin 192.168.0.0/24`)
   336  	if err != nil {
   337  		t.Error(err)
   338  	}
   339  
   340  	printJSON(t, rule)
   341  }
   342  
   343  func TestCIDRArrayMatches(t *testing.T) {
   344  	rule, err := parseRule(`network.source.cidr allin [ 192.168.0.0/24, ::1/128 ]`)
   345  	if err != nil {
   346  		t.Error(err)
   347  	}
   348  
   349  	printJSON(t, rule)
   350  }