fix(guardrails): mark Singulr block verdicts as blocked_content

should_block=True raises GuardrailRaisedException without blocked_content=True,
so the batch upload path treats a real block verdict as a technical failure and
aborts the whole file instead of dropping only the blocked record.
This commit is contained in:
aniket-kardile 2026-09-01 13:03:50 +05:30
parent c2d21422b5
commit cd6d38ea85
No known key found for this signature in database
2 changed files with 10 additions and 2 deletions

View file

@ -268,6 +268,7 @@ class SingulrGuardrail(CustomGuardrail):
guardrail_name=self.guardrail_name,
status_code=400,
message=f"Blocked by Singulr, Blocking due to {guardrail_resp.blocking_due_to or 'unknown'}",
blocked_content=True,
)
return inputs
@ -292,6 +293,7 @@ class SingulrGuardrail(CustomGuardrail):
guardrail_name=self.guardrail_name,
status_code=400,
message=f"Blocked by Singulr, Blocking due to {guardrail_resp.blocking_due_to or 'unknown'}",
blocked_content=True,
)
async def _apply_guardrail_on_mcp_response(
@ -319,6 +321,7 @@ class SingulrGuardrail(CustomGuardrail):
guardrail_name=self.guardrail_name,
status_code=400,
message=f"Blocked by Singulr, Blocking due to {guardrail_resp.blocking_due_to or 'unknown'}",
blocked_content=True,
)
return inputs
@ -379,6 +382,7 @@ class SingulrGuardrail(CustomGuardrail):
guardrail_name=self.guardrail_name,
status_code=400,
message=f"Blocked by Singulr, Blocking due to {guardrail_resp.blocking_due_to or 'unknown'}",
blocked_content=True,
)
return inputs

View file

@ -545,6 +545,7 @@ class TestSingulrBlockAction:
input_type="request",
)
assert "PII Information detected" in str(exc_info.value)
assert exc_info.value.blocked_content is True
@pytest.mark.asyncio
async def test_should_block_true_raises_on_response(self, singulr_guardrail):
@ -562,6 +563,7 @@ class TestSingulrBlockAction:
input_type="response",
)
assert "Toxic content detected" in str(exc_info.value)
assert exc_info.value.blocked_content is True
@pytest.mark.asyncio
async def test_block_without_reason_uses_unknown_placeholder(self, singulr_guardrail):
@ -607,12 +609,13 @@ class TestSingulrMcpRequest:
resp = _make_response({"should_block": True, "blocking_due_to": "Disallowed tool"})
request_data = {"mcp_tool_name": "delete_file", "mcp_arguments": {"path": "/etc/passwd"}}
with patch.object(singulr_guardrail.async_handler, "post", return_value=resp):
with pytest.raises(GuardrailRaisedException, match="Disallowed tool"):
with pytest.raises(GuardrailRaisedException, match="Disallowed tool") as exc_info:
await singulr_guardrail.apply_guardrail(
inputs={"texts": []},
request_data=request_data,
input_type="request",
)
assert exc_info.value.blocked_content is True
class TestSingulrMcpResponse:
@ -653,12 +656,13 @@ class TestSingulrMcpResponse:
resp = _make_response({"should_block": True, "blocking_due_to": "Sensitive tool output"})
request_data = {"call_type": "call_mcp_tool", "mcp_tool_name": "search_docs"}
with patch.object(singulr_guardrail.async_handler, "post", return_value=resp):
with pytest.raises(GuardrailRaisedException, match="Sensitive tool output"):
with pytest.raises(GuardrailRaisedException, match="Sensitive tool output") as exc_info:
await singulr_guardrail.apply_guardrail(
inputs={"texts": ["leaked secret"]},
request_data=request_data,
input_type="response",
)
assert exc_info.value.blocked_content is True
@pytest.mark.asyncio
async def test_mcp_response_resolves_metadata_from_nested_litellm_params(self, singulr_guardrail):