diff --git a/Dockerfile b/Dockerfile index 3e5f9c68..bf2a232a 100644 --- a/Dockerfile +++ b/Dockerfile @@ -18,7 +18,7 @@ USER 10001 COPY --chown=app:app pyproject.toml uv.lock* README.md /app/ -RUN uv sync --extra dev --frozen +RUN uv sync --extra dev ENV PATH="/app/.venv/bin:$PATH" diff --git a/compose.yml b/compose.yml index 17423bb3..c686a98d 100644 --- a/compose.yml +++ b/compose.yml @@ -38,7 +38,6 @@ services: - ./tests:/app/tests:z - ./docs:/app/docs:z - ./pyproject.toml:/app/pyproject.toml:z - - ./uv.lock:/app/uv.lock:z - ./vulture_whitelist.py:/app/vulture_whitelist.py:z depends_on: redis: diff --git a/tests/conftest.py b/tests/conftest.py index 2d7e63ad..38a35d37 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -60,6 +60,14 @@ async def _clear_middleware_state_registry() -> AsyncGenerator[None, None]: REDIS_PREFIX = os.getenv("REDIS_PREFIX") or "test:fastapi_guard:" +@pytest.fixture(scope="session", autouse=True) +def _engine_default_redis_url_follows_redis_url() -> None: + # A SecurityConfig built without redis_url falls back to localhost:6379, which + # is not where Redis lives inside the compose network. + SecurityConfig.model_fields["redis_url"].default = REDIS_URL + SecurityConfig.model_rebuild(force=True) + + @pytest.fixture(autouse=True) async def reset_state() -> AsyncGenerator[None, None]: # Reset IPBanManager diff --git a/tests/test_decorators/test_middleware_integration.py b/tests/test_decorators/test_middleware_integration.py index e4217aeb..5c5e0a4c 100644 --- a/tests/test_decorators/test_middleware_integration.py +++ b/tests/test_decorators/test_middleware_integration.py @@ -1,3 +1,4 @@ +import os from unittest.mock import AsyncMock, Mock, patch import pytest @@ -12,6 +13,8 @@ from guard.adapters import StarletteGuardResponse from guard.middleware import SecurityMiddleware +REDIS_URL = os.getenv("REDIS_URL") or "redis://localhost:6379" + def _http_scope( *, path: str = "/test", headers: list[tuple[bytes, bytes]] | None = None @@ -553,7 +556,7 @@ async def mock_call_next(request: Request) -> Response: async def test_route_specific_rate_limit_with_redis() -> None: app = FastAPI() - config = SecurityConfig(enable_redis=True, redis_url="redis://localhost:6379") + config = SecurityConfig(enable_redis=True, redis_url=REDIS_URL) middleware = SecurityMiddleware(app, config=config) mock_redis_handler = Mock() diff --git a/tests/test_middleware/test_redis_unavailable_response.py b/tests/test_middleware/test_redis_unavailable_response.py index 44eb3767..4efd1e71 100644 --- a/tests/test_middleware/test_redis_unavailable_response.py +++ b/tests/test_middleware/test_redis_unavailable_response.py @@ -1,3 +1,5 @@ +import os + import pytest from fastapi import FastAPI from fastapi.testclient import TestClient @@ -7,6 +9,8 @@ from guard.lifespan import guard_lifespan from guard.middleware import SecurityMiddleware +REDIS_URL = os.getenv("REDIS_URL") or "redis://localhost:6379" + DEAD_REDIS_URL = "redis://127.0.0.1:6399" @@ -44,7 +48,7 @@ def test_next_request_succeeds_once_redis_initialization_recovers( real_initialize = RedisManager.initialize async def _fake_initialize(self: RedisManager) -> None: - self.config.redis_url = "redis://localhost:6379" + self.config.redis_url = REDIS_URL await real_initialize(self) monkeypatch.setattr(RedisManager, "initialize", _fake_initialize)