You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Part of #974 — Extensions SDK testing: PipelinePolicy
Depends on #975 — PipelinePolicy model, fixtures, and basic happy-path test
Context
Once the model class, fixtures, and basic happy path are in place (#975), we need thorough test coverage for PipelinePolicy's features. PipelinePolicy is a generic, declarative extension — different scenarios are different YAML specs — so the test matrix naturally covers the SDK's action types, CEL predicates, pipeline ordering, and targeting modes.
The extension is pre-installed on the test cluster via the helm chart — these tests assume it is already available.
Test cases
Request actions
deny action
CEL predicate denies request — Policy with deny action where predicate evaluates to true → request returns 403
CEL predicate does not deny request — Policy with deny action where predicate evaluates to false → request returns 200
Header-based deny — predicate: '"x-blocked" in request.headers' → requests with header get denied, without header pass
Multiple deny actions (OR behavior) — Two deny actions in sequence; request is denied if either predicate matches
Deny with custom status code — deny with withStatus: 429 → denied request returns 429 instead of default
Deny with custom headers — deny with withHeaders: '[["x-deny-reason", "blocked"]]' → denied response includes custom headers
Deny with custom body — deny with withBody: "Access denied" → denied response body is "Access denied"
Deny with all response fields — deny with withStatus, withHeaders, and withBody all set → all fields present in denied response
fail action
Fail terminates chain — fail action with matching predicate and logMessage → request fails (503 or appropriate error), message logged
Fail does not trigger — fail action with non-matching predicate → request passes through normally
Fail after gRPC call — grpc_method populates variable, fail checks variable for invalid state → chain terminates on bad response
grpc_method action
Basic gRPC upstream call — Register an actionMethod pointing to a gRPC service, use grpc_method request action with var → verify the upstream is called (use the response var in a subsequent action)
Conditional gRPC call — grpc_method with a predicate → upstream is only called when predicate matches
gRPC upstream unavailable — actionMethod points to a non-existent service → verify graceful failure (503 or appropriate error)
gRPC response var used in deny — grpc_method stores response in var, subsequent deny action uses that var in predicate → deny decision based on gRPC response
Response actions
add_headers action
Single header — headersToAdd: '[["x-custom", "value"]]' → response contains x-custom: value
Multiple headers — Add multiple headers in a single action via CEL array → all present in response
Multiple add_headers actions — Two separate response actions each adding headers → all headers present
Conditional header — add_headers with predicate → header only added when predicate matches
Mutually exclusive headers via predicates — Two add_headers actions with opposite predicates → only one set of headers appears depending on request
deny action in response phase
Override response — deny in response phase with matching predicate and withStatus: 503 → backend response replaced with 503 before reaching client
Response deny with headers and body — deny in response phase with withStatus, withHeaders, and withBody → client receives the deny response instead of backend response
Pipeline ordering and composition
Request action ordering matters — A deny action before a grpc_method action: if deny triggers, gRPC is never called
Fail before gRPC — A fail action before a grpc_method action: if fail triggers, gRPC is never called
Response action ordering — Multiple response actions execute in spec order
Empty pipeline — PipelinePolicy with targetRef but no actions → requests pass through unmodified (200, no extra headers)
Request-only pipeline — Only request actions, no response actions → deny/fail works, no header modifications
Response-only pipeline — Only response actions, no request actions → all requests pass, headers modified
Mixed pipeline — Request actions (grpc_method + deny) followed by response actions (add_headers) → full pipeline executes in order
Pipeline validation
Variable forward reference rejected — Action references a var before the grpc_method that populates it → pipeline should fail to commit/enforce
Duplicate variable name rejected — Two grpc_method actions with the same var name → pipeline should fail to commit/enforce
Request after response phase rejected — Request actions defined after response actions → pipeline should fail to commit/enforce
TargetRef variations
Target HTTPRoute — PipelinePolicy targeting an HTTPRoute → only traffic through that route is affected
Target Gateway — PipelinePolicy targeting a Gateway → all routes on the gateway are affected
Target with sectionName — PipelinePolicy targeting a specific Gateway listener or HTTPRoute rule
Policy lifecycle
Policy status conditions — After commit, PipelinePolicy status shows Accepted: True and Enforced: True
Delete policy — After deleting the PipelinePolicy, traffic flows without pipeline actions (no headers, no blocking). Mark flaky(reruns=0) since it deletes a module-scoped fixture
Update policy — Modify the policy spec (e.g., change the deny predicate) and verify the new behavior takes effect
Interaction with other Kuadrant policies
PipelinePolicy + AuthPolicy — Both policies target the same route; verify both are enforced (auth identity + pipeline actions)
PipelinePolicy + RateLimitPolicy — Both policies target the same route; verify rate limits apply alongside pipeline actions
Error and edge cases
Invalid targetRef — PipelinePolicy targeting a non-existent HTTPRoute → policy should not reach Enforced state
Invalid CEL expression — Malformed predicate in deny action → policy behavior (should fail to enforce or reject)
Notes
These tests assume the extension is already installed on the cluster via the helm chart.
Parent
Part of #974 — Extensions SDK testing: PipelinePolicy
Depends on #975 — PipelinePolicy model, fixtures, and basic happy-path test
Context
Once the model class, fixtures, and basic happy path are in place (#975), we need thorough test coverage for PipelinePolicy's features. PipelinePolicy is a generic, declarative extension — different scenarios are different YAML specs — so the test matrix naturally covers the SDK's action types, CEL predicates, pipeline ordering, and targeting modes.
The extension is pre-installed on the test cluster via the helm chart — these tests assume it is already available.
Test cases
Request actions
denyactiondenyaction wherepredicateevaluates to true → request returns 403denyaction wherepredicateevaluates to false → request returns 200predicate: 'request.url_path == "/blocked"'→/blockedreturns 403,/getreturns 200predicate: '"x-blocked" in request.headers'→ requests with header get denied, without header passdenyactions in sequence; request is denied if either predicate matchesdenywithwithStatus: 429→ denied request returns 429 instead of defaultdenywithwithHeaders: '[["x-deny-reason", "blocked"]]'→ denied response includes custom headersdenywithwithBody: "Access denied"→ denied response body is "Access denied"denywithwithStatus,withHeaders, andwithBodyall set → all fields present in denied responsefailactionfailaction with matching predicate andlogMessage→ request fails (503 or appropriate error), message loggedfailaction with non-matching predicate → request passes through normallygrpc_methodpopulates variable,failchecks variable for invalid state → chain terminates on bad responsegrpc_methodactionactionMethodpointing to a gRPC service, usegrpc_methodrequest action withvar→ verify the upstream is called (use the response var in a subsequent action)grpc_methodwith apredicate→ upstream is only called when predicate matchesactionMethodpoints to a non-existent service → verify graceful failure (503 or appropriate error)grpc_methodstores response invar, subsequentdenyaction uses that var in predicate → deny decision based on gRPC responseResponse actions
add_headersactionheadersToAdd: '[["x-custom", "value"]]'→ response containsx-custom: valueadd_headersactions — Two separate response actions each adding headers → all headers presentadd_headerswithpredicate→ header only added when predicate matchesadd_headersactions with opposite predicates → only one set of headers appears depending on requestdenyaction in response phasedenyin response phase with matching predicate andwithStatus: 503→ backend response replaced with 503 before reaching clientdenyin response phase withwithStatus,withHeaders, andwithBody→ client receives the deny response instead of backend responsePipeline ordering and composition
denyaction before agrpc_methodaction: if deny triggers, gRPC is never calledfailaction before agrpc_methodaction: if fail triggers, gRPC is never calledtargetRefbut no actions → requests pass through unmodified (200, no extra headers)Pipeline validation
varbefore thegrpc_methodthat populates it → pipeline should fail to commit/enforcegrpc_methodactions with the samevarname → pipeline should fail to commit/enforceTargetRef variations
Policy lifecycle
Accepted: TrueandEnforced: Trueflaky(reruns=0)since it deletes a module-scoped fixtureInteraction with other Kuadrant policies
Error and edge cases
EnforcedstateNotes
PipelinePolicyclass from PipelinePolicy model, fixtures, and basic happy-path test #975.Test location
Acceptance criteria
deny,fail,grpc_method)add_headers,denyin response phase)withStatus,withHeaders,withBody)make commit-acceptancepasses