Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion api/services/auth/firecrawl/firecrawl.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@

from services.auth.api_key_auth_base import ApiKeyAuthBase, AuthCredentials

_CREDENTIAL_VALIDATION_TIMEOUT = httpx.Timeout(10.0, connect=3.0)


class FirecrawlAuth(ApiKeyAuthBase):
def __init__(self, credentials: AuthCredentials):
Expand Down Expand Up @@ -42,7 +44,7 @@ def _build_url(self, path: str) -> str:
return f"{self.base_url.rstrip('/')}/{path.lstrip('/')}"

def _post_request(self, url, data, headers):
return httpx.post(url, headers=headers, json=data)
return httpx.post(url, headers=headers, json=data, timeout=_CREDENTIAL_VALIDATION_TIMEOUT)

def _handle_error(self, response):
try:
Expand Down
19 changes: 18 additions & 1 deletion api/tests/unit_tests/services/auth/test_firecrawl_auth.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
import httpx
import pytest

from services.auth.firecrawl.firecrawl import FirecrawlAuth
from services.auth.firecrawl.firecrawl import _CREDENTIAL_VALIDATION_TIMEOUT, FirecrawlAuth


class TestFirecrawlAuth:
Expand Down Expand Up @@ -86,6 +86,7 @@ def test_should_validate_valid_credentials_successfully(self, mock_post, auth_in
"https://api.firecrawl.dev/v1/crawl",
headers={"Content-Type": "application/json", "Authorization": "Bearer test_api_key_123"},
json=expected_data,
timeout=_CREDENTIAL_VALIDATION_TIMEOUT,
)

@pytest.mark.parametrize(
Expand Down Expand Up @@ -195,3 +196,19 @@ def test_should_handle_timeout_with_retry_suggestion(self, mock_post, auth_insta

# Verify the timeout exception is raised with original message
assert "timed out" in str(exc_info.value)

@patch("services.auth.firecrawl.firecrawl.httpx.post", autospec=True)
def test_should_pass_bounded_timeout_to_credential_validation(self, mock_post, auth_instance):
"""Credential validation must not use the default unbounded timeout."""
mock_response = MagicMock()
mock_response.status_code = 200
mock_post.return_value = mock_response

auth_instance.validate_credentials()

call_kwargs = mock_post.call_args
assert "timeout" in call_kwargs.kwargs, "timeout keyword is missing from _post_request"
timeout = call_kwargs.kwargs["timeout"]
assert isinstance(timeout, httpx.Timeout)
assert timeout.connect == _CREDENTIAL_VALIDATION_TIMEOUT.connect
assert timeout.read == _CREDENTIAL_VALIDATION_TIMEOUT.read
Loading