fix: 补充克隆音色权限校验 + 测试 user_id mock
CI/CD Pipeline / Build Staging API Image (pull_request) Has been skipped
CI/CD Pipeline / Build Staging Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Build Staging Web Image (pull_request) Has been skipped
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (pull_request) Has been skipped
CI/CD Pipeline / Staging API Integration Tests (pull_request) Has been skipped
CI/CD Pipeline / Staging E2E Tests (pull_request) Has been skipped
CI/CD Pipeline / ACR Image Cleanup (pull_request) Has been skipped
CI/CD Pipeline / Check if frontend-only change (pull_request) Successful in 28s
CI/CD Pipeline / Frontend Lint (pull_request) Has been skipped
CI/CD Pipeline / Frontend Unit Tests (pull_request) Has been skipped
CI/CD Pipeline / PR Build Web Image (pull_request) Has been skipped
CI/CD Pipeline / PR Build Worker Image (pull_request) Successful in 19s
AI Code Review / AI Code Review (pull_request) Successful in 1m44s
PR Automation / Auto Merge on CI Green + Approved (pull_request) Successful in 1m46s
Preview Deploy / Deploy Preview Environment (pull_request) Successful in 1m47s
CI/CD Pipeline / PR Build API Image (pull_request) Successful in 1m37s
CI/CD Pipeline / Validate - Migration (alembic) (pull_request) Successful in 2m40s
CI/CD Pipeline / Validate - Type Check (mypy) (pull_request) Successful in 3m11s
PR Automation / Auto Approve on CI Green (pull_request) Successful in 3m48s
CI/CD Pipeline / Unit Tests (pull_request) Successful in 6m20s
CI/CD Pipeline / Validate - Code Quality (pull_request) Successful in 8m22s
CI/CD Pipeline / Build Production API Image (pull_request) Has been skipped
CI/CD Pipeline / Build Production Web Image (pull_request) Has been skipped
CI/CD Pipeline / Build Production Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Deploy Production (pull_request) Has been skipped
CI/CD Pipeline / Production Browser E2E (pull_request) Has been skipped
CI/CD Pipeline / Canary Release to Production (pull_request) Has been skipped
CI/CD Pipeline / Integration Tests (pull_request) Successful in 6m45s
CI/CD Pipeline / CI Gate (pull_request) Successful in 14s
ACR Cleanup / ACR Image Cleanup (pull_request_target) Successful in 1m1s
Preview Cleanup / Cleanup Preview Environment (pull_request) Successful in 1m6s

AI Code Review 指出越权风险:未校验 VoiceCloneProfile 归属。
新增 profile.user_id != authenticated_user.user.id → 403。
补充 12 个测试全部通过。
This commit is contained in:
CI Bot
2026-08-25 16:05:13 +08:00
parent 7e7b73a2e1
commit 287a5dcd0f
2 changed files with 40 additions and 1 deletions
+6 -1
View File
@@ -392,7 +392,12 @@ def preview_tts(
actual_voice_id = request.voice_id
profile = voice_clone_repo.get(request.voice_id)
if profile is not None:
# 命中克隆音色 profile
# 命中克隆音色 profile — 校验归属权限
if profile.user_id != authenticated_user.user.id:
raise HTTPException(
status_code=status.HTTP_403_FORBIDDEN,
detail="无权访问该音色",
)
if not profile.voice_id:
raise HTTPException(
status_code=status.HTTP_400_BAD_REQUEST,
+34
View File
@@ -309,6 +309,7 @@ class TestTTSPreviewEndpoint:
# Mock voice clone profile with voice_id
mock_profile = MagicMock()
mock_profile.user_id = "user-1"
mock_profile.voice_id = "cosyvoice_actual_voice_123"
mock_clone_repo = MagicMock()
mock_clone_repo.get.return_value = mock_profile
@@ -351,6 +352,7 @@ class TestTTSPreviewEndpoint:
# Mock voice clone profile with empty voice_id (clone not finished)
mock_profile = MagicMock()
mock_profile.user_id = "user-1"
mock_profile.voice_id = ""
mock_clone_repo = MagicMock()
mock_clone_repo.get.return_value = mock_profile
@@ -405,3 +407,35 @@ class TestTTSPreviewEndpoint:
voice_id="longxiaoxia_v3",
speed=1.0,
)
def test_preview_clone_voice_wrong_user_returns_403(self):
"""Accessing another user's clone profile returns 403."""
from fastapi import FastAPI
app = FastAPI()
from app.api.routes.tts import router
app.include_router(router, prefix="/tts")
from app.auth import get_current_user
from app.dependencies import get_voice_clone_profile_repository
fake_user = MagicMock()
fake_user.user.id = "user-1"
app.dependency_overrides[get_current_user] = lambda: fake_user
# Mock profile belonging to a different user
mock_profile = MagicMock()
mock_profile.user_id = "user-2"
mock_profile.voice_id = "cosyvoice_voice_xyz"
mock_clone_repo = MagicMock()
mock_clone_repo.get.return_value = mock_profile
app.dependency_overrides[get_voice_clone_profile_repository] = lambda: mock_clone_repo
client = self._make_client(app)
resp = client.post(
"/tts/preview",
json={"text": "越权测试", "voice_id": "other-user-profile-uuid"},
)
assert resp.status_code == 403
assert "无权访问该音色" in resp.json()["detail"]