Skip to content

Conversation

fabian4
Copy link
Contributor

@fabian4 fabian4 commented Sep 8, 2025

Proposed changes

Problem: Add regex for path matching

external (regex path match without any head/method/queryparams condition)

exact: /foo => = /foo
prefix: /foo => = /foo + ^~ /foo/
regex: /foo/(.*)$ => ~ /foo/(.*)$

Closes #3110

Checklist

Before creating a PR, run through this checklist and mark each as complete.

  • I have read the CONTRIBUTING doc
  • I have added tests that prove my fix is effective or that my feature works
  • I have checked that all unit tests pass after adding my changes
  • I have updated necessary documentation
  • I have rebased my branch onto main
  • I will ensure my PR is targeting the main branch and pulling from my branch from my own fork

Release notes

If this PR introduces a change that affects users and needs to be mentioned in the release notes,
please add a brief note that summarizes the change.

Add regex support for path matching

Copy link

nginx-bot bot commented Sep 8, 2025

Hi @fabian4!

Thanks for opening this pull request!
Be sure to check out our Contributing Guidelines while you wait for someone on the team to review this.

@nginx-bot nginx-bot bot added the community label Sep 8, 2025
@fabian4 fabian4 marked this pull request as draft September 8, 2025 15:12
@fabian4 fabian4 force-pushed the add_regex_for_path_matching branch 2 times, most recently from 2202934 to 72227ea Compare September 9, 2025 15:28
@sindhushiv sindhushiv added this to the v2.2.0 milestone Sep 10, 2025
@sindhushiv sindhushiv moved this from 🆕 New to External Pull Requests in NGINX Gateway Fabric Sep 10, 2025
@salonichf5
Copy link
Contributor

Hey @fabian4, thanks a lot for your contribution to NGINX Gateway Fabric!

I noticed there are still some parts left in this PR—were you looking for initial feedback before continuing development, or are you planning to submit this in parts?

@fabian4
Copy link
Contributor Author

fabian4 commented Sep 12, 2025

Hi @salonichf5, thanks a lot for the comment! I kept this PR as a draft since there are still some parts I’d like to finish up. In the meantime, getting some early feedback would be super helpful — that way I can adjust things early and make sure I’m heading in the right direction. Really appreciate your input!

@fabian4 fabian4 closed this Sep 12, 2025
@fabian4 fabian4 force-pushed the add_regex_for_path_matching branch from 72227ea to 54135b5 Compare September 12, 2025 15:14
@github-project-automation github-project-automation bot moved this from External Pull Requests to ✅ Done in NGINX Gateway Fabric Sep 12, 2025
@fabian4 fabian4 reopened this Sep 12, 2025
@github-project-automation github-project-automation bot moved this from ✅ Done to 🆕 New in NGINX Gateway Fabric Sep 12, 2025
@sjberman sjberman moved this from 🆕 New to External Pull Requests in NGINX Gateway Fabric Sep 12, 2025
@fabian4 fabian4 force-pushed the add_regex_for_path_matching branch from c76e809 to 63c06fe Compare September 14, 2025 04:47
@salonichf5
Copy link
Contributor

Hi @salonichf5, thanks a lot for the comment! I kept this PR as a draft since there are still some parts I’d like to finish up. In the meantime, getting some early feedback would be super helpful — that way I can adjust things early and make sure I’m heading in the right direction. Really appreciate your input!

For sure, we will get some eyes on it. Thank you again for the contribution.

@fabian4 fabian4 marked this pull request as ready for review September 22, 2025 06:58
@sjberman sjberman added the enhancement New feature or request label Sep 22, 2025
@sjberman
Copy link
Collaborator

@fabian4 We'll be sure to review this soon!

In the meantime, I ran the pipeline and there are some linting/unit test errors. Also, please be sure to follow this guide for formatting your main commit message and PR description. And please update the release note section the PR description as well, so we can include a notein our CHANGELOG when this ultimately gets released.

