Skip to content

Commit 3556628

Browse files
committed
feat: add xfail markers for known issues, add deny-with-CEL-body and top-level-fail validation tests
Signed-off-by: Silvia Tarabova <starabov@redhat.com>
1 parent b94d078 commit 3556628

6 files changed

Lines changed: 125 additions & 9 deletions

File tree

testsuite/tests/singlecluster/extensions/pipeline_policy/interactions/test_pipeline_policy_auth.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,8 @@ def test_auth_and_pipeline_unauthorized(client):
3636
assert response.headers.get("x-pipeline-policy") is None
3737

3838

39+
@pytest.mark.issue("https://github.com/Kuadrant/wasm-shim/issues/371")
40+
@pytest.mark.xfail(reason="https://github.com/Kuadrant/wasm-shim/issues/371")
3941
def test_auth_and_pipeline_blocked_path(client, auth):
4042
"""Authenticated request to blocked path is denied by PipelinePolicy deny action."""
4143
response = client.get("/blocked", auth=auth)

testsuite/tests/singlecluster/extensions/pipeline_policy/test_pipeline_policy_composition.py

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,87 @@ def test_fail_before_deny(request, cluster, blame, route, client, threat_assessm
4949
assert response.status_code == 500
5050

5151

52+
@pytest.mark.issue("https://github.com/Kuadrant/wasm-shim/issues/371")
53+
@pytest.mark.xfail(reason="https://github.com/Kuadrant/wasm-shim/issues/371")
54+
def test_deny_after_grpc_call(request, cluster, blame, route, client, threat_assessment_service):
55+
"""Deny action after gRPC call works when the deny predicate matches."""
56+
svc_url = (
57+
f"grpc://{threat_assessment_service.name()}.{threat_assessment_service.namespace()}.svc.cluster.local:8080"
58+
)
59+
policy = PipelinePolicy.create_instance(cluster, blame("grpc-deny"), route)
60+
policy.add_action_method(
61+
name="assess",
62+
url=svc_url,
63+
service="threat.v1.ThreatAssessmentService",
64+
method="AssessRequest",
65+
message_template="threat.v1.ThreatRequest{uri: request.path}",
66+
)
67+
policy.on_http_request.add_grpc_method(method="assess", var="threat")
68+
policy.on_http_request.add_deny(predicate='request.url_path == "/blocked"', with_status=403)
69+
request.addfinalizer(policy.delete)
70+
policy.commit()
71+
policy.wait_for_ready()
72+
73+
response = client.get("/blocked")
74+
assert response.status_code == 403
75+
76+
77+
def test_deny_based_on_grpc_var(request, cluster, blame, route, client, threat_assessment_service):
78+
"""Deny action using gRPC response variable denies requests when threat level is high."""
79+
svc_url = (
80+
f"grpc://{threat_assessment_service.name()}.{threat_assessment_service.namespace()}.svc.cluster.local:8080"
81+
)
82+
policy = PipelinePolicy.create_instance(cluster, blame("grpc-var-deny"), route)
83+
policy.add_action_method(
84+
name="assess",
85+
url=svc_url,
86+
service="threat.v1.ThreatAssessmentService",
87+
method="AssessRequest",
88+
message_template="threat.v1.ThreatRequest{uri: request.path}",
89+
)
90+
policy.on_http_request.add_grpc_method(method="assess", var="threat")
91+
policy.on_http_request.add_deny(predicate="threat.threat_level >= 4", with_status=403)
92+
request.addfinalizer(policy.delete)
93+
policy.commit()
94+
policy.wait_for_ready()
95+
96+
response = client.get("/admin")
97+
assert response.status_code == 403
98+
99+
response = client.get("/get")
100+
assert response.status_code == 200
101+
102+
103+
@pytest.mark.issue("https://github.com/Kuadrant/kuadrant-operator/issues/2018")
104+
@pytest.mark.xfail(reason="https://github.com/Kuadrant/kuadrant-operator/issues/2018")
105+
def test_deny_with_dynamic_body(request, cluster, blame, route, client, threat_assessment_service):
106+
"""Deny action with CEL expression in withBody interpolates gRPC response variable."""
107+
svc_url = (
108+
f"grpc://{threat_assessment_service.name()}.{threat_assessment_service.namespace()}.svc.cluster.local:8080"
109+
)
110+
policy = PipelinePolicy.create_instance(cluster, blame("dyn-body"), route)
111+
policy.add_action_method(
112+
name="assess",
113+
url=svc_url,
114+
service="threat.v1.ThreatAssessmentService",
115+
method="AssessRequest",
116+
message_template="threat.v1.ThreatRequest{uri: request.path}",
117+
)
118+
policy.on_http_request.add_grpc_method(method="assess", var="threat")
119+
policy.on_http_request.add_deny(
120+
predicate="threat.threat_level >= 4",
121+
with_status=403,
122+
with_body="'blocked: threat level ' + string(threat.threat_level)",
123+
)
124+
request.addfinalizer(policy.delete)
125+
policy.commit()
126+
policy.wait_for_ready()
127+
128+
response = client.get("/admin")
129+
assert response.status_code == 403
130+
assert "blocked: threat level" in response.text
131+
132+
52133
def test_response_action_ordering(request, cluster, blame, route, client):
53134
"""Response actions execute in spec order; both headers from separate actions are present."""
54135
policy = PipelinePolicy.create_instance(cluster, blame("respord"), route)

testsuite/tests/singlecluster/extensions/pipeline_policy/test_pipeline_policy_deny.py

Lines changed: 15 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -20,30 +20,30 @@ def pipeline_policy(pipeline_policy):
2020
with_status=403,
2121
with_headers='[["x-deny-reason", "blocked"]]',
2222
)
23-
# Custom body
23+
# Custom body (CEL expression)
2424
pipeline_policy.on_http_request.add_deny(
2525
predicate='request.url_path == "/custom-body"',
2626
with_status=403,
27-
with_body="Access denied",
27+
with_body="'Access denied'",
2828
)
29-
# All response fields
29+
# All response fields (CEL expression in body)
3030
pipeline_policy.on_http_request.add_deny(
3131
predicate='request.url_path == "/custom-all"',
3232
with_status=451,
3333
with_headers='[["x-deny-reason", "full-custom"]]',
34-
with_body="Fully customized denial",
34+
with_body="'Fully customized denial'",
3535
)
3636
# Response phase deny — status override
3737
pipeline_policy.on_http_response.add_deny(
3838
predicate='"x-override-code" in request.headers',
3939
with_status=503,
4040
)
41-
# Response phase deny — all fields
41+
# Response phase deny — all fields (CEL expression in body)
4242
pipeline_policy.on_http_response.add_deny(
4343
predicate='"x-resp-deny" in request.headers',
4444
with_status=418,
4545
with_headers='[["x-deny-phase", "response"]]',
46-
with_body="Teapot response",
46+
with_body="'Teapot response'",
4747
)
4848
return pipeline_policy
4949

