Skip to content

feat(api): Add filterContext field to Lua type in EnvoyExtensionPolicy - #8730

Merged
rudrakhp merged 16 commits into
envoyproxy:mainfrom
norman-zon:8765-envoyextensionpolicy-filtercontext
Jun 20, 2026
Merged

feat(api): Add filterContext field to Lua type in EnvoyExtensionPolicy#8730
rudrakhp merged 16 commits into
envoyproxy:mainfrom
norman-zon:8765-envoyextensionpolicy-filtercontext

Conversation

@norman-zon

Copy link
Copy Markdown
Contributor

What type of PR is this?

feat/api

What this PR does / why we need it:

Adds an optional filterContext field (map[string]string) to the Lua type in EnvoyExtensionPolicySpec, exposing Envoy's existing LuaPerRoute.filter_context field.

This allows a shared Lua script (stored in a ConfigMap via ValueRef) to be parameterized differently per route using request_handle:filterContext(). Without this, users must either duplicate the entire script inline with hardcoded values for each route or use EnvoyPatchPolicy to manually patch the generated xDS — both of which are fragile and defeat the purpose of script reuse.

Example usage:

lua:
  - type: ValueRef
    valueRef:
      name: shared-auth-lua
      kind: ConfigMap
    filterContext:
      token_header: x-api-key

The Lua script accesses the values via:

local ctx = request_handle:filterContext()
local header_name = ctx["token_header"]

Changes:

  • api/v1alpha1/lua_types.go — add FilterContext map[string]string to Lua struct
  • internal/ir/xds.go — add FilterContext to IR Lua struct
  • internal/gatewayapi/envoyextensionpolicy.go — pass FilterContext from API → IR
  • internal/xds/translator/lua.go — set FilterContext on LuaPerRoute, converting map[string]stringstructpb.Struct
  • GatewayAPI and xDS translator testdata updated
  • E2E test added: Lua script reads filterContext() and sets value as response header
  • Documentation updated with FilterContext section in Lua task guide
  • Release note added

No new Envoy features required — this only exposes an existing LuaPerRoute field.

Which issue(s) this PR fixes:

Fixes #8715

Release Notes: Yes

@norman-zon
norman-zon requested a review from a team as a code owner April 13, 2026 08:59
@netlify

netlify Bot commented Apr 13, 2026

Copy link
Copy Markdown

Deploy Preview for cerulean-figolla-1f9435 ready!

Name Link
🔨 Latest commit 23ec2f0
🔍 Latest deploy log https://app.netlify.com/projects/cerulean-figolla-1f9435/deploys/6a36887527abf30008261d5a
😎 Deploy Preview https://deploy-preview-8730--cerulean-figolla-1f9435.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify project configuration.

@codecov

codecov Bot commented Apr 13, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 75.00000% with 2 lines in your changes missing coverage. Please review.
✅ Project coverage is 75.20%. Comparing base (675f6e2) to head (23ec2f0).

Files with missing lines Patch % Lines
internal/xds/translator/lua.go 60.00% 1 Missing and 1 partial ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #8730      +/-   ##
==========================================
+ Coverage   75.19%   75.20%   +0.01%     
==========================================
  Files         252      252              
  Lines       41031    41037       +6     
==========================================
+ Hits        30853    30862       +9     
+ Misses       8083     8080       -3     
  Partials     2095     2095              

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@zirain

zirain commented Apr 14, 2026

Copy link
Copy Markdown
Member

@codex review

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. What shall we delve into next?

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

@norman-zon
norman-zon force-pushed the 8765-envoyextensionpolicy-filtercontext branch 2 times, most recently from 4bc5e02 to 070ba24 Compare April 15, 2026 12:51
zirain
zirain previously approved these changes Apr 15, 2026
@zirain

zirain commented Apr 16, 2026

Copy link
Copy Markdown
Member

FAIL: TestE2E/LuaHTTP/http_route_with_lua_filter_context (60.01s) e2e failed.

@rudrakhp rudrakhp left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

