diff --git a/lib/crewai-tools/src/crewai_tools/tools/crewai_platform_tools/crewai_platform_action_tool.py b/lib/crewai-tools/src/crewai_tools/tools/crewai_platform_tools/crewai_platform_action_tool.py index 3a3ae3be9..d7e878f13 100644 --- a/lib/crewai-tools/src/crewai_tools/tools/crewai_platform_tools/crewai_platform_action_tool.py +++ b/lib/crewai-tools/src/crewai_tools/tools/crewai_platform_tools/crewai_platform_action_tool.py @@ -1,7 +1,6 @@ """Crewai Enterprise Tools.""" import json -import os from typing import Any from crewai.tools import BaseTool @@ -12,6 +11,7 @@ import requests from crewai_tools.tools.crewai_platform_tools.misc import ( get_platform_api_base_url, get_platform_integration_token, + platform_tls_verify, ) @@ -72,7 +72,7 @@ class CrewAIPlatformActionTool(BaseTool): headers=headers, json=payload, timeout=60, - verify=os.environ.get("CREWAI_FACTORY", "false").lower() != "true", + verify=platform_tls_verify(), ) data = response.json() diff --git a/lib/crewai-tools/src/crewai_tools/tools/crewai_platform_tools/crewai_platform_tool_builder.py b/lib/crewai-tools/src/crewai_tools/tools/crewai_platform_tools/crewai_platform_tool_builder.py index e9cc8c3e6..25034561b 100644 --- a/lib/crewai-tools/src/crewai_tools/tools/crewai_platform_tools/crewai_platform_tool_builder.py +++ b/lib/crewai-tools/src/crewai_tools/tools/crewai_platform_tools/crewai_platform_tool_builder.py @@ -1,7 +1,6 @@ """CrewAI platform tool builder for fetching and creating action tools.""" import logging -import os from types import TracebackType from typing import Any @@ -14,6 +13,7 @@ from crewai_tools.tools.crewai_platform_tools.crewai_platform_action_tool import from crewai_tools.tools.crewai_platform_tools.misc import ( get_platform_api_base_url, get_platform_integration_token, + platform_tls_verify, ) @@ -49,7 +49,7 @@ class CrewaiPlatformToolBuilder: headers=headers, timeout=30, params={"apps": ",".join(self._apps)}, - verify=os.environ.get("CREWAI_FACTORY", "false").lower() != "true", + verify=platform_tls_verify(), ) response.raise_for_status() except Exception as e: diff --git a/lib/crewai-tools/src/crewai_tools/tools/crewai_platform_tools/misc.py b/lib/crewai-tools/src/crewai_tools/tools/crewai_platform_tools/misc.py index 06cf7147d..2427f355e 100644 --- a/lib/crewai-tools/src/crewai_tools/tools/crewai_platform_tools/misc.py +++ b/lib/crewai-tools/src/crewai_tools/tools/crewai_platform_tools/misc.py @@ -1,4 +1,35 @@ import os +import warnings + + +def platform_tls_verify() -> bool: + """TLS verification setting for CrewAI platform API requests. + + Verification is ON by default and should stay on: these requests carry the + platform integration token, so an unverified connection exposes it to + man-in-the-middle attacks. It can be disabled only via an explicit opt-out + (``CREWAI_PLATFORM_INSECURE_SKIP_TLS_VERIFY``; the legacy ``CREWAI_FACTORY`` + is still honored for internal builds), and doing so warns loudly. To trust a + self-signed endpoint *securely*, leave verification on and point requests at + the CA bundle via the standard ``REQUESTS_CA_BUNDLE`` environment variable. + """ + if ( + os.getenv("CREWAI_PLATFORM_INSECURE_SKIP_TLS_VERIFY", "false").strip().lower() + == "true" + or os.getenv("CREWAI_FACTORY", "false").strip().lower() == "true" + ): + warnings.warn( + "TLS certificate verification is DISABLED for CrewAI platform API " + "requests; the integration token is sent over an unverified connection " + "and is exposed to man-in-the-middle attacks. Unset " + "CREWAI_PLATFORM_INSECURE_SKIP_TLS_VERIFY (and the legacy CREWAI_FACTORY). " + "To trust a self-signed endpoint securely, keep verification on and set " + "REQUESTS_CA_BUNDLE to your CA instead.", + UserWarning, + stacklevel=2, + ) + return False + return True def get_platform_api_base_url() -> str: diff --git a/lib/crewai-tools/tests/tools/crewai_platform_tools/test_platform_tls_verify.py b/lib/crewai-tools/tests/tools/crewai_platform_tools/test_platform_tls_verify.py new file mode 100644 index 000000000..2af224d74 --- /dev/null +++ b/lib/crewai-tools/tests/tools/crewai_platform_tools/test_platform_tls_verify.py @@ -0,0 +1,44 @@ +"""Tests for platform-API TLS verification behavior.""" + +import warnings + +import pytest + +from crewai_tools.tools.crewai_platform_tools.misc import platform_tls_verify + + +@pytest.fixture(autouse=True) +def _clear_tls_env(monkeypatch: pytest.MonkeyPatch) -> None: + monkeypatch.delenv("CREWAI_FACTORY", raising=False) + monkeypatch.delenv("CREWAI_PLATFORM_INSECURE_SKIP_TLS_VERIFY", raising=False) + + +def test_tls_verify_on_by_default() -> None: + with warnings.catch_warnings(): + warnings.simplefilter("error") # any warning would fail the test + assert platform_tls_verify() is True + + +def test_tls_verify_disabled_by_explicit_flag_warns_loudly( + monkeypatch: pytest.MonkeyPatch, +) -> None: + monkeypatch.setenv("CREWAI_PLATFORM_INSECURE_SKIP_TLS_VERIFY", "true") + with pytest.warns(UserWarning, match="TLS certificate verification is DISABLED"): + assert platform_tls_verify() is False + + +def test_tls_verify_disabled_by_legacy_factory_flag_warns_loudly( + monkeypatch: pytest.MonkeyPatch, +) -> None: + # Back-compat: CREWAI_FACTORY still disables, but now loudly instead of silently. + monkeypatch.setenv("CREWAI_FACTORY", "true") + with pytest.warns(UserWarning, match="TLS certificate verification is DISABLED"): + assert platform_tls_verify() is False + + +def test_tls_verify_only_exact_true_disables(monkeypatch: pytest.MonkeyPatch) -> None: + # A stray non-"true" value must not silently drop TLS verification. + monkeypatch.setenv("CREWAI_FACTORY", "1") + with warnings.catch_warnings(): + warnings.simplefilter("error") + assert platform_tls_verify() is True