@@ -92,15 +92,19 @@ def test_deny_custom_headers(client):
9292
assert response.headers.get("x-deny-reason") == "blocked"
9393

9494

95+
@pytest.mark.issue("https://github.com/Kuadrant/kuadrant-operator/issues/2018")
96+
@pytest.mark.xfail(reason="https://github.com/Kuadrant/kuadrant-operator/issues/2018")
9597
def test_deny_custom_body(client):
96-
"""Deny with withBody returns custom body text."""
98+
"""Deny with withBody as CEL expression returns custom body text."""
9799
response = client.get("/custom-body")
98100
assert response.status_code == 403
99101
assert response.text == "Access denied"
100102

101103

104+
@pytest.mark.issue("https://github.com/Kuadrant/kuadrant-operator/issues/2018")
105+
@pytest.mark.xfail(reason="https://github.com/Kuadrant/kuadrant-operator/issues/2018")
102106
def test_deny_all_response_fields(client):
103-
"""Deny with withStatus, withHeaders, and withBody all set returns all fields."""
107+
"""Deny with withStatus, withHeaders, and withBody as CEL expression returns all fields."""
104108
response = client.get("/custom-all")
105109
assert response.status_code == 451
106110
assert response.headers.get("x-deny-reason") == "full-custom"
@@ -119,8 +123,10 @@ def test_response_deny_no_override(client):
119123
assert response.status_code == 200
120124

121125

126+
@pytest.mark.issue("https://github.com/Kuadrant/kuadrant-operator/issues/2018")
127+
@pytest.mark.xfail(reason="https://github.com/Kuadrant/kuadrant-operator/issues/2018")
122128
def test_response_deny_with_headers_and_body(client):
123-
"""Response deny with all fields replaces the backend response."""
129+
"""Response deny with all fields as CEL expressions replaces the backend response."""
124130
response = client.get("/get", headers={"x-resp-deny": "true"})
125131
assert response.status_code == 418
126132
assert response.headers.get("x-deny-phase") == "response"

testsuite/tests/singlecluster/extensions/pipeline_policy/test_pipeline_policy_isolation.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,8 @@ def test_policy_affects_targeted_route(client):
8787
assert response.headers.get("x-pipeline-policy") == "active"
8888