@fabian4 fabian4 force-pushed the add_regex_for_path_matching branch from 194ac10 to ff24ee1 Compare September 22, 2025 15:15
@github-actions github-actions bot removed the enhancement New feature or request label Sep 22, 2025
@salonichf5 salonichf5 requested a review from Copilot September 23, 2025 02:12
Copy link

@Copilot Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull Request Overview

This PR adds regex support for path matching in NGINX Gateway Fabric, extending the existing exact and prefix path matching capabilities. It introduces a new PathTypeRegularExpression type and implements the necessary validation and configuration logic to support regex-based routing.

Key changes:

  • Adds validation infrastructure for regex path patterns with RE2 compatibility
  • Updates dataplane configuration to handle regex path types
  • Modifies NGINX config generation to create regex location blocks with ~ prefix

Reviewed Changes

Copilot reviewed 14 out of 14 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
internal/controller/state/validation/validator.go Adds new interface method for regex path validation
internal/controller/state/validation/validationfakes/fake_httpfields_validator.go Updates test fake with new regex validation method
internal/controller/state/graph/httproute_test.go Updates test expectations to accept regex paths
internal/controller/state/graph/httproute.go Implements regex path validation in route matching logic
internal/controller/state/dataplane/types.go Adds PathTypeRegularExpression constant
internal/controller/state/dataplane/convert_test.go Updates test to handle regex path conversion
internal/controller/state/dataplane/convert.go Adds regex path type conversion
internal/controller/nginx/config/validation/http_njs_match_test.go Removes obsolete path validation test
internal/controller/nginx/config/validation/http_njs_match.go Removes path validation method moved to common
internal/controller/nginx/config/validation/http_filters.go Adds new path validation methods
internal/controller/nginx/config/validation/common_test.go Adds comprehensive regex path validation tests
internal/controller/nginx/config/validation/common.go Implements regex path validation with RE2 constraints
internal/controller/nginx/config/servers_test.go Updates test expectations for new path formatting
internal/controller/nginx/config/servers.go Implements regex location generation and path handling

Tip: Customize your code reviews with copilot-instructions.md. Create the file or learn how to get started.

@github-project-automation github-project-automation bot moved this from External Pull Requests to 🏗 In Progress in NGINX Gateway Fabric Sep 23, 2025
@fabian4
Copy link
Contributor Author

fabian4 commented Sep 23, 2025

https://github.com/nginx/nginx-gateway-fabric/actions/runs/17919926662/job/50987553809?pr=3874
https://github.com/nginx/nginx-gateway-fabric/actions/runs/17919926622/job/50987553763?pr=3874

BTW I can't figure why above test are failing since I can't get any thing like that when I run unit test and lint on my env.

It says the github.com/nginx/agent/[email protected] package sum mismatch and the go lint location is empty. I don't think I have touched the related code, So still confused about the reason here.

@sjberman
Copy link
Collaborator

sjberman commented Sep 23, 2025

@fabian4 Yeah I saw similar issues on my fork recently as well, not sure what's happening there. We'll investigate.

@fabian4 fabian4 requested a review from salonichf5 September 25, 2025 07:35
@sindhushiv sindhushiv moved this from 🏗 In Progress to External Pull Requests in NGINX Gateway Fabric Sep 25, 2025
@salonichf5
Copy link
Contributor

salonichf5 commented Sep 26, 2025

@fabian I just had the first successful run for my fork test PR, so hopefully the pipeline issues should resolve for you now.

I'll get on to testing your PR once we can run the linter and tests in the pipeline.

Problem: As regex path matching is missing support for NGF.

Solution: Add support for regex path matching, only allow a full path rewrite/redirect after the regex path match.

Testing: Add additional unit test case for regex path match.
@fabian4 fabian4 force-pushed the add_regex_for_path_matching branch from 7f70c31 to 895c15c Compare September 29, 2025 11:13
@salonichf5
Copy link
Contributor

Testing done on the branch

Error expected cases:

  1. Test for Path types allowed - PASSED
    - path:
        type: RegularExpressionInvalid
        value: /coffee-hello///

The HTTPRoute "coffee" is invalid: 
* spec.rules[1].matches[0].path.type: Unsupported value: "RegularExpressionInvalid": supported values: "Exact", "PathPrefix", "RegularExpression"
* <nil>: Invalid value: null: some validation rules were not checked because the object was invalid; correct the existing errors to complete validation
  1. Invalid Regular expression

