<?xml version="1.0" encoding="utf-8"?><testsuites name="pytest tests"><testsuite name="pytest" errors="0" failures="15" skipped="44" tests="250" time="996.338" timestamp="2026-09-10T14:54:58.366587+00:00" hostname="maas-group-test-5g4vd-e2e-maas-openshift-pod"><testcase classname="tests.test_namespace_scoping.TestMaaSAPIWatchNamespace" name="test_subscription_in_subscription_namespace_visible_to_api@security" time="0.003"><skipped type="pytest.skip" message="test_namespace_scoping validates single-tenant dormant mode; skipped when ENABLE_TENANT_NAMESPACE_DISCOVERY=true">/workspace/source/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.TestMaaSAPIWatchNamespace" name="test_subscription_in_another_namespace_not_visible_to_api@security" 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/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_namespace_scoping.TestMaaSControllerWatchNamespace" name="test_authpolicy_and_subscription_in_maas_subscription_namespace@security" 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/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_namespace_scoping.TestMaaSControllerWatchNamespace" name="test_authpolicy_and_subscription_in_another_namespace@security" 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/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@security" 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/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@security" 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/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@security" time="0.221"><failure message="AssertionError: Expected API-key-authenticated mint to be denied, got 201 body_bytes=326&#10;assert 201 in (401, 403)&#10; +  where 201 = &lt;Response [201]&gt;.status_code">self = &lt;test_negative_security.TestAPIKeyManagementIsolation object at 0x7f050aaea340&gt;

    def test_api_key_cannot_mint_another_api_key(self):
        """A valid subscription-bound API key must be denied on POST /v1/api-keys.
    
        The initial key is minted with a cluster token as a control. The test then
        presents that valid key to the management endpoint and verifies that the
        gateway or MaaS API rejects it without returning new key material.
        """
        _wait_for_gateway_auth_enforced()
        oc_token = _get_cluster_token()
        parent_key_id = None
    
        try:
            parent = _create_api_key_raw(
                oc_token,
                name=f"e2e-delegation-parent-{uuid.uuid4().hex[:8]}",
                subscription=SIMULATOR_SUBSCRIPTION,
            )
            assert parent.status_code in (200, 201), (
                f"Control API key mint failed: {parent.status_code} "
                f"body_bytes={len(parent.content)}"
            )
            parent_body = parent.json()
            parent_key_id = parent_body.get("id")
            parent_key = parent_body.get("key", "")
            assert parent_key.startswith("sk-oai-"), "Control mint did not return an API key"
    
            # Use the API key, not the cluster token, to attempt delegation.
            # Do not log the response body: a regression could return a live key.
            delegated = requests.post(
                f"{_maas_api_url()}/v1/api-keys",
                headers={
                    "Authorization": f"Bearer {parent_key}",
                    "Content-Type": "application/json",
                },
                json={
                    "name": f"e2e-delegation-child-{uuid.uuid4().hex[:8]}",
                    "subscription": SIMULATOR_SUBSCRIPTION,
                },
                timeout=TIMEOUT,
                verify=TLS_VERIFY,
            )
    
            log.info(
                "API-key-authenticated key mint -&gt; %s body_bytes=%d",
                delegated.status_code,
                len(delegated.content),
            )
&gt;           assert delegated.status_code in (401, 403), (
                f"Expected API-key-authenticated mint to be denied, got "
                f"{delegated.status_code} body_bytes={len(delegated.content)}"
            )
E           AssertionError: Expected API-key-authenticated mint to be denied, got 201 body_bytes=326
E           assert 201 in (401, 403)
E            +  where 201 = &lt;Response [201]&gt;.status_code

test/e2e/tests/test_negative_security.py:123: AssertionError</failure></testcase><testcase classname="tests.test_smoke" name="test_healthz_or_404@readonly" time="0.033" /><testcase classname="tests.test_model_identity_conflict.TestModelIdentityConflictDetection" name="test_colliding_model_names_flagged_then_resolved@models" time="134.081" /><testcase classname="tests.test_smoke" name="test_tokens_endpoint_replaced_by_api_keys@readonly" time="0.026" /><testcase classname="tests.test_smoke" name="test_models_catalog@readonly" time="0.034" /><testcase classname="tests.test_smoke" name="test_chat_completions_gateway_alive@readonly" time="0.088" /><testcase classname="tests.test_api_keys.TestAPIKeyCRUD" name="test_create_api_key@api_keys" time="0.234" /><testcase classname="tests.test_smoke" name="test_legacy_completions_optionally@readonly" time="0.036" /><testcase classname="tests.test_api_keys.TestAPIKeyCRUD" name="test_list_api_keys@api_keys" time="0.153" /><testcase classname="tests.test_negative_security.TestHeaderSpoofing" name="test_forged_identity_headers_rejected_on_key_mint[username-only]@security" time="0.327" /><testcase classname="tests.test_aitenant_lifecycle.TestAITenantLifecycle" name="test_default_aitenant_bootstraps_maas_tenant_config_without_gateway_mutation@mt_lifecycle" time="1.739" /><testcase classname="tests.test_api_keys.TestAPIKeyCRUD" name="test_revoke_api_key@api_keys" time="0.118" /><testcase classname="tests.test_tenant.TestTenantLifecycle" name="test_tenant_ready_and_phase_healthy@readonly" time="0.358" /><testcase classname="tests.test_api_keys.TestAPIKeyAuthorization" name="test_admin_manage_other_users_keys@api_keys" time="0.194" /><testcase classname="tests.test_tenant.TestTenantContract" name="test_status_has_phase_and_conditions@readonly" time="0.121" /><testcase classname="tests.test_negative_security.TestHeaderSpoofing" name="test_forged_identity_headers_rejected_on_key_mint[group-only]@security" time="0.324" /><testcase classname="tests.test_api_keys.TestAPIKeyAuthorization" name="test_non_admin_cannot_access_other_users_keys@api_keys" time="0.141" /><testcase classname="tests.test_tenant.TestTenantContract" name="test_spec_is_well_formed@readonly" time="0.128" /><testcase classname="tests.test_tenant.TestTenantContract" name="test_conditions_use_kubernetes_metav1_shape@readonly" time="0.124" /><testcase classname="tests.test_api_keys.TestAPIKeyBulkOperations" name="test_bulk_revoke_own_keys@api_keys" time="0.422" /><testcase classname="tests.test_negative_security.TestHeaderSpoofing" name="test_injected_identity_headers_rejected_on_inference@security" time="0.215" /><testcase classname="tests.test_tenant.TestTenantNoFalseOwnership" name="test_maas_user_crs_not_owned_by_tenant@readonly" time="0.353" /><testcase classname="tests.test_negative_security.TestHeaderSpoofing" name="test_duplicate_subscription_headers_ignored@security" time="0.283" /><testcase classname="tests.test_api_keys.TestAPIKeyBulkOperations" name="test_bulk_revoke_other_user_forbidden@api_keys" time="0.056" /><testcase classname="tests.test_api_keys.TestAPIKeyBulkOperations" name="test_bulk_revoke_admin_can_revoke_any_user@api_keys" time="0.153" /><testcase classname="tests.test_negative_security.TestExpiredKeyRejection" name="test_expired_key_rejected_at_gateway@security" time="5.089" /><testcase classname="tests.test_api_keys.TestAPIKeyBulkOperations" name="test_bulk_revoke_by_subscription@api_keys" time="1.695" /><testcase classname="tests.test_config_tenant.TestConfigAnchorPresence" name="test_cluster_config_default_exists@readonly" time="0.404" /><testcase classname="tests.test_config_tenant.TestConfigAnchorPresence" name="test_cluster_config_not_terminating@readonly" time="0.148" /><testcase classname="tests.test_aitenant_lifecycle.TestAITenantLifecycle" name="test_aitenant_rejected_outside_ai_tenants_namespace@mt_lifecycle" time="6.794" /><testcase classname="tests.test_config_tenant.TestConfigTenantOwnership" name="test_default_aitenant_lists_config_owner_reference@readonly" time="0.141" /><testcase classname="tests.test_config_tenant.TestConfigTenantOwnership" name="test_tenant_config_lists_config_owner_reference@readonly" time="0.131" /><testcase classname="tests.test_config_tenant.TestConfigTenantOwnership" name="test_maas_controller_deployment_does_not_list_config_owner_reference@readonly" time="0.112" /><testcase classname="tests.test_tenant_discovery" name="test_tenant_discovery_requires_auth@readonly" time="4.332" /><testcase classname="tests.test_api_keys.TestAPIKeyBulkOperations" name="test_bulk_revoke_by_subscription_forbidden_for_non_admin@api_keys" time="0.038" /><testcase classname="tests.test_api_keys.TestAPIKeyBulkOperations" name="test_bulk_revoke_dry_run@api_keys" time="0.195" /><testcase classname="tests.test_api_keys.TestAPIKeyBulkOperations" name="test_bulk_revoke_dry_run_by_subscription@api_keys" time="1.510" /><testcase classname="tests.test_api_keys.TestAPIKeyBulkOperations" name="test_bulk_revoke_combined_user_and_subscription@api_keys" time="12.098"><failure message="subprocess.CalledProcessError: Command '['oc', 'apply', '-f', '-']' returned non-zero exit status 1.">self = &lt;test_api_keys.TestAPIKeyBulkOperations object at 0x7f69910cd2b0&gt;
api_keys_base_url = 'https://maas.apps.c11d0304-e0a5-4709-b419-13ceda2bba51.prod.konfluxeaas.com/maas-api/v1/api-keys'
headers = {'Authorization': 'Bearer eyJhbGciOiJSUzI1NiIsImtpZCI6ImFPT3pVTnVFLTc0UHhoUk1mVXEybUo0OFhwYWIwbWtSM1VtMEhhMWFaYkEifQ.e...N77BlNAtYag-NJvoiEEOVxGhHGwbnnbqOZC4DJHCn2mVtluNm_pcfrfRFCU-yble6pu-Xt5-jFUI04PHg', 'Content-Type': 'application/json'}
admin_headers = {'Authorization': 'Bearer eyJhbGciOiJSUzI1NiIsImtpZCI6ImFPT3pVTnVFLTc0UHhoUk1mVXEybUo0OFhwYWIwbWtSM1VtMEhhMWFaYkEifQ.e...iPb7lKEfhpwT5m0N3S9HIGwdTXc7nSwmNDYIPfN4tfF-sL5E5h9RRli6sbxcAuipT4ImN0gozxz36yIuA', 'Content-Type': 'application/json'}

    def test_bulk_revoke_combined_user_and_subscription(self, api_keys_base_url: str, headers: dict, admin_headers: dict):
        """Admin can revoke keys for a specific user within a specific subscription.
    
        Negative control: a second user's keys in the same subscription must remain active.
        """
        if not admin_headers:
            pytest.skip("ADMIN_OC_TOKEN not set")
    
        sub_name = f"e2e-combo-sub-{os.urandom(4).hex()}"
        ns = _ns()
        sa_name = f"e2e-combo-sa-{os.urandom(4).hex()}"
        sa2_name = f"e2e-combo-sa2-{os.urandom(4).hex()}"
    
        key_ids = []
        key_ids_user2 = []
        try:
            oc_token = _create_sa_token(sa_name, namespace=MODEL_NAMESPACE)
            sa_user = _sa_to_user(sa_name, namespace=MODEL_NAMESPACE)
            sa_headers = {"Authorization": f"Bearer {oc_token}", "Content-Type": "application/json"}
    
            oc_token2 = _create_sa_token(sa2_name, namespace=MODEL_NAMESPACE)
            sa_user2 = _sa_to_user(sa2_name, namespace=MODEL_NAMESPACE)
            sa2_headers = {"Authorization": f"Bearer {oc_token2}", "Content-Type": "application/json"}
    
&gt;           _create_test_auth_policy(f"{sub_name}-auth", MODEL_REF, users=[sa_user, sa_user2])