8989

90+
@pytest.mark.issue("https://github.com/Kuadrant/kuadrant-operator/issues/2023")
91+
@pytest.mark.xfail(reason="https://github.com/Kuadrant/kuadrant-operator/issues/2023")
9092
def test_policy_does_not_affect_other_route(client2):
9193
"""Route without PipelinePolicy on the same gateway does not get the response header."""
9294
time.sleep(EXTENSION_POLICY_PROPAGATION_WAIT)
@@ -95,6 +97,8 @@ def test_policy_does_not_affect_other_route(client2):
9597
assert response.headers.get("x-pipeline-policy") is None
9698

9799

100+
@pytest.mark.issue("https://github.com/Kuadrant/kuadrant-operator/issues/2023")
101+
@pytest.mark.xfail(reason="https://github.com/Kuadrant/kuadrant-operator/issues/2023")
98102
def test_policy_does_not_affect_other_gateway(client3):
99103
"""Route on a different gateway does not get the response header."""
100104
time.sleep(EXTENSION_POLICY_PROPAGATION_WAIT)

testsuite/tests/singlecluster/extensions/pipeline_policy/test_pipeline_policy_lifecycle.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,8 @@ def test_update_policy(request, cluster, blame, route, client):
3535
assert response.headers.get("x-update-new") == "true"
3636

3737

38+
@pytest.mark.issue("https://github.com/Kuadrant/kuadrant-operator/issues/2009")
39+
@pytest.mark.xfail(reason="https://github.com/Kuadrant/kuadrant-operator/issues/2009")
3840
@pytest.mark.flaky(reruns=0)
3941
def test_delete_policy(request, cluster, blame, route, client):
4042
"""After deleting the PipelinePolicy, the CR is removed and the actions stop being enforced."""

testsuite/tests/singlecluster/extensions/pipeline_policy/test_pipeline_policy_validation.py

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@ def commit():
1414
"""No module-level policy; each test creates its own with bad configuration."""
1515

1616

17+
@pytest.mark.issue("https://github.com/Kuadrant/kuadrant-operator/issues/2022")
18+
@pytest.mark.xfail(reason="https://github.com/Kuadrant/kuadrant-operator/issues/2022")
1719
def test_invalid_target_ref(request, cluster, blame):
1820
"""PipelinePolicy targeting a non-existent HTTPRoute does not reach Enforced state."""
1921
target = CustomReference(
@@ -33,6 +35,8 @@ def test_invalid_target_ref(request, cluster, blame):
3335
), f"Policy did not report TargetNotFound, status: {policy.refresh().model.status.conditions}"
3436

3537

38+
@pytest.mark.issue("https://github.com/Kuadrant/kuadrant-operator/issues/2022")
39+
@pytest.mark.xfail(reason="https://github.com/Kuadrant/kuadrant-operator/issues/2022")
3640
def test_invalid_gateway_target_ref(request, cluster, blame):
3741
"""PipelinePolicy targeting a non-existent Gateway does not reach Enforced state."""
3842
target = CustomReference(
@@ -52,6 +56,23 @@ def test_invalid_gateway_target_ref(request, cluster, blame):
5256
), f"Policy did not report TargetNotFound, status: {policy.refresh().model.status.conditions}"
5357

5458

59+
@pytest.mark.issue("https://github.com/Kuadrant/kuadrant-operator/issues/2015")
60+
@pytest.mark.xfail(reason="https://github.com/Kuadrant/kuadrant-operator/issues/2015")
61+
def test_top_level_fail_action(request, cluster, blame, route):
62+
"""PipelinePolicy with a top-level fail action (not inside gRPC onReply) should not be accepted."""
63+
policy = PipelinePolicy.create_instance(cluster, blame("top-fail"), route)
64+
policy.on_http_request.add_fail("top-level fail", predicate='request.url_path == "/fail"')
65+
66+
request.addfinalizer(policy.delete)
67+
policy.commit()
68+
69+
# TODO: add expected message assertion once the validation is implemented
70+
assert policy.wait_until(
71+
has_condition("Accepted", "False"),
72+
timelimit=30,
73+
), f"Policy with top-level fail was accepted, status: {policy.refresh().model.status.conditions}"
74+
75+
5576
def test_invalid_cel_expression(request, cluster, blame, route):
5677
"""PipelinePolicy with malformed CEL predicate fails to enforce."""
5778
policy = PipelinePolicy.create_instance(cluster, blame("bad-cel"), route)

0 commit comments

Comments
 (0)