From 58777076c53c5d4c3edc78c3e32acaf85e44309b Mon Sep 17 00:00:00 2001 From: stumpylog <797416+stumpylog@users.noreply.github.com> Date: Tue, 22 Sep 2026 10:02:39 -0700 Subject: [PATCH] Cover webhooks to internal hosts when they are allowed Every webhook test that reaches a real socket ran with internal requests disallowed, and the rest intercept above the transport. Wiring the transport to always disallow internal addresses would therefore have passed the suite while breaking webhooks to internal hosts on every default install. A new test sends a webhook to localhost with internal requests allowed and checks that the payload arrives and that the guard resolved nothing. The Host header test's docstring is also corrected: the header now comes from the URL, not from a resolved hostname. Co-Authored-By: Claude Opus 5 --- src/documents/tests/test_workflows.py | 31 ++++++++++++++++++++++++++- 1 file changed, 30 insertions(+), 1 deletion(-) diff --git a/src/documents/tests/test_workflows.py b/src/documents/tests/test_workflows.py index 6f852c4f5..89e5c4390 100644 --- a/src/documents/tests/test_workflows.py +++ b/src/documents/tests/test_workflows.py @@ -5192,6 +5192,35 @@ class TestWebhookSecurity: assert received.body == b"hi" assert received.headers["host"] == f"webhook.test:{local_http_server.port}" + @override_settings(WEBHOOKS_ALLOW_INTERNAL_REQUESTS=True) + def test_allow_internal_sends_to_internal_address( + self, + local_http_server: LocalHTTPServer, + fake_dns: FakeDNS, + ) -> None: + """ + GIVEN: + - A webhook to localhost + - WEBHOOKS_ALLOW_INTERNAL_REQUESTS is True + WHEN: + - send_webhook is called + THEN: + - The payload arrives at the internal address + - The guard does not resolve the host, leaving it to the stock + connection path + """ + send_webhook( + url=f"http://localhost:{local_http_server.port}", + data="hi", + headers={}, + files=None, + as_json=False, + ) + + received = local_http_server.requests[0] + assert received.body == b"hi" + assert fake_dns.lookups == [] + @override_settings(WEBHOOKS_ALLOW_INTERNAL_REQUESTS=False) def test_block_is_an_expected_task_failure( self, @@ -5267,7 +5296,7 @@ class TestWebhookSecurity: WHEN: - send_webhook is called with a malicious Host header THEN: - - The Host header is stripped and replaced with the resolved hostname + - The Host header is stripped and set from the URL hostname """ httpx_mock.add_response(content=b"ok")