Skip to content

Global Policy Support for LLM Providers and Proxies#2238

Closed
ashera96 wants to merge 6 commits into
wso2:mainfrom
ashera96:global-policy-llm
Closed

Global Policy Support for LLM Providers and Proxies#2238
ashera96 wants to merge 6 commits into
wso2:mainfrom
ashera96:global-policy-llm

Conversation

@ashera96

Copy link
Copy Markdown
Contributor

Purpose

Introduces globalPolicies and operationPolicies as first-class fields on LLM provider and proxy deployment artifacts, replacing the flat policies list. This enables provider-wide policy enforcement — such as a rate limit that applies across all operations — without duplicating configuration per path.

Schema change

Artifacts now carry two distinct policy lists:

  • globalPolicies — applied uniformly across every operation on the provider/proxy
  • operationPolicies — scoped to specific paths and HTTP methods, preserving the existing per-operation behaviour

Gateway version-aware delivery

A new deploymenttransform package handles artifact adaptation at deploy time. Gateways at version ≥ 1.2.0 receive the new globalPolicies/operationPolicies shape; older gateways transparently receive the legacy flattened policies list with the correct apiVersion stamp — no gateway-side change required for backward compatibility.

AI Workspace UI

Guardrails tabs updated for both LLM proxies and service providers to surface global vs. per-operation policy configuration.

Version bump

Gateway management API and artifact apiVersion promoted to v1alpha2; platform-api resource URL promoted to v1alpha2.

@coderabbitai

coderabbitai Bot commented Jun 21, 2026

Copy link
Copy Markdown
Contributor

Important

Review skipped

Too many files!

This PR contains 248 files, which is 98 over the limit of 150.

To get a review, narrow the scope:
• coderabbit review --type committed # exclude uncommitted changes
• coderabbit review --dir # limit to a subdirectory
• coderabbit review --base # compare against a closer base

Upgrade to a paid plan to raise the limit.

⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 39174fa9-cf78-45e1-b376-de4bbcfe2f99

📥 Commits

Reviewing files that changed from the base of the PR and between 58e813e and e09ac78.