You will need to add mocks for the filterContext() api in the validator mocks which is failing your E2E. Please refer how other APIs are mocked for this.

@norman-zon
norman-zon force-pushed the 8765-envoyextensionpolicy-filtercontext branch from 81ff141 to c6098cd Compare April 28, 2026 07:55
@norman-zon
norman-zon requested a review from rudrakhp April 28, 2026 08:29
@norman-zon
norman-zon force-pushed the 8765-envoyextensionpolicy-filtercontext branch from f8106cf to 6dc32d9 Compare April 30, 2026 06:58

@rudrakhp rudrakhp left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Overall LGTM with some comments. Thanks for the contribution!

Comment thread internal/ir/xds.go Outdated
Comment thread api/v1alpha1/lua_types.go
Comment thread api/v1alpha1/lua_types.go Outdated
Comment thread internal/xds/translator/lua.go Outdated
@rudrakhp rudrakhp added this to the v1.8.0 Release milestone Apr 30, 2026
norman-zon added 5 commits May 5, 2026 10:50
…#8715)

Add an optional `filterContext` field (map[string]string) to the Lua type
in EnvoyExtensionPolicySpec. This exposes Envoy's existing
LuaPerRoute.filter_context so that a shared Lua script can be
parameterized differently per route via request_handle:filterContext().

Without this, users must either duplicate the entire script inline with
hardcoded values or resort to EnvoyPatchPolicy to manually patch xDS.

Changes:
- api: add FilterContext to Lua struct
- ir: add FilterContext to IR Lua struct
- gatewayapi: pass FilterContext from API to IR in buildLua()
- xds: set FilterContext on LuaPerRoute in patchRoute(), converting
  map[string]string to structpb.Struct
- tests: update gatewayapi/xds translator testdata, add e2e test
- docs: add FilterContext section to Lua extension task guide

Signed-off-by: Norman Stetter <85173861+norman-zon@users.noreply.github.com>
Signed-off-by: Norman Stetter <85173861+norman-zon@users.noreply.github.com>
Signed-off-by: Norman Stetter <85173861+norman-zon@users.noreply.github.com>
Signed-off-by: Norman Stetter <85173861+norman-zon@users.noreply.github.com>
Signed-off-by: Norman Stetter <85173861+norman-zon@users.noreply.github.com>
norman-zon added a commit to norman-zon/envoy-gateway that referenced this pull request May 5, 2026
Address review feedback on envoyproxy#8730:

- Change FilterContext field type from map[string]string to
  *apiextensionsv1.JSON in both the API (lua_types.go) and IR (xds.go),
  matching the existing pattern used by Wasm.Config and
  DynamicModule.Config.
- Drop json/yaml struct tags from ir.Lua.FilterContext, consistent with
  the other untagged fields on that struct.
- Update the xDS translator to unmarshal FilterContext.Raw into
  structpb.Struct via protojson.Unmarshal, replacing the previous
  string-only map iteration.
- Regenerate deepcopy, CRD manifests, and test fixtures.

Users can now pass non-string JSON values (numbers, bools, nested
objects) in filterContext without stringifying them.

Signed-off-by: Norman Stetter <85173861+norman-zon@users.noreply.github.com>
@norman-zon
norman-zon force-pushed the 8765-envoyextensionpolicy-filtercontext branch from 6dc32d9 to 93ac819 Compare May 5, 2026 08:52
Address review feedback on envoyproxy#8730:

- Change FilterContext field type from map[string]string to
  *apiextensionsv1.JSON in both the API (lua_types.go) and IR (xds.go),
  matching the existing pattern used by Wasm.Config and
  DynamicModule.Config.
- Drop json/yaml struct tags from ir.Lua.FilterContext, consistent with
  the other untagged fields on that struct.
- Update the xDS translator to unmarshal FilterContext.Raw into
  structpb.Struct via protojson.Unmarshal, replacing the previous
  string-only map iteration.
- Regenerate deepcopy, CRD manifests, and test fixtures.

