Files
wehub-resource-sync 7a0da7932b
OSV-Scanner (Scheduled) / scan-scheduled (push) Failing after 0s
Create Release / test-gate (push) Has been cancelled
Create Release / release-gate (push) Has been cancelled
Create Release / ci-gate (push) Has been cancelled
Create Release / version-check (push) Has been cancelled
Create Release / e2e-test-gate (push) Has been cancelled
Create Release / responsive-test-gate (push) Has been cancelled
Create Release / compat-test-gate (push) Has been cancelled
Create Release / compose-integration-gate (push) Has been cancelled
Create Release / vulture-gate (push) Has been cancelled
Create Release / build (push) Has been cancelled
Create Release / provenance (push) Has been cancelled
Create Release / prerelease-docker (push) Has been cancelled
Create Release / publish-docker (push) Has been cancelled
Create Release / create-release (push) Has been cancelled
Create Release / cleanup-changelog (push) Has been cancelled
Create Release / trigger-pypi (push) Has been cancelled
Create Release / monitor-pypi (push) Has been cancelled
Create Release / Clean up orphan prerelease tags and signatures (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [research-form] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [research-metrics] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [research-workflow] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [settings-core] (push) Has been cancelled
CodeQL Advanced / Analyze (javascript-typescript) (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [history-news] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [library] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [link-analytics] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [chat-core] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [chat-lifecycle] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [error-benchmark] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [settings-pages] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) (push) Has been cancelled
Docker Tests (Consolidated) / Accessibility Tests (push) Has been cancelled
Docker Tests (Consolidated) / LLM Unit Tests (push) Has been cancelled
Docker Tests (Consolidated) / LLM Example Tests (push) Has been cancelled
Docker Tests (Consolidated) / Production Image Smoke Test (push) Has been cancelled
Docker Tests (Consolidated) / Infrastructure Tests (push) Has been cancelled
OSSF Scorecard / OSSF Security Scorecard Analysis (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [mobile] (push) Has been cancelled
Backwards Compatibility / Verify Encryption Constants (push) Has been cancelled
Backwards Compatibility / PyPI Version Compatibility (push) Has been cancelled
Backwards Compatibility / Database Migration Tests (push) Has been cancelled
CodeQL Advanced / Analyze (python) (push) Has been cancelled
Docker Tests (Consolidated) / detect-changes (push) Has been cancelled
Docker Tests (Consolidated) / Build Test Image (push) Has been cancelled
Docker Tests (Consolidated) / All Pytest Tests + Coverage (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [accessibility] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [api-crud] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [auth-login] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [auth-pages] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [auth-register] (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 13:08:55 +08:00

97 lines
3.3 KiB
Python

"""
Tests for get_client_ip() from security/rate_limiter.py
Tests cover:
- X-Forwarded-For header parsing (single IP, multiple IPs, whitespace stripping)
- X-Real-IP header parsing (presence, whitespace stripping)
- Header priority (X-Forwarded-For over X-Real-IP)
- Fallback to get_remote_address() when no proxy headers present
"""
from unittest.mock import patch
from flask import Flask
from local_deep_research.security.rate_limiter import get_client_ip
def _make_app():
"""Create a minimal Flask test app."""
app = Flask(__name__)
app.config["TESTING"] = True
return app
class TestGetClientIp:
"""Tests for get_client_ip function."""
def test_returns_single_ip_from_x_forwarded_for(self):
"""Should return the IP when X-Forwarded-For contains a single IP."""
app = _make_app()
with app.test_request_context(
environ_base={"HTTP_X_FORWARDED_FOR": "1.2.3.4"}
):
result = get_client_ip()
assert result == "1.2.3.4"
def test_returns_first_ip_from_x_forwarded_for_with_multiple(self):
"""Should return the first IP when X-Forwarded-For has comma-separated IPs."""
app = _make_app()
with app.test_request_context(
environ_base={
"HTTP_X_FORWARDED_FOR": "1.2.3.4, 5.6.7.8, 9.10.11.12"
}
):
result = get_client_ip()
assert result == "1.2.3.4"
def test_strips_whitespace_from_x_forwarded_for(self):
"""Should strip leading/trailing whitespace from X-Forwarded-For IP."""
app = _make_app()
with app.test_request_context(
environ_base={"HTTP_X_FORWARDED_FOR": " 1.2.3.4 , 5.6.7.8"}
):
result = get_client_ip()
assert result == "1.2.3.4"
def test_returns_x_real_ip_when_no_x_forwarded_for(self):
"""Should return X-Real-IP when X-Forwarded-For is absent."""
app = _make_app()
with app.test_request_context(
environ_base={"HTTP_X_REAL_IP": "10.20.30.40"}
):
result = get_client_ip()
assert result == "10.20.30.40"
def test_strips_whitespace_from_x_real_ip(self):
"""Should strip leading/trailing whitespace from X-Real-IP."""
app = _make_app()
with app.test_request_context(
environ_base={"HTTP_X_REAL_IP": " 10.20.30.40 "}
):
result = get_client_ip()
assert result == "10.20.30.40"
def test_x_forwarded_for_takes_priority_over_x_real_ip(self):
"""X-Forwarded-For should take priority when both headers are present."""
app = _make_app()
with app.test_request_context(
environ_base={
"HTTP_X_FORWARDED_FOR": "192.168.1.1",
"HTTP_X_REAL_IP": "10.0.0.1",
}
):
result = get_client_ip()
assert result == "192.168.1.1"
def test_falls_back_to_get_remote_address(self):
"""Should fall back to get_remote_address() when no proxy headers present."""
app = _make_app()
with app.test_request_context():
with patch(
"local_deep_research.security.rate_limiter.get_remote_address",
return_value="127.0.0.1",
):
result = get_client_ip()
assert result == "127.0.0.1"