From 89a53b52111cfa2d947ddbd42005bbcefb32bc7f Mon Sep 17 00:00:00 2001 From: CI Test Date: Wed, 1 Jul 2026 23:45:07 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20=E4=BF=AE=E5=A4=8D=20submit/retry/cancel?= =?UTF-8?q?=20=E8=B7=AF=E7=94=B1=E6=9D=83=E9=99=90=E6=A3=80=E6=9F=A5?= =?UTF-8?q?=E9=A1=BA=E5=BA=8F=EF=BC=88P1=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 将权限检查从状态变更之后移到之前,防止非授权用户触发状态变更: - submit_job: 先获取 job 并验证权限,再执行 SubmitJobUseCase - retry_job: 同上 - cancel_job: 同上 修复审计 P1 问题。 --- apps/api/app/api/routes/jobs.py | 31 +++++++++++++++++++++---------- 1 file changed, 21 insertions(+), 10 deletions(-) diff --git a/apps/api/app/api/routes/jobs.py b/apps/api/app/api/routes/jobs.py index ee8554ab4..84b72163f 100755 --- a/apps/api/app/api/routes/jobs.py +++ b/apps/api/app/api/routes/jobs.py @@ -130,6 +130,13 @@ def submit_job( 将任务状态从 pending 切换为 running,并 dispatch Celery 异步任务。 """ + # 权限检查:先获取任务并验证权限,再执行状态变更 + job = job_repo.get(job_id) + if job is None: + raise HTTPException(status_code=404, detail=f"Job {job_id} not found") + if job.created_by_user_id and job.created_by_user_id != authenticated_user.user.id: + raise HTTPException(status_code=403, detail="Access denied to this job") + use_case = SubmitJobUseCase(job_repo) try: @@ -137,10 +144,6 @@ def submit_job( except ValueError as e: raise HTTPException(status_code=400, detail=str(e)) - # 权限检查 - if job.created_by_user_id and job.created_by_user_id != authenticated_user.user.id: - raise HTTPException(status_code=403, detail="Access denied to this job") - # Dispatch Celery 任务 celery_task_name = _JOB_TYPE_TO_CELERY_TASK.get(job.job_type.value) if celery_task_name: @@ -290,6 +293,13 @@ def retry_job( 将任务重置为 pending,retry_count + 1,但不自动 dispatch。 需要再次调用 /submit 提交执行。 """ + # 权限检查:先获取任务并验证权限,再执行状态变更 + job = job_repo.get(job_id) + if job is None: + raise HTTPException(status_code=404, detail=f"Job {job_id} not found") + if job.created_by_user_id and job.created_by_user_id != authenticated_user.user.id: + raise HTTPException(status_code=403, detail="Access denied to this job") + use_case = RetryJobUseCase(job_repo) try: @@ -297,9 +307,6 @@ def retry_job( except ValueError as e: raise HTTPException(status_code=400, detail=str(e)) - if job.created_by_user_id and job.created_by_user_id != authenticated_user.user.id: - raise HTTPException(status_code=403, detail="Access denied to this job") - return job_to_response(job) @@ -310,6 +317,13 @@ def cancel_job( job_repo: Any = Depends(get_job_repository), ) -> JobResponse: """取消任务。""" + # 权限检查:先获取任务并验证权限,再执行状态变更 + job = job_repo.get(job_id) + if job is None: + raise HTTPException(status_code=404, detail=f"Job {job_id} not found") + if job.created_by_user_id and job.created_by_user_id != authenticated_user.user.id: + raise HTTPException(status_code=403, detail="Access denied to this job") + use_case = CancelJobUseCase(job_repo) try: @@ -317,7 +331,4 @@ def cancel_job( except ValueError as e: raise HTTPException(status_code=400, detail=str(e)) - if job.created_by_user_id and job.created_by_user_id != authenticated_user.user.id: - raise HTTPException(status_code=403, detail="Access denied to this job") - return job_to_response(job)