diff --git a/testsuite/kuadrant/policy/__init__.py b/testsuite/kuadrant/policy/__init__.py index 0e3f7aa9..8b0c6ccf 100644 --- a/testsuite/kuadrant/policy/__init__.py +++ b/testsuite/kuadrant/policy/__init__.py @@ -1,9 +1,25 @@ """Contains Base class for policies""" +from dataclasses import dataclass + from testsuite.kubernetes import KubernetesObject from testsuite.utils import check_condition +@dataclass +class CelPredicate: + """Dataclass that references CEL predicate e.g. auth.identity.anonymous == 'true'""" + + predicate: str + + +@dataclass +class CelExpression: + """Dataclass that references CEL expression""" + + expression: str + + def has_condition(condition_type, status="True", reason=None, message=None): """Returns function, that returns True if the Kubernetes object has a specific value""" diff --git a/testsuite/kuadrant/policy/authorization/sections.py b/testsuite/kuadrant/policy/authorization/sections.py index 7f158ff0..b35cb145 100644 --- a/testsuite/kuadrant/policy/authorization/sections.py +++ b/testsuite/kuadrant/policy/authorization/sections.py @@ -232,7 +232,7 @@ def add_success_dynamic(self, name: str, value: SUCCESS_RESPONSE, **common_featu This section is for items wrapped as Envoy Dynamic Metadata. """ - success_dynamic_metadata = self.section.setdefault("success", {}).setdefault("dynamicMetadata", {}) + success_dynamic_metadata = self.section.setdefault("success", {}).setdefault("filters", {}) asdict_value = asdict(value) add_common_features(asdict_value, **common_features) success_dynamic_metadata.update({name: asdict_value}) diff --git a/testsuite/kuadrant/policy/rate_limit.py b/testsuite/kuadrant/policy/rate_limit.py index 0dcadf8d..55102209 100644 --- a/testsuite/kuadrant/policy/rate_limit.py +++ b/testsuite/kuadrant/policy/rate_limit.py @@ -2,13 +2,12 @@ import time from dataclasses import dataclass -from typing import Iterable, Literal +from typing import Iterable from testsuite.gateway import Referencable from testsuite.kubernetes import modify from testsuite.kubernetes.client import KubernetesClient -from testsuite.kuadrant.policy import Policy -from testsuite.kuadrant.policy.authorization import Rule +from testsuite.kuadrant.policy import Policy, CelPredicate, CelExpression from testsuite.utils import asdict @@ -17,8 +16,7 @@ class Limit: """Limit dataclass""" limit: int - duration: int - unit: Literal["second", "minute", "day"] = "second" + window: str class RateLimitPolicy(Policy): @@ -47,8 +45,8 @@ def add_limit( self, name, limits: Iterable[Limit], - when: Iterable[Rule] = None, - counters: list[str] = None, + when: list[CelPredicate] = None, + counters: list[CelExpression] = None, ): """Add another limit""" limit: dict = { @@ -57,7 +55,7 @@ def add_limit( if when: limit["when"] = [asdict(rule) for rule in when] if counters: - limit["counters"] = counters + limit["counters"] = [asdict(rule) for rule in counters] if self.spec_section is None: self.spec_section = self.model.spec diff --git a/testsuite/tests/kuadrantctl/cli/test_simple_limit.py b/testsuite/tests/kuadrantctl/cli/test_simple_limit.py index fa630ce9..4bf6860a 100644 --- a/testsuite/tests/kuadrantctl/cli/test_simple_limit.py +++ b/testsuite/tests/kuadrantctl/cli/test_simple_limit.py @@ -16,7 +16,7 @@ def oas(oas, blame, gateway, hostname, backend): oas.add_top_level_route(gateway, hostname, blame("route")) oas.add_backend_to_paths(backend) - oas["paths"]["/anything"]["get"]["x-kuadrant"] = {"rate_limit": {"rates": [asdict(Limit(3, 20))]}} + oas["paths"]["/anything"]["get"]["x-kuadrant"] = {"rate_limit": {"rates": [asdict(Limit(3, "20s"))]}} return oas diff --git a/testsuite/tests/singlecluster/defaults/test_basic_rate_limit.py b/testsuite/tests/singlecluster/defaults/test_basic_rate_limit.py index 713bb5da..8e4887b2 100644 --- a/testsuite/tests/singlecluster/defaults/test_basic_rate_limit.py +++ b/testsuite/tests/singlecluster/defaults/test_basic_rate_limit.py @@ -6,7 +6,7 @@ pytestmark = [pytest.mark.kuadrant_only, pytest.mark.limitador] -LIMIT = Limit(3, 5) +LIMIT = Limit(3, "5s") @pytest.fixture(scope="module") diff --git a/testsuite/tests/singlecluster/defaults/test_rules_exclusivity.py b/testsuite/tests/singlecluster/defaults/test_rules_exclusivity.py index 2f8f35bd..536289cc 100644 --- a/testsuite/tests/singlecluster/defaults/test_rules_exclusivity.py +++ b/testsuite/tests/singlecluster/defaults/test_rules_exclusivity.py @@ -28,8 +28,8 @@ def test_rules_exclusivity_authorization(cluster, route, oidc_provider, module_l def test_rules_exclusivity_rate_limit(cluster, route, module_label, blame): """Test that server will reject object with implicit and explicit defaults simultaneously in RateLimitPolicy""" rate_limit = RateLimitPolicy.create_instance(cluster, blame("limit"), route, labels={"testRun": module_label}) - rate_limit.defaults.add_limit("inside-defaults", [Limit(2, 5)]) - rate_limit.add_limit("outside-defaults", [Limit(2, 5)]) + rate_limit.defaults.add_limit("inside-defaults", [Limit(2, "5s")]) + rate_limit.add_limit("outside-defaults", [Limit(2, "5s")]) with pytest.raises(OpenShiftPythonException, match="Implicit and explicit defaults are mutually exclusive"): rate_limit.commit() diff --git a/testsuite/tests/singlecluster/gateway/reconciliation/test_affected_by.py b/testsuite/tests/singlecluster/gateway/reconciliation/test_affected_by.py index fef3e5a5..10d6923b 100644 --- a/testsuite/tests/singlecluster/gateway/reconciliation/test_affected_by.py +++ b/testsuite/tests/singlecluster/gateway/reconciliation/test_affected_by.py @@ -14,7 +14,7 @@ def rate_limit(cluster, blame, module_label, route): """ policy = RateLimitPolicy.create_instance(cluster, blame("limit"), route, labels={"testRun": module_label}) - policy.add_limit("basic", [Limit(5, 10)]) + policy.add_limit("basic", [Limit(5, "10s")]) return policy diff --git a/testsuite/tests/singlecluster/identical_hostnames/test_identical_hostnames_on_routes_desired.py b/testsuite/tests/singlecluster/identical_hostnames/test_identical_hostnames_on_routes_desired.py index d75bbfd7..55b734e3 100644 --- a/testsuite/tests/singlecluster/identical_hostnames/test_identical_hostnames_on_routes_desired.py +++ b/testsuite/tests/singlecluster/identical_hostnames/test_identical_hostnames_on_routes_desired.py @@ -29,7 +29,7 @@ def authorization2(request, route2, blame, openshift, label): @pytest.fixture(scope="module") def rate_limit(rate_limit): """Add limit to 1st RateLimitPolicy allowing 1 request per 10 minutes (a.k.a. '1rp10m' RateLimitPolicy)""" - rate_limit.add_limit("1rp10m", [Limit(1, 10)]) + rate_limit.add_limit("1rp10m", [Limit(1, "10s")]) return rate_limit @@ -38,7 +38,7 @@ def rate_limit2(request, route2, blame, openshift, label): """2nd RateLimitPolicy allowing 2 requests per 10 minutes (a.k.a. '2rp10m' RateLimitPolicy)""" rlp = RateLimitPolicy.create_instance(openshift, blame("2rp10m"), route2, labels={"testRun": label}) request.addfinalizer(rlp.delete) - rlp.add_limit("2rp10m", [Limit(2, 10)]) + rlp.add_limit("2rp10m", [Limit(2, "10s")]) rlp.commit() rlp.wait_for_ready() return rlp diff --git a/testsuite/tests/singlecluster/identical_hostnames/test_identical_hostnames_rlp_on_gw_and_route.py b/testsuite/tests/singlecluster/identical_hostnames/test_identical_hostnames_rlp_on_gw_and_route.py index e4d5ca79..e8f05761 100644 --- a/testsuite/tests/singlecluster/identical_hostnames/test_identical_hostnames_rlp_on_gw_and_route.py +++ b/testsuite/tests/singlecluster/identical_hostnames/test_identical_hostnames_rlp_on_gw_and_route.py @@ -16,7 +16,7 @@ def rate_limit2(request, gateway, blame, cluster, label): """2nd RateLimitPolicy object allowing 1 request per 10 minutes (a.k.a. '1rp10m')""" rlp = RateLimitPolicy.create_instance(cluster, blame("2rp10m"), gateway, labels={"testRun": label}) request.addfinalizer(rlp.delete) - rlp.add_limit("1rp10m", [Limit(1, 600)]) + rlp.add_limit("1rp10m", [Limit(1, "600s")]) rlp.commit() rlp.wait_for_partial_enforced() return rlp diff --git a/testsuite/tests/singlecluster/identical_hostnames/test_identical_hostnames_rlp_on_routes.py b/testsuite/tests/singlecluster/identical_hostnames/test_identical_hostnames_rlp_on_routes.py index d6dadd86..bd922867 100644 --- a/testsuite/tests/singlecluster/identical_hostnames/test_identical_hostnames_rlp_on_routes.py +++ b/testsuite/tests/singlecluster/identical_hostnames/test_identical_hostnames_rlp_on_routes.py @@ -14,7 +14,7 @@ @pytest.fixture(scope="module") def rate_limit(rate_limit): """Add limit to 1st RateLimitPolicy allowing 1 request per 10 minutes (a.k.a. '1rp10m' RateLimitPolicy)""" - rate_limit.add_limit("1rp10m", [Limit(1, 10)]) + rate_limit.add_limit("1rp10m", [Limit(1, "10s")]) return rate_limit @@ -23,7 +23,7 @@ def rate_limit2(request, route2, blame, cluster, label): """2nd RateLimitPolicy allowing 2 requests per 10 minutes (a.k.a. '2rp10m' RateLimitPolicy)""" rlp = RateLimitPolicy.create_instance(cluster, blame("2rp10m"), route2, labels={"testRun": label}) request.addfinalizer(rlp.delete) - rlp.add_limit("2rp10m", [Limit(2, 10)]) + rlp.add_limit("2rp10m", [Limit(2, "10s")]) rlp.commit() rlp.wait_for_ready() return rlp diff --git a/testsuite/tests/singlecluster/limitador/method/test_route_subset_method.py b/testsuite/tests/singlecluster/limitador/method/test_route_subset_method.py index 1909a4c1..6d5711f5 100644 --- a/testsuite/tests/singlecluster/limitador/method/test_route_subset_method.py +++ b/testsuite/tests/singlecluster/limitador/method/test_route_subset_method.py @@ -3,7 +3,7 @@ import pytest from testsuite.gateway import RouteMatch, PathMatch, MatchType, HTTPMethod -from testsuite.kuadrant.policy.authorization import Pattern +from testsuite.kuadrant.policy import CelPredicate from testsuite.kuadrant.policy.rate_limit import Limit @@ -28,8 +28,8 @@ def route(route, backend): @pytest.fixture(scope="module") def rate_limit(rate_limit): """Add limit to the policy""" - when = [Pattern("request.path", "eq", "/anything"), Pattern("request.method", "eq", "GET")] - rate_limit.add_limit("anything", [Limit(5, 10)], when=when) + when = [CelPredicate("request.path == '/anything'"), CelPredicate("request.method == 'GET'")] + rate_limit.add_limit("anything", [Limit(5, "10s")], when=when) return rate_limit diff --git a/testsuite/tests/singlecluster/limitador/metrics/test_metrics.py b/testsuite/tests/singlecluster/limitador/metrics/test_metrics.py index c1c550a7..2b3e1269 100644 --- a/testsuite/tests/singlecluster/limitador/metrics/test_metrics.py +++ b/testsuite/tests/singlecluster/limitador/metrics/test_metrics.py @@ -8,7 +8,7 @@ @pytest.fixture(scope="module") def rate_limit(rate_limit): """Add limit to the policy""" - rate_limit.add_limit("multiple", [Limit(3, 10)]) + rate_limit.add_limit("multiple", [Limit(3, "10s")]) return rate_limit diff --git a/testsuite/tests/singlecluster/limitador/route/test_limit_targeting_two_rules.py b/testsuite/tests/singlecluster/limitador/route/test_limit_targeting_two_rules.py index 57126b5e..35548ff7 100644 --- a/testsuite/tests/singlecluster/limitador/route/test_limit_targeting_two_rules.py +++ b/testsuite/tests/singlecluster/limitador/route/test_limit_targeting_two_rules.py @@ -2,7 +2,7 @@ import pytest -from testsuite.kuadrant.policy.authorization import Pattern +from testsuite.kuadrant.policy import CelPredicate from testsuite.kuadrant.policy.rate_limit import Limit @@ -12,8 +12,7 @@ @pytest.fixture(scope="module") def rate_limit(rate_limit): """Add limit to the policy""" - when = Pattern("request.method", "eq", "GET") - rate_limit.add_limit("test", [Limit(5, 10)], when=[when]) + rate_limit.add_limit("test", [Limit(5, "10s")], when=[CelPredicate("request.method == 'GET'")]) return rate_limit diff --git a/testsuite/tests/singlecluster/limitador/route/test_multiple_same_rule.py b/testsuite/tests/singlecluster/limitador/route/test_multiple_same_rule.py index 100d4cd9..0796e1bb 100644 --- a/testsuite/tests/singlecluster/limitador/route/test_multiple_same_rule.py +++ b/testsuite/tests/singlecluster/limitador/route/test_multiple_same_rule.py @@ -2,8 +2,8 @@ import pytest +from testsuite.kuadrant.policy import CelPredicate from testsuite.kuadrant.policy.rate_limit import Limit -from testsuite.kuadrant.policy.authorization import Pattern pytestmark = [pytest.mark.kuadrant_only, pytest.mark.limitador] @@ -12,9 +12,9 @@ @pytest.fixture(scope="module") def rate_limit(rate_limit): """Add limit to the policy""" - when = Pattern("request.path", "eq", "/get") - rate_limit.add_limit("test1", [Limit(8, 10)], when=[when]) - rate_limit.add_limit("test2", [Limit(3, 5)], when=[when]) + when = CelPredicate("request.path == '/get'") + rate_limit.add_limit("test1", [Limit(8, "10s")], when=[when]) + rate_limit.add_limit("test2", [Limit(3, "5s")], when=[when]) return rate_limit diff --git a/testsuite/tests/singlecluster/limitador/route/test_route_rule.py b/testsuite/tests/singlecluster/limitador/route/test_route_rule.py index ebc8a5b4..f199eb10 100644 --- a/testsuite/tests/singlecluster/limitador/route/test_route_rule.py +++ b/testsuite/tests/singlecluster/limitador/route/test_route_rule.py @@ -2,8 +2,8 @@ import pytest +from testsuite.kuadrant.policy import CelPredicate from testsuite.kuadrant.policy.rate_limit import Limit -from testsuite.kuadrant.policy.authorization import Pattern pytestmark = [pytest.mark.kuadrant_only, pytest.mark.limitador] @@ -11,8 +11,7 @@ @pytest.fixture(scope="module") def rate_limit(rate_limit): """Add limit to the policy""" - when = [Pattern("request.path", "eq", "/get")] - rate_limit.add_limit("multiple", [Limit(5, 10)], when=when) + rate_limit.add_limit("multiple", [Limit(5, "10s")], when=[CelPredicate("request.path == '/get'")]) return rate_limit diff --git a/testsuite/tests/singlecluster/limitador/test_basic_limit.py b/testsuite/tests/singlecluster/limitador/test_basic_limit.py index c26e17a7..c1473865 100644 --- a/testsuite/tests/singlecluster/limitador/test_basic_limit.py +++ b/testsuite/tests/singlecluster/limitador/test_basic_limit.py @@ -12,9 +12,9 @@ @pytest.fixture( scope="module", params=[ - pytest.param(Limit(2, 15), id="2 requests every 15 sec"), - pytest.param(Limit(5, 10), id="5 requests every 10 sec"), - pytest.param(Limit(3, 5), id="3 request every 5 sec"), + pytest.param(Limit(2, "15s"), id="2 requests every 15 sec"), + pytest.param(Limit(5, "10s"), id="5 requests every 10 sec"), + pytest.param(Limit(3, "5s"), id="3 request every 5 sec"), ], ) def limit(request): diff --git a/testsuite/tests/singlecluster/limitador/test_multiple_iterations.py b/testsuite/tests/singlecluster/limitador/test_multiple_iterations.py index 513a2c59..aa6f9d1b 100644 --- a/testsuite/tests/singlecluster/limitador/test_multiple_iterations.py +++ b/testsuite/tests/singlecluster/limitador/test_multiple_iterations.py @@ -14,7 +14,7 @@ @pytest.fixture(scope="module") def rate_limit(rate_limit): """Add limit to the policy""" - rate_limit.add_limit("multiple", [Limit(5, 10)]) + rate_limit.add_limit("multiple", [Limit(5, "10s")]) return rate_limit diff --git a/testsuite/tests/singlecluster/overrides/test_basic_rate_limit.py b/testsuite/tests/singlecluster/overrides/test_basic_rate_limit.py index f88656b6..9b0460ba 100644 --- a/testsuite/tests/singlecluster/overrides/test_basic_rate_limit.py +++ b/testsuite/tests/singlecluster/overrides/test_basic_rate_limit.py @@ -6,8 +6,8 @@ pytestmark = [pytest.mark.kuadrant_only, pytest.mark.limitador] -GATEWAY_LIMIT = Limit(3, 5) -ROUTE_LIMIT = Limit(2, 5) +GATEWAY_LIMIT = Limit(3, "5s") +ROUTE_LIMIT = Limit(2, "5s") @pytest.fixture(scope="module") diff --git a/testsuite/tests/singlecluster/overrides/test_route_override.py b/testsuite/tests/singlecluster/overrides/test_route_override.py index 2012043f..64c161de 100644 --- a/testsuite/tests/singlecluster/overrides/test_route_override.py +++ b/testsuite/tests/singlecluster/overrides/test_route_override.py @@ -18,7 +18,7 @@ def authorization(authorization, oidc_provider): @pytest.fixture(scope="module") def rate_limit(rate_limit): """Add basic rate limiting rules in the overrides block""" - rate_limit.overrides.add_limit("override", [Limit(2, 5)]) + rate_limit.overrides.add_limit("override", [Limit(2, "5s")]) return rate_limit diff --git a/testsuite/tests/singlecluster/overrides/test_rules_exclusivity.py b/testsuite/tests/singlecluster/overrides/test_rules_exclusivity.py index 299e7f9f..e8f3d823 100644 --- a/testsuite/tests/singlecluster/overrides/test_rules_exclusivity.py +++ b/testsuite/tests/singlecluster/overrides/test_rules_exclusivity.py @@ -45,8 +45,8 @@ def test_rules_exclusivity_explicit_authorization(cluster, route, oidc_provider, def test_rules_exclusivity_implicit_rate_limit(cluster, route, module_label, blame): """Test that server will reject a RateLimitPolicy with overrides and implicit defaults defined simultaneously""" rate_limit = RateLimitPolicy.create_instance(cluster, blame("limit"), route, labels={"testRun": module_label}) - rate_limit.overrides.add_limit("overrides", [Limit(2, 5)]) - rate_limit.add_limit("implicit-defaults", [Limit(2, 5)]) + rate_limit.overrides.add_limit("overrides", [Limit(2, "5s")]) + rate_limit.add_limit("implicit-defaults", [Limit(2, "5s")]) with pytest.raises(OpenShiftPythonException, match="Overrides and implicit defaults are mutually exclusive"): rate_limit.commit() @@ -56,8 +56,8 @@ def test_rules_exclusivity_implicit_rate_limit(cluster, route, module_label, bla def test_rules_exclusivity_explicit_rate_limit(cluster, route, module_label, blame): """Test that server will reject a RateLimitPolicy with overrides and explicit defaults defined simultaneously""" rate_limit = RateLimitPolicy.create_instance(cluster, blame("limit"), route, labels={"testRun": module_label}) - rate_limit.overrides.add_limit("overrides", [Limit(2, 5)]) - rate_limit.defaults.add_limit("explicit-defaults", [Limit(2, 5)]) + rate_limit.overrides.add_limit("overrides", [Limit(2, "5s")]) + rate_limit.defaults.add_limit("explicit-defaults", [Limit(2, "5s")]) with pytest.raises(OpenShiftPythonException, match="Overrides and explicit defaults are mutually exclusive"): rate_limit.commit() diff --git a/testsuite/tests/singlecluster/test_rate_limit_anonymous.py b/testsuite/tests/singlecluster/test_rate_limit_anonymous.py index d44d7bad..7572b05a 100644 --- a/testsuite/tests/singlecluster/test_rate_limit_anonymous.py +++ b/testsuite/tests/singlecluster/test_rate_limit_anonymous.py @@ -3,7 +3,8 @@ import pytest from testsuite.httpx.auth import HttpxOidcClientAuth -from testsuite.kuadrant.policy.authorization import Pattern, JsonResponse, ValueFrom +from testsuite.kuadrant.policy import CelPredicate +from testsuite.kuadrant.policy.authorization import JsonResponse, ValueFrom from testsuite.kuadrant.policy.rate_limit import Limit pytestmark = [pytest.mark.kuadrant_only, pytest.mark.limitador] @@ -14,14 +15,8 @@ def rate_limit(rate_limit): """Add limit to the policy only for anonymous users""" rate_limit.add_limit( "basic", - [Limit(5, 10)], - when=[ - Pattern( - selector=r"metadata.filter_metadata.envoy\.filters\.http\.ext_authz.identity.anonymous", - operator="eq", - value='"true"', - ) - ], + [Limit(5, "10s")], + when=[CelPredicate("auth.identity.anonymous == 'true'")], ) return rate_limit diff --git a/testsuite/tests/singlecluster/test_rate_limit_authz.py b/testsuite/tests/singlecluster/test_rate_limit_authz.py index 2160bf3b..d22aa296 100644 --- a/testsuite/tests/singlecluster/test_rate_limit_authz.py +++ b/testsuite/tests/singlecluster/test_rate_limit_authz.py @@ -3,6 +3,7 @@ import pytest from testsuite.httpx.auth import HttpxOidcClientAuth +from testsuite.kuadrant.policy import CelExpression from testsuite.kuadrant.policy.authorization import ValueFrom, JsonResponse from testsuite.kuadrant.policy.rate_limit import Limit @@ -13,9 +14,7 @@ @pytest.fixture(scope="module") def rate_limit(rate_limit): """Add limit to the policy""" - rate_limit.add_limit( - "basic", [Limit(5, 60)], counters=[r"metadata.filter_metadata.envoy\.filters\.http\.ext_authz.identity.user"] - ) + rate_limit.add_limit("basic", [Limit(5, "60s")], counters=[CelExpression("auth.identity.user")]) return rate_limit