📒 Files selected for processing (248)
  • .github/workflows/operator-integration-test.yml
  • cli/it/resources/gateway/sample-api.yaml
  • cli/it/resources/gateway/sample-mcp-config.yaml
  • cli/src/cmd/gateway/restapi/apikey/create.go
  • cli/src/cmd/gateway/subscription/create.go
  • cli/src/cmd/gateway/subscriptionplan/create.go
  • cli/src/internal/gateway/cr_test.go
  • cli/src/internal/mcp/generator.go
  • docs/rest-apis/gateway/README.md
  • docs/rest-apis/gateway/certificate-management.md
  • docs/rest-apis/gateway/llm-provider-management.md
  • docs/rest-apis/gateway/llm-provider-template-management.md
  • docs/rest-apis/gateway/llm-proxy-management.md
  • docs/rest-apis/gateway/mcp-proxy-management.md
  • docs/rest-apis/gateway/rest-api-management.md
  • docs/rest-apis/gateway/schemas.md
  • docs/rest-apis/gateway/secrets-management.md
  • docs/rest-apis/gateway/webbroker-api-management.md
  • docs/rest-apis/gateway/websub-api-management.md
  • event-gateway/it/features/webbroker-api-management.feature
  • event-gateway/it/features/webbroker-e2e.feature
  • event-gateway/it/features/websub-api-management.feature
  • event-gateway/it/features/websub-e2e.feature
  • event-gateway/it/features/websub-webhook-secrets.feature
  • event-gateway/it/state.go
  • event-gateway/spec/postman/Control Plane.postman_collection.json
  • gateway/build-manifest.yaml
  • gateway/examples/api-key.yaml
  • gateway/examples/basic-ratelimit-demo-api.yaml
  • gateway/examples/certificate.yaml
  • gateway/examples/llm-provider-template.yaml
  • gateway/examples/llm-provider.yaml
  • gateway/examples/llm-proxy.yaml
  • gateway/examples/managed-secret.yaml
  • gateway/examples/mcp-proxy.yaml
  • gateway/examples/petstore-api.yaml
  • gateway/examples/reading-list-v1.json
  • gateway/examples/sample-echo-api.yaml
  • gateway/examples/subscription-plan.yaml
  • gateway/examples/subscription.yaml
  • gateway/gateway-controller/api/management-openapi.yaml
  • gateway/gateway-controller/cmd/controller/main.go
  • gateway/gateway-controller/default-llm-provider-templates/anthropic-template.yaml
  • gateway/gateway-controller/default-llm-provider-templates/awsbedrock-template.yaml
  • gateway/gateway-controller/default-llm-provider-templates/azureaifoundry-template.yaml
  • gateway/gateway-controller/default-llm-provider-templates/azureopenai-template.yaml
  • gateway/gateway-controller/default-llm-provider-templates/gemini-template.yaml
  • gateway/gateway-controller/default-llm-provider-templates/mistral-template.yaml
  • gateway/gateway-controller/default-llm-provider-templates/openai-template.yaml
  • gateway/gateway-controller/pkg/api/handlers/handlers_test.go
  • gateway/gateway-controller/pkg/api/handlers/list_operations_test.go
  • gateway/gateway-controller/pkg/api/handlers/policy_ordering_test.go
  • gateway/gateway-controller/pkg/api/handlers/resource_response.go
  • gateway/gateway-controller/pkg/api/management/generated.go
  • gateway/gateway-controller/pkg/config/api_validator.go
  • gateway/gateway-controller/pkg/config/api_validator_test.go
  • gateway/gateway-controller/pkg/config/label_validation_test.go
  • gateway/gateway-controller/pkg/config/llm_parser_test.go
  • gateway/gateway-controller/pkg/config/llm_validator.go
  • gateway/gateway-controller/pkg/config/llm_validator_additional_test.go
  • gateway/gateway-controller/pkg/config/llm_validator_policy_exclusivity_test.go
  • gateway/gateway-controller/pkg/config/llm_validator_test.go
  • gateway/gateway-controller/pkg/config/mcp_validator.go
  • gateway/gateway-controller/pkg/config/mcp_validator_test.go
  • gateway/gateway-controller/pkg/config/policy_validator_test.go
  • gateway/gateway-controller/pkg/config/secret_validator.go
  • gateway/gateway-controller/pkg/config/secret_validator_test.go
  • gateway/gateway-controller/pkg/config/validator_test.go
  • gateway/gateway-controller/pkg/controlplane/api_deleted_test.go
  • gateway/gateway-controller/pkg/controlplane/controlplane_test.go
  • gateway/gateway-controller/pkg/eventlistener/apikey_processor_test.go
  • gateway/gateway-controller/pkg/eventlistener/listener_test.go
  • gateway/gateway-controller/pkg/eventlistener/llm_provider_processor_test.go
  • gateway/gateway-controller/pkg/eventlistener/mcp_processor_test.go
  • gateway/gateway-controller/pkg/secrets/service_test.go
  • gateway/gateway-controller/pkg/storage/sqlite_test.go
  • gateway/gateway-controller/pkg/utils/api_deployment_test.go
  • gateway/gateway-controller/pkg/utils/llm_deployment_test.go
  • gateway/gateway-controller/pkg/utils/llm_provider_template_loader_test.go
  • gateway/gateway-controller/pkg/utils/llm_provider_transformer_test.go
  • gateway/gateway-controller/pkg/utils/llm_transformer.go
  • gateway/gateway-controller/pkg/utils/llm_transformer_test.go
  • gateway/gateway-controller/pkg/utils/mcp_deployment_test.go
  • gateway/gateway-controller/pkg/utils/mcp_transformer.go
  • gateway/gateway-controller/pkg/utils/mcp_transformer_test.go
  • gateway/gateway-controller/pkg/utils/on_prem_apim_utils_test.go
  • gateway/gateway-controller/pkg/utils/websub_topic_registration_test.go
  • gateway/gateway-controller/pkg/xds/translator_test.go
  • gateway/gateway-controller/tests/integration/storage_test.go
  • gateway/gateway-controller/tests/integration/vhost_test.go
  • gateway/it/features/analytics-basic.feature
  • gateway/it/features/analytics-header-filter.feature
  • gateway/it/features/api-error-responses.feature
  • gateway/it/features/api-keys.feature
  • gateway/it/features/api-management.feature
  • gateway/it/features/api-with-policies.feature
  • gateway/it/features/api_deploy.feature
  • gateway/it/features/aws-bedrock-guardrail.feature
  • gateway/it/features/azure-content-safety.feature
  • gateway/it/features/backend_timeout.feature
  • gateway/it/features/basic-ratelimit.feature
  • gateway/it/features/cel-conditions.feature
  • gateway/it/features/config-dump.feature
  • gateway/it/features/content-length-guardrail.feature
  • gateway/it/features/cors.feature
  • gateway/it/features/dynamic-endpoint.feature
  • gateway/it/features/host-rewrite.feature
  • gateway/it/features/interceptor-service.feature
  • gateway/it/features/json-schema-guardrail.feature
  • gateway/it/features/jwt-auth.feature
  • gateway/it/features/lazy-resources-xds.feature
  • gateway/it/features/llm-cost-based-ratelimit.feature
  • gateway/it/features/llm-policy-path-specificity.feature
  • gateway/it/features/llm-provider-templates.feature
  • gateway/it/features/llm-provider-wide-ratelimit.feature
  • gateway/it/features/llm-provider.feature
  • gateway/it/features/llm-proxies.feature
  • gateway/it/features/log-message.feature
  • gateway/it/features/mcp_deploy.feature
  • gateway/it/features/mcp_policies.feature
  • gateway/it/features/metrics.feature
  • gateway/it/features/model-round-robin.feature
  • gateway/it/features/model-weighted-round-robin.feature
  • gateway/it/features/pii-masking-regex.feature
  • gateway/it/features/policy-engine-admin.feature
  • gateway/it/features/prompt-compressor.feature
  • gateway/it/features/prompt-decorator.feature
  • gateway/it/features/prompt-template.feature
  • gateway/it/features/ratelimit.feature
  • gateway/it/features/regex-guardrail.feature
  • gateway/it/features/request-rewrite.feature
  • gateway/it/features/respond.feature
  • gateway/it/features/route-path-matching.feature
  • gateway/it/features/sandbox-routing.feature
  • gateway/it/features/search-deployments.feature
  • gateway/it/features/secrets.feature
  • gateway/it/features/semantic-cache.feature
  • gateway/it/features/semantic-prompt-guard.feature
  • gateway/it/features/semantic-tool-filtering.feature
  • gateway/it/features/sentence-count-guardrail.feature
  • gateway/it/features/startup-db-bootstrap.feature
  • gateway/it/features/subscription-analytics.feature
  • gateway/it/features/subscription-validation.feature
  • gateway/it/features/template-functions.feature
  • gateway/it/features/token-based-ratelimit.feature
  • gateway/it/features/url-guardrail.feature
  • gateway/it/features/vhost-routing-multi.feature
  • gateway/it/features/vhost-routing-single.feature
  • gateway/it/features/word-count-guardrail.feature
  • gateway/it/state.go
  • gateway/it/steps_secrets.go
  • gateway/it/suite_test.go
  • gateway/perf/create_apis_and_capture_stats.sh
  • kubernetes/gateway-operator/internal/controller/httproute_controller.go
  • kubernetes/gateway-operator/internal/controller/llmprovider_controller.go
  • kubernetes/gateway-operator/internal/controller/llmprovidertemplate_controller.go
  • kubernetes/gateway-operator/internal/controller/llmproxy_controller.go
  • kubernetes/gateway-operator/internal/controller/managedsecret_controller.go
  • kubernetes/gateway-operator/internal/controller/mcp_controller.go
  • kubernetes/gateway-operator/internal/controller/restapi_controller.go
  • kubernetes/gateway-operator/internal/gatewayclient/rest_api.go
  • kubernetes/helm/resources/apim-gateway-api-operator-demo/04-httproute.yaml
  • kubernetes/helm/resources/gateway-api-operator-demo/04-02-httproute.yaml
  • kubernetes/helm/resources/gateway-api-operator-demo/04-httproute.yaml
  • platform-api/src/api/generated.go
  • platform-api/src/internal/constants/constants.go
  • platform-api/src/internal/deploymenttransform/policies.go
  • platform-api/src/internal/deploymenttransform/registry.go
  • platform-api/src/internal/deploymenttransform/transform_test.go
  • platform-api/src/internal/deploymenttransform/version.go
  • platform-api/src/internal/dto/llm_deployment.go
  • platform-api/src/internal/handler/api.go
  • platform-api/src/internal/handler/api_key.go
  • platform-api/src/internal/handler/apikey_user.go
  • platform-api/src/internal/handler/application.go
  • platform-api/src/internal/handler/deployment.go
  • platform-api/src/internal/handler/devportal.go
  • platform-api/src/internal/handler/gateway.go
  • platform-api/src/internal/handler/git.go
  • platform-api/src/internal/handler/llm.go
  • platform-api/src/internal/handler/llm_apikey.go
  • platform-api/src/internal/handler/llm_deployment.go
  • platform-api/src/internal/handler/llm_proxy_apikey.go
  • platform-api/src/internal/handler/mcp.go
  • platform-api/src/internal/handler/mcp_deployment.go
  • platform-api/src/internal/handler/organization.go
  • platform-api/src/internal/handler/project.go
  • platform-api/src/internal/handler/subscription_handler.go
  • platform-api/src/internal/handler/subscription_plan_handler.go
  • platform-api/src/internal/handler/webbroker_api.go
  • platform-api/src/internal/handler/webbroker_api_deployment.go
  • platform-api/src/internal/handler/webbroker_apikey.go
  • platform-api/src/internal/handler/websub_api.go
  • platform-api/src/internal/handler/websub_api_deployment.go
  • platform-api/src/internal/handler/websub_apikey.go
  • platform-api/src/internal/middleware/openapi_scope_registry_test.go
  • platform-api/src/internal/model/llm.go
  • platform-api/src/internal/repository/gateway.go
  • platform-api/src/internal/repository/interfaces.go
  • platform-api/src/internal/service/deployment_test.go
  • platform-api/src/internal/service/gateway.go
  • platform-api/src/internal/service/llm.go
  • platform-api/src/internal/service/llm_deployment.go
  • platform-api/src/internal/service/llm_deployment_test.go
  • platform-api/src/internal/service/llm_policy_migration_test.go
  • platform-api/src/internal/service/llm_test.go
  • platform-api/src/internal/utils/api.go
  • platform-api/src/internal/utils/api_test.go
  • platform-api/src/resources/default-llm-provider-templates/anthropic-template.yaml
  • platform-api/src/resources/default-llm-provider-templates/awsbedrock-template.yaml
  • platform-api/src/resources/default-llm-provider-templates/azureaifoundry-template.yaml
  • platform-api/src/resources/default-llm-provider-templates/azureopenai-template.yaml
  • platform-api/src/resources/default-llm-provider-templates/gemini-template.yaml
  • platform-api/src/resources/default-llm-provider-templates/mistral-template.yaml
  • platform-api/src/resources/default-llm-provider-templates/openai-template.yaml
  • platform-api/src/resources/openapi.yaml
  • portals/ai-workspace/configs/config-platform-api-template.toml
  • portals/ai-workspace/configs/config-platform-api.toml
  • portals/ai-workspace/configs/config-template.toml
  • portals/ai-workspace/configs/config.toml
  • portals/ai-workspace/docker-compose.yaml
  • portals/ai-workspace/src/apis/platformApis.ts
  • portals/ai-workspace/src/clients/choreoApiClient.ts
  • portals/ai-workspace/src/config.env.ts
  • portals/ai-workspace/src/contexts/ChoreoUserContext.tsx
  • portals/ai-workspace/src/pages/appShell/appShellPages/proxies/LLMProxyGuardrailsTab.tsx
  • portals/ai-workspace/src/pages/appShell/appShellPages/serviceProvider/ServiceProviderGuardrailsTab.tsx
  • portals/ai-workspace/src/pages/appShell/appShellPages/serviceProvider/ServiceProviderNew.tsx
  • portals/ai-workspace/src/utils/types.ts
  • portals/management-portal/src/hooks/GithubAPICreation.ts
  • portals/management-portal/src/hooks/apiPublish.ts
  • portals/management-portal/src/hooks/apis.ts
  • portals/management-portal/src/hooks/deployments.ts
  • portals/management-portal/src/hooks/devportals.ts
  • portals/management-portal/src/hooks/gateways.ts
  • portals/management-portal/src/hooks/orgs.tsx
  • portals/management-portal/src/hooks/projects.ts
  • portals/management-portal/src/hooks/validation.ts
  • portals/management-portal/src/pages/overview/StepTwoApis.tsx
  • samples/ai-gw-llm-proxy/inject-mock.sh
  • samples/ai-gw-llm-proxy/provider.yaml
  • samples/ai-gw-llm-proxy/proxy.yaml
  • samples/ai-gw-mcp-claude-desktop/inject-mock.sh
  • samples/ai-gw-mcp-claude-desktop/mcp.yaml
  • samples/llm-cost-control-and-privacy-control/llm-provider.yaml
  • samples/llm-cost-control-and-privacy-control/llm-proxy.yaml
  • samples/llm-cost-control-and-privacy-control/setup.sh
  • samples/llm-cost-control-and-privacy-control/teardown.sh

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

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

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.

@ashera96 ashera96 force-pushed the global-policy-llm branch 4 times, most recently from 0eabb3a to 2ac0e23 Compare June 22, 2026 06:25
@ashera96

Copy link
Copy Markdown
Contributor Author

@coderabbitai review --dir gateway/

@coderabbitai

coderabbitai Bot commented Jun 22, 2026

Copy link
Copy Markdown
Contributor

Tip

For best results, initiate chat on the files or code changes.

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Explore the gateway/ directory structure
tree gateway/ 2>/dev/null || find gateway/ -type f | sort

Length of output: 26240


🏁 Script executed:

#!/bin/bash
# Get all Go files in gateway/ directory
fd -e go . gateway/ | sort

Length of output: 26174


🏁 Script executed:

#!/bin/bash
# Get the PR diff for gateway/ directory
gh pr diff 2238 --repo wso2/api-platform -- 'gateway/**' 2>/dev/null | head -3000

Length of output: 377


🏁 Script executed:

#!/bin/bash
# Get list of changed files in the PR
gh api repos/wso2/api-platform/pulls/2238/files --paginate --jq '.[].filename' 2>/dev/null | grep '^gateway/' | sort

Length of output: 6758


🏁 Script executed:

#!/bin/bash
# Get PR details
gh pr view 2238 --repo wso2/api-platform 2>/dev/null || echo "Cannot access PR"

