Skip to content

Request transformation#932

Open
Tharsanan1 wants to merge 4 commits intowso2:mainfrom
Tharsanan1:request-transformation
Open

Request transformation#932
Tharsanan1 wants to merge 4 commits intowso2:mainfrom
Tharsanan1:request-transformation

Conversation

@Tharsanan1
Copy link
Contributor

@Tharsanan1 Tharsanan1 commented Feb 4, 2026

Purpose

Fixes: #442

Summary by CodeRabbit

  • New Features

    • Added Request Transformation Policy enabling path rewriting (prefix, full-path, and regex-based), query parameter rewriting (add, replace, remove, append), and HTTP method rewriting with optional conditional matching based on headers and query parameters.
  • Documentation

    • Added comprehensive design documentation for Request Transformation Policy.
  • Tests

    • Added integration test scenarios for Request Transformation Policy functionality.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Feb 4, 2026

Warning

Rate limit exceeded

@Tharsanan1 has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 15 minutes and 55 seconds before requesting another review.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

Walkthrough

This PR introduces a Request Transformation Policy feature enabling rewriting of request paths, query parameters, and HTTP methods through dynamic metadata communication between the policy engine and a Lua-based transformation filter integrated into the Envoy HTTP filter chain.

Changes

Cohort / File(s) Summary
Configuration & Constants
gateway/configs/config-template.toml, kubernetes/helm/.../gateway-config.yaml, kubernetes/helm/.../values.yaml, gateway/gateway-controller/pkg/config/config.go, gateway/gateway-controller/pkg/constants/constants.go
Add lua_script_path configuration key to router settings, expose via Helm templates and values, introduce DefaultLuaScriptPath constant, add LuaScriptPath field to RouterConfig, and define ExtProcMetadataNamespace constant.
Lua Script & Dockerfile
gateway/gateway-controller/lua/request_transformation.lua, gateway/gateway-controller/Dockerfile
Implement Lua HTTP request transformation filter that reads target method from dynamic metadata, validates against allowed HTTP methods, and updates request :method header; copy lua directory into runtime image.
Policy Definition & Design
gateway/gateway-controller/default-policies/request-transformation.yaml, policies/request-transformation/design.md
Define request-transformation policy schema supporting path rewrite (prefix, full-path, regex), query parameter rewrite (Add, Replace, Remove, Append, ReplaceRegexMatch), and HTTP method rewrite with optional match conditions; provide comprehensive design documentation covering architecture, semantics, and error handling.
XDS Translator & Filter Chain
gateway/gateway-controller/pkg/xds/translator.go
Add createLuaFilter method to build Envoy Lua filter configuration, integrate Lua filter into HTTP filter chains across multiple listener builders (main, internal, dynamic forward), update ext_proc metadata namespaces to use ExtProcMetadataNamespace constant.
Dynamic Metadata Support
gateway/policy-engine/internal/kernel/execution_context.go, gateway/policy-engine/internal/kernel/translator.go, gateway/policy-engine/internal/kernel/extproc.go, sdk/gateway/policy/v1alpha/action.go
Add dynamicMetadata field to PolicyExecutionContext; extend translator to propagate dynamic metadata across request and response paths; update action types (UpstreamRequestModifications, ImmediateResponse, UpstreamResponseModifications) with DynamicMetadata field; update buildDynamicMetadata to aggregate multi-namespace metadata.
Integration Testing
gateway/it/features/request-transformation.feature
Add comprehensive feature file with scenarios validating path rewrites (prefix, full-path, regex), query parameter rewrites, HTTP method rewrite, and conditional matching based on headers.

Sequence Diagram(s)

sequenceDiagram
    participant Client
    participant Envoy as Envoy (Gateway)
    participant ExtProc as Policy Engine<br/>(ext_proc)
    participant LuaFilter as Lua Filter
    participant Upstream

    Client->>Envoy: HTTP Request (GET /api/v1/users)
    Envoy->>ExtProc: RequestHeaders Phase
    ExtProc->>ExtProc: Evaluate Policies<br/>(Request Transformation)
    ExtProc->>ExtProc: Set Dynamic Metadata<br/>(request_transformation.target_method: POST)
    ExtProc->>Envoy: ResponseHeaders with<br/>DynamicMetadata
    Envoy->>LuaFilter: RequestHeaders Phase
    LuaFilter->>LuaFilter: Read Dynamic Metadata<br/>from ext_proc namespace
    LuaFilter->>LuaFilter: Extract target_method<br/>Normalize & Validate
    LuaFilter->>LuaFilter: Apply Path Rewrite<br/>(regex/prefix/full)
    LuaFilter->>LuaFilter: Apply Query Rewrite<br/>(Add/Replace/Remove)
    LuaFilter->>LuaFilter: Update :method Header<br/>(e.g., GET → POST)
    LuaFilter->>Upstream: Transformed Request
    Upstream->>LuaFilter: Response
    LuaFilter->>Client: Response
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Poem

