Skip to content

[python] PoC: AI Guard test under INTEGRATION_FRAMEWORKS#7257

Draft
avara1986 wants to merge 3 commits into
mainfrom
avara/appsec-68977-integration-frameworks-ai-guard-poc
Draft

[python] PoC: AI Guard test under INTEGRATION_FRAMEWORKS#7257
avara1986 wants to merge 3 commits into
mainfrom
avara/appsec-68977-integration-frameworks-ai-guard-poc

Conversation

@avara1986

Copy link
Copy Markdown
Member

What

Proof-of-concept exploring whether AI Guard coverage can be consolidated under the INTEGRATION_FRAMEWORKS scenario instead of the dedicated AI_GUARD scenario.

Adds tests/integration_frameworks/llm/openai/test_openai_ai_guard.py, which drives AI Guard evaluation through the OpenAI framework weblog using the test_client/test_agent fixtures, and asserts on the ai_guard span (meta.ai_guard.*, meta_struct.ai_guard) — reusing the payloads and span shape from tests/ai_guard/test_ai_guard_sdk.py.

Status: DRAFT / investigation

This is a scaffold for the investigation tracked in APPSEC-68977. It is not runnable yet — it depends on prerequisites still to be validated:

  • an /ai_guard/evaluate endpoint in utils/build/docker/python/openai_app/openai.py that calls the tracer's AI Guard client;
  • the test-agent VCR proxy serving an /vcr/aiguard upstream (or reusing the standalone VCRCassettesContainer);
  • DD_AI_GUARD_ENABLED / DD_AI_GUARD_ENDPOINT wired into IntegrationFrameworksScenario.

Jira

Investigation task: https://datadoghq.atlassian.net/browse/APPSEC-68977 (under epic APPSEC-68823)

🤖 Generated with Claude Code

@github-actions

github-actions Bot commented Jul 3, 2026

Copy link
Copy Markdown
Contributor

CODEOWNERS have been resolved as:

tests/integration_frameworks/llm/openai/test_openai_ai_guard.py         @DataDog/ml-observability
tests/integration_frameworks/utils/vcr-cassettes/aiguard/test_after_model_validation_stream_True_aiguard_evaluate_post_5dec5d6a.json  @DataDog/system-tests-core
tests/integration_frameworks/utils/vcr-cassettes/aiguard/test_before_model_validation_aiguard_evaluate_post_ca44130a.json  @DataDog/system-tests-core
tests/integration_frameworks/utils/vcr-cassettes/aiguard/test_before_model_validation_aiguard_evaluate_post_d13cc790.json  @DataDog/system-tests-core
tests/integration_frameworks/utils/vcr-cassettes/aiguard/test_tool_call_validation_aiguard_evaluate_post_9e556a11.json  @DataDog/system-tests-core
tests/integration_frameworks/utils/vcr-cassettes/aiguard/test_tool_call_validation_aiguard_evaluate_post_a304603c.json  @DataDog/system-tests-core
tests/integration_frameworks/utils/vcr-cassettes/openai/test_after_model_validation_stream_True_openai_chat_completions_post_5c14b241.json  @DataDog/system-tests-core
tests/integration_frameworks/utils/vcr-cassettes/openai/test_before_model_validation_openai_chat_completions_post_eb8df755.json  @DataDog/system-tests-core
tests/integration_frameworks/utils/vcr-cassettes/openai/test_tool_call_validation_openai_chat_completions_post_f2dffea2.json  @DataDog/system-tests-core
manifests/java.yml                                                      @DataDog/asm-java @DataDog/apm-java
manifests/nodejs.yml                                                    @DataDog/dd-trace-js
manifests/python.yml                                                    @DataDog/apm-python @DataDog/asm-python
utils/docker_fixtures/_test_agent.py                                    @DataDog/system-tests-core
utils/docker_fixtures/_test_clients/_test_client_framework_integrations.py  @DataDog/system-tests-core

@datadog-datadog-prod-us1

datadog-datadog-prod-us1 Bot commented Jul 3, 2026

Copy link
Copy Markdown

Pipelines  Tests

Fix all issues with BitsAI

⚠️ Warnings

🚦 5 Pipeline jobs failed

Testing the test | System Tests (python, dev) / End-to-end #1 / openai-py@2.0.0 1   View in Datadog   GitHub Actions

🧪 1 Test failed

