제공자 키 저장 쿼리 충돌 수정
Some checks failed
API contract / OpenAPI type drift (push) Failing after 54s

This commit is contained in:
Yun Chan 2026-09-22 22:53:18 +09:00
parent 84e33024a7
commit d58eb67764
2 changed files with 58 additions and 4 deletions

View file

@ -340,7 +340,7 @@ async def save_credential(
async with pool.acquire() as conn: async with pool.acquire() as conn:
row = await conn.fetchrow( row = await conn.fetchrow(
""" """
INSERT INTO app.admin_provider_credential ( INSERT INTO app.admin_provider_credential AS existing (
provider, token_encrypted, token_hint, auth_kind, updated_by, updated_at, provider, token_encrypted, token_hint, auth_kind, updated_by, updated_at,
refresh_token_encrypted, extra refresh_token_encrypted, extra
) )
@ -351,8 +351,14 @@ async def save_credential(
auth_kind = EXCLUDED.auth_kind, auth_kind = EXCLUDED.auth_kind,
updated_by = EXCLUDED.updated_by, updated_by = EXCLUDED.updated_by,
updated_at = now(), updated_at = now(),
refresh_token_encrypted = COALESCE(EXCLUDED.refresh_token_encrypted, refresh_token_encrypted), refresh_token_encrypted = COALESCE(
extra = CASE WHEN EXCLUDED.extra::text = '{}'::jsonb THEN extra ELSE EXCLUDED.extra END, EXCLUDED.refresh_token_encrypted,
existing.refresh_token_encrypted
),
extra = CASE
WHEN EXCLUDED.extra = '{}'::jsonb THEN existing.extra
ELSE EXCLUDED.extra
END,
last_verified_at = NULL, last_verified_at = NULL,
last_verify_ok = NULL, last_verify_ok = NULL,
last_verify_error = NULL last_verify_error = NULL

View file

@ -1,7 +1,7 @@
"""provider 자격증명 서비스(암호화·카탈로그) 단위 테스트.""" """provider 자격증명 서비스(암호화·카탈로그) 단위 테스트."""
import unittest import unittest
from unittest.mock import patch from unittest.mock import AsyncMock, patch
from pydantic import SecretStr from pydantic import SecretStr
@ -73,5 +73,53 @@ class CatalogTest(unittest.TestCase):
self.assertIn("codex", codes) self.assertIn("codex", codes)
class SaveCredentialQueryTest(unittest.IsolatedAsyncioTestCase):
async def test_upsert_preserves_omitted_refresh_and_extra(self):
row = {
"provider": "openrouter",
"token_hint": "…next",
"auth_kind": "oauth_token",
"updated_by": "admin@example.com",
"updated_at": None,
"last_verified_at": None,
"last_verify_ok": None,
"last_verify_error": None,
"refresh_token_encrypted": None,
"extra": {},
}
conn = AsyncMock()
conn.fetchrow.return_value = row
class _Acquire:
async def __aenter__(self):
return conn
async def __aexit__(self, exc_type, exc, traceback):
return False
class _Pool:
def acquire(self):
return _Acquire()
with (
patch.object(svc, "ensure_table", AsyncMock()),
patch.object(svc, "get_pool", return_value=_Pool()),
patch.object(svc.settings, "provider_credential_secret", SecretStr("unit-test-master-secret-0123456789")),
):
await svc.save_credential(
provider="openrouter",
token="new-access-token",
auth_kind="oauth_token",
updated_by="admin@example.com",
)
query = conn.fetchrow.await_args.args[0]
self.assertIn("INSERT INTO app.admin_provider_credential AS existing", query)
self.assertIn("EXCLUDED.refresh_token_encrypted,\n existing.refresh_token_encrypted", query)
self.assertIn("WHEN EXCLUDED.extra = '{}'::jsonb THEN existing.extra", query)
self.assertEqual(conn.fetchrow.await_args.args[6], None)
self.assertEqual(conn.fetchrow.await_args.args[7], "{}")
if __name__ == "__main__": if __name__ == "__main__":
unittest.main() unittest.main()