Skip to content

Feat/nemoguard content safety#192

Merged
Arshardh merged 6 commits into
wso2:python-policiesfrom
ovindumandith:feat/nemoguard-content-safety
May 6, 2026
Merged

Feat/nemoguard content safety#192
Arshardh merged 6 commits into
wso2:python-policiesfrom
ovindumandith:feat/nemoguard-content-safety

Conversation

@ovindumandith
Copy link
Copy Markdown
Contributor

Purpose

Adds a new AI gateway policy — nvidia-nemoguard-content-safety — to protect LLM-backed APIs by screening both request and response content using NVIDIA NeMo Guard (llama-3.1-nemoguard-8b-content-safety). This addresses the need for broad, multi-category content safety enforcement at the gateway layer without requiring changes to the upstream LLM service.

Goals

  • Provide a drop-in content safety guardrail that can block unsafe user inputs before they reach the upstream LLM.
  • Optionally screen LLM responses before they are delivered to the client.
  • Support fine-grained per-category blocking across 23 NVIDIA safety categories (S1–S23).
  • Follow the same patterns and conventions established by the existing granite-guardian-prompt-injection Python policy.

Approach

Implemented as a Python policy package using apip_sdk_core. The policy class NemoGuardContentSafetyPolicy implements both RequestPolicy and ResponsePolicy and buffers both request and response bodies. On each call it:

  • Extracts the relevant text from the body using a configurable JSONPath expression.
  • Builds a structured prompt embedding the full NVIDIA safety taxonomy and the conversation context.
  • Forwards the prompt to the NeMo Guard OpenAI-compatible inference endpoint (/v1/chat/completions).
  • Parses the JSON verdict (User Safety / Response Safety) and detected category codes.
  • Blocks the request (or replaces the response) if any enabled category returns an unsafe verdict.

Key design decisions:

  • Single policy class covering both request and response phases — mode() always buffers both; the response handler returns passthrough immediately when response.enabled=false.
  • Typed frozen dataclasses (SystemParams, PhaseParams, RequestParams) for parameter handling.
  • _blocked_codes() maps per-category boolean toggles to an S-code frozenset; None means block all categories.
  • _coerce_bool() and _coerce_int_in_range() prevent string "false"/"true" from being misinterpreted.
  • _resolve_jsonpath() includes try/except guard for malformed bracket expressions.

User stories

  • As an API platform operator, I want to screen user messages for unsafe content before they reach the upstream LLM, so that my API cannot be used to generate harmful outputs.
  • As an API platform operator, I want to optionally screen LLM responses before delivery, so that any unsafe model output is intercepted at the gateway.
  • As an API platform operator, I want to enable or disable individual safety categories independently, so that I can tune detection sensitivity without deploying a different model.
  • As an API platform operator, I want fail-open and fail-closed error handling options, so that I can balance safety enforcement against availability requirements.

Release note

Added nvidia-nemoguard-content-safety policy (v0.1.0): a Python gateway policy that validates request and/or response content using NVIDIA NeMo Guard (llama-3.1-nemoguard-8b-content-safety). Supports 23 configurable safety categories, per-phase JSONPath targeting, confidence-independent verdict blocking, and both fail-open and fail-closed error handling.

Documentation

Added policy documentation at docs/nvidia-nemoguard-content-safety/v0.1/:

  • metadata.json
  • docs/nvidia-nemoguard-content-safety.md — covers Overview, Features, Configuration (system + per-phase user parameters, safety category reference table, build.yaml integration), and three Reference Scenarios.

Training

N/A

Certification

N/A - This PR introduces a new standalone gateway policy package and does not currently impact existing certification exam content.

Marketing

N/A

Automation tests

  • Unit tests

    55 unit tests in policies/nvidia-nemoguard-content-safety/tests/test_policy.py. Code coverage includes parameter normalisation (normalize_system_params, normalize_request_params, _normalize_phase_params), category code mapping (_blocked_codes), prompt construction (_build_nemoguard_prompt), JSONPath resolution including malformed bracket handling, request-phase passthrough and blocking, response-phase passthrough and blocking, fail-closed (503) and fail-open error handling for both phases, string "false"/"true" bool coercion, and HTTP call details (auth, endpoint URL, timeout).

  • Integration tests

    N/A — policy requires a live NeMo Guard vLLM endpoint; covered by unit tests via stub HTTP layer.