test/e2e/tests/test_api_keys.py:540: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
test/e2e/tests/test_helper.py:908: in _create_test_auth_policy
    _apply_cr({
test/e2e/tests/test_helper.py:620: in _apply_cr
    subprocess.run(["oc", "apply", "-f", "-"], input=json.dumps(cr_dict), capture_output=True, text=True, check=True)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

input = '{"apiVersion": "maas.opendatahub.io/v1alpha1", "kind": "MaaSAuthPolicy", "metadata": {"name": "e2e-combo-sub-537e7727...system:serviceaccount:llm:e2e-combo-sa-a18a8657", "system:serviceaccount:llm:e2e-combo-sa2-6b8acdf4"], "groups": []}}}'
capture_output = True, timeout = None, check = True
popenargs = (['oc', 'apply', '-f', '-'],)
kwargs = {'stderr': -1, 'stdin': -1, 'stdout': -1, 'text': True}
process = &lt;Popen: returncode: 1 args: ['oc', 'apply', '-f', '-']&gt;, stdout = ''
stderr = 'Error from server (InternalError): error when creating "STDIN": Internal error occurred: failed calling webhook "vmaa...ontroller-webhook-service.opendatahub.svc:443/validate-maas-opendatahub-io-v1alpha1-maasauthpolicy?timeout=10s": EOF\n'
retcode = 1

    def run(*popenargs,
            input=None, capture_output=False, timeout=None, check=False, **kwargs):
        """Run command with arguments and return a CompletedProcess instance.
    
        The returned instance will have attributes args, returncode, stdout and
        stderr. By default, stdout and stderr are not captured, and those attributes
        will be None. Pass stdout=PIPE and/or stderr=PIPE in order to capture them.
    
        If check is True and the exit code was non-zero, it raises a
        CalledProcessError. The CalledProcessError object will have the return code
        in the returncode attribute, and output &amp; stderr attributes if those streams
        were captured.
    
        If timeout is given, and the process takes too long, a TimeoutExpired
        exception will be raised.
    
        There is an optional argument "input", allowing you to
        pass bytes or a string to the subprocess's stdin.  If you use this argument
        you may not also use the Popen constructor's "stdin" argument, as
        it will be used internally.
    
        By default, all communication is in bytes, and therefore any "input" should
        be bytes, and the stdout and stderr will be bytes. If in text mode, any
        "input" should be a string, and stdout and stderr will be strings decoded
        according to locale encoding, or by "encoding" if set. Text mode is
        triggered by setting any of text, encoding, errors or universal_newlines.
    
        The other arguments are the same as for the Popen constructor.
        """
        if input is not None:
            if kwargs.get('stdin') is not None:
                raise ValueError('stdin and input arguments may not both be used.')
            kwargs['stdin'] = PIPE
    
        if capture_output:
            if kwargs.get('stdout') is not None or kwargs.get('stderr') is not None:
                raise ValueError('stdout and stderr arguments may not be used '
                                 'with capture_output.')
            kwargs['stdout'] = PIPE
            kwargs['stderr'] = PIPE
    
        with Popen(*popenargs, **kwargs) as process:
            try:
                stdout, stderr = process.communicate(input, timeout=timeout)
            except TimeoutExpired as exc:
                process.kill()
                if _mswindows:
                    # Windows accumulates the output in a single blocking
                    # read() call run on child threads, with the timeout
                    # being done in a join() on those threads.  communicate()
                    # _after_ kill() is required to collect that and add it
                    # to the exception.
                    exc.stdout, exc.stderr = process.communicate()
                else:
                    # POSIX _communicate already populated the output so
                    # far into the TimeoutExpired exception.
                    process.wait()
                raise
            except:  # Including KeyboardInterrupt, communicate handled that.
                process.kill()
                # We don't call process.wait() as .__exit__ does that for us.
                raise
            retcode = process.poll()
            if check and retcode:
&gt;               raise CalledProcessError(retcode, process.args,
                                         output=stdout, stderr=stderr)
E               subprocess.CalledProcessError: Command '['oc', 'apply', '-f', '-']' returned non-zero exit status 1.

/usr/lib64/python3.9/subprocess.py:528: CalledProcessError</failure></testcase><testcase classname="tests.test_negative_security.TestCrossModelAccess" name="test_key_cannot_access_model_outside_subscription@security" time="4.419" /><testcase classname="tests.test_tenant_discovery" name="test_tenant_discovery_with_invalid_token@readonly" time="2.001" /><testcase classname="tests.test_aitenant_lifecycle.TestAITenantLifecycle" name="test_aitenant_create_bootstrap_resources@mt_lifecycle" time="8.354"><failure message="RuntimeError: `oc apply` failed: Error from server (InternalError): error when creating &quot;STDIN&quot;: Internal error occurred: failed calling webhook &quot;vaitenant.kb.io&quot;: failed to call webhook: Post &quot;https://maas-controller-webhook-service.opendatahub.svc:443/validate-maas-opendatahub-io-v1alpha1-aitenant?timeout=10s&quot;: EOF">self = &lt;test_aitenant_lifecycle.TestAITenantLifecycle object at 0x7f6bbc425a90&gt;

    def test_aitenant_create_bootstrap_resources(self):
        case = _new_aitenant_case()
    
        try:
            _apply_gateway_fixture(case)
&gt;           _apply_aitenant(case)

test/e2e/tests/test_aitenant_lifecycle.py:421: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
test/e2e/tests/test_aitenant_lifecycle.py:191: in _apply_aitenant
    _apply(
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

obj = {'apiVersion': 'maas.opendatahub.io/v1alpha1', 'kind': 'AITenant', 'metadata': {'name': 'e2e-ait-3b43a1da', 'namespace': 'ai-tenants'}, 'spec': {}}

    def _apply(obj):
        result = _oc_run(["apply", "-f", "-"], input_text=json.dumps(obj))
        if result.returncode != 0:
&gt;           raise RuntimeError(f"`oc apply` failed: {result.stderr.strip() or result.stdout.strip()}")
E           RuntimeError: `oc apply` failed: Error from server (InternalError): error when creating "STDIN": Internal error occurred: failed calling webhook "vaitenant.kb.io": failed to call webhook: Post "https://maas-controller-webhook-service.opendatahub.svc:443/validate-maas-opendatahub-io-v1alpha1-aitenant?timeout=10s": EOF

test/e2e/tests/test_aitenant_lifecycle.py:69: RuntimeError</failure></testcase><testcase classname="tests.test_tenant_discovery" name="test_tenant_discovery_authenticated@readonly" time="0.001"><skipped type="pytest.skip" message="Skipping when Gateway uses ClusterIP + OpenShift Route (unsupported configuration). This mixes incompatible routing paradigms. Gateway has no external hostname in spec.listeners, so /v1/tenants returns an error. Supported configuration: LoadBalancer service with hostname in spec.listeners.">/workspace/source/test/e2e/tests/test_tenant_discovery.py:79: Skipping when Gateway uses ClusterIP + OpenShift Route (unsupported configuration). This mixes incompatible routing paradigms. Gateway has no external hostname in spec.listeners, so /v1/tenants returns an error. Supported configuration: LoadBalancer service with hostname in spec.listeners.</skipped></testcase><testcase classname="tests.test_tenant_discovery" name="test_tenant_discovery_gateway_matches_deployment@readonly" time="0.000"><skipped type="pytest.skip" message="Skipping when Gateway uses ClusterIP + OpenShift Route (unsupported configuration). This mixes incompatible routing paradigms. Gateway has no external hostname in spec.listeners, so /v1/tenants returns an error. Supported configuration: LoadBalancer service with hostname in spec.listeners.">/workspace/source/test/e2e/tests/test_tenant_discovery.py:155: Skipping when Gateway uses ClusterIP + OpenShift Route (unsupported configuration). This mixes incompatible routing paradigms. Gateway has no external hostname in spec.listeners, so /v1/tenants returns an error. Supported configuration: LoadBalancer service with hostname in spec.listeners.</skipped></testcase><testcase classname="tests.test_tenant_discovery" name="test_tenant_discovery_not_exposed_through_gateway@readonly" time="0.028" /><testcase classname="tests.test_tenant_auto_resolve.TestTenantAutoResolve" name="test_auto_resolve_populates_resolved_tenant_ref@tenant_auto_resolve" time="8.966"><failure message="RuntimeError: `oc apply` failed: Error from server (InternalError): error when creating &quot;STDIN&quot;: Internal error occurred: failed calling webhook &quot;vaitenant.kb.io&quot;: failed to call webhook: Post &quot;https://maas-controller-webhook-service.opendatahub.svc:443/validate-maas-opendatahub-io-v1alpha1-aitenant?timeout=10s&quot;: EOF">self = &lt;test_tenant_auto_resolve.TestTenantAutoResolve object at 0x7f13d486e520&gt;

    def test_auto_resolve_populates_resolved_tenant_ref(self):
        """When tenantRef is omitted, resolvedTenantRef is populated from the gateway."""
        case = new_named_tenant_case("e2e-autores")
        model_name = f"autores-model-{case['suffix']}"
        try:
&gt;           bootstrap_aitenant_tenant(case)

test/e2e/tests/test_tenant_auto_resolve.py:91: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
test/e2e/tests/multitenancy_helpers.py:783: in bootstrap_aitenant_tenant
    apply_aitenant(case)
test/e2e/tests/multitenancy_helpers.py:742: in apply_aitenant
    _apply(
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

obj = {'apiVersion': 'maas.opendatahub.io/v1alpha1', 'kind': 'AITenant', 'metadata': {'name': 'e2e-autores-4454b7', 'namespace': 'ai-tenants'}, 'spec': {'gateway': {'name': 'e2e-autores-4454b7'}}}

    def _apply(obj: dict) -&gt; None:
        result = _oc_run(["apply", "-f", "-"], input_text=json.dumps(obj))
        if result.returncode != 0:
&gt;           raise RuntimeError(f"`oc apply` failed: {result.stderr.strip() or result.stdout.strip()}")
E           RuntimeError: `oc apply` failed: Error from server (InternalError): error when creating "STDIN": Internal error occurred: failed calling webhook "vaitenant.kb.io": failed to call webhook: Post "https://maas-controller-webhook-service.opendatahub.svc:443/validate-maas-opendatahub-io-v1alpha1-aitenant?timeout=10s": EOF

test/e2e/tests/multitenancy_helpers.py:155: RuntimeError</failure></testcase><testcase classname="tests.test_negative_security.TestMissingModelRef" name="test_subscription_with_nonexistent_model_ref@security" time="5.666"><failure message="subprocess.CalledProcessError: Command '['oc', 'apply', '-f', '-']' returned non-zero exit status 1.">self = &lt;test_negative_security.TestMissingModelRef object at 0x7f050aaf1670&gt;

    def test_subscription_with_nonexistent_model_ref(self):
        """MaaSSubscription generates TRLP only for valid model, not ghost model.
    
        Creates a subscription referencing one valid model and one ghost model,
        waits for Degraded phase, then asserts that a TRLP exists for the valid
        model but not for the ghost model.
        """
        suffix = uuid.uuid4().hex[:8]
        sub_name = f"e2e-neg-ghost-sub-{suffix}"
        auth_name = f"e2e-neg-ghost-sub-auth-{suffix}"
        ghost_model = f"nonexistent-model-{suffix}"
    
        try:
&gt;           _create_test_auth_policy(auth_name, MODEL_REF, groups=["system:authenticated"])

test/e2e/tests/test_negative_security.py:514: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
test/e2e/tests/test_helper.py:908: in _create_test_auth_policy
    _apply_cr({
test/e2e/tests/test_helper.py:620: in _apply_cr
    subprocess.run(["oc", "apply", "-f", "-"], input=json.dumps(cr_dict), capture_output=True, text=True, check=True)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

input = '{"apiVersion": "maas.opendatahub.io/v1alpha1", "kind": "MaaSAuthPolicy", "metadata": {"name": "e2e-neg-ghost-sub-auth...k-opt-125m-simulated", "namespace": "llm"}], "subjects": {"users": [], "groups": [{"name": "system:authenticated"}]}}}'
capture_output = True, timeout = None, check = True
popenargs = (['oc', 'apply', '-f', '-'],)
kwargs = {'stderr': -1, 'stdin': -1, 'stdout': -1, 'text': True}
process = &lt;Popen: returncode: 1 args: ['oc', 'apply', '-f', '-']&gt;, stdout = ''
stderr = 'Error from server (InternalError): error when creating "STDIN": Internal error occurred: failed calling webhook "vmaa...ontroller-webhook-service.opendatahub.svc:443/validate-maas-opendatahub-io-v1alpha1-maasauthpolicy?timeout=10s": EOF\n'
retcode = 1

    def run(*popenargs,
            input=None, capture_output=False, timeout=None, check=False, **kwargs):
        """Run command with arguments and return a CompletedProcess instance.
    
        The returned instance will have attributes args, returncode, stdout and
        stderr. By default, stdout and stderr are not captured, and those attributes
        will be None. Pass stdout=PIPE and/or stderr=PIPE in order to capture them.
    
        If check is True and the exit code was non-zero, it raises a
        CalledProcessError. The CalledProcessError object will have the return code
        in the returncode attribute, and output &amp; stderr attributes if those streams
        were captured.
    
        If timeout is given, and the process takes too long, a TimeoutExpired
        exception will be raised.
    
        There is an optional argument "input", allowing you to
        pass bytes or a string to the subprocess's stdin.  If you use this argument
        you may not also use the Popen constructor's "stdin" argument, as
        it will be used internally.
    
        By default, all communication is in bytes, and therefore any "input" should
        be bytes, and the stdout and stderr will be bytes. If in text mode, any
        "input" should be a string, and stdout and stderr will be strings decoded
        according to locale encoding, or by "encoding" if set. Text mode is
        triggered by setting any of text, encoding, errors or universal_newlines.
    
        The other arguments are the same as for the Popen constructor.
        """
        if input is not None:
            if kwargs.get('stdin') is not None:
                raise ValueError('stdin and input arguments may not both be used.')
            kwargs['stdin'] = PIPE
    
        if capture_output:
            if kwargs.get('stdout') is not None or kwargs.get('stderr') is not None:
                raise ValueError('stdout and stderr arguments may not be used '
                                 'with capture_output.')
            kwargs['stdout'] = PIPE
            kwargs['stderr'] = PIPE
    
        with Popen(*popenargs, **kwargs) as process:
            try:
                stdout, stderr = process.communicate(input, timeout=timeout)
            except TimeoutExpired as exc:
                process.kill()
                if _mswindows:
                    # Windows accumulates the output in a single blocking
                    # read() call run on child threads, with the timeout
                    # being done in a join() on those threads.  communicate()
                    # _after_ kill() is required to collect that and add it
                    # to the exception.
                    exc.stdout, exc.stderr = process.communicate()
                else:
                    # POSIX _communicate already populated the output so
                    # far into the TimeoutExpired exception.
                    process.wait()
                raise
            except:  # Including KeyboardInterrupt, communicate handled that.
                process.kill()
                # We don't call process.wait() as .__exit__ does that for us.
                raise
            retcode = process.poll()
            if check and retcode:
&gt;               raise CalledProcessError(retcode, process.args,
                                         output=stdout, stderr=stderr)
E               subprocess.CalledProcessError: Command '['oc', 'apply', '-f', '-']' returned non-zero exit status 1.

/usr/lib64/python3.9/subprocess.py:528: CalledProcessError</failure></testcase><testcase classname="tests.test_negative_security.TestMissingModelRef" name="test_authpolicy_with_nonexistent_model_ref@security" time="0.258"><failure message="subprocess.CalledProcessError: Command '['oc', 'apply', '-f', '-']' returned non-zero exit status 1.">self = &lt;test_negative_security.TestMissingModelRef object at 0x7f050aaf18b0&gt;

    def test_authpolicy_with_nonexistent_model_ref(self):
        """MaaSAuthPolicy does not generate per-model AuthPolicies in gateway-only mode.
    
        Creates an auth policy referencing one valid model and one ghost model,
        waits for Degraded phase, then asserts that no legacy per-model
        AuthPolicies exist for either model.
        """
        suffix = uuid.uuid4().hex[:8]
        policy_name = f"e2e-neg-ghost-policy-{suffix}"
        ghost_model = f"nonexistent-model-{suffix}"
    
        try:
&gt;           _create_test_auth_policy(
                policy_name,
                [MODEL_REF, ghost_model],
                groups=["system:authenticated"],
            )

test/e2e/tests/test_negative_security.py:555: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
test/e2e/tests/test_helper.py:908: in _create_test_auth_policy
    _apply_cr({
test/e2e/tests/test_helper.py:620: in _apply_cr
    subprocess.run(["oc", "apply", "-f", "-"], input=json.dumps(cr_dict), capture_output=True, text=True, check=True)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

input = '{"apiVersion": "maas.opendatahub.io/v1alpha1", "kind": "MaaSAuthPolicy", "metadata": {"name": "e2e-neg-ghost-policy-3...stent-model-332227cd", "namespace": "llm"}], "subjects": {"users": [], "groups": [{"name": "system:authenticated"}]}}}'
capture_output = True, timeout = None, check = True
popenargs = (['oc', 'apply', '-f', '-'],)
kwargs = {'stderr': -1, 'stdin': -1, 'stdout': -1, 'text': True}
process = &lt;Popen: returncode: 1 args: ['oc', 'apply', '-f', '-']&gt;, stdout = ''
stderr = 'Error from server (InternalError): error when creating "STDIN": Internal error occurred: failed calling webhook "vmaa...3/validate-maas-opendatahub-io-v1alpha1-maasauthpolicy?timeout=10s": http: server gave HTTP response to HTTPS client\n'
retcode = 1

    def run(*popenargs,
            input=None, capture_output=False, timeout=None, check=False, **kwargs):
        """Run command with arguments and return a CompletedProcess instance.
    
        The returned instance will have attributes args, returncode, stdout and
        stderr. By default, stdout and stderr are not captured, and those attributes
        will be None. Pass stdout=PIPE and/or stderr=PIPE in order to capture them.
    
        If check is True and the exit code was non-zero, it raises a
        CalledProcessError. The CalledProcessError object will have the return code
        in the returncode attribute, and output &amp; stderr attributes if those streams
        were captured.
    
        If timeout is given, and the process takes too long, a TimeoutExpired
        exception will be raised.
    
        There is an optional argument "input", allowing you to
        pass bytes or a string to the subprocess's stdin.  If you use this argument
        you may not also use the Popen constructor's "stdin" argument, as
        it will be used internally.
    
        By default, all communication is in bytes, and therefore any "input" should
        be bytes, and the stdout and stderr will be bytes. If in text mode, any
        "input" should be a string, and stdout and stderr will be strings decoded
        according to locale encoding, or by "encoding" if set. Text mode is
        triggered by setting any of text, encoding, errors or universal_newlines.
    
        The other arguments are the same as for the Popen constructor.
        """
        if input is not None:
            if kwargs.get('stdin') is not None:
                raise ValueError('stdin and input arguments may not both be used.')
            kwargs['stdin'] = PIPE
    
        if capture_output:
            if kwargs.get('stdout') is not None or kwargs.get('stderr') is not None:
                raise ValueError('stdout and stderr arguments may not be used '
                                 'with capture_output.')
            kwargs['stdout'] = PIPE
            kwargs['stderr'] = PIPE
    
        with Popen(*popenargs, **kwargs) as process:
            try:
                stdout, stderr = process.communicate(input, timeout=timeout)
            except TimeoutExpired as exc:
                process.kill()
                if _mswindows:
                    # Windows accumulates the output in a single blocking
                    # read() call run on child threads, with the timeout
                    # being done in a join() on those threads.  communicate()
                    # _after_ kill() is required to collect that and add it
                    # to the exception.
                    exc.stdout, exc.stderr = process.communicate()
                else:
                    # POSIX _communicate already populated the output so
                    # far into the TimeoutExpired exception.
                    process.wait()
                raise
            except:  # Including KeyboardInterrupt, communicate handled that.
                process.kill()
                # We don't call process.wait() as .__exit__ does that for us.
                raise
            retcode = process.poll()
            if check and retcode:
&gt;               raise CalledProcessError(retcode, process.args,
                                         output=stdout, stderr=stderr)
E               subprocess.CalledProcessError: Command '['oc', 'apply', '-f', '-']' returned non-zero exit status 1.

/usr/lib64/python3.9/subprocess.py:528: CalledProcessError</failure></testcase><testcase classname="tests.test_aitenant_lifecycle.TestAITenantLifecycle" name="test_aitenant_migrates_and_removes_legacy_tenant@mt_lifecycle" time="2.579"><failure message="RuntimeError: `oc apply` failed: Error from server (InternalError): error when creating &quot;STDIN&quot;: Internal error occurred: failed calling webhook &quot;vaitenant.kb.io&quot;: failed to call webhook: Post &quot;https://maas-controller-webhook-service.opendatahub.svc:443/validate-maas-opendatahub-io-v1alpha1-aitenant?timeout=10s&quot;: no endpoints available for service &quot;maas-controller-webhook-service&quot;">self = &lt;test_aitenant_lifecycle.TestAITenantLifecycle object at 0x7f6bbc4bafa0&gt;

    def test_aitenant_migrates_and_removes_legacy_tenant(self):
        if not _crd_exists(LEGACY_TENANT_CRD):
            pytest.skip(f"Missing CRD {LEGACY_TENANT_CRD}; legacy Tenant migration test is not applicable")
    
        suffix = uuid.uuid4().hex[:8]
        aitenant_name = f"e2e-migrate-{suffix}"
        tenant_ns = f"ai-tenant-{aitenant_name}"
        gateway_name = f"{aitenant_name}-gw"
        max_expiration_days = 37
    
        try:
            _apply({"apiVersion": "v1", "kind": "Namespace", "metadata": {"name": tenant_ns}})
            _apply_gateway_fixture({"gateway_name": gateway_name, "aitenant_name": aitenant_name})
            _apply(
                {
                    "apiVersion": "maas.opendatahub.io/v1alpha1",
                    "kind": "Tenant",
                    "metadata": {
                        "name": TENANT_NAME,
                        "namespace": tenant_ns,
                    },
                    "spec": {
                        "gatewayRef": {
                            "namespace": GATEWAY_NAMESPACE,
                            "name": gateway_name,
                        },
                        "apiKeys": {
                            "maxExpirationDays": max_expiration_days,
                        },
                        "externalOIDC": {
                            "issuerUrl": "https://issuer.example.com/realms/e2e",
                            "clientId": "e2e-client",
                            "ttl": 600,
                        },
                        "telemetry": {
                            "enabled": False,
                            "metrics": {
                                "captureOrganization": False,
                                "captureUser": True,
                                "captureGroup": True,
                                "captureModelUsage": False,
                            },
                        },
                    },
                }
            )
&gt;           _apply_aitenant(
                {
                    "aitenant_name": aitenant_name,
                    "tenant_ns": tenant_ns,
                    "gateway_name": gateway_name,
                }
            )

test/e2e/tests/test_aitenant_lifecycle.py:472: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
test/e2e/tests/test_aitenant_lifecycle.py:191: in _apply_aitenant
    _apply(
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

obj = {'apiVersion': 'maas.opendatahub.io/v1alpha1', 'kind': 'AITenant', 'metadata': {'name': 'e2e-migrate-fbdf5841', 'namespace': 'ai-tenants'}, 'spec': {}}

    def _apply(obj):
        result = _oc_run(["apply", "-f", "-"], input_text=json.dumps(obj))
        if result.returncode != 0:
&gt;           raise RuntimeError(f"`oc apply` failed: {result.stderr.strip() or result.stdout.strip()}")
E           RuntimeError: `oc apply` failed: Error from server (InternalError): error when creating "STDIN": Internal error occurred: failed calling webhook "vaitenant.kb.io": failed to call webhook: Post "https://maas-controller-webhook-service.opendatahub.svc:443/validate-maas-opendatahub-io-v1alpha1-aitenant?timeout=10s": no endpoints available for service "maas-controller-webhook-service"

test/e2e/tests/test_aitenant_lifecycle.py:69: RuntimeError</failure></testcase><testcase classname="tests.test_negative_security.TestHeaderAbuse" name="test_special_characters_in_subscription_header@security" time="0.327" /><testcase classname="tests.test_api_keys.TestAPIKeyBulkOperations" name="test_bulk_revoke_missing_scope_returns_400@api_keys" time="0.040" /><testcase classname="tests.test_api_keys.TestAPIKeyExpiration" name="test_create_key_within_expiration_limit@api_keys" time="0.034" /><testcase classname="tests.test_api_keys.TestAPIKeyExpiration" name="test_create_key_at_expiration_limit@api_keys" time="0.034" /><testcase classname="tests.test_api_keys.TestAPIKeyExpiration" name="test_create_key_exceeds_expiration_limit@api_keys" time="0.031" /><testcase classname="tests.test_api_keys.TestAPIKeyExpiration" name="test_create_key_without_expiration@api_keys" time="0.037" /><testcase classname="tests.test_api_keys.TestAPIKeyExpiration" name="test_create_key_with_short_expiration@api_keys" time="0.038" /><testcase classname="tests.test_negative_security.TestWebhookValidation" name="test_subscription_rejected_in_unlabeled_namespace@security" time="6.819"><failure message="AssertionError: Expected webhook rejection, got: Error from server (InternalError): error when creating &quot;STDIN&quot;: Internal error occurred: failed calling webhook &quot;vmaassubscription.kb.io&quot;: failed to call webhook: Post &quot;https://maas-controller-webhook-service.opendatahub.svc:443/validate-maas-opendatahub-io-v1alpha1-maassubscription?timeout=10s&quot;: no endpoints available for service &quot;maas-controller-webhook-service&quot;&#10;  &#10;assert 'admission webhook' in 'error from server (internalerror): error when creating &quot;stdin&quot;: internal error occurred: failed calling webhook &quot;vmaassubscription.kb.io&quot;: failed to call webhook: post &quot;https://maas-controller-webhook-service.opendatahub.svc:443/validate-maas-opendatahub-io-v1alpha1-maassubscription?timeout=10s&quot;: no endpoints available for service &quot;maas-controller-webhook-service&quot;\n'&#10; +  where 'error from server (internalerror): error when creating &quot;stdin&quot;: internal error occurred: failed calling webhook &quot;vmaassubscription.kb.io&quot;: failed to call webhook: post &quot;https://maas-controller-webhook-service.opendatahub.svc:443/validate-maas-opendatahub-io-v1alpha1-maassubscription?timeout=10s&quot;: no endpoints available for service &quot;maas-controller-webhook-service&quot;\n' = &lt;built-in method lower of str object at 0x7f050a9ff510&gt;()&#10; +    where &lt;built-in method lower of str object at 0x7f050a9ff510&gt; = 'Error from server (InternalError): error when creating &quot;STDIN&quot;: Internal error occurred: failed calling webhook &quot;vmaassubscription.kb.io&quot;: failed to call webhook: Post &quot;https://maas-controller-webhook-service.opendatahub.svc:443/validate-maas-opendatahub-io-v1alpha1-maassubscription?timeout=10s&quot;: no endpoints available for service &quot;maas-controller-webhook-service&quot;\n'.lower&#10; +      where 'Error from server (InternalError): error when creating &quot;STDIN&quot;: Internal error occurred: failed calling webhook &quot;vmaassubscription.kb.io&quot;: failed to call webhook: Post &quot;https://maas-controller-webhook-service.opendatahub.svc:443/validate-maas-opendatahub-io-v1alpha1-maassubscription?timeout=10s&quot;: no endpoints available for service &quot;maas-controller-webhook-service&quot;\n' = CompletedProcess(args=['oc', 'apply', '-f', '-'], returncode=1, stdout='', stderr='Error from server (InternalError): error when creating &quot;STDIN&quot;: Internal error occurred: failed calling webhook &quot;vmaassubscription.kb.io&quot;: failed to call webhook: Post &quot;https://maas-controller-webhook-service.opendatahub.svc:443/validate-maas-opendatahub-io-v1alpha1-maassubscription?timeout=10s&quot;: no endpoints available for service &quot;maas-controller-webhook-service&quot;\n').stderr">self = &lt;test_negative_security.TestWebhookValidation object at 0x7f050aaf1e50&gt;

    def test_subscription_rejected_in_unlabeled_namespace(self):
        """MaaSSubscription create is rejected in namespace without MaasTenantConfig CR.
    
        Webhooks require namespaces to have a MaasTenantConfig CR to contain tenant resources.
        """
        test_ns = f"e2e-webhook-test-{uuid.uuid4().hex[:6]}"
    
        try:
            # Create namespace without MaasTenantConfig CR
            result = subprocess.run(
                ["oc", "create", "namespace", test_ns],
                capture_output=True, text=True, timeout=30
            )
            assert result.returncode == 0, f"Failed to create namespace: {result.stderr}"
    
            # Try to create MaaSSubscription (should be rejected by webhook)
            result = subprocess.run(
                ["oc", "apply", "-f", "-"],
                input=json.dumps({
                    "apiVersion": "maas.opendatahub.io/v1alpha1",
                    "kind": "MaaSSubscription",
                    "metadata": {"name": "test-sub", "namespace": test_ns},
                    "spec": {
                        "owner": {"groups": [{"name": "system:authenticated"}]},
                        "modelRefs": [{
                            "name": MODEL_REF,
                            "namespace": MODEL_NAMESPACE,
                            "tokenRateLimits": [{"limit": 100, "window": "1m"}]
                        }],
                    },
                }),
                capture_output=True, text=True, timeout=30
            )
    
            # Verify webhook rejection
            assert result.returncode != 0, "Expected webhook to reject subscription in namespace without MaasTenantConfig CR"
&gt;           assert "admission webhook" in result.stderr.lower(), \
                f"Expected webhook rejection, got: {result.stderr}"
E               AssertionError: Expected webhook rejection, got: Error from server (InternalError): error when creating "STDIN": Internal error occurred: failed calling webhook "vmaassubscription.kb.io": failed to call webhook: Post "https://maas-controller-webhook-service.opendatahub.svc:443/validate-maas-opendatahub-io-v1alpha1-maassubscription?timeout=10s": no endpoints available for service "maas-controller-webhook-service"
E                 
E               assert 'admission webhook' in 'error from server (internalerror): error when creating "stdin": internal error occurred: failed calling webhook "vmaassubscription.kb.io": failed to call webhook: post "https://maas-controller-webhook-service.opendatahub.svc:443/validate-maas-opendatahub-io-v1alpha1-maassubscription?timeout=10s": no endpoints available for service "maas-controller-webhook-service"\n'
E                +  where 'error from server (internalerror): error when creating "stdin": internal error occurred: failed calling webhook "vmaassubscription.kb.io": failed to call webhook: post "https://maas-controller-webhook-service.opendatahub.svc:443/validate-maas-opendatahub-io-v1alpha1-maassubscription?timeout=10s": no endpoints available for service "maas-controller-webhook-service"\n' = &lt;built-in method lower of str object at 0x7f050a9ff510&gt;()
E                +    where &lt;built-in method lower of str object at 0x7f050a9ff510&gt; = 'Error from server (InternalError): error when creating "STDIN": Internal error occurred: failed calling webhook "vmaassubscription.kb.io": failed to call webhook: Post "https://maas-controller-webhook-service.opendatahub.svc:443/validate-maas-opendatahub-io-v1alpha1-maassubscription?timeout=10s": no endpoints available for service "maas-controller-webhook-service"\n'.lower
E                +      where 'Error from server (InternalError): error when creating "STDIN": Internal error occurred: failed calling webhook "vmaassubscription.kb.io": failed to call webhook: Post "https://maas-controller-webhook-service.opendatahub.svc:443/validate-maas-opendatahub-io-v1alpha1-maassubscription?timeout=10s": no endpoints available for service "maas-controller-webhook-service"\n' = CompletedProcess(args=['oc', 'apply', '-f', '-'], returncode=1, stdout='', stderr='Error from server (InternalError): error when creating "STDIN": Internal error occurred: failed calling webhook "vmaassubscription.kb.io": failed to call webhook: Post "https://maas-controller-webhook-service.opendatahub.svc:443/validate-maas-opendatahub-io-v1alpha1-maassubscription?timeout=10s": no endpoints available for service "maas-controller-webhook-service"\n').stderr

test/e2e/tests/test_negative_security.py:657: AssertionError</failure></testcase><testcase classname="tests.test_api_keys.TestAPIKeyModelInference" name="test_api_key_model_access_success@api_keys" time="0.114" /><testcase classname="tests.test_api_keys.TestAPIKeyModelInference" name="test_invalid_api_key_rejected@api_keys" time="0.029" /><testcase classname="tests.test_api_keys.TestAPIKeyModelInference" name="test_no_auth_header_rejected@api_keys" time="0.026" /><testcase classname="tests.test_api_keys.TestAPIKeyModelInference" name="test_revoked_api_key_rejected@api_keys" time="2.136" /><testcase classname="tests.test_tenant_auto_resolve.TestTenantAutoResolve" name="test_explicit_tenant_ref_preserved@tenant_auto_resolve" time="3.380"><failure message="RuntimeError: `oc apply` failed: Error from server (InternalError): error when creating &quot;STDIN&quot;: Internal error occurred: failed calling webhook &quot;vaitenant.kb.io&quot;: failed to call webhook: Post &quot;https://maas-controller-webhook-service.opendatahub.svc:443/validate-maas-opendatahub-io-v1alpha1-aitenant?timeout=10s&quot;: no endpoints available for service &quot;maas-controller-webhook-service&quot;">self = &lt;test_tenant_auto_resolve.TestTenantAutoResolve object at 0x7f13d4887850&gt;

    def test_explicit_tenant_ref_preserved(self):
        """When tenantRef is set explicitly, resolvedTenantRef reflects the explicit value."""
        case = new_named_tenant_case("e2e-explicit")
        model_name = f"explicit-model-{case['suffix']}"
        try:
&gt;           bootstrap_aitenant_tenant(case)

test/e2e/tests/test_tenant_auto_resolve.py:127: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
test/e2e/tests/multitenancy_helpers.py:783: in bootstrap_aitenant_tenant
    apply_aitenant(case)
test/e2e/tests/multitenancy_helpers.py:742: in apply_aitenant
    _apply(
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

obj = {'apiVersion': 'maas.opendatahub.io/v1alpha1', 'kind': 'AITenant', 'metadata': {'name': 'e2e-explicit-bae22d', 'namespace': 'ai-tenants'}, 'spec': {'gateway': {'name': 'e2e-explicit-bae22d'}}}

    def _apply(obj: dict) -&gt; None:
        result = _oc_run(["apply", "-f", "-"], input_text=json.dumps(obj))
        if result.returncode != 0:
&gt;           raise RuntimeError(f"`oc apply` failed: {result.stderr.strip() or result.stdout.strip()}")
E           RuntimeError: `oc apply` failed: Error from server (InternalError): error when creating "STDIN": Internal error occurred: failed calling webhook "vaitenant.kb.io": failed to call webhook: Post "https://maas-controller-webhook-service.opendatahub.svc:443/validate-maas-opendatahub-io-v1alpha1-aitenant?timeout=10s": no endpoints available for service "maas-controller-webhook-service"

test/e2e/tests/multitenancy_helpers.py:155: RuntimeError</failure></testcase><testcase classname="tests.test_aitenant_lifecycle.TestAITenantLifecycle" name="test_aitenant_delete_cleans_maas_resources_and_preserves_user_objects@mt_lifecycle" time="4.689"><failure message="RuntimeError: `oc apply` failed: Error from server (InternalError): error when creating &quot;STDIN&quot;: Internal error occurred: failed calling webhook &quot;vaitenant.kb.io&quot;: failed to call webhook: Post &quot;https://maas-controller-webhook-service.opendatahub.svc:443/validate-maas-opendatahub-io-v1alpha1-aitenant?timeout=10s&quot;: no endpoints available for service &quot;maas-controller-webhook-service&quot;">self = &lt;test_aitenant_lifecycle.TestAITenantLifecycle object at 0x7f6bbc3d95b0&gt;

    def test_aitenant_delete_cleans_maas_resources_and_preserves_user_objects(self):
        case = _new_aitenant_case()
    
        try:
            _apply_gateway_fixture(case)
&gt;           _apply_aitenant(case)

test/e2e/tests/test_aitenant_lifecycle.py:541: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
test/e2e/tests/test_aitenant_lifecycle.py:191: in _apply_aitenant
    _apply(
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

obj = {'apiVersion': 'maas.opendatahub.io/v1alpha1', 'kind': 'AITenant', 'metadata': {'name': 'e2e-ait-f7fc2b9f', 'namespace': 'ai-tenants'}, 'spec': {}}

    def _apply(obj):
        result = _oc_run(["apply", "-f", "-"], input_text=json.dumps(obj))
        if result.returncode != 0:
&gt;           raise RuntimeError(f"`oc apply` failed: {result.stderr.strip() or result.stdout.strip()}")
E           RuntimeError: `oc apply` failed: Error from server (InternalError): error when creating "STDIN": Internal error occurred: failed calling webhook "vaitenant.kb.io": failed to call webhook: Post "https://maas-controller-webhook-service.opendatahub.svc:443/validate-maas-opendatahub-io-v1alpha1-aitenant?timeout=10s": no endpoints available for service "maas-controller-webhook-service"

test/e2e/tests/test_aitenant_lifecycle.py:69: RuntimeError</failure></testcase><testcase classname="tests.test_api_keys.TestAPIKeyModelInference" name="test_api_key_chat_completions@api_keys" time="0.039" /><testcase classname="tests.test_api_keys.TestAPIKeyRevocationE2E" name="test_double_revoke_returns_404@api_keys" time="0.106" /><testcase classname="tests.test_api_keys.TestAPIKeyRevocationE2E" name="test_revoke_nonexistent_key_returns_404@api_keys" time="0.032" /><testcase classname="tests.test_api_keys.TestAPIKeyRevocationE2E" name="test_revoke_then_create_new_key_works@api_keys" time="0.173" /><testcase classname="tests.test_api_keys.TestAPIKeyRevocationE2E" name="test_individual_revoke_multiple_keys@api_keys" time="0.224" /><testcase classname="tests.test_api_keys.TestAPIKeyRevocationE2E" name="test_revoke_keys_rejected_at_gateway@api_keys" time="0.331" /><testcase classname="tests.test_api_keys.TestEphemeralKeyCleanup" name="test_cronjob_exists_and_configured@api_keys" time="0.114" /><testcase classname="tests.test_api_keys.TestEphemeralKeyCleanup" name="test_cleanup_networkpolicy_exists@api_keys" time="0.115" /><testcase classname="tests.test_api_keys.TestEphemeralKeyCleanup" name="test_create_ephemeral_key@api_keys" time="0.115" /><testcase classname="tests.test_api_keys.TestEphemeralKeyCleanup" name="test_trigger_cleanup_preserves_active_keys@api_keys" time="0.461" /><testcase classname="tests.test_tenant_auto_resolve.TestTenantAutoResolve" name="test_no_matching_tenant_enters_failed@tenant_auto_resolve" time="147.775" /><testcase classname="tests.test_api_keys.TestAPIKeySubscriptionPhases" name="test_create_key_for_active_subscription@api_keys" time="0.921"><failure message="subprocess.CalledProcessError: Command '['oc', 'apply', '-f', '-']' returned non-zero exit status 1.">self = &lt;test_api_keys.TestAPIKeySubscriptionPhases object at 0x7f69910d6490&gt;

    def test_create_key_for_active_subscription(self):
        """API key creation succeeds for Active subscription."""
        ns = _ns()
        subscription_name = "e2e-apikey-active-sub"
        auth_name = "e2e-apikey-active-auth"
        sa_name = "e2e-apikey-active-sa"
    
        try:
            oc_token = _create_sa_token(sa_name, namespace=MODEL_NAMESPACE)
            sa_user = _sa_to_user(sa_name, namespace=MODEL_NAMESPACE)
    
&gt;           _create_test_auth_policy(auth_name, MODEL_REF, users=[sa_user])

test/e2e/tests/test_api_keys.py:1398: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
test/e2e/tests/test_helper.py:908: in _create_test_auth_policy
    _apply_cr({
test/e2e/tests/test_helper.py:620: in _apply_cr
    subprocess.run(["oc", "apply", "-f", "-"], input=json.dumps(cr_dict), capture_output=True, text=True, check=True)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

input = '{"apiVersion": "maas.opendatahub.io/v1alpha1", "kind": "MaaSAuthPolicy", "metadata": {"name": "e2e-apikey-active-auth...ated", "namespace": "llm"}], "subjects": {"users": ["system:serviceaccount:llm:e2e-apikey-active-sa"], "groups": []}}}'
capture_output = True, timeout = None, check = True
popenargs = (['oc', 'apply', '-f', '-'],)
kwargs = {'stderr': -1, 'stdin': -1, 'stdout': -1, 'text': True}
process = &lt;Popen: returncode: 1 args: ['oc', 'apply', '-f', '-']&gt;, stdout = ''
stderr = 'Error from server (InternalError): error when creating "STDIN": Internal error occurred: failed calling webhook "vmaa...atahub-io-v1alpha1-maasauthpolicy?timeout=10s": no endpoints available for service "maas-controller-webhook-service"\n'
retcode = 1

    def run(*popenargs,
            input=None, capture_output=False, timeout=None, check=False, **kwargs):
        """Run command with arguments and return a CompletedProcess instance.
    
        The returned instance will have attributes args, returncode, stdout and
        stderr. By default, stdout and stderr are not captured, and those attributes
        will be None. Pass stdout=PIPE and/or stderr=PIPE in order to capture them.
    
        If check is True and the exit code was non-zero, it raises a
        CalledProcessError. The CalledProcessError object will have the return code
        in the returncode attribute, and output &amp; stderr attributes if those streams
        were captured.
    
        If timeout is given, and the process takes too long, a TimeoutExpired
        exception will be raised.
    
        There is an optional argument "input", allowing you to
        pass bytes or a string to the subprocess's stdin.  If you use this argument
        you may not also use the Popen constructor's "stdin" argument, as
        it will be used internally.
    
        By default, all communication is in bytes, and therefore any "input" should
        be bytes, and the stdout and stderr will be bytes. If in text mode, any
        "input" should be a string, and stdout and stderr will be strings decoded
        according to locale encoding, or by "encoding" if set. Text mode is
        triggered by setting any of text, encoding, errors or universal_newlines.
    
        The other arguments are the same as for the Popen constructor.
        """
        if input is not None:
            if kwargs.get('stdin') is not None:
                raise ValueError('stdin and input arguments may not both be used.')
            kwargs['stdin'] = PIPE
    
        if capture_output:
            if kwargs.get('stdout') is not None or kwargs.get('stderr') is not None:
                raise ValueError('stdout and stderr arguments may not be used '
                                 'with capture_output.')
            kwargs['stdout'] = PIPE
            kwargs['stderr'] = PIPE
    
        with Popen(*popenargs, **kwargs) as process:
            try:
                stdout, stderr = process.communicate(input, timeout=timeout)
            except TimeoutExpired as exc:
                process.kill()
                if _mswindows:
                    # Windows accumulates the output in a single blocking
                    # read() call run on child threads, with the timeout
                    # being done in a join() on those threads.  communicate()
                    # _after_ kill() is required to collect that and add it
                    # to the exception.
                    exc.stdout, exc.stderr = process.communicate()
                else:
                    # POSIX _communicate already populated the output so
                    # far into the TimeoutExpired exception.
                    process.wait()
                raise
            except:  # Including KeyboardInterrupt, communicate handled that.
                process.kill()
                # We don't call process.wait() as .__exit__ does that for us.
                raise
            retcode = process.poll()
            if check and retcode:
&gt;               raise CalledProcessError(retcode, process.args,
                                         output=stdout, stderr=stderr)
E               subprocess.CalledProcessError: Command '['oc', 'apply', '-f', '-']' returned non-zero exit status 1.

/usr/lib64/python3.9/subprocess.py:528: CalledProcessError</failure></testcase><testcase classname="tests.test_api_keys.TestAPIKeySubscriptionPhases" name="test_create_key_for_degraded_subscription@api_keys" time="0.874"><failure message="subprocess.CalledProcessError: Command '['oc', 'apply', '-f', '-']' returned non-zero exit status 1.">self = &lt;test_api_keys.TestAPIKeySubscriptionPhases object at 0x7f69910d6a90&gt;

    def test_create_key_for_degraded_subscription(self):
        """API key creation succeeds for Degraded subscription."""
        ns = _ns()
        subscription_name = "e2e-apikey-degraded-sub"
        auth_name = "e2e-apikey-degraded-auth"
        sa_name = "e2e-apikey-degraded-sa"
        missing_model = "nonexistent-model-apikey"
    
        try:
            oc_token = _create_sa_token(sa_name, namespace=MODEL_NAMESPACE)
            sa_user = _sa_to_user(sa_name, namespace=MODEL_NAMESPACE)
    
&gt;           _create_test_auth_policy(auth_name, MODEL_REF, users=[sa_user])

test/e2e/tests/test_api_keys.py:1435: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
test/e2e/tests/test_helper.py:908: in _create_test_auth_policy
    _apply_cr({
test/e2e/tests/test_helper.py:620: in _apply_cr
    subprocess.run(["oc", "apply", "-f", "-"], input=json.dumps(cr_dict), capture_output=True, text=True, check=True)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

input = '{"apiVersion": "maas.opendatahub.io/v1alpha1", "kind": "MaaSAuthPolicy", "metadata": {"name": "e2e-apikey-degraded-au...ed", "namespace": "llm"}], "subjects": {"users": ["system:serviceaccount:llm:e2e-apikey-degraded-sa"], "groups": []}}}'
capture_output = True, timeout = None, check = True
popenargs = (['oc', 'apply', '-f', '-'],)
kwargs = {'stderr': -1, 'stdin': -1, 'stdout': -1, 'text': True}
process = &lt;Popen: returncode: 1 args: ['oc', 'apply', '-f', '-']&gt;, stdout = ''
stderr = 'Error from server (InternalError): error when creating "STDIN": Internal error occurred: failed calling webhook "vmaa...atahub-io-v1alpha1-maasauthpolicy?timeout=10s": no endpoints available for service "maas-controller-webhook-service"\n'
retcode = 1

    def run(*popenargs,
            input=None, capture_output=False, timeout=None, check=False, **kwargs):
        """Run command with arguments and return a CompletedProcess instance.
    
        The returned instance will have attributes args, returncode, stdout and
        stderr. By default, stdout and stderr are not captured, and those attributes
        will be None. Pass stdout=PIPE and/or stderr=PIPE in order to capture them.
    
        If check is True and the exit code was non-zero, it raises a
        CalledProcessError. The CalledProcessError object will have the return code
        in the returncode attribute, and output &amp; stderr attributes if those streams
        were captured.
    
        If timeout is given, and the process takes too long, a TimeoutExpired
        exception will be raised.
    
        There is an optional argument "input", allowing you to
        pass bytes or a string to the subprocess's stdin.  If you use this argument
        you may not also use the Popen constructor's "stdin" argument, as
        it will be used internally.
    
        By default, all communication is in bytes, and therefore any "input" should
        be bytes, and the stdout and stderr will be bytes. If in text mode, any
        "input" should be a string, and stdout and stderr will be strings decoded
        according to locale encoding, or by "encoding" if set. Text mode is
        triggered by setting any of text, encoding, errors or universal_newlines.
    
        The other arguments are the same as for the Popen constructor.
        """
        if input is not None:
            if kwargs.get('stdin') is not None:
                raise ValueError('stdin and input arguments may not both be used.')
            kwargs['stdin'] = PIPE
    
        if capture_output:
            if kwargs.get('stdout') is not None or kwargs.get('stderr') is not None:
                raise ValueError('stdout and stderr arguments may not be used '
                                 'with capture_output.')
            kwargs['stdout'] = PIPE
            kwargs['stderr'] = PIPE
    
        with Popen(*popenargs, **kwargs) as process:
            try:
                stdout, stderr = process.communicate(input, timeout=timeout)
            except TimeoutExpired as exc:
                process.kill()
                if _mswindows:
                    # Windows accumulates the output in a single blocking
                    # read() call run on child threads, with the timeout
                    # being done in a join() on those threads.  communicate()
                    # _after_ kill() is required to collect that and add it
                    # to the exception.
                    exc.stdout, exc.stderr = process.communicate()
                else:
                    # POSIX _communicate already populated the output so
                    # far into the TimeoutExpired exception.
                    process.wait()
                raise
            except:  # Including KeyboardInterrupt, communicate handled that.
                process.kill()
                # We don't call process.wait() as .__exit__ does that for us.
                raise
            retcode = process.poll()
            if check and retcode:
&gt;               raise CalledProcessError(retcode, process.args,
                                         output=stdout, stderr=stderr)
E               subprocess.CalledProcessError: Command '['oc', 'apply', '-f', '-']' returned non-zero exit status 1.

/usr/lib64/python3.9/subprocess.py:528: CalledProcessError</failure></testcase><testcase classname="tests.test_api_keys.TestAPIKeySubscriptionPhases" name="test_create_key_for_failed_subscription@api_keys" time="0.929"><failure message="subprocess.CalledProcessError: Command '['oc', 'apply', '-f', '-']' returned non-zero exit status 1.">self = &lt;test_api_keys.TestAPIKeySubscriptionPhases object at 0x7f69910d67c0&gt;

    def test_create_key_for_failed_subscription(self):
        """API key creation is rejected for Failed subscription to prevent key spam."""
        ns = _ns()
        subscription_name = "e2e-apikey-failed-sub"
        auth_name = "e2e-apikey-failed-auth"
        sa_name = "e2e-apikey-failed-sa"
        nonexistent_model = "nonexistent-model-apikey-failed"
    
        try:
            oc_token = _create_sa_token(sa_name, namespace=MODEL_NAMESPACE)
            sa_user = _sa_to_user(sa_name, namespace=MODEL_NAMESPACE)
    
&gt;           _create_test_auth_policy(auth_name, MODEL_REF, users=[sa_user])

test/e2e/tests/test_api_keys.py:1477: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
test/e2e/tests/test_helper.py:908: in _create_test_auth_policy
    _apply_cr({
test/e2e/tests/test_helper.py:620: in _apply_cr
    subprocess.run(["oc", "apply", "-f", "-"], input=json.dumps(cr_dict), capture_output=True, text=True, check=True)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

input = '{"apiVersion": "maas.opendatahub.io/v1alpha1", "kind": "MaaSAuthPolicy", "metadata": {"name": "e2e-apikey-failed-auth...ated", "namespace": "llm"}], "subjects": {"users": ["system:serviceaccount:llm:e2e-apikey-failed-sa"], "groups": []}}}'
capture_output = True, timeout = None, check = True
popenargs = (['oc', 'apply', '-f', '-'],)
kwargs = {'stderr': -1, 'stdin': -1, 'stdout': -1, 'text': True}
process = &lt;Popen: returncode: 1 args: ['oc', 'apply', '-f', '-']&gt;, stdout = ''
stderr = 'Error from server (InternalError): error when creating "STDIN": Internal error occurred: failed calling webhook "vmaa...atahub-io-v1alpha1-maasauthpolicy?timeout=10s": no endpoints available for service "maas-controller-webhook-service"\n'
retcode = 1

    def run(*popenargs,
            input=None, capture_output=False, timeout=None, check=False, **kwargs):
        """Run command with arguments and return a CompletedProcess instance.
    
        The returned instance will have attributes args, returncode, stdout and
        stderr. By default, stdout and stderr are not captured, and those attributes
        will be None. Pass stdout=PIPE and/or stderr=PIPE in order to capture them.
    
        If check is True and the exit code was non-zero, it raises a
        CalledProcessError. The CalledProcessError object will have the return code
        in the returncode attribute, and output &amp; stderr attributes if those streams
        were captured.
    
        If timeout is given, and the process takes too long, a TimeoutExpired
        exception will be raised.
    
        There is an optional argument "input", allowing you to
        pass bytes or a string to the subprocess's stdin.  If you use this argument
        you may not also use the Popen constructor's "stdin" argument, as
        it will be used internally.
    
        By default, all communication is in bytes, and therefore any "input" should
        be bytes, and the stdout and stderr will be bytes. If in text mode, any
        "input" should be a string, and stdout and stderr will be strings decoded
        according to locale encoding, or by "encoding" if set. Text mode is
        triggered by setting any of text, encoding, errors or universal_newlines.
    
        The other arguments are the same as for the Popen constructor.
        """
        if input is not None:
            if kwargs.get('stdin') is not None:
                raise ValueError('stdin and input arguments may not both be used.')
            kwargs['stdin'] = PIPE
    
        if capture_output:
            if kwargs.get('stdout') is not None or kwargs.get('stderr') is not None:
                raise ValueError('stdout and stderr arguments may not be used '
                                 'with capture_output.')
            kwargs['stdout'] = PIPE
            kwargs['stderr'] = PIPE
    
        with Popen(*popenargs, **kwargs) as process:
            try:
                stdout, stderr = process.communicate(input, timeout=timeout)
            except TimeoutExpired as exc:
                process.kill()
                if _mswindows:
                    # Windows accumulates the output in a single blocking
                    # read() call run on child threads, with the timeout
                    # being done in a join() on those threads.  communicate()
                    # _after_ kill() is required to collect that and add it
                    # to the exception.
                    exc.stdout, exc.stderr = process.communicate()
                else:
                    # POSIX _communicate already populated the output so
                    # far into the TimeoutExpired exception.
                    process.wait()
                raise
            except:  # Including KeyboardInterrupt, communicate handled that.
                process.kill()
                # We don't call process.wait() as .__exit__ does that for us.
                raise
            retcode = process.poll()
            if check and retcode:
&gt;               raise CalledProcessError(retcode, process.args,
                                         output=stdout, stderr=stderr)
E               subprocess.CalledProcessError: Command '['oc', 'apply', '-f', '-']' returned non-zero exit status 1.

/usr/lib64/python3.9/subprocess.py:528: CalledProcessError</failure></testcase><testcase classname="tests.test_negative_security.TestWebhookValidation" name="test_authpolicy_rejected_in_unlabeled_namespace@security" time="6.387"><failure message="AssertionError: Expected webhook rejection, got: Error from server (InternalError): error when creating &quot;STDIN&quot;: Internal error occurred: failed calling webhook &quot;vmaasauthpolicy.kb.io&quot;: failed to call webhook: Post &quot;https://maas-controller-webhook-service.opendatahub.svc:443/validate-maas-opendatahub-io-v1alpha1-maasauthpolicy?timeout=10s&quot;: no endpoints available for service &quot;maas-controller-webhook-service&quot;&#10;  &#10;assert 'admission webhook' in 'error from server (internalerror): error when creating &quot;stdin&quot;: internal error occurred: failed calling webhook &quot;vmaasauthpolicy.kb.io&quot;: failed to call webhook: post &quot;https://maas-controller-webhook-service.opendatahub.svc:443/validate-maas-opendatahub-io-v1alpha1-maasauthpolicy?timeout=10s&quot;: no endpoints available for service &quot;maas-controller-webhook-service&quot;\n'&#10; +  where 'error from server (internalerror): error when creating &quot;stdin&quot;: internal error occurred: failed calling webhook &quot;vmaasauthpolicy.kb.io&quot;: failed to call webhook: post &quot;https://maas-controller-webhook-service.opendatahub.svc:443/validate-maas-opendatahub-io-v1alpha1-maasauthpolicy?timeout=10s&quot;: no endpoints available for service &quot;maas-controller-webhook-service&quot;\n' = &lt;built-in method lower of str object at 0x7f050a9ff6b0&gt;()&#10; +    where &lt;built-in method lower of str object at 0x7f050a9ff6b0&gt; = 'Error from server (InternalError): error when creating &quot;STDIN&quot;: Internal error occurred: failed calling webhook &quot;vmaasauthpolicy.kb.io&quot;: failed to call webhook: Post &quot;https://maas-controller-webhook-service.opendatahub.svc:443/validate-maas-opendatahub-io-v1alpha1-maasauthpolicy?timeout=10s&quot;: no endpoints available for service &quot;maas-controller-webhook-service&quot;\n'.lower&#10; +      where 'Error from server (InternalError): error when creating &quot;STDIN&quot;: Internal error occurred: failed calling webhook &quot;vmaasauthpolicy.kb.io&quot;: failed to call webhook: Post &quot;https://maas-controller-webhook-service.opendatahub.svc:443/validate-maas-opendatahub-io-v1alpha1-maasauthpolicy?timeout=10s&quot;: no endpoints available for service &quot;maas-controller-webhook-service&quot;\n' = CompletedProcess(args=['oc', 'apply', '-f', '-'], returncode=1, stdout='', stderr='Error from server (InternalError): error when creating &quot;STDIN&quot;: Internal error occurred: failed calling webhook &quot;vmaasauthpolicy.kb.io&quot;: failed to call webhook: Post &quot;https://maas-controller-webhook-service.opendatahub.svc:443/validate-maas-opendatahub-io-v1alpha1-maasauthpolicy?timeout=10s&quot;: no endpoints available for service &quot;maas-controller-webhook-service&quot;\n').stderr">self = &lt;test_negative_security.TestWebhookValidation object at 0x7f050aaf90d0&gt;

    def test_authpolicy_rejected_in_unlabeled_namespace(self):
        """MaaSAuthPolicy create is rejected in namespace without MaasTenantConfig CR."""
        test_ns = f"e2e-webhook-test-{uuid.uuid4().hex[:6]}"
    
        try:
            # Create namespace without MaasTenantConfig CR
            result = subprocess.run(
                ["oc", "create", "namespace", test_ns],
                capture_output=True, text=True, timeout=30
            )
            assert result.returncode == 0, f"Failed to create namespace: {result.stderr}"
    
            # Try to create MaaSAuthPolicy (should be rejected by webhook)
            result = subprocess.run(
                ["oc", "apply", "-f", "-"],
                input=json.dumps({
                    "apiVersion": "maas.opendatahub.io/v1alpha1",
                    "kind": "MaaSAuthPolicy",
                    "metadata": {"name": "test-policy", "namespace": test_ns},
                    "spec": {
                        "modelRefs": [{"name": MODEL_REF, "namespace": MODEL_NAMESPACE}],
                        "subjects": {"groups": [{"name": "system:authenticated"}]},
                    },
                }),
                capture_output=True, text=True, timeout=30
            )
    
            # Verify webhook rejection
            assert result.returncode != 0, "Expected webhook to reject auth policy in namespace without MaasTenantConfig CR"
&gt;           assert "admission webhook" in result.stderr.lower(), \
                f"Expected webhook rejection, got: {result.stderr}"
E               AssertionError: Expected webhook rejection, got: Error from server (InternalError): error when creating "STDIN": Internal error occurred: failed calling webhook "vmaasauthpolicy.kb.io": failed to call webhook: Post "https://maas-controller-webhook-service.opendatahub.svc:443/validate-maas-opendatahub-io-v1alpha1-maasauthpolicy?timeout=10s": no endpoints available for service "maas-controller-webhook-service"
E                 
E               assert 'admission webhook' in 'error from server (internalerror): error when creating "stdin": internal error occurred: failed calling webhook "vmaasauthpolicy.kb.io": failed to call webhook: post "https://maas-controller-webhook-service.opendatahub.svc:443/validate-maas-opendatahub-io-v1alpha1-maasauthpolicy?timeout=10s": no endpoints available for service "maas-controller-webhook-service"\n'
E                +  where 'error from server (internalerror): error when creating "stdin": internal error occurred: failed calling webhook "vmaasauthpolicy.kb.io": failed to call webhook: post "https://maas-controller-webhook-service.opendatahub.svc:443/validate-maas-opendatahub-io-v1alpha1-maasauthpolicy?timeout=10s": no endpoints available for service "maas-controller-webhook-service"\n' = &lt;built-in method lower of str object at 0x7f050a9ff6b0&gt;()
E                +    where &lt;built-in method lower of str object at 0x7f050a9ff6b0&gt; = 'Error from server (InternalError): error when creating "STDIN": Internal error occurred: failed calling webhook "vmaasauthpolicy.kb.io": failed to call webhook: Post "https://maas-controller-webhook-service.opendatahub.svc:443/validate-maas-opendatahub-io-v1alpha1-maasauthpolicy?timeout=10s": no endpoints available for service "maas-controller-webhook-service"\n'.lower
E                +      where 'Error from server (InternalError): error when creating "STDIN": Internal error occurred: failed calling webhook "vmaasauthpolicy.kb.io": failed to call webhook: Post "https://maas-controller-webhook-service.opendatahub.svc:443/validate-maas-opendatahub-io-v1alpha1-maasauthpolicy?timeout=10s": no endpoints available for service "maas-controller-webhook-service"\n' = CompletedProcess(args=['oc', 'apply', '-f', '-'], returncode=1, stdout='', stderr='Error from server (InternalError): error when creating "STDIN": Internal error occurred: failed calling webhook "vmaasauthpolicy.kb.io": failed to call webhook: Post "https://maas-controller-webhook-service.opendatahub.svc:443/validate-maas-opendatahub-io-v1alpha1-maasauthpolicy?timeout=10s": no endpoints available for service "maas-controller-webhook-service"\n').stderr

test/e2e/tests/test_negative_security.py:703: AssertionError</failure></testcase><testcase classname="tests.test_aitenant_lifecycle.TestAITenantLifecycle" name="test_aitenant_derives_non_default_tenant_namespace@mt_lifecycle" time="12.191"><failure message="RuntimeError: `oc apply` failed: Error from server (InternalError): error when creating &quot;STDIN&quot;: Internal error occurred: failed calling webhook &quot;vaitenant.kb.io&quot;: failed to call webhook: Post &quot;https://maas-controller-webhook-service.opendatahub.svc:443/validate-maas-opendatahub-io-v1alpha1-aitenant?timeout=10s&quot;: no endpoints available for service &quot;maas-controller-webhook-service&quot;">self = &lt;test_aitenant_lifecycle.TestAITenantLifecycle object at 0x7f6bbc3d9430&gt;

    def test_aitenant_derives_non_default_tenant_namespace(self):
        """RHOAIENG-66836: non-default AITenant must not use models-as-a-service tenant namespace."""
        suffix = uuid.uuid4().hex[:8]
        aitenant_name = f"e2e-derive-{suffix}"
        reserved_ns = _ns()
        expected_ns = f"ai-tenant-{aitenant_name}"
        gateway_name = aitenant_name
    
        try:
            _apply_gateway_fixture({"gateway_name": gateway_name, "aitenant_name": aitenant_name})
&gt;           _apply(
                {
                    "apiVersion": "maas.opendatahub.io/v1alpha1",
                    "kind": "AITenant",
                    "metadata": {"name": aitenant_name, "namespace": AITENANT_NAMESPACE},
                    "spec": {},
                }
            )

test/e2e/tests/test_aitenant_lifecycle.py:602: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

obj = {'apiVersion': 'maas.opendatahub.io/v1alpha1', 'kind': 'AITenant', 'metadata': {'name': 'e2e-derive-79e15b7c', 'namespace': 'ai-tenants'}, 'spec': {}}

    def _apply(obj):
        result = _oc_run(["apply", "-f", "-"], input_text=json.dumps(obj))
        if result.returncode != 0:
&gt;           raise RuntimeError(f"`oc apply` failed: {result.stderr.strip() or result.stdout.strip()}")
E           RuntimeError: `oc apply` failed: Error from server (InternalError): error when creating "STDIN": Internal error occurred: failed calling webhook "vaitenant.kb.io": failed to call webhook: Post "https://maas-controller-webhook-service.opendatahub.svc:443/validate-maas-opendatahub-io-v1alpha1-aitenant?timeout=10s": no endpoints available for service "maas-controller-webhook-service"

test/e2e/tests/test_aitenant_lifecycle.py:69: RuntimeError</failure></testcase><testcase classname="tests.test_api_keys.TestAPIKeySubscriptionFilter" name="test_search_filters_by_subscription@api_keys" time="39.451" /><testcase classname="tests.test_tenant_namespace_discovery.TestTenantNamespaceDiscovery" name="test_labeled_tenant_namespace_is_discovered@mt_lifecycle" time="8.635" /><testcase classname="tests.test_external_models.TestExternalModelDiscovery" name="test_maasmodelref_created@external" time="39.523" /><testcase classname="tests.test_external_models.TestExternalModelDiscovery" name="test_reconciler_created_httproute@external" time="0.124" /><testcase classname="tests.test_external_models.TestExternalModelDiscovery" name="test_reconciler_created_backend_service@external" time="0.114" /><testcase classname="tests.test_external_models.TestExternalModelAuth" name="test_invalid_key_returns_401@external" time="0.041" /><testcase classname="tests.test_external_models.TestExternalModelAuth" name="test_no_key_returns_401@external" time="0.026" /><testcase classname="tests.test_external_models.TestExternalModelEgress" name="test_request_forwarded_returns_200@external" time="0.325" /><testcase classname="tests.test_external_models.TestExternalModelCleanup" name="test_delete_removes_httproute@external" time="12.638" /><testcase classname="tests.test_tenant_namespace_discovery.TestTenantNamespaceDiscovery" name="test_label_removal_stops_reconciliation@mt_lifecycle" time="42.588" /><testcase classname="tests.test_external_models.TestExternalModelPathRouting" name="test_wrong_path_returns_not_found@external" time="0.033" /><testcase classname="tests.test_external_models.TestLegacyExternalModelMigration" name="test_migration_sets_legacy_status_and_removes_networking@external" time="23.786" /><testcase classname="tests.test_api_keys.TestAPIKeySubscriptionFilter" name="test_search_without_subscription_returns_all@api_keys" time="0.330" /><testcase classname="tests.test_api_keys.TestAPIKeyLabels" name="test_create_api_key_with_labels@api_keys" time="0.070" /><testcase classname="tests.test_api_keys.TestAPIKeyLabels" name="test_search_api_keys_by_labels@api_keys" time="0.192" /><testcase classname="tests.test_api_keys.TestAPIKeyLabels" name="test_labels_validation_errors@api_keys" time="0.107" /><testcase classname="tests.test_api_keys.TestAPIKeyLabels" name="test_backward_compatibility_no_labels@api_keys" time="0.071" /><testcase classname="tests.test_subscription.TestAuthEnforcement" name="test_authorized_user_gets_200@api_keys" time="0.080" /><testcase classname="tests.test_subscription.TestAuthEnforcement" name="test_no_auth_gets_401@api_keys" time="0.027" /><testcase classname="tests.test_subscription.TestAuthEnforcement" name="test_invalid_token_gets_403@api_keys" time="0.041" /><testcase classname="tests.test_subscription.TestAuthEnforcement" name="test_wrong_group_gets_403@api_keys" time="0.038" /><testcase classname="tests.test_subscription.TestAPIKeySubscriptionBinding" name="test_create_api_key_uses_highest_priority_subscription@api_keys" time="10.344" /><testcase classname="tests.test_subscription.TestAPIKeySubscriptionBinding" name="test_create_api_key_with_explicit_simulator_subscription@api_keys" time="0.066" /><testcase classname="tests.test_subscription.TestAPIKeySubscriptionBinding" name="test_create_api_key_nonexistent_subscription_errors@api_keys" time="0.254" /><testcase classname="tests.test_subscription.TestSubscriptionEnforcement" name="test_subscribed_user_gets_200@api_keys" time="0.157" /><testcase classname="tests.test_subscription.TestSubscriptionEnforcement" name="test_auth_pass_no_subscription_gets_403@api_keys" time="0.627" /><testcase classname="tests.test_subscription.TestMultipleAuthPoliciesPerModel" name="test_two_auth_policies_or_logic@api_keys" time="1.157" /><testcase classname="tests.test_external_models.TestExternalModelBodyRouting" name="test_correct_model_in_body_succeeds@external" time="0.333" /><testcase classname="tests.test_external_models.TestExternalModelBodyRouting" name="test_wrong_model_in_body_does_not_error@external" time="0.234" /><testcase classname="tests.test_external_models.TestExternalModelBodyRouting" name="test_missing_model_in_body_does_not_error@external" time="1.249" /><testcase classname="tests.test_subscription.TestCascadeDeletion" name="test_unconfigured_model_denied_by_gateway_auth@api_keys" time="0.496" /><testcase classname="tests.test_subscription.TestOrderingEdgeCases" name="test_subscription_before_auth_policy@api_keys" time="1.924" /><testcase classname="tests.test_external_oidc.TestOIDCTokenFlow" name="test_oidc_token_can_create_api_key@external" time="0.000"><skipped type="pytest.skip" message="EXTERNAL_OIDC is not true">/workspace/source/test/e2e/tests/test_external_oidc.py:252: EXTERNAL_OIDC is not true</skipped></testcase><testcase classname="tests.test_external_oidc.TestOIDCTokenFlow" name="test_invalid_oidc_token_gets_401@external" time="0.000"><skipped type="pytest.skip" message="EXTERNAL_OIDC is not true">/workspace/source/test/e2e/tests/test_external_oidc.py:263: EXTERNAL_OIDC is not true</skipped></testcase><testcase classname="tests.test_external_oidc.TestOIDCTokenFlow" name="test_empty_bearer_token_gets_401@external" time="0.000"><skipped type="pytest.skip" message="EXTERNAL_OIDC is not true">/workspace/source/test/e2e/tests/test_external_oidc.py:277: EXTERNAL_OIDC is not true</skipped></testcase><testcase classname="tests.test_external_oidc.TestOIDCTokenFlow" name="test_no_auth_header_gets_401@external" time="0.000"><skipped type="pytest.skip" message="EXTERNAL_OIDC is not true">/workspace/source/test/e2e/tests/test_external_oidc.py:290: EXTERNAL_OIDC is not true</skipped></testcase><testcase classname="tests.test_external_oidc.TestOIDCTokenFlow" name="test_tampered_expired_oidc_token_gets_401@external" time="0.000"><skipped type="pytest.skip" message="EXTERNAL_OIDC is not true">/workspace/source/test/e2e/tests/test_external_oidc.py:303: EXTERNAL_OIDC is not true</skipped></testcase><testcase classname="tests.test_external_oidc.TestOIDCTokenFlow" name="test_real_expired_oidc_token_gets_401@external" time="0.000"><skipped type="pytest.skip" message="EXTERNAL_OIDC is not true">/workspace/source/test/e2e/tests/test_external_oidc.py:335: EXTERNAL_OIDC is not true</skipped></testcase><testcase classname="tests.test_external_oidc.TestOIDCTokenClaims" name="test_token_contains_groups_claim@external" time="0.000"><skipped type="pytest.skip" message="EXTERNAL_OIDC is not true">/workspace/source/test/e2e/tests/test_external_oidc.py:379: EXTERNAL_OIDC is not true</skipped></testcase><testcase classname="tests.test_external_oidc.TestOIDCTokenClaims" name="test_token_contains_preferred_username@external" time="0.000"><skipped type="pytest.skip" message="EXTERNAL_OIDC is not true">/workspace/source/test/e2e/tests/test_external_oidc.py:395: EXTERNAL_OIDC is not true</skipped></testcase><testcase classname="tests.test_external_oidc.TestOIDCTokenClaims" name="test_different_users_have_different_groups@external" time="0.000"><skipped type="pytest.skip" message="EXTERNAL_OIDC is not true">/workspace/source/test/e2e/tests/test_external_oidc.py:405: EXTERNAL_OIDC is not true</skipped></testcase><testcase classname="tests.test_external_oidc.TestOIDCMultiUser" name="test_bob_sre_can_mint_api_key@external" time="0.000"><skipped type="pytest.skip" message="EXTERNAL_OIDC is not true">/workspace/source/test/e2e/tests/test_external_oidc.py:428: EXTERNAL_OIDC is not true</skipped></testcase><testcase classname="tests.test_external_oidc.TestOIDCMultiUser" name="test_wrong_password_gets_rejected@external" time="0.000"><skipped type="pytest.skip" message="EXTERNAL_OIDC is not true">/workspace/source/test/e2e/tests/test_external_oidc.py:436: EXTERNAL_OIDC is not true</skipped></testcase><testcase classname="tests.test_external_oidc.TestOIDCMultiUser" name="test_nonexistent_user_gets_rejected@external" time="0.000"><skipped type="pytest.skip" message="EXTERNAL_OIDC is not true">/workspace/source/test/e2e/tests/test_external_oidc.py:441: EXTERNAL_OIDC is not true</skipped></testcase><testcase classname="tests.test_external_oidc.TestOIDCModelAccess" name="test_minted_api_key_can_list_models_and_infer@external" time="0.000"><skipped type="pytest.skip" message="EXTERNAL_OIDC is not true">/workspace/source/test/e2e/tests/test_external_oidc.py:454: EXTERNAL_OIDC is not true</skipped></testcase><testcase classname="tests.test_external_oidc.TestOIDCModelAccess" name="test_revoked_api_key_cannot_access_models@external" time="0.000"><skipped type="pytest.skip" message="EXTERNAL_OIDC is not true">/workspace/source/test/e2e/tests/test_external_oidc.py:501: EXTERNAL_OIDC is not true</skipped></testcase><testcase classname="tests.test_external_oidc.TestOIDCModelAccess" name="test_oidc_user_without_group_access_gets_empty_list@external" time="0.000"><skipped type="pytest.skip" message="EXTERNAL_OIDC is not true">/workspace/source/test/e2e/tests/test_external_oidc.py:537: EXTERNAL_OIDC is not true</skipped></testcase><testcase classname="tests.test_external_oidc.TestOIDCMultiTenant" name="test_tenant_b_token_rejected_by_maas@external" time="0.000"><skipped type="pytest.skip" message="EXTERNAL_OIDC is not true">/workspace/source/test/e2e/tests/test_external_oidc.py:602: EXTERNAL_OIDC is not true</skipped></testcase><testcase classname="tests.test_external_oidc.TestOIDCMultiTenant" name="test_tenant_a_users_are_isolated@external" time="0.000"><skipped type="pytest.skip" message="EXTERNAL_OIDC is not true">/workspace/source/test/e2e/tests/test_external_oidc.py:633: EXTERNAL_OIDC is not true</skipped></testcase><testcase classname="tests.test_external_oidc.TestOIDCAPIKeyLifecycle" name="test_create_and_revoke_api_key@external" time="0.000"><skipped type="pytest.skip" message="EXTERNAL_OIDC is not true">/workspace/source/test/e2e/tests/test_external_oidc.py:659: EXTERNAL_OIDC is not true</skipped></testcase><testcase classname="tests.test_external_oidc.TestOIDCAPIKeyLifecycle" name="test_api_key_owner_matches_oidc_username@external" time="0.000"><skipped type="pytest.skip" message="EXTERNAL_OIDC is not true">/workspace/source/test/e2e/tests/test_external_oidc.py:690: EXTERNAL_OIDC is not true</skipped></testcase><testcase classname="tests.test_external_oidc.TestOIDCHeaderInjection" name="test_injected_username_header_rejected@external" time="0.000"><skipped type="pytest.skip" message="EXTERNAL_OIDC is not true">/workspace/source/test/e2e/tests/test_external_oidc.py:750: EXTERNAL_OIDC is not true</skipped></testcase><testcase classname="tests.test_external_oidc.TestOIDCHeaderInjection" name="test_injected_group_header_rejected@external" time="0.000"><skipped type="pytest.skip" message="EXTERNAL_OIDC is not true">/workspace/source/test/e2e/tests/test_external_oidc.py:786: EXTERNAL_OIDC is not true</skipped></testcase><testcase classname="tests.test_external_oidc.TestOIDCHeaderInjection" name="test_injected_subscription_header_ignored@external" time="0.000"><skipped type="pytest.skip" message="EXTERNAL_OIDC is not true">/workspace/source/test/e2e/tests/test_external_oidc.py:824: EXTERNAL_OIDC is not true</skipped></testcase><testcase classname="tests.test_external_oidc.TestOIDCHeaderInjection" name="test_injected_username_on_oidc_token_rejected@external" time="0.000"><skipped type="pytest.skip" message="EXTERNAL_OIDC is not true">/workspace/source/test/e2e/tests/test_external_oidc.py:872: EXTERNAL_OIDC is not true</skipped></testcase><testcase classname="tests.test_external_oidc.TestOIDCClientBinding" name="test_wrong_oauth_client_token_is_rejected@external" time="0.000"><skipped type="pytest.skip" message="EXTERNAL_OIDC not enabled">/workspace/source/test/e2e/tests/test_external_oidc.py:961: EXTERNAL_OIDC not enabled</skipped></testcase><testcase classname="tests.test_external_oidc.TestOIDCGroupSafety" name="test_unsafe_group_name_is_rejected@external" time="0.000"><skipped type="pytest.skip" message="EXTERNAL_OIDC not enabled">/workspace/source/test/e2e/tests/test_external_oidc.py:1013: EXTERNAL_OIDC not enabled</skipped></testcase><testcase classname="tests.test_external_oidc.TestOIDCGroupSafety" name="test_mixed_safe_and_unsafe_groups_is_rejected@external" time="0.000"><skipped type="pytest.skip" message="EXTERNAL_OIDC not enabled">/workspace/source/test/e2e/tests/test_external_oidc.py:1049: EXTERNAL_OIDC not enabled</skipped></testcase><testcase classname="tests.test_external_oidc.TestOIDCDirectModelAccess" name="test_oidc_token_can_list_models_directly@external" time="0.000"><skipped type="pytest.skip" message="EXTERNAL_OIDC not enabled">/workspace/source/test/e2e/tests/test_external_oidc.py:1103: EXTERNAL_OIDC not enabled</skipped></testcase><testcase classname="tests.test_external_oidc.TestOIDCAlertingInfra" name="test_authorino_prometheusrule_exists@external" time="0.001"><skipped type="pytest.skip" message="EXTERNAL_OIDC not enabled">/workspace/source/test/e2e/tests/test_external_oidc.py:1142: EXTERNAL_OIDC not enabled</skipped></testcase><testcase classname="tests.test_subscription.TestManagedAnnotation" name="test_authpolicy_managed_false_prevents_update@api_keys" time="0.242"><skipped type="pytest.skip" message="gateway-only mode: per-model AuthPolicy is not created">/workspace/source/test/e2e/tests/test_subscription.py:1069: gateway-only mode: per-model AuthPolicy is not created</skipped></testcase><testcase classname="tests.test_subscription.TestManagedAnnotation" name="test_trlp_managed_false_prevents_update@api_keys" time="5.626" /><testcase classname="tests.test_subscription.TestE2ESubscriptionFlow" name="test_e2e_with_both_access_and_subscription_gets_200@api_keys" time="1.860" /><testcase classname="tests.test_subscription.TestE2ESubscriptionFlow" name="test_e2e_with_subscription_but_no_access_gets_403@api_keys" time="2.004" /><testcase classname="tests.test_tenant_namespace_discovery.TestTenantNamespaceDiscovery" name="test_unlabeled_namespace_ignored@mt_lifecycle" time="22.007" /><testcase classname="tests.test_subscription.TestE2ESubscriptionFlow" name="test_e2e_multiple_subscriptions_separate_keys_gets_200@api_keys" time="2.052" /><testcase classname="tests.test_subscription.TestE2ESubscriptionFlow" name="test_e2e_mint_api_key_denied_for_inaccessible_subscription@api_keys" time="2.316" /><testcase classname="tests.test_subscription.TestE2ESubscriptionFlow" name="test_e2e_group_based_access_gets_200@api_keys" time="1.497" /><testcase classname="tests.test_subscription.TestE2ESubscriptionFlow" name="test_e2e_group_based_subscription_but_no_auth_gets_403@api_keys" time="1.597" /><testcase classname="tests.test_subscription.TestStatusReporting" name="test_subscription_active_status_with_valid_model@api_keys" time="1.498" /><testcase classname="tests.test_subscription.TestStatusReporting" name="test_subscription_failed_status_with_missing_model@api_keys" time="0.907" /><testcase classname="tests.test_subscription.TestStatusReporting" name="test_authpolicy_active_status_with_valid_model@api_keys" time="1.040" /><testcase classname="tests.test_subscription.TestStatusReporting" name="test_authpolicy_failed_status_with_missing_model@api_keys" time="0.902" /><testcase classname="tests.test_subscription.TestStatusReporting" name="test_subscription_degraded_status_with_partial_models@api_keys" time="1.218" /><testcase classname="tests.test_subscription.TestStatusReporting" name="test_authpolicy_degraded_status_with_partial_models@api_keys" time="0.892" /><testcase classname="tests.test_subscription.TestStatusReporting" name="test_subscription_status_transitions_on_model_deletion@api_keys" time="10.854" /><testcase classname="tests.test_tenant_namespace_discovery.TestTenantNamespaceDiscovery" name="test_dynamic_discovery_after_label_added@mt_lifecycle" time="27.746" /><testcase classname="tests.test_subscription.TestDegradedSubscriptionFiltering" name="test_degraded_healthy_model_allows_inference@api_keys" time="3.448" /><testcase classname="tests.test_subscription.TestDegradedSubscriptionFiltering" name="test_failed_subscription_blocks_inference@api_keys" time="1.616" /><testcase classname="tests.test_subscription.TestDegradedSubscriptionFiltering" name="test_models_endpoint_with_degraded_subscription_api_key@api_keys" time="1.305" /><testcase classname="tests.test_subscription.TestDegradedSubscriptionFiltering" name="test_models_endpoint_with_degraded_subscription_kube_token@api_keys" time="1.262" /><testcase classname="tests.test_subscription_list_endpoints.TestListSubscriptions" name="test_returns_accessible_subscriptions@api_keys" time="0.409" /><testcase classname="tests.test_subscription_list_endpoints.TestListSubscriptions" name="test_unauthenticated_returns_401@api_keys" time="0.026" /><testcase classname="tests.test_subscription_list_endpoints.TestListSubscriptions" name="test_subscription_includes_model_refs@api_keys" time="0.809" /><testcase classname="tests.test_subscription_list_endpoints.TestListSubscriptions" name="test_model_ref_display_name_and_description_enriched@api_keys" time="5.832" /><testcase classname="tests.test_subscription_list_endpoints.TestListSubscriptionsForModel" name="test_returns_subscriptions_for_model@api_keys" time="8.529" /><testcase classname="tests.test_models_endpoint.TestModelsEndpoint" name="test_explicit_subscription_header@models" time="1.247" /><testcase classname="tests.test_models_endpoint.TestModelsEndpoint" name="test_empty_subscription_header_value@models" time="0.489" /><testcase classname="tests.test_models_endpoint.TestModelsEndpoint" name="test_models_filtered_by_subscription@models" time="0.890" /><testcase classname="tests.test_models_endpoint.TestModelsEndpoint" name="test_deduplication_same_model_multiple_refs@models" time="1.527" /><testcase classname="tests.test_tenant_namespace_discovery.TestTenantNamespaceDiscovery" name="test_per_tenant_oidc_configuration@mt_lifecycle" time="0.001"><skipped type="pytest.skip" message="OIDC_ISSUER_URL not set; per-tenant OIDC E2E requires external OIDC deploy">/workspace/source/test/e2e/tests/test_tenant_namespace_discovery.py:189: OIDC_ISSUER_URL not set; per-tenant OIDC E2E requires external OIDC deploy</skipped></testcase><testcase classname="tests.test_tenant_namespace_discovery.TestTenantNamespaceDiscovery" name="test_namespace_qualified_collision_prevention@mt_lifecycle" time="15.687" /><testcase classname="tests.test_subscription_list_endpoints.TestListSubscriptionsForModel" name="test_unknown_model_returns_empty@api_keys" time="0.399" /><testcase classname="tests.test_subscription_list_endpoints.TestListSubscriptionsForModel" name="test_unauthenticated_returns_401@api_keys" time="0.025" /><testcase classname="tests.test_subscription_list_endpoints.TestSubscriptionModelAccessFiltering" name="test_filters_unauthorized_models@api_keys" time="5.572" /><testcase classname="tests.test_models_endpoint.TestModelsEndpoint" name="test_multiple_distinct_models_in_subscription@models" time="6.032" /><testcase classname="tests.test_subscription_list_endpoints.TestSubscriptionModelAccessFiltering" name="test_omits_subscription_with_no_authorized_models@api_keys" time="7.723" /><testcase classname="tests.test_models_endpoint.TestModelsEndpoint" name="test_user_token_returns_all_models@models" time="7.391" /><testcase classname="tests.test_embedding_inference.TestEmbeddingPathRouting" name="test_embedding_path_based_200@api_keys" time="0.045" /><testcase classname="tests.test_embedding_inference.TestEmbeddingPathRouting" name="test_embedding_bbr_llmisvc_200@api_keys" time="11.620" /><testcase classname="tests.test_models_endpoint.TestModelsEndpoint" name="test_user_token_with_subscription_header_filters@models" time="1.490" /><testcase classname="tests.test_models_endpoint.TestModelsEndpoint" name="test_response_schema_matches_openapi@models" time="0.402" /><testcase classname="tests.test_tenant_namespace_discovery.TestTenantNamespaceDiscovery" name="test_tenant_admin_rbac_is_namespace_scoped@mt_lifecycle" time="53.740" /><testcase classname="tests.test_models_endpoint.TestModelsEndpoint" name="test_model_metadata_preserved@models" time="0.398" /><testcase classname="tests.test_models_endpoint.TestModelsEndpoint" name="test_api_key_scoped_to_subscription@models" time="1.509" /><testcase classname="tests.test_models_endpoint.TestModelsEndpoint" name="test_api_key_with_deleted_subscription_403@models" time="1.488" /><testcase classname="tests.test_models_endpoint.TestModelsEndpoint" name="test_api_key_with_inaccessible_subscription_403@models" time="2.069" /><testcase classname="tests.test_models_endpoint.TestModelsEndpoint" name="test_invalid_subscription_header_403@models" time="3.581" /><testcase classname="tests.test_models_endpoint.TestModelsEndpoint" name="test_access_denied_to_subscription_403@models" time="2.214" /><testcase classname="tests.test_models_endpoint.TestModelsEndpoint" name="test_api_key_ignores_subscription_header@models" time="20.874" /><testcase classname="tests.test_tenant_model_inference.TestTenantModelInference" name="test_model_routes_through_tenant_gateway@tenant_isolation" time="182.468" /><testcase classname="tests.test_tenant_model_inference.TestTenantModelInference" name="test_inference_succeeds_through_tenant_gateway@tenant_isolation" time="8.311" /><testcase classname="tests.test_models_endpoint.TestModelsEndpoint" name="test_multiple_api_keys_different_subscriptions@models" time="6.888" /><testcase classname="tests.test_tenant_model_inference.TestTenantModelInference" name="test_tenant_isolation_cross_gateway_blocked@tenant_isolation" time="0.333" /><testcase classname="tests.test_tenant_model_inference.TestTenantBodyRouting" name="test_correct_model_in_body_succeeds@tenant_isolation" time="8.219" /><testcase classname="tests.test_models_endpoint.TestModelsEndpoint" name="test_service_account_token_multiple_subs_no_header@models" time="8.958" /><testcase classname="tests.test_tenant_model_inference.TestTenantBodyRouting" name="test_wrong_model_in_body_rejected@tenant_isolation" time="8.205" /><testcase classname="tests.test_models_endpoint.TestModelsEndpoint" name="test_service_account_token_multiple_subs_with_header@models" time="6.877" /><testcase classname="tests.test_tenant_namespace_discovery.TestTenantWebhookValidation" name="test_maassubscription_rejected_without_tenant_config_cr@mt_lifecycle" time="5.928" /><testcase classname="tests.test_tenant_model_inference.TestTenantBodyRouting" name="test_missing_model_in_body_rejected@tenant_isolation" time="8.196" /><testcase classname="tests.test_models_endpoint.TestModelsEndpoint" name="test_unauthenticated_request_401@models" time="0.025" /><testcase classname="tests.test_gateway_scoped_authpolicy.TestGatewayAuthPolicyStructure" name="test_target_ref_points_to_gateway@models" time="0.227" /><testcase classname="tests.test_gateway_scoped_authpolicy.TestGatewayAuthPolicyStructure" name="test_no_per_model_authpolicy_for_fixture_model@models" time="0.114" /><testcase classname="tests.test_gateway_scoped_authpolicy.TestGatewayAuthPolicyLifecycle" name="test_gateway_auth_rego_is_fixed_size@models" time="1.124" /><testcase classname="tests.test_gateway_scoped_authpolicy.TestGatewayAuthPolicyLifecycle" name="test_only_one_gateway_authpolicy_named_maas_gateway_auth@models" time="0.232" /><testcase classname="tests.test_gateway_scoped_authpolicy.TestGatewayAuthPolicyManagementEndpointAccess" name="test_gateway_auth_group_membership_has_when_guard@models" time="0.113" /><testcase classname="tests.test_gateway_scoped_authpolicy.TestGatewayAuthPolicyManagementEndpointAccess" name="test_gateway_auth_subscription_check_gated_by_model_identity@models" time="0.122" /><testcase classname="tests.test_gateway_scoped_authpolicy.TestGatewayAuthPolicyManagementEndpointAccess" name="test_gateway_default_auth_scoped_if_present@models" time="0.123"><skipped type="pytest.skip" message="gateway-default-auth not present (maas-gateway-auth is active); scoping is validated by unit tests">/workspace/source/test/e2e/tests/test_gateway_scoped_authpolicy.py:212: gateway-default-auth not present (maas-gateway-auth is active); scoping is validated by unit tests</skipped></testcase><testcase classname="tests.test_tenant_namespace_discovery.TestTenantWebhookValidation" name="test_maasauthpolicy_rejected_without_tenant_config_cr@mt_lifecycle" time="6.191" /><testcase classname="tests.test_tenant_model_inference.TestTenantBodyRouting" name="test_each_tenant_routes_to_own_model@tenant_isolation" time="56.899" /><testcase classname="tests.test_tenant_namespace_discovery.TestTenantDiscoveryDormantMode" name="test_dormant_mode_ignores_labeled_namespace@mt_lifecycle" time="0.001"><skipped type="pytest.skip" message="Dormant-mode test mutates controller flags; set ENABLE_TENANT_DISCOVERY_DORMANT_E2E=true">/workspace/source/test/e2e/tests/test_tenant_namespace_discovery.py:355: Dormant-mode test mutates controller flags; set ENABLE_TENANT_DISCOVERY_DORMANT_E2E=true</skipped></testcase><testcase classname="tests.test_tenant_namespace_discovery.TestLegacyDefaultNamespaceStillWorks" name="test_models_as_a_service_namespace_reconciles@mt_lifecycle" time="0.592" /><testcase classname="tests.test_tenant_discovery_isolation" name="test_tenant_discovery_same_tenant_access@mt_lifecycle" time="58.282"><skipped type="pytest.skip" message="Skipping when Gateway uses ClusterIP + OpenShift Route (unsupported configuration). This mixes incompatible routing paradigms. Gateway has no external hostname in spec.listeners, so /v1/tenants returns an error. Supported configuration: LoadBalancer service with hostname in spec.listeners.">/workspace/source/test/e2e/tests/test_tenant_discovery_isolation.py:93: Skipping when Gateway uses ClusterIP + OpenShift Route (unsupported configuration). This mixes incompatible routing paradigms. Gateway has no external hostname in spec.listeners, so /v1/tenants returns an error. Supported configuration: LoadBalancer service with hostname in spec.listeners.</skipped></testcase><testcase classname="tests.test_tenant_discovery_isolation" name="test_tenant_discovery_cross_tenant_isolation@mt_lifecycle" time="0.001"><skipped type="pytest.skip" message="Skipping when Gateway uses ClusterIP + OpenShift Route (unsupported configuration). This mixes incompatible routing paradigms. Gateway has no external hostname in spec.listeners, so /v1/tenants returns an error. Supported configuration: LoadBalancer service with hostname in spec.listeners.">/workspace/source/test/e2e/tests/test_tenant_discovery_isolation.py:141: Skipping when Gateway uses ClusterIP + OpenShift Route (unsupported configuration). This mixes incompatible routing paradigms. Gateway has no external hostname in spec.listeners, so /v1/tenants returns an error. Supported configuration: LoadBalancer service with hostname in spec.listeners.</skipped></testcase><testcase classname="tests.test_tenant_discovery_isolation" name="test_tenant_discovery_unauthorized_access@mt_lifecycle" time="10.873" /><testcase classname="tests.test_tenant_discovery_isolation" name="test_tenant_discovery_each_tenant_returns_own_gateway@mt_lifecycle" time="0.001"><skipped type="pytest.skip" message="Skipping when Gateway uses ClusterIP + OpenShift Route (unsupported configuration). This mixes incompatible routing paradigms. Gateway has no external hostname in spec.listeners, so /v1/tenants returns an error. Supported configuration: LoadBalancer service with hostname in spec.listeners.">/workspace/source/test/e2e/tests/test_tenant_discovery_isolation.py:228: Skipping when Gateway uses ClusterIP + OpenShift Route (unsupported configuration). This mixes incompatible routing paradigms. Gateway has no external hostname in spec.listeners, so /v1/tenants returns an error. Supported configuration: LoadBalancer service with hostname in spec.listeners.</skipped></testcase><testcase classname="tests.test_multi_tenant_integration.TestMultiTenantIntegration" name="test_full_tenant_lifecycle_create_to_delete@mt_lifecycle" time="147.210" /><testcase classname="tests.test_tenant_auth_isolation.TestTenantAuthIsolation" name="test_api_key_creation_scoped_to_tenant@tenant_isolation" time="136.079" /><testcase classname="tests.test_tenant_auth_isolation.TestTenantAuthIsolation" name="test_api_key_validates_against_correct_tenant@tenant_isolation" time="15.297" /><testcase classname="tests.test_multi_tenant_integration.TestMultiTenantIntegration" name="test_default_tenant_unaffected_by_multitenancy_enablement@mt_lifecycle" time="0.945" /><testcase classname="tests.test_multi_tenant_integration.TestMultiTenantIntegration" name="test_same_named_resources_across_tenants@mt_lifecycle" time="16.532" /><testcase classname="tests.test_tenant_auth_isolation.TestTenantAuthIsolation" name="test_api_key_rejected_cross_tenant@tenant_isolation" time="15.375" /><testcase classname="tests.test_tenant_auth_isolation.TestTenantAuthIsolation" name="test_oidc_token_validation_per_tenant@tenant_isolation" time="0.001"><skipped type="pytest.skip" message="Per-tenant OIDC tokens unavailable — set OIDC_TOKEN_URL (tenant-a) and OIDC_TOKEN_URL_TENANT_B (tenant-b), or OIDC_TOKEN_TENANT_A / OIDC_TOKEN_TENANT_B">/workspace/source/test/e2e/tests/test_tenant_auth_isolation.py:215: Per-tenant OIDC tokens unavailable — set OIDC_TOKEN_URL (tenant-a) and OIDC_TOKEN_URL_TENANT_B (tenant-b), or OIDC_TOKEN_TENANT_A / OIDC_TOKEN_TENANT_B</skipped></testcase><testcase classname="tests.test_multi_tenant_integration.TestMultiTenantIntegration" name="test_tenant_namespace_label_change_triggers_reconciliation@mt_lifecycle" time="38.565" /><testcase classname="tests.test_tenant_auth_isolation.TestTenantAuthIsolation" name="test_api_key_list_scoped_to_tenant@tenant_isolation" time="15.476" /><testcase classname="tests.test_tenant_auth_isolation.TestTenantAuthIsolation" name="test_api_key_metadata_not_leaked_cross_tenant@tenant_isolation" time="15.485" /><testcase classname="tests.test_tenant_auth_isolation.TestTenantAuthIsolation" name="test_api_key_subscription_selection_uses_tenant_namespace@tenant_isolation" time="20.805" /><testcase classname="tests.test_multi_tenant_maas_api.TestPerTenantMaaSAPI" name="test_aitenant_creates_dedicated_maas_api_infrastructure@mt_lifecycle" time="58.861" /><testcase classname="tests.test_multi_tenant_maas_api.TestPerTenantMaaSAPI" name="test_tenant_name_environment_variable_set@mt_lifecycle" time="0.231" /><testcase classname="tests.test_multi_tenant_maas_api.TestPerTenantMaaSAPI" name="test_service_routing_isolation@mt_lifecycle" time="0.468" /><testcase classname="tests.test_multi_tenant_maas_api.TestPerTenantMaaSAPI" name="test_httproute_tenant_attachment@mt_lifecycle" time="0.228" /><testcase classname="tests.test_multi_tenant_maas_api.TestPerTenantMaaSAPI" name="test_default_and_multiple_tenants_coexist@mt_lifecycle" time="81.823" /><testcase classname="tests.test_tenant_subscription_isolation.TestTenantSubscriptionIsolation" name="test_subscription_list_scoped_to_tenant@tenant_isolation" time="85.898" /><testcase classname="tests.test_tenant_subscription_isolation.TestTenantSubscriptionIsolation" name="test_subscription_selection_per_tenant@tenant_isolation" time="21.400" /><testcase classname="tests.test_tenant_rate_limit_isolation.TestTenantRateLimitIsolation" name="test_rate_limit_enforced_per_tenant@tenant_isolation" time="87.481" /><testcase classname="tests.test_tenant_rate_limit_isolation.TestTenantRateLimitIsolation" name="test_independent_tenant_rate_limits@tenant_isolation" time="12.600" /><testcase classname="tests.test_per_tenant_ipp_isolation.TestPerTenantIPPInfrastructure" name="test_per_tenant_ipp_deployments_exist@tenant_isolation" time="59.479" /><testcase classname="tests.test_per_tenant_ipp_isolation.TestPerTenantIPPInfrastructure" name="test_per_tenant_ipp_env_vars@tenant_isolation" time="0.230" /><testcase classname="tests.test_per_tenant_ipp_isolation.TestPerTenantIPPInfrastructure" name="test_per_tenant_envoyfilter_workload_selector_isolated@tenant_isolation" time="0.343" /><testcase classname="tests.test_per_tenant_ipp_isolation.TestPerTenantIPPInfrastructure" name="test_per_tenant_envoyfilter_grpc_clusters@tenant_isolation" time="0.225" /><testcase classname="tests.test_per_tenant_ipp_isolation.TestPerTenantIPPInfrastructure" name="test_default_tenant_keeps_legacy_ipp_names@tenant_isolation" time="0.226" /><testcase classname="tests.test_per_tenant_ipp_isolation.TestPerTenantIPPInfrastructure" name="test_multiple_tenant_ipp_stacks_coexist@tenant_isolation" time="0.345" /><testcase classname="tests.test_per_tenant_ipp_isolation.TestPerTenantIPPInfrastructure" name="test_per_tenant_networkpolicy_when_applied@tenant_isolation" time="0.225" /><testcase classname="tests.test_per_tenant_ipp_isolation.TestPerTenantIPPRouting" name="test_default_gateway_hits_default_ipp_only@tenant_isolation" time="2.522" /><testcase classname="tests.test_per_tenant_ipp_isolation.TestPerTenantIPPRouting" name="test_tenant_gateway_hits_tenant_ipp_only@tenant_isolation" time="66.618" /><testcase classname="tests.test_per_tenant_ipp_isolation.TestPerTenantIPPCleanup" name="test_ipp_resources_removed_on_aitenant_delete@tenant_isolation" time="165.071" /></testsuite></testsuites>