🐰 Hops of joy through paths rewritten,
Methods transformed, requests smitten,
Lua whispers what it knows,
Dynamic metadata flows and flows,
Metadata magic, oh so bright—
Making transformations right!

🚥 Pre-merge checks | ✅ 2 | ❌ 3
❌ Failed checks (2 warnings, 1 inconclusive)
Check name Status Explanation Resolution
Description check ⚠️ Warning The PR description is severely incomplete, containing only the Purpose section with a single issue link. Goals, Approach, User stories, Documentation, Automation tests, Security checks, Samples, Related PRs, and Test environment sections are all missing. Complete the PR description by adding all required sections: Goals, Approach with design rationale, User stories, Documentation links, detailed Unit and Integration test coverage, Security checks confirmation, Samples, Related PRs, and Test environment details.
Docstring Coverage ⚠️ Warning Docstring coverage is 71.43% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Title check ❓ Inconclusive The title 'Request transformation' is vague and generic, using non-descriptive terminology that doesn't clearly convey the specific changes in the PR. Use a more specific title that indicates the main change, such as 'Add request transformation policy with Lua filter for path and method rewriting' or 'Implement dynamic metadata-driven request transformation'.
✅ Passed checks (2 passed)
Check name Status Explanation
Linked Issues check ✅ Passed The PR successfully implements all core requirements from issue #442: Policy Engine now sets Dynamic Metadata via new DynamicMetadata fields in action types, Lua filter reads and applies metadata to transform request paths and methods, and integration tests validate both path and method transformations.
Out of Scope Changes check ✅ Passed All changes are directly related to implementing request transformation as specified in issue #442. No unrelated modifications or scope creep detected across configuration, controller, policy engine, SDK, and test files.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In `@policies/request-transformation/design.md`:
- Around line 514-516: The design doc's namespace entry currently lists
"envoy.filters.http.lua" but the implementation uses
"api_platform.policy_engine.envoy.filters.http.ext_proc"; update the table row
for the request_transformation.target_method policy to use the implementation
namespace "api_platform.policy_engine.envoy.filters.http.ext_proc" (or, if you
prefer to change code, make the Lua script use "envoy.filters.http.lua") so the
design entry for request_transformation.target_method matches the actual
namespace string used by the Lua implementation.
🧹 Nitpick comments (9)
gateway/gateway-controller/default-policies/request-transformation.yaml (1)

35-42: Consider adding conditional validation for value field.