tests.integration_frameworks.llm.openai.test_openai_ai_guard.TestOpenAiAiGuard.test_after_model_validation[openai-py@2.0.0] from system_tests_suite   View in Datadog
ValueError: Number (1) of traces not available from test agent, got 2:
[[{'service': 'openai', 'name': 'openai.request', 'resource': 'createChatCompletion', 'trace_id': 17615974951985064350, 'span_id': 4435589855698258319, 'start': 1783104267416352873, 'duration': 64580078, 'meta': {'_dd.svc_src': 'm', '_dd.p.tid': '6a48030b00000000', '_dd.p.dm': '-13', 'language': 'python', 'ai_guard.event': 'true', 'component': 'openai', 'openai.request.method': 'POST', '_dd.llmobs.model_provider': 'openai', 'runtime-id': 'f548a09183584532a8a87e0cc8e6ae59', 'openai.request.model': 'gpt-4o-mini', 'openai.request.provider': 'OpenAI', 'openai.response.model': 'gpt-4o-mini-2024-07-18', 'openai.request.endpoint': '/v1/chat/completions', '_dd.llmobs.model_name': 'gpt-4o-mini-2024-07-18', '_dd.tags.process': 'entrypoint.basedir:app,entrypoint.name:integration_frameworks,entrypoint.type:module,entrypoint.workdir:app,svc.auto:openai', '_dd.llmobs.span_kind': 'llm'}, 'metrics': {'_dd.llmobs.input_tokens': 16.0, 'process_id': 1.0, '_dd.llmobs.cache_read_input_tokens': 0.0, '_dd.llmobs.enabled': 0.0, '_dd.tracer_kr': 1.0, 'openai.organization.ratelimit.requests.limit': 30000.0, '_dd.llmobs.output_tokens': 35.0, '_dd.llmobs.total_tokens': 51.0, '_dd.measured': 1.0, 'openai.organization.ratelimit.tokens.remaining': 149999990.0, 'openai.organization.ratelimit.requests.remaining': 29999.0, 'openai.organization.ratelimit.tokens.limit': 150000000.0, '_sampling_priority_v1': 2.0, '_dd.top_level': 1.0}}, {'service': 'openai', 'name': 'ai_guard', 'resource': 'ai_guard', 'trace_id': 17615974951985064350, 'span_id': 3033706063057357302, 'parent_id': 4435589855698258319, 'start': 1783104267416543609, 'duration': 2483575, 'meta': {'ai_guard.target': 'prompt', 'ai_guard.action': 'ALLOW', 'ai_guard.reason': 'No rule match.', '_dd.svc_src': 'm'}, 'meta_struct': {'ai_guard': {'messages': [{'role': 'user', 'content': 'Tell me a short story about a robot.'}]}}}, {'service': 'openai', 'name': 'http.request', 'resource': 'http.request', 'trace_id': 17615974951985064350, 'span_id': 13194093504696542325, 'parent_id': 4435589855698258319, 'start': 1783104267423186251, 'duration': 2912329, 'meta': {'span.kind': 'client', 'http.useragent': 'OpenAI/Python 2.0.0', 'out.host': 'ddapm-test-agent-8cbf06', 'component': 'httpx', 'http.method': 'POST', 'http.status_code': '200', 'http.url': 'http://ddapm-test-agent-8cbf06:8126/vcr/openai/chat/completions', '_dd.svc_src': 'httpx'}, 'metrics': {'_dd.measured': 1.0}, 'type': 'http'}], [{'service': 'openai', 'name': 'ai_guard', 'resource': 'ai_guard', 'trace_id': 12333806726689590109, 'span_id': 376930979058414664, 'start': 1783104267481410543, 'duration': 2468568, 'error': 1, 'meta': {'error.message': 'AI Guard service call failed, status: 500', '_dd.p.dm': '-0', '_dd.tags.process': 'entrypoint.basedir:app,entrypoint.name:integration_frameworks,entrypoint.type:module,entrypoint.workdir:app,svc.auto:openai', '_dd.p.tid': '6a48030b00000000', 'error.type': 'ddtrace.appsec.ai_guard._api_client.AIGuardClientError', 'error.stack': 'Traceback (most recent call last):\n  File "/usr/local/lib/python3.11/site-packages/ddtrace/appsec/ai_guard/_api_client.py", line 306, in evaluate\n    raise AIGuardClientError(\nddtrace.appsec.ai_guard._api_client.AIGuardClientError: AI Guard service call failed, status: 500\n', 'ai_guard.target': 'prompt', 'language': 'python', 'runtime-id': 'f548a09183584532a8a87e0cc8e6ae59'}, 'metrics': {'_sampling_priority_v1': 1.0, '_dd.tracer_kr': 1.0, 'process_id': 1.0, '_dd.top_level': 1.0}, 'meta_struct': {'ai_guard': {'messages': [{'role': 'user', 'content': 'Tell me a short story about a robot.'}, {'role': 'assistant', 'content': 'Once in a bustling city of the future, there lived a small robot named Tinker. Tinker was not like the towering, sophisticated robots that handled daily tasks; he was'}]}}}]]

