Skip to content
Merged
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
3 changes: 2 additions & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,8 @@ COPY --chown=app:app djangoapi_guard/ /app/djangoapi_guard/
COPY --chown=app:app tests/ /app/tests/
COPY --chown=app:app examples/ /app/examples/

RUN mkdir -p /app/data/ipinfo
RUN uv pip install --python .venv/bin/python --no-deps -e /app \
&& mkdir -p /app/data/ipinfo

# Probes the app service on port 8000. Any HTTP answer counts as alive; a refused connection or a timeout fails.
HEALTHCHECK --interval=10s --timeout=5s --start-period=20s --retries=3 \
Expand Down
5 changes: 2 additions & 3 deletions compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,14 @@ services:
args:
PYTHON_VERSION: ${PYTHON_VERSION:-3.10}
image: djapi-guard-example-py${PYTHON_VERSION:-3.10}
command: gunicorn examples.simple.example_project.wsgi:application --bind 0.0.0.0:8000 --reload
command: gunicorn --chdir examples/simple example_project.wsgi:application --bind 0.0.0.0:8000 --reload
ports:
- "8000:8000"
environment:
- REDIS_URL=redis://redis:6379
- REDIS_PREFIX=${REDIS_PREFIX:-"djangoapi_guard:"}
- IPINFO_TOKEN=${IPINFO_TOKEN:-"test_token"}
- DJANGO_SETTINGS_MODULE=examples.simple.example_project.settings
- DJANGO_SETTINGS_MODULE=example_project.settings
volumes:
- ./examples:/app/examples:z
- ./djangoapi_guard:/app/djangoapi_guard:z
Expand All @@ -38,7 +38,6 @@ services:
- ./djangoapi_guard:/app/djangoapi_guard:z
- ./tests:/app/tests:z
- ./pyproject.toml:/app/pyproject.toml:z
- ./uv.lock:/app/uv.lock:z
- ./vulture_whitelist.py:/app/vulture_whitelist.py:z
depends_on:
redis:
Expand Down
2 changes: 2 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ dev = [
"bandit[toml]",
"deptry",
"django-stubs",
"gunicorn",
"guard-agent",
"httpx",
"mkdocs",
Expand Down Expand Up @@ -220,6 +221,7 @@ known_first_party = ["djangoapi_guard", "guard_core"]
per_rule_ignores = { "DEP002" = [
"bandit",
"django-stubs",
"gunicorn",
"guard-agent",
"guard-core",
"httpx",
Expand Down
10 changes: 10 additions & 0 deletions tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,16 @@
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "tests.settings")


@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 = (
os.getenv("REDIS_URL") or "redis://localhost:6379"
)
SecurityConfig.model_rebuild(force=True)


@pytest.fixture
def request_factory() -> RequestFactory:
return RequestFactory()
Expand Down
4 changes: 2 additions & 2 deletions tests/test_decorators/test_advanced.py
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,7 @@ def test_honeypot_form_detection(security_config: SecurityConfig) -> None:
"application/x-www-form-urlencoded" if key == "content-type" else default
)
mock_request.body.return_value = b"bot_trap=filled"
mock_request.read_body_prefix.return_value = b"bot_trap=filled"
mock_request.read_body_prefix = lambda _max_bytes: b"bot_trap=filled"

result = validator(mock_request)
assert result is not None
Expand Down Expand Up @@ -202,7 +202,7 @@ def test_honeypot_json_detection(security_config: SecurityConfig) -> None:
)
body_bytes = json.dumps({"spam_check": "filled"}).encode()
mock_request.body.return_value = body_bytes
mock_request.read_body_prefix.return_value = body_bytes
mock_request.read_body_prefix = lambda _max_bytes: body_bytes

result = validator(mock_request)
assert result is not None
Expand Down
17 changes: 10 additions & 7 deletions tests/test_middleware.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import logging
import os
import sys
import time
from collections.abc import Awaitable, Callable, Iterator
Expand All @@ -25,6 +26,8 @@
from djangoapi_guard.adapters import DjangoGuardRequest, DjangoGuardResponse
from djangoapi_guard.middleware import DjangoAPIGuard

REDIS_URL = os.getenv("REDIS_URL") or "redis://localhost:6379"


@pytest.fixture(autouse=True)
def reset_rate_limiter() -> Iterator[None]:
Expand Down Expand Up @@ -782,7 +785,7 @@ def test_redis_initialization(self) -> None:
config = SecurityConfig(
enable_redis=True,
enable_agent=False,
redis_url="redis://localhost:6379",
redis_url=REDIS_URL,
block_cloud_providers={"AWS"},
)
with (
Expand Down Expand Up @@ -815,7 +818,7 @@ def test_redis_initialization_without_cloud(self) -> None:
config = SecurityConfig(
enable_redis=True,
enable_agent=False,
redis_url="redis://localhost:6379",
redis_url=REDIS_URL,
)
with (
patch(
Expand Down Expand Up @@ -1144,7 +1147,7 @@ def test_lua_script_execution(self) -> None:
config = SecurityConfig(
enable_redis=True,
enable_agent=False,
redis_url="redis://localhost:6379",
redis_url=REDIS_URL,
rate_limit=2,
rate_limit_window=1,
enable_rate_limiting=True,
Expand Down Expand Up @@ -1196,7 +1199,7 @@ def test_fallback_to_pipeline(self) -> None:
config = SecurityConfig(
enable_redis=True,
enable_agent=False,
redis_url="redis://localhost:6379",
redis_url=REDIS_URL,
rate_limit=2,
rate_limit_window=1,
enable_rate_limiting=True,
Expand Down Expand Up @@ -1278,7 +1281,7 @@ def test_rate_limiter_redis_errors(self) -> None:
config = SecurityConfig(
enable_redis=True,
enable_agent=False,
redis_url="redis://localhost:6379",
redis_url=REDIS_URL,
rate_limit=2,
rate_limit_window=1,
enable_rate_limiting=True,
Expand Down Expand Up @@ -1362,7 +1365,7 @@ def test_rate_limiter_init_redis_exception(self) -> None:
config = SecurityConfig(
enable_redis=True,
enable_agent=False,
redis_url="redis://localhost:6379",
redis_url=REDIS_URL,
)
handler = rate_limit_handler(config)

Expand Down Expand Up @@ -1390,7 +1393,7 @@ def test_rate_limit_reset_with_redis_errors(self) -> None:
config = SecurityConfig(
enable_redis=True,
enable_agent=False,
redis_url="redis://localhost:6379",
redis_url=REDIS_URL,
rate_limit=2,
enable_rate_limiting=True,
)
Expand Down
Loading