Security checks

Samples

See Reference Scenarios in the policy documentation:

  • Default request-phase content safety on a chat completions route.
  • Response-phase checking with category filtering and assessment details.
  • Fail-open configuration for high-availability deployments.

Related PRs

  • feat/granite-guardian-prompt-injection — the existing Python policy this one is modelled after.

Migrations (if applicable)

N/A

Test environment

  • Python 3.13
  • Windows 11 Pro (local unit tests via python -m unittest)

Learning

  • NVIDIA NeMo Guardrails documentation: Researched content safety model prompt structure and JSON output schema.
  • llama-3.1-nemoguard-8b-content-safety model card: Leveraged for the S1–S23 category taxonomy and inference format mapping.
  • Existing granite-guardian-prompt-injection policy: Studied for SDK patterns, test stub approaches, and packaging conventions.

Content safety guardrail using NVIDIA NeMo Guard (llama-3.1-nemoguard-8b-content-safety).
Buffers request and response bodies, extracts user/assistant text via configurable JSONPath
expressions, and forwards to the NeMo Guard inference endpoint for classification across 23
safety categories. Unsafe requests are blocked; unsafe responses are replaced with a sanitised
error message.

- Migrated from wso2_gateway_policy_sdk to apip_sdk_core
- Single NemoGuardContentSafetyPolicy class implementing both RequestPolicy and ResponsePolicy
- Typed frozen dataclasses: SystemParams, PhaseParams, RequestParams
- normalize_system_params / normalize_request_params with safe coercion helpers
- Per-phase (request/response) configuration: enabled, jsonPath, blockStatusCode,
  categories filter, passthroughOnError, showAssessment
- _blocked_codes maps boolean category toggles to S-code frozenset (None = block all)
- _resolve_jsonpath with try/except guard for unclosed brackets
- 55 unit tests covering normalisation, prompt building, blocking, error handling,
  category filtering, and HTTP call details
@CLAassistant
Copy link
Copy Markdown

CLA assistant check
Thank you for your submission! We really appreciate it. Like many open source projects, we ask that you sign our Contributor License Agreement before we can accept your contribution.
You have signed the CLA already but the status is still pending? Let us recheck it.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Apr 30, 2026

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: d10f5c68-008c-48c2-a9b2-047db5b05097

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

This pull request introduces a new NVIDIA NeMo Guard Content Safety policy as a complete feature addition. The changes include policy implementation in Python, configuration schema definitions in YAML, documentation covering functionality and configuration, build and packaging configuration, and comprehensive unit tests. The policy validates request and response content by extracting text via configurable JSONPath, sending it to an external NeMo Guard inference endpoint, and blocking or passing through based on safety classification across 23 configurable categories.

Sequence Diagram(s)

sequenceDiagram
    participant Client
    participant Gateway
    participant Policy as NeMo Guard<br/>Policy
    participant NeMoGuard as NeMo Guard<br/>Inference Service
    participant Backend

    Client->>Gateway: HTTP Request
    Gateway->>Policy: Buffer & check request body
    
    alt Request check enabled
        Policy->>Policy: Extract content via JSONPath
        Policy->>NeMoGuard: POST /v1/chat/completions<br/>(with safety prompt)
        NeMoGuard-->>Policy: Safety classification response
        
        alt Content unsafe & blocking enabled
            Policy-->>Gateway: ImmediateResponse<br/>(configurable status code)
            Gateway-->>Client: Blocked response
        else Content safe or passthrough
            Policy-->>Gateway: Continue
        end
    end
    
    Gateway->>Backend: Forward request
    Backend-->>Gateway: Response
    Gateway->>Policy: Buffer & check response body
    
    alt Response check enabled
        Policy->>Policy: Extract content via JSONPath
        Policy->>NeMoGuard: POST /v1/chat/completions<br/>(with safety prompt)
        NeMoGuard-->>Policy: Safety classification response
        
        alt Content unsafe & blocking enabled
            Policy-->>Gateway: ImmediateResponse<br/>(replacement response)
            Gateway-->>Client: Sanitized response
        else Content safe or passthrough
            Policy-->>Gateway: Continue
        end
    end
    
    Gateway-->>Client: Response
