22
33import pytest
44import requests
5+ from simple_logger .logger import get_logger
56from timeout_sampler import retry
67
8+ from tests .model_explainability .guardrails .utils import (
9+ verify_builtin_detector_unsuitable_input_response ,
10+ verify_negative_detection_response ,
11+ verify_builtin_detector_unsuitable_output_response ,
12+ get_auth_headers ,
13+ get_chat_payload ,
14+ )
715from tests .model_explainability .utils import validate_tai_component_images
816from utilities .constants import Timeout , MinIo
17+ from utilities .plugins .constant import OpenAIEnpoints
18+
19+ LOGGER = get_logger (name = __name__ )
20+ EXAMPLE_EMAIL_ADDRESS : str = "myemail@domain.com"
21+ INPUT_WITH_EMAIL_ADDRESS : str = f"This is my email address: { EXAMPLE_EMAIL_ADDRESS } , just answer ACK."
22+ PII_ENDPOINT : str = "/pii"
23+
24+
25+ @pytest .mark .parametrize (
26+ "model_namespace" ,
27+ [
28+ pytest .param (
29+ {"name" : "test-guardrails-image" },
30+ )
31+ ],
32+ indirect = True ,
33+ )
34+ @pytest .mark .smoke
35+ def test_validate_guardrails_orchestrator_images (guardrails_orchestrator_pod , trustyai_operator_configmap ):
36+ """Test to verify Guardrails pod images.
37+ Checks if the image tag from the ConfigMap is used within the Pod and if it's pinned using a sha256 digest.
38+ """
39+ validate_tai_component_images (pod = guardrails_orchestrator_pod , tai_operator_configmap = trustyai_operator_configmap )
940
1041
1142@pytest .mark .parametrize (
2152)
2253@pytest .mark .rawdeployment
2354@pytest .mark .smoke
24- class TestGuardrailsOrchestrator :
25- def test_guardrails_health_endpoint (self , admin_client , qwen_isvc , guardrails_orchestrator_health_route ):
55+ class TestGuardrailsOrchestratorWithBuiltInDetectors :
56+ """
57+ Tests that the basic functionality of the GuardrailsOrchestrator work properly with the built-in (regex) detectors.
58+ 1. Deploy an LLM using vLLM as a SR.
59+ 2. Deploy the Guardrails Orchestrator.
60+ 3. Check that the Orchestrator is healthy by querying the health and info endpoints of its /health route.
61+ 4. Check that the built-in regex detectors work as expected:
62+ 4.1. Unsuitable input detection.
63+ 4.2. Unsuitable output detection.
64+ 4.3. No detection.
65+ 5. Check that the /passthrough endpoint forwards the
66+ query directly to the model without performing any detection.
67+ """
68+
69+ def test_guardrails_health_endpoint (self , qwen_isvc , guardrails_orchestrator_health_route ):
2670 # It takes a bit for the endpoint to come online, so we retry for a brief period of time
2771 @retry (wait_timeout = Timeout .TIMEOUT_1MIN , sleep = 1 )
2872 def check_health_endpoint ():
@@ -34,7 +78,7 @@ def check_health_endpoint():
3478 response = check_health_endpoint ()
3579 assert "fms-guardrails-orchestr8" in response .text
3680
37- def test_guardrails_info_endpoint (self , admin_client , qwen_isvc , guardrails_orchestrator_health_route ):
81+ def test_guardrails_info_endpoint (self , qwen_isvc , guardrails_orchestrator_health_route ):
3882 response = requests .get (url = f"https://{ guardrails_orchestrator_health_route .host } /info" , verify = False )
3983 assert response .status_code == http .HTTPStatus .OK
4084
@@ -43,10 +87,66 @@ def test_guardrails_info_endpoint(self, admin_client, qwen_isvc, guardrails_orch
4387 assert response_data ["services" ]["chat_generation" ]["status" ] == healthy_status
4488 assert response_data ["services" ]["regex" ]["status" ] == healthy_status
4589
46- def test_validate_guardrails_orchestrator_images (self , guardrails_orchestrator_pod , trustyai_operator_configmap ):
47- """Test to verify Guardrails pod images.
48- Checks if the image tag from the ConfigMap is used within the Pod and if it's pinned using a sha256 digest.
49- """
50- validate_tai_component_images (
51- pod = guardrails_orchestrator_pod , tai_operator_configmap = trustyai_operator_configmap
90+ def test_guardrails_builtin_detectors_unsuitable_input (
91+ self , current_client_token , openshift_ca_bundle_file , guardrails_orchestrator_route
92+ ):
93+ response = requests .post (
94+ url = f"https://{ guardrails_orchestrator_route .host } { PII_ENDPOINT } { OpenAIEnpoints .CHAT_COMPLETIONS } " ,
95+ headers = get_auth_headers (token = current_client_token ),
96+ json = get_chat_payload (content = INPUT_WITH_EMAIL_ADDRESS ),
97+ verify = openshift_ca_bundle_file ,
98+ )
99+
100+ verify_builtin_detector_unsuitable_input_response (
101+ response = response ,
102+ detector_id = "regex" ,
103+ detection_name = "EmailAddress" ,
104+ detection_type = "pii" ,
105+ detection_text = EXAMPLE_EMAIL_ADDRESS ,
106+ )
107+
108+ def test_guardrails_builtin_detectors_unsuitable_output (
109+ self , current_client_token , openshift_ca_bundle_file , guardrails_orchestrator_route
110+ ):
111+ response = requests .post (
112+ url = f"https://{ guardrails_orchestrator_route .host } { PII_ENDPOINT } { OpenAIEnpoints .CHAT_COMPLETIONS } " ,
113+ headers = get_auth_headers (token = current_client_token ),
114+ json = get_chat_payload (
115+ content = "Hi, write three and only three examples of email adresses "
116+ "that I can use to create an account for an online service."
117+ "Don't provide any additional explanation."
118+ ),
119+ verify = openshift_ca_bundle_file ,
52120 )
121+
122+ verify_builtin_detector_unsuitable_output_response (
123+ response = response , detector_id = "regex" , detection_name = "EmailAddress" , detection_type = "pii"
124+ )
125+
126+ @pytest .mark .parametrize (
127+ "message, url_path" ,
128+ [
129+ pytest .param (
130+ "What is the opposite of up?" ,
131+ PII_ENDPOINT ,
132+ id = "harmless_input" ,
133+ ),
134+ pytest .param (INPUT_WITH_EMAIL_ADDRESS , "/passthrough" , id = "pastthrough_endpoint" ),
135+ ],
136+ )
137+ def test_guardrails_builtin_detectors_negative_detection (
138+ self ,
139+ current_client_token ,
140+ openshift_ca_bundle_file ,
141+ guardrails_orchestrator_route ,
142+ message ,
143+ url_path ,
144+ ):
145+ response = requests .post (
146+ url = f"https://{ guardrails_orchestrator_route .host } { url_path } { OpenAIEnpoints .CHAT_COMPLETIONS } " ,
147+ headers = get_auth_headers (token = current_client_token ),
148+ json = get_chat_payload (content = str (message )),
149+ verify = openshift_ca_bundle_file ,
150+ )
151+
152+ verify_negative_detection_response (response = response )
0 commit comments