From 82015865cc5e7edbeae153f4a0076d2c8d330872 Mon Sep 17 00:00:00 2001 From: phala Date: Fri, 6 Jan 2023 10:20:31 +0100 Subject: [PATCH] Add support for Kuadrant --- config/settings.local.yaml.tpl | 8 +- config/settings.yaml | 8 +- testsuite/config/__init__.py | 3 +- testsuite/openshift/client.py | 9 +- testsuite/openshift/httpbin.py | 6 +- .../openshift/objects/auth_config/__init__.py | 12 +- .../objects/auth_config/auth_policy.py | 37 +++++ .../openshift/objects/auth_config/sections.py | 11 +- .../openshift/objects/gateway_api/__init__.py | 141 ++++++++++++++++++ testsuite/tests/conftest.py | 40 ++++- .../tests/kuadrant/authorino/conftest.py | 2 +- .../anonymous/test_anonymous_context.py | 2 +- .../authorino/identity/api_key/conftest.py | 6 + .../kuadrant/authorino/metadata/test_uma.py | 6 + .../authorino/multiple_hosts/conftest.py | 6 + .../operator/clusterwide/conftest.py | 9 +- .../kuadrant/authorino/operator/conftest.py | 8 + .../kuadrant/authorino/response/conftest.py | 6 + testsuite/tests/kuadrant/conftest.py | 28 +++- 19 files changed, 322 insertions(+), 26 deletions(-) create mode 100644 testsuite/openshift/objects/auth_config/auth_policy.py create mode 100644 testsuite/openshift/objects/gateway_api/__init__.py create mode 100644 testsuite/tests/kuadrant/authorino/operator/conftest.py diff --git a/config/settings.local.yaml.tpl b/config/settings.local.yaml.tpl index 43343633..d68f7915 100644 --- a/config/settings.local.yaml.tpl +++ b/config/settings.local.yaml.tpl @@ -32,4 +32,10 @@ # deploy: false # If false, the testsuite will use already deployed authorino for testing # url: "" # URL for already deployed Authorino # envoy: -# image: "docker.io/envoyproxy/envoy:v1.23-latest" # Envoy image, the testsuite should use, only for Authorino tests now \ No newline at end of file +# image: "docker.io/envoyproxy/envoy:v1.23-latest" # Envoy image, the testsuite should use, only for Authorino tests now +# kuadrant: +# enabled: true # True, if Testsuite should test Kuadrant instead of individual operators +# namespace: "kuadrant" # Namespaces where Kuadrant resides +# gateway: # Reference to Gateway that should be used +# namespace: "istio-system" +# name: "istio-ingressgateway" \ No newline at end of file diff --git a/config/settings.yaml b/config/settings.yaml index d562b04c..eff755ba 100644 --- a/config/settings.yaml +++ b/config/settings.yaml @@ -13,4 +13,10 @@ default: deploy: true log_level: "debug" envoy: - image: "docker.io/envoyproxy/envoy:v1.23-latest" \ No newline at end of file + image: "docker.io/envoyproxy/envoy:v1.23-latest" + kuadrant: + enabled: true + project: "kuadrant" + gateway: + project: "istio-system" + name: "istio-ingressgateway" \ No newline at end of file diff --git a/testsuite/config/__init__.py b/testsuite/config/__init__.py index 47563a32..cc11de9b 100644 --- a/testsuite/config/__init__.py +++ b/testsuite/config/__init__.py @@ -32,7 +32,8 @@ def __init__(self, name, default, **kwargs) -> None: DefaultValueValidator("rhsso.url", default=fetch_route("no-ssl-sso")), DefaultValueValidator("rhsso.password", default=fetch_secret("credential-sso", "ADMIN_PASSWORD")), DefaultValueValidator("mockserver.url", default=fetch_route("mockserver", force_http=True)), + Validator("kuadrant.enable", must_exist=False, eq=False) | Validator("kuadrant.gateway.name", must_exist=True), ], - validate_only=["authorino"], + validate_only=["authorino", "kuadrant"], loaders=["dynaconf.loaders.env_loader", "testsuite.config.openshift_loader"] ) diff --git a/testsuite/openshift/client.py b/testsuite/openshift/client.py index 9a4f8462..ee101533 100644 --- a/testsuite/openshift/client.py +++ b/testsuite/openshift/client.py @@ -4,6 +4,7 @@ import os from functools import cached_property from typing import Dict, Optional +from urllib.parse import urlparse import openshift as oc from openshift import Context, Selector, OpenShiftPythonException @@ -34,7 +35,7 @@ def __init__(self, project: str, api_url: str = None, token: str = None, kubecon self.token = token self._kubeconfig_path = kubeconfig_path - def change_project(self, project): + def change_project(self, project) -> "OpenShiftClient": """Return new OpenShiftClient with a different project""" return OpenShiftClient(project, self._api_url, self.token, self._kubeconfig_path) @@ -56,6 +57,12 @@ def api_url(self): with self.context: return oc.whoami("--show-server=true") + @cached_property + def apps_url(self): + """Return URL under which all routes are routed""" + hostname = urlparse(self.api_url).hostname + return "apps." + hostname.split(".", 1)[1] + @property def project(self): """Returns real OpenShift project name""" diff --git a/testsuite/openshift/httpbin.py b/testsuite/openshift/httpbin.py index 3d7aa577..4b179cbe 100644 --- a/testsuite/openshift/httpbin.py +++ b/testsuite/openshift/httpbin.py @@ -4,9 +4,10 @@ from testsuite.objects import LifecycleObject from testsuite.openshift.client import OpenShiftClient +from testsuite.openshift.objects.gateway_api import Referencable -class Httpbin(LifecycleObject): +class Httpbin(LifecycleObject, Referencable): """Httpbin deployed in OpenShift through template""" def __init__(self, openshift: OpenShiftClient, name, label) -> None: super().__init__() @@ -19,6 +20,9 @@ def __init__(self, openshift: OpenShiftClient, name, label) -> None: @property def reference(self): return { + "group": "", + "kind": "Service", + "port": 8080, "name": self.name, "namespace": self.openshift.project } diff --git a/testsuite/openshift/objects/auth_config/__init__.py b/testsuite/openshift/objects/auth_config/__init__.py index 19224307..3312e641 100644 --- a/testsuite/openshift/objects/auth_config/__init__.py +++ b/testsuite/openshift/objects/auth_config/__init__.py @@ -13,6 +13,11 @@ class AuthConfig(OpenShiftObject, Authorization): """Represents AuthConfig CR from Authorino""" + @property + def auth_section(self): + """Returns objects where all auth related things should be added""" + return self.model.spec + @cached_property def authorization(self) -> Authorizations: """Gives access to authorization settings""" @@ -34,7 +39,8 @@ def responses(self) -> Responses: return ResponsesSection(self, "response") @classmethod - def create_instance(cls, openshift: OpenShiftClient, name, route: Route, labels: Dict[str, str] = None): + def create_instance(cls, openshift: OpenShiftClient, name, route: Route, + labels: Dict[str, str] = None, hostnames=None): """Creates base instance""" model: Dict = { "apiVersion": "authorino.kuadrant.io/v1beta1", @@ -44,7 +50,7 @@ def create_instance(cls, openshift: OpenShiftClient, name, route: Route, labels: "namespace": openshift.project }, "spec": { - "hosts": route.hostnames + "hosts": hostnames or route.hostnames } } @@ -71,5 +77,5 @@ def remove_all_hosts(self): @modify def set_deny_with(self, code, value): """Set denyWith""" - self.model.spec["denyWith"] = { + self.auth_section["denyWith"] = { "unauthenticated": {"code": code, "headers": [{"name": "Location", "valueFrom": {"authJSON": value}}]}} diff --git a/testsuite/openshift/objects/auth_config/auth_policy.py b/testsuite/openshift/objects/auth_config/auth_policy.py new file mode 100644 index 00000000..09af0ac6 --- /dev/null +++ b/testsuite/openshift/objects/auth_config/auth_policy.py @@ -0,0 +1,37 @@ +"""Module containing classes related to Auth Policy""" +from typing import Dict + +from testsuite.openshift.client import OpenShiftClient +from testsuite.openshift.objects.auth_config import AuthConfig +from testsuite.openshift.objects.gateway_api import Referencable + + +class AuthPolicy(AuthConfig): + """AuthPolicy object, it serves as Kuadrants AuthConfig""" + + @property + def auth_section(self): + return self.model.spec.setdefault("authScheme", {}) + + # pylint: disable=unused-argument + @classmethod + def create_instance(cls, openshift: OpenShiftClient, name, route: Referencable, # type: ignore + labels: Dict[str, str] = None, hostnames=None): + """Creates base instance + """ + model: Dict = { + "apiVersion": "kuadrant.io/v1beta1", + "kind": "AuthPolicy", + "metadata": { + "name": name, + "namespace": openshift.project + }, + "spec": { + "targetRef": route.reference, + } + } + + if labels is not None: + model["metadata"]["labels"] = labels + + return cls(model, context=openshift.context) diff --git a/testsuite/openshift/objects/auth_config/sections.py b/testsuite/openshift/objects/auth_config/sections.py index 7a001684..e7a8ae3d 100644 --- a/testsuite/openshift/objects/auth_config/sections.py +++ b/testsuite/openshift/objects/auth_config/sections.py @@ -1,14 +1,17 @@ """AuthConfig CR object""" from dataclasses import asdict -from typing import Dict, Literal, Iterable +from typing import Dict, Literal, Iterable, TYPE_CHECKING from testsuite.objects import Identities, Metadata, Responses, MatchExpression, Authorizations, Rule, Cache, Value -from testsuite.openshift.objects import OpenShiftObject, modify +from testsuite.openshift.objects import modify + +if TYPE_CHECKING: + from testsuite.openshift.objects.auth_config import AuthConfig class Section: """Common class for all Sections""" - def __init__(self, obj: OpenShiftObject, section_name) -> None: + def __init__(self, obj: "AuthConfig", section_name) -> None: super().__init__() self.obj = obj self.section_name = section_name @@ -27,7 +30,7 @@ def committed(self): @property def section(self): """The actual dict section which will be edited""" - return self.obj.model.spec.setdefault(self.section_name, []) + return self.obj.auth_section.setdefault(self.section_name, []) def add_item(self, name, value, priority: int = None, when: Iterable[Rule] = None, metrics: bool = None, cache: Cache = None): diff --git a/testsuite/openshift/objects/gateway_api/__init__.py b/testsuite/openshift/objects/gateway_api/__init__.py new file mode 100644 index 00000000..e1af05d9 --- /dev/null +++ b/testsuite/openshift/objects/gateway_api/__init__.py @@ -0,0 +1,141 @@ +"""Module containing all Gateway API related classes""" +import typing +from abc import ABC, abstractmethod +from functools import cached_property + +from openshift import Selector + +from testsuite.httpx import HttpxBackoffClient +from testsuite.openshift.client import OpenShiftClient +from testsuite.openshift.objects import OpenShiftObject, modify +from testsuite.openshift.objects.proxy import Proxy +from testsuite.openshift.objects.route import Route +from testsuite.utils import randomize + +if typing.TYPE_CHECKING: + from testsuite.openshift.httpbin import Httpbin + + +class Referencable(ABC): + """Object that can be referenced in Gateway API style""" + @property + @abstractmethod + def reference(self) -> dict[str, str]: + """ + Returns dict, which can be used as reference in Gateway API Objects. + https://gateway-api.sigs.k8s.io/references/spec/#gateway.networking.k8s.io/v1beta1.ParentReference + """ + + +class HTTPRoute(OpenShiftObject, Referencable, Route): + """HTTPRoute object, serves as replacement for Routes and Ingresses""" + + @cached_property + def hostnames(self): + return self.model.spec.hostnames + + @classmethod + def create_instance(cls, openshift: OpenShiftClient, name, parent: Referencable, + hostname, backend: "Httpbin", labels: dict[str, str] = None): + """Creates new instance of HTTPRoute""" + model = { + "apiVersion": "gateway.networking.k8s.io/v1alpha2", + "kind": "HTTPRoute", + "metadata": { + "name": name, + "namespace": openshift.project + }, + "spec": { + "parentRefs": [parent.reference], + "hostnames": [hostname], + "rules": [ + { + # "matches": [ + # { + # "path": { + # "type": "PathPrefix", + # "value": "/" + # }, + # "method": "GET" + # }, + # ], + "backendRefs": [backend.reference] + } + ] + } + } + + if labels is not None: + model["metadata"]["labels"] = labels # type: ignore + + return cls(model, context=openshift.context) + + @property + def reference(self): + return { + "group": "gateway.networking.k8s.io", + "kind": "HTTPRoute", + "name": self.name(), + "namespace": self.namespace() + } + + @modify + def add_hostname(self, hostname): + """Adds hostname to the Route""" + self.model.spec.hostnames.append(hostname) + + +# pylint: disable=too-many-instance-attributes +class Gateway(Referencable, Proxy): + """Gateway object already present on the server""" + + def __init__(self, openshift: OpenShiftClient, name, namespace, label, httpbin: "Httpbin") -> None: + super().__init__() + self.openshift = openshift + self.system_openshift = openshift.change_project(namespace) + self.name = name + self.label = label + self.namespace = namespace + self.httpbin = httpbin + + self._route: HTTPRoute = None # type: ignore + self._selector: Selector = None # type: ignore + + def _expose_route(self, name, service): + return self.system_openshift.routes.expose(name, service, port=8080) + + @cached_property + def route(self) -> HTTPRoute: + return self._route + + def add_hostname(self, name) -> tuple[Route, str]: + route = self._expose_route(name, self.name) + self._selector.union(route.self_selector()) + self.route.add_hostname(route.model.spec.host) + return self.route, route.model.spec.host + + def client(self, **kwargs): + """Return Httpx client for the requests to this backend""" + return HttpxBackoffClient(base_url=f"http://{self.route.hostnames[0]}", **kwargs) + + def commit(self): + name = randomize(self.name) + route = self._expose_route(name, self.name) + self._selector = route.self_selector() + + self._route = HTTPRoute.create_instance(self.openshift, name, self, route.model.spec.host, + self.httpbin, {"app": self.label}) + self._route.commit() + + def delete(self): + self._route.delete() + self._selector.delete() + + @property + def reference(self): + return { + "group": "gateway.networking.k8s.io", + "kind": "Gateway", + "name": self.name, + "namespace": self.namespace + } diff --git a/testsuite/tests/conftest.py b/testsuite/tests/conftest.py index a14e6116..b95c32a9 100644 --- a/testsuite/tests/conftest.py +++ b/testsuite/tests/conftest.py @@ -1,11 +1,10 @@ """Root conftest""" import signal -from urllib.parse import urlparse - import pytest from dynaconf import ValidationError from keycloak import KeycloakAuthenticationError +from weakget import weakget from testsuite.mockserver import Mockserver from testsuite.oidc import OIDCProvider @@ -14,6 +13,8 @@ from testsuite.openshift.httpbin import Httpbin from testsuite.openshift.envoy import Envoy from testsuite.oidc.rhsso import RHSSO +from testsuite.openshift.objects.gateway_api import Gateway +from testsuite.openshift.objects.proxy import Proxy from testsuite.utils import randomize, _whoami @@ -190,6 +191,31 @@ def module_label(label): return randomize(label) +@pytest.fixture(scope="session") +def kuadrant(testconfig, openshift): + """Returns Kuadrant instance if exists, or None""" + settings = weakget(testconfig) + try: + if not settings["kuadrant"]["enabled"] % True: + return None + + # Try if Kuadrant is deployed + kuadrant_openshift = openshift.change_project(settings["kuadrant"]["project"] % None) + kuadrants = kuadrant_openshift.do_action("get", "kuadrant", "-o", "json", parse_output=True) + assert len(kuadrants.model["items"]) > 0 + + # Try if the configured Gateway is deployed + gateway_openshift = openshift.change_project(settings["kuadrant"]["gateway"]["project"] % None) + name = testconfig["kuadrant"]["gateway"]["name"] + gateway_openshift.do_action("get", f"Gateway/{name}") + + # TODO: Return actual Kuadrant object + return True + # pylint: disable=broad-except + except Exception: + return None + + @pytest.fixture(scope="session") def backend(request, openshift, blame, label): """Deploys Httpbin backend""" @@ -200,9 +226,12 @@ def backend(request, openshift, blame, label): @pytest.fixture(scope="module") -def envoy(request, authorino, openshift, blame, backend, module_label, testconfig): +def envoy(request, kuadrant, authorino, openshift, blame, backend, module_label, testconfig) -> Proxy: """Deploys Envoy that wire up the Backend behind the reverse-proxy and Authorino instance""" - envoy = Envoy(openshift, authorino, blame("envoy"), module_label, backend, testconfig["envoy"]["image"]) + if kuadrant: + envoy: Proxy = Gateway(openshift, "istio-ingressgateway", "istio-system", module_label, backend) + else: + envoy = Envoy(openshift, authorino, blame("envoy"), module_label, backend, testconfig["envoy"]["image"]) request.addfinalizer(envoy.delete) envoy.commit() return envoy @@ -213,5 +242,4 @@ def wildcard_domain(openshift): """ Wildcard domain of openshift cluster """ - hostname = urlparse(openshift.api_url).hostname - return "*.apps." + hostname.split(".", 1)[1] + return f"*.{openshift.apps_url}" diff --git a/testsuite/tests/kuadrant/authorino/conftest.py b/testsuite/tests/kuadrant/authorino/conftest.py index 077e1362..d41e6bdc 100644 --- a/testsuite/tests/kuadrant/authorino/conftest.py +++ b/testsuite/tests/kuadrant/authorino/conftest.py @@ -49,7 +49,7 @@ def authorization(authorization, oidc_provider, authorino, envoy, blame, openshi if authorization is None: authorization = AuthConfig.create_instance(openshift, blame("ac"), envoy.route, labels={"testRun": module_label}) - authorization.identity.oidc("rhsso", oidc_provider.well_known["issuer"]) + authorization.identity.oidc("rhsso", oidc_provider.well_known["issuer"]) return authorization diff --git a/testsuite/tests/kuadrant/authorino/identity/anonymous/test_anonymous_context.py b/testsuite/tests/kuadrant/authorino/identity/anonymous/test_anonymous_context.py index 15f30a16..3a291567 100644 --- a/testsuite/tests/kuadrant/authorino/identity/anonymous/test_anonymous_context.py +++ b/testsuite/tests/kuadrant/authorino/identity/anonymous/test_anonymous_context.py @@ -20,5 +20,5 @@ def test_anonymous_context(client): - Assert that response has the right information in context """ response = client.get("/get") - assert json.loads(response.json()["headers"]["Auth-Json"])["auth"] assert response.status_code == 200 + assert json.loads(response.json()["headers"]["Auth-Json"])["auth"] diff --git a/testsuite/tests/kuadrant/authorino/identity/api_key/conftest.py b/testsuite/tests/kuadrant/authorino/identity/api_key/conftest.py index 6b64b712..90d7efed 100644 --- a/testsuite/tests/kuadrant/authorino/identity/api_key/conftest.py +++ b/testsuite/tests/kuadrant/authorino/identity/api_key/conftest.py @@ -4,6 +4,12 @@ from testsuite.httpx.auth import HeaderApiKeyAuth +@pytest.fixture(scope="module") +def run_on_kuadrant(): + """Secrets are not correctly reconciled https://github.com/Kuadrant/kuadrant-operator/issues/127""" + return False + + @pytest.fixture(scope="module") def api_key(create_api_key, module_label): """Creates API key Secret""" diff --git a/testsuite/tests/kuadrant/authorino/metadata/test_uma.py b/testsuite/tests/kuadrant/authorino/metadata/test_uma.py index ee884545..7cf7cc78 100644 --- a/testsuite/tests/kuadrant/authorino/metadata/test_uma.py +++ b/testsuite/tests/kuadrant/authorino/metadata/test_uma.py @@ -27,6 +27,12 @@ """ +@pytest.fixture(scope="module") +def run_on_kuadrant(): + """Secrets are not correctly reconciled https://github.com/Kuadrant/kuadrant-operator/issues/127""" + return False + + @pytest.fixture(scope="module", autouse=True) def client_secret(create_client_secret, rhsso): """Creates a required secret, used by Authorino to start the authentication with the UMA registry.""" diff --git a/testsuite/tests/kuadrant/authorino/multiple_hosts/conftest.py b/testsuite/tests/kuadrant/authorino/multiple_hosts/conftest.py index 41571ade..348d4e87 100644 --- a/testsuite/tests/kuadrant/authorino/multiple_hosts/conftest.py +++ b/testsuite/tests/kuadrant/authorino/multiple_hosts/conftest.py @@ -4,6 +4,12 @@ from testsuite.httpx import HttpxBackoffClient +@pytest.fixture(scope="module") +def run_on_kuadrant(): + """Handling of hosts needs to be rewritten""" + return False + + @pytest.fixture(scope="module") def hostname(envoy): """Original hostname""" diff --git a/testsuite/tests/kuadrant/authorino/operator/clusterwide/conftest.py b/testsuite/tests/kuadrant/authorino/operator/clusterwide/conftest.py index da67a6db..41a44f89 100644 --- a/testsuite/tests/kuadrant/authorino/operator/clusterwide/conftest.py +++ b/testsuite/tests/kuadrant/authorino/operator/clusterwide/conftest.py @@ -13,14 +13,14 @@ def authorino_parameters(): @pytest.fixture(scope="module") def hostname2(envoy, blame): """Second route for the envoy""" - _, hostname = envoy.add_hostname(blame("route")) - return hostname + return envoy.add_hostname(blame("route")) @pytest.fixture(scope="module") def authorization2(hostname2, blame, openshift2, module_label, oidc_provider): """Second valid hostname""" - auth = AuthConfig.create_instance(openshift2, blame("ac"), hostname2, labels={"testRun": module_label}) + route, _ = hostname2 + auth = AuthConfig.create_instance(openshift2, blame("ac"), route, labels={"testRun": module_label}) auth.identity.oidc("rhsso", oidc_provider.well_known["issuer"]) return auth @@ -28,8 +28,9 @@ def authorization2(hostname2, blame, openshift2, module_label, oidc_provider): @pytest.fixture(scope="module") def client2(hostname2, envoy): """Client for second AuthConfig""" + _, hostname = hostname2 client = envoy.client() - client.base_url = f"http://{hostname2}" + client.base_url = f"http://{hostname}" yield client client.close() diff --git a/testsuite/tests/kuadrant/authorino/operator/conftest.py b/testsuite/tests/kuadrant/authorino/operator/conftest.py new file mode 100644 index 00000000..f6b423e1 --- /dev/null +++ b/testsuite/tests/kuadrant/authorino/operator/conftest.py @@ -0,0 +1,8 @@ +"""Module containing common features of all Operator tests""" +import pytest + + +@pytest.fixture(scope="module") +def run_on_kuadrant(): + """Kuadrant doesn't allow customization of Authorino parameters""" + return False diff --git a/testsuite/tests/kuadrant/authorino/response/conftest.py b/testsuite/tests/kuadrant/authorino/response/conftest.py index 8e98adcf..48306fae 100644 --- a/testsuite/tests/kuadrant/authorino/response/conftest.py +++ b/testsuite/tests/kuadrant/authorino/response/conftest.py @@ -4,6 +4,12 @@ from testsuite.openshift.objects.auth_config import AuthConfig +@pytest.fixture(scope="module") +def run_on_kuadrant(): + """Tests needs to be rewritten to not create special AuthConfig""" + return False + + @pytest.fixture(scope="module") def responses(): """Returns responses to be added to the AuthConfig""" diff --git a/testsuite/tests/kuadrant/conftest.py b/testsuite/tests/kuadrant/conftest.py index 79964fdc..a646b23f 100644 --- a/testsuite/tests/kuadrant/conftest.py +++ b/testsuite/tests/kuadrant/conftest.py @@ -2,17 +2,41 @@ all methods are placeholders for now since we do not work with Kuadrant""" import pytest +from testsuite.openshift.objects.auth_config.auth_policy import AuthPolicy + @pytest.fixture(scope="session") -def authorino(): +def run_on_kuadrant(): + """True, if the tests should pass when running on Kuadrant""" + return True + + +@pytest.fixture(scope="module", autouse=True) +def skip_non_kuadrant(kuadrant, run_on_kuadrant): + """Skips all tests that are not working with Kuadrant""" + if kuadrant and not run_on_kuadrant: + pytest.skip("This test doesn't work with Kuadrant") + + +# pylint: disable=unused-argument +@pytest.fixture(scope="module") +def authorino(kuadrant, skip_non_kuadrant): """Authorino instance when configured through Kuadrant""" + if kuadrant: + # No available modification + return True return None # pylint: disable=unused-argument @pytest.fixture(scope="module") -def authorization(authorino, envoy, blame, openshift): +def authorization(authorino, kuadrant, oidc_provider, envoy, blame, openshift, module_label): """Authorization object (In case of Kuadrant AuthPolicy)""" + if kuadrant: + policy = AuthPolicy.create_instance(openshift, + blame("policy"), envoy.route, labels={"testRun": module_label}) + policy.identity.oidc("rhsso", oidc_provider.well_known["issuer"]) + return policy return None