Loading
🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (1 warning, 1 inconclusive)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 4.88% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Title check ❓ Inconclusive The title 'Feat/nemoguard content safety' is vague and uses generic conventions (Feat/ prefix). While it refers to the main feature being added, it lacks specificity about what NemoGuard content safety does or how it functions. Consider a more descriptive title such as 'Add nvidia-nemoguard-content-safety policy for request/response screening' to clarify the feature's purpose and scope.
✅ Passed checks (3 passed)
Check name Status Explanation
Description check ✅ Passed The PR description is comprehensive and well-structured, covering all major template sections including Purpose, Goals, Approach, User stories, Release notes, Documentation, Security checks, and Test environment details.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Tip

💬 Introducing Slack Agent: The best way for teams to turn conversations into code.

Slack Agent is built on CodeRabbit's deep understanding of your code, so your team can collaborate across the entire SDLC without losing context.

  • Generate code and open pull requests
  • Plan features and break down work
  • Investigate incidents and troubleshoot customer tickets together
  • Automate recurring tasks and respond to alerts with triggers
  • Summarize progress and report instantly

Built for teams:

  • Shared memory across your entire org—no repeating context
  • Per-thread sandboxes to safely plan and execute work
  • Governance built-in—scoped access, auditability, and budget controls

One agent for your entire SDLC. Right inside Slack.

👉 Get started


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 5

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In
`@docs/nvidia-nemoguard-content-safety/v0.1/docs/nvidia-nemoguard-content-safety.md`:
- Around line 202-203: Example 2's description claims only violence and illegal
activity are blocked but the YAML for both request and response includes the
criminal_planning category; update either the prose or the YAML so they match:
either change the descriptive sentence in "Example 2" to list violence, illegal
activity, and criminal_planning, or remove "criminal_planning" from the YAML
category lists in both the request and response examples so the text and samples
are consistent (look for the "Example 2" heading and the YAML block containing
"criminal_planning" to make the edit).

In `@policies/nvidia-nemoguard-content-safety/policy-definition.yaml`:
- Around line 24-31: The schema currently allows unknown keys in configurable
objects (e.g., the request phase object under properties.request and similar
phase/parameters/category objects), so add additionalProperties: false to each
of those object schemas (including the parameters objects, each phase object
like request/response, and category objects referenced in the
policy-definition.yaml) to ensure typos and unexpected keys fail validation;
locate the object schemas (symbols: properties.request, parameters, category)
and insert additionalProperties: false directly under those object definitions.

In `@policies/nvidia-nemoguard-content-safety/pyproject.toml`:
- Around line 12-14: The dependency declaration for "requests" is unbounded;
update the pyproject.toml dependencies list to pin a safe supported range by
replacing "requests" with a constrained spec such as "requests>=2.33.1,<3.0.0"
so the project uses the patched 2.33.1+ releases while avoiding major-breaking
3.x versions; locate the dependency entry in pyproject.toml (the dependencies =
[...] block) and make this change.

In
`@policies/nvidia-nemoguard-content-safety/src/nvidia_nemoguard_content_safety_v0/policy.py`:
- Around line 229-237: The response flow currently treats missing or unparsable
request bodies as safe because on_response_body() only adds user_text from
res_ctx.request_body and then _call_nemoguard() returns False if no user message
exists; change this by detecting when request extraction
(res_ctx.request_body/res_ctx.request_body.content ->
req_params.request.json_path -> _resolve_jsonpath) fails and either (A)
construct a response-only moderation payload from the response content and
append it to messages before calling _call_nemoguard(), or (B) invoke the
configured error-handling path instead of proceeding as safe; ensure the call
site in on_response_body() still invokes _call_nemoguard(messages, ...) even
when request_text is absent, and apply the same fix to the similar block around
the code referenced at lines 467-470 so responses cannot bypass moderation when
request extraction fails.

