diff --git a/src/polygateway/config.py b/src/polygateway/config.py index 47fe0c1..de7c088 100644 --- a/src/polygateway/config.py +++ b/src/polygateway/config.py @@ -191,8 +191,11 @@ class GatewaySettings: raise ValueError("telemetry_backend=postgres 时必须提供 telemetry_pg_dsn") stripped = _strip_dsn_driver(self.telemetry_pg_dsn) if stripped != self.telemetry_pg_dsn: + # 只报 scheme 段: DSN 带密码,整串不得进日志(P5 敏感信息只走 .env) logger.warning( - "telemetry_pg_dsn 含 SQLAlchemy 驱动后缀(asyncpg 不认),已剥为 {}", stripped + "telemetry_pg_dsn 的 scheme 含 asyncpg 不认的驱动后缀,已由 {} 剥为 {}", + self.telemetry_pg_dsn.partition("://")[0], + stripped.partition("://")[0], ) object.__setattr__(self, "telemetry_pg_dsn", stripped) diff --git a/tests/unit/test_config.py b/tests/unit/test_config.py index da21c4f..64d58ba 100644 --- a/tests/unit/test_config.py +++ b/tests/unit/test_config.py @@ -523,11 +523,22 @@ class TestCrossFieldInvariants: settings = dataclasses.replace( base, telemetry_backend="postgres", - telemetry_pg_dsn="postgresql+asyncpg://u@h/db", + telemetry_pg_dsn="postgresql+asyncpg://u:s3cret@h/db", ) - assert settings.telemetry_pg_dsn == "postgresql://u@h/db" + assert settings.telemetry_pg_dsn == "postgresql://u:s3cret@h/db" assert any("asyncpg" in m for m in warnings) + def test_dsn_warning_does_not_leak_credentials(self): + """DSN 带密码,日志只能出现 scheme 段(P5: 敏感信息只走 .env)。""" + base = self._base() + with _captured_warnings() as warnings: + dataclasses.replace( + base, + telemetry_backend="postgres", + telemetry_pg_dsn="postgresql+asyncpg://u:s3cret@h/db", + ) + assert warnings and not any("s3cret" in m or "@h/db" in m for m in warnings) + def test_env_path_strips_dsn_without_warning(self): """env 路已在 _load_pg_dsn 剥过,不该给三项目的历史 DSN 写法刷噪音。""" with _captured_warnings() as warnings: