diff --git a/backend/app/gateway/routers/api_keys.py b/backend/app/gateway/routers/api_keys.py index f890fd54..4662bee5 100644 --- a/backend/app/gateway/routers/api_keys.py +++ b/backend/app/gateway/routers/api_keys.py @@ -11,7 +11,7 @@ from __future__ import annotations from datetime import datetime from typing import Literal -from fastapi import APIRouter, Depends, HTTPException, Request, Response +from fastapi import APIRouter, Depends, HTTPException, Response from pydantic import BaseModel, Field from app.gateway.authz import require_workspace_admin @@ -66,11 +66,12 @@ async def _require_sa_in_workspace(sa_id: str, sa_repo: ServiceAccountRepository @router.post("", status_code=201, dependencies=[Depends(require_workspace_admin)]) async def create_api_key( body: CreateApiKeyRequest, - request: Request, key_repo: ApiKeyRepository = Depends(get_api_key_repo), sa_repo: ServiceAccountRepository = Depends(get_service_account_repo), ): - await _require_sa_in_workspace(body.service_account_id, sa_repo) + sa = await _require_sa_in_workspace(body.service_account_id, sa_repo) + if sa["status"] != "active": + raise HTTPException(status_code=409, detail="service account is not active") gen = generate_api_key(body.env) created = await key_repo.create( service_account_id=body.service_account_id, diff --git a/backend/tests/test_api_keys_router.py b/backend/tests/test_api_keys_router.py index a5c6810a..1b708e59 100644 --- a/backend/tests/test_api_keys_router.py +++ b/backend/tests/test_api_keys_router.py @@ -123,3 +123,37 @@ async def test_member_cannot_create_key(tmp_path): assert r.status_code == 403 finally: await _cleanup() + + +async def test_revoke_other_workspace_key_404(tmp_path): + await _init_db_with_sa(tmp_path, sa_id="sa-1", workspace_id="w-1") + try: + client_a = TestClient(_make_app(workspace_id="w-1")) + created = client_a.post("/api/v1/api-keys", json={"service_account_id": "sa-1", "name": "k", "scopes": ""}).json() + client_b = TestClient(_make_app(workspace_id="w-2")) + assert client_b.delete(f"/api/v1/api-keys/{created['id']}").status_code == 404 + finally: + await _cleanup() + + +async def test_list_other_workspace_sa_404(tmp_path): + await _init_db_with_sa(tmp_path, sa_id="sa-1", workspace_id="w-1") + try: + client_b = TestClient(_make_app(workspace_id="w-2")) + assert client_b.get("/api/v1/api-keys", params={"service_account_id": "sa-1"}).status_code == 404 + finally: + await _cleanup() + + +async def test_create_for_suspended_sa_409(tmp_path): + await _init_db_with_sa(tmp_path) + try: + from deerflow.persistence.engine import get_session_factory + from deerflow.persistence.service_account import ServiceAccountRepository + + await ServiceAccountRepository(get_session_factory()).update_status("sa-1", "suspended") + client = TestClient(_make_app()) + r = client.post("/api/v1/api-keys", json={"service_account_id": "sa-1", "name": "x", "scopes": ""}) + assert r.status_code == 409 + finally: + await _cleanup()