<?xml version="1.0" encoding="utf-8"?><testsuites name="pytest tests"><testsuite name="pytest" errors="1" failures="4" skipped="8" tests="125" time="483.556" timestamp="2026-10-30T20:16:21.787751+00:00" hostname="ai-gateway-controller-group4c2d38156f40a113e61a8c4eccaa1ef9-pod"><testcase classname="tests.test_api_keys.TestAPIKeyCRUD" name="test_list_api_keys" time="86.146" /><testcase classname="tests.test_api_keys.TestAPIKeyBulkOperations" name="test_bulk_revoke_own_keys" time="86.997" /><testcase classname="tests.test_api_keys.TestAPIKeyAuthorization" name="test_admin_manage_other_users_keys" time="86.979" /><testcase classname="tests.test_api_keys.TestAPIKeyBulkOperations" name="test_bulk_revoke_by_subscription" time="13.633" /><testcase classname="tests.test_api_keys.TestAPIKeyBulkOperations" name="test_bulk_revoke_dry_run" time="0.667" /><testcase classname="tests.test_api_keys.TestAPIKeyExpiration" name="test_expiration_policy_boundaries[at-limit]" time="0.115" /><testcase classname="tests.test_api_keys.TestAPIKeyBulkOperations" name="test_bulk_revoke_combined_user_and_subscription" time="13.803" /><testcase classname="tests.test_api_keys.TestAPIKeyExpiration" name="test_expiration_policy_boundaries[without-expiration]" time="0.113" /><testcase classname="tests.test_api_keys.TestAPIKeyExpiration" name="test_expiration_policy_boundaries[short-expiration]" time="0.148" /><testcase classname="tests.test_api_keys.TestAPIKeyModelInference" name="test_api_key_model_access_success" time="0.272" /><testcase classname="tests.test_api_keys.TestAPIKeyModelInference" name="test_invalid_api_key_rejected" time="0.090" /><testcase classname="tests.test_api_keys.TestAPIKeyModelInference" name="test_no_auth_header_rejected" time="0.083" /><testcase classname="tests.test_api_keys.TestAPIKeyModelInference" name="test_revoked_api_key_rejected" time="2.546" /><testcase classname="tests.test_api_keys.TestAPIKeyModelInference" name="test_api_key_chat_completions" time="0.120" /><testcase classname="tests.test_api_keys.TestAPIKeyRevocationE2E" name="test_double_revoke_returns_404" time="0.349" /><testcase classname="tests.test_api_keys.TestAPIKeyRevocationE2E" name="test_revoke_nonexistent_key_returns_404" time="0.138" /><testcase classname="tests.test_api_keys.TestAPIKeyRevocationE2E" name="test_revoke_then_create_new_key_works" time="0.588" /><testcase classname="tests.test_api_keys.TestAPIKeyRevocationE2E" name="test_individual_revoke_multiple_keys" time="0.787" /><testcase classname="tests.test_api_keys.TestAPIKeyRevocationE2E" name="test_revoke_keys_rejected_at_gateway" time="1.358" /><testcase classname="tests.test_api_keys.TestEphemeralKeyCleanup" name="test_cronjob_exists_and_configured" time="0.160" /><testcase classname="tests.test_api_keys.TestEphemeralKeyCleanup" name="test_cleanup_networkpolicy_exists" time="0.152" /><testcase classname="tests.test_api_keys.TestEphemeralKeyCleanup" name="test_create_ephemeral_key" time="1.575" /><testcase classname="tests.test_api_keys.TestEphemeralKeyCleanup" name="test_trigger_cleanup_preserves_active_keys" time="0.291"><skipped type="pytest.skip" message="Cannot find maas-api pod in odh-ai-gateway-infra: error: error executing jsonpath &quot;{.items[0].metadata.name}&quot;: Error executing template: array index out of bounds: index 0, length 0. Printing more information for debugging the template:&#10;&#09;template was:&#10;&#09;&#09;{.items[0].metadata.name}&#10;&#09;object given to jsonpath engine was:&#10;&#09;&#09;map[string]interface {}{&quot;apiVersion&quot;:&quot;v1&quot;, &quot;items&quot;:[]interface {}{}, &quot;kind&quot;:&quot;List&quot;, &quot;metadata&quot;:map[string]interface {}{&quot;resourceVersion&quot;:&quot;&quot;}}">/workspace/source/test/maas-e2e/test/e2e/tests/test_api_keys.py:1429: Cannot find maas-api pod in odh-ai-gateway-infra: error: error executing jsonpath "{.items[0].metadata.name}": Error executing template: array index out of bounds: index 0, length 0. Printing more information for debugging the template:
	template was:
		{.items[0].metadata.name}
	object given to jsonpath engine was:
		map[string]interface {}{"apiVersion":"v1", "items":[]interface {}{}, "kind":"List", "metadata":map[string]interface {}{"resourceVersion":""}}</skipped></testcase><testcase classname="tests.test_api_keys.TestAPIKeySubscriptionPhases" name="test_create_key_for_active_subscription" time="12.208" /><testcase classname="tests.test_api_keys.TestAPIKeyBulkOperations" name="test_bulk_revoke_other_user_forbidden" time="98.340" /><testcase classname="tests.test_api_keys.TestAPIKeyCRUD" name="test_create_api_key" time="98.563" /><testcase classname="tests.test_api_keys.TestAPIKeyCRUD" name="test_revoke_api_key" time="98.781" /><testcase classname="tests.test_api_keys.TestAPIKeyBulkOperations" name="test_bulk_revoke_missing_scope_returns_400" time="0.198" /><testcase classname="tests.test_api_keys.TestAPIKeySubscriptionPhases" name="test_create_key_for_failed_subscription" time="12.306" /><testcase classname="tests.test_api_keys.TestAPIKeyBulkOperations" name="test_bulk_revoke_by_subscription_forbidden_for_non_admin" time="0.135" /><testcase classname="tests.test_api_keys.TestAPIKeyLabels" name="test_create_api_key_with_labels" time="0.285" /><testcase classname="tests.test_api_keys.TestAPIKeyLabels" name="test_search_api_keys_by_labels" time="0.725" /><testcase classname="tests.test_api_keys.TestAPIKeyBulkOperations" name="test_bulk_revoke_admin_can_revoke_any_user" time="1.162" /><testcase classname="tests.test_api_keys.TestAPIKeyAuthorization" name="test_non_admin_cannot_access_other_users_keys" time="99.904" /><testcase classname="tests.test_api_keys.TestAPIKeySubscriptionFilter" name="test_search_without_subscription_returns_all" time="0.798" /><testcase classname="tests.test_api_keys.TestAPIKeyExpiration" name="test_expiration_policy_boundaries[within-limit]" time="0.503" /><testcase classname="tests.test_api_keys.TestAPIKeyBulkOperations" name="test_bulk_revoke_dry_run_by_subscription" time="13.038" /><testcase classname="tests.test_api_keys.TestAPIKeyLabels" name="test_labels_validation_errors" time="0.377" /><testcase classname="tests.test_namespace_scoping.TestMaaSAPIWatchNamespace" name="test_subscription_in_subscription_namespace_visible_to_api" time="0.001"><skipped type="pytest.skip" message="test_namespace_scoping validates single-tenant dormant mode; skipped when ENABLE_TENANT_NAMESPACE_DISCOVERY=true">/workspace/source/test/maas-e2e/test/e2e/tests/test_namespace_scoping.py:214: test_namespace_scoping validates single-tenant dormant mode; skipped when ENABLE_TENANT_NAMESPACE_DISCOVERY=true</skipped></testcase><testcase classname="tests.test_namespace_scoping.TestMaaSControllerWatchNamespace" name="test_authpolicy_and_subscription_in_another_namespace" time="0.000"><skipped type="pytest.skip" message="test_namespace_scoping validates single-tenant dormant mode; skipped when ENABLE_TENANT_NAMESPACE_DISCOVERY=true">/workspace/source/test/maas-e2e/test/e2e/tests/test_namespace_scoping.py:324: test_namespace_scoping validates single-tenant dormant mode; skipped when ENABLE_TENANT_NAMESPACE_DISCOVERY=true</skipped></testcase><testcase classname="tests.test_namespace_scoping.TestModelRef" name="test_auth_policy_model_ref" time="0.000"><skipped type="pytest.skip" message="test_namespace_scoping validates single-tenant dormant mode; skipped when ENABLE_TENANT_NAMESPACE_DISCOVERY=true">/workspace/source/test/maas-e2e/test/e2e/tests/test_namespace_scoping.py:382: test_namespace_scoping validates single-tenant dormant mode; skipped when ENABLE_TENANT_NAMESPACE_DISCOVERY=true</skipped></testcase><testcase classname="tests.test_namespace_scoping.TestModelRef" name="test_subscription_model_ref" time="0.000"><skipped type="pytest.skip" message="test_namespace_scoping validates single-tenant dormant mode; skipped when ENABLE_TENANT_NAMESPACE_DISCOVERY=true">/workspace/source/test/maas-e2e/test/e2e/tests/test_namespace_scoping.py:456: test_namespace_scoping validates single-tenant dormant mode; skipped when ENABLE_TENANT_NAMESPACE_DISCOVERY=true</skipped></testcase><testcase classname="tests.test_negative_security.TestAPIKeyManagementIsolation" name="test_api_key_cannot_mint_another_api_key" time="0.574" /><testcase classname="tests.test_namespace_scoping.TestMaaSControllerWatchNamespace" name="test_authpolicy_and_subscription_in_maas_subscription_namespace" time="0.001"><skipped type="pytest.skip" message="test_namespace_scoping validates single-tenant dormant mode; skipped when ENABLE_TENANT_NAMESPACE_DISCOVERY=true">/workspace/source/test/maas-e2e/test/e2e/tests/test_namespace_scoping.py:287: test_namespace_scoping validates single-tenant dormant mode; skipped when ENABLE_TENANT_NAMESPACE_DISCOVERY=true</skipped></testcase><testcase classname="tests.test_negative_security.TestHeaderSpoofing" name="test_forged_identity_headers_rejected_on_key_mint[group-only]" time="0.892" /><testcase classname="tests.test_api_keys.TestAPIKeyLabels" name="test_backward_compatibility_no_labels" time="0.606" /><testcase classname="tests.test_api_keys.TestAPIKeyExpiration" name="test_expiration_policy_boundaries[exceeds-limit]" time="0.503" /><testcase classname="tests.test_negative_security.TestHeaderSpoofing" name="test_forged_identity_headers_rejected_on_key_mint[username-only]" time="0.871" /><testcase classname="tests.test_negative_security.TestHeaderSpoofing" name="test_forged_identity_headers_rejected_on_key_mint[identity-envelope]" time="0.844" /><testcase classname="tests.test_negative_security.TestHeaderSpoofing" name="test_forged_identity_headers_rejected_on_key_mint[keyname-only]" time="0.875" /><testcase classname="tests.test_negative_security.TestHeaderSpoofing" name="test_forged_identity_headers_rejected_on_key_mint[admin-scope]" time="0.948" /><testcase classname="tests.test_negative_security.TestHeaderSpoofing" name="test_injected_identity_headers_rejected_on_inference" time="0.485" /><testcase classname="tests.test_negative_security.TestHeaderSpoofing" name="test_duplicate_subscription_headers_ignored" time="8.802" /><testcase classname="tests.test_negative_security.TestExpiredKeyRejection" name="test_expired_key_rejected_at_gateway" time="5.428" /><testcase classname="tests.test_negative_security.TestMissingModelRef" name="test_subscription_with_nonexistent_model_ref" time="11.483" /><testcase classname="tests.test_negative_security.TestCrossModelAccess" name="test_key_cannot_access_model_outside_subscription" time="0.458" /><testcase classname="tests.test_negative_security.TestInternalEndpointIsolation" name="test_internal_endpoint_not_routable[api-keys-cleanup]" time="0.238" /><testcase classname="tests.test_negative_security.TestInternalEndpointIsolation" name="test_internal_endpoint_not_routable[api-keys-validate]" time="0.245" /><testcase classname="tests.test_negative_security.TestInternalEndpointIsolation" name="test_health_endpoint_accessible" time="0.075" /><testcase classname="tests.test_negative_security.TestInternalEndpointIsolation" name="test_v1_models_via_maas_api_prefix" time="0.320" /><testcase classname="tests.test_subscription.TestAuthEnforcement" name="test_authorized_user_gets_200" time="0.387" /><testcase classname="tests.test_subscription.TestAuthEnforcement" name="test_no_auth_gets_401" time="0.083" /><testcase classname="tests.test_subscription.TestAuthEnforcement" name="test_invalid_token_gets_403" time="0.102" /><testcase classname="tests.test_subscription.TestAuthEnforcement" name="test_wrong_group_gets_403" time="0.093" /><testcase classname="tests.test_subscription.TestAPIKeySubscriptionBinding" name="test_create_api_key_uses_highest_priority_subscription" time="0.569" /><testcase classname="tests.test_subscription.TestAPIKeySubscriptionBinding" name="test_create_api_key_with_explicit_simulator_subscription" time="0.266" /><testcase classname="tests.test_subscription.TestAPIKeySubscriptionBinding" name="test_create_api_key_nonexistent_subscription_errors" time="10.371" /><testcase classname="tests.test_negative_security.TestHeaderAbuse" name="test_special_characters_in_subscription_header" time="1.146" /><testcase classname="tests.test_subscription.TestOrderingEdgeCases" name="test_subscription_before_auth_policy" time="17.249" /><testcase classname="tests.test_api_keys.TestAPIKeySubscriptionPhases" name="test_create_key_for_degraded_subscription" time="14.610" /><testcase classname="tests.test_negative_security.TestMissingModelRef" name="test_authpolicy_with_nonexistent_model_ref" time="3.096" /><testcase classname="tests.test_api_keys.TestAPIKeySubscriptionFilter" name="test_search_filters_by_subscription" time="24.886" /><testcase classname="tests.test_namespace_scoping.TestMaaSAPIWatchNamespace" name="test_subscription_in_another_namespace_not_visible_to_api" time="0.000"><skipped type="pytest.skip" message="test_namespace_scoping validates single-tenant dormant mode; skipped when ENABLE_TENANT_NAMESPACE_DISCOVERY=true">/workspace/source/test/maas-e2e/test/e2e/tests/test_namespace_scoping.py:247: test_namespace_scoping validates single-tenant dormant mode; skipped when ENABLE_TENANT_NAMESPACE_DISCOVERY=true</skipped></testcase><testcase classname="tests.test_subscription.TestE2ESubscriptionFlow" name="test_e2e_multiple_subscriptions_separate_keys_gets_200" time="203.670"><failure message="TimeoutError: TokenRateLimitPolicy maas-trlp-simulator-w4-9c901b was not created and enforced in e2e-models-e2e-worker-w4-9c901b within 180s: generation=5, observedGeneration=5, Enforced={'lastTransitionTime': '2026-10-30T20:17:57Z', 'message': 'TokenRateLimitPolicy waiting for the following components to sync: [Limitador]', 'reason': 'Unknown', 'status': 'False', 'type': 'Enforced'}, includes_subscription=True">self = &lt;test_subscription.TestE2ESubscriptionFlow object at 0x7fef51f7eed0&gt;

    def test_e2e_multiple_subscriptions_separate_keys_gets_200(self):
        """
        User with two subscriptions for the same model: mint one API key per subscription;
        each key succeeds on inference without x-maas-subscription.
        """
        ns = _ns()
        auth_policy_name = "e2e-test-auth-multi-sub-valid"
        subscription_1 = "e2e-test-subscription-free"
        subscription_2 = "e2e-test-subscription-premium"
        sa_name = "e2e-sa-multi-sub-valid"
    
        try:
            # Create service account and get OC token for maas-api
            oc_token = _create_sa_token(sa_name, namespace=ns)
            sa_user = _sa_to_user(sa_name, namespace=ns)
    
            # Create test resources with 2 subscriptions for the same user
            _create_test_auth_policy(auth_policy_name, MODEL_REF, users=[sa_user])
            _create_test_subscription(subscription_1, MODEL_REF, users=[sa_user], token_limit=100)
            _create_test_subscription(subscription_2, MODEL_REF, users=[sa_user], token_limit=1000)
    
            _wait_for_maas_auth_policy_phase(auth_policy_name, require_enforced=False)
