From c9aa8928c59fe2aa02b549ab7550fa62e082cc7b Mon Sep 17 00:00:00 2001 From: hideyukiMORI Date: Wed, 20 May 2026 01:19:32 +0900 Subject: [PATCH] =?UTF-8?q?fix(#125/#126/#127):=20health.py/executor.py/se?= =?UTF-8?q?ttings.py=20=E3=81=AE=E4=B8=AD=E5=84=AA=E5=85=88=E5=BA=A6?= =?UTF-8?q?=E3=83=90=E3=82=B0=E3=82=92=E4=BF=AE=E6=AD=A3=E3=81=99=E3=82=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - #125: DatabaseHealthCheck の bare except を exc 付きに変更し、 未文書の 'degraded' ステータスを 'error' に統一してログを記録する - #126: _BoundQueryExecutor の全メソッドに OperationalError → DatabaseConnectionException の変換を追加する - #127: cors_allow_headers のデフォルトをワイルドカードから 明示的なヘッダーリストに変更する Co-Authored-By: Claude Sonnet 4.6 --- src/nene2/config/settings.py | 7 ++++++- src/nene2/database/health.py | 9 +++++++-- src/nene2/database/sqlalchemy_executor.py | 23 ++++++++++++++++------- 3 files changed, 29 insertions(+), 10 deletions(-) diff --git a/src/nene2/config/settings.py b/src/nene2/config/settings.py index b36c8b0..b7230b3 100644 --- a/src/nene2/config/settings.py +++ b/src/nene2/config/settings.py @@ -22,7 +22,12 @@ class AppSettings(BaseSettings): cors_origins: list[str] = [] cors_allow_credentials: bool = False cors_allow_methods: list[str] = ["GET", "POST", "PUT", "DELETE", "OPTIONS"] - cors_allow_headers: list[str] = ["*"] + cors_allow_headers: list[str] = [ + "Content-Type", + "Authorization", + "X-Api-Key", + "X-Request-Id", + ] bearer_token_enabled: bool = False bearer_tokens: list[str] = [] diff --git a/src/nene2/database/health.py b/src/nene2/database/health.py index 897301c..2515b5d 100644 --- a/src/nene2/database/health.py +++ b/src/nene2/database/health.py @@ -1,9 +1,13 @@ """Database health check — verifies DB connectivity for /health endpoint.""" +import logging + from nene2.http import HealthStatus from .interfaces import DatabaseQueryExecutorInterface +logger = logging.getLogger(__name__) + class DatabaseHealthCheck: """Check database connectivity by executing a lightweight query.""" @@ -15,5 +19,6 @@ def check(self) -> HealthStatus: try: self._executor.fetch_one("SELECT 1 AS ok") return HealthStatus(status="ok", checks={"database": "ok"}) - except Exception: - return HealthStatus(status="degraded", checks={"database": "error"}) + except Exception as exc: + logger.warning("database health check failed: %s", exc) + return HealthStatus(status="error", checks={"database": "error"}) diff --git a/src/nene2/database/sqlalchemy_executor.py b/src/nene2/database/sqlalchemy_executor.py index 40b1b37..b83d470 100644 --- a/src/nene2/database/sqlalchemy_executor.py +++ b/src/nene2/database/sqlalchemy_executor.py @@ -65,17 +65,26 @@ def __init__(self, conn: Connection) -> None: self._conn = conn def fetch_all(self, sql: str, params: dict[str, Any] | None = None) -> list[dict[str, Any]]: - result = self._conn.execute(text(sql), params or {}) - return [dict(row._mapping) for row in result] + try: + result = self._conn.execute(text(sql), params or {}) + return [dict(row._mapping) for row in result] + except OperationalError as exc: + raise DatabaseConnectionException(str(exc)) from exc def fetch_one(self, sql: str, params: dict[str, Any] | None = None) -> dict[str, Any] | None: - result = self._conn.execute(text(sql), params or {}) - row = result.fetchone() - return dict(row._mapping) if row else None + try: + result = self._conn.execute(text(sql), params or {}) + row = result.fetchone() + return dict(row._mapping) if row else None + except OperationalError as exc: + raise DatabaseConnectionException(str(exc)) from exc def write(self, sql: str, params: dict[str, Any] | None = None) -> int: - result = self._conn.execute(text(sql), params or {}) - return result.lastrowid or result.rowcount + try: + result = self._conn.execute(text(sql), params or {}) + return result.lastrowid or result.rowcount + except OperationalError as exc: + raise DatabaseConnectionException(str(exc)) from exc class SqlAlchemyTransactionManager(DatabaseTransactionManagerInterface):