Skip to content

formatter: expose CEL expression config in header mutations#45815

Open
kamalmarhubi wants to merge 4 commits into
envoyproxy:mainfrom
kamalmarhubi:push-qtrtktvmplnx
Open

formatter: expose CEL expression config in header mutations#45815
kamalmarhubi wants to merge 4 commits into
envoyproxy:mainfrom
kamalmarhubi:push-qtrtktvmplnx

Conversation

@kamalmarhubi

@kamalmarhubi kamalmarhubi commented Jun 23, 2026

Copy link
Copy Markdown

Commit Message:
formatter: expose CEL expression config in header mutations

Add cel_config to envoy.formatter.cel configuration, allowing CEL runtime options such as string functions to be enabled on a per-formatter basis. Include a formatters field on the header mutation and early header mutation filters so those filters can use configured formatter command parsers, including CEL with cel_config.

Specific changes:

  • formatter/cel: explicitly configured envoy.formatter.cel parsers now carry cel_config. The built-in %CEL% parser still uses the active server context, so existing unconfigured usage is unchanged.
  • header_mutation / early_header_mutation: add formatters for configuring extension formatter command parsers used in mutation values.

Built-in command parsers remain available when formatters is empty, so there is no behaviour change unless a config opts in.

Fixes #45420

Additional Description: See #45420 for motivation: enabling CEL string functions in (early) header mutation, eg to transform trace-context headers.
AI Disclosure: This was developed by iterating with OpenAI Codex (GPT-5.5), with review and further iteration using Claude Code (Opus 4.8). I reviewed and edited the generated output, understand the submitted changes, and take responsibility for them.
Risk Level: Low
Testing:

bazel test \
  //test/extensions/formatter/cel:cel_test \
  //test/extensions/filters/http/header_mutation:header_mutation_test \
  //test/extensions/http/early_header_mutation/header_mutation:header_mutation_test

