From bf2a809db7ba56e6f155d4ec98b43c4d4c433dc3 Mon Sep 17 00:00:00 2001 From: HarshCasper Date: Wed, 4 Feb 2026 15:36:46 +0530 Subject: [PATCH 1/4] fix(paradedb): prevent extension from intercepting all HTTP requests --- paradedb/localstack_paradedb/extension.py | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/paradedb/localstack_paradedb/extension.py b/paradedb/localstack_paradedb/extension.py index a666bdbf..8634860f 100644 --- a/paradedb/localstack_paradedb/extension.py +++ b/paradedb/localstack_paradedb/extension.py @@ -2,6 +2,7 @@ import socket from localstack_extensions.utils.docker import ProxiedDockerContainerExtension +from localstack.extensions.api import http from localstack import config # Environment variables for configuration @@ -56,6 +57,22 @@ def _tcp_health_check(): tcp_ports=[postgres_port], # Enable TCP proxying through gateway ) + def update_gateway_routes(self, router: http.Router[http.RouteHandler]): + """ + Override to set up only TCP routing without HTTP proxy. + + ParadeDB uses the native PostgreSQL wire protocol (not HTTP), so we + only need TCP protocol routing - not HTTP proxying. Adding an HTTP + proxy without a host restriction would cause all HTTP requests to be + forwarded to the PostgreSQL container, breaking other services. + """ + # Start the container + self.start_container() + + # Set up only TCP protocol routing (skip HTTP proxy from base class) + if self.tcp_ports: + self._setup_tcp_protocol_routing() + def tcp_connection_matcher(self, data: bytes) -> bool: """ Identify PostgreSQL/ParadeDB connections by protocol handshake. From 47715b1c1f9e3b7d129f3e98f187501e974b1bd6 Mon Sep 17 00:00:00 2001 From: Waldemar Hummer Date: Wed, 4 Feb 2026 12:16:52 +0100 Subject: [PATCH 2/4] test(paradedb): add test for mixed TCP and HTTP traffic Adds a test to verify that the ParadeDB extension correctly handles mixed protocol traffic - PostgreSQL wire protocol (TCP) for ParadeDB queries alongside regular HTTP-based AWS API requests (S3, STS). Co-Authored-By: Claude Opus 4.5 --- paradedb/tests/test_extension.py | 74 ++++++++++++++++++++++++++++++++ 1 file changed, 74 insertions(+) diff --git a/paradedb/tests/test_extension.py b/paradedb/tests/test_extension.py index b816682c..df35240e 100644 --- a/paradedb/tests/test_extension.py +++ b/paradedb/tests/test_extension.py @@ -1,3 +1,4 @@ +import boto3 import psycopg2 from localstack.utils.strings import short_uid @@ -104,3 +105,76 @@ def test_paradedb_quickstart(): conn.commit() cursor.close() conn.close() + + +def test_mixed_tcp_and_http_traffic(): + """ + Test that mixed TCP (ParadeDB) and HTTP (AWS) traffic works correctly. + + This verifies that the ParadeDB extension only intercepts PostgreSQL wire + protocol connections and doesn't interfere with regular HTTP-based AWS + API requests to LocalStack. + """ + # First, verify ParadeDB TCP connection works + conn = get_connection() + cursor = conn.cursor() + cursor.execute("SELECT 1 as test_value;") + result = cursor.fetchone() + assert result[0] == 1, "ParadeDB TCP connection should work" + cursor.close() + conn.close() + + # Now verify AWS HTTP requests still work (S3 and STS) + # These should NOT be intercepted by the ParadeDB extension + endpoint_url = f"http://localhost:{PORT}" + + # Test S3 HTTP requests + s3_client = boto3.client( + "s3", + endpoint_url=endpoint_url, + aws_access_key_id="test", + aws_secret_access_key="test", + region_name="us-east-1", + ) + + bucket_name = f"test-bucket-{short_uid()}" + s3_client.create_bucket(Bucket=bucket_name) + + # List buckets to verify HTTP API is working + buckets = s3_client.list_buckets() + bucket_names = [b["Name"] for b in buckets["Buckets"]] + assert bucket_name in bucket_names, "S3 HTTP API should work alongside ParadeDB TCP" + + # Put and get an object + test_key = "test-object.txt" + test_content = b"Hello from mixed TCP/HTTP test!" + s3_client.put_object(Bucket=bucket_name, Key=test_key, Body=test_content) + response = s3_client.get_object(Bucket=bucket_name, Key=test_key) + retrieved_content = response["Body"].read() + assert retrieved_content == test_content, "S3 object operations should work" + + # Clean up S3 + s3_client.delete_object(Bucket=bucket_name, Key=test_key) + s3_client.delete_bucket(Bucket=bucket_name) + + # Test STS HTTP requests + sts_client = boto3.client( + "sts", + endpoint_url=endpoint_url, + aws_access_key_id="test", + aws_secret_access_key="test", + region_name="us-east-1", + ) + + caller_identity = sts_client.get_caller_identity() + assert "Account" in caller_identity, "STS HTTP API should work alongside ParadeDB TCP" + assert "Arn" in caller_identity, "STS should return valid caller identity" + + # Finally, verify ParadeDB still works after HTTP requests + conn = get_connection() + cursor = conn.cursor() + cursor.execute("SELECT 'tcp_works_after_http' as verification;") + result = cursor.fetchone() + assert result[0] == "tcp_works_after_http", "ParadeDB should still work after HTTP requests" + cursor.close() + conn.close() From 2cba78254a0dba04006da4d2c9f457c68d960122 Mon Sep 17 00:00:00 2001 From: Waldemar Hummer Date: Wed, 4 Feb 2026 12:31:46 +0100 Subject: [PATCH 3/4] tmp commit to trigger error --- paradedb/localstack_paradedb/extension.py | 32 +++++++++++------------ paradedb/tests/test_extension.py | 8 ++++-- 2 files changed, 22 insertions(+), 18 deletions(-) diff --git a/paradedb/localstack_paradedb/extension.py b/paradedb/localstack_paradedb/extension.py index 8634860f..195596c7 100644 --- a/paradedb/localstack_paradedb/extension.py +++ b/paradedb/localstack_paradedb/extension.py @@ -2,7 +2,6 @@ import socket from localstack_extensions.utils.docker import ProxiedDockerContainerExtension -from localstack.extensions.api import http from localstack import config # Environment variables for configuration @@ -57,21 +56,22 @@ def _tcp_health_check(): tcp_ports=[postgres_port], # Enable TCP proxying through gateway ) - def update_gateway_routes(self, router: http.Router[http.RouteHandler]): - """ - Override to set up only TCP routing without HTTP proxy. - - ParadeDB uses the native PostgreSQL wire protocol (not HTTP), so we - only need TCP protocol routing - not HTTP proxying. Adding an HTTP - proxy without a host restriction would cause all HTTP requests to be - forwarded to the PostgreSQL container, breaking other services. - """ - # Start the container - self.start_container() - - # Set up only TCP protocol routing (skip HTTP proxy from base class) - if self.tcp_ports: - self._setup_tcp_protocol_routing() + # TODO: uncomment + # def update_gateway_routes(self, router: http.Router[http.RouteHandler]): + # """ + # Override to set up only TCP routing without HTTP proxy. + # + # ParadeDB uses the native PostgreSQL wire protocol (not HTTP), so we + # only need TCP protocol routing - not HTTP proxying. Adding an HTTP + # proxy without a host restriction would cause all HTTP requests to be + # forwarded to the PostgreSQL container, breaking other services. + # """ + # # Start the container + # self.start_container() + # + # # Set up only TCP protocol routing (skip HTTP proxy from base class) + # if self.tcp_ports: + # self._setup_tcp_protocol_routing() def tcp_connection_matcher(self, data: bytes) -> bool: """ diff --git a/paradedb/tests/test_extension.py b/paradedb/tests/test_extension.py index df35240e..1c2504f0 100644 --- a/paradedb/tests/test_extension.py +++ b/paradedb/tests/test_extension.py @@ -167,7 +167,9 @@ def test_mixed_tcp_and_http_traffic(): ) caller_identity = sts_client.get_caller_identity() - assert "Account" in caller_identity, "STS HTTP API should work alongside ParadeDB TCP" + assert "Account" in caller_identity, ( + "STS HTTP API should work alongside ParadeDB TCP" + ) assert "Arn" in caller_identity, "STS should return valid caller identity" # Finally, verify ParadeDB still works after HTTP requests @@ -175,6 +177,8 @@ def test_mixed_tcp_and_http_traffic(): cursor = conn.cursor() cursor.execute("SELECT 'tcp_works_after_http' as verification;") result = cursor.fetchone() - assert result[0] == "tcp_works_after_http", "ParadeDB should still work after HTTP requests" + assert result[0] == "tcp_works_after_http", ( + "ParadeDB should still work after HTTP requests" + ) cursor.close() conn.close() From cfa2303b64359e69670daf8a1c362d44a1f99d2d Mon Sep 17 00:00:00 2001 From: Waldemar Hummer Date: Wed, 4 Feb 2026 12:41:17 +0100 Subject: [PATCH 4/4] undo tmp change --- paradedb/localstack_paradedb/extension.py | 33 ++++++++++++----------- 1 file changed, 17 insertions(+), 16 deletions(-) diff --git a/paradedb/localstack_paradedb/extension.py b/paradedb/localstack_paradedb/extension.py index 195596c7..4732787c 100644 --- a/paradedb/localstack_paradedb/extension.py +++ b/paradedb/localstack_paradedb/extension.py @@ -3,6 +3,7 @@ from localstack_extensions.utils.docker import ProxiedDockerContainerExtension from localstack import config +from localstack.extensions.api import http # Environment variables for configuration ENV_POSTGRES_USER = "PARADEDB_POSTGRES_USER" @@ -56,22 +57,22 @@ def _tcp_health_check(): tcp_ports=[postgres_port], # Enable TCP proxying through gateway ) - # TODO: uncomment - # def update_gateway_routes(self, router: http.Router[http.RouteHandler]): - # """ - # Override to set up only TCP routing without HTTP proxy. - # - # ParadeDB uses the native PostgreSQL wire protocol (not HTTP), so we - # only need TCP protocol routing - not HTTP proxying. Adding an HTTP - # proxy without a host restriction would cause all HTTP requests to be - # forwarded to the PostgreSQL container, breaking other services. - # """ - # # Start the container - # self.start_container() - # - # # Set up only TCP protocol routing (skip HTTP proxy from base class) - # if self.tcp_ports: - # self._setup_tcp_protocol_routing() + # TODO: this should be migrated into the base class directly ..! + def update_gateway_routes(self, router: http.Router[http.RouteHandler]): + """ + Override to set up only TCP routing without HTTP proxy. + + ParadeDB uses the native PostgreSQL wire protocol (not HTTP), so we + only need TCP protocol routing - not HTTP proxying. Adding an HTTP + proxy without a host restriction would cause all HTTP requests to be + forwarded to the PostgreSQL container, breaking other services. + """ + # Start the container + self.start_container() + + # Set up only TCP protocol routing (skip HTTP proxy from base class) + if self.tcp_ports: + self._setup_tcp_protocol_routing() def tcp_connection_matcher(self, data: bytes) -> bool: """