From 63291a5c13c8f6a4a5e7fe28016498eb70bbbb8e Mon Sep 17 00:00:00 2001 From: Tomas Repel Date: Thu, 21 Nov 2024 07:56:45 +0100 Subject: [PATCH 1/2] Update 'identical hostname' tests since the behavior has changed Signed-off-by: Tomas Repel --- .../identical_hostnames/auth/__init__.py | 0 .../identical_hostnames/auth/conftest.py | 18 ++++ ...dentical_hostnames_auth_on_gw_and_route.py | 78 ++++++++++++++++ ...test_identical_hostnames_auth_on_routes.py | 65 +++++++++++++ .../identical_hostnames/rlp/__init__.py | 0 .../identical_hostnames/rlp/conftest.py | 12 +++ ...identical_hostnames_rlp_on_gw_and_route.py | 90 ++++++++++++++++++ .../test_identical_hostnames_rlp_on_routes.py | 79 ++++++++++++++++ ...dentical_hostnames_auth_on_gw_and_route.py | 61 ------------ ..._hostnames_auth_on_gw_and_route_desired.py | 53 ----------- ...test_identical_hostnames_auth_on_routes.py | 79 ---------------- ...t_identical_hostnames_on_routes_desired.py | 93 ------------------- ...identical_hostnames_rlp_on_gw_and_route.py | 62 ------------- .../test_identical_hostnames_rlp_on_routes.py | 78 ---------------- 14 files changed, 342 insertions(+), 426 deletions(-) create mode 100644 testsuite/tests/singlecluster/identical_hostnames/auth/__init__.py create mode 100644 testsuite/tests/singlecluster/identical_hostnames/auth/conftest.py create mode 100644 testsuite/tests/singlecluster/identical_hostnames/auth/test_identical_hostnames_auth_on_gw_and_route.py create mode 100644 testsuite/tests/singlecluster/identical_hostnames/auth/test_identical_hostnames_auth_on_routes.py create mode 100644 testsuite/tests/singlecluster/identical_hostnames/rlp/__init__.py create mode 100644 testsuite/tests/singlecluster/identical_hostnames/rlp/conftest.py create mode 100644 testsuite/tests/singlecluster/identical_hostnames/rlp/test_identical_hostnames_rlp_on_gw_and_route.py create mode 100644 testsuite/tests/singlecluster/identical_hostnames/rlp/test_identical_hostnames_rlp_on_routes.py delete mode 100644 testsuite/tests/singlecluster/identical_hostnames/test_identical_hostnames_auth_on_gw_and_route.py delete mode 100644 testsuite/tests/singlecluster/identical_hostnames/test_identical_hostnames_auth_on_gw_and_route_desired.py delete mode 100644 testsuite/tests/singlecluster/identical_hostnames/test_identical_hostnames_auth_on_routes.py delete mode 100644 testsuite/tests/singlecluster/identical_hostnames/test_identical_hostnames_on_routes_desired.py delete mode 100644 testsuite/tests/singlecluster/identical_hostnames/test_identical_hostnames_rlp_on_gw_and_route.py delete mode 100644 testsuite/tests/singlecluster/identical_hostnames/test_identical_hostnames_rlp_on_routes.py diff --git a/testsuite/tests/singlecluster/identical_hostnames/auth/__init__.py b/testsuite/tests/singlecluster/identical_hostnames/auth/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/testsuite/tests/singlecluster/identical_hostnames/auth/conftest.py b/testsuite/tests/singlecluster/identical_hostnames/auth/conftest.py new file mode 100644 index 00000000..b7f84fb2 --- /dev/null +++ b/testsuite/tests/singlecluster/identical_hostnames/auth/conftest.py @@ -0,0 +1,18 @@ +"""Conftest for "identical hostname" tests""" + +import pytest + + +@pytest.fixture(scope="module") +def authorization(authorization): + """1st 'allow-all' Authorization object""" + authorization.authorization.add_opa_policy("rego", "allow = true") + return authorization + + +@pytest.fixture(scope="module") +def rate_limit(): + """ + For these tests RateLimitPolicy is not required + """ + return None diff --git a/testsuite/tests/singlecluster/identical_hostnames/auth/test_identical_hostnames_auth_on_gw_and_route.py b/testsuite/tests/singlecluster/identical_hostnames/auth/test_identical_hostnames_auth_on_gw_and_route.py new file mode 100644 index 00000000..93b12b88 --- /dev/null +++ b/testsuite/tests/singlecluster/identical_hostnames/auth/test_identical_hostnames_auth_on_gw_and_route.py @@ -0,0 +1,78 @@ +""" +There used to be a limitation if using one HTTPRoute declaring the same hostname as parent Gateway related to AuthPolicy +https://github.com/Kuadrant/kuadrant-operator/blob/c8d083808daff46772254e223407c849b55020a7/doc/auth.md#limitation-multiple-network-resources-with-identical-hostnames +(second topology mentioned there) +This test validates that it has been properly fixed, i.e. both AuthPolicies are fully and successfully enforced. +""" + +import pytest + +from testsuite.kuadrant.policy import has_condition +from testsuite.kuadrant.policy.authorization.auth_policy import AuthPolicy + +pytestmark = [pytest.mark.kuadrant_only] + + +@pytest.fixture(scope="module") +def authorization2(gateway, blame, cluster, label): + """2nd 'deny-all' Authorization object""" + auth_policy = AuthPolicy.create_instance(cluster, blame("authz2"), gateway, labels={"testRun": label}) + auth_policy.authorization.add_opa_policy("rego", "allow = false") + return auth_policy + + +@pytest.fixture(scope="module", autouse=True) +def commit(request, authorization, authorization2): + """Ensure Authorizations are created""" + for auth in [authorization, authorization2]: + if auth is not None: + request.addfinalizer(auth.delete) + auth.commit() + auth.wait_for_accepted() + + authorization.wait_for_ready() + + # At this point the 'route2' has not been created yet so authorization2 is completely overridden by authorization1 + assert authorization2.wait_until(has_condition("Enforced", "False", "Overridden")), ( + f"'deny-all' AuthPolicy did not reach expected record status, instead it was: " + f"{authorization2.model.status.condition}" + ) + + +def test_identical_hostnames_auth_on_gw_and_route(client, authorization, authorization2): + """ + Tests that Gateway-attached AuthPolicy affects on 'route2' even if both 'route' and 'route2' declare identical + hostname and there is another AuthPolicy already successfully enforced on 'route'. + Setup: + - Two HTTPRoutes declaring identical hostnames but different paths: '/anything/route1' and '/anything/route2' + - 'allow-all' AuthPolicy enforced on the '/anything/route1' HTTPRoute + - 'deny-all' AuthPolicy (created after 'allow-all' AuthPolicy) enforced on the Gateway + Test: + - Send a request via 'route' and assert that response status code is 200 OK + - Send a request via 'route2' and assert that response status code is 403 Forbidden + - Delete the 'allow-all' AuthPolicy + - Send a request via both routes + - Assert that both response status codes are 403 (Forbidden) + """ + + # Verify that the GW-level 'deny-all' AuthPolicy is now only partially enforced ('route2' only). It is overridden + # for 'route1' by HTTPRoute-level 'allow-all' AuthPolicy + authorization2.wait_for_partial_enforced() + + # Access via 'route' is allowed due to 'allow-all' AuthPolicy + response = client.get("/anything/route1/get") + assert response.status_code == 200 + + # 'deny-all' Gateway AuthPolicy affects route2 + response = client.get("/anything/route2/get") + assert response.status_code == 403 + + # Deletion of 'allow-all' AuthPolicy should make the 'deny-all' Gateway AuthPolicy enforced on both routes + authorization.delete() + authorization2.wait_for_ready() + + response = client.get("/anything/route1/get") + assert response.status_code == 403 + + response = client.get("/anything/route2/get") + assert response.status_code == 403 diff --git a/testsuite/tests/singlecluster/identical_hostnames/auth/test_identical_hostnames_auth_on_routes.py b/testsuite/tests/singlecluster/identical_hostnames/auth/test_identical_hostnames_auth_on_routes.py new file mode 100644 index 00000000..00d4b7de --- /dev/null +++ b/testsuite/tests/singlecluster/identical_hostnames/auth/test_identical_hostnames_auth_on_routes.py @@ -0,0 +1,65 @@ +""" +There used to be a limitation if using two HTTPRoutes declaring the same hostname related to AuthPolicy: +https://github.com/Kuadrant/kuadrant-operator/blob/c8d083808daff46772254e223407c849b55020a7/doc/auth.md#limitation-multiple-network-resources-with-identical-hostnames +(the first topology mentioned there) +This test validates that it has been properly fixed, i.e. both AuthPolicies are fully and successfully enforced. +""" + +import pytest + +from testsuite.kuadrant.policy.authorization.auth_policy import AuthPolicy + +pytestmark = [pytest.mark.kuadrant_only] + + +@pytest.fixture(scope="module") +def authorization2(route2, blame, cluster, label): + """2nd 'deny-all' Authorization object""" + auth_policy = AuthPolicy.create_instance(cluster, blame("authz2"), route2, labels={"testRun": label}) + auth_policy.authorization.add_opa_policy("rego", "allow = false") + return auth_policy + + +@pytest.fixture(scope="module", autouse=True) +def commit(request, authorization, authorization2): + """Ensure Authorizations are created""" + for auth in [authorization, authorization2]: + if auth is not None: + request.addfinalizer(auth.delete) + auth.commit() + auth.wait_for_ready() + + +def test_identical_hostnames_auth_on_routes(client, authorization): + """ + Validate that 2nd AuthPolicy is fully enforced on 'route2' declaring identical hostname as 'route' when another + AuthPolicy already successfully enforced on 'route'. + Setup: + - Two HTTPRoutes declaring identical hostnames but different paths: '/anything/route1' and '/anything/route2' + - 'allow-all' AuthPolicy enforced on the '/anything/route1' HTTPRoute + - 'deny-all' AuthPolicy (created after 'allow-all' AuthPolicy) enforced on the '/anything/route2' HTTPRoute + Test: + - Send a request via 'route' and assert that response status code is 200 OK + - Send a request via 'route2' and assert that response status code is 403 Forbidden + - Delete the 'allow-all' AuthPolicy + - Send a request via both routes + - Assert that access via 'route' is still 200 (OK), deletion of 'allow-all' Authpolicy should have no effect + - Assert that access via 'route2' is still 403 (Forbidden) + """ + + response = client.get("/anything/route1/get") + assert response.status_code == 200 + + response = client.get("/anything/route2/get") + assert response.status_code == 403 + + # Deletion of 'allow-all' AuthPolicy + authorization.delete() + + # Access via 'route' is still allowed because 'deny-all' AuthPolicy is not enforced on this route + response = client.get("/anything/route1/get") + assert response.status_code == 200 + + # Access via 'route2' is still not allowed due to 'deny-all' AuthPolicy being enforced on 'route2' + response = client.get("/anything/route2/get") + assert response.status_code == 403 diff --git a/testsuite/tests/singlecluster/identical_hostnames/rlp/__init__.py b/testsuite/tests/singlecluster/identical_hostnames/rlp/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/testsuite/tests/singlecluster/identical_hostnames/rlp/conftest.py b/testsuite/tests/singlecluster/identical_hostnames/rlp/conftest.py new file mode 100644 index 00000000..47c67442 --- /dev/null +++ b/testsuite/tests/singlecluster/identical_hostnames/rlp/conftest.py @@ -0,0 +1,12 @@ +"""Conftest for "identical hostname" tests""" + +import pytest + +from testsuite.kuadrant.policy.rate_limit import Limit + + +@pytest.fixture(scope="module") +def rate_limit(rate_limit): + """Add limit to 1st RateLimitPolicy allowing 1 request per 10 seconds (a.k.a. '1rp10s' RateLimitPolicy)""" + rate_limit.add_limit("1rp10s", [Limit(1, "10s")]) + return rate_limit diff --git a/testsuite/tests/singlecluster/identical_hostnames/rlp/test_identical_hostnames_rlp_on_gw_and_route.py b/testsuite/tests/singlecluster/identical_hostnames/rlp/test_identical_hostnames_rlp_on_gw_and_route.py new file mode 100644 index 00000000..40b42a22 --- /dev/null +++ b/testsuite/tests/singlecluster/identical_hostnames/rlp/test_identical_hostnames_rlp_on_gw_and_route.py @@ -0,0 +1,90 @@ +""" +There used to be a limitation if using one HTTPRoute declaring the same hostname as parent Gateway related to RLP. +https://github.com/Kuadrant/kuadrant-operator/blob/3b8e313d552090c52d8aadca95f6952f42a03192/doc/rate-limiting.md#limitation-multiple-network-resources-with-identical-hostnames +(second topology mentioned there) +This test validates that it has been properly fixed, i.e. both RateLimitPolicies (RLPs) are successfully enforced. +""" + +from time import sleep +import pytest + +from testsuite.kuadrant.policy import has_condition +from testsuite.kuadrant.policy.rate_limit import RateLimitPolicy, Limit + +pytestmark = [pytest.mark.kuadrant_only] + +LIMIT = Limit(2, "10s") + + +@pytest.fixture(scope="module") +def rate_limit2(gateway, blame, cluster, label): + """2nd RateLimitPolicy object allowing 2 requests per 10 seconds (a.k.a. '2rp10s')""" + rlp = RateLimitPolicy.create_instance(cluster, blame("2rp10s"), gateway, labels={"testRun": label}) + rlp.add_limit("2rp10s", [LIMIT]) + return rlp + + +@pytest.fixture(scope="module", autouse=True) +def commit(request, rate_limit, rate_limit2): + """Ensure RLPs are created""" + for rlp in [rate_limit, rate_limit2]: + if rlp is not None: + request.addfinalizer(rlp.delete) + rlp.commit() + rlp.wait_for_accepted() + + rate_limit.wait_for_ready() + + # At this point the 'route2' has not been created yet so rate_limit2 is completely overridden by rate_limit + assert rate_limit2.wait_until( + has_condition("Enforced", "False", "Overridden") + ), f"'2pr10s' RLP did not reach expected record status, instead it was: {rate_limit2.model.status.condition}" + + +def test_identical_hostnames_rlp_on_gw_and_route(client, rate_limit, rate_limit2): + """ + Tests that Gateway-attached RateLimitPolicy is enforced on 'route2' if both 'route' and 'route2' declare + identical hostname and there is another RateLimitPolicy already successfully enforced on 'route'. + Setup: + - Two HTTPRoutes declaring identical hostnames but different paths: '/anything/route1' and '/anything/route2' + - '1rp10s' RateLimitPolicy enforced on the '/anything/route1' HTTPRoute + - '2rp10s' RateLimitPolicy (created after '1pr10s' RateLimitPolicy) enforced on the Gateway + Test: + - Send requests via 'route' and assert that 429 is returned after one 200 OK + - Send a request via 'route2' and assert that 429 is returned after two 200s + - Delete the '1rp10s' RateLimitPolicy + - Send a request via both routes + - Assert that on both routes the 429s are returned after two 200s + """ + # At this point route2 exists so the '2rp10s' RLP should not be overridden, should be partially enforced instead + rate_limit2.wait_for_partial_enforced() + + # Access via 'route' is limited due to '1rp10s' RateLimitPolicy + response = client.get("/anything/route1/get") + assert response.status_code == 200 + response = client.get("/anything/route1/get") + assert response.status_code == 429 + + # Access via 'route2' is limited due to '2rp10s' Gateway RateLimitPolicy + responses = client.get_many("/anything/route2/get", LIMIT.limit) + responses.assert_all(status_code=200) + response = client.get("/anything/route2/get") + assert response.status_code == 429 + + # Deletion of '1rp10s' RateLimitPolicy should make both routes rate-limited by '2pr10s' RLP. + # '2pr10s' RLP should get fully enforced (was: partially enforced) + rate_limit.delete() + rate_limit2.wait_for_ready() + + # Wait for 15 seconds to make sure counter is reset + sleep(15) + + responses = client.get_many("/anything/route1/get", LIMIT.limit) + responses.assert_all(status_code=200) + response = client.get("/anything/route1/get") + assert response.status_code == 429 + + responses = client.get_many("/anything/route2/get", LIMIT.limit) + responses.assert_all(status_code=200) + response = client.get("/anything/route2/get") + assert response.status_code == 429 diff --git a/testsuite/tests/singlecluster/identical_hostnames/rlp/test_identical_hostnames_rlp_on_routes.py b/testsuite/tests/singlecluster/identical_hostnames/rlp/test_identical_hostnames_rlp_on_routes.py new file mode 100644 index 00000000..ed2349df --- /dev/null +++ b/testsuite/tests/singlecluster/identical_hostnames/rlp/test_identical_hostnames_rlp_on_routes.py @@ -0,0 +1,79 @@ +""" +There used to be a limitation if using one HTTPRoute declaring the same hostname as parent Gateway related to RLP. +https://github.com/Kuadrant/kuadrant-operator/blob/3b8e313d552090c52d8aadca95f6952f42a03192/doc/rate-limiting.md#limitation-multiple-network-resources-with-identical-hostnames +(the first topology mentioned there) +This test validates that it has been properly fixed, i.e. both RateLimitPolicies (RLPs) are successfully enforced. +""" + +from time import sleep +import pytest + +from testsuite.kuadrant.policy.rate_limit import RateLimitPolicy, Limit + + +pytestmark = [pytest.mark.kuadrant_only] + +LIMIT = Limit(2, "10s") + + +@pytest.fixture(scope="module") +def rate_limit2(route2, blame, cluster, label): + """2nd RateLimitPolicy allowing 2 requests per 10 seconds (a.k.a. '2rp10s' RateLimitPolicy)""" + rlp = RateLimitPolicy.create_instance(cluster, blame("2rp10s"), route2, labels={"testRun": label}) + rlp.add_limit("2rp10m", [LIMIT]) + return rlp + + +@pytest.fixture(scope="module", autouse=True) +def commit(request, rate_limit, rate_limit2): + """Ensure Authorizations are created""" + for rlp in [rate_limit, rate_limit2]: + if rlp is not None: + request.addfinalizer(rlp.delete) + rlp.commit() + rlp.wait_for_ready() + + +def test_identical_hostnames_rlp_on_routes(client, rate_limit2): + """ + Validates that 1st RateLimitPolicy is still enforced on 'route' declaring identical hostname as 'route2' if another + RateLimitPolicy got successfully enforced on 'route2' in the interim. + Setup: + - Two HTTPRoutes declaring identical hostnames but different paths: '/anything/route1' and '/anything/route2' + - '1rp10m' RateLimitPolicy enforced on the '/anything/route1' HTTPRoute + - '2rp10m' RateLimitPolicy (created after '1rp10s' RateLimitPolicy) enforced on the '/anything/route2' HTTPRoute + Test: + - Send a request via 'route' and assert that no 429s (Too Many Requests) are returned + - Send a request via 'route2' and assert that no 429s (Too Many Requests) are returned + - Delete the '2rp10s' RateLimitPolicy + - Send a request via both routes + - Assert that 429 is returned after single 200 (OK) for route1 + - Assert that there are no 429s for 'route2' + """ + # Access via 'route' is limited due to '1rp10s' RateLimitPolicy + # despite it reporting being successfully enforced + response = client.get("/anything/route1/get") + assert response.status_code == 200 + response = client.get("/anything/route1/get") + assert response.status_code == 429 + + # Access via 'route2' is limited due to '2rp10s' RateLimitPolicy + responses = client.get_many("/anything/route2/get", LIMIT.limit) + responses.assert_all(status_code=200) + response = client.get("/anything/route2/get") + assert response.status_code == 429 + + # Deletion of '2rp10m' RateLimitPolicy + rate_limit2.delete() + + # Access via 'route' should now be still limited via '1rp10s' RateLimitPolicy + # Wait for 15s to make sure the counter is reset + sleep(15) + response = client.get("/anything/route1/get") + assert response.status_code == 200 + response = client.get("/anything/route1/get") + assert response.status_code == 429 + + # Access via 'route2' is now not limited at all + responses = client.get_many("/anything/route2/get", LIMIT.limit + 1) + responses.assert_all(status_code=200) diff --git a/testsuite/tests/singlecluster/identical_hostnames/test_identical_hostnames_auth_on_gw_and_route.py b/testsuite/tests/singlecluster/identical_hostnames/test_identical_hostnames_auth_on_gw_and_route.py deleted file mode 100644 index 68035245..00000000 --- a/testsuite/tests/singlecluster/identical_hostnames/test_identical_hostnames_auth_on_gw_and_route.py +++ /dev/null @@ -1,61 +0,0 @@ -""" -Tests behavior of using one HTTPRoute declaring the same hostname as parent Gateway related to AuthPolicy. -https://github.com/Kuadrant/kuadrant-operator/blob/main/doc/auth.md#limitation-multiple-network-resources-with-identical-hostnames -(second topology mentioned there) -""" - -import pytest - -from testsuite.kuadrant.policy.authorization.auth_policy import AuthPolicy - -pytestmark = [pytest.mark.kuadrant_only] - - -@pytest.fixture(scope="class", autouse=True) -def authorization2(request, gateway, blame, cluster, label): - """2nd Authorization object""" - auth_policy = AuthPolicy.create_instance(cluster, blame("authz2"), gateway, labels={"testRun": label}) - auth_policy.authorization.add_opa_policy("rego", "allow = false") - request.addfinalizer(auth_policy.delete) - auth_policy.commit() - auth_policy.wait_for_ready() - return auth_policy - - -def test_identical_hostnames_auth_on_gw_and_route_ignored(client, authorization, hostname): - """ - Tests that Gateway-attached AuthPolicy is ignored on 'route2' if both 'route' and 'route2' declare - identical hostname and there is another AuthPolicy already successfully enforced on 'route'. - Setup: - - Two HTTPRoutes declaring identical hostnames but different paths: '/anything/route1' and '/anything/route2' - - Empty AuthPolicy enforced on the '/anything/route1' HTTPRoute - - 'deny-all' AuthPolicy (created after Empty AuthPolicy) enforced on the Gateway - Test: - - Send a request via 'route' and assert that response status code is 200 - - Send a request via 'route2' and assert that response status code is 200 - - Delete the Empty AuthPolicy - - Send a request via both routes - - Assert that both response status codes are 403 (Forbidden) - """ - - # Verify that the Empty AuthPolicy is still enforced despite 'deny-all' AuthPolicy being enforced too now - authorization.wait_for_ready() - - # Access via 'route' is allowed due to Empty AuthPolicy - response = client.get("/anything/route1/get") - assert response.status_code == 200 - - # Despite 'deny-all' Gateway AuthPolicy reporting being successfully enforced - # it is still allowed to access the resources via 'route2' - response = client.get("/anything/route2/get") - assert response.status_code == 200 - - # Deletion of Empty AuthPolicy should make the 'deny-all' Gateway AuthPolicy effectively enforced on both routes. - # It might take some time hence the use of retry client. - authorization.delete() - with hostname.client(retry_codes={200}) as retry_client: - response = retry_client.get("/anything/route1/get") - assert response.status_code == 403 - - response = client.get("/anything/route2/get") - assert response.status_code == 403 diff --git a/testsuite/tests/singlecluster/identical_hostnames/test_identical_hostnames_auth_on_gw_and_route_desired.py b/testsuite/tests/singlecluster/identical_hostnames/test_identical_hostnames_auth_on_gw_and_route_desired.py deleted file mode 100644 index cbda1bd8..00000000 --- a/testsuite/tests/singlecluster/identical_hostnames/test_identical_hostnames_auth_on_gw_and_route_desired.py +++ /dev/null @@ -1,53 +0,0 @@ -""" -Tests desired behavior of using one HTTPRoute declaring the same hostname as parent Gateway related to AuthPolicy. -https://github.com/Kuadrant/kuadrant-operator/blob/main/doc/auth.md#limitation-multiple-network-resources-with-identical-hostnames -(see second topology mentioned there). This test should start passing once the policy-2 affects the route-b which is -considered to be desired behavior. -""" - -import pytest - -from testsuite.kuadrant.policy.authorization.auth_policy import AuthPolicy - -pytestmark = [pytest.mark.kuadrant_only] - - -@pytest.fixture(scope="class", autouse=True) -def authorization2(request, gateway, blame, openshift, label): - """2nd 'deny-all' Authorization object""" - auth_policy = AuthPolicy.create_instance(openshift, blame("authz2"), gateway, labels={"testRun": label}) - auth_policy.authorization.add_opa_policy("rego", "allow = false") - request.addfinalizer(auth_policy.delete) - auth_policy.commit() - auth_policy.wait_for_ready() - return auth_policy - - -@pytest.mark.issue("https://github.com/Kuadrant/kuadrant-operator/issues/431") -@pytest.mark.xfail( - reason="Currently the Gateway-attached Policy is ignored so 200 (OK) is returned instead of 403 (Forbidden)" -) -def test_identical_hostnames_auth_on_gw_and_route_enforced(client, authorization): - """ - Tests that Gateway-attached AuthPolicy is successfully enforced on 'route2' even if both 'route' and 'route2' - declare identical hostname and there is another AuthPolicy already successfully enforced on 'route'. - Setup: - - Two HTTPRoutes declaring identical hostnames but different paths: '/anything/route1' and '/anything/route2' - - Empty AuthPolicy enforced on the '/anything/route1' HTTPRoute - - 'deny-all' AuthPolicy (created after Empty AuthPolicy) enforced on the Gateway - Test: - - Send a request via 'route' and assert that response status code is 200 - - Send a request via 'route2' and assert that response status code is 403 (it is expected to fail) - """ - - # Verify that the Empty AuthPolicy is still enforced despite 'deny-all' AuthPolicy being enforced too now - authorization.wait_for_ready() - - # Access via 'route' is allowed due to Empty AuthPolicy - response = client.get("/anything/route1/get") - assert response.status_code == 200 - - # Access via 'route2' should be forbidden due to 'deny-all' Gateway-attached AuthPolicy - # However, this is currently expected to fail - response = client.get("/anything/route2/get") - assert response.status_code == 403 diff --git a/testsuite/tests/singlecluster/identical_hostnames/test_identical_hostnames_auth_on_routes.py b/testsuite/tests/singlecluster/identical_hostnames/test_identical_hostnames_auth_on_routes.py deleted file mode 100644 index 739ba511..00000000 --- a/testsuite/tests/singlecluster/identical_hostnames/test_identical_hostnames_auth_on_routes.py +++ /dev/null @@ -1,79 +0,0 @@ -""" -Tests behavior of using two HTTPRoutes declaring the same hostname related to AuthPolicy. -https://github.com/Kuadrant/kuadrant-operator/blob/main/doc/auth.md#limitation-multiple-network-resources-with-identical-hostnames -(the first topology mentioned there) -""" - -import pytest - -from testsuite.kuadrant.policy import has_condition -from testsuite.kuadrant.policy.authorization.auth_policy import AuthPolicy - -pytestmark = [pytest.mark.kuadrant_only] - - -@pytest.fixture(scope="class") -def authorization2(request, route2, blame, cluster, label): - """2nd Authorization object""" - auth_policy = AuthPolicy.create_instance(cluster, blame("authz2"), route2, labels={"testRun": label}) - auth_policy.authorization.add_opa_policy("rego", "allow = false") - request.addfinalizer(auth_policy.delete) - auth_policy.commit() - auth_policy.wait_for_accepted() - return auth_policy - - -def test_identical_hostnames_auth_on_routes_rejected(client, authorization, authorization2): - """ - Tests that 2nd AuthPolicy is rejected on 'route2' declaring identical hostname as 'route' with another - AuthPolicy already successfully enforced on 'route'. - Setup: - - Two HTTPRoutes declaring identical hostnames but different paths: '/anything/route1' and '/anything/route2' - - Empty AuthPolicy enforced on the '/anything/route1' HTTPRoute - - 'deny-all' AuthPolicy (created after Empty AuthPolicy) accepted on the '/anything/route2' HTTPRoute - Test: - - Assert that 'deny-all' AuthPolicy reports an error - - Send a request via 'route' and assert that response status code is 200 - - Send a request via 'route2' and assert that response status code is 200 - - Delete the Empty AuthPolicy - - Change 'deny-all' AuthPolicy to trigger its reconciliation - - Send a request via both routes - - Assert that access via 'route' is 200 (OK) - - Assert that access via 'route2 is 403 (Forbidden) - """ - assert authorization2.wait_until( - has_condition( - "Enforced", - "False", - "Unknown", - "AuthPolicy has encountered some issues: AuthScheme is not ready yet", - ), - timelimit=20, - ), ( - f"AuthPolicy did not reach expected status (Enforced False), " - f"instead it was: {authorization2.refresh().model.status.conditions}" - ) - - response = client.get("/anything/route1/get") - assert response.status_code == 200 - - response = client.get("/anything/route2/get") - assert response.status_code == 200 - - # Deletion of Empty AuthPolicy should allow for 'deny-all' AuthPolicy to be enforced successfully. - authorization.delete() - - # 2nd AuthPolicy only recovers from the "AuthScheme is not ready yet" error if reconciliation is explicitly - # triggered, e.g. by changing the AuthPolicy CR content (changing AllValues to True in this particular case) - # Reported as bug https://github.com/Kuadrant/kuadrant-operator/issues/702 - authorization2.authorization.add_opa_policy("rego", "allow = false", True) - authorization2.refresh() - authorization2.wait_for_ready() - - # Access via 'route' is still allowed - response = client.get("/anything/route1/get") - assert response.status_code == 200 - - # Access via 'route2' is now not allowed due to 'deny-all' AuthPolicy being enforced on 'route2' - response = client.get("/anything/route2/get") - assert response.status_code == 403 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 deleted file mode 100644 index 55b734e3..00000000 --- a/testsuite/tests/singlecluster/identical_hostnames/test_identical_hostnames_on_routes_desired.py +++ /dev/null @@ -1,93 +0,0 @@ -""" -Tests desired behavior of using two HTTPRoutes declaring the same hostname using both AuthPolicy and RateLimitPolicy. -https://github.com/Kuadrant/kuadrant-operator/blob/main/doc/auth.md#limitation-multiple-network-resources-with-identical-hostnames -https://github.com/Kuadrant/kuadrant-operator/blob/main/doc/rate-limiting.md#limitation-multiple-network-resources-with-identical-hostnames -(see the first topology mentioned in both links). -For AuthPolicy, the test should start passing once the policy-2 is enforced on route-b -For RateLimitPolicy (RLP) the test should start passing once the policy-1 is effectively enforced on route-a -""" - -import pytest - -from testsuite.kuadrant.policy.authorization.auth_policy import AuthPolicy -from testsuite.kuadrant.policy.rate_limit import Limit, RateLimitPolicy - -pytestmark = [pytest.mark.kuadrant_only] - - -@pytest.fixture(scope="class") -def authorization2(request, route2, blame, openshift, label): - """2nd Authorization object""" - auth_policy = AuthPolicy.create_instance(openshift, blame("authz2"), route2, labels={"testRun": label}) - auth_policy.authorization.add_opa_policy("rego", "allow = false") - request.addfinalizer(auth_policy.delete) - auth_policy.commit() - auth_policy.wait_for_accepted() - return auth_policy - - -@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, "10s")]) - return rate_limit - - -@pytest.fixture(scope="class", autouse=True) -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, "10s")]) - rlp.commit() - rlp.wait_for_ready() - return rlp - - -@pytest.mark.issue("https://github.com/Kuadrant/kuadrant-operator/issues/431") -@pytest.mark.xfail(reason="Currently the 2nd AuthPolicy fails with: AuthScheme is not ready yet, see issue 431, Tier2") -def test_identical_hostnames_auth_on_routes_enforced(client, authorization2): - """ - Tests that 2nd AuthPolicy is enforced on 'route2' declaring identical hostname as 'route' with another - AuthPolicy already successfully enforced on 'route'. - Setup: - - Two HTTPRoutes declaring identical hostnames but different paths: '/anything/route1' and '/anything/route2' - - Empty AuthPolicy enforced on the '/anything/route1' HTTPRoute - - 2nd 'deny-all' AuthPolicy (created after Empty AuthPolicy) accepted on the '/anything/route2' HTTPRoute - Test: - - Assert that 'deny-all' AuthPolicy is enforced (expected to fail) - """ - - # 2nd 'deny-all' AuthPolicy should be enforced, this is expected to fail currently - assert authorization2.wait_for_ready() - - # Access via route2 should be forbidden due to enforced 'deny-all' AuthPolicy, this is expected to fail currently - response = client.get("/anything/route2/get") - assert response.status_code == 403 - - -@pytest.mark.issue("https://github.com/Kuadrant/kuadrant-operator/issues/431") -@pytest.mark.xfail(reason="2nd RLP wins currently whereas 1st RLP should win to be consistent with AuthPolicy behavior") -def test_identical_hostnames_rlp_on_routes_1st_wins(client, rate_limit): - """ - Tests that 1st RateLimitPolicy stays enforced on 'route' declaring identical hostname as 'route2' when another - RateLimitPolicy gets successfully enforced on 'route2'. - Setup: - - Two HTTPRoutes declaring identical hostnames but different paths: '/anything/route1' and '/anything/route2' - - '1rp10m' RateLimitPolicy enforced on the '/anything/route1' HTTPRoute - - '2rp10m' RateLimitPolicy (created after '1rp10m' RateLimitPolicy) enforced on the '/anything/route2' HTTPRoute - Test: - - Assert that 1st '1rp10m' RateLimitPolicy is enforced - - Send a request via 'route' and assert that 429s (Too Many Requests) are returned (this is expected to fail) - """ - - # Verify that the '1rp10m' RLP is still enforced despite '2rp10m' RLP being enforced too now - rate_limit.wait_for_ready() - - # Access via 'route1' is limited by 1st '1rp10m' RLP hence the first request is 200 (OK) - response = client.get("/anything/route1/get") - assert response.status_code == 200 - - # This is currently expected to fail because 1st '1rp10m' RLP is actually not enforced despite its status saying so - response = client.get("/anything/route1/get") - assert response.status_code == 429 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 deleted file mode 100644 index e8f05761..00000000 --- a/testsuite/tests/singlecluster/identical_hostnames/test_identical_hostnames_rlp_on_gw_and_route.py +++ /dev/null @@ -1,62 +0,0 @@ -""" -Tests behavior of using one HTTPRoute declaring the same hostname as parent Gateway related to RateLimitPolicy. -https://github.com/Kuadrant/kuadrant-operator/blob/main/doc/rate-limiting.md#limitation-multiple-network-resources-with-identical-hostnames -(second topology mentioned there) -""" - -import pytest - -from testsuite.kuadrant.policy.rate_limit import RateLimitPolicy, Limit - -pytestmark = [pytest.mark.kuadrant_only] - - -@pytest.fixture(scope="class") -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, "600s")]) - rlp.commit() - rlp.wait_for_partial_enforced() - return rlp - - -def test_identical_hostnames_rlp_on_gw_and_route_ignored(client, rate_limit, rate_limit2): - """ - Tests that Gateway-attached RateLimitPolicy is ignored on 'route2' if both 'route' and 'route2' declare - identical hostname and there is another RateLimitPolicy already successfully enforced on 'route'. - Setup: - - Two HTTPRoutes declaring identical hostnames but different paths: '/anything/route1' and '/anything/route2' - - Empty RateLimitPolicy enforced on the '/anything/route1' HTTPRoute - - '1rp10m' RateLimitPolicy (created after Empty RateLimitPolicy) enforced on the Gateway - Test: - - Send a request via 'route' and assert that no 429s (Too Many Requests) are returned - - Send a request via 'route2' and assert that no 429s (Too Many Requests)are returned - - Delete the Empty RateLimitPolicy - - Send a request via both routes - - Assert that on both routes the 429s are returned after single 200 (OK) - """ - - # Verify that the Empty RLP is still enforced despite '1rp10m' RLP being partially enforced now - rate_limit.wait_for_ready() - - # Access via 'route' is not limited due to Empty RateLimitPolicy - responses = client.get_many("/anything/route1/get", 2) - responses.assert_all(status_code=200) - - # Access via 'route2' is limited due to '1rp10m' Gateway RateLimitPolicy (it is partially enforced) - response = client.get("/anything/route2/get") - assert response.status_code == 200 - responses = client.get_many("/anything/route2/get", 2) - responses.assert_all(status_code=429) - - # Deletion of Empty RateLimitPolicy should make the '1rp10m' Gateway RateLimitPolicy fully enforced on both routes - rate_limit.delete() - rate_limit2.wait_for_ready() - - response = client.get("/anything/route1/get") - assert response.status_code == 429 - - response = client.get("/anything/route2/get") - assert response.status_code == 429 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 deleted file mode 100644 index bd922867..00000000 --- a/testsuite/tests/singlecluster/identical_hostnames/test_identical_hostnames_rlp_on_routes.py +++ /dev/null @@ -1,78 +0,0 @@ -""" -Tests behavior of using one HTTPRoute declaring the same hostname as parent Gateway related to RateLimitPolicy. -https://github.com/Kuadrant/kuadrant-operator/blob/main/doc/rate-limiting.md#limitation-multiple-network-resources-with-identical-hostnames -(the first topology mentioned there) -""" - -import pytest - -from testsuite.kuadrant.policy.rate_limit import RateLimitPolicy, Limit - -pytestmark = [pytest.mark.kuadrant_only] - - -@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, "10s")]) - return rate_limit - - -@pytest.fixture(scope="class") -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, "10s")]) - rlp.commit() - rlp.wait_for_ready() - return rlp - - -def test_identical_hostnames_rlp_on_routes_ignored(client, rate_limit, rate_limit2, hostname): - """ - Tests that 1st RateLimitPolicy gets ignored on 'route' declaring identical hostname as 'route2' when another - RateLimitPolicy gets successfully enforced on 'route2'. - Setup: - - Two HTTPRoutes declaring identical hostnames but different paths: '/anything/route1' and '/anything/route2' - - '1rp10m' RateLimitPolicy enforced on the '/anything/route1' HTTPRoute - - '2rp10m' RateLimitPolicy (created after '1rp10m' RateLimitPolicy) enforced on the '/anything/route2' HTTPRoute - Test: - - Send a request via 'route' and assert that no 429s (Too Many Requests) are returned - - Send a request via 'route2' and assert that no 429s (Too Many Requests) are returned - - Delete the Empty RateLimitPolicy - - Send a request via both routes - - Assert that on both routes the 429s are returned after single 200 (OK) - """ - - # Verify that the '1rp10m' RLP is still enforced despite '2rp10m' RLP being enforced too now - rate_limit.wait_for_ready() - - # Access via 'route' is not limited at all because '1rp10m' RateLimitPolicy is ignored - # despite it reporting being successfully enforced - responses = client.get_many("/anything/route1/get", 3) - responses.assert_all(status_code=200) - - # Access via 'route2' is limited due to '2rp10m' RateLimitPolicy - responses = client.get_many("/anything/route2/get", 2) - responses.assert_all(status_code=200) - # There might be more than two 200 OKs responses, might be due to '2rp10m' enforcement still being in progres - with hostname.client(retry_codes={200}) as retry_client: - response = retry_client.get("/anything/route2/get") - assert response.status_code == 429 - - # Deletion of '2rp10m' RateLimitPolicy should make '1rp10m' RateLimitPolicy effectively enforced. - rate_limit2.delete() - rate_limit.wait_for_ready() - - # Access via 'route' should now be limited via '1rp10m' RateLimitPolicy - response = client.get("/anything/route1/get") - assert response.status_code == 200 - # There might be more than two 200 OKs responses, might be due to '1rp10m' enforcement still being in progres - with hostname.client(retry_codes={200}) as retry_client: - response = retry_client.get("/anything/route1/get") - assert response.status_code == 429 - - # Access via 'route2' is now not limited at all - responses = client.get_many("/anything/route2/get", 3) - responses.assert_all(status_code=200) From 430cc7a3140647e6edc0626b4aac546814a7be1e Mon Sep 17 00:00:00 2001 From: Tomas Repel Date: Mon, 25 Nov 2024 14:02:43 +0100 Subject: [PATCH 2/2] Removed redundant RLP removal, rename of test files Signed-off-by: Tomas Repel --- .../singlecluster/identical_hostnames/auth/conftest.py | 8 -------- ...th_on_gw_and_route.py => test_auth_on_gw_and_route.py} | 0 ...hostnames_auth_on_routes.py => test_auth_on_routes.py} | 0 ...rlp_on_gw_and_route.py => test_rlp_on_gw_and_route.py} | 0 ...l_hostnames_rlp_on_routes.py => test_rlp_on_routes.py} | 0 5 files changed, 8 deletions(-) rename testsuite/tests/singlecluster/identical_hostnames/auth/{test_identical_hostnames_auth_on_gw_and_route.py => test_auth_on_gw_and_route.py} (100%) rename testsuite/tests/singlecluster/identical_hostnames/auth/{test_identical_hostnames_auth_on_routes.py => test_auth_on_routes.py} (100%) rename testsuite/tests/singlecluster/identical_hostnames/rlp/{test_identical_hostnames_rlp_on_gw_and_route.py => test_rlp_on_gw_and_route.py} (100%) rename testsuite/tests/singlecluster/identical_hostnames/rlp/{test_identical_hostnames_rlp_on_routes.py => test_rlp_on_routes.py} (100%) diff --git a/testsuite/tests/singlecluster/identical_hostnames/auth/conftest.py b/testsuite/tests/singlecluster/identical_hostnames/auth/conftest.py index b7f84fb2..a59ea64f 100644 --- a/testsuite/tests/singlecluster/identical_hostnames/auth/conftest.py +++ b/testsuite/tests/singlecluster/identical_hostnames/auth/conftest.py @@ -8,11 +8,3 @@ def authorization(authorization): """1st 'allow-all' Authorization object""" authorization.authorization.add_opa_policy("rego", "allow = true") return authorization - - -@pytest.fixture(scope="module") -def rate_limit(): - """ - For these tests RateLimitPolicy is not required - """ - return None diff --git a/testsuite/tests/singlecluster/identical_hostnames/auth/test_identical_hostnames_auth_on_gw_and_route.py b/testsuite/tests/singlecluster/identical_hostnames/auth/test_auth_on_gw_and_route.py similarity index 100% rename from testsuite/tests/singlecluster/identical_hostnames/auth/test_identical_hostnames_auth_on_gw_and_route.py rename to testsuite/tests/singlecluster/identical_hostnames/auth/test_auth_on_gw_and_route.py diff --git a/testsuite/tests/singlecluster/identical_hostnames/auth/test_identical_hostnames_auth_on_routes.py b/testsuite/tests/singlecluster/identical_hostnames/auth/test_auth_on_routes.py similarity index 100% rename from testsuite/tests/singlecluster/identical_hostnames/auth/test_identical_hostnames_auth_on_routes.py rename to testsuite/tests/singlecluster/identical_hostnames/auth/test_auth_on_routes.py diff --git a/testsuite/tests/singlecluster/identical_hostnames/rlp/test_identical_hostnames_rlp_on_gw_and_route.py b/testsuite/tests/singlecluster/identical_hostnames/rlp/test_rlp_on_gw_and_route.py similarity index 100% rename from testsuite/tests/singlecluster/identical_hostnames/rlp/test_identical_hostnames_rlp_on_gw_and_route.py rename to testsuite/tests/singlecluster/identical_hostnames/rlp/test_rlp_on_gw_and_route.py diff --git a/testsuite/tests/singlecluster/identical_hostnames/rlp/test_identical_hostnames_rlp_on_routes.py b/testsuite/tests/singlecluster/identical_hostnames/rlp/test_rlp_on_routes.py similarity index 100% rename from testsuite/tests/singlecluster/identical_hostnames/rlp/test_identical_hostnames_rlp_on_routes.py rename to testsuite/tests/singlecluster/identical_hostnames/rlp/test_rlp_on_routes.py