mirror of
https://github.com/crewAIInc/crewAI.git
synced 2026-08-10 08:21:54 +00:00
fix: clear CodeQL incomplete URL substring sanitization alerts (#6804)
Some checks failed
CodeQL Advanced / Analyze (actions) (push) Has been cancelled
CodeQL Advanced / Analyze (python) (push) Has been cancelled
Vulnerability Scan / Detect changes (push) Has been cancelled
Vulnerability Scan / pip-audit (push) Has been cancelled
Nightly Canary Release / Check for new commits (push) Has been cancelled
Nightly Canary Release / Build nightly packages (push) Has been cancelled
Nightly Canary Release / Publish nightly to PyPI (push) Has been cancelled
Mark stale issues and pull requests / stale (push) Has been cancelled
Some checks failed
CodeQL Advanced / Analyze (actions) (push) Has been cancelled
CodeQL Advanced / Analyze (python) (push) Has been cancelled
Vulnerability Scan / Detect changes (push) Has been cancelled
Vulnerability Scan / pip-audit (push) Has been cancelled
Nightly Canary Release / Check for new commits (push) Has been cancelled
Nightly Canary Release / Build nightly packages (push) Has been cancelled
Nightly Canary Release / Publish nightly to PyPI (push) Has been cancelled
Mark stale issues and pull requests / stale (push) Has been cancelled
* fix: clear CodeQL incomplete URL substring sanitization alerts Replace hostname substring checks with urlparse hostname matching in RAG DataType classification, and assert the full mocked Stagehand navigate result instead of searching for a URL substring. Co-authored-by: Rip&Tear <theCyberTech@users.noreply.github.com> * test: call DataTypes.from_content in GitHub hostname tests from_content lives on DataTypes, not the DataType enum. Co-authored-by: Rip&Tear <theCyberTech@users.noreply.github.com> * test: harden tool-call streaming emit mock against instance shadowing CI failed when class-level CrewAIEventsBus.emit patches were shadowed by the singleton instance. Patch both the class and crewai_event_bus.emit, and read events from kwargs/args explicitly. Co-authored-by: Rip&Tear <theCyberTech@users.noreply.github.com> --------- Co-authored-by: Cursor Agent <cursoragent@cursor.com> Co-authored-by: Rip&Tear <theCyberTech@users.noreply.github.com>
This commit is contained in:
@@ -135,7 +135,8 @@ class DataTypes:
|
||||
|
||||
if "docs" in url.netloc or ("docs" in url.path and url.scheme != "file"):
|
||||
return DataType.DOCS_SITE
|
||||
if "github.com" in url.netloc:
|
||||
hostname = (url.hostname or "").lower()
|
||||
if hostname == "github.com" or hostname.endswith(".github.com"):
|
||||
return DataType.GITHUB
|
||||
|
||||
return DataType.WEBSITE
|
||||
|
||||
32
lib/crewai-tools/tests/rag/test_data_types.py
Normal file
32
lib/crewai-tools/tests/rag/test_data_types.py
Normal file
@@ -0,0 +1,32 @@
|
||||
"""Tests for DataTypes content classification."""
|
||||
|
||||
from crewai_tools.rag.data_types import DataType, DataTypes
|
||||
|
||||
|
||||
class TestDataTypesFromContentGitHub:
|
||||
"""GitHub URL detection must use hostname matching, not substrings."""
|
||||
|
||||
def test_github_com_url(self) -> None:
|
||||
assert (
|
||||
DataTypes.from_content("https://github.com/crewai/crewai")
|
||||
== DataType.GITHUB
|
||||
)
|
||||
|
||||
def test_github_subdomain_url(self) -> None:
|
||||
assert (
|
||||
DataTypes.from_content("https://gist.github.com/user/abc")
|
||||
== DataType.GITHUB
|
||||
)
|
||||
|
||||
def test_spoofed_github_hostname_is_website(self) -> None:
|
||||
# Substring checks like `"github.com" in netloc` would misclassify this.
|
||||
assert (
|
||||
DataTypes.from_content("https://github.com.evil.example/crewai")
|
||||
== DataType.WEBSITE
|
||||
)
|
||||
|
||||
def test_github_in_path_is_not_github(self) -> None:
|
||||
assert (
|
||||
DataTypes.from_content("https://example.com/github.com/repo")
|
||||
== DataType.WEBSITE
|
||||
)
|
||||
@@ -163,8 +163,14 @@ def test_navigate_command(mock_run, stagehand_tool):
|
||||
command_type="navigate",
|
||||
)
|
||||
|
||||
# Assertions
|
||||
assert "https://example.com" in result
|
||||
# Assertions — compare the full mocked result (avoid URL substring checks)
|
||||
assert result == "Successfully navigated to https://example.com"
|
||||
mock_run.assert_called_once_with(
|
||||
stagehand_tool,
|
||||
instruction="Go to example.com",
|
||||
url="https://example.com",
|
||||
command_type="navigate",
|
||||
)
|
||||
|
||||
|
||||
@patch(
|
||||
|
||||
@@ -38,18 +38,33 @@ def get_temperature_tool_schema() -> dict[str, Any]:
|
||||
|
||||
@pytest.fixture
|
||||
def mock_emit() -> MagicMock:
|
||||
"""Mock the event bus emit function."""
|
||||
from crewai.events.event_bus import CrewAIEventsBus
|
||||
"""Mock the singleton event bus emit used by LLM providers.
|
||||
|
||||
with patch.object(CrewAIEventsBus, "emit") as mock:
|
||||
yield mock
|
||||
Patch the singleton instance (not only the class) so a leftover
|
||||
instance-level ``emit`` from other tests cannot shadow the mock.
|
||||
"""
|
||||
from crewai.events.event_bus import CrewAIEventsBus, crewai_event_bus
|
||||
|
||||
with (
|
||||
patch.object(CrewAIEventsBus, "emit") as class_mock,
|
||||
patch.object(crewai_event_bus, "emit", new=class_mock),
|
||||
):
|
||||
yield class_mock
|
||||
|
||||
|
||||
def _event_from_emit_call(call: Any) -> Any:
|
||||
"""Return the event argument from an emit mock call."""
|
||||
event = call.kwargs.get("event")
|
||||
if event is None and len(call.args) >= 2:
|
||||
event = call.args[1]
|
||||
return event
|
||||
|
||||
|
||||
def get_tool_call_events(mock_emit: MagicMock) -> list[LLMStreamChunkEvent]:
|
||||
"""Extract tool call streaming events from mock emit calls."""
|
||||
tool_call_events = []
|
||||
for call in mock_emit.call_args_list:
|
||||
event = call[1].get("event") if len(call) > 1 else None
|
||||
event = _event_from_emit_call(call)
|
||||
if isinstance(event, LLMStreamChunkEvent) and event.call_type == LLMCallType.TOOL_CALL:
|
||||
tool_call_events.append(event)
|
||||
return tool_call_events
|
||||
@@ -59,7 +74,7 @@ def get_all_stream_events(mock_emit: MagicMock) -> list[LLMStreamChunkEvent]:
|
||||
"""Extract all streaming events from mock emit calls."""
|
||||
stream_events = []
|
||||
for call in mock_emit.call_args_list:
|
||||
event = call[1].get("event") if len(call) > 1 else None
|
||||
event = _event_from_emit_call(call)
|
||||
if isinstance(event, LLMStreamChunkEvent):
|
||||
stream_events.append(event)
|
||||
return stream_events
|
||||
|
||||
Reference in New Issue
Block a user