Skip to content

Commit

Permalink
topdown: support glob.match without delimiters (#4933)
Browse files Browse the repository at this point in the history
Using null for delimiters disables delimiters in glob matching. Preferable over regex on some cases for performance reasons.

Fixes #4923.

Signed-off-by: vinhph0906 <vinhph0906@gmail.com>
Co-authored-by: Stephan Renatus <stephan.renatus@gmail.com>
  • Loading branch information
vinhph0906 and srenatus committed Jul 25, 2022
1 parent c981cc9 commit da4a100
Show file tree
Hide file tree
Showing 10 changed files with 80 additions and 23 deletions.
5 changes: 4 additions & 1 deletion ast/builtins.go
Expand Up @@ -2604,7 +2604,10 @@ var GlobMatch = &Builtin{
Decl: types.NewFunction(
types.Args(
types.Named("pattern", types.S),
types.Named("delimiters", types.NewArray(nil, types.S)).Description("glob pattern delimiters, e.g. `[\".\", \":\"]`, defaults to `[\".\"]` if unset."),
types.Named("delimiters", types.NewAny(
types.NewArray(nil, types.S),
types.NewNull(),
)).Description("glob pattern delimiters, e.g. `[\".\", \":\"]`, defaults to `[\".\"]` if unset. If `delimiters` is `null`, glob match without delimiter."),
types.Named("match", types.S),
),
types.Named("result", types.B).Description("true if `match` can be found in `pattern` which is separated by `delimiters`"),
Expand Down
4 changes: 2 additions & 2 deletions builtin_metadata.json
Expand Up @@ -3677,9 +3677,9 @@
"type": "string"
},
{
"description": "glob pattern delimiters, e.g. `[\".\", \":\"]`, defaults to `[\".\"]` if unset.",
"description": "glob pattern delimiters, e.g. `[\".\", \":\"]`, defaults to `[\".\"]` if unset. If `delimiters` is `null`, glob match without delimiter.",
"name": "delimiters",
"type": "array[string]"
"type": "any\u003cnull, array[string]\u003e"
},
{
"name": "match",
Expand Down
16 changes: 12 additions & 4 deletions capabilities.json
Expand Up @@ -894,10 +894,18 @@
"type": "string"
},
{
"dynamic": {
"type": "string"
},
"type": "array"
"of": [
{
"type": "null"
},
{
"dynamic": {
"type": "string"
},
"type": "array"
}
],
"type": "any"
},
{
"type": "string"
Expand Down
1 change: 1 addition & 0 deletions docs/content/policy-reference.md
Expand Up @@ -337,6 +337,7 @@ The following table shows examples of how ``glob.match`` works:
| -------- | ---------- | ----------- |
| ``output := glob.match("*.github.com", [], "api.github.com")`` | ``true`` | A glob with the default ``["."]`` delimiter. |
| ``output := glob.match("*.github.com", [], "api.cdn.github.com")`` | ``false`` | A glob with the default ``["."]`` delimiter. |
| ``output := glob.match("*hub.com", null, "api.cdn.github.com")`` | ``true`` | A glob without delimiter. |
| ``output := glob.match("*:github:com", [":"], "api:github:com")`` | ``true`` | A glob with delimiters ``[":"]``. |
| ``output := glob.match("api.**.com", [], "api.github.com")`` | ``true`` | A super glob. |
| ``output := glob.match("api.**.com", [], "api.cdn.github.com")`` | ``true`` | A super glob. |
Expand Down
10 changes: 4 additions & 6 deletions internal/compiler/wasm/opa/callgraph.csv

Large diffs are not rendered by default.

29 changes: 29 additions & 0 deletions test/cases/testdata/globmatch/test-globmatch-0159.yaml
@@ -0,0 +1,29 @@
cases:
- data: {}
modules:
- |
package generated
p[x] {
glob.match("*", null, "foo.bar", x)
}
note: globmatch/glob match single without default delimiter
query: data.generated.p = x
sort_bindings: true
want_result:
- x:
- true
- data: {}
modules:
- |
package generated
p[x] {
glob.match("foo*", null, "foo.bar", x)
}
note: globmatch/glob match single without default delimiter, glob non-empty
query: data.generated.p = x
sort_bindings: true
want_result:
- x:
- true
22 changes: 14 additions & 8 deletions topdown/glob.go
Expand Up @@ -18,16 +18,22 @@ func builtinGlobMatch(a, b, c ast.Value) (ast.Value, error) {
if err != nil {
return nil, err
}
var delimiters []rune
switch b.(type) {
case ast.Null:
delimiters = []rune{}
case *ast.Array:
delimiters, err = builtins.RuneSliceOperand(b, 2)
if err != nil {
return nil, err
}

delimiters, err := builtins.RuneSliceOperand(b, 2)
if err != nil {
return nil, err
}

if len(delimiters) == 0 {
delimiters = []rune{'.'}
if len(delimiters) == 0 {
delimiters = []rune{'.'}
}
default:
return nil, builtins.NewOperandTypeErr(2, b, "array", "null")
}

match, err := builtins.StringOperand(c, 3)
if err != nil {
return nil, err
Expand Down
2 changes: 1 addition & 1 deletion wasm/src/glob-compiler.cc
Expand Up @@ -128,7 +128,7 @@ std::string glob_translate(const char *glob, size_t n, const std::vector<std::st

if (delimiters.empty())
{
single_mark = "[^\\.]";
single_mark = ".";
} else {
single_mark = "[^";

Expand Down
13 changes: 12 additions & 1 deletion wasm/src/glob.cc
Expand Up @@ -53,7 +53,9 @@ static glob_cache* cache()
OPA_BUILTIN
opa_value *opa_glob_match(opa_value *pattern, opa_value *delimiters, opa_value *match)
{
if (opa_value_type(pattern) != OPA_STRING || opa_value_type(delimiters) != OPA_ARRAY || opa_value_type(match) != OPA_STRING)
if (opa_value_type(pattern) != OPA_STRING ||
(opa_value_type(delimiters) != OPA_ARRAY && opa_value_type(delimiters) != OPA_NULL) ||
opa_value_type(match) != OPA_STRING)
{
return NULL;
}
Expand All @@ -75,6 +77,15 @@ opa_value *opa_glob_match(opa_value *pattern, opa_value *delimiters, opa_value *
v.push_back(std::string(s->v, s->len));
prev = curr;
}

// NOTE(sr): If we're passed an empty array, use "." as default delimiter.
// If we're passed OPA_NULL, use no delimiter; but separate glob parts by '.*'
if (opa_value_type(delimiters) == OPA_ARRAY) {
if (v.empty())
{
v.push_back(std::string("."));
}
}

glob_cache *c = cache();
cache_key key = cache_key(std::string(p->v, p->len), v);
Expand Down
1 change: 1 addition & 0 deletions wasm/tests/test-glob.cc
Expand Up @@ -234,6 +234,7 @@ void test_glob_translate()
for (int i = 0; i < sizeof(delimiters)/sizeof(const char*); i++) { \
v.push_back(delimiters[i]); \
} \
if (v.empty()) { v.push_back(std::string(".")); } \
glob_translate(pattern, strlen(pattern), v, &re2); \
test_str_eq(test_case, expected, re2.c_str()); \
re2::RE2::Options options; \
Expand Down

0 comments on commit da4a100

Please sign in to comment.