Skip to content

Commit f4d351c

Browse files
Added Red Team tests and pushed new recordings (#42711)
* Added RedTeam tests * updated tests * pushed assets * Update sdk/ai/azure-ai-projects/tests/test_redteams_async.py Co-authored-by: Copilot <[email protected]> * Update sdk/ai/azure-ai-projects/tests/test_redteams.py Co-authored-by: Copilot <[email protected]> * Update sdk/ai/azure-ai-projects/tests/test_base.py Co-authored-by: Copilot <[email protected]> * Update connection_name to a fixed value --------- Co-authored-by: Copilot <[email protected]>
1 parent eb3bef0 commit f4d351c

File tree

4 files changed

+184
-1
lines changed

4 files changed

+184
-1
lines changed

sdk/ai/azure-ai-projects/assets.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,5 +2,5 @@
22
"AssetsRepo": "Azure/azure-sdk-assets",
33
"AssetsRepoPrefixPath": "python",
44
"TagPrefix": "python/ai/azure-ai-projects",
5-
"Tag": "python/ai/azure-ai-projects_85a150439d"
5+
"Tag": "python/ai/azure-ai-projects_f7878e759e"
66
}

sdk/ai/azure-ai-projects/tests/test_base.py

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,12 @@
3333

3434

3535
class TestBase(AzureRecordedTestCase):
36+
test_redteams_params = {
37+
# cSpell:disable-next-line
38+
"connection_name": "naposaniwestus3",
39+
"connection_type": ConnectionType.AZURE_OPEN_AI,
40+
"model_deployment_name": "gpt-4o-mini"
41+
}
3642

