TestValidateSafeUrl Class — langchain Architecture
Architecture documentation for the TestValidateSafeUrl class in test_ssrf_protection.py from the langchain codebase.
Entity Profile
Dependency Diagram
graph TD 55eb5d18_546a_f8ab_e6ce_af072e9c336d["TestValidateSafeUrl"] 809833dd_a5e7_1f87_e9af_5c61581d9739["test_ssrf_protection.py"] 55eb5d18_546a_f8ab_e6ce_af072e9c336d -->|defined in| 809833dd_a5e7_1f87_e9af_5c61581d9739 ee237cd8_5d94_3663_13c0_e4f6ffd3a0c0["test_valid_public_https_url()"] 55eb5d18_546a_f8ab_e6ce_af072e9c336d -->|method| ee237cd8_5d94_3663_13c0_e4f6ffd3a0c0 69461f1f_b422_cdfe_8be5_083f7f083a99["test_valid_public_http_url()"] 55eb5d18_546a_f8ab_e6ce_af072e9c336d -->|method| 69461f1f_b422_cdfe_8be5_083f7f083a99 5e6c7a97_7049_0667_e065_2d4167a742ac["test_localhost_blocked_by_default()"] 55eb5d18_546a_f8ab_e6ce_af072e9c336d -->|method| 5e6c7a97_7049_0667_e065_2d4167a742ac c8b20d51_1005_37bc_6306_db0d41109d76["test_localhost_allowed_with_flag()"] 55eb5d18_546a_f8ab_e6ce_af072e9c336d -->|method| c8b20d51_1005_37bc_6306_db0d41109d76 92be9769_371c_422e_221a_e08d07b64a48["test_private_ip_blocked_by_default()"] 55eb5d18_546a_f8ab_e6ce_af072e9c336d -->|method| 92be9769_371c_422e_221a_e08d07b64a48 fe3f2a01_66e3_6766_b1ba_a7faceece821["test_private_ip_allowed_with_flag()"] 55eb5d18_546a_f8ab_e6ce_af072e9c336d -->|method| fe3f2a01_66e3_6766_b1ba_a7faceece821 926c132f_c4fb_f7f2_e01e_e6250505cabf["test_cloud_metadata_always_blocked()"] 55eb5d18_546a_f8ab_e6ce_af072e9c336d -->|method| 926c132f_c4fb_f7f2_e01e_e6250505cabf f0fc89f1_5ad0_640e_869e_8542a044f7af["test_invalid_scheme_blocked()"] 55eb5d18_546a_f8ab_e6ce_af072e9c336d -->|method| f0fc89f1_5ad0_640e_869e_8542a044f7af b6144be6_5f2e_2d8d_8980_26fff33ffbc1["test_https_only_mode()"] 55eb5d18_546a_f8ab_e6ce_af072e9c336d -->|method| b6144be6_5f2e_2d8d_8980_26fff33ffbc1 ab1ddc45_6888_edda_a49c_3c181160cc0f["test_url_without_hostname()"] 55eb5d18_546a_f8ab_e6ce_af072e9c336d -->|method| ab1ddc45_6888_edda_a49c_3c181160cc0f 0391ee8e_890a_2721_a500_5de6e0a6773e["test_dns_resolution_failure()"] 55eb5d18_546a_f8ab_e6ce_af072e9c336d -->|method| 0391ee8e_890a_2721_a500_5de6e0a6773e a2e0f492_67ec_f59a_b47a_5ae280b5140d["test_testserver_allowed()"] 55eb5d18_546a_f8ab_e6ce_af072e9c336d -->|method| a2e0f492_67ec_f59a_b47a_5ae280b5140d
Relationship Graph
Source Code
libs/core/tests/unit_tests/test_ssrf_protection.py lines 85–183
class TestValidateSafeUrl:
"""Tests for validate_safe_url function."""
def test_valid_public_https_url(self) -> None:
"""Test that valid public HTTPS URLs are accepted."""
url = "https://hooks.slack.com/services/xxx"
result = validate_safe_url(url)
assert result == url
def test_valid_public_http_url(self) -> None:
"""Test that valid public HTTP URLs are accepted."""
url = "http://example.com/webhook"
result = validate_safe_url(url)
assert result == url
def test_localhost_blocked_by_default(self) -> None:
"""Test that localhost URLs are blocked by default."""
with pytest.raises(ValueError, match="Localhost"):
validate_safe_url("http://localhost:8080/webhook")
with pytest.raises(ValueError, match="localhost"):
validate_safe_url("http://127.0.0.1:8080/webhook")
def test_localhost_allowed_with_flag(self) -> None:
"""Test that localhost is allowed with allow_private=True."""
url = "http://localhost:8080/webhook"
result = validate_safe_url(url, allow_private=True)
assert result == url
url = "http://127.0.0.1:8080/webhook"
result = validate_safe_url(url, allow_private=True)
assert result == url
def test_private_ip_blocked_by_default(self) -> None:
"""Test that private IPs are blocked by default."""
with pytest.raises(ValueError, match="private IP"):
validate_safe_url("http://192.168.1.1/webhook")
with pytest.raises(ValueError, match="private IP"):
validate_safe_url("http://10.0.0.1/webhook")
with pytest.raises(ValueError, match="private IP"):
validate_safe_url("http://172.16.0.1/webhook")
def test_private_ip_allowed_with_flag(self) -> None:
"""Test that private IPs are allowed with allow_private=True."""
# Note: These will fail DNS resolution in tests, so we skip actual validation
# In production, they would be validated properly
def test_cloud_metadata_always_blocked(self) -> None:
"""Test that cloud metadata endpoints are always blocked."""
with pytest.raises(ValueError, match="metadata"):
validate_safe_url("http://169.254.169.254/latest/meta-data/")
# Even with allow_private=True
with pytest.raises(ValueError, match="metadata"):
validate_safe_url(
"http://169.254.169.254/latest/meta-data/",
allow_private=True,
)
def test_invalid_scheme_blocked(self) -> None:
"""Test that non-HTTP(S) schemes are blocked."""
with pytest.raises(ValueError, match="scheme"):
validate_safe_url("ftp://example.com/file")
with pytest.raises(ValueError, match="scheme"):
validate_safe_url("file:///etc/passwd")
with pytest.raises(ValueError, match="scheme"):
validate_safe_url("javascript:alert(1)")
def test_https_only_mode(self) -> None:
"""Test that HTTP is blocked when allow_http=False."""
with pytest.raises(ValueError, match="HTTPS"):
validate_safe_url("http://example.com/webhook", allow_http=False)
# HTTPS should still work
url = "https://example.com/webhook"
result = validate_safe_url(url, allow_http=False)
assert result == url
Source
Frequently Asked Questions
What is the TestValidateSafeUrl class?
TestValidateSafeUrl is a class in the langchain codebase, defined in libs/core/tests/unit_tests/test_ssrf_protection.py.
Where is TestValidateSafeUrl defined?
TestValidateSafeUrl is defined in libs/core/tests/unit_tests/test_ssrf_protection.py at line 85.
Analyze Your Own Codebase
Get architecture documentation, dependency graphs, and domain analysis for your codebase in minutes.
Try Supermodel Free