"""GET /api/v1/apikeys/apply-approvals — the「API Key 申请审批」待我审批 list. An AI API-Key APPLY (申请) request is decided in the Feishu「审批」app, so Helix cannot list it from a stored approver_id — it must resolve the live Feishu pending-approver set per pending instance and keep only the applies the caller is currently the approver of. These tests pin: * a pending apply whose Feishu instance is waiting on the caller → surfaces, with the display fields the todo tab renders; * a pending apply waiting on SOMEONE ELSE → does NOT surface (it's not 待我审批); * a pending apply with no Feishu instance recorded → skipped (can't resolve who acts on it). """ from __future__ import annotations import uuid from decimal import Decimal import pytest from sqlalchemy.ext.asyncio import AsyncSession from app.domains.apikey.models import ApiKeyAssignment, ApiKeyProvider from app.domains.apikey.service import STATUS_ACTIVE, STATUS_PENDING from app.identity.person_models import IdentityPerson async def _provider(db: AsyncSession) -> ApiKeyProvider: p = ApiKeyProvider( id=uuid.uuid4(), name=f"AWS BedRock {uuid.uuid4().hex[:4]}", description="", is_active=True, sort_order=0, ) db.add(p) await db.flush() return p async def _applicant(db: AsyncSession) -> IdentityPerson: person = IdentityPerson( id=uuid.uuid4(), work_email=f"applicant-{uuid.uuid4().hex[:8]}@test.local", display_name="Kenneth Lee", employment_status="active", source_system="test", hris_person_id=f"sf-{uuid.uuid4().hex[:6]}", ) db.add(person) await db.flush() return person async def _pending_apply( db: AsyncSession, *, provider: ApiKeyProvider, applicant: IdentityPerson, instance_code: str | None, status: str = STATUS_PENDING, ) -> ApiKeyAssignment: detail = {"feishu": {"instance_code": instance_code}} if instance_code else {} a = ApiKeyAssignment( id=uuid.uuid4(), provider_id=provider.id, assigned_to=applicant.id, status=status, request_number=f"AK-{uuid.uuid4().hex[:8].upper()}", project_name="Agent Framework", reason="building agents on AWS Agentcore", monthly_budget_usd=Decimal("20.00"), expected_usage="500K/day", key_value=None, detail=detail, ) db.add(a) await db.commit() return a def _patch_feishu(monkeypatch, pending_emails: list[str]) -> None: import app.domains.apikey.service as svc_mod from app.approval.feishu_client import FeishuApprovalClient async def _fake_cfg(*, session=None): return {"app_id": "x", "app_secret": "y"} async def _fake_pending(self, instance_code): return [e.lower() for e in pending_emails] monkeypatch.setattr(svc_mod, "get_feishu_config", _fake_cfg) monkeypatch.setattr( FeishuApprovalClient, "list_pending_approver_emails", _fake_pending, ) @pytest.mark.asyncio async def test_apply_approval_surfaces_for_current_feishu_approver( client, employee_user, db_session, monkeypatch, ): me, token = employee_user provider = await _provider(db_session) applicant = await _applicant(db_session) apply = await _pending_apply( db_session, provider=provider, applicant=applicant, instance_code=f"INST-{uuid.uuid4().hex[:10]}", ) # Feishu says the caller is the one currently pending on this instance. _patch_feishu(monkeypatch, [me.work_email]) resp = await client.get( "/api/v1/apikeys/apply-approvals", headers={"Authorization": f"Bearer {token}"}, ) assert resp.status_code == 200 items = resp.json()["data"] assert len(items) == 1 row = items[0] assert row["id"] == str(apply.id) assert row["requester_display_name"] == "Kenneth Lee" assert row["project_name"] == "Agent Framework" assert row["monthly_budget_usd"] == "20.00" assert row["expected_usage"] == "500K/day" assert row["provider_name"] == provider.name assert row["feishu_instance_code"] == apply.detail["feishu"]["instance_code"] @pytest.mark.asyncio async def test_apply_approval_hidden_when_pending_on_someone_else( client, employee_user, db_session, monkeypatch, ): _, token = employee_user provider = await _provider(db_session) applicant = await _applicant(db_session) await _pending_apply( db_session, provider=provider, applicant=applicant, instance_code=f"INST-{uuid.uuid4().hex[:10]}", ) # The instance is waiting on a DIFFERENT approver — not 待我审批. _patch_feishu(monkeypatch, ["someone-else@test.local"]) resp = await client.get( "/api/v1/apikeys/apply-approvals", headers={"Authorization": f"Bearer {token}"}, ) assert resp.status_code == 200 assert resp.json()["data"] == [] @pytest.mark.asyncio async def test_apply_approval_skips_rows_without_feishu_instance( client, employee_user, db_session, monkeypatch, ): me, token = employee_user provider = await _provider(db_session) applicant = await _applicant(db_session) # No instance_code recorded → can't resolve who acts on it → skipped, # even though Feishu would name the caller. await _pending_apply( db_session, provider=provider, applicant=applicant, instance_code=None, ) # An already-active assignment must never show in a pending list either. await _pending_apply( db_session, provider=provider, applicant=applicant, instance_code=f"INST-{uuid.uuid4().hex[:10]}", status=STATUS_ACTIVE, ) _patch_feishu(monkeypatch, [me.work_email]) resp = await client.get( "/api/v1/apikeys/apply-approvals", headers={"Authorization": f"Bearer {token}"}, ) assert resp.status_code == 200 assert resp.json()["data"] == []