3743
test_connections_params = {
3844
"connection_name": "connection1",
@@ -116,6 +122,55 @@ def validate_connection(
116122
assert connection.credentials.type == CredentialType.API_KEY
117123
assert connection.credentials.api_key is not None
118124

125+
@classmethod
126+
def validate_red_team_response(cls, response, expected_attack_strategies: int = -1, expected_risk_categories: int = -1):
127+
"""Assert basic red team scan response properties."""
128+
assert response is not None
129+
assert hasattr(response, 'name')
130+
assert hasattr(response, 'display_name')
131+
assert hasattr(response, 'status')
132+
assert hasattr(response, 'attack_strategies')
133+
assert hasattr(response, 'risk_categories')
134+
assert hasattr(response, 'target')
135+
assert hasattr(response, 'properties')
136+
137+
# Validate attack strategies and risk categories
138+
if expected_attack_strategies != -1:
139+
assert len(response.attack_strategies) == expected_attack_strategies
140+
if expected_risk_categories != -1:
141+
assert len(response.risk_categories) == expected_risk_categories
142+
assert response.status is not None
143+
cls._assert_azure_ml_properties(response)
144+
145+
@classmethod
146+
def _assert_azure_ml_properties(cls, response):
147+
"""Assert Azure ML specific properties are present and valid."""
148+
properties = response.properties
149+
assert properties is not None, "Red team scan properties should not be None"
150+
151+
required_properties = [
152+
'runType',
153+
'redteaming',
154+
'_azureml.evaluation_run',
155+
'_azureml.evaluate_artifacts',
156+
'AiStudioEvaluationUri'
157+
]
158+
159+
for prop in required_properties:
160+
assert prop in properties, f"Missing required property: {prop}"
161+
162+
# Validate specific property values
163+
assert properties['runType'] == 'eval_run'
164+
assert properties['_azureml.evaluation_run'] == 'evaluation.service'
165+
assert 'instance_results.json' in properties['_azureml.evaluate_artifacts']
166+
assert properties['redteaming'] == 'asr'
167+
168+
# Validate AI Studio URI format
169+
ai_studio_uri = properties['AiStudioEvaluationUri']
170+
assert ai_studio_uri.startswith('https://ai.azure.com/resource/build/redteaming/')
171+
assert 'wsid=' in ai_studio_uri
172+
assert 'tid=' in ai_studio_uri
173+
119174
@classmethod
120175
def validate_deployment(
121176
cls,
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
# ------------------------------------
2+
# Copyright (c) Microsoft Corporation.
3+
# Licensed under the MIT License.
4+
# ------------------------------------
5+
6+
from azure.ai.projects import AIProjectClient
7+
from azure.ai.projects.models import (
8+
RedTeam,
9+
AzureOpenAIModelConfiguration,
10+
AttackStrategy,
11+
RiskCategory,
12+
)
13+
from test_base import TestBase, servicePreparer
14+
from devtools_testutils import recorded_by_proxy
15+
16+
17+
class TestRedTeams(TestBase):
18+
19+
# To run this test, use the following command in the \sdk\ai\azure-ai-projects folder:
20+
# cls & pytest tests\test_redteams.py::TestRedTeams::test_red_teams -s
21+
@servicePreparer()
22+
@recorded_by_proxy
23+
def test_red_teams(self, **kwargs):
24+
25+
endpoint = kwargs.pop("azure_ai_projects_tests_project_endpoint")
26+
print("\n=====> Endpoint:", endpoint)
27+
28+
connection_name = self.test_redteams_params["connection_name"]
29+
model_deployment_name = self.test_redteams_params["model_deployment_name"]
30+
31+
with AIProjectClient(
32+
endpoint=endpoint,
33+
credential=self.get_credential(AIProjectClient, is_async=False),
34+
) as project_client:
35+
36+
# [START red_team_sample]
37+
print("Creating a Red Team scan for direct model testing")
38+
39+
# Create target configuration for testing an Azure OpenAI model
40+
target_config = AzureOpenAIModelConfiguration(model_deployment_name=f"{connection_name}/{model_deployment_name}")
41+
42+
# Create the Red Team configuration
43+
red_team = RedTeam(
44+
attack_strategies=[AttackStrategy.BASE64],
45+
risk_categories=[RiskCategory.VIOLENCE],
46+
display_name="redteamtest1", # Use a simpler name
47+
target=target_config,
48+
)
49+
50+
# Create and run the Red Team scan
51+
red_team_response = project_client.red_teams.create(red_team=red_team)
52+
print(f"Red Team scan created with scan name: {red_team_response.name}")
53+
TestBase.validate_red_team_response(red_team_response, expected_attack_strategies=1, expected_risk_categories=1)
54+
55+
print("Getting Red Team scan details")
56+
# Use the name returned by the create operation for the get call
57+
get_red_team_response = project_client.red_teams.get(name=red_team_response.name)
58+
print(f"Red Team scan status: {get_red_team_response.status}")
59+
TestBase.validate_red_team_response(get_red_team_response, expected_attack_strategies=1, expected_risk_categories=1)
60+
61+
print("Listing all Red Team scans")
62+
for scan in project_client.red_teams.list():
63+
print(f"Found scan: {scan.name}, Status: {scan.status}")
64+
TestBase.validate_red_team_response(scan)
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
# ------------------------------------
2+
# Copyright (c) Microsoft Corporation.
3+
# Licensed under the MIT License.
4+
# ------------------------------------
5+
6+
from azure.ai.projects.aio import AIProjectClient
7+
from azure.ai.projects.models import (
8+
RedTeam,
9+
AzureOpenAIModelConfiguration,
10+
AttackStrategy,
11+
RiskCategory,
12+
)
13+
from test_base import TestBase, servicePreparer
14+
from devtools_testutils.aio import recorded_by_proxy_async
15+
16+
17+
class TestRedTeams(TestBase):
18+
19+
# To run this test, use the following command in the \sdk\ai\azure-ai-projects folder:
20+
# cls & pytest tests\test_redteams.py::TestRedTeams::test_red_teams_async -s
21+
@servicePreparer()
22+
@recorded_by_proxy_async
23+
async def test_red_teams_async(self, **kwargs):
24+
25+
endpoint = kwargs.pop("azure_ai_projects_tests_project_endpoint")
26+
print("\n=====> Endpoint:", endpoint)
27+
28+
connection_name = self.test_redteams_params["connection_name"]
29+
model_deployment_name = self.test_redteams_params["model_deployment_name"]
30+
31+
async with AIProjectClient(
32+
endpoint=endpoint,
33+
credential=self.get_credential(AIProjectClient, is_async=True),
34+
) as project_client:
35+
36+
# [START red_team_sample]
37+
print("Creating a Red Team scan for direct model testing")
38+
39+
# Create target configuration for testing an Azure OpenAI model
40+
target_config = AzureOpenAIModelConfiguration(model_deployment_name=f"{connection_name}/{model_deployment_name}")
41+
42+
# Create the Red Team configuration
43+
red_team = RedTeam(
44+
attack_strategies=[AttackStrategy.BASE64],
45+
risk_categories=[RiskCategory.VIOLENCE],
46+
display_name="redteamtest1", # Use a simpler name
47+
target=target_config,
48+
)
49+
50+
# Create and run the Red Team scan
51+
red_team_response = await project_client.red_teams.create(red_team=red_team)
52+
print(f"Red Team scan created with scan name: {red_team_response.name}")
53+
TestBase.validate_red_team_response(red_team_response, expected_attack_strategies=1, expected_risk_categories=1)
54+
55+
print("Getting Red Team scan details")
56+
# Use the name returned by the create operation for the get call
57+
get_red_team_response = await project_client.red_teams.get(name=red_team_response.name)
58+
print(f"Red Team scan status: {get_red_team_response.status}")
59+
TestBase.validate_red_team_response(get_red_team_response, expected_attack_strategies=1, expected_risk_categories=1)
60+
61+
print("Listing all Red Team scans")
62+
async for scan in project_client.red_teams.list():
63+
print(f"Found scan: {scan.name}, Status: {scan.status}")
64+
TestBase.validate_red_team_response(scan)

0 commit comments

Comments
 (0)