|
| 1 | +from unittest.mock import MagicMock |
| 2 | + |
| 3 | +from cycode.cli.apps.ai_guardrails.scan.payload import AIHookPayload |
| 4 | +from cycode.cli.apps.ai_guardrails.scan.types import AiHookEventType, AIHookOutcome |
| 5 | +from cycode.cyclient.ai_security_manager_client import AISecurityManagerClient |
| 6 | + |
| 7 | + |
| 8 | +def _build_client() -> tuple[AISecurityManagerClient, MagicMock]: |
| 9 | + http_client = MagicMock() |
| 10 | + service_config = MagicMock() |
| 11 | + service_config.get_service_name.return_value = None |
| 12 | + |
| 13 | + return AISecurityManagerClient(http_client, service_config), http_client |
| 14 | + |
| 15 | + |
| 16 | +def _posted_body(http_client: MagicMock) -> dict: |
| 17 | + return http_client.post.call_args.kwargs['body'] |
| 18 | + |
| 19 | + |
| 20 | +def test_create_event_reports_the_payload_hook_event_id_as_the_event_id() -> None: |
| 21 | + """The CLI owns the id so the guardrail detection, reported separately, can name this exact event.""" |
| 22 | + client, http_client = _build_client() |
| 23 | + payload = AIHookPayload(event_name='Prompt', conversation_id='conv-1', generation_id='gen-1') |
| 24 | + |
| 25 | + client.create_event(payload, AiHookEventType.PROMPT, AIHookOutcome.ALLOWED) |
| 26 | + |
| 27 | + assert _posted_body(http_client)['id'] == payload.hook_event_id |
| 28 | + |
| 29 | + |
| 30 | +def test_create_event_reports_a_distinct_id_per_hook_event() -> None: |
| 31 | + client, http_client = _build_client() |
| 32 | + conversation_id = 'conv-1' |
| 33 | + # Two hooks of the same prompt: the generation id is shared, the hook event id must not be |
| 34 | + first = AIHookPayload(event_name='Prompt', conversation_id=conversation_id, generation_id='gen-1') |
| 35 | + second = AIHookPayload(event_name='FileRead', conversation_id=conversation_id, generation_id='gen-1') |
| 36 | + |
| 37 | + client.create_event(first, AiHookEventType.PROMPT, AIHookOutcome.ALLOWED) |
| 38 | + client.create_event(second, AiHookEventType.FILE_READ, AIHookOutcome.ALLOWED) |
| 39 | + |
| 40 | + reported_ids = [call.kwargs['body']['id'] for call in http_client.post.call_args_list] |
| 41 | + assert reported_ids == [first.hook_event_id, second.hook_event_id] |
| 42 | + assert len(set(reported_ids)) == 2 |
| 43 | + |
| 44 | + |
| 45 | +def test_create_event_without_a_conversation_posts_nothing() -> None: |
| 46 | + client, http_client = _build_client() |
| 47 | + |
| 48 | + client.create_event(AIHookPayload(event_name='Prompt'), AiHookEventType.PROMPT, AIHookOutcome.ALLOWED) |
| 49 | + |
| 50 | + http_client.post.assert_not_called() |
0 commit comments