Files
codex-py/codex/db.py
Tarik Moussa b4fbd7930e 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>
2026-06-15 21:32:13 +02:00

63 lines
2.0 KiB
Python

"""Database connection helpers.
Provides:
- :func:`get_conn` — a context manager that yields a psycopg connection.
- :func:`apply_schema` — idempotently applies ``infra/schema.sql``.
The connection pool (psycopg_pool) is intentionally deferred to F-05
(ingest); here we expose a simple per-call ``psycopg.connect`` wrapper
that is sufficient for schema migration and unit-testing without requiring
an additional ``psycopg[pool]`` dependency at scaffold stage.
"""
from __future__ import annotations
from collections.abc import Generator
from contextlib import contextmanager
from pathlib import Path
import psycopg
import psycopg.rows
from codex.config import get_settings
@contextmanager
def get_conn() -> Generator[psycopg.Connection[psycopg.rows.DictRow], None, None]:
"""Yield a psycopg connection with dict-row factory.
The connection is opened from :func:`codex.config.get_settings`
``database_url`` and closed automatically when the context exits.
Usage::
with get_conn() as conn:
conn.execute("SELECT 1")
"""
settings = get_settings()
with psycopg.connect(
settings.database_url.get_secret_value(),
row_factory=psycopg.rows.dict_row,
) as conn:
yield conn
def apply_schema(conn: psycopg.Connection[psycopg.rows.DictRow]) -> None:
"""Idempotently apply ``infra/schema.sql`` to the connected database.
Safe to call repeatedly — every statement is ``CREATE … IF NOT EXISTS`` or
``ADD COLUMN IF NOT EXISTS``, so re-application is a no-op.
Requires a connection whose role can run DDL (owns / can CREATE + ALTER the
tables). The least-privilege application role is typically DML-only and will
raise ``InsufficientPrivilege``; use a privileged connection — see
``codex migrate`` and ``MIGRATION_DATABASE_URL`` (audit M-1).
Args:
conn: An open psycopg connection with DDL privileges.
"""
schema_path = Path(__file__).parent.parent / "infra" / "schema.sql"
sql = schema_path.read_text(encoding="utf-8")
conn.execute(sql)
conn.commit()