Skip to content

fix(llm-transformer): remove unwanted template params from guardrail policies#1689

Open
Sithumli wants to merge 2 commits intowso2:mainfrom
Sithumli:fix/1592-unwanted-guardrail-params
Open

fix(llm-transformer): remove unwanted template params from guardrail policies#1689
Sithumli wants to merge 2 commits intowso2:mainfrom
Sithumli:fix/1592-unwanted-guardrail-params

Conversation

@Sithumli
Copy link
Copy Markdown

@Sithumli Sithumli commented Apr 13, 2026

Purpose

Fixes unwanted LLM template extraction parameters being attached to guardrail policies when deployed with LLM providers. When policies like word-count-guardrail are attached to an LLM provider, the policy
engine config dump shows extraneous parameters (promptTokens, completionTokens, totalTokens, remainingTokens, requestModel, responseModel) that are not defined in the policy schema
and should not be present.

Approach

  • Replace mergeParams(pathEntry.Params, templateParams) with copyParams(pathEntry.Params) in three locations within llm_transformer.go (transformProxy and transformProvider methods for both AllowAll
    and DenyAll modes)
  • Add new copyParams() helper function that creates a shallow copy of user-provided parameters without merging LLM template extraction fields
  • Template extraction fields (buildTemplateParams()) are preserved for other uses but no longer injected into user policy parameters

Testing

  • Deployed LLM provider with word-count-guardrail attached
  • Verified via /config_dump endpoint that only user-provided params (request, response) appear
  • Before fix: 8 parameters including unwanted template fields
  • After fix: Only user-configured parameters

Fixes #1592

…policies

When policies like word-count-guardrail are attached to LLM providers,
LLM template extraction parameters (promptTokens, completionTokens,
totalTokens, remainingTokens, requestModel, responseModel) were being
unconditionally merged into every policy's parameters.

These template-level extraction fields are not needed by user-defined
policies and were appearing as unwanted parameters in the policy engine
config dump.

This change ensures that only user-provided parameters are assigned to
policies, preventing leakage of LLM template extraction fields.

Fixes wso2#1592
Copilot AI review requested due to automatic review settings April 13, 2026 14:16
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Apr 13, 2026

Summary

This pull request refines parameter handling in LLM provider transformation to prevent template-level extraction fields from being merged into user-defined policy parameters.

Changes

gateway/gateway-controller/pkg/utils/llm_transformer.go (+16/-15 lines)

  • Added copyParams() helper function that creates a shallow copy of the provided parameter map, returning nil if the input is empty
  • Updated three policy construction locations (in transformProxy and transformProvider methods for both AllowAll and DenyAll access control modes) to use copyParams(pathEntry.Params) instead of merging template parameters with user parameters
  • The buildTemplateParams() function remains available for other uses but is no longer injected into user policy parameters

gateway/gateway-controller/pkg/utils/llm_transformer_test.go (+6/-6 lines)

  • Updated TestTransformProvider_ExpandsWildcardPolicyPathWithTemplateMappings test assertions to verify that template-derived parameters (specifically requestModel) do not appear in user-defined policy configurations
  • Changed assertions from checking parameter presence to confirming absence (assert.False), validating that only user-provided parameters like userParam are retained in the final policy configuration

Outcome

When LLM providers are deployed with attached guardrail policies, the configuration now contains only the parameters explicitly defined by users. Template-level extraction parameters that were previously appearing in policy engine configuration dumps (such as promptTokens, completionTokens, totalTokens, remainingTokens, requestModel, responseModel) are no longer included in the policy parameter sets, resulting in cleaner and more predictable policy configurations.

Walkthrough

Template-derived extraction parameters are no longer merged into policy parameters. The transformer now constructs policy parameters solely from user-specified pathEntry.Params using a new shallow-copy helper copyParams, and removed calls to buildTemplateParams and related error handling.

Changes

Cohort / File(s) Summary
Parameter Handling Refactor
gateway/gateway-controller/pkg/utils/llm_transformer.go
Removed buildTemplateParams(...) calls and the merge of template-derived parameters into path-level params. Introduced copyParams(params map[string]interface{}) *map[string]interface{} and use of copyParams(pathEntry.Params) so attached policies receive only user-provided params.
Tests Updated
gateway/gateway-controller/pkg/utils/llm_transformer_test.go
Adjusted assertions to expect that template-derived param requestModel is no longer present in policy parameters; tests now verify only user-defined params (e.g., userParam).

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Poem

🐰 Hop hop hooray!
Template params were leading astray,
Now policies keep only what's meant—
Unwanted extraction parameters went! 🎉
Cleaner configs light up the way! 🌟

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 50.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title 'fix(llm-transformer): remove unwanted template params from guardrail policies' clearly and concisely summarizes the main change in the pull request.
Description check ✅ Passed The PR description covers Purpose, Approach, and Testing sections well, though it omits several template sections like Goals, User stories, Documentation, and others.
Linked Issues check ✅ Passed The code changes directly address issue #1592 by preventing template extraction parameters from being injected into user-defined guardrail policy parameters.
Out of Scope Changes check ✅ Passed All changes in llm_transformer.go and its test file are directly related to removing unwanted template parameters from guardrail policies as specified in issue #1592.

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

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 golangci-lint (2.11.4)

level=error msg="[linters_context] typechecking error: pattern ./...: directory prefix . does not contain modules listed in go.work or their selected dependencies"


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
Copy Markdown
Contributor

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

Fixes LLM provider/proxy policy transformation so that LLM template extraction fields (e.g., token/model identifiers) are no longer merged into user-defined policy parameters (notably guardrail policies), reducing config noise and aligning parameters with the policy schema.

Changes:

  • Replaced mergeParams(pathEntry.Params, templateParams) with copyParams(pathEntry.Params) when attaching policies to operations (proxy + provider, AllowAll + DenyAll flows).
  • Added copyParams() helper to clone user-provided params without injecting template-derived fields.

Comment thread gateway/gateway-controller/pkg/utils/llm_transformer.go
Comment on lines +784 to +795
// copyParams creates a shallow copy of the parameters map and returns a pointer to it.
// Returns nil if the input map is nil or empty.
func copyParams(params map[string]interface{}) *map[string]interface{} {
if len(params) == 0 {
return nil
}
copied := make(map[string]interface{}, len(params))
for k, v := range params {
copied[k] = v
}
return &copied
}
Copy link

Copilot AI Apr 13, 2026

Choose a reason for hiding this comment

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

New helper copyParams and the behavioral change (policies should no longer receive template extraction keys like requestModel/promptTokens/etc.) aren’t covered by unit tests. Since this package already has tests for related helpers (buildTemplateParams/mergeParams), add tests for copyParams and a transformer-level test asserting that attached policies only include user-provided params (and not template extraction fields).

Copilot uses AI. Check for mistakes.
Copy link
Copy Markdown
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.

🧹 Nitpick comments (1)
gateway/gateway-controller/pkg/utils/llm_transformer_test.go (1)

984-1006: Optional: strengthen assertions to catch any future template-param leak.

The current checks only verify requestModel is absent. Since the fix is meant to exclude all template extraction fields (responseModel, promptTokens, completionTokens, totalTokens, remainingTokens, requestModel), consider asserting the params map length equals 1 (or explicitly checking each excluded key). That way, if a future regression re-introduces any template field — not just requestModel — this test will catch it.

♻️ Suggested tightening
-	// User-defined policies should only contain user params, not template params
-	_, hasRequestModel := (*responsesPolicy.Params)["requestModel"]
-	assert.False(t, hasRequestModel, "template params should not be merged into user-defined policies")
-	assert.Equal(t, "value", (*responsesPolicy.Params)["userParam"])
+	// User-defined policies should only contain user params, not template params
+	assert.Len(t, *responsesPolicy.Params, 1, "only user-provided params should be present")
+	assert.Equal(t, "value", (*responsesPolicy.Params)["userParam"])
+	for _, k := range []string{"requestModel", "responseModel", "promptTokens", "completionTokens", "totalTokens", "remainingTokens"} {
+		_, present := (*responsesPolicy.Params)[k]
+		assert.Falsef(t, present, "template param %q should not be merged into user-defined policies", k)
+	}

Apply the same to the wildcardPolicy block.

Also note: there is no dedicated unit test for the new copyParams helper introduced in llm_transformer.go. A small test covering nil input, empty map, and shallow-copy semantics (mutating the copy does not affect the original) would be worth adding.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@gateway/gateway-controller/pkg/utils/llm_transformer_test.go` around lines
984 - 1006, Strengthen the test assertions to ensure no template extraction
fields leak by asserting the params map contains only the expected user key:
replace the current single-key absence check for "requestModel" with an explicit
size check (assert.Len == 1) and/or explicit absence checks for all template
keys (responseModel, promptTokens, completionTokens, totalTokens,
remainingTokens, requestModel) against responsesPolicy.Params and
wildcardPolicy.Params (keep the existing assert.Equal on "userParam");
additionally add a small unit test for the new copyParams helper in
llm_transformer.go that verifies behavior for nil input, empty map, and
shallow-copy semantics (mutating the returned map does not change the original).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@gateway/gateway-controller/pkg/utils/llm_transformer_test.go`:
- Around line 984-1006: Strengthen the test assertions to ensure no template
extraction fields leak by asserting the params map contains only the expected
user key: replace the current single-key absence check for "requestModel" with
an explicit size check (assert.Len == 1) and/or explicit absence checks for all
template keys (responseModel, promptTokens, completionTokens, totalTokens,
remainingTokens, requestModel) against responsesPolicy.Params and
wildcardPolicy.Params (keep the existing assert.Equal on "userParam");
additionally add a small unit test for the new copyParams helper in
llm_transformer.go that verifies behavior for nil input, empty map, and
shallow-copy semantics (mutating the returned map does not change the original).

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 5578f94f-ae2a-4f1b-bf42-fd93020f64e0

📥 Commits

Reviewing files that changed from the base of the PR and between b3db035 and 543f7fe.

📒 Files selected for processing (1)
  • gateway/gateway-controller/pkg/utils/llm_transformer_test.go

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.

[Bug]: Unwanted params attached to guardrails

2 participants