From 2fb4fbbe93d8382709cd350890cb1d3b51bfdd09 Mon Sep 17 00:00:00 2001 From: Artyom Antonov Date: Thu, 27 Jun 2024 17:49:05 +0500 Subject: [PATCH 1/4] validate regex syntax in seriesByTag matching terms --- finder/tagged.go | 17 ++++++ tests/feature_flags_both_true/test.toml | 58 +++++++++++++++++-- .../test.toml | 58 +++++++++++++++++-- tests/feature_flags_false/test.toml | 58 +++++++++++++++++-- .../test.toml | 58 +++++++++++++++++-- 5 files changed, 233 insertions(+), 16 deletions(-) diff --git a/finder/tagged.go b/finder/tagged.go index b63d9782..df7273e3 100644 --- a/finder/tagged.go +++ b/finder/tagged.go @@ -5,6 +5,7 @@ import ( "context" "fmt" "net/http" + "regexp" "sort" "strings" @@ -21,6 +22,7 @@ import ( var ( // ErrEmptyArgs = errors.New("empty arguments") ErrCostlySeriesByTag = errs.NewErrorWithCode("seriesByTag argument has too much wildcard and regex terms", http.StatusForbidden) + ErrIncorrectRegex = errs.NewErrorWithCode("incorrect regex syntax", http.StatusBadRequest) ) type TaggedTermOp int @@ -253,6 +255,15 @@ func setCost(term *TaggedTerm, costs *config.Costs) { } } +func validateRegex(regex string) error { + if regex != "*" { + if _, err := regexp.Compile(regex); err != nil { + return ErrIncorrectRegex + } + } + return nil +} + func ParseTaggedConditions(conditions []string, config *config.Config, autocomplete bool) ([]TaggedTerm, error) { nonWildcards := 0 terms := make([]TaggedTerm, len(conditions)) @@ -297,8 +308,14 @@ func ParseTaggedConditions(conditions []string, config *config.Config, autocompl case "!=": terms[i].Op = TaggedTermNe case "=~": + if err := validateRegex(terms[i].Value); err != nil { + return nil, err + } terms[i].Op = TaggedTermMatch case "!=~": + if err := validateRegex(terms[i].Value); err != nil { + return nil, err + } terms[i].Op = TaggedTermNotMatch default: return nil, fmt.Errorf("wrong seriesByTag expr: %#v", s) diff --git a/tests/feature_flags_both_true/test.toml b/tests/feature_flags_both_true/test.toml index 83e039c9..80f259d2 100644 --- a/tests/feature_flags_both_true/test.toml +++ b/tests/feature_flags_both_true/test.toml @@ -37,10 +37,6 @@ points = [{value = 1.0, time = "rnow-10"}] name = "request_success_total.counter;app=test;project=Test;environment=TEST;t=cqa" points = [{value = 1.0, time = "rnow-10"}] -[[test.input]] -name = "request_success_total.counter;app=test;project=Test;environment=TEST;t=cqa" -points = [{value = 1.0, time = "rnow-10"}] - [[test.input]] name = "test;env=prod" points = [{value = 1.0, time = "rnow-10"}] @@ -974,6 +970,60 @@ req_start = "rnow-10" req_stop = "rnow+10" values = [1.0, nan] +# ### seriesByTag('name=request_success_total.counter', 'app=test', 'project=Test', 'environment=TEST', 't=~*a*') ### + +[[test.render_checks]] +from = "rnow-10" +until = "rnow+1" +timeout = "1h" +targets = [ + "seriesByTag('name=request_success_total.counter', 'app=test', 'project=Test', 'environment=TEST', 't=~*a*')", +] +error_regexp = "^400: incorrect regex syntax" + +# ### seriesByTag('name=request_success_total.counter', 'app=test', 'project=Test', 'environment=TEST', 't=~*') ### + +[[test.render_checks]] +from = "rnow-10" +until = "rnow+1" +timeout = "1h" +targets = [ + "seriesByTag('name=request_success_total.counter', 'app=test', 'project=Test', 'environment=TEST', 't=~*')", +] + +[[test.render_checks.result]] +name = "request_success_total.counter;app=test;environment=TEST;project=Test;t=cqa" +path = "seriesByTag('name=request_success_total.counter', 'app=test', 'project=Test', 'environment=TEST', 't=~*')" +consolidation = "avg" +start = "rnow-10" +stop = "rnow+10" +step = 10 +req_start = "rnow-10" +req_stop = "rnow+10" +values = [1.0, nan] + +[[test.render_checks.result]] +name = "request_success_total.counter;app=test;environment=TEST;project=Test;t=q" +path = "seriesByTag('name=request_success_total.counter', 'app=test', 'project=Test', 'environment=TEST', 't=~*')" +consolidation = "avg" +start = "rnow-10" +stop = "rnow+10" +step = 10 +req_start = "rnow-10" +req_stop = "rnow+10" +values = [1.0, nan] + +[[test.render_checks.result]] +name = "request_success_total.counter;app=test;environment=TEST;project=Test;t=qac" +path = "seriesByTag('name=request_success_total.counter', 'app=test', 'project=Test', 'environment=TEST', 't=~*')" +consolidation = "avg" +start = "rnow-10" +stop = "rnow+10" +step = 10 +req_start = "rnow-10" +req_stop = "rnow+10" +values = [1.0, nan] + # # End - Test no flags # ######################################################################### diff --git a/tests/feature_flags_dont_match_missing_tags/test.toml b/tests/feature_flags_dont_match_missing_tags/test.toml index e58016cb..7cc9d068 100644 --- a/tests/feature_flags_dont_match_missing_tags/test.toml +++ b/tests/feature_flags_dont_match_missing_tags/test.toml @@ -37,10 +37,6 @@ points = [{value = 1.0, time = "rnow-10"}] name = "request_success_total.counter;app=test;project=Test;environment=TEST;t=cqa" points = [{value = 1.0, time = "rnow-10"}] -[[test.input]] -name = "request_success_total.counter;app=test;project=Test;environment=TEST;t=cqa" -points = [{value = 1.0, time = "rnow-10"}] - [[test.input]] name = "test;env=prod" points = [{value = 1.0, time = "rnow-10"}] @@ -930,6 +926,60 @@ req_start = "rnow-10" req_stop = "rnow+10" values = [1.0, nan] +# ### seriesByTag('name=request_success_total.counter', 'app=test', 'project=Test', 'environment=TEST', 't=~*a*') ### + +[[test.render_checks]] +from = "rnow-10" +until = "rnow+1" +timeout = "1h" +targets = [ + "seriesByTag('name=request_success_total.counter', 'app=test', 'project=Test', 'environment=TEST', 't=~*a*')", +] +error_regexp = "^400: incorrect regex syntax" + +# ### seriesByTag('name=request_success_total.counter', 'app=test', 'project=Test', 'environment=TEST', 't=~*') ### + +[[test.render_checks]] +from = "rnow-10" +until = "rnow+1" +timeout = "1h" +targets = [ + "seriesByTag('name=request_success_total.counter', 'app=test', 'project=Test', 'environment=TEST', 't=~*')", +] + +[[test.render_checks.result]] +name = "request_success_total.counter;app=test;environment=TEST;project=Test;t=cqa" +path = "seriesByTag('name=request_success_total.counter', 'app=test', 'project=Test', 'environment=TEST', 't=~*')" +consolidation = "avg" +start = "rnow-10" +stop = "rnow+10" +step = 10 +req_start = "rnow-10" +req_stop = "rnow+10" +values = [1.0, nan] + +[[test.render_checks.result]] +name = "request_success_total.counter;app=test;environment=TEST;project=Test;t=q" +path = "seriesByTag('name=request_success_total.counter', 'app=test', 'project=Test', 'environment=TEST', 't=~*')" +consolidation = "avg" +start = "rnow-10" +stop = "rnow+10" +step = 10 +req_start = "rnow-10" +req_stop = "rnow+10" +values = [1.0, nan] + +[[test.render_checks.result]] +name = "request_success_total.counter;app=test;environment=TEST;project=Test;t=qac" +path = "seriesByTag('name=request_success_total.counter', 'app=test', 'project=Test', 'environment=TEST', 't=~*')" +consolidation = "avg" +start = "rnow-10" +stop = "rnow+10" +step = 10 +req_start = "rnow-10" +req_stop = "rnow+10" +values = [1.0, nan] + # # End - Test no flags # ######################################################################### diff --git a/tests/feature_flags_false/test.toml b/tests/feature_flags_false/test.toml index a6a9e6b1..18592f9e 100644 --- a/tests/feature_flags_false/test.toml +++ b/tests/feature_flags_false/test.toml @@ -37,10 +37,6 @@ points = [{value = 1.0, time = "rnow-10"}] name = "request_success_total.counter;app=test;project=Test;environment=TEST;t=cqa" points = [{value = 1.0, time = "rnow-10"}] -[[test.input]] -name = "request_success_total.counter;app=test;project=Test;environment=TEST;t=cqa" -points = [{value = 1.0, time = "rnow-10"}] - [[test.input]] name = "test;env=prod" points = [{value = 1.0, time = "rnow-10"}] @@ -1292,6 +1288,60 @@ req_start = "rnow-10" req_stop = "rnow+10" values = [1.0, nan] +# ### seriesByTag('name=request_success_total.counter', 'app=test', 'project=Test', 'environment=TEST', 't=~*a*') ### + +[[test.render_checks]] +from = "rnow-10" +until = "rnow+1" +timeout = "1h" +targets = [ + "seriesByTag('name=request_success_total.counter', 'app=test', 'project=Test', 'environment=TEST', 't=~*a*')", +] +error_regexp = "^400: incorrect regex syntax" + +# ### seriesByTag('name=request_success_total.counter', 'app=test', 'project=Test', 'environment=TEST', 't=~*') ### + +[[test.render_checks]] +from = "rnow-10" +until = "rnow+1" +timeout = "1h" +targets = [ + "seriesByTag('name=request_success_total.counter', 'app=test', 'project=Test', 'environment=TEST', 't=~*')", +] + +[[test.render_checks.result]] +name = "request_success_total.counter;app=test;environment=TEST;project=Test;t=cqa" +path = "seriesByTag('name=request_success_total.counter', 'app=test', 'project=Test', 'environment=TEST', 't=~*')" +consolidation = "avg" +start = "rnow-10" +stop = "rnow+10" +step = 10 +req_start = "rnow-10" +req_stop = "rnow+10" +values = [1.0, nan] + +[[test.render_checks.result]] +name = "request_success_total.counter;app=test;environment=TEST;project=Test;t=q" +path = "seriesByTag('name=request_success_total.counter', 'app=test', 'project=Test', 'environment=TEST', 't=~*')" +consolidation = "avg" +start = "rnow-10" +stop = "rnow+10" +step = 10 +req_start = "rnow-10" +req_stop = "rnow+10" +values = [1.0, nan] + +[[test.render_checks.result]] +name = "request_success_total.counter;app=test;environment=TEST;project=Test;t=qac" +path = "seriesByTag('name=request_success_total.counter', 'app=test', 'project=Test', 'environment=TEST', 't=~*')" +consolidation = "avg" +start = "rnow-10" +stop = "rnow+10" +step = 10 +req_start = "rnow-10" +req_stop = "rnow+10" +values = [1.0, nan] + # # End - Test no flags # ######################################################################### diff --git a/tests/feature_flags_use_carbon_behaviour/test.toml b/tests/feature_flags_use_carbon_behaviour/test.toml index 61fb2801..1906db71 100644 --- a/tests/feature_flags_use_carbon_behaviour/test.toml +++ b/tests/feature_flags_use_carbon_behaviour/test.toml @@ -37,10 +37,6 @@ points = [{value = 1.0, time = "rnow-10"}] name = "request_success_total.counter;app=test;project=Test;environment=TEST;t=cqa" points = [{value = 1.0, time = "rnow-10"}] -[[test.input]] -name = "request_success_total.counter;app=test;project=Test;environment=TEST;t=cqa" -points = [{value = 1.0, time = "rnow-10"}] - [[test.input]] name = "test;env=prod" points = [{value = 1.0, time = "rnow-10"}] @@ -1336,6 +1332,60 @@ req_start = "rnow-10" req_stop = "rnow+10" values = [1.0, nan] +# ### seriesByTag('name=request_success_total.counter', 'app=test', 'project=Test', 'environment=TEST', 't=~*a*') ### + +[[test.render_checks]] +from = "rnow-10" +until = "rnow+1" +timeout = "1h" +targets = [ + "seriesByTag('name=request_success_total.counter', 'app=test', 'project=Test', 'environment=TEST', 't=~*a*')", +] +error_regexp = "^400: incorrect regex syntax" + +# ### seriesByTag('name=request_success_total.counter', 'app=test', 'project=Test', 'environment=TEST', 't=~*') ### + +[[test.render_checks]] +from = "rnow-10" +until = "rnow+1" +timeout = "1h" +targets = [ + "seriesByTag('name=request_success_total.counter', 'app=test', 'project=Test', 'environment=TEST', 't=~*')", +] + +[[test.render_checks.result]] +name = "request_success_total.counter;app=test;environment=TEST;project=Test;t=cqa" +path = "seriesByTag('name=request_success_total.counter', 'app=test', 'project=Test', 'environment=TEST', 't=~*')" +consolidation = "avg" +start = "rnow-10" +stop = "rnow+10" +step = 10 +req_start = "rnow-10" +req_stop = "rnow+10" +values = [1.0, nan] + +[[test.render_checks.result]] +name = "request_success_total.counter;app=test;environment=TEST;project=Test;t=q" +path = "seriesByTag('name=request_success_total.counter', 'app=test', 'project=Test', 'environment=TEST', 't=~*')" +consolidation = "avg" +start = "rnow-10" +stop = "rnow+10" +step = 10 +req_start = "rnow-10" +req_stop = "rnow+10" +values = [1.0, nan] + +[[test.render_checks.result]] +name = "request_success_total.counter;app=test;environment=TEST;project=Test;t=qac" +path = "seriesByTag('name=request_success_total.counter', 'app=test', 'project=Test', 'environment=TEST', 't=~*')" +consolidation = "avg" +start = "rnow-10" +stop = "rnow+10" +step = 10 +req_start = "rnow-10" +req_stop = "rnow+10" +values = [1.0, nan] + # # End - Test no flags # ######################################################################### From 7fed0f3d0c2dbcc421cb2f2da98e5cbdfb89ef82 Mon Sep 17 00:00:00 2001 From: Artyom Antonov Date: Wed, 3 Jul 2024 02:32:29 +0500 Subject: [PATCH 2/4] validate queries in plain format --- finder/index.go | 13 +++++++++++++ pkg/where/match.go | 35 +++++++++++++++++++++++++++++++++++ pkg/where/match_test.go | 30 ++++++++++++++++++++++++++++++ 3 files changed, 78 insertions(+) diff --git a/finder/index.go b/finder/index.go index 1d4e59ee..cf99324c 100644 --- a/finder/index.go +++ b/finder/index.go @@ -4,11 +4,13 @@ import ( "bytes" "context" "fmt" + "net/http" "strings" "github.com/lomik/graphite-clickhouse/config" "github.com/lomik/graphite-clickhouse/helper/clickhouse" "github.com/lomik/graphite-clickhouse/helper/date" + "github.com/lomik/graphite-clickhouse/helper/errs" "github.com/lomik/graphite-clickhouse/pkg/scope" "github.com/lomik/graphite-clickhouse/pkg/where" ) @@ -153,7 +155,18 @@ func (idx *IndexFinder) whereFilter(query string, from int64, until int64) *wher return w } +func (idx *IndexFinder) validateQuery(query string) error { + if where.HasUnmatchedBrackets(query) { + return errs.NewErrorWithCode("query has unmatched brackets", http.StatusBadRequest) + } + return nil +} + func (idx *IndexFinder) Execute(ctx context.Context, config *config.Config, query string, from int64, until int64, stat *FinderStat) (err error) { + err = idx.validateQuery(query) + if err != nil { + return err + } w := idx.whereFilter(query, from, until) idx.body, stat.ChReadRows, stat.ChReadBytes, err = clickhouse.Query( diff --git a/pkg/where/match.go b/pkg/where/match.go index 9c002e41..ade75d1d 100644 --- a/pkg/where/match.go +++ b/pkg/where/match.go @@ -85,6 +85,41 @@ func clearGlob(query string) string { return query } +func HasUnmatchedBrackets(query string) bool { + matchingBracket := map[rune]rune{ + '}': '{', + ']': '[', + } + stack := make([]rune, 0) + + nodeHasUnmatched := func(query string) bool { + for _, c := range query { + if c == '{' || c == '[' { + stack = append(stack, c) + } + if c == '}' || c == ']' { + if len(stack) == 0 { + return true + } + if stack[len(stack)-1] == matchingBracket[c] { + stack = stack[:len(stack)-1] + } else { + return true + } + } + } + return len(stack) != 0 + } + + for _, node := range strings.Split(query, ".") { + if nodeHasUnmatched(node) { + return true + } + } + + return false +} + func glob(field string, query string, optionalDotAtEnd bool) string { if query == "*" { return "" diff --git a/pkg/where/match_test.go b/pkg/where/match_test.go index 378c1679..f6b31ad6 100644 --- a/pkg/where/match_test.go +++ b/pkg/where/match_test.go @@ -28,6 +28,36 @@ func Test_clearGlob(t *testing.T) { } } +func Test_HasUnmatchedBrackets(t *testing.T) { + tests := []struct { + query string + want bool + }{ + {"a.{a,b.te{s}t.b", true}, + {"a.{a,b}.te{s}t.b", false}, + {"a.{a,b}.te{s,t}}*.b", true}, + {"a.{a,b}.test*.b", false}, + {"a.a,b}.test*.b", true}, + {"a.{a,b.test*.b}", true}, + {"a.[a,b.test*.b]", true}, + {"a.[a,b].test*.b", false}, + {"a.[b].te{s}t.b", false}, + {"a.{[cd],[ef]}.b", false}, + {"a.[ab].te{s,t}*.b", false}, + {"a.{a,b.}.te{s,t}*.b", true}, // dots are not escaped inside curly brackets + {"О.[б].те{s}t.b", false}, // utf-8 string + {"О.[б.теs}t.b", true}, + {"О.[].те{}t.b", false}, // utf-8 string with empthy blocks + } + for _, tt := range tests { + t.Run(tt.query, func(t *testing.T) { + if got := HasUnmatchedBrackets(tt.query); got != tt.want { + t.Errorf("HasUnmatchedBrackets() = %v, want %v", got, tt.want) + } + }) + } +} + func TestGlob(t *testing.T) { field := "test" tests := []struct { From 7ee27160af52a535f42d14d10e5e2ee2778b4715 Mon Sep 17 00:00:00 2001 From: Artyom Antonov Date: Mon, 28 Oct 2024 13:30:43 +0500 Subject: [PATCH 3/4] parse regex compile error from clickhouse instead --- finder/index.go | 4 ++-- finder/tagged.go | 18 ------------------ helper/clickhouse/clickhouse.go | 3 +++ helper/clickhouse/clickhouse_test.go | 10 ++++++++++ tests/feature_flags_both_true/test.toml | 2 +- .../test.toml | 2 +- tests/feature_flags_false/test.toml | 2 +- .../test.toml | 2 +- 8 files changed, 19 insertions(+), 24 deletions(-) diff --git a/finder/index.go b/finder/index.go index cf99324c..6ec4a0f3 100644 --- a/finder/index.go +++ b/finder/index.go @@ -155,7 +155,7 @@ func (idx *IndexFinder) whereFilter(query string, from int64, until int64) *wher return w } -func (idx *IndexFinder) validateQuery(query string) error { +func (idx *IndexFinder) validatePlainQuery(query string) error { if where.HasUnmatchedBrackets(query) { return errs.NewErrorWithCode("query has unmatched brackets", http.StatusBadRequest) } @@ -163,7 +163,7 @@ func (idx *IndexFinder) validateQuery(query string) error { } func (idx *IndexFinder) Execute(ctx context.Context, config *config.Config, query string, from int64, until int64, stat *FinderStat) (err error) { - err = idx.validateQuery(query) + err = idx.validatePlainQuery(query) if err != nil { return err } diff --git a/finder/tagged.go b/finder/tagged.go index 30c06a2b..7c7e1c75 100644 --- a/finder/tagged.go +++ b/finder/tagged.go @@ -5,7 +5,6 @@ import ( "context" "fmt" "net/http" - "regexp" "sort" "strings" @@ -20,9 +19,7 @@ import ( ) var ( - // ErrEmptyArgs = errors.New("empty arguments") ErrCostlySeriesByTag = errs.NewErrorWithCode("seriesByTag argument has too much wildcard and regex terms", http.StatusForbidden) - ErrIncorrectRegex = errs.NewErrorWithCode("incorrect regex syntax", http.StatusBadRequest) ) type TaggedTermOp int @@ -255,15 +252,6 @@ func setCost(term *TaggedTerm, costs *config.Costs) { } } -func validateRegex(regex string) error { - if regex != "*" { - if _, err := regexp.Compile(regex); err != nil { - return ErrIncorrectRegex - } - } - return nil -} - func ParseTaggedConditions(conditions []string, config *config.Config, autocomplete bool) ([]TaggedTerm, error) { nonWildcards := 0 terms := make([]TaggedTerm, len(conditions)) @@ -311,14 +299,8 @@ func ParseTaggedConditions(conditions []string, config *config.Config, autocompl case "!=": terms[i].Op = TaggedTermNe case "=~": - if err := validateRegex(terms[i].Value); err != nil { - return nil, err - } terms[i].Op = TaggedTermMatch case "!=~": - if err := validateRegex(terms[i].Value); err != nil { - return nil, err - } terms[i].Op = TaggedTermNotMatch default: return nil, fmt.Errorf("wrong seriesByTag expr: %#v", s) diff --git a/helper/clickhouse/clickhouse.go b/helper/clickhouse/clickhouse.go index 326c0129..ebba7fec 100644 --- a/helper/clickhouse/clickhouse.go +++ b/helper/clickhouse/clickhouse.go @@ -75,6 +75,9 @@ func extractClickhouseError(e string) (int, string) { if strings.HasPrefix(e, "clickhouse response status 404: Code: 60. DB::Exception: Table default.") { return http.StatusServiceUnavailable, "Storage default tables damaged" } + if strings.HasPrefix(e, "clickhouse response status 500: Code: 427") || strings.HasPrefix(e, "clickhouse response status 400: Code: 427.") { + return http.StatusBadRequest, "Incorrect regex syntax" + } return http.StatusServiceUnavailable, "Storage unavailable" } diff --git a/helper/clickhouse/clickhouse_test.go b/helper/clickhouse/clickhouse_test.go index 4a3304a8..5c72d399 100644 --- a/helper/clickhouse/clickhouse_test.go +++ b/helper/clickhouse/clickhouse_test.go @@ -39,6 +39,16 @@ func Test_extractClickhouseError(t *testing.T) { wantStatus: http.StatusServiceUnavailable, wantMessage: "Storage default tables damaged", }, + { + errStr: `clickhouse response status 500: Code: 427, e.displayText() = DB::Exception: OptimizedRegularExpression: cannot compile re2: ^t=.**a*, error: bad repetition operator: **. Look at https://github.com/google/re2/wiki/Syntax for reference. Please note that if you specify regex as an SQL string literal, the slashes have to be additionally escaped. For example, to match an opening brace, write '\(' -- the first slash is for SQL and the second one is for regex: while executing 'FUNCTION match(x :: 0, '^t=.**a*' :: 2) -> match(x, '^t=.**a*') UInt8 : 1': while executing 'FUNCTION arrayExists(__lambda_11 :: 7, Tags :: 3) -> arrayExists(lambda(tuple(x), and(like(x, 't=%'), match(x, '^t=.**a*'))), Tags) UInt8 : 6' (version 21.3.20.1 (official build))`, + wantStatus: http.StatusBadRequest, + wantMessage: "Incorrect regex syntax", + }, + { + errStr: `clickhouse response status 500: Code: 427. DB::Exception: OptimizedRegularExpression: cannot compile re2: ^t=.**a*, error: bad repetition operator: **. Look at https://github.com/google/re2/wiki/Syntax for reference. Please note that if you specify regex as an SQL string literal, the slashes have to be additionally escaped. For example, to match an opening brace, write '\(' -- the first slash is for SQL and the second one is for regex: while executing 'FUNCTION and(like(x, 't=%') :: 3, match(x, '^t=.**a*') :: 1) -> and(like(x, 't=%'), match(x, '^t=.**a*')) UInt8 : 2': while executing 'FUNCTION and(and(greaterOrEquals(Date, '2024-10-28'), lessOrEquals(Date, '2024-10-28')) :: 0, and(equals(Tag1, '__name__=request_success_total.counter'), arrayExists(lambda(tuple(x), equals(x, 'app=test')), Tags), arrayExists(lambda(tuple(x), equals(x, 'project=Test')), Tags), arrayExists(lambda(tuple(x), equals(x, 'environment=TEST')), Tags), arrayExists(lambda(tuple(x), and(like(x, 't=%'), match(x, '^t=.**a*'))), Tags)) :: 3) -> and(and(greaterOrEquals(Date, '2024-10-28'), lessOrEquals(Date, '2024-10-28')), and(equals(Tag1, '__name__=request_success_total.counter'), arrayExists(lambda(tuple(x), equals(x, 'app=test')), Tags), arrayExists(lambda(tuple(x), equals(x, 'project=Test')), Tags), arrayExists(lambda(tuple(x), equals(x, 'environment=TEST')), Tags), arrayExists(lambda(tuple(x), and(like(x, 't=%'), match(x, '^t=.**a*'))), Tags))) UInt8 : 6'. (CANNOT_COMPILE_REGEXP) (version 22.8.21.38 (official build))`, + wantStatus: http.StatusBadRequest, + wantMessage: "Incorrect regex syntax", + }, { errStr: "Other error", wantStatus: http.StatusServiceUnavailable, diff --git a/tests/feature_flags_both_true/test.toml b/tests/feature_flags_both_true/test.toml index 80f259d2..fd383dca 100644 --- a/tests/feature_flags_both_true/test.toml +++ b/tests/feature_flags_both_true/test.toml @@ -979,7 +979,7 @@ timeout = "1h" targets = [ "seriesByTag('name=request_success_total.counter', 'app=test', 'project=Test', 'environment=TEST', 't=~*a*')", ] -error_regexp = "^400: incorrect regex syntax" +error_regexp = "^400: Incorrect regex syntax" # ### seriesByTag('name=request_success_total.counter', 'app=test', 'project=Test', 'environment=TEST', 't=~*') ### diff --git a/tests/feature_flags_dont_match_missing_tags/test.toml b/tests/feature_flags_dont_match_missing_tags/test.toml index 7cc9d068..8e38d444 100644 --- a/tests/feature_flags_dont_match_missing_tags/test.toml +++ b/tests/feature_flags_dont_match_missing_tags/test.toml @@ -935,7 +935,7 @@ timeout = "1h" targets = [ "seriesByTag('name=request_success_total.counter', 'app=test', 'project=Test', 'environment=TEST', 't=~*a*')", ] -error_regexp = "^400: incorrect regex syntax" +error_regexp = "^400: Incorrect regex syntax" # ### seriesByTag('name=request_success_total.counter', 'app=test', 'project=Test', 'environment=TEST', 't=~*') ### diff --git a/tests/feature_flags_false/test.toml b/tests/feature_flags_false/test.toml index 18592f9e..f3f7a65f 100644 --- a/tests/feature_flags_false/test.toml +++ b/tests/feature_flags_false/test.toml @@ -1297,7 +1297,7 @@ timeout = "1h" targets = [ "seriesByTag('name=request_success_total.counter', 'app=test', 'project=Test', 'environment=TEST', 't=~*a*')", ] -error_regexp = "^400: incorrect regex syntax" +error_regexp = "^400: Incorrect regex syntax" # ### seriesByTag('name=request_success_total.counter', 'app=test', 'project=Test', 'environment=TEST', 't=~*') ### diff --git a/tests/feature_flags_use_carbon_behaviour/test.toml b/tests/feature_flags_use_carbon_behaviour/test.toml index 1906db71..c332be71 100644 --- a/tests/feature_flags_use_carbon_behaviour/test.toml +++ b/tests/feature_flags_use_carbon_behaviour/test.toml @@ -1341,7 +1341,7 @@ timeout = "1h" targets = [ "seriesByTag('name=request_success_total.counter', 'app=test', 'project=Test', 'environment=TEST', 't=~*a*')", ] -error_regexp = "^400: incorrect regex syntax" +error_regexp = "^400: Incorrect regex syntax" # ### seriesByTag('name=request_success_total.counter', 'app=test', 'project=Test', 'environment=TEST', 't=~*') ### From 38f3ea7caf98ee0ed95e8e8b79b5d997164b460d Mon Sep 17 00:00:00 2001 From: Artyom Antonov Date: Tue, 29 Oct 2024 14:17:11 +0500 Subject: [PATCH 4/4] improve readability --- pkg/where/match.go | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/pkg/where/match.go b/pkg/where/match.go index ade75d1d..0fe678e6 100644 --- a/pkg/where/match.go +++ b/pkg/where/match.go @@ -98,14 +98,10 @@ func HasUnmatchedBrackets(query string) bool { stack = append(stack, c) } if c == '}' || c == ']' { - if len(stack) == 0 { - return true - } - if stack[len(stack)-1] == matchingBracket[c] { - stack = stack[:len(stack)-1] - } else { + if len(stack) == 0 || stack[len(stack)-1] != matchingBracket[c] { return true } + stack = stack[:len(stack)-1] } } return len(stack) != 0