From c8ab1cbab26f882d63a3a5a5d085e4cd3c5353d4 Mon Sep 17 00:00:00 2001 From: Alex Date: Wed, 16 Sep 2026 23:30:47 +0100 Subject: [PATCH] fix: report a malformed Redis URL instead of raising from urlsplit urlsplit raises ValueError on input such as redis://[::1 , which nothing converted, so a typo left native setup with a traceback rather than the message every other unusable URL gets. --- docsgpt/deploy/commands.py | 6 +++++- tests/deploy/test_native.py | 16 ++++++++++++++++ 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/docsgpt/deploy/commands.py b/docsgpt/deploy/commands.py index 8d00f7bb..5a853e8f 100644 --- a/docsgpt/deploy/commands.py +++ b/docsgpt/deploy/commands.py @@ -209,7 +209,11 @@ def _redis_urls(base: str) -> dict[str, str]: Everything else in the URL is kept — TLS, credentials, and query parameters such as the ``ssl_cert_reqs`` that a rediss:// endpoint usually needs. """ - parts = urlsplit(base) + try: + parts = urlsplit(base) + except ValueError as exc: + # urlsplit raises on things like redis://[::1 ; that is a typo, not a crash. + raise DeployError(f"the Redis URL {base!r} could not be read: {exc}") from exc if parts.scheme not in ("redis", "rediss"): raise DeployError( f"the Redis URL {base!r} should start with redis:// or rediss://, with any options as " diff --git a/tests/deploy/test_native.py b/tests/deploy/test_native.py index cd7092ca..0e09a382 100644 --- a/tests/deploy/test_native.py +++ b/tests/deploy/test_native.py @@ -200,6 +200,22 @@ class TestNativeUp: assert env["CELERY_BROKER_URL"] == "redis://localhost:6379/0?health_check_interval=30" assert env["CACHE_REDIS_URL"] == "redis://localhost:6379/2?health_check_interval=30" + def test_a_malformed_redis_url_is_reported_not_raised(self, tmp_path): + """urlsplit raises ValueError on an unterminated IPv6 bracket; a typo is not a traceback.""" + argv = ["up", "--native", "--dir", str(tmp_path), "--yes", + "--postgres-uri", "postgresql://localhost/d", "--redis-url", "redis://[::1"] + with pytest.raises(DeployError, match="could not be read"): + _run(argv, _native_context()) + + def test_an_ipv6_redis_url_still_works(self, tmp_path): + """Refusing the malformed form must not cost the valid one.""" + argv = ["up", "--native", "--dir", str(tmp_path), "--yes", "--postgres-uri", "postgresql://localhost/d", + "--redis-url", "redis://[::1]:6379/2"] + assert _run(argv, _native_context()) == 0 + env = envfile.read(tmp_path / ".env") + assert env["CELERY_BROKER_URL"] == "redis://[::1]:6379/2" + assert env["CACHE_REDIS_URL"] == "redis://[::1]:6379/4" + @pytest.mark.parametrize("url", ["localhost:6379", "redis+socket:///var/run/redis.sock", "redis://localhost:6379/queue"]) def test_a_redis_url_that_cannot_be_numbered_is_refused(self, tmp_path, url):