구글 계정 식별 회귀를 고정

This commit is contained in:
Yun Chan 2026-08-30 00:00:04 +09:00
parent 3a7b6f7760
commit 21bbe3f98d

View file

@ -430,6 +430,28 @@ class AuthProviderScaffoldTest(unittest.IsolatedAsyncioTestCase):
) )
self.assertEqual(unverified.exception.status_code, 403) self.assertEqual(unverified.exception.status_code, 403)
def test_google_provider_identity_is_subject_based_and_separates_accounts(
self,
) -> None:
first_login = auth_routes._provider_external_id(
"google",
"google-subject-a",
"first-address@gmail.com",
)
same_account_new_email = auth_routes._provider_external_id(
"google",
"google-subject-a",
"renamed-address@gmail.com",
)
different_google_account = auth_routes._provider_external_id(
"google",
"google-subject-b",
"second-address@gmail.com",
)
self.assertEqual(first_login, same_account_new_email)
self.assertNotEqual(first_login, different_google_account)
async def test_super_admin_email_is_admin_and_auto_approved(self) -> None: async def test_super_admin_email_is_admin_and_auto_approved(self) -> None:
with ( with (
patched_settings( patched_settings(
@ -461,7 +483,7 @@ class AuthProviderScaffoldTest(unittest.IsolatedAsyncioTestCase):
async def test_existing_primary_role_super_admin_persists_admin_access_on_login( async def test_existing_primary_role_super_admin_persists_admin_access_on_login(
self, self,
) -> None: ) -> None:
email = "persistent-root@twentyoz.kr" email = "yunchan8804@gmail.com"
existing = _managed_user(email=email, role="learner", admin_access=False) existing = _managed_user(email=email, role="learner", admin_access=False)
auth_sessions._users[existing.user_id] = existing auth_sessions._users[existing.user_id] = existing
auth_sessions._email_index[email] = existing.user_id auth_sessions._email_index[email] = existing.user_id
@ -478,9 +500,9 @@ class AuthProviderScaffoldTest(unittest.IsolatedAsyncioTestCase):
): ):
_, user = await auth_sessions.create_session( _, user = await auth_sessions.create_session(
email=email, email=email,
display_name="Persistent Root", display_name="Yun Chan",
role="learner", role="learner",
external_id="google:persistent-root", external_id="google:yunchan8804",
) )
self.assertEqual(user.role, "learner") self.assertEqual(user.role, "learner")
@ -705,6 +727,68 @@ class AuthProviderScaffoldTest(unittest.IsolatedAsyncioTestCase):
self.assertIn("$7::boolean", conn.queries[0]) self.assertIn("$7::boolean", conn.queries[0])
self.assertIn("$9::boolean", conn.queries[1]) self.assertIn("$9::boolean", conn.queries[1])
async def test_google_oauth_claims_only_exact_normalized_email_placeholder(
self,
) -> None:
class RecordingConn:
def __init__(self) -> None:
self.query = ""
self.args: tuple[Any, ...] = ()
async def fetchrow(self, query: str, *args: Any) -> dict[str, Any]:
self.query = query
self.args = args
now = datetime.now(timezone.utc)
return {
"user_id": "00000000-0000-0000-0000-000000000607",
"email": "claim.me@example.com",
"display_name": "Claim Me",
"role": "learner",
"admin_access": False,
"account_status": "approved",
"cohort": "",
"affiliation": "",
"created_at": now,
"last_seen_at": now,
}
class RecordingAcquire:
def __init__(self, conn: RecordingConn) -> None:
self.conn = conn
async def __aenter__(self) -> RecordingConn:
return self.conn
async def __aexit__(self, exc_type, exc, tb) -> None:
return None
class RecordingPool:
def __init__(self, conn: RecordingConn) -> None:
self.conn = conn
def acquire(self) -> RecordingAcquire:
return RecordingAcquire(self.conn)
conn = RecordingConn()
with patch.object(auth_sessions, "get_pool", return_value=RecordingPool(conn)):
user = await auth_sessions.upsert_managed_user(
auth_sessions.ManagedUserUpsertInput(
email=" Claim.Me@Example.com ",
display_name="Claim Me",
role="learner",
external_id="google:claim-subject",
account_status="approved",
)
)
self.assertEqual(user.email, "claim.me@example.com")
self.assertIn("WHERE lower(email) = $2", conn.query)
self.assertIn("AND (external_id = $6 OR external_id IS NULL)", conn.query)
self.assertIn("WHERE existing.external_id = $1", conn.query)
self.assertEqual(conn.args[0], "google:claim-subject")
self.assertEqual(conn.args[1], "claim.me@example.com")
self.assertEqual(conn.args[5], "email:claim.me@example.com")
async def test_google_oauth_promotes_preregistered_pending_user_in_db(self) -> None: async def test_google_oauth_promotes_preregistered_pending_user_in_db(self) -> None:
class RecordingConn: class RecordingConn:
def __init__(self) -> None: def __init__(self) -> None: