Skip to content

Commit a087bdb

Browse files
committed
test: update API key authorization tests
Signed-off-by: Swati Mukund Bagal <[email protected]>
1 parent ee0784a commit a087bdb

File tree

5 files changed

+80
-33
lines changed

5 files changed

+80
-33
lines changed

tests/model_serving/maas_billing/maas_subscription/conftest.py

Lines changed: 12 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@
77
import pytest
88
import requests
99
from kubernetes.dynamic import DynamicClient
10-
from ocp_resources.cluster_role_binding import ClusterRoleBinding
1110
from ocp_resources.data_science_cluster import DataScienceCluster
1211
from ocp_resources.deployment import Deployment
1312
from ocp_resources.llm_inference_service import LLMInferenceService
@@ -38,10 +37,11 @@
3837
from tests.model_serving.maas_billing.utils import build_maas_headers
3938
from utilities.constants import DscComponents
4039
from utilities.general import generate_random_name
41-
from utilities.infra import create_inference_token, create_ns, login_with_user_password
40+
from utilities.infra import create_inference_token, create_ns, get_openshift_token, login_with_user_password
4241
from utilities.llmd_constants import ContainerImages, ModelStorage
4342
from utilities.llmd_utils import create_llmisvc
4443
from utilities.plugins.constant import OpenAIEnpoints
44+
from utilities.resources.auth import Auth
4545

4646
LOGGER = get_logger(name=__name__)
4747

@@ -687,7 +687,7 @@ def free_user_username(
687687
key_id=active_api_key_id,
688688
ocp_user_token=ocp_token_for_actor,
689689
)
690-
LOGGER.info(f"free_user_username: resolved username='{username}' from key id={active_api_key_id}")
690+
LOGGER.info(f"free_user_username: resolved username from key id={active_api_key_id}")
691691
return username
692692

693693

@@ -705,7 +705,7 @@ def admin_username(
705705
key_id=admin_active_api_key_id,
706706
ocp_user_token=admin_ocp_token,
707707
)
708-
LOGGER.info(f"admin_username: resolved username='{username}' from key id={admin_active_api_key_id}")
708+
LOGGER.info(f"admin_username: resolved username from key id={admin_active_api_key_id}")
709709
return username
710710

711711

