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 }