Users can now pass non-string JSON values (numbers, bools, nested
objects) in filterContext without stringifying them.

Signed-off-by: Norman Stetter <85173861+norman-zon@users.noreply.github.com>
@norman-zon
norman-zon force-pushed the 8765-envoyextensionpolicy-filtercontext branch from 93ac819 to c01f433 Compare May 5, 2026 09:01
@norman-zon
norman-zon requested a review from rudrakhp May 5, 2026 09:03
…ropagate filter context in Lua test

filterContext() is only available on request_handle, not response_handle.
Read the value in envoy_on_request and store it via dynamicMetadata, then
retrieve it in envoy_on_response to set the X-Lua-Filter-Context header.

Fixes TestE2E/LuaHTTP/http_route_with_lua_filter_context

Signed-off-by: Norman Stetter <85173861+norman-zon@users.noreply.github.com>
@zhaohuabing zhaohuabing removed this from the v1.8.0 Release milestone May 7, 2026
@rudrakhp

Copy link
Copy Markdown
Member

@norman-zon the http_route_with_lua_filter_context E2E test seems to be failing. Please have a look.

…ilterContext() directly

The previous script had a nil-value bug:
- ctx["custom_value"] returns nil when filterContext() wraps an empty struct
- Storing nil via dynamicMetadata and then using it in headers():add() caused
  a silent Lua error, so the response header was never set

Fix by calling response_handle:filterContext() directly in envoy_on_response,
which is available on both request and response handles per Envoy's C++ source.
Also add a nil guard for val before calling headers():add() to be safe.

Signed-off-by: Norman Stetter <85173861+norman-zon@users.noreply.github.com>
@norman-zon
norman-zon force-pushed the 8765-envoyextensionpolicy-filtercontext branch from 4c7ed0c to 6f8bc94 Compare June 16, 2026 12:40
@norman-zon

Copy link
Copy Markdown
Contributor Author

@rudrakhp, I think I found the issue. Can you please re-trigger the tests?

@zirain

zirain commented Jun 16, 2026

Copy link
Copy Markdown
Member

/retest

@norman-zon

Copy link
Copy Markdown
Contributor Author

I think I need a bit of help with fixing the E2E tests. Could someone take a look and give me a hint?

…ases

Signed-off-by: Norman Stetter <85173861+norman-zon@users.noreply.github.com>
Signed-off-by: Norman Stetter <85173861+norman-zon@users.noreply.github.com>
filterContext() returns a MetadataMapWrapper whose only Lua methods are
get and __pairs; its metatable __index points at the methods table, so
ctx["custom_value"] resolves to a method lookup and always returns nil.
Read values via ctx:get("custom_value") instead.

The per-route filter config is re-resolved on the response path, so the
response handle exposes filterContext directly; the dynamicMetadata bridge
is unnecessary and the script is now a single response-phase function.

Update the luavalidator mock so StreamHandle:filterContext() returns the
Metadata wrapper (with a :get method) matching real Envoy, add a validator
test for the get() syntax, and fix the docs examples accordingly.

Signed-off-by: Norman Stetter <85173861+norman-zon@users.noreply.github.com>
@norman-zon
norman-zon force-pushed the 8765-envoyextensionpolicy-filtercontext branch from 7847562 to 0351375 Compare June 18, 2026 07:23
@norman-zon

Copy link
Copy Markdown
Contributor Author

Ok. One more try. Can you please /retest @zirain

@norman-zon

Copy link
Copy Markdown
Contributor Author

/retest

rudrakhp
rudrakhp previously approved these changes Jun 18, 2026
@rudrakhp
rudrakhp requested review from a team and zirain June 18, 2026 17:05
zirain
zirain previously approved these changes Jun 19, 2026
Signed-off-by: Rudrakh Panigrahi <rudrakh97@gmail.com>
@rudrakhp
rudrakhp dismissed stale reviews from zirain and themself via cf8f442 June 19, 2026 14:37
@rudrakhp
rudrakhp merged commit e0fa702 into envoyproxy:main Jun 20, 2026
65 of 68 checks passed
cleman95 pushed a commit to cleman95/gateway that referenced this pull request Jun 25, 2026
envoyproxy#8730)

