feat(config): wrap credentials in SecretStr (audit S-4)

database_url, migration_database_url, mcp_auth_token and the mathpix app
id/key are now pydantic SecretStr, so they render as '**********' in any
repr/log/traceback instead of leaking the plaintext credential. Consumers
(db.get_conn, cli.migrate, mcp._require_http_token, mathpix.extract_formulas)
call .get_secret_value() at the point of use. Tests updated to the SecretStr
type.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Tarik Moussa
2026-06-15 21:32:13 +02:00
parent e7b854db10
commit b4fbd7930e
8 changed files with 27 additions and 19 deletions

View File

@@ -9,7 +9,7 @@ from __future__ import annotations
from functools import lru_cache
from pydantic import AliasChoices, Field
from pydantic import AliasChoices, Field, SecretStr
from pydantic_settings import BaseSettings, SettingsConfigDict
@@ -26,15 +26,15 @@ class Settings(BaseSettings):
# ------------------------------------------------------------------
# Database
# ------------------------------------------------------------------
database_url: str = Field(
default="postgresql://researcher:change_me@localhost:5432/papers",
database_url: SecretStr = Field(
default=SecretStr("postgresql://researcher:change_me@localhost:5432/papers"),
description=(
"libpq-compatible connection string consumed by psycopg. "
"Example: postgresql://user:pass@host:5432/dbname"
),
)
migration_database_url: str | None = Field(
migration_database_url: SecretStr | None = Field(
default=None,
description=(
"Optional privileged connection string used by `codex migrate` to apply "
@@ -148,7 +148,7 @@ class Settings(BaseSettings):
# ------------------------------------------------------------------
# F-09 Rich Parsing
# ------------------------------------------------------------------
mathpix_app_id: str | None = Field(
mathpix_app_id: SecretStr | None = Field(
default=None,
description=(
"MathPix App ID for cloud formula extraction. "
@@ -156,7 +156,7 @@ class Settings(BaseSettings):
),
)
mathpix_app_key: str | None = Field(
mathpix_app_key: SecretStr | None = Field(
default=None,
description=(
"MathPix App Key for cloud formula extraction. "
@@ -257,7 +257,7 @@ class Settings(BaseSettings):
description="Bind port for HTTP transport (ignored for stdio).",
)
mcp_auth_token: str | None = Field(
mcp_auth_token: SecretStr | None = Field(
default=None,
description=(
"Bearer token required when mcp_transport='http'. "