fix: keep credentials out of doctor's output, and read the revision from the schema it checked

The Redis check put the whole URL in its failure message. A managed Redis URL
carries user:password@host, so a failed ping printed the password to the
terminal and into any log or issue the output was pasted into. It names
scheme://host:port/db now, and falls back to naming no URL when the value
cannot be parsed at all.

The Postgres check asked to_regclass about public.alembic_version and then read
version_num through search_path, so another schema could answer with a
different revision, or the query could fail, and doctor would send you to run
migrations against a database that is already fine.
This commit is contained in:
Alex committed 2026-09-17 11:52:28 +01:00
1 parent bcf2707efa
commit 9326c6edb1
2 files changed
+48 -4

No files matched your search

+15 -2
View File
@@ -796,7 +796,8 @@ def _check_postgres(uri: Optional[str]) -> Check:
applied = cursor.fetchone()[0] is not None
current = None
if applied:
cursor.execute("select version_num from alembic_version")
# public, like the to_regclass check above: search_path could resolve another one.
cursor.execute("select version_num from public.alembic_version")
row = cursor.fetchone()
current = row[0] if row else None
except (psycopg.Error, OSError, ValueError) as exc:
@@ -810,6 +811,18 @@ def _check_postgres(uri: Optional[str]) -> Check:
return Check("postgres", "ok", f"PostgreSQL {version}, schema at {current}")
def _redis_endpoint(url: str) -> str:
"""A Redis URL without its credentials: this ends up on a terminal, in CI logs and in issues."""
try:
parts = urlsplit(url)
except ValueError:
return "the configured URL"
host = parts.hostname or ""
if parts.port:
host = f"{host}:{parts.port}"
return f"{parts.scheme}://{host}{parts.path}" if host else "the configured URL"
def _check_redis(urls: Mapping[str, str]) -> Check:
"""Ping every Redis the settings name; they are usually one server, three databases."""
if not urls:
@@ -822,7 +835,7 @@ def _check_redis(urls: Mapping[str, str]) -> Check:
try:
redis.Redis.from_url(url, socket_connect_timeout=3).ping()
except Exception as exc: # noqa: BLE001 - every client error here is the same finding
return Check("redis", "fail", f"{label} ({url}) does not answer: {str(exc).strip()}")
return Check("redis", "fail", f"{label} ({_redis_endpoint(url)}) does not answer: {str(exc).strip()}")
return Check("redis", "ok", f"answering on {len(urls)} database(s)")