* feat: add filterContext field to Lua EnvoyExtensionPolicy (envoyproxy#8715)

Add an optional `filterContext` field (map[string]string) to the Lua type
in EnvoyExtensionPolicySpec. This exposes Envoy's existing
LuaPerRoute.filter_context so that a shared Lua script can be
parameterized differently per route via request_handle:filterContext().

Without this, users must either duplicate the entire script inline with
hardcoded values or resort to EnvoyPatchPolicy to manually patch xDS.

Changes:
- api: add FilterContext to Lua struct
- ir: add FilterContext to IR Lua struct
- gatewayapi: pass FilterContext from API to IR in buildLua()
- xds: set FilterContext on LuaPerRoute in patchRoute(), converting
  map[string]string to structpb.Struct
- tests: update gatewayapi/xds translator testdata, add e2e test
- docs: add FilterContext section to Lua extension task guide

Signed-off-by: Norman Stetter <85173861+norman-zon@users.noreply.github.com>

* feat: update release notes

Signed-off-by: Norman Stetter <85173861+norman-zon@users.noreply.github.com>

* chore: regenerate test output and helm CRD files

Signed-off-by: Norman Stetter <85173861+norman-zon@users.noreply.github.com>

* fix: add missing mocks

Signed-off-by: Norman Stetter <85173861+norman-zon@users.noreply.github.com>

* fix(e2e): use retry pattern for lua filter context test

Signed-off-by: Norman Stetter <85173861+norman-zon@users.noreply.github.com>

* fix(api): use apiextensionsv1.JSON for Lua filterContext

Address review feedback on envoyproxy#8730:

- Change FilterContext field type from map[string]string to
  *apiextensionsv1.JSON in both the API (lua_types.go) and IR (xds.go),
  matching the existing pattern used by Wasm.Config and
  DynamicModule.Config.
- Drop json/yaml struct tags from ir.Lua.FilterContext, consistent with
  the other untagged fields on that struct.
- Update the xDS translator to unmarshal FilterContext.Raw into
  structpb.Struct via protojson.Unmarshal, replacing the previous
  string-only map iteration.
- Regenerate deepcopy, CRD manifests, and test fixtures.

Users can now pass non-string JSON values (numbers, bools, nested
objects) in filterContext without stringifying them.

Signed-off-by: Norman Stetter <85173861+norman-zon@users.noreply.github.com>

* fix(e2e): use request_handle:filterContext() and dynamicMetadata to propagate filter context in Lua test

filterContext() is only available on request_handle, not response_handle.
Read the value in envoy_on_request and store it via dynamicMetadata, then
retrieve it in envoy_on_response to set the X-Lua-Filter-Context header.

Fixes TestE2E/LuaHTTP/http_route_with_lua_filter_context

Signed-off-by: Norman Stetter <85173861+norman-zon@users.noreply.github.com>

* fix(e2e): simplify lua filter context script to use response_handle:filterContext() directly

The previous script had a nil-value bug:
- ctx["custom_value"] returns nil when filterContext() wraps an empty struct
- Storing nil via dynamicMetadata and then using it in headers():add() caused
  a silent Lua error, so the response header was never set

Fix by calling response_handle:filterContext() directly in envoy_on_response,
which is available on both request and response handles per Envoy's C++ source.
Also add a nil guard for val before calling headers():add() to be safe.

Signed-off-by: Norman Stetter <85173861+norman-zon@users.noreply.github.com>

* fix(e2e): use dynamicMetadata to bridge lua filter context between phases

Signed-off-by: Norman Stetter <85173861+norman-zon@users.noreply.github.com>

* fix(e2e): simplify lua filter context by storing value string directly

Signed-off-by: Norman Stetter <85173861+norman-zon@users.noreply.github.com>

* fix(e2e): read Lua filterContext via ctx:get() instead of table indexing

filterContext() returns a MetadataMapWrapper whose only Lua methods are
get and __pairs; its metatable __index points at the methods table, so
ctx["custom_value"] resolves to a method lookup and always returns nil.
Read values via ctx:get("custom_value") instead.

The per-route filter config is re-resolved on the response path, so the
response handle exposes filterContext directly; the dynamicMetadata bridge
is unnecessary and the script is now a single response-phase function.

Update the luavalidator mock so StreamHandle:filterContext() returns the
Metadata wrapper (with a :get method) matching real Envoy, add a validator
test for the get() syntax, and fix the docs examples accordingly.

Signed-off-by: Norman Stetter <85173861+norman-zon@users.noreply.github.com>

---------

Signed-off-by: Norman Stetter <85173861+norman-zon@users.noreply.github.com>
Signed-off-by: Rudrakh Panigrahi <rudrakh97@gmail.com>
Co-authored-by: Rudrakh Panigrahi <rudrakh97@gmail.com>
zac-nixon pushed a commit to zac-nixon/gateway that referenced this pull request Jun 29, 2026
envoyproxy#8730)

* feat: add filterContext field to Lua EnvoyExtensionPolicy (envoyproxy#8715)

Add an optional `filterContext` field (map[string]string) to the Lua type
in EnvoyExtensionPolicySpec. This exposes Envoy's existing
LuaPerRoute.filter_context so that a shared Lua script can be
parameterized differently per route via request_handle:filterContext().

Without this, users must either duplicate the entire script inline with
hardcoded values or resort to EnvoyPatchPolicy to manually patch xDS.

Changes:
- api: add FilterContext to Lua struct
- ir: add FilterContext to IR Lua struct
- gatewayapi: pass FilterContext from API to IR in buildLua()
- xds: set FilterContext on LuaPerRoute in patchRoute(), converting
  map[string]string to structpb.Struct
- tests: update gatewayapi/xds translator testdata, add e2e test
- docs: add FilterContext section to Lua extension task guide

Signed-off-by: Norman Stetter <85173861+norman-zon@users.noreply.github.com>

* feat: update release notes

Signed-off-by: Norman Stetter <85173861+norman-zon@users.noreply.github.com>

* chore: regenerate test output and helm CRD files

Signed-off-by: Norman Stetter <85173861+norman-zon@users.noreply.github.com>

* fix: add missing mocks

Signed-off-by: Norman Stetter <85173861+norman-zon@users.noreply.github.com>

* fix(e2e): use retry pattern for lua filter context test

Signed-off-by: Norman Stetter <85173861+norman-zon@users.noreply.github.com>

* fix(api): use apiextensionsv1.JSON for Lua filterContext

Address review feedback on envoyproxy#8730:

- Change FilterContext field type from map[string]string to
  *apiextensionsv1.JSON in both the API (lua_types.go) and IR (xds.go),
  matching the existing pattern used by Wasm.Config and
  DynamicModule.Config.
- Drop json/yaml struct tags from ir.Lua.FilterContext, consistent with
  the other untagged fields on that struct.
- Update the xDS translator to unmarshal FilterContext.Raw into
  structpb.Struct via protojson.Unmarshal, replacing the previous
  string-only map iteration.
- Regenerate deepcopy, CRD manifests, and test fixtures.

Users can now pass non-string JSON values (numbers, bools, nested
objects) in filterContext without stringifying them.

Signed-off-by: Norman Stetter <85173861+norman-zon@users.noreply.github.com>

* fix(e2e): use request_handle:filterContext() and dynamicMetadata to propagate filter context in Lua test

filterContext() is only available on request_handle, not response_handle.
Read the value in envoy_on_request and store it via dynamicMetadata, then
retrieve it in envoy_on_response to set the X-Lua-Filter-Context header.

Fixes TestE2E/LuaHTTP/http_route_with_lua_filter_context

Signed-off-by: Norman Stetter <85173861+norman-zon@users.noreply.github.com>

* fix(e2e): simplify lua filter context script to use response_handle:filterContext() directly

The previous script had a nil-value bug:
- ctx["custom_value"] returns nil when filterContext() wraps an empty struct
- Storing nil via dynamicMetadata and then using it in headers():add() caused
  a silent Lua error, so the response header was never set

Fix by calling response_handle:filterContext() directly in envoy_on_response,
which is available on both request and response handles per Envoy's C++ source.
Also add a nil guard for val before calling headers():add() to be safe.

Signed-off-by: Norman Stetter <85173861+norman-zon@users.noreply.github.com>

* fix(e2e): use dynamicMetadata to bridge lua filter context between phases

Signed-off-by: Norman Stetter <85173861+norman-zon@users.noreply.github.com>

* fix(e2e): simplify lua filter context by storing value string directly

Signed-off-by: Norman Stetter <85173861+norman-zon@users.noreply.github.com>

* fix(e2e): read Lua filterContext via ctx:get() instead of table indexing

filterContext() returns a MetadataMapWrapper whose only Lua methods are
get and __pairs; its metatable __index points at the methods table, so
ctx["custom_value"] resolves to a method lookup and always returns nil.
Read values via ctx:get("custom_value") instead.

The per-route filter config is re-resolved on the response path, so the
response handle exposes filterContext directly; the dynamicMetadata bridge
is unnecessary and the script is now a single response-phase function.

Update the luavalidator mock so StreamHandle:filterContext() returns the
Metadata wrapper (with a :get method) matching real Envoy, add a validator
test for the get() syntax, and fix the docs examples accordingly.

Signed-off-by: Norman Stetter <85173861+norman-zon@users.noreply.github.com>

---------

Signed-off-by: Norman Stetter <85173861+norman-zon@users.noreply.github.com>
Signed-off-by: Rudrakh Panigrahi <rudrakh97@gmail.com>
Co-authored-by: Rudrakh Panigrahi <rudrakh97@gmail.com>
guydc pushed a commit to guydc/gateway that referenced this pull request Jun 30, 2026
envoyproxy#8730)

* feat: add filterContext field to Lua EnvoyExtensionPolicy (envoyproxy#8715)

Add an optional `filterContext` field (map[string]string) to the Lua type
in EnvoyExtensionPolicySpec. This exposes Envoy's existing
LuaPerRoute.filter_context so that a shared Lua script can be
parameterized differently per route via request_handle:filterContext().

Without this, users must either duplicate the entire script inline with
hardcoded values or resort to EnvoyPatchPolicy to manually patch xDS.

Changes:
- api: add FilterContext to Lua struct
- ir: add FilterContext to IR Lua struct
- gatewayapi: pass FilterContext from API to IR in buildLua()
- xds: set FilterContext on LuaPerRoute in patchRoute(), converting
  map[string]string to structpb.Struct
- tests: update gatewayapi/xds translator testdata, add e2e test
- docs: add FilterContext section to Lua extension task guide

Signed-off-by: Norman Stetter <85173861+norman-zon@users.noreply.github.com>

* feat: update release notes

Signed-off-by: Norman Stetter <85173861+norman-zon@users.noreply.github.com>

* chore: regenerate test output and helm CRD files

Signed-off-by: Norman Stetter <85173861+norman-zon@users.noreply.github.com>

* fix: add missing mocks

Signed-off-by: Norman Stetter <85173861+norman-zon@users.noreply.github.com>

* fix(e2e): use retry pattern for lua filter context test

Signed-off-by: Norman Stetter <85173861+norman-zon@users.noreply.github.com>

* fix(api): use apiextensionsv1.JSON for Lua filterContext

Address review feedback on envoyproxy#8730:

- Change FilterContext field type from map[string]string to
  *apiextensionsv1.JSON in both the API (lua_types.go) and IR (xds.go),
  matching the existing pattern used by Wasm.Config and
  DynamicModule.Config.
- Drop json/yaml struct tags from ir.Lua.FilterContext, consistent with
  the other untagged fields on that struct.
- Update the xDS translator to unmarshal FilterContext.Raw into
  structpb.Struct via protojson.Unmarshal, replacing the previous
  string-only map iteration.
- Regenerate deepcopy, CRD manifests, and test fixtures.

Users can now pass non-string JSON values (numbers, bools, nested
objects) in filterContext without stringifying them.

Signed-off-by: Norman Stetter <85173861+norman-zon@users.noreply.github.com>

* fix(e2e): use request_handle:filterContext() and dynamicMetadata to propagate filter context in Lua test

filterContext() is only available on request_handle, not response_handle.
Read the value in envoy_on_request and store it via dynamicMetadata, then
retrieve it in envoy_on_response to set the X-Lua-Filter-Context header.

Fixes TestE2E/LuaHTTP/http_route_with_lua_filter_context

Signed-off-by: Norman Stetter <85173861+norman-zon@users.noreply.github.com>

* fix(e2e): simplify lua filter context script to use response_handle:filterContext() directly

The previous script had a nil-value bug:
- ctx["custom_value"] returns nil when filterContext() wraps an empty struct
- Storing nil via dynamicMetadata and then using it in headers():add() caused
  a silent Lua error, so the response header was never set

Fix by calling response_handle:filterContext() directly in envoy_on_response,
which is available on both request and response handles per Envoy's C++ source.
Also add a nil guard for val before calling headers():add() to be safe.

Signed-off-by: Norman Stetter <85173861+norman-zon@users.noreply.github.com>

* fix(e2e): use dynamicMetadata to bridge lua filter context between phases

Signed-off-by: Norman Stetter <85173861+norman-zon@users.noreply.github.com>

* fix(e2e): simplify lua filter context by storing value string directly

Signed-off-by: Norman Stetter <85173861+norman-zon@users.noreply.github.com>

* fix(e2e): read Lua filterContext via ctx:get() instead of table indexing

filterContext() returns a MetadataMapWrapper whose only Lua methods are
get and __pairs; its metatable __index points at the methods table, so
ctx["custom_value"] resolves to a method lookup and always returns nil.
Read values via ctx:get("custom_value") instead.

The per-route filter config is re-resolved on the response path, so the
response handle exposes filterContext directly; the dynamicMetadata bridge
is unnecessary and the script is now a single response-phase function.

Update the luavalidator mock so StreamHandle:filterContext() returns the
Metadata wrapper (with a :get method) matching real Envoy, add a validator
test for the get() syntax, and fix the docs examples accordingly.

Signed-off-by: Norman Stetter <85173861+norman-zon@users.noreply.github.com>

---------

Signed-off-by: Norman Stetter <85173861+norman-zon@users.noreply.github.com>
Signed-off-by: Rudrakh Panigrahi <rudrakh97@gmail.com>
Co-authored-by: Rudrakh Panigrahi <rudrakh97@gmail.com>
abe-servescale pushed a commit to abe-servescale/gateway that referenced this pull request Jul 11, 2026
envoyproxy#8730)

* feat: add filterContext field to Lua EnvoyExtensionPolicy (envoyproxy#8715)

Add an optional `filterContext` field (map[string]string) to the Lua type
in EnvoyExtensionPolicySpec. This exposes Envoy's existing
LuaPerRoute.filter_context so that a shared Lua script can be
parameterized differently per route via request_handle:filterContext().

Without this, users must either duplicate the entire script inline with
hardcoded values or resort to EnvoyPatchPolicy to manually patch xDS.

Changes:
- api: add FilterContext to Lua struct
- ir: add FilterContext to IR Lua struct
- gatewayapi: pass FilterContext from API to IR in buildLua()
- xds: set FilterContext on LuaPerRoute in patchRoute(), converting
  map[string]string to structpb.Struct
- tests: update gatewayapi/xds translator testdata, add e2e test
- docs: add FilterContext section to Lua extension task guide

Signed-off-by: Norman Stetter <85173861+norman-zon@users.noreply.github.com>

* feat: update release notes

Signed-off-by: Norman Stetter <85173861+norman-zon@users.noreply.github.com>

* chore: regenerate test output and helm CRD files

Signed-off-by: Norman Stetter <85173861+norman-zon@users.noreply.github.com>

* fix: add missing mocks

Signed-off-by: Norman Stetter <85173861+norman-zon@users.noreply.github.com>

* fix(e2e): use retry pattern for lua filter context test

Signed-off-by: Norman Stetter <85173861+norman-zon@users.noreply.github.com>

* fix(api): use apiextensionsv1.JSON for Lua filterContext

Address review feedback on envoyproxy#8730:

- Change FilterContext field type from map[string]string to
  *apiextensionsv1.JSON in both the API (lua_types.go) and IR (xds.go),
  matching the existing pattern used by Wasm.Config and
  DynamicModule.Config.
- Drop json/yaml struct tags from ir.Lua.FilterContext, consistent with
  the other untagged fields on that struct.
- Update the xDS translator to unmarshal FilterContext.Raw into
  structpb.Struct via protojson.Unmarshal, replacing the previous
  string-only map iteration.
- Regenerate deepcopy, CRD manifests, and test fixtures.

Users can now pass non-string JSON values (numbers, bools, nested
objects) in filterContext without stringifying them.

Signed-off-by: Norman Stetter <85173861+norman-zon@users.noreply.github.com>

* fix(e2e): use request_handle:filterContext() and dynamicMetadata to propagate filter context in Lua test

filterContext() is only available on request_handle, not response_handle.
Read the value in envoy_on_request and store it via dynamicMetadata, then
retrieve it in envoy_on_response to set the X-Lua-Filter-Context header.

Fixes TestE2E/LuaHTTP/http_route_with_lua_filter_context

Signed-off-by: Norman Stetter <85173861+norman-zon@users.noreply.github.com>

* fix(e2e): simplify lua filter context script to use response_handle:filterContext() directly

The previous script had a nil-value bug:
- ctx["custom_value"] returns nil when filterContext() wraps an empty struct
- Storing nil via dynamicMetadata and then using it in headers():add() caused
  a silent Lua error, so the response header was never set

Fix by calling response_handle:filterContext() directly in envoy_on_response,
which is available on both request and response handles per Envoy's C++ source.
Also add a nil guard for val before calling headers():add() to be safe.

Signed-off-by: Norman Stetter <85173861+norman-zon@users.noreply.github.com>

* fix(e2e): use dynamicMetadata to bridge lua filter context between phases

Signed-off-by: Norman Stetter <85173861+norman-zon@users.noreply.github.com>

* fix(e2e): simplify lua filter context by storing value string directly

Signed-off-by: Norman Stetter <85173861+norman-zon@users.noreply.github.com>

* fix(e2e): read Lua filterContext via ctx:get() instead of table indexing

filterContext() returns a MetadataMapWrapper whose only Lua methods are
get and __pairs; its metatable __index points at the methods table, so
ctx["custom_value"] resolves to a method lookup and always returns nil.
Read values via ctx:get("custom_value") instead.

The per-route filter config is re-resolved on the response path, so the
response handle exposes filterContext directly; the dynamicMetadata bridge
is unnecessary and the script is now a single response-phase function.

Update the luavalidator mock so StreamHandle:filterContext() returns the
Metadata wrapper (with a :get method) matching real Envoy, add a validator
test for the get() syntax, and fix the docs examples accordingly.

Signed-off-by: Norman Stetter <85173861+norman-zon@users.noreply.github.com>

---------

Signed-off-by: Norman Stetter <85173861+norman-zon@users.noreply.github.com>
Signed-off-by: Rudrakh Panigrahi <rudrakh97@gmail.com>
Co-authored-by: Rudrakh Panigrahi <rudrakh97@gmail.com>
Signed-off-by: Andrea Abellonio <andrea.abellonio@servescale.ai>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add filterContext field to Lua type in EnvoyExtensionPolicy

4 participants