In `@policies/nvidia-nemoguard-content-safety/tests/test_policy.py`:
- Around line 100-123: The test currently installs global stubs via
install_dependency_stubs() and mutates sys.path in load_policy_module(), leaving
requests/apip_sdk_core and the added src path in the process state; change this
so the stubs and path changes are scoped and cleaned up: move the call to
load_policy_module() out of module import-time and into test setup and teardown
(or use a context manager/pytest fixture) that (1) saves original sys.modules
entries for "requests" and "apip_sdk_core", (2) calls
install_dependency_stubs(), (3) inserts src_dir into sys.path, (4) imports the
policy via importlib.import_module("nvidia_nemoguard_content_safety_v0.policy"),
and finally (5) restores sys.modules (replacing or deleting the fake entries)
and restores sys.path to its prior state in teardown; update references to
install_dependency_stubs and load_policy_module accordingly so no global process
state is left modified after each test.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: dc9d5b0b-f9d2-4dff-a9ff-8a37571d76dd

📥 Commits

Reviewing files that changed from the base of the PR and between 504169a and 3ebb7bb.

📒 Files selected for processing (11)
  • docs/README.md
  • docs/nvidia-nemoguard-content-safety/v0.1/docs/nvidia-nemoguard-content-safety.md
  • docs/nvidia-nemoguard-content-safety/v0.1/metadata.json
  • policies/nvidia-nemoguard-content-safety/README.md
  • policies/nvidia-nemoguard-content-safety/policy-definition.yaml
  • policies/nvidia-nemoguard-content-safety/pyproject.toml
  • policies/nvidia-nemoguard-content-safety/requirements.txt
  • policies/nvidia-nemoguard-content-safety/src/nvidia_nemoguard_content_safety_v0/__init__.py
  • policies/nvidia-nemoguard-content-safety/src/nvidia_nemoguard_content_safety_v0/policy.py
  • policies/nvidia-nemoguard-content-safety/tests/__init__.py
  • policies/nvidia-nemoguard-content-safety/tests/test_policy.py

Comment on lines +202 to +203
Enable response-phase checking and restrict blocking to a specific subset of categories. This example blocks only violence and illegal activity in both directions, ignoring all other categories:

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Example 2 description contradicts the YAML category set.

The text says only violence and illegal activity are blocked, but criminal_planning is also enabled in both request and response examples. Please align the prose or remove that category from the sample.

Also applies to: 217-227

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@docs/nvidia-nemoguard-content-safety/v0.1/docs/nvidia-nemoguard-content-safety.md`
around lines 202 - 203, Example 2's description claims only violence and illegal
activity are blocked but the YAML for both request and response includes the
criminal_planning category; update either the prose or the YAML so they match:
either change the descriptive sentence in "Example 2" to list violence, illegal
activity, and criminal_planning, or remove "criminal_planning" from the YAML
category lists in both the request and response examples so the text and samples
are consistent (look for the "Example 2" heading and the YAML block containing
"criminal_planning" to make the edit).

Comment on lines +24 to +31
type: object
properties:
request:
type: object
x-wso2-policy-advanced-param: false
description: Configuration for request-phase content safety checks.
properties:
enabled:
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Harden schema by rejecting unknown keys in configurable objects.

parameters, phase objects, and category objects currently accept extra keys. Add additionalProperties: false so typos fail fast instead of being silently ignored.

Suggested schema hardening
 parameters:
   type: object
+  additionalProperties: false
   properties:
     request:
       type: object
+      additionalProperties: false
@@
         categories:
           type: object
+          additionalProperties: false
@@
     response:
       type: object
+      additionalProperties: false
@@
         categories:
           type: object
+          additionalProperties: false

Also applies to: 53-61, 193-217

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@policies/nvidia-nemoguard-content-safety/policy-definition.yaml` around lines
24 - 31, The schema currently allows unknown keys in configurable objects (e.g.,
the request phase object under properties.request and similar
phase/parameters/category objects), so add additionalProperties: false to each
of those object schemas (including the parameters objects, each phase object
like request/response, and category objects referenced in the
policy-definition.yaml) to ensure typos and unexpected keys fail validation;
locate the object schemas (symbols: properties.request, parameters, category)
and insert additionalProperties: false directly under those object definitions.