Length of output: 2536


🏁 Script executed:

#!/bin/bash
# Get diffs for key source files
for file in \
  "gateway/gateway-controller/pkg/utils/llm_transformer.go" \
  "gateway/gateway-controller/pkg/utils/mcp_transformer.go" \
  "gateway/gateway-controller/pkg/config/llm_validator.go" \
  "gateway/gateway-controller/pkg/config/mcp_validator.go" \
  "gateway/gateway-controller/pkg/api/handlers/resource_response.go"; do
  echo "=== DIFF: $file ==="
  gh api "repos/wso2/api-platform/pulls/2238/files" --paginate --jq ".[] | select(.filename == \"$file\") | .patch" 2>/dev/null
  echo ""
done

Length of output: 20868


🏁 Script executed:

#!/bin/bash
# Get the management openapi yaml diff
gh api "repos/wso2/api-platform/pulls/2238/files" --paginate --jq '.[] | select(.filename == "gateway/gateway-controller/api/management-openapi.yaml") | .patch' 2>/dev/null | head -500

Length of output: 16191


🏁 Script executed:

#!/bin/bash
# Check for deploymenttransform package mentioned in PR
fd -e go . gateway/ | xargs grep -l "deploymenttransform" 2>/dev/null
rg -r "deploymenttransform" gateway/ --include="*.go" -l 2>/dev/null

