Spaces:
Sleeping
Sleeping
Update db/url_utils.py
Browse filesSummary of Step 6.3 completion
File Change Status
alembic/env.py Strip query params, mask all logs, use asyncpg β
alembic.ini sqlalchemy.url blank, logger at WARN β
db/migrations.py Mask URL before logging β
db/connection.py Strip query params, mask logs, echo=False β
db/url_utils.py redact_database_url() strips query params β
app/server.py Uses redact_database_url() (now includes query strip) β
Result: No raw DATABASE_URL (credentials OR query params) will ever appear in logs, Alembic output, SQLAlchemy echoes, or exception messages.
- db/url_utils.py +16 -6
db/url_utils.py
CHANGED
|
@@ -1,4 +1,4 @@
|
|
| 1 |
-
# db/url_utils.py
|
| 2 |
import re
|
| 3 |
|
| 4 |
_SECRET_RE = re.compile(r"(?<=://)[^:]+:[^@]+(?=@)")
|
|
@@ -12,14 +12,25 @@ _ALLOWED_SCHEMES = (
|
|
| 12 |
|
| 13 |
def redact_database_url(url: str) -> str:
|
| 14 |
"""
|
| 15 |
-
|
| 16 |
-
This is the ONLY function that should appear in log statements.
|
| 17 |
|
| 18 |
Example
|
| 19 |
-------
|
| 20 |
-
postgresql://user:s3cr3t@host/db
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 21 |
"""
|
| 22 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 23 |
|
| 24 |
|
| 25 |
def validate_database_url(url: str) -> None:
|
|
@@ -34,5 +45,4 @@ def validate_database_url(url: str) -> None:
|
|
| 34 |
raise ValueError(
|
| 35 |
f"DATABASE_URL uses an unsupported scheme. "
|
| 36 |
f"Expected one of: {', '.join(_ALLOWED_SCHEMES)}"
|
| 37 |
-
# β scheme list only β raw URL is intentionally excluded
|
| 38 |
)
|
|
|
|
| 1 |
+
# db/url_utils.py
|
| 2 |
import re
|
| 3 |
|
| 4 |
_SECRET_RE = re.compile(r"(?<=://)[^:]+:[^@]+(?=@)")
|
|
|
|
| 12 |
|
| 13 |
def redact_database_url(url: str) -> str:
|
| 14 |
"""
|
| 15 |
+
Mask credentials AND query params in a DSN for safe logging.
|
|
|
|
| 16 |
|
| 17 |
Example
|
| 18 |
-------
|
| 19 |
+
postgresql://user:s3cr3t@host/db?sslmode=require
|
| 20 |
+
β postgresql://***@host/db
|
| 21 |
+
|
| 22 |
+
Rationale
|
| 23 |
+
---------
|
| 24 |
+
Query params like ?sslmode=require&channel_binding=require can leak
|
| 25 |
+
internal infrastructure details; stripping them reduces the attack surface.
|
| 26 |
"""
|
| 27 |
+
masked = _SECRET_RE.sub("***", url)
|
| 28 |
+
|
| 29 |
+
# Strip query params (everything after ?)
|
| 30 |
+
if "?" in masked:
|
| 31 |
+
masked = masked.split("?")[0]
|
| 32 |
+
|
| 33 |
+
return masked
|
| 34 |
|
| 35 |
|
| 36 |
def validate_database_url(url: str) -> None:
|
|
|
|
| 45 |
raise ValueError(
|
| 46 |
f"DATABASE_URL uses an unsupported scheme. "
|
| 47 |
f"Expected one of: {', '.join(_ALLOWED_SCHEMES)}"
|
|
|
|
| 48 |
)
|