@@ -726,26 +726,14 @@ def admin_active_api_key_id(
726726

727727
@pytest.fixture(scope="class")
728728
def admin_ocp_token(admin_client: DynamicClient) -> Generator[str, Any, Any]:
729-
"""OCP bearer token for a dedicated SA with cluster-admin ClusterRole, recognised as admin by MaaS API."""
730-
applications_namespace = py_config["applications_namespace"]
731-
sa_name = f"maas-e2e-admin-{generate_random_name()}"
732-
733-
with ServiceAccount(
734-
client=admin_client,
735-
namespace=applications_namespace,
736-
name=sa_name,
737-
teardown=True,
738-
) as sa:
739-
sa.wait(timeout=60)
740-
741-
with ClusterRoleBinding(
742-
client=admin_client,
743-
name=sa_name,
744-
cluster_role="cluster-admin",
745-
subjects=[{"kind": "ServiceAccount", "name": sa_name, "namespace": applications_namespace}],
746-
teardown=True,
747-
):
748-
yield create_inference_token(model_service_account=sa)
729+
"""Temporarily adds dedicated-admins to Auth CR adminGroups so the admin token is recognised by MaaS."""
730+
auth = Auth(client=admin_client, name="auth")
731+
current_groups: list[str] = list(auth.instance.spec.adminGroups or [])
732+
patched_groups = list(set(current_groups + ["dedicated-admins"]))
733+
LOGGER.info(f"admin_ocp_token: patching Auth CR adminGroups to {patched_groups}")
734+
735+
with ResourceEditor(patches={auth: {"spec": {"adminGroups": patched_groups}}}):
736+
yield get_openshift_token(client=admin_client)
749737

750738

751739
@pytest.fixture(scope="function")

tests/model_serving/maas_billing/maas_subscription/test_api_key_authorization.py

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -41,16 +41,14 @@ def test_admin_manage_other_users_keys(
4141
pagination={"limit": 50, "offset": 0},
4242
)
4343
assert list_resp.status_code == 200, (
44-
f"Expected 200 on admin search for username='{free_user_username}', "
45-
f"got {list_resp.status_code}: {list_resp.text[:200]}"
44+
f"Expected 200 on admin search by username, got {list_resp.status_code}: {list_resp.text[:200]}"
4645
)
4746
items: list[dict] = list_body.get("items") or list_body.get("data") or []
4847
key_ids = [item["id"] for item in items]
4948
assert active_api_key_id in key_ids, (
50-
f"Expected free user's key id={active_api_key_id} in admin search results "
51-
f"for username='{free_user_username}', found ids={key_ids}"
49+
f"Expected free user's key id={active_api_key_id} in admin search results, found ids={key_ids}"
5250
)
53-
LOGGER.info(f"[authz] Admin found {len(items)} active key(s) for user='{free_user_username}'")
51+
LOGGER.info(f"[authz] Admin found {len(items)} active key(s) for the free user")
5452

5553
revoke_resp, revoke_body = revoke_api_key(
5654
request_session_http=request_session_http,
@@ -100,7 +98,7 @@ def test_non_admin_cannot_access_other_users_keys(
10098
)
10199
LOGGER.info(f"[authz] Free user correctly received 404 on DELETE of admin's key id={admin_active_api_key_id}")
102100

103-
@pytest.mark.tier1
101+
@pytest.mark.tier2
104102
def test_non_admin_search_only_returns_own_keys(
105103
self,
106104
request_session_http: requests.Session,
@@ -134,7 +132,7 @@ def test_non_admin_search_only_returns_own_keys(
134132
f"[authz] Free user search returned {len(items)} key(s) — own key present, admin's key correctly excluded"
135133
)
136134

137-
@pytest.mark.tier1
135+
@pytest.mark.tier2
138136
def test_non_admin_cannot_search_by_other_username(
139137
self,
140138
request_session_http: requests.Session,
@@ -152,7 +150,11 @@ def test_non_admin_cannot_search_by_other_username(
152150
pagination={"limit": 50, "offset": 0},
153151
)
154152
assert list_resp.status_code == 403, (
155-
f"Expected 403 when free user searches by admin username='{admin_username}', "
153+
f"Expected 403 when free user searches by another user's username, "
156154
f"got {list_resp.status_code}: {list_resp.text[:200]}"
157155
)
156+
<<<<<<< HEAD
158157
LOGGER.info(f"[authz] Free user correctly received 403 when searching by admin username='{admin_username}'")
158+
=======
159+
LOGGER.info("[authz] Free user correctly received 403 when searching by another user's username")
160+
>>>>>>> 626a88d (test: update API key authorization tests)

tests/model_serving/maas_billing/maas_subscription/utils.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -321,12 +321,16 @@ def create_and_yield_api_key_id(
321321
LOGGER.info(f"create_and_yield_api_key_id: created key id={body['id']} name={key_name}")
322322
yield body["id"]
323323
LOGGER.info(f"create_and_yield_api_key_id: teardown revoking key id={body['id']}")
324-
revoke_api_key(
324+
revoke_resp, _ = revoke_api_key(
325325
request_session_http=request_session_http,
326326
base_url=base_url,
327327
key_id=body["id"],
328328
ocp_user_token=ocp_user_token,
329329
)
330+
if revoke_resp.status_code not in (200, 404):
331+
raise AssertionError(
332+
f"Unexpected teardown status for key id={body['id']}: {revoke_resp.status_code} {revoke_resp.text[:200]}"
333+
)
330334

331335

332336
def revoke_api_key(

utilities/constants.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,7 @@ class ApiGroups:
140140
KSERVE: str = "serving.kserve.io"
141141
KUADRANT_IO: str = "kuadrant.io"
142142
MAAS_IO: str = "maas.opendatahub.io"
143+
AUTH_IO: str = "SERVICES_PLATFORM_OPENDATAHUB_IO"
143144

144145

145146
class Annotations:

utilities/resources/auth.py

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
# Generated using https://github.com/RedHatQE/openshift-python-wrapper/blob/main/scripts/resource/README.md
2+
3+
4+
from typing import Any
5+
6+
from ocp_resources.exceptions import MissingRequiredArgumentError
7+
from ocp_resources.resource import Resource
8+
9+
10+
class Auth(Resource):
11+
"""
12+
Auth is the Schema for the auths API
13+
"""
14+
15+
api_group: str = Resource.ApiGroup.SERVICES_PLATFORM_OPENDATAHUB_IO
16+
17+
def __init__(
18+
self,
19+
admin_groups: list[Any] | None = None,
20+
allowed_groups: list[Any] | None = None,
21+
**kwargs: Any,
22+
) -> None:
23+
r"""
24+
Args:
25+
admin_groups (list[Any]): No field description from API
26+
27+
allowed_groups (list[Any]): No field description from API
28+
29+
"""
30+
super().__init__(**kwargs)
31+
32+
self.admin_groups = admin_groups
33+
self.allowed_groups = allowed_groups
34+
35+
def to_dict(self) -> None:
36+
37+
super().to_dict()
38+
39+
if not self.kind_dict and not self.yaml_file:
40+
if self.admin_groups is None:
41+
raise MissingRequiredArgumentError(argument="self.admin_groups")
42+
43+
if self.allowed_groups is None:
44+
raise MissingRequiredArgumentError(argument="self.allowed_groups")
45+
46+
self.res["spec"] = {}
47+
_spec = self.res["spec"]
48+
49+
_spec["adminGroups"] = self.admin_groups
50+
_spec["allowedGroups"] = self.allowed_groups
51+
52+
# End of generated code

0 commit comments

Comments
 (0)