From 3504dcab7ae27bc4cb4fe502a99bb0df92a49204 Mon Sep 17 00:00:00 2001 From: xuans Date: Tue, 29 Sep 2026 21:42:35 +0800 Subject: [PATCH] =?UTF-8?q?=E8=A1=A5=E9=BD=90=E4=BB=BB=E5=8A=A1=E5=8F=96?= =?UTF-8?q?=E6=B6=88=E6=9D=83=E9=99=90=E9=97=AD=E7=8E=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 增加项目任务取消权限校验和回归测试,并记录本轮开发进度。 --- backend/internal/httpapi/task_api.go | 3 ++ backend/internal/httpapi/task_api_test.go | 39 +++++++++++++++++++++++ doc/Scert开发任务清单.md | 13 +++++++- doc/Scert整改任务执行清单.md | 13 +++++++- doc/Scert整改合并优化清单.md | 13 +++++++- doc/基础整改任务规格.md | 13 +++++++- 6 files changed, 90 insertions(+), 4 deletions(-) diff --git a/backend/internal/httpapi/task_api.go b/backend/internal/httpapi/task_api.go index 1ecfb75..cd2f36d 100644 --- a/backend/internal/httpapi/task_api.go +++ b/backend/internal/httpapi/task_api.go @@ -273,6 +273,9 @@ func (s *Server) cancelTask(c *gin.Context) { c.JSON(http.StatusConflict, gin.H{"error": "管理证书任务由续期调度控制,不能单独修改取消状态", "task": item}) return } + if !s.authorizeProjectPermissions(c, item.ProjectID, domain.PermissionTaskCancel) { + return + } finished := time.Now().UTC() if err := reader.CancelVisibleTask(c.Request.Context(), c.GetString(authenticatedActorKey), taskID, "任务已由用户取消", &finished); err != nil { if errors.Is(err, repository.ErrProjectAccessDenied) || errors.Is(err, sql.ErrNoRows) { diff --git a/backend/internal/httpapi/task_api_test.go b/backend/internal/httpapi/task_api_test.go index f7cdb93..372bdc8 100644 --- a/backend/internal/httpapi/task_api_test.go +++ b/backend/internal/httpapi/task_api_test.go @@ -369,6 +369,45 @@ func TestTaskAPIReturnsNotImplementedWhenTaskDependenciesAreMissing(t *testing.T } } +type taskPermissionProjectMemberRepository struct { + repository.ProjectMemberRepository + authorize func(context.Context, string, string, domain.ProjectPermission) error +} + +func (r taskPermissionProjectMemberRepository) AuthorizeProject(ctx context.Context, actorID, projectID string, permission domain.ProjectPermission) error { + if r.authorize != nil { + return r.authorize(ctx, actorID, projectID, permission) + } + return nil +} + +func TestTaskAPIDeniesCancelWithoutProjectPermission(t *testing.T) { + server, tasks, _, closeDB := newTaskAPITestServer(t, nil) + defer closeDB() + server.projectMembers = taskPermissionProjectMemberRepository{ + ProjectMemberRepository: server.projectMembers, + authorize: func(_ context.Context, _ string, _ string, permission domain.ProjectPermission) error { + if permission == domain.PermissionTaskCancel { + return repository.ErrProjectAccessDenied + } + return nil + }, + } + item := repository.Task{ + HistoryScope: repository.HistoryScope{ScopeType: repository.ScopeProject, ProjectID: domain.DefaultProjectID}, + ID: "cancel-permission-task", DomainID: "domain-1", TaskType: "certificate_issue", Status: "running", Stage: "certificate_issue", + } + if err := tasks.CreateTask(t.Context(), item); err != nil { + t.Fatal(err) + } + + response := httptest.NewRecorder() + serveAdminHTTP(server, response, httptest.NewRequest(http.MethodDelete, "/api/v1/tasks/"+item.ID, nil)) + stored, err := tasks.GetTask(t.Context(), item.ID) + if response.Code != http.StatusForbidden || err != nil || stored.Status != "running" { + t.Fatalf("cancel permission denial changed task: %d %+v %v", response.Code, stored, err) + } +} func TestIssueDomainSanitizesDeploymentReportWithoutTaskRepository(t *testing.T) { cfg := readyTestConfig(t.TempDir()) server := New(Dependencies{ diff --git a/doc/Scert开发任务清单.md b/doc/Scert开发任务清单.md index 51c77ec..2d5646e 100644 --- a/doc/Scert开发任务清单.md +++ b/doc/Scert开发任务清单.md @@ -3462,4 +3462,15 @@ Linux Ubuntu 22.04 上的 `Scert-admin` 手动启停、无开机自启动、无 - `[~]` P0-07 其他资源写入权限、三数据库矩阵、浏览器清缓存验收、密码 SSH、远端部署及 Linux/Windows 生产服务仍需继续开发或复审。 - `[!]` 总体验收不得升级,P0-03 仍为“完成,待复审”。 -下一步继续执行前端回归与生产构建,再提交并推送本轮测试代码;完成开发阶段后,统一进行三数据库、浏览器、远端服务器和生产部署测试。 \ No newline at end of file +下一步继续执行前端回归与生产构建,再提交并推送本轮测试代码;完成开发阶段后,统一进行三数据库、浏览器、远端服务器和生产部署测试。 +## 本轮开发进度(2026-09-29) + +总体验收位置继续保持 **P0-03:完成,待复审**;本轮继续推进 P0-07 项目任务权限闭环,不将局部测试结果视为生产部署验收通过。 + +- [x] 项目任务取消入口新增 ask.cancel 实时项目权限校验,权限拒绝时不会调用取消写入,也不会改变任务状态。 +- [x] 已补充缺少任务取消权限的 HTTP 回归测试;任务取消、工作流任务保护及成功证书任务回归测试通过。 +- [x] 已确认域名与服务器多对多部署关联仍按既有事务模型工作:一个域名可绑定多个服务器,一个服务器可关联多个域名,解绑单个域名不影响其他关联。 +- [~] P0-07 仍需继续补齐续期、证书导入/部署、其他任务写入权限及三数据库矩阵。 +- [!] 浏览器清缓存验收、密码 SSH、远端部署、HTTPS/DNS/ACME、Linux/Windows 服务和生产部署验收尚未执行。 + +下一步继续完成开发阶段剩余权限闭环,再统一执行生产构建、部署和验收;总体验收位置仍以 P0-03 为准。 \ No newline at end of file diff --git a/doc/Scert整改任务执行清单.md b/doc/Scert整改任务执行清单.md index 6767bb3..1811d8e 100644 --- a/doc/Scert整改任务执行清单.md +++ b/doc/Scert整改任务执行清单.md @@ -758,4 +758,15 @@ P0-05 从 `[!]` 调整为 `[~]`,并未标记完成;P0-04 剩余门禁和全 - `[~]` P0-07 其他资源写入权限、三数据库矩阵、浏览器清缓存验收、密码 SSH、远端部署及 Linux/Windows 生产服务仍需继续开发或复审。 - `[!]` 总体验收不得升级,P0-03 仍为“完成,待复审”。 -下一步继续执行前端回归与生产构建,再提交并推送本轮测试代码;完成开发阶段后,统一进行三数据库、浏览器、远端服务器和生产部署测试。 \ No newline at end of file +下一步继续执行前端回归与生产构建,再提交并推送本轮测试代码;完成开发阶段后,统一进行三数据库、浏览器、远端服务器和生产部署测试。 +## 本轮开发进度(2026-09-29) + +总体验收位置继续保持 **P0-03:完成,待复审**;本轮继续推进 P0-07 项目任务权限闭环,不将局部测试结果视为生产部署验收通过。 + +- [x] 项目任务取消入口新增 ask.cancel 实时项目权限校验,权限拒绝时不会调用取消写入,也不会改变任务状态。 +- [x] 已补充缺少任务取消权限的 HTTP 回归测试;任务取消、工作流任务保护及成功证书任务回归测试通过。 +- [x] 已确认域名与服务器多对多部署关联仍按既有事务模型工作:一个域名可绑定多个服务器,一个服务器可关联多个域名,解绑单个域名不影响其他关联。 +- [~] P0-07 仍需继续补齐续期、证书导入/部署、其他任务写入权限及三数据库矩阵。 +- [!] 浏览器清缓存验收、密码 SSH、远端部署、HTTPS/DNS/ACME、Linux/Windows 服务和生产部署验收尚未执行。 + +下一步继续完成开发阶段剩余权限闭环,再统一执行生产构建、部署和验收;总体验收位置仍以 P0-03 为准。 \ No newline at end of file diff --git a/doc/Scert整改合并优化清单.md b/doc/Scert整改合并优化清单.md index ba295a5..1161ff8 100644 --- a/doc/Scert整改合并优化清单.md +++ b/doc/Scert整改合并优化清单.md @@ -1398,4 +1398,15 @@ P0-11 生产验收门禁 - `[~]` P0-07 其他资源写入权限、三数据库矩阵、浏览器清缓存验收、密码 SSH、远端部署及 Linux/Windows 生产服务仍需继续开发或复审。 - `[!]` 总体验收不得升级,P0-03 仍为“完成,待复审”。 -下一步继续执行前端回归与生产构建,再提交并推送本轮测试代码;完成开发阶段后,统一进行三数据库、浏览器、远端服务器和生产部署测试。 \ No newline at end of file +下一步继续执行前端回归与生产构建,再提交并推送本轮测试代码;完成开发阶段后,统一进行三数据库、浏览器、远端服务器和生产部署测试。 +## 本轮开发进度(2026-09-29) + +总体验收位置继续保持 **P0-03:完成,待复审**;本轮继续推进 P0-07 项目任务权限闭环,不将局部测试结果视为生产部署验收通过。 + +- [x] 项目任务取消入口新增 ask.cancel 实时项目权限校验,权限拒绝时不会调用取消写入,也不会改变任务状态。 +- [x] 已补充缺少任务取消权限的 HTTP 回归测试;任务取消、工作流任务保护及成功证书任务回归测试通过。 +- [x] 已确认域名与服务器多对多部署关联仍按既有事务模型工作:一个域名可绑定多个服务器,一个服务器可关联多个域名,解绑单个域名不影响其他关联。 +- [~] P0-07 仍需继续补齐续期、证书导入/部署、其他任务写入权限及三数据库矩阵。 +- [!] 浏览器清缓存验收、密码 SSH、远端部署、HTTPS/DNS/ACME、Linux/Windows 服务和生产部署验收尚未执行。 + +下一步继续完成开发阶段剩余权限闭环,再统一执行生产构建、部署和验收;总体验收位置仍以 P0-03 为准。 \ No newline at end of file diff --git a/doc/基础整改任务规格.md b/doc/基础整改任务规格.md index 465a68d..3ddecbc 100644 --- a/doc/基础整改任务规格.md +++ b/doc/基础整改任务规格.md @@ -347,4 +347,15 @@ P0-06 与 P0-07 均维持 `[~]`,六阶段中的隔离、生产和最终验收 - `[~]` P0-07 其他资源写入权限、三数据库矩阵、浏览器清缓存验收、密码 SSH、远端部署及 Linux/Windows 生产服务仍需继续开发或复审。 - `[!]` 总体验收不得升级,P0-03 仍为“完成,待复审”。 -下一步继续执行前端回归与生产构建,再提交并推送本轮测试代码;完成开发阶段后,统一进行三数据库、浏览器、远端服务器和生产部署测试。 \ No newline at end of file +下一步继续执行前端回归与生产构建,再提交并推送本轮测试代码;完成开发阶段后,统一进行三数据库、浏览器、远端服务器和生产部署测试。 +## 本轮开发进度(2026-09-29) + +总体验收位置继续保持 **P0-03:完成,待复审**;本轮继续推进 P0-07 项目任务权限闭环,不将局部测试结果视为生产部署验收通过。 + +- [x] 项目任务取消入口新增 ask.cancel 实时项目权限校验,权限拒绝时不会调用取消写入,也不会改变任务状态。 +- [x] 已补充缺少任务取消权限的 HTTP 回归测试;任务取消、工作流任务保护及成功证书任务回归测试通过。 +- [x] 已确认域名与服务器多对多部署关联仍按既有事务模型工作:一个域名可绑定多个服务器,一个服务器可关联多个域名,解绑单个域名不影响其他关联。 +- [~] P0-07 仍需继续补齐续期、证书导入/部署、其他任务写入权限及三数据库矩阵。 +- [!] 浏览器清缓存验收、密码 SSH、远端部署、HTTPS/DNS/ACME、Linux/Windows 服务和生产部署验收尚未执行。 + +下一步继续完成开发阶段剩余权限闭环,再统一执行生产构建、部署和验收;总体验收位置仍以 P0-03 为准。 \ No newline at end of file