The value field has minLength: 1 but is only required for Exact and Regex match types (not Present). The current schema allows omitting value (it's not in required), but if provided, it must be non-empty. This is technically correct behavior.

However, the schema doesn't enforce that value must be present when type is Exact or Regex. Users could provide type: Exact without a value, which would likely fail at runtime.

kubernetes/helm/gateway-helm-chart/values.yaml (1)

174-176: Minor: Comment is too narrow for the feature scope.

The comment says "request method transformation" but the Lua script handles path rewriting, query parameter rewriting, AND method transformation. Consider updating for accuracy:

📝 Suggested comment update
-        # Lua script path for request method transformation
+        # Lua script path for request transformation (path, query, method rewrites)
         lua_script_path: ./lua/request_transformation.lua
kubernetes/helm/gateway-helm-chart/templates/gateway/gateway-config.yaml (1)

82-84: Duplicate [gateway_controller.router] section header.

A [gateway_controller.router] section already exists at line 44. While TOML allows redeclaring sections to continue adding keys, this creates fragmented configuration that's harder to maintain. Consider moving lua_script_path alongside the other router settings:

♻️ Suggested consolidation
     [gateway_controller.router]
     gateway_host = {{ $gc.router.gateway_host | quote }}
     listener_port = {{ $gc.router.listener_port }}
     https_enabled = {{ $gc.router.https_enabled }}
     https_port = {{ $gc.router.https_port }}
     tracing_service_name = {{ $gc.router.tracing_service_name | default "" | quote }}
+    lua_script_path = {{ $gc.router.lua_script_path | quote }}
 
     [gateway_controller.router.access_logs]
     ...
-
-    [gateway_controller.router]
-    lua_script_path = {{ $gc.router.lua_script_path | quote }}
-
     [gateway_controller.router.policy_engine]
gateway/configs/config-template.toml (1)

105-107: Duplicate [gateway_controller.router] section header.

Same issue as the Helm template - [gateway_controller.router] is already declared at line 40. Consolidate lua_script_path with the existing router settings for cleaner configuration:

♻️ Suggested consolidation
 [gateway_controller.router]
 # Gateway host for incoming requests
 gateway_host = "*"
 # Listener port for incoming HTTP traffic (Envoy proxy port)
 listener_port = 8080
 # HTTPS listener configuration
 https_enabled = true
 https_port = 8443
 # Tracing service name
 tracing_service_name = "router"
+# Lua script path for request transformation
+lua_script_path = "./lua/request_transformation.lua"
 
 [gateway_controller.router.access_logs]
 ...
-
-[gateway_controller.router]
-lua_script_path = "./lua/request_transformation.lua"
-
 [gateway_controller.router.policy_engine]
gateway/gateway-controller/pkg/config/config.go (1)

212-212: Consider adding validation for LuaScriptPath.

The LuaScriptPath field is added to the config, but there's no corresponding validation in the Validate() method. While the translator will fail if the file doesn't exist, adding validation here would provide earlier feedback during config loading.

This is optional since the error will be caught at runtime during filter creation.

gateway/gateway-controller/lua/request_transformation.lua (1)

55-55: Hardcoded namespace string duplicates constant value.

The namespace "api_platform.policy_engine.envoy.filters.http.ext_proc" is hardcoded here but defined as ExtProcMetadataNamespace in constants.go. While Lua scripts can't directly reference Go constants, consider adding a comment documenting the dependency to help maintainers keep them in sync.

-  local extproc_metadata = dynamic_metadata:get("api_platform.policy_engine.envoy.filters.http.ext_proc")
+  -- NOTE: This namespace must match constants.ExtProcMetadataNamespace in Go code
+  local extproc_metadata = dynamic_metadata:get("api_platform.policy_engine.envoy.filters.http.ext_proc")
policies/request-transformation/design.md (1)

31-33: Add language specifier to fenced code block.

The code block lacks a language specifier per markdownlint MD040.

-```
+```text
 Request → ext_proc (Policy Engine) → Lua Filter → Upstream
-```
+```
gateway/it/features/request-transformation.feature (1)

213-253: Consider verifying parameter removal in query rewrite test.

The scenario tests Add and Replace actions but doesn't explicitly verify that the debug parameter was removed. While line 253 checks the expected values, adding verification that debug is absent would strengthen the test.

This is optional since the test validates the core functionality.

gateway/gateway-controller/pkg/xds/translator.go (1)

2370-2402: Well-implemented Lua filter creation with proper error handling.

The implementation:

  • Falls back to default path if not configured
  • Validates file readability and non-empty content
  • Uses inline code delivery as documented in design.md

Minor observation: script (trimmed) is used for validation but scriptBytes (untrimmed) is used for InlineCode. This is fine since Lua ignores surrounding whitespace, but for consistency you could use script:

 	luaConfig := &luav3.Lua{
-		InlineCode: string(scriptBytes),
+		InlineCode: script,
 	}

server_header_value = "WSO2 API Platform"

[gateway_controller.router.lua.request_transformation]
script_path = "./lua/request_transformation.lua"
Copy link
Contributor

Choose a reason for hiding this comment

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

Should this be a config? This is an internal file we maintain, right? Users are not required to change this.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yes — this is an internal script we ship. I ll remove it from the default config templates, but keep the configurability in code. That way anyone who custom‑builds the gateway can still ship a differently named/path Lua file and point the gateway to it via config(no need to touch the code for changing a file path in n the image) if needed. WDYT?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Support path/method Rewrite and Dynamic Endpoint Actions

2 participants