Comment on lines +12 to +14
dependencies = [
"requests",
]
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🌐 Web query:

What is the latest stable requests version compatible with Python 3.10, and what minimum version is currently recommended to avoid known high-severity advisories?

💡 Result:

The latest stable version of the requests library compatible with Python 3.10 is 2.33.1. All versions from 2.33.0 onwards require Python >=3.10 and dropped support for Python 3.9, making 2.33.1 (released 2026-03-30) fully compatible as Python 3.10 remains in security support until October 2026. To avoid known high-severity advisories, the minimum recommended version is 2.33.1, as it addresses all disclosed vulnerabilities: - CVE-2026-25645 (pre-2.33.0, local file overwrite via zip extraction, CVSS 4.4 Medium) - CVE-2024-47081 (pre-2.32.4, .netrc credential leak, CVSS 5.3 Medium) - CVE-2023-32681 (2.3.0 to pre-2.31.0, Proxy-Authorization leak, CVSS 6.1 Medium) - Older issues like CVE-2018-18074 (pre-2.20.0, auth header leak on redirect, CVSS 7.5 High) are also fixed. Snyk confirms no known security issues in 2.33.1. Python 3.10 compatibility is explicit in PyPI metadata (Python: >=3.10) and GitHub docs.

Citations:


🏁 Script executed:

cat -n policies/nvidia-nemoguard-content-safety/pyproject.toml

Repository: wso2/gateway-controllers

Length of output: 998


Constrain requests to a supported safe range.

requests is currently unbounded. Add an explicit version range to improve reproducibility and ensure all known security advisories are addressed. Since this package requires Python >=3.10, use version 2.33.1 or later (the current stable release with all CVEs patched).

Suggested update
 dependencies = [
-  "requests",
+  "requests>=2.33.1,<4",
 ]
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
dependencies = [
"requests",
]
dependencies = [
"requests>=2.33.1,<4",
]
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@policies/nvidia-nemoguard-content-safety/pyproject.toml` around lines 12 -
14, The dependency declaration for "requests" is unbounded; update the
pyproject.toml dependencies list to pin a safe supported range by replacing
"requests" with a constrained spec such as "requests>=2.33.1,<3.0.0" so the
project uses the patched 2.33.1+ releases while avoiding major-breaking 3.x
versions; locate the dependency entry in pyproject.toml (the dependencies =
[...] block) and make this change.

Comment on lines +229 to +237
if res_ctx.request_body and res_ctx.request_body.present and res_ctx.request_body.content:
req_json_path = req_params.request.json_path
try:
req_data = json.loads(res_ctx.request_body.content)
user_text = _resolve_jsonpath(req_data, req_json_path)
if user_text and isinstance(user_text, str):
messages.append({"role": "user", "content": user_text})
except (json.JSONDecodeError, UnicodeDecodeError):
pass
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Response checks should not silently depend on request extraction succeeding.

on_response_body() will continue when the original request body is missing or cannot be parsed, but _call_nemoguard() then returns False as soon as no user message is present. In practice, that makes response.enabled=true bypass moderation for any response whose paired request body is unavailable or uses a different shape than request.jsonPath. Please either support a response-only prompt here or route this case through the configured error-handling path instead of treating it as safe.

Also applies to: 467-470

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@policies/nvidia-nemoguard-content-safety/src/nvidia_nemoguard_content_safety_v0/policy.py`
around lines 229 - 237, The response flow currently treats missing or unparsable
request bodies as safe because on_response_body() only adds user_text from
res_ctx.request_body and then _call_nemoguard() returns False if no user message
exists; change this by detecting when request extraction
(res_ctx.request_body/res_ctx.request_body.content ->
req_params.request.json_path -> _resolve_jsonpath) fails and either (A)
construct a response-only moderation payload from the response content and
append it to messages before calling _call_nemoguard(), or (B) invoke the
configured error-handling path instead of proceeding as safe; ensure the call
site in on_response_body() still invokes _call_nemoguard(messages, ...) even
when request_text is absent, and apply the same fix to the similar block around
the code referenced at lines 467-470 so responses cannot bypass moderation when
request extraction fails.