# Check if the package exists
find gateway/ -type d -name "deploymenttransform" 2>/dev/null

Length of output: 542


🏁 Script executed:

#!/bin/bash
# Get diff for llm_validator_policy_exclusivity_test.go
gh api "repos/wso2/api-platform/pulls/2238/files" --paginate \
  --jq '.[] | select(.filename == "gateway/gateway-controller/pkg/config/llm_validator_policy_exclusivity_test.go") | .patch' 2>/dev/null

Length of output: 6545


🏁 Script executed:

#!/bin/bash
# Get diff for main.go and api_validator.go
for file in \
  "gateway/gateway-controller/cmd/controller/main.go" \
  "gateway/gateway-controller/pkg/config/api_validator.go"; do
  echo "=== DIFF: $file ==="
  gh api "repos/wso2/api-platform/pulls/2238/files" --paginate --jq ".[] | select(.filename == \"$file\") | .patch" 2>/dev/null
  echo ""
done

Length of output: 1988


🏁 Script executed:

#!/bin/bash
# Get diff for llm_transformer_test.go
gh api "repos/wso2/api-platform/pulls/2238/files" --paginate \
  --jq '.[] | select(.filename == "gateway/gateway-controller/pkg/utils/llm_transformer_test.go") | .patch' 2>/dev/null | head -300

