Search code examples
oparego

OPA rego policy - pattern matching using valid regex not working


I'm using OPA to write an access policy to a microservice, and I'm now tackling the problem of matching an URL containing a path param.

The URL follows the pattern: /v1/users/{uuid}

I came up with the following regex which matches /v1/users/ followed by a valid UUID: ^/v1/users/[0-9a-fA-F]{8}\b-[0-9a-fA-F]{4}\b-[0-9a-fA-F]{4}\b-[0-9a-fA-F]{4}\b-[0-9a-fA-F]{12}$

When testing it against /v1/users/29fe7f14-f04b-4607-9ece-9bd0525f7b38 on an online regex tester it succesfully matches.

However, it isn't matching inside the policy:

is_accessing_user_resource if {
    re_match(
        "^/v1/users/[0-9a-fA-F]{8}\b-[0-9a-fA-F]{4}\b-[0-9a-fA-F]{4}\b-[0-9a-fA-F]{4}\b-[0-9a-fA-F]{12}$",
        input.path,
    )
}

I'm testing it with the following input.json

{
    "body": null,
    "claims": {},
    "method": "GET",
    "path": "/v1/users/29fe7f14-f04b-4607-9ece-9bd0525f7b38"
}

Is there any adaptation needed when using regex in rego?


Solution

  • By reading the documentation regarding raw strings:

    The other type of string declaration is a raw string declaration. These are made of characters surrounded by backticks (`), with the exception that raw strings may not contain backticks themselves. Raw strings are what they sound like: escape sequences are not interpreted, but instead taken as the literal text inside the backticks. For example, the raw string `hello\there`  will be the text “hello\there”, not “hello” and “here” separated by a tab. Raw strings are particularly useful when constructing regular expressions for matching, as it eliminates the need to double escape special characters." da doc A simple example is a regex to match a valid Rego variable. With a regular string, the regex is "[a-zA-Z_]\w*", but with raw strings, it becomes `[a-zA-Z_]\w*`.

    In this case, my regex was failing to match because it contained unescaped backslashes.

    It was solved by changing the the quotation marks to backticks, like so:

    re_match(
            `^/v1/users/[0-9a-fA-F]{8}\b-[0-9a-fA-F]{4}\b-[0-9a-fA-F]{4}\b-[0-9a-fA-F]{4}\b-[0-9a-fA-F]{12}$`,
            input.path,
        )