Comment on lines +100 to +123
def install_dependency_stubs() -> None:
sdk_module = types.ModuleType("apip_sdk_core")
sdk_module.BodyProcessingMode = BodyProcessingMode
sdk_module.ProcessingMode = ProcessingMode
sdk_module.RequestPolicy = RequestPolicy
sdk_module.ResponsePolicy = ResponsePolicy
sdk_module.UpstreamRequestModifications = UpstreamRequestModifications
sdk_module.DownstreamResponseModifications = DownstreamResponseModifications
sdk_module.ImmediateResponse = ImmediateResponse
sys.modules["apip_sdk_core"] = sdk_module

requests_module = types.ModuleType("requests")
requests_module.post = FakeRequests.post
sys.modules["requests"] = requests_module


def load_policy_module():
install_dependency_stubs()
src_dir = Path(__file__).resolve().parent.parent / "src"
if str(src_dir) not in sys.path:
sys.path.insert(0, str(src_dir))
sys.modules.pop("nvidia_nemoguard_content_safety_v0", None)
sys.modules.pop("nvidia_nemoguard_content_safety_v0.policy", None)
return importlib.import_module("nvidia_nemoguard_content_safety_v0.policy")
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Scope the dependency stubs to this test module.

These helpers replace sys.modules["requests"] / sys.modules["apip_sdk_core"] and prepend to sys.path, but nothing restores the original process state. Because policy = load_policy_module() runs at import time, later tests can end up importing the fake modules or resolving from the added src path. Please move the load into setup/teardown that restores sys.modules and sys.path, or keep the overrides inside a scoped patch.

Also applies to: 126-126

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@policies/nvidia-nemoguard-content-safety/tests/test_policy.py` around lines
100 - 123, The test currently installs global stubs via
install_dependency_stubs() and mutates sys.path in load_policy_module(), leaving
requests/apip_sdk_core and the added src path in the process state; change this
so the stubs and path changes are scoped and cleaned up: move the call to
load_policy_module() out of module import-time and into test setup and teardown
(or use a context manager/pytest fixture) that (1) saves original sys.modules
entries for "requests" and "apip_sdk_core", (2) calls
install_dependency_stubs(), (3) inserts src_dir into sys.path, (4) imports the
policy via importlib.import_module("nvidia_nemoguard_content_safety_v0.policy"),
and finally (5) restores sys.modules (replacing or deleting the fake entries)
and restores sys.path to its prior state in teardown; update references to
install_dependency_stubs and load_policy_module accordingly so no global process
state is left modified after each test.

@renuka-fernando renuka-fernando changed the base branch from main to python-policies May 5, 2026 17:34
Comment on lines +483 to +489
response = http_client.post(
f"{params.endpoint}/v1/chat/completions",
headers=headers,
json=payload,
timeout=params.timeout,
)
response.raise_for_status()
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are we handling any Python-specific logic here? Otherwise, let's go with a Go policy.
cc: @Arshardh

@@ -0,0 +1,572 @@
# Copyright (c) 2025, WSO2 LLC. (https://www.wso2.com).
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
# Copyright (c) 2025, WSO2 LLC. (https://www.wso2.com).
# Copyright (c) 2026, WSO2 LLC. (https://www.wso2.com).

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in latest commit

Comment on lines +5 to +9
Validates request and/or response content using NVIDIA NeMo Guard
(llama-3.1-nemoguard-8b-content-safety). Request bodies are checked before
they reach the upstream LLM; response bodies are checked before they are
delivered to the client. Unsafe requests are rejected with a configurable
status code; unsafe responses are replaced with a sanitised error message.
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can add new lines until a sentence goes to 120 characters.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in latest commit

@Arshardh Arshardh merged commit bfc9724 into wso2:python-policies May 6, 2026
2 of 3 checks passed
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.

4 participants