Length of output: 11312


🏁 Script executed:

#!/bin/bash
# Check actual file content for withGlobalAdvancedRatelimitKeyExtraction and collectOperationLevelLLMPolicies
# to verify slice aliasing concern in transformProxy/transformProvider
cat gateway/gateway-controller/pkg/utils/llm_transformer.go | grep -n "append\|merged\|spec.Policies\|gp\[" | head -40

Length of output: 2035



@ashera96 Here is the review of the gateway/ directory changes.


Review: gateway/ — Global Policy Support for LLM Providers and Proxies

Summary

The changes correctly introduce globalPolicies/operationPolicies as first-class fields, bump the artifact apiVersion to v1alpha2, add the exclusivity validator, and simplify LLMPolicyPathMethods from a typed string alias to plain []string. The test coverage for the exclusivity rules is solid. A few issues are noted below.


Issues

1. withGlobalAdvancedRatelimitKeyExtraction skips injection when Params is nil

File: gateway/gateway-controller/pkg/utils/llm_transformer.go

func withGlobalAdvancedRatelimitKeyExtraction(p api.Policy) api.Policy {
    if p.Params == nil {
        return p   // ← key extraction is never injected
    }
    ...
}

When an advanced-ratelimit global policy is configured without any explicit params, the function returns early and never injects the keyExtraction: [{type: "apiname"}] entry. This means the policy falls through to the default per-route bucket instead of the intended API-wide counter.

Suggested fix:

func withGlobalAdvancedRatelimitKeyExtraction(p api.Policy) api.Policy {
    if p.Params != nil {
        if _, ok := (*p.Params)["keyExtraction"]; ok {
            return p
        }
    }
    var base map[string]interface{}
    if p.Params != nil {
        base = make(map[string]interface{}, len(*p.Params)+1)
        for k, v := range *p.Params {
            base[k] = v
        }
    } else {
        base = make(map[string]interface{}, 1)
    }
    base["keyExtraction"] = []map[string]interface{}{{"type": "apiname"}}
    p.Params = &base
    return p
}

2. Hardcoded "advanced-ratelimit" policy name in transformer logic

File: gateway/gateway-controller/pkg/utils/llm_transformer.go

The transformer contains a string literal "advanced-ratelimit" baked into transformProxy and transformProvider:

if p.Name == "advanced-ratelimit" {
    p = withGlobalAdvancedRatelimitKeyExtraction(p)
}

This couples the transformer to a specific policy name. If the policy is renamed or if additional ratelimit policies need the same treatment, this will silently fail. Consider exporting this as a constant (e.g., constants.AdvancedRatelimitPolicyName) or using a dedicated marker/annotation on the policy schema.


3. Missing deploymenttransform package

The PR description states:

A new deploymenttransform package handles artifact adaptation at deploy time. Gateways at version ≥ 1.2.0 receive the new globalPolicies/operationPolicies shape; older gateways transparently receive the legacy flattened policies list.

No such package exists anywhere in the gateway/ directory. The current implementation always emits the v1alpha2 shape to all gateways regardless of version. If backward compatibility with pre-1.2.0 gateways is a requirement, this capability is absent from the PR. Please clarify whether this is deferred to a follow-up or is expected in this PR.


4. Admin API base path not bumped (asymmetry)

File: gateway/gateway-controller/cmd/controller/main.go

const (
    managementAPIBasePath = "/api/management/v1alpha2"  // bumped
    adminAPIBasePath      = "/api/admin/v0.9"           // not bumped
)

The management API path moved to v1alpha2, but the admin API path remains at v0.9. If this is intentional (the admin API is versioned independently), a comment explaining the discrepancy would help future readers.


5. Minor: missing test case in TestValidateLLMProxy_PolicyListExclusivity

File: gateway/gateway-controller/pkg/config/llm_validator_policy_exclusivity_test.go

TestValidateLLMProvider_PolicyListExclusivity includes a "global + operation (both new)" case asserting that using both globalPolicies and operationPolicies together is valid (wantErr: false). The parallel proxy test TestValidateLLMProxy_PolicyListExclusivity is missing this case. Consider adding it for symmetry.


6. Potential slice aliasing in global policy merge

File: gateway/gateway-controller/pkg/utils/llm_transformer.go (lines ~314 and ~652)

merged := append(*spec.Policies, gp...)
spec.Policies = &merged

If *spec.Policies has sufficient spare capacity, append will extend in-place and mutate the backing array shared with the original slice. In the current code this is low risk because the initial spec.Policies allocation is size-1 (the host-header policy), so a reallocation will happen. However, this is fragile. A defensive copy makes the intent explicit:

merged := make([]api.Policy, len(*spec.Policies), len(*spec.Policies)+len(gp))
copy(merged, *spec.Policies)
merged = append(merged, gp...)
spec.Policies = &merged

Positive observations

  • The collectOperationLevelLLMPolicies function cleanly merges the new and deprecated lists, placing new policies first — consistent with the intended priority order.
  • legacyToOperationPolicy is well-isolated and its comment clearly marks it as the sole remaining reference to the legacy type, which will simplify future removal.
  • validatePolicyListExclusivity correctly treats non-nil but empty slices as absent, and its test table is thorough.
  • Changing LLMPolicyPathMethods from a typed string alias to []string removes unnecessary type friction throughout the codebase.

@ashera96 ashera96 force-pushed the global-policy-llm branch from c42b801 to e09ac78 Compare June 22, 2026 12:07
@ashera96 ashera96 marked this pull request as draft June 22, 2026 13:45
@ashera96 ashera96 closed this Jun 25, 2026
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.

1 participant