diff options
Diffstat (limited to 'tests')
| -rw-r--r-- | tests/conftest.py | 24 | ||||
| -rw-r--r-- | tests/test_forms.py | 2 | ||||
| -rw-r--r-- | tests/test_url_security.py | 42 | ||||
| -rw-r--r-- | tests/test_views.py | 3 |
4 files changed, 71 insertions, 0 deletions
diff --git a/tests/conftest.py b/tests/conftest.py index 94ba650..f1ef4b5 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -18,6 +18,14 @@ HTTPHandler = Callable[ ] +class FakeHostAnswers: + def __init__(self, *addresses: str): + self._addresses = addresses + + def addresses(self): + return iter(self._addresses) + + @pytest.fixture def app() -> Iterator[Flask]: """ @@ -101,6 +109,12 @@ def install_httpx_mock( Replace the HTTPX transport without replacing HTTPX itself. """ + monkeypatch.setattr( + receiver_module, + "ensure_public_url", + lambda url: None, + ) + real_client = httpx.Client def install(handler: HTTPHandler) -> None: @@ -123,3 +137,13 @@ def install_httpx_mock( ) return install + + +@pytest.fixture +def public_dns( + monkeypatch: pytest.MonkeyPatch, +) -> None: + monkeypatch.setattr( + "webmentions_ssg.url_security.dns.resolver.resolve_name", + lambda hostname: FakeHostAnswers("93.184.216.34"), + ) diff --git a/tests/test_forms.py b/tests/test_forms.py index 9be6ca8..2d5fc01 100644 --- a/tests/test_forms.py +++ b/tests/test_forms.py @@ -89,6 +89,7 @@ VALID_TARGET = "https://dennisfink.me/blog/example/" ) def test_endpoint_form_rejects_invalid_data( app: Flask, + public_dns: None, form_data: dict[str, str], invalid_field: str, expected_error: str | None, @@ -111,6 +112,7 @@ def test_endpoint_form_rejects_invalid_data( def test_endpoint_form_accepts_valid_data( app: Flask, + public_dns: None, ) -> None: with app.test_request_context( "/endpoint", diff --git a/tests/test_url_security.py b/tests/test_url_security.py new file mode 100644 index 0000000..fba6d7d --- /dev/null +++ b/tests/test_url_security.py @@ -0,0 +1,42 @@ +import pytest + +from webmentions_ssg.url_security import ( + NonPublicAddressError, + ensure_public_url, +) + + +class FakeAnswers: + def __init__(self, *addresses: str): + self._addresses = addresses + + def addresses(self): + return iter(self._addresses) + + +@pytest.mark.parametrize( + ("url", "resolved_addresses"), + [ + ("http://127.0.0.1/", ["127.0.0.1"]), + ("http://127.0.0.1:8080/test", ["127.0.0.1"]), + ("http://[::1]/", ["::1"]), + ("http://10.0.0.1/", ["10.0.0.1"]), + ("http://172.16.0.1/", ["172.16.0.1"]), + ("http://192.168.1.1/", ["192.168.1.1"]), + ("http://169.254.169.254/", ["169.254.169.254"]), + ("http://localhost/", ["127.0.0.1", "::1"]), + ("http://internal.example/", ["192.168.1.10"]), + ], +) +def test_ensure_public_url_rejects_non_public_addresses( + monkeypatch: pytest.MonkeyPatch, + url: str, + resolved_addresses: list[str], +) -> None: + monkeypatch.setattr( + "webmentions_ssg.url_security.dns.resolver.resolve_name", + lambda hostname: FakeAnswers(*resolved_addresses), + ) + + with pytest.raises(NonPublicAddressError): + ensure_public_url(url) diff --git a/tests/test_views.py b/tests/test_views.py index d7fd798..70ed732 100644 --- a/tests/test_views.py +++ b/tests/test_views.py @@ -42,6 +42,7 @@ def test_endpoint_creates_webmention( client: FlaskClient, views_module: ModuleType, monkeypatch: pytest.MonkeyPatch, + public_dns: None, ) -> None: queued: list[uuid.UUID] = [] @@ -85,6 +86,7 @@ def test_endpoint_is_idempotent( client: FlaskClient, views_module: ModuleType, monkeypatch: pytest.MonkeyPatch, + public_dns: None, ) -> None: queued: list[uuid.UUID] = [] @@ -138,6 +140,7 @@ def test_resending_resets_failure_state( client: FlaskClient, views_module: ModuleType, monkeypatch: pytest.MonkeyPatch, + public_dns: None, ) -> None: monkeypatch.setattr( views_module, |