Docs Changes: Inline proto documentation for the new cel_config and formatters fields.
Release Notes: Added (formatter, header_mutation, early_header_mutation).
Platform Specific Features: N/A. (The CEL formatter is already excluded on Windows via WINDOWS_SKIP_TARGETS; I haven't changed that.)
API Considerations: adds optional cel_config (reusing config.core.v3.CelExpressionConfig) to envoy.extensions.formatter.cel.v3.Cel, and optional formatters (repeated config.core.v3.TypedExtensionConfig) to the two header mutation messages. All additive; omitting them preserves existing behaviour.

@kamalmarhubi kamalmarhubi requested a review from kyessenov as a code owner June 23, 2026 20:48
@repokitteh-read-only

Copy link
Copy Markdown

Hi @kamalmarhubi, welcome and thank you for your contribution.

We will try to review your Pull Request as quickly as possible.

In the meantime, please take a look at the contribution guidelines if you have not done so already.

🐱

Caused by: #45815 was opened by kamalmarhubi.

see: more, trace.

@repokitteh-read-only

Copy link
Copy Markdown

CC @envoyproxy/api-shepherds: Your approval is needed for changes made to (api/envoy/|docs/root/api-docs/).
envoyproxy/api-shepherds assignee is @adisuissa
CC @envoyproxy/api-watchers: FYI only for changes made to (api/envoy/|docs/root/api-docs/).

🐱

Caused by: #45815 was opened by kamalmarhubi.

see: more, trace.

@kamalmarhubi

Copy link
Copy Markdown
Author

@adisuissa fyi the API was already given the ok by @wbpcode here: #45420 (comment)

@kamalmarhubi kamalmarhubi changed the title formatter: expose CelExpressionConfig on the CEL formatter formatter: expose CEL expression config and use it in header mutations Jun 24, 2026
@kamalmarhubi kamalmarhubi changed the title formatter: expose CEL expression config and use it in header mutations formatter: expose CEL expression config in header mutations Jun 24, 2026
@kamalmarhubi

Copy link
Copy Markdown
Author

Reviewer note: this is broken down into hopefully digestible commits.

Add `cel_config` to `envoy.formatter.cel` configuration, allowing CEL
runtime options to be enabled on a per-formatter basis.

This is prerequisite work for envoyproxy#45420: the header mutation filters need
to enable CEL string functions through formatter configuration, but the
CEL formatter extension did not expose the underlying CEL expression
runtime options.

The built-in CEL parser still uses the active server context, so
existing unconfigured CEL formatter command usage is unchanged.

Signed-off-by: Kamal Al Marhubi <kamal@marhubi.com>
Header mutation values already use substitution format strings, but the
HTTP filter had no API surface for configured formatter parsers. Add
`formatters` to the filter config and thread the parsed parsers through
top-level and per-route mutation construction.

Built-in parsers remain available when the field is empty.

Signed-off-by: Kamal Al Marhubi <kamal@marhubi.com>
Early header mutation values also use substitution format strings, but the
extension had no API surface for configured formatter parsers. Add
`formatters` to the early header mutation config and pass parsed parsers
into header mutation construction.

Built-in parsers remain available when the field is empty.

Fixes envoyproxy#45420

Signed-off-by: Kamal Al Marhubi <kamal@marhubi.com>

@wbpcode wbpcode 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.

I think this! Thanks for this great contribution. Only one comment.

Comment on lines +157 to +161
PerRouteHeaderMutation::PerRouteHeaderMutation(const PerRouteProtoConfig& config,
Server::Configuration::ServerFactoryContext& context,
absl::Status& creation_status)
: mutations_(config.mutations(), context, creation_status) {}
: PerRouteHeaderMutation(config, context, ProtobufMessage::getNullValidationVisitor(),
creation_status) {}

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.

I guess the previous header mutation constructor is unnecessary (except for test)? Could we remove it?

@kamalmarhubi kamalmarhubi Jun 25, 2026

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

For some reason I missed the human review and only saw the robot review below. In any case, you're sort of in agreement, and the 3-arg constructor is gone.

@wbpcode

wbpcode commented Jun 24, 2026

Copy link
Copy Markdown
Member

/gemini review

@wbpcode

wbpcode commented Jun 24, 2026

Copy link
Copy Markdown
Member

/wait

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Code Review

This pull request introduces the ability to configure extension formatter command parsers (such as CEL with custom runtime options) for header mutation substitution values in both the HTTP header mutation filter and the early header mutation extension. It also exposes cel_config on the CEL formatter to allow enabling CEL runtime options like string functions. One improvement opportunity was identified in header_mutation.cc to use the context's messageValidationVisitor() instead of a null validation visitor to ensure proper configuration validation.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment on lines +157 to +161
PerRouteHeaderMutation::PerRouteHeaderMutation(const PerRouteProtoConfig& config,
Server::Configuration::ServerFactoryContext& context,
absl::Status& creation_status)
: mutations_(config.mutations(), context, creation_status) {}
: PerRouteHeaderMutation(config, context, ProtobufMessage::getNullValidationVisitor(),
creation_status) {}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

medium

Using ProtobufMessage::getNullValidationVisitor() bypasses message validation. Since ServerFactoryContext provides a valid messageValidationVisitor(), we should use it instead to ensure any configuration issues or deprecations are properly validated and logged.

Suggested change
PerRouteHeaderMutation::PerRouteHeaderMutation(const PerRouteProtoConfig& config,
Server::Configuration::ServerFactoryContext& context,
absl::Status& creation_status)
: mutations_(config.mutations(), context, creation_status) {}
: PerRouteHeaderMutation(config, context, ProtobufMessage::getNullValidationVisitor(),
creation_status) {}
PerRouteHeaderMutation::PerRouteHeaderMutation(const PerRouteProtoConfig& config,
Server::Configuration::ServerFactoryContext& context,
absl::Status& creation_status)
: PerRouteHeaderMutation(config, context, context.messageValidationVisitor(),
creation_status) {}
References
  1. In Envoy, the validation_visitor object has a server-level lifetime, making it safe to capture by reference in lambdas even when those lambdas are stored in long-lived components like singleton-managed providers.

@kamalmarhubi kamalmarhubi Jun 24, 2026

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Fair point. prior to these changes there was no validation visitor used in this path. In these changes I left the tests using the 3-arg constructor, and defaulted to the null validation visitor. But I've now dropped it, and pass in the visitor explicitly from call sites instead. Pushed as fixup commit.

Signed-off-by: Kamal Al Marhubi <kamal@marhubi.com>

@adisuissa adisuissa left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

The api change LGTM.
/lgtm api
IMHO having a single PR doing 3 concurrent changes is a bit much, but I'll leave it to the extension owners reviewers.

@adisuissa adisuissa left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

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.

Expose CEL config on early header mutation extension

3 participants