diff --git a/litellm/proxy/guardrails/guardrail_hooks/panw_prisma_airs/panw_prisma_airs.py b/litellm/proxy/guardrails/guardrail_hooks/panw_prisma_airs/panw_prisma_airs.py index 68a403aa3d5..df94fc5e5bc 100644 --- a/litellm/proxy/guardrails/guardrail_hooks/panw_prisma_airs/panw_prisma_airs.py +++ b/litellm/proxy/guardrails/guardrail_hooks/panw_prisma_airs/panw_prisma_airs.py @@ -205,6 +205,12 @@ class PanwPrismaAirsHandler(CustomGuardrail): guardrail_name, ) + if self.experimental_use_latest_role_message_only is True: + verbose_proxy_logger.warning( + "PANW Prisma AIRS Guardrail '%s': experimental_use_latest_role_message_only=true - only the latest user/developer message is scanned on the request side. Earlier turns in caller-supplied history are not rescanned before being forwarded to the model. Enable only where every turn is scanned while it is the latest message, or where conversation history is server-controlled.", + guardrail_name, + ) + verbose_proxy_logger.info( "Initialized PANW Prisma AIRS Guardrail: %s (profile=%s, mask_request=%s, mask_response=%s, fallback_on_error=%s, timeout=%s)", guardrail_name, diff --git a/tests/test_litellm/proxy/guardrails/guardrail_hooks/test_panw_prisma_airs.py b/tests/test_litellm/proxy/guardrails/guardrail_hooks/test_panw_prisma_airs.py index 598b363c0fe..b3701014aff 100644 --- a/tests/test_litellm/proxy/guardrails/guardrail_hooks/test_panw_prisma_airs.py +++ b/tests/test_litellm/proxy/guardrails/guardrail_hooks/test_panw_prisma_airs.py @@ -5243,6 +5243,31 @@ class TestPanwAirsLatestRoleMessageOnlyOpenAIShape: assert mock_api.call_count == 2 +class TestPanwAirsLatestRoleMessageOnlyStartupWarning: + """Enabling latest-only scanning trusts caller-supplied history, so the operator + gets an explicit startup warning - same treatment as fallback_on_error='allow'.""" + + def test_warns_when_explicitly_enabled(self): + with patch( + "litellm.proxy.guardrails.guardrail_hooks.panw_prisma_airs.panw_prisma_airs.verbose_proxy_logger" + ) as mock_logger: + make_handler(experimental_use_latest_role_message_only=True) + + warned = " ".join(str(c) for c in mock_logger.warning.call_args_list) + assert "experimental_use_latest_role_message_only=true" in warned + assert "not rescanned" in warned + + @pytest.mark.parametrize("flag", [None, False]) + def test_no_warning_when_unset_or_disabled(self, flag): + with patch( + "litellm.proxy.guardrails.guardrail_hooks.panw_prisma_airs.panw_prisma_airs.verbose_proxy_logger" + ) as mock_logger: + make_handler(experimental_use_latest_role_message_only=flag) + + warned = " ".join(str(c) for c in mock_logger.warning.call_args_list) + assert "experimental_use_latest_role_message_only" not in warned + + class TestPanwAirsMcpToolCallWithoutCallId: """Tests for MCP tool invocations flowing through apply_guardrail without litellm_call_id — the bug fix for _convert_mcp_to_llm_format synthetic data."""