feat: add CIDR/netmask support for trusted proxy IPs

TRUSTED_PROXY_IPS now accepts CIDR notation (e.g., 192.168.1.0/24)
in addition to exact IP addresses. Supports both IPv4 and IPv6.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
2026-01-03 11:46:04 +00:00
parent 240cf440cb
commit f2145e4827
4 changed files with 250 additions and 5 deletions

View File

@@ -300,3 +300,89 @@ class TestLoggingAfter:
assert before_ms <= parsed["ts"] <= after_ms
# Should be a reasonable timestamp (year 2020+)
assert parsed["ts"] > 1577836800000 # 2020-01-01
class TestIsTrustedProxyCIDR:
"""Tests for CIDR support in is_trusted_proxy."""
def test_ip_within_cidr_is_trusted(self):
"""IP within CIDR range should be trusted."""
from animaltrack.web.middleware import is_trusted_proxy
req = MagicMock()
req.client = MagicMock(host="192.168.1.50")
settings = make_test_settings(trusted_proxy_ips="192.168.1.0/24")
assert is_trusted_proxy(req, settings) is True
def test_ip_outside_cidr_not_trusted(self):
"""IP outside CIDR range should not be trusted."""
from animaltrack.web.middleware import is_trusted_proxy
req = MagicMock()
req.client = MagicMock(host="192.168.2.50")
settings = make_test_settings(trusted_proxy_ips="192.168.1.0/24")
assert is_trusted_proxy(req, settings) is False
def test_exact_ip_still_works(self):
"""Exact IP matching should still work."""
from animaltrack.web.middleware import is_trusted_proxy
req = MagicMock()
req.client = MagicMock(host="10.0.0.1")
settings = make_test_settings(trusted_proxy_ips="10.0.0.1")
assert is_trusted_proxy(req, settings) is True
def test_mixed_exact_and_cidr(self):
"""Mix of exact IPs and CIDR should work."""
from animaltrack.web.middleware import is_trusted_proxy
settings = make_test_settings(trusted_proxy_ips="10.0.0.1,192.168.0.0/16")
# Exact IP match
req1 = MagicMock()
req1.client = MagicMock(host="10.0.0.1")
assert is_trusted_proxy(req1, settings) is True
# CIDR match
req2 = MagicMock()
req2.client = MagicMock(host="192.168.100.200")
assert is_trusted_proxy(req2, settings) is True
# No match
req3 = MagicMock()
req3.client = MagicMock(host="172.16.0.1")
assert is_trusted_proxy(req3, settings) is False
def test_ipv6_cidr_matching(self):
"""IPv6 CIDR matching should work."""
from animaltrack.web.middleware import is_trusted_proxy
settings = make_test_settings(trusted_proxy_ips="fd00::/8")
req = MagicMock()
req.client = MagicMock(host="fd12:3456:789a::1")
assert is_trusted_proxy(req, settings) is True
req2 = MagicMock()
req2.client = MagicMock(host="fe80::1")
assert is_trusted_proxy(req2, settings) is False
def test_localhost_cidr(self):
"""Localhost CIDR should work."""
from animaltrack.web.middleware import is_trusted_proxy
settings = make_test_settings(trusted_proxy_ips="127.0.0.0/8")
req = MagicMock()
req.client = MagicMock(host="127.0.0.1")
assert is_trusted_proxy(req, settings) is True
req2 = MagicMock()
req2.client = MagicMock(host="127.255.255.255")
assert is_trusted_proxy(req2, settings) is True