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

@@ -12,6 +12,7 @@ from __future__ import annotations
from unittest.mock import MagicMock, patch
import pytest
from pydantic import SecretStr
# ---------------------------------------------------------------------------
# _require_http_token
@@ -37,7 +38,7 @@ def test_require_http_token_returns_token_when_set() -> None:
from codex.mcp_server import _require_http_token
mock_settings = MagicMock()
mock_settings.mcp_auth_token = "super-secret-token"
mock_settings.mcp_auth_token = SecretStr("super-secret-token")
with patch("codex.config.get_settings", return_value=mock_settings):
result = _require_http_token()
@@ -97,7 +98,7 @@ def test_main_http_with_token_calls_uvicorn() -> None:
mock_settings = MagicMock()
mock_settings.mcp_transport = "http"
mock_settings.mcp_auth_token = "test-token"
mock_settings.mcp_auth_token = SecretStr("test-token")
mock_settings.mcp_host = "127.0.0.1"
mock_settings.mcp_port = 8765

View File

@@ -10,6 +10,7 @@ from typing import Any
from unittest.mock import MagicMock, patch
import pytest
from pydantic import SecretStr
from codex.models import FormulaChunk
@@ -295,8 +296,8 @@ class TestRouteSelection:
def test_mathpix_selected_when_creds_present(self) -> None:
"""extract_formulas calls MathPix backend when both creds are set."""
mock_settings = MagicMock()
mock_settings.mathpix_app_id = "my_id"
mock_settings.mathpix_app_key = "my_key"
mock_settings.mathpix_app_id = SecretStr("my_id")
mock_settings.mathpix_app_key = SecretStr("my_key")
mock_settings.pix2tex_fallback = True
with (

View File

@@ -8,7 +8,10 @@ from codex.config import Settings, get_settings
def test_settings_defaults() -> None:
"""Settings() is constructable without env vars; expected defaults are set."""
s = Settings()
assert s.database_url == "postgresql://researcher:change_me@localhost:5432/papers"
assert (
s.database_url.get_secret_value()
== "postgresql://researcher:change_me@localhost:5432/papers"
)
assert s.embedding_model == "BAAI/bge-m3"
assert s.embedding_dim == 1024
@@ -20,7 +23,7 @@ def test_settings_env_override(monkeypatch: object) -> None:
mp: pytest.MonkeyPatch = monkeypatch # type: ignore[assignment]
mp.setenv("DATABASE_URL", "postgresql://x:y@h:5432/db")
s = Settings()
assert s.database_url == "postgresql://x:y@h:5432/db"
assert s.database_url.get_secret_value() == "postgresql://x:y@h:5432/db"
def test_get_settings_is_singleton() -> None: