7a0da7932b
Backwards Compatibility / Verify Encryption Constants (push) Waiting to run
Backwards Compatibility / PyPI Version Compatibility (push) Waiting to run
Backwards Compatibility / Database Migration Tests (push) Waiting to run
CodeQL Advanced / Analyze (javascript-typescript) (push) Waiting to run
CodeQL Advanced / Analyze (python) (push) Waiting to run
Docker Tests (Consolidated) / UI Tests (Puppeteer) [research-form] (push) Blocked by required conditions
Docker Tests (Consolidated) / UI Tests (Puppeteer) [research-metrics] (push) Blocked by required conditions
Docker Tests (Consolidated) / UI Tests (Puppeteer) [research-workflow] (push) Blocked by required conditions
Docker Tests (Consolidated) / UI Tests (Puppeteer) [settings-core] (push) Blocked by required conditions
Docker Tests (Consolidated) / UI Tests (Puppeteer) [settings-pages] (push) Blocked by required conditions
Docker Tests (Consolidated) / UI Tests (Puppeteer) [history-news] (push) Blocked by required conditions
Docker Tests (Consolidated) / UI Tests (Puppeteer) [library] (push) Blocked by required conditions
Docker Tests (Consolidated) / UI Tests (Puppeteer) [link-analytics] (push) Blocked by required conditions
Docker Tests (Consolidated) / UI Tests (Puppeteer) [mobile] (push) Blocked by required conditions
Docker Tests (Consolidated) / detect-changes (push) Waiting to run
Docker Tests (Consolidated) / Build Test Image (push) Waiting to run
Docker Tests (Consolidated) / All Pytest Tests + Coverage (push) Blocked by required conditions
Docker Tests (Consolidated) / UI Tests (Puppeteer) [accessibility] (push) Blocked by required conditions
Docker Tests (Consolidated) / UI Tests (Puppeteer) [api-crud] (push) Blocked by required conditions
Docker Tests (Consolidated) / UI Tests (Puppeteer) [auth-login] (push) Blocked by required conditions
Docker Tests (Consolidated) / UI Tests (Puppeteer) [auth-pages] (push) Blocked by required conditions
Docker Tests (Consolidated) / UI Tests (Puppeteer) [auth-register] (push) Blocked by required conditions
Docker Tests (Consolidated) / UI Tests (Puppeteer) [chat-core] (push) Blocked by required conditions
Docker Tests (Consolidated) / UI Tests (Puppeteer) [chat-lifecycle] (push) Blocked by required conditions
Docker Tests (Consolidated) / UI Tests (Puppeteer) [error-benchmark] (push) Blocked by required conditions
Docker Tests (Consolidated) / UI Tests (Puppeteer) (push) Blocked by required conditions
Docker Tests (Consolidated) / Accessibility Tests (push) Blocked by required conditions
Docker Tests (Consolidated) / LLM Unit Tests (push) Blocked by required conditions
Docker Tests (Consolidated) / LLM Example Tests (push) Blocked by required conditions
Docker Tests (Consolidated) / Production Image Smoke Test (push) Blocked by required conditions
Docker Tests (Consolidated) / Infrastructure Tests (push) Blocked by required conditions
OSSF Scorecard / OSSF Security Scorecard Analysis (push) Waiting to run
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
324 lines
11 KiB
Python
324 lines
11 KiB
Python
"""
|
|
Behavioral tests for network_utils module.
|
|
|
|
Tests the is_private_ip function which determines if IP addresses
|
|
or hostnames are private/local.
|
|
"""
|
|
|
|
|
|
class TestIsPrivateIPv4Loopback:
|
|
"""Tests for IPv4 loopback address detection."""
|
|
|
|
def test_localhost_string_is_private(self):
|
|
"""Localhost hostname is private."""
|
|
from local_deep_research.security.network_utils import is_private_ip
|
|
|
|
assert is_private_ip("localhost") is True
|
|
|
|
def test_127_0_0_1_is_private(self):
|
|
"""127.0.0.1 loopback is private."""
|
|
from local_deep_research.security.network_utils import is_private_ip
|
|
|
|
assert is_private_ip("127.0.0.1") is True
|
|
|
|
def test_127_0_0_0_is_private(self):
|
|
"""Start of loopback range is private."""
|
|
from local_deep_research.security.network_utils import is_private_ip
|
|
|
|
assert is_private_ip("127.0.0.0") is True
|
|
|
|
def test_127_255_255_255_is_private(self):
|
|
"""End of loopback range is private."""
|
|
from local_deep_research.security.network_utils import is_private_ip
|
|
|
|
assert is_private_ip("127.255.255.255") is True
|
|
|
|
def test_0_0_0_0_is_private(self):
|
|
"""0.0.0.0 is treated as private."""
|
|
from local_deep_research.security.network_utils import is_private_ip
|
|
|
|
assert is_private_ip("0.0.0.0") is True
|
|
|
|
|
|
class TestIsPrivateIPv4RFC1918:
|
|
"""Tests for RFC 1918 private IPv4 ranges."""
|
|
|
|
def test_10_0_0_1_is_private(self):
|
|
"""10.0.0.1 (Class A private) is private."""
|
|
from local_deep_research.security.network_utils import is_private_ip
|
|
|
|
assert is_private_ip("10.0.0.1") is True
|
|
|
|
def test_10_255_255_255_is_private(self):
|
|
"""End of 10.x.x.x range is private."""
|
|
from local_deep_research.security.network_utils import is_private_ip
|
|
|
|
assert is_private_ip("10.255.255.255") is True
|
|
|
|
def test_172_16_0_1_is_private(self):
|
|
"""172.16.0.1 (Class B private start) is private."""
|
|
from local_deep_research.security.network_utils import is_private_ip
|
|
|
|
assert is_private_ip("172.16.0.1") is True
|
|
|
|
def test_172_31_255_255_is_private(self):
|
|
"""172.31.255.255 (Class B private end) is private."""
|
|
from local_deep_research.security.network_utils import is_private_ip
|
|
|
|
assert is_private_ip("172.31.255.255") is True
|
|
|
|
def test_172_15_0_1_is_not_private(self):
|
|
"""172.15.0.1 is outside private range."""
|
|
from local_deep_research.security.network_utils import is_private_ip
|
|
|
|
assert is_private_ip("172.15.0.1") is False
|
|
|
|
def test_172_32_0_1_is_not_private(self):
|
|
"""172.32.0.1 is outside private range."""
|
|
from local_deep_research.security.network_utils import is_private_ip
|
|
|
|
assert is_private_ip("172.32.0.1") is False
|
|
|
|
def test_192_168_0_1_is_private(self):
|
|
"""192.168.0.1 (Class C private) is private."""
|
|
from local_deep_research.security.network_utils import is_private_ip
|
|
|
|
assert is_private_ip("192.168.0.1") is True
|
|
|
|
def test_192_168_255_255_is_private(self):
|
|
"""192.168.255.255 (Class C private end) is private."""
|
|
from local_deep_research.security.network_utils import is_private_ip
|
|
|
|
assert is_private_ip("192.168.255.255") is True
|
|
|
|
|
|
class TestIsPrivateIPv4Public:
|
|
"""Tests for public IPv4 addresses."""
|
|
|
|
def test_8_8_8_8_is_not_private(self):
|
|
"""Google DNS is public."""
|
|
from local_deep_research.security.network_utils import is_private_ip
|
|
|
|
assert is_private_ip("8.8.8.8") is False
|
|
|
|
def test_1_1_1_1_is_not_private(self):
|
|
"""Cloudflare DNS is public."""
|
|
from local_deep_research.security.network_utils import is_private_ip
|
|
|
|
assert is_private_ip("1.1.1.1") is False
|
|
|
|
def test_208_67_222_222_is_not_private(self):
|
|
"""OpenDNS is public."""
|
|
from local_deep_research.security.network_utils import is_private_ip
|
|
|
|
assert is_private_ip("208.67.222.222") is False
|
|
|
|
def test_93_184_216_34_is_not_private(self):
|
|
"""example.com IP is public."""
|
|
from local_deep_research.security.network_utils import is_private_ip
|
|
|
|
assert is_private_ip("93.184.216.34") is False
|
|
|
|
|
|
class TestIsPrivateIPv4LinkLocal:
|
|
"""Tests for link-local IPv4 addresses."""
|
|
|
|
def test_169_254_0_1_is_private(self):
|
|
"""Link-local start is private."""
|
|
from local_deep_research.security.network_utils import is_private_ip
|
|
|
|
assert is_private_ip("169.254.0.1") is True
|
|
|
|
def test_169_254_255_254_is_private(self):
|
|
"""Link-local end is private."""
|
|
from local_deep_research.security.network_utils import is_private_ip
|
|
|
|
assert is_private_ip("169.254.255.254") is True
|
|
|
|
def test_169_253_0_1_is_not_link_local(self):
|
|
"""Address just below link-local range."""
|
|
from local_deep_research.security.network_utils import is_private_ip
|
|
|
|
assert is_private_ip("169.253.0.1") is False
|
|
|
|
|
|
class TestIsPrivateIPv6:
|
|
"""Tests for IPv6 addresses."""
|
|
|
|
def test_ipv6_loopback_is_private(self):
|
|
"""IPv6 loopback is private."""
|
|
from local_deep_research.security.network_utils import is_private_ip
|
|
|
|
assert is_private_ip("::1") is True
|
|
|
|
def test_bracketed_ipv6_loopback_is_private(self):
|
|
"""Bracketed IPv6 loopback is private."""
|
|
from local_deep_research.security.network_utils import is_private_ip
|
|
|
|
assert is_private_ip("[::1]") is True
|
|
|
|
def test_fc00_prefix_is_private(self):
|
|
"""fc00::/7 unique local is private."""
|
|
from local_deep_research.security.network_utils import is_private_ip
|
|
|
|
assert is_private_ip("fc00::1") is True
|
|
|
|
def test_fd00_prefix_is_private(self):
|
|
"""fd00:: unique local is private."""
|
|
from local_deep_research.security.network_utils import is_private_ip
|
|
|
|
assert is_private_ip("fd00::1") is True
|
|
|
|
def test_fe80_prefix_is_private(self):
|
|
"""fe80:: link-local is private."""
|
|
from local_deep_research.security.network_utils import is_private_ip
|
|
|
|
assert is_private_ip("fe80::1") is True
|
|
|
|
def test_2001_4860_is_not_private(self):
|
|
"""Google IPv6 is public."""
|
|
from local_deep_research.security.network_utils import is_private_ip
|
|
|
|
assert is_private_ip("2001:4860:4860::8888") is False
|
|
|
|
def test_bracketed_ipv6_public(self):
|
|
"""Bracketed public IPv6 is not private."""
|
|
from local_deep_research.security.network_utils import is_private_ip
|
|
|
|
assert is_private_ip("[2001:4860:4860::8888]") is False
|
|
|
|
|
|
class TestIsPrivateMDNS:
|
|
"""Tests for mDNS .local domains."""
|
|
|
|
def test_local_domain_is_private(self):
|
|
"""Host.local is private."""
|
|
from local_deep_research.security.network_utils import is_private_ip
|
|
|
|
assert is_private_ip("myhost.local") is True
|
|
|
|
def test_nested_local_domain_is_private(self):
|
|
"""subdomain.host.local is private."""
|
|
from local_deep_research.security.network_utils import is_private_ip
|
|
|
|
assert is_private_ip("sub.myhost.local") is True
|
|
|
|
def test_local_only_is_private(self):
|
|
"""Just .local is private."""
|
|
from local_deep_research.security.network_utils import is_private_ip
|
|
|
|
assert is_private_ip("something.local") is True
|
|
|
|
def test_localhost_is_local_domain(self):
|
|
"""localhost ends with local but is handled separately."""
|
|
from local_deep_research.security.network_utils import is_private_ip
|
|
|
|
# localhost is handled as special case before .local check
|
|
assert is_private_ip("localhost") is True
|
|
|
|
|
|
class TestIsPrivateHostnames:
|
|
"""Tests for regular hostnames."""
|
|
|
|
def test_public_hostname_is_not_private(self):
|
|
"""api.openai.com is public."""
|
|
from local_deep_research.security.network_utils import is_private_ip
|
|
|
|
assert is_private_ip("api.openai.com") is False
|
|
|
|
def test_google_hostname_is_not_private(self):
|
|
"""google.com is public."""
|
|
from local_deep_research.security.network_utils import is_private_ip
|
|
|
|
assert is_private_ip("google.com") is False
|
|
|
|
def test_example_hostname_is_not_private(self):
|
|
"""example.com is public."""
|
|
from local_deep_research.security.network_utils import is_private_ip
|
|
|
|
assert is_private_ip("example.com") is False
|
|
|
|
def test_github_hostname_is_not_private(self):
|
|
"""github.com is public."""
|
|
from local_deep_research.security.network_utils import is_private_ip
|
|
|
|
assert is_private_ip("github.com") is False
|
|
|
|
def test_localhost_subdomain_is_not_special(self):
|
|
"""subdomain.localhost is not treated as localhost."""
|
|
from local_deep_research.security.network_utils import is_private_ip
|
|
|
|
# subdomain.localhost is not in the special list
|
|
# and doesn't end with .local
|
|
assert is_private_ip("sub.localhost") is False
|
|
|
|
|
|
class TestIsPrivateEdgeCases:
|
|
"""Tests for edge cases and boundary conditions."""
|
|
|
|
def test_empty_string_is_not_private(self):
|
|
"""Empty string returns False."""
|
|
from local_deep_research.security.network_utils import is_private_ip
|
|
|
|
assert is_private_ip("") is False
|
|
|
|
def test_invalid_ip_format(self):
|
|
"""Invalid IP format is not private."""
|
|
from local_deep_research.security.network_utils import is_private_ip
|
|
|
|
assert is_private_ip("999.999.999.999") is False
|
|
|
|
def test_partial_ip_is_not_private(self):
|
|
"""Partial IP like 192.168 is not valid."""
|
|
from local_deep_research.security.network_utils import is_private_ip
|
|
|
|
assert is_private_ip("192.168") is False
|
|
|
|
def test_ip_with_port_is_hostname(self):
|
|
"""IP:port is treated as hostname."""
|
|
from local_deep_research.security.network_utils import is_private_ip
|
|
|
|
# 192.168.1.1:8080 is not a valid IP address
|
|
# It will be treated as a hostname
|
|
assert is_private_ip("192.168.1.1:8080") is False
|
|
|
|
def test_negative_octets_invalid(self):
|
|
"""Negative octets are invalid."""
|
|
from local_deep_research.security.network_utils import is_private_ip
|
|
|
|
assert is_private_ip("-1.0.0.0") is False
|
|
|
|
def test_whitespace_not_private(self):
|
|
"""Whitespace-only string is not private."""
|
|
from local_deep_research.security.network_utils import is_private_ip
|
|
|
|
assert is_private_ip(" ") is False
|
|
|
|
def test_special_characters_not_private(self):
|
|
"""Special characters not private."""
|
|
from local_deep_research.security.network_utils import is_private_ip
|
|
|
|
assert is_private_ip("@#$%") is False
|
|
|
|
|
|
class TestIsPrivateCarrierGradeNAT:
|
|
"""Tests for Carrier-Grade NAT (CGNAT) addresses."""
|
|
|
|
def test_100_64_0_1_is_private(self):
|
|
"""100.64.0.1 (CGNAT) is private."""
|
|
from local_deep_research.security.network_utils import is_private_ip
|
|
|
|
# CGNAT range is 100.64.0.0/10, which is_private considers private
|
|
# because it's in the shared address space
|
|
result = is_private_ip("100.64.0.1")
|
|
# This could be True or False depending on implementation
|
|
# CGNAT is technically "shared" not "private" in RFC terms
|
|
assert isinstance(result, bool)
|
|
|
|
def test_100_127_255_255_is_in_cgnat_range(self):
|
|
"""100.127.255.255 (end of CGNAT) boundary check."""
|
|
from local_deep_research.security.network_utils import is_private_ip
|
|
|
|
result = is_private_ip("100.127.255.255")
|
|
assert isinstance(result, bool)
|