diff --git a/pkg/policy/criteria/matchers.go b/pkg/policy/criteria/matchers.go index 52b76315a..2b0e1b968 100644 --- a/pkg/policy/criteria/matchers.go +++ b/pkg/policy/criteria/matchers.go @@ -21,6 +21,7 @@ func matchString(dst *ast.Body, left *ast.Term, right parser.Value) error { lookup := map[string]matcher{ "contains": matchStringContains, "ends_with": matchStringEndsWith, + "not": matchStringNot, "is": matchStringIs, "starts_with": matchStringStartsWith, } @@ -47,6 +48,11 @@ func matchStringEndsWith(dst *ast.Body, left *ast.Term, right parser.Value) erro return nil } +func matchStringNot(dst *ast.Body, left *ast.Term, right parser.Value) error { + *dst = append(*dst, ast.NotEqual.Expr(left, ast.NewTerm(right.RegoValue()))) + return nil +} + func matchStringIs(dst *ast.Body, left *ast.Term, right parser.Value) error { *dst = append(*dst, ast.Equal.Expr(left, ast.NewTerm(right.RegoValue()))) return nil @@ -66,8 +72,9 @@ func matchStringList(dst *ast.Body, left *ast.Term, right parser.Value) error { } lookup := map[string]matcher{ - "has": matchStringListHas, - "is": matchStringListIs, + "has": matchStringListHas, + "is": matchStringListIs, + "exclude": matchStringListExclude, } for k, v := range obj { f, ok := lookup[k] @@ -112,3 +119,24 @@ func matchStringListIs(dst *ast.Body, left *ast.Term, right parser.Value) error ) return matchStringListHas(dst, left, right) } + +func matchStringListExclude(dst *ast.Body, left *ast.Term, right parser.Value) error { + body := ast.Body{ + ast.MustParseExpr("some v"), + ast.Equality.Expr(ast.VarTerm("v"), ast.RefTerm(left, ast.VarTerm("$0"))), + } + err := matchStringIs(&body, ast.VarTerm("v"), right) + if err != nil { + return err + } + *dst = append(*dst, ast.Equal.Expr( + ast.Count.Call( + ast.ArrayComprehensionTerm( + ast.BooleanTerm(true), + body, + ), + ), + ast.IntNumberTerm(0), + )) + return nil +} diff --git a/pkg/policy/criteria/matchers_test.go b/pkg/policy/criteria/matchers_test.go index f99450597..563367b5c 100644 --- a/pkg/policy/criteria/matchers_test.go +++ b/pkg/policy/criteria/matchers_test.go @@ -50,6 +50,16 @@ func TestStringMatcher(t *testing.T) { require.NoError(t, err) assert.Equal(t, `example == "test"`, str(body)) }) + t.Run("not", func(t *testing.T) { + t.Parallel() + + var body ast.Body + err := matchString(&body, ast.VarTerm("example"), parser.Object{ + "not": parser.String("test"), + }) + require.NoError(t, err) + assert.Equal(t, `example != "test"`, str(body)) + }) t.Run("starts_with", func(t *testing.T) { t.Parallel() @@ -118,6 +128,16 @@ func TestStringListMatcher(t *testing.T) { require.NoError(t, err) assert.Equal(t, `count(example) == 1`+"\n"+`count([true | some v; v = example[_]; v == "test"]) > 0`, str(body)) }) + t.Run("exclude", func(t *testing.T) { + t.Parallel() + + var body ast.Body + err := matchStringList(&body, ast.VarTerm("example"), parser.Object{ + "exclude": parser.String("test"), + }) + require.NoError(t, err) + assert.Equal(t, `count([true | some v; v = example[_]; v == "test"]) == 0`, str(body)) + }) t.Run("string", func(t *testing.T) { t.Parallel()