Case 1: Drops its if starts with ^

  Last Transition Time:  2025-10-01T21:21:34Z
      Message:               Dropped Rule(s): spec.rules[1].matches[0].path.value: Invalid value: "^/foo$": must start with / and must not include any whitespace character, `{`, `}` or `;` (e.g. '/',  or '/path',  or '/path/subpath-123', regex used for validation is '/[^\s{};]*')

    - path:
        type: RegularExpression
        value: ^/foo$

Case 2: unescaped $


    - path:
        type: RegularExpression
        value: /foo$

ime:  2025-10-01T21:22:59Z
      Message:               Dropped Rule(s): spec.rules[1].matches[0].path.value: Invalid value: "/foo$": invalid unescaped `$` at position 4 in path '/foo$'

Case 3: Very long pattern

   - path:
        type: RegularExpression
        value: /aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa

The HTTPRoute "coffee" is invalid: 
* spec.rules[1].matches[0].path.value: Too long: may not be more than 1024 bytes
* <nil>: Invalid value: null: some validation rules were not checked because the object was invalid; correct the existing errors to complete validation

  1. Malicious attacks using regex ( got these from malicious intent regex from chatgpt)
Regex Pattern Example Input Why Unsafe / Invalid Expected Outcome Actual Outcome
/(a+)+ /aaaaaa... (1M chars) Catastrophic backtracking (ReDoS) Reject Accepted
/(.+)+ /longpath.... Nested quantifiers cause blowup Reject Accepted
/.* /foo, /bar Overly broad, matches everything Reject Dropped Rule(s): spec.rules[1].matches[0].path.value: Invalid value: "/(?<=foo)bar": invalid RE2 regex ...
/(?<=foo)bar /foobar Lookbehind unsupported (RE2) Reject Dropped Rule(s): invalid RE2 regex, error parsing (?<=foo)bar
/\1 /foo Backreference, unsafe Reject Dropped Rule(s): invalid escape sequence \1
/(a /a Unterminated group (syntax error) Reject Dropped Rule(s): missing closing )
/.{0,} /longinput Equivalent to match-all Reject Dropped Rule(s): must not include {, } or ;
/.../. /../../etc/passwd Path traversal pattern Reject Accepted

@salonichf5
Copy link
Contributor

Testing done on the branch

Checking functionality that Regex works as expected

Regex Pattern Should Match Should NOT Match Results
/foo /foo, /foo/, /foo/bar, /foobar /bar, /fo PASS
/foo.*bar /foo123bar, /foo/bar /foo, /bar PASS
/api/v[0-9]+ /api/v1, /api/v12, /api/v123 /api/, /api/v PASS
/ /, /foo, // this matches everything should we allow it? PASS
`/(users admins)/[a-z]+` /users/john, /admins/alice PASS

return fmt.Sprintf("~ %s", rule.Path)
default:
return rule.Path
return "" // should never happen because path type is validated earlier
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should we panic here like we do for other cases @ciarams87 ?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i guess its fine, this is how we have handled it in the past so should be good

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think your first instinct was correct actually - this should be a panic. Now this function silently returns an invalid location path instead of at least returning the original path as a fallback. This is a programmer error (all path types should be handled), not a runtime error from user input (which is validated earlier), so panic() is appropriate and consistent.

@salonichf5
Copy link
Contributor

We need to also validate preexisting behaviour for URLRewrite, Redirect and other filters.

@salonichf5
Copy link
Contributor

@fabian4 Thank you for your patience. We are currently testing Regex thoroughly—both on its own and in combination with our other filters.
We’ll consolidate all findings and provide you with a complete review of the changes required, so they can be addressed together.

I really appreciate your contribution. From my initial round of testing, everything looks good overall, with only a few exceptions that we’d like to discuss as a team to decide whether we want to allow them or not.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
Status: External Pull Requests
Development

Successfully merging this pull request may close these issues.

Regex for path matching: RegularExpression
7 participants