&gt;           _wait_for_subscription_inference_ready(
                subscription_1,
                MODEL_REF,
                model_namespace=MODEL_NAMESPACE,
                timeout=180,
            )

test/maas-e2e/test/e2e/tests/test_subscription.py:2089: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
test/maas-e2e/test/e2e/tests/test_helper.py:1781: in _wait_for_subscription_inference_ready
    _wait_for_token_rate_limit_policy(
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

model_ref = 'simulator-w4-9c901b'
model_namespace = 'e2e-models-e2e-worker-w4-9c901b', timeout = 180
subscription_name = 'e2e-test-subscription-free'
subscription_namespace = 'ai-tenant-e2e-worker-w4-9c901b'

    def _wait_for_token_rate_limit_policy(
        model_ref, model_namespace=MODEL_NAMESPACE, timeout=60, *, subscription_name=None, subscription_namespace=None
    ):
        """Wait for the current TokenRateLimitPolicy generation to be enforced.
    
        If a subscription is supplied, wait until the policy includes it. This
        prevents accepting the old policy before the controller updates its spec.
    
        Args:
            model_ref: Name of the model (e.g., "e2e-distinct-simulated")
            model_namespace: Namespace where the TRLP should be created (default: MODEL_NAMESPACE)
            timeout: Maximum wait time in seconds (default: 60)
            subscription_name: Subscription that the policy must include, if supplied
            subscription_namespace: Subscription namespace (defaults to _ns())
    
        Raises:
            TimeoutError: If TRLP isn't created and enforced within timeout
        """
        trlp_name = f"maas-trlp-{model_ref}"
        expected_subscription = (
            f"{subscription_namespace or _ns()}/{subscription_name}" if subscription_name else None
        )
        last_snapshot = "not found"
        deadline = time.time() + timeout
        log.info(f"Waiting for TokenRateLimitPolicy {trlp_name} in {model_namespace} (timeout: {timeout}s)...")
    
        while time.time() &lt; deadline:
            result = subprocess.run(
                ["oc", "get", "tokenratelimitpolicy", trlp_name, "-n", model_namespace, "-o", "json"],
                capture_output=True,
                text=True,
                timeout=30,
            )
            if result.returncode == 0:
                try:
                    trlp = json.loads(result.stdout)
                    metadata = trlp.get("metadata", {})
                    status = trlp.get("status", {})
                    generation = metadata.get("generation")
                    observed = status.get("observedGeneration")
                    conditions = status.get("conditions", [])
                    enforced = next((c for c in conditions if c.get("type") == "Enforced"), None)
                    subscriptions = {
                        name.strip()
                        for name in metadata.get("annotations", {}).get(
                            "maas.opendatahub.io/subscriptions", ""
                        ).split(",")
                    }
                    includes_subscription = expected_subscription is None or expected_subscription in subscriptions
                    last_snapshot = (
                        f"generation={generation}, observedGeneration={observed}, "
                        f"Enforced={enforced}, includes_subscription={includes_subscription}"
                    )
                    if (
                        enforced and enforced.get("status") == "True"
                        and generation is not None and observed == generation
                        and includes_subscription
                    ):
                        log.info(f"TokenRateLimitPolicy {trlp_name} generation {generation} is enforced")
                        return
                    log.debug(f"TokenRateLimitPolicy {trlp_name} is not ready: {last_snapshot}")
                except (json.JSONDecodeError, KeyError) as e:
                    log.debug(f"Failed to parse TRLP status: {e}")
            elif _is_not_found_error(result.stderr):
                log.debug(f"TokenRateLimitPolicy {trlp_name} not found yet...")
            elif _is_transient_kubectl_error(result.stderr):
                log.debug(
                    f"Transient error while reading TokenRateLimitPolicy {trlp_name}: {result.stderr.strip()}"
                )
            else:
                raise RuntimeError(
                    f"Failed to get TokenRateLimitPolicy {trlp_name} in namespace '{model_namespace}': "
                    f"{result.stderr.strip()}"
                )
            time.sleep(3)
    
&gt;       raise TimeoutError(
            f"TokenRateLimitPolicy {trlp_name} was not created and enforced in {model_namespace} within {timeout}s: {last_snapshot}"
        )
E       TimeoutError: TokenRateLimitPolicy maas-trlp-simulator-w4-9c901b was not created and enforced in e2e-models-e2e-worker-w4-9c901b within 180s: generation=5, observedGeneration=5, Enforced={'lastTransitionTime': '2026-10-30T20:17:57Z', 'message': 'TokenRateLimitPolicy waiting for the following components to sync: [Limitador]', 'reason': 'Unknown', 'status': 'False', 'type': 'Enforced'}, includes_subscription=True

test/maas-e2e/test/e2e/tests/test_helper.py:1538: TimeoutError</failure></testcase><testcase classname="tests.test_negative_security.TestInternalEndpointIsolation" name="test_internal_endpoint_not_routable[subscriptions-select]" time="0.242" /><testcase classname="tests.test_subscription.TestE2ESubscriptionFlow" name="test_e2e_with_both_access_and_subscription_gets_200" time="197.671"><failure message="TimeoutError: TokenRateLimitPolicy maas-trlp-premium-w0-c646da was not created and enforced in e2e-models-e2e-worker-w0-c646da within 180s: generation=2, observedGeneration=2, Enforced={'lastTransitionTime': '2026-10-30T20:18:33Z', 'message': 'TokenRateLimitPolicy waiting for the following components to sync: [Limitador]', 'reason': 'Unknown', 'status': 'False', 'type': 'Enforced'}, includes_subscription=True">self = &lt;test_subscription.TestE2ESubscriptionFlow object at 0x7fd2db189790&gt;

    def test_e2e_with_both_access_and_subscription_gets_200(self):
        """
        API key with both access and subscription should get 200 OK.
    
        Uses an existing model reference that aligns with gateway path-based model identity.
        """
        ns = _ns()
        auth_policy_name = "e2e-test-auth-success"
        subscription_name = "e2e-test-subscription-success"
        sa_name = "e2e-sa-success"
    
        try:
            # Create service account and get OC token for maas-api
            oc_token = _create_sa_token(sa_name, namespace=ns)
            sa_user = _sa_to_user(sa_name, namespace=ns)
    
            # Use pre-existing premium model to keep model identity consistent with gateway path.
            _create_test_auth_policy(auth_policy_name, PREMIUM_MODEL_REF, users=[sa_user])
            _create_test_subscription(subscription_name, PREMIUM_MODEL_REF, users=[sa_user])
            _wait_for_maas_auth_policy_phase(auth_policy_name, namespace=ns, timeout=120, require_auth_policies=False)
&gt;           _wait_for_subscription_inference_ready(
                subscription_name,
                PREMIUM_MODEL_REF,
                namespace=ns,
                model_namespace=MODEL_NAMESPACE,
                timeout=180,
            )

test/maas-e2e/test/e2e/tests/test_subscription.py:1887: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
test/maas-e2e/test/e2e/tests/test_helper.py:1781: in _wait_for_subscription_inference_ready
    _wait_for_token_rate_limit_policy(
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

model_ref = 'premium-w0-c646da'
model_namespace = 'e2e-models-e2e-worker-w0-c646da', timeout = 180
subscription_name = 'e2e-test-subscription-success'
subscription_namespace = 'ai-tenant-e2e-worker-w0-c646da'

    def _wait_for_token_rate_limit_policy(
        model_ref, model_namespace=MODEL_NAMESPACE, timeout=60, *, subscription_name=None, subscription_namespace=None
    ):
        """Wait for the current TokenRateLimitPolicy generation to be enforced.
    
        If a subscription is supplied, wait until the policy includes it. This
        prevents accepting the old policy before the controller updates its spec.
    
        Args:
            model_ref: Name of the model (e.g., "e2e-distinct-simulated")
            model_namespace: Namespace where the TRLP should be created (default: MODEL_NAMESPACE)
            timeout: Maximum wait time in seconds (default: 60)
            subscription_name: Subscription that the policy must include, if supplied
            subscription_namespace: Subscription namespace (defaults to _ns())
    
        Raises:
            TimeoutError: If TRLP isn't created and enforced within timeout
        """
        trlp_name = f"maas-trlp-{model_ref}"
        expected_subscription = (
            f"{subscription_namespace or _ns()}/{subscription_name}" if subscription_name else None
        )
        last_snapshot = "not found"
        deadline = time.time() + timeout
        log.info(f"Waiting for TokenRateLimitPolicy {trlp_name} in {model_namespace} (timeout: {timeout}s)...")
    
        while time.time() &lt; deadline:
            result = subprocess.run(
                ["oc", "get", "tokenratelimitpolicy", trlp_name, "-n", model_namespace, "-o", "json"],
                capture_output=True,
                text=True,
                timeout=30,
            )
            if result.returncode == 0:
                try:
                    trlp = json.loads(result.stdout)
                    metadata = trlp.get("metadata", {})
                    status = trlp.get("status", {})
                    generation = metadata.get("generation")
                    observed = status.get("observedGeneration")
                    conditions = status.get("conditions", [])
                    enforced = next((c for c in conditions if c.get("type") == "Enforced"), None)
                    subscriptions = {
                        name.strip()
                        for name in metadata.get("annotations", {}).get(
                            "maas.opendatahub.io/subscriptions", ""
                        ).split(",")
                    }
                    includes_subscription = expected_subscription is None or expected_subscription in subscriptions
                    last_snapshot = (
                        f"generation={generation}, observedGeneration={observed}, "
                        f"Enforced={enforced}, includes_subscription={includes_subscription}"
                    )
                    if (
                        enforced and enforced.get("status") == "True"
                        and generation is not None and observed == generation
                        and includes_subscription
                    ):
                        log.info(f"TokenRateLimitPolicy {trlp_name} generation {generation} is enforced")
                        return
                    log.debug(f"TokenRateLimitPolicy {trlp_name} is not ready: {last_snapshot}")
                except (json.JSONDecodeError, KeyError) as e:
                    log.debug(f"Failed to parse TRLP status: {e}")
            elif _is_not_found_error(result.stderr):
                log.debug(f"TokenRateLimitPolicy {trlp_name} not found yet...")
            elif _is_transient_kubectl_error(result.stderr):
                log.debug(
                    f"Transient error while reading TokenRateLimitPolicy {trlp_name}: {result.stderr.strip()}"
                )
            else:
                raise RuntimeError(
                    f"Failed to get TokenRateLimitPolicy {trlp_name} in namespace '{model_namespace}': "
                    f"{result.stderr.strip()}"
                )
            time.sleep(3)
    
&gt;       raise TimeoutError(
            f"TokenRateLimitPolicy {trlp_name} was not created and enforced in {model_namespace} within {timeout}s: {last_snapshot}"
        )
E       TimeoutError: TokenRateLimitPolicy maas-trlp-premium-w0-c646da was not created and enforced in e2e-models-e2e-worker-w0-c646da within 180s: generation=2, observedGeneration=2, Enforced={'lastTransitionTime': '2026-10-30T20:18:33Z', 'message': 'TokenRateLimitPolicy waiting for the following components to sync: [Limitador]', 'reason': 'Unknown', 'status': 'False', 'type': 'Enforced'}, includes_subscription=True

test/maas-e2e/test/e2e/tests/test_helper.py:1538: TimeoutError</failure></testcase><testcase classname="tests.test_subscription.TestE2ESubscriptionFlow" name="test_e2e_group_based_access_gets_200" time="197.481"><failure message="TimeoutError: TokenRateLimitPolicy maas-trlp-simulator-w1-5197ec was not created and enforced in e2e-models-e2e-worker-w1-5197ec within 180s: generation=4, observedGeneration=4, Enforced={'lastTransitionTime': '2026-10-30T20:17:45Z', 'message': 'TokenRateLimitPolicy waiting for the following components to sync: [Limitador]', 'reason': 'Unknown', 'status': 'False', 'type': 'Enforced'}, includes_subscription=True">self = &lt;test_subscription.TestE2ESubscriptionFlow object at 0x7f4497f82110&gt;

    def test_e2e_group_based_access_gets_200(self):
        """
        E2E test: Group-based auth and subscription (success case).
    
        Validates that users can access models via group membership in both
        MaaSAuthPolicy and MaaSSubscription, not just explicit user lists.
        """
        ns = _ns()
        auth_policy_name = "e2e-test-group-auth"
        subscription_name = "e2e-test-group-subscription"
        sa_name = "e2e-sa-group"
    
        # Use namespace-specific group that SA will be in
        test_group = f"system:serviceaccounts:{ns}"
    
        try:
            # Create service account and get OC token for maas-api
            oc_token = _create_sa_token(sa_name, namespace=ns)
    
            # Create auth policy using GROUP (not user)
            _create_test_auth_policy(auth_policy_name, MODEL_REF, groups=[test_group])
    
            # Create subscription using GROUP (not user)
            _create_test_subscription(subscription_name, MODEL_REF, groups=[test_group])
    
            _wait_for_maas_auth_policy_phase(auth_policy_name, require_enforced=False)
&gt;           _wait_for_subscription_inference_ready(
                subscription_name,
                MODEL_REF,
                model_namespace=MODEL_NAMESPACE,
                timeout=180,
            )

test/maas-e2e/test/e2e/tests/test_subscription.py:2216: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
test/maas-e2e/test/e2e/tests/test_helper.py:1781: in _wait_for_subscription_inference_ready
    _wait_for_token_rate_limit_policy(
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

model_ref = 'simulator-w1-5197ec'
model_namespace = 'e2e-models-e2e-worker-w1-5197ec', timeout = 180
subscription_name = 'e2e-test-group-subscription'
subscription_namespace = 'ai-tenant-e2e-worker-w1-5197ec'

    def _wait_for_token_rate_limit_policy(
        model_ref, model_namespace=MODEL_NAMESPACE, timeout=60, *, subscription_name=None, subscription_namespace=None
    ):
        """Wait for the current TokenRateLimitPolicy generation to be enforced.
    
        If a subscription is supplied, wait until the policy includes it. This
        prevents accepting the old policy before the controller updates its spec.
    
        Args:
            model_ref: Name of the model (e.g., "e2e-distinct-simulated")
            model_namespace: Namespace where the TRLP should be created (default: MODEL_NAMESPACE)
            timeout: Maximum wait time in seconds (default: 60)
            subscription_name: Subscription that the policy must include, if supplied
            subscription_namespace: Subscription namespace (defaults to _ns())
    
        Raises:
            TimeoutError: If TRLP isn't created and enforced within timeout
        """
        trlp_name = f"maas-trlp-{model_ref}"
        expected_subscription = (
            f"{subscription_namespace or _ns()}/{subscription_name}" if subscription_name else None
        )
        last_snapshot = "not found"
        deadline = time.time() + timeout
        log.info(f"Waiting for TokenRateLimitPolicy {trlp_name} in {model_namespace} (timeout: {timeout}s)...")
    
        while time.time() &lt; deadline:
            result = subprocess.run(
                ["oc", "get", "tokenratelimitpolicy", trlp_name, "-n", model_namespace, "-o", "json"],
                capture_output=True,
                text=True,
                timeout=30,
            )
            if result.returncode == 0:
                try:
                    trlp = json.loads(result.stdout)
                    metadata = trlp.get("metadata", {})
                    status = trlp.get("status", {})
                    generation = metadata.get("generation")
                    observed = status.get("observedGeneration")
                    conditions = status.get("conditions", [])
                    enforced = next((c for c in conditions if c.get("type") == "Enforced"), None)
                    subscriptions = {
                        name.strip()
                        for name in metadata.get("annotations", {}).get(
                            "maas.opendatahub.io/subscriptions", ""
                        ).split(",")
                    }
                    includes_subscription = expected_subscription is None or expected_subscription in subscriptions
                    last_snapshot = (
                        f"generation={generation}, observedGeneration={observed}, "
                        f"Enforced={enforced}, includes_subscription={includes_subscription}"
                    )
                    if (
                        enforced and enforced.get("status") == "True"
                        and generation is not None and observed == generation
                        and includes_subscription
                    ):
                        log.info(f"TokenRateLimitPolicy {trlp_name} generation {generation} is enforced")
                        return
                    log.debug(f"TokenRateLimitPolicy {trlp_name} is not ready: {last_snapshot}")
                except (json.JSONDecodeError, KeyError) as e:
                    log.debug(f"Failed to parse TRLP status: {e}")
            elif _is_not_found_error(result.stderr):
                log.debug(f"TokenRateLimitPolicy {trlp_name} not found yet...")
            elif _is_transient_kubectl_error(result.stderr):
                log.debug(
                    f"Transient error while reading TokenRateLimitPolicy {trlp_name}: {result.stderr.strip()}"
                )
            else:
                raise RuntimeError(
                    f"Failed to get TokenRateLimitPolicy {trlp_name} in namespace '{model_namespace}': "
                    f"{result.stderr.strip()}"
                )
            time.sleep(3)
    
&gt;       raise TimeoutError(
            f"TokenRateLimitPolicy {trlp_name} was not created and enforced in {model_namespace} within {timeout}s: {last_snapshot}"
        )
E       TimeoutError: TokenRateLimitPolicy maas-trlp-simulator-w1-5197ec was not created and enforced in e2e-models-e2e-worker-w1-5197ec within 180s: generation=4, observedGeneration=4, Enforced={'lastTransitionTime': '2026-10-30T20:17:45Z', 'message': 'TokenRateLimitPolicy waiting for the following components to sync: [Limitador]', 'reason': 'Unknown', 'status': 'False', 'type': 'Enforced'}, includes_subscription=True

test/maas-e2e/test/e2e/tests/test_helper.py:1538: TimeoutError</failure></testcase><testcase classname="tests.test_subscription.TestSubscriptionEnforcement" name="test_subscribed_user_gets_200" time="0.297" /><testcase classname="tests.test_subscription.TestManagedAnnotation" name="test_trlp_managed_false_prevents_update" time="288.042" /><testcase classname="tests.test_subscription.TestManagedAnnotation" name="test_authpolicy_managed_false_prevents_update" time="0.325"><skipped type="pytest.skip" message="gateway-only mode: per-model AuthPolicy is not created">/workspace/source/test/maas-e2e/test/e2e/tests/test_subscription.py:1580: gateway-only mode: per-model AuthPolicy is not created</skipped></testcase><testcase classname="tests.test_subscription.TestE2ESubscriptionFlow" name="test_e2e_with_subscription_but_no_access_gets_403" time="13.370" /><testcase classname="tests.test_subscription.TestStatusReporting" name="test_subscription_failed_status_with_missing_model" time="54.445" /><testcase classname="tests.test_subscription.TestStatusReporting" name="test_subscription_degraded_status_with_partial_models" time="49.661" /><testcase classname="tests.test_subscription.TestStatusReporting" name="test_authpolicy_active_status_with_valid_model" time="12.193" /><testcase classname="tests.test_subscription.TestStatusReporting" name="test_authpolicy_degraded_status_with_partial_models" time="3.368" /><testcase classname="tests.test_subscription.TestDegradedSubscriptionFiltering" name="test_models_endpoint_with_degraded_subscription_kube_token" time="11.788" /><testcase classname="tests.test_subscription.TestDegradedSubscriptionFiltering" name="test_models_endpoint_with_degraded_subscription_api_key" time="13.149" /><testcase classname="tests.test_subscription_list_endpoints.TestListSubscriptions" name="test_returns_accessible_subscriptions" time="4.962" /><testcase classname="tests.test_subscription_list_endpoints.TestListSubscriptions" name="test_unauthenticated_returns_401[subscriptions-for-model]" time="0.079" /><testcase classname="tests.test_subscription_list_endpoints.TestListSubscriptions" name="test_model_ref_display_name_and_description_enriched" time="12.521" /><testcase classname="tests.test_subscription_list_endpoints.TestListSubscriptions" name="test_unauthenticated_returns_401[all-subscriptions]" time="4.225" /><testcase classname="tests.test_subscription_list_endpoints.TestListSubscriptions" name="test_subscription_includes_model_refs" time="11.427" /><testcase classname="tests.test_subscription.TestStatusReporting" name="test_subscription_status_transitions_on_model_deletion" time="84.658" /><testcase classname="tests.test_subscription_list_endpoints.TestListSubscriptionsForModel" name="test_returns_subscriptions_for_model" time="25.459" /><testcase classname="tests.test_subscription_list_endpoints.TestListSubscriptionsForModel" name="test_unknown_model_returns_empty" time="0.734" /><testcase classname="tests.test_subscription_list_endpoints.TestSubscriptionModelAccessFiltering" name="test_omits_subscription_with_no_authorized_models" time="14.615" /><testcase classname="tests.test_models_endpoint.TestModelsEndpoint" name="test_empty_subscription_header_value" time="5.213" /><testcase classname="tests.test_models_endpoint.TestModelsEndpoint" name="test_deduplication_same_model_multiple_refs" time="15.025" /><testcase classname="tests.test_subscription.TestDegradedSubscriptionFiltering" name="test_degraded_healthy_model_allows_inference" time="12.032" /><testcase classname="tests.test_subscription_list_endpoints.TestSubscriptionModelAccessFiltering" name="test_filters_unauthorized_models" time="12.340" /><testcase classname="tests.test_models_endpoint.TestModelsEndpoint" name="test_multiple_distinct_models_in_subscription" time="12.875" /><testcase classname="tests.test_models_endpoint.TestModelsEndpoint" name="test_user_token_returns_all_models" time="32.480" /><testcase classname="tests.test_models_endpoint.TestModelsEndpoint" name="test_user_token_with_subscription_header_filters" time="20.509" /><testcase classname="tests.test_models_endpoint.TestModelsEndpoint" name="test_api_key_with_deleted_subscription_403" time="38.311" /><testcase classname="tests.test_models_endpoint.TestModelsEndpoint" name="test_api_key_scoped_to_subscription" time="14.428" /><testcase classname="tests.test_models_endpoint.TestModelsEndpoint" name="test_response_schema_and_metadata" time="4.236" /><testcase classname="tests.test_models_endpoint.TestModelsEndpoint" name="test_invalid_subscription_header_403" time="15.233" /><testcase classname="tests.test_models_endpoint.TestModelsEndpoint" name="test_access_denied_to_subscription_403" time="24.152" /><testcase classname="tests.test_models_endpoint.TestModelsEndpoint" name="test_api_key_ignores_subscription_header" time="29.221" /><testcase classname="tests.test_models_endpoint.TestModelsEndpoint" name="test_api_key_with_inaccessible_subscription_403" time="14.415" /><testcase classname="tests.test_models_endpoint.TestModelsEndpoint" name="test_multiple_api_keys_different_subscriptions" time="29.482" /><testcase classname="tests.test_subscription.TestE2ESubscriptionFlow" name="test_e2e_group_based_subscription_but_no_auth_gets_403" time="15.036" /><testcase classname="tests.test_models_endpoint.TestModelsEndpoint" name="test_service_account_token_multiple_subs_with_header" time="32.175" /><testcase classname="tests.test_subscription.TestE2ESubscriptionFlow" name="test_e2e_mint_api_key_denied_for_inaccessible_subscription" time="24.896" /><testcase classname="tests.test_models_endpoint.TestModelsEndpoint" name="test_service_account_token_multiple_subs_no_header" time="35.264" /><testcase classname="tests.test_smoke" name="test_tokens_endpoint_replaced_by_api_keys" time="2.090"><failure message="AssertionError: Expected 401/404/405 (endpoint replaced), got 500: Internal Server Error.&#10;  &#10;assert 500 in (401, 404, 405)&#10; +  where 500 = &lt;Response [500]&gt;.status_code">maas_api_base_url = 'https://maas.apps.3d1a0c34cf950dbd372c.prod.konflux-ocp-ci.dev/maas-api'

    def test_tokens_endpoint_replaced_by_api_keys(maas_api_base_url: str):
        """
        Verify /v1/tokens endpoint has been replaced by the API key system.
        The endpoint may return 401 (auth required), 404 (removed), or 405 (method not allowed).
        Any of these indicates the old token minting is no longer available.
        """
        url = f"{maas_api_base_url}/v1/tokens"
        r = requests.post(url, json={"expiration": "1m"}, timeout=20, verify=TLS_VERIFY)
        msg = f"[token] POST {url} (no auth) -&gt; {r.status_code}"
        log.info(msg)
        print(msg)
    
        # 401/404/405 all indicate the old token minting endpoint is gone/protected
&gt;       assert r.status_code in (401, 404, 405), f"Expected 401/404/405 (endpoint replaced), got {r.status_code}: {r.text[:400]}"
E       AssertionError: Expected 401/404/405 (endpoint replaced), got 500: Internal Server Error.
E         
E       assert 500 in (401, 404, 405)
E        +  where 500 = &lt;Response [500]&gt;.status_code

test/maas-e2e/test/e2e/tests/test_smoke.py:50: AssertionError</failure></testcase><testcase classname="tests.test_smoke" name="test_legacy_completions_optionally" time="2.138"><error message="failed on setup with &quot;requests.exceptions.HTTPError: 500 Server Error: Internal Server Error for url: https://maas.apps.3d1a0c34cf950dbd372c.prod.konflux-ocp-ci.dev/maas-api/v1/models&quot;">maas_api_base_url = 'https://maas.apps.3d1a0c34cf950dbd372c.prod.konflux-ocp-ci.dev/maas-api'
headers = {'Authorization': 'Bearer eyJhbGciOiJSUzI1NiIsImtpZCI6Ik9Va1JFSmZSUXBtYjFJX1lOSmg3eDdpTE96YzY3Y293WEItaEFhQ3FuNWMifQ.e...1fLuSLF4krv3X7YHMr3-YStPhNfTw8yLS1wTVARyjkUDN2zWtrpabPElrK5WRz4hsSW4sZIPaW-IQXB6Q', 'Content-Type': 'application/json'}

    @pytest.fixture(scope="session")
    def model_catalog(maas_api_base_url: str, headers: dict):
        r = requests.get(f"{maas_api_base_url}/v1/models", headers=headers, timeout=45, verify=TLS_VERIFY)
&gt;       r.raise_for_status()

test/maas-e2e/test/e2e/tests/conftest.py:276: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = &lt;Response [500]&gt;

    def raise_for_status(self) -&gt; None:
        """Raises :class:`HTTPError`, if one occurred."""
    
        http_error_msg = ""
        if isinstance(self.reason, bytes):
            # We attempt to decode utf-8 first because some servers
            # choose to localize their reason strings. If the string
            # isn't utf-8, we fall back to iso-8859-1 for all other
            # encodings. (See PR #3538)
            try:
                reason = self.reason.decode("utf-8")
            except UnicodeDecodeError:
                reason = self.reason.decode("iso-8859-1")
        else:
            reason = self.reason
    
        if 400 &lt;= self.status_code &lt; 500:
            http_error_msg = (
                f"{self.status_code} Client Error: {reason} for url: {self.url}"
            )
    
        elif 500 &lt;= self.status_code &lt; 600:
            http_error_msg = (
                f"{self.status_code} Server Error: {reason} for url: {self.url}"
            )
    
        if http_error_msg:
&gt;           raise HTTPError(http_error_msg, response=self)
E           requests.exceptions.HTTPError: 500 Server Error: Internal Server Error for url: https://maas.apps.3d1a0c34cf950dbd372c.prod.konflux-ocp-ci.dev/maas-api/v1/models

test/e2e/.venv/lib64/python3.11/site-packages/requests/models.py:1167: HTTPError</error></testcase><testcase classname="tests.test_tenant.TestTenantLifecycle" name="test_tenant_ready_and_phase_healthy" time="47.598" /><testcase classname="tests.test_models_endpoint.TestModelsEndpoint" name="test_unauthenticated_request_401" time="53.519" /><testcase classname="tests.test_smoke" name="test_chat_completions_gateway_alive" time="50.012" /><testcase classname="tests.test_smoke" name="test_models_catalog" time="41.680" /><testcase classname="tests.test_smoke" name="test_chat_completions_streaming_sse" time="43.750" /><testcase classname="tests.test_subscription.TestStatusReporting" name="test_subscription_active_status_with_valid_model" time="92.834" /><testcase classname="tests.test_smoke" name="test_healthz_or_404" time="34.514" /><testcase classname="tests.test_subscription.TestStatusReporting" name="test_authpolicy_failed_status_with_missing_model" time="70.684" /></testsuite></testsuites>