self = <tests.integration_frameworks.llm.openai.test_openai_ai_guard.TestOpenAiAiGuard object at 0x7f4bf7690ce0>
test_agent = <utils.docker_fixtures._test_agent.TestAgentAPI object at 0x7f4bf831c290>
test_client = <utils.docker_fixtures._test_clients._test_client_framework_integrations.FrameworkTestClientApi object at 0x7f4bf8332990>

    def test_after_model_validation(self, test_agent: TestAgentAPI, test_client: FrameworkTestClientApi):
        """The streamed model response is evaluated by AI Guard after the model returns."""
        with test_agent.vcr_context(stream=True):
...

Testing the test | System Tests (java, dev) / parametric / parametric (1)   View in Datadog   GitHub Actions

🧪 1 Test failed

tests.parametric.test_headers_opm.Test_HeadersOPM_Injection.test_local_opm_overrides_inbound_opm[library_env0-agent_env0, parametric-java] from system_tests_suite   View in Datadog
failed on setup with "docker.errors.APIError: 409 Client Error for http+docker://localhost/v1.48/networks/create: Conflict ("network with name apm_shared_tests_network_dd0fc6 already exists")"

self = <docker.api.client.APIClient object at 0x7fb98428f230>
response = <Response [409]>

    def _raise_for_status(self, response):
        """Raises stored :class:\`APIError\`, if one occurred."""
        try:
>           response.raise_for_status()

...

Testing the test | System Tests (python, prod) / parametric / parametric (1)   View in Datadog   GitHub Actions

🧪 1 Test failed

tests.parametric.test_dynamic_configuration.TestDynamicConfigV1_ServiceTargets.test_match_service_target_case_insensitively[library_env1, parametric-python] from system_tests_suite   View in Datadog
failed on setup with "Timeout of 60 seconds exceeded waiting for HTTP server to start. Please check logs."

Timeout of 60 seconds exceeded waiting for HTTP server to start. Please check logs.

View all 5 failed jobs.

ℹ️ Info

No other issues found (see more)

❄️ No new flaky tests detected

Useful? React with 👍 / 👎

This comment will be updated automatically if new data arrives.
🔗 Commit SHA: e19802e | Docs | Datadog PR Page | Give us feedback!

@avara1986 avara1986 force-pushed the avara/appsec-68977-integration-frameworks-ai-guard-poc branch from 78379f1 to ca1a97f Compare July 3, 2026 13:02
@avara1986 avara1986 changed the title PoC: AI Guard test under INTEGRATION_FRAMEWORKS (APPSEC-68977) [python] PoC: AI Guard test under INTEGRATION_FRAMEWORKS Jul 3, 2026
…APPSEC-68977)

Exercise the auto-instrumented AI Guard/OpenAI integration (ai_guard_listen)
the way the LLM Obs suite does: call the OpenAI SDK directly through the
existing /chat/completions weblog endpoint with DD_AI_GUARD_ENABLED=true, and
assert an ai_guard span is emitted for before-model, after-model (streamed)
and tool-call evaluation. The evaluation outcome (ALLOW/DENY/ABORT) stays
covered by the dedicated AI_GUARD scenario and is not re-asserted here.

The AI Guard endpoint is not yet wired into the INTEGRATION_FRAMEWORKS
scenario (no DD_AI_GUARD_ENDPOINT / no aiguard VCR cassettes), so the
integration path 500s for every language. Marked missing_feature for
python, nodejs and java until the scenario wiring + cassettes land.

Investigation task: APPSEC-68977

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@avara1986 avara1986 force-pushed the avara/appsec-68977-integration-frameworks-ai-guard-poc branch from ca1a97f to 4de1a84 Compare July 3, 2026 13:15
avara1986 and others added 2 commits July 3, 2026 16:00
library_env now injects real DD_API_KEY/DD_APP_KEY in --generate-cassettes
mode (the AI Guard client calls the real API to record the aiguard cassette)
and keeps mock keys on replay, where the VCR proxy matches on the request
rather than auth.

Investigation task: APPSEC-68977

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant