补齐证书任务开始审计链
为 HTTP 证书申请任务增加开始执行审计;审计写入失败时收敛任务和尝试状态,补充回归测试并更新四份整改清单,验收位置继续保持 P0-03 完成待复审。
This commit is contained in:
parent
ff37ff4dec
commit
d1070b699e
@ -147,6 +147,20 @@ func (s *Server) executeCertificateIssueTask(c *gin.Context, task repository.Tas
|
||||
s.writeError(c, http.StatusInternalServerError, "更新任务状态失败", err)
|
||||
return
|
||||
}
|
||||
if s.audit != nil {
|
||||
if err := s.audit.CreateAuditLog(c.Request.Context(), repository.AuditLog{
|
||||
TaskID: task.ID, OperatorID: task.OperatorID,
|
||||
Action: auditAction, ResourceType: "domain", ResourceID: task.DomainID,
|
||||
Status: "running", Message: "开始申请证书并部署",
|
||||
}); err != nil {
|
||||
finished := time.Now().UTC()
|
||||
failureMessage := "任务启动审计记录失败"
|
||||
_ = s.tasks.UpdateTask(context.Background(), task.ID, "failed", "record", failureMessage, &now, &finished)
|
||||
_ = s.tasks.FinishAttempt(context.Background(), attempt.ID, "failed", failureMessage, &finished)
|
||||
s.writeError(c, http.StatusInternalServerError, failureMessage, err)
|
||||
return
|
||||
}
|
||||
}
|
||||
executionCtx, cancel := context.WithTimeout(c.Request.Context(), certificateTaskTimeout)
|
||||
s.registerTaskCancel(task.ID, cancel)
|
||||
defer func() {
|
||||
|
||||
@ -84,7 +84,7 @@ func TestTaskAPIRecordsSuccessfulIssueAndAudit(t *testing.T) {
|
||||
t.Fatalf("任务尝试记录错误:%+v %v", attempts, err)
|
||||
}
|
||||
logs, err := auditRepo.ListAuditLogs(context.Background(), 10)
|
||||
if err != nil || len(logs) != 1 || logs[0].Status != "success" {
|
||||
if err != nil || len(logs) != 2 || logs[0].Status != "success" || logs[1].Status != "running" {
|
||||
t.Fatalf("审计日志记录错误:%+v %v", logs, err)
|
||||
}
|
||||
wantScope := repository.HistoryScope{ScopeType: repository.ScopeProject, ProjectID: domain.DefaultProjectID}
|
||||
@ -168,6 +168,47 @@ func (r *failingTaskStartRepository) UpdateTask(ctx context.Context, id, status,
|
||||
return r.TaskRepository.UpdateTask(ctx, id, status, stage, message, startedAt, finishedAt)
|
||||
}
|
||||
|
||||
type failingTaskStartAuditRepository struct {
|
||||
repository.AuditRepository
|
||||
failure error
|
||||
}
|
||||
|
||||
func (r failingTaskStartAuditRepository) CreateAuditLog(ctx context.Context, item repository.AuditLog) error {
|
||||
if item.Status == "running" {
|
||||
return r.failure
|
||||
}
|
||||
return r.AuditRepository.CreateAuditLog(ctx, item)
|
||||
}
|
||||
|
||||
func TestTaskAPIClosesTaskWhenStartAuditFails(t *testing.T) {
|
||||
server, taskRepo, auditRepo, closeDB := newTaskAPITestServer(t, func(context.Context, string) (certificate.IssueResult, deployment.Report, error) {
|
||||
t.Fatal("任务启动审计失败时不应执行证书申请")
|
||||
return certificate.IssueResult{}, deployment.Report{}, nil
|
||||
})
|
||||
defer closeDB()
|
||||
server.audit = failingTaskStartAuditRepository{
|
||||
AuditRepository: auditRepo,
|
||||
failure: errors.New("模拟任务启动审计失败"),
|
||||
}
|
||||
|
||||
response := httptest.NewRecorder()
|
||||
serveAdminHTTP(server, response, httptest.NewRequest(http.MethodPost, "/api/v1/domains/domain-1/issue", nil))
|
||||
if response.Code != http.StatusInternalServerError || !strings.Contains(response.Body.String(), "任务启动审计记录失败") {
|
||||
t.Fatalf("任务启动审计失败响应错误:%d %s", response.Code, response.Body.String())
|
||||
}
|
||||
items, err := taskRepo.ListTasks(context.Background(), "", 10)
|
||||
if err != nil || len(items) != 1 || items[0].Status != "failed" || items[0].Stage != "record" {
|
||||
t.Fatalf("任务启动审计失败后任务未收敛:%+v %v", items, err)
|
||||
}
|
||||
attempts, err := taskRepo.ListAttempts(context.Background(), items[0].ID)
|
||||
if err != nil || len(attempts) != 1 || attempts[0].Status != "failed" {
|
||||
t.Fatalf("任务启动审计失败后尝试未收敛:%+v %v", attempts, err)
|
||||
}
|
||||
logs, err := auditRepo.ListAuditLogs(context.Background(), 10)
|
||||
if err != nil || len(logs) != 0 {
|
||||
t.Fatalf("启动审计写入失败时不应生成伪造终态审计:%+v %v", logs, err)
|
||||
}
|
||||
}
|
||||
func TestTaskAPIClosesTaskWhenStartStateUpdateFails(t *testing.T) {
|
||||
server, taskRepo, auditRepo, closeDB := newTaskAPITestServer(t, func(context.Context, string) (certificate.IssueResult, deployment.Report, error) {
|
||||
t.Fatal("任务启动失败时不应执行证书申请")
|
||||
@ -237,7 +278,7 @@ func TestTaskAPIReturnsFailureAndKeepsTaskTrace(t *testing.T) {
|
||||
t.Fatalf("失败任务状态错误:%+v %v", items, err)
|
||||
}
|
||||
logs, err := auditRepo.ListAuditLogs(context.Background(), 10)
|
||||
if err != nil || len(logs) != 1 || logs[0].Status != "error" {
|
||||
if err != nil || len(logs) != 2 || logs[0].Status != "error" || logs[1].Status != "running" {
|
||||
t.Fatalf("失败审计状态错误:%+v %v", logs, err)
|
||||
}
|
||||
}
|
||||
@ -312,7 +353,7 @@ func TestTaskAPICanCancelRunningIssue(t *testing.T) {
|
||||
t.Fatalf("任务取消状态没有持久化:%+v %v", item, err)
|
||||
}
|
||||
logs, err := auditRepo.ListAuditLogs(t.Context(), 10)
|
||||
if err != nil || len(logs) != 2 {
|
||||
if err != nil || len(logs) != 3 {
|
||||
t.Fatalf("取消和申请收尾审计缺失:%+v,%v", logs, err)
|
||||
}
|
||||
for _, entry := range logs {
|
||||
@ -528,7 +569,7 @@ func TestTaskAPIRetriesFailedCertificateIssue(t *testing.T) {
|
||||
t.Fatalf("retry attempts were not recorded correctly: %+v %v", attempts, err)
|
||||
}
|
||||
logs, err := auditRepo.ListAuditLogs(context.Background(), 10)
|
||||
if err != nil || len(logs) != 2 || logs[0].Action != "certificate_issue_retry" || logs[0].OperatorID != "test-admin" {
|
||||
if err != nil || len(logs) != 4 || logs[0].Action != "certificate_issue_retry" || logs[0].Status != "success" || logs[1].Action != "certificate_issue_retry" || logs[1].Status != "running" || logs[0].OperatorID != "test-admin" {
|
||||
t.Fatalf("retry audit was not recorded correctly: %+v %v", logs, err)
|
||||
}
|
||||
}
|
||||
@ -559,7 +600,7 @@ func TestTaskAPIRecordsPartialDeploymentSuccess(t *testing.T) {
|
||||
t.Fatalf("partial attempt status: %+v %v", attempts, err)
|
||||
}
|
||||
logs, err := auditRepo.ListAuditLogs(context.Background(), 10)
|
||||
if err != nil || len(logs) != 1 || logs[0].Status != "partial_success" {
|
||||
if err != nil || len(logs) != 2 || logs[0].Status != "partial_success" || logs[1].Status != "running" {
|
||||
t.Fatalf("partial audit status: %+v %v", logs, err)
|
||||
}
|
||||
}
|
||||
@ -586,7 +627,7 @@ func TestTaskAPIRecordsPartialDeploymentFailureAsPartialSuccess(t *testing.T) {
|
||||
t.Fatalf("partial failure attempt status: %+v %v", attempts, err)
|
||||
}
|
||||
logs, err := auditRepo.ListAuditLogs(context.Background(), 10)
|
||||
if err != nil || len(logs) != 1 || logs[0].Status != "partial_success" {
|
||||
if err != nil || len(logs) != 2 || logs[0].Status != "partial_success" || logs[1].Status != "running" {
|
||||
t.Fatalf("partial failure audit status: %+v %v", logs, err)
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,5 +1,16 @@
|
||||
# Scert 开发任务清单
|
||||
|
||||
## 最新进度摘要(2026-09-29 继续开发)
|
||||
|
||||
**总体验收位置仍为 P0-03 完成,待复审。** 本轮继续推进 P0-10 任务事务链,不把局部代码或专项测试视为整项复审通过。
|
||||
|
||||
- [x] HTTP 证书申请任务补齐“开始执行”审计;开始审计与终态审计均关联任务创建人、项目和任务 ID。
|
||||
- [x] 开始审计写入失败时,任务和任务尝试收敛为失败并停止证书申请;专项回归测试已覆盖该异常路径。
|
||||
- [x] `go test ./internal/httpapi` 已通过;尚未据此升级 P0-10 或总体验收状态。
|
||||
- [~] P0-10 的 DNS 验证任务、批量部署结果、崩溃恢复、重试幂等及其他长耗时入口仍需继续审查。
|
||||
- [ ] P0-12 备份恢复、三数据库实库矩阵、浏览器清缓存、密码 SSH、远端部署和生产验收尚未执行。
|
||||
- [!] 不新增 `[✓]` 复审通过项,总体验收继续保持 **P0-03 完成,待复审**。
|
||||
|
||||
## 最新执行摘要(2026-09-29 继续开发)
|
||||
|
||||
总体验收位置继续保持 **P0-03 完成,待复审**;本轮继续先开发、后统一测试,不进入远端生产验收。
|
||||
|
||||
@ -1,5 +1,16 @@
|
||||
# Scert 整改任务执行清单
|
||||
|
||||
## 最新进度摘要(2026-09-29 继续开发)
|
||||
|
||||
**总体验收位置仍为 P0-03 完成,待复审。** 本轮继续推进 P0-10 任务事务链,不把局部代码或专项测试视为整项复审通过。
|
||||
|
||||
- [x] HTTP 证书申请任务补齐“开始执行”审计;开始审计与终态审计均关联任务创建人、项目和任务 ID。
|
||||
- [x] 开始审计写入失败时,任务和任务尝试收敛为失败并停止证书申请;专项回归测试已覆盖该异常路径。
|
||||
- [x] `go test ./internal/httpapi` 已通过;尚未据此升级 P0-10 或总体验收状态。
|
||||
- [~] P0-10 的 DNS 验证任务、批量部署结果、崩溃恢复、重试幂等及其他长耗时入口仍需继续审查。
|
||||
- [ ] P0-12 备份恢复、三数据库实库矩阵、浏览器清缓存、密码 SSH、远端部署和生产验收尚未执行。
|
||||
- [!] 不新增 `[✓]` 复审通过项,总体验收继续保持 **P0-03 完成,待复审**。
|
||||
|
||||
## 最新任务批次(2026-09-29 继续开发)
|
||||
|
||||
总体验收仍保持 **P0-03 完成,待复审**;本批只补齐 P0-10 任务创建人和审计归属,不代表生产部署验收通过。
|
||||
|
||||
@ -2,6 +2,17 @@
|
||||
|
||||
## 最新进度摘要(2026-09-29 继续开发)
|
||||
|
||||
**总体验收位置仍为 P0-03 完成,待复审。** 本轮继续推进 P0-10 任务事务链,不把局部代码或专项测试视为整项复审通过。
|
||||
|
||||
- [x] HTTP 证书申请任务补齐“开始执行”审计;开始审计与终态审计均关联任务创建人、项目和任务 ID。
|
||||
- [x] 开始审计写入失败时,任务和任务尝试收敛为失败并停止证书申请;专项回归测试已覆盖该异常路径。
|
||||
- [x] `go test ./internal/httpapi` 已通过;尚未据此升级 P0-10 或总体验收状态。
|
||||
- [~] P0-10 的 DNS 验证任务、批量部署结果、崩溃恢复、重试幂等及其他长耗时入口仍需继续审查。
|
||||
- [ ] P0-12 备份恢复、三数据库实库矩阵、浏览器清缓存、密码 SSH、远端部署和生产验收尚未执行。
|
||||
- [!] 不新增 `[✓]` 复审通过项,总体验收继续保持 **P0-03 完成,待复审**。
|
||||
|
||||
## 最新进度摘要(2026-09-29 继续开发)
|
||||
|
||||
**总体验收位置仍为 P0-03 完成,待复审。** 本轮只推进 P0-10 任务归属链,不把局部代码或专项测试结果视为整项复审通过。
|
||||
|
||||
- [x] 任务工作流从认证请求上下文读取创建人,并写入证书任务的 `operator_id`。
|
||||
|
||||
@ -1,5 +1,16 @@
|
||||
# 基础整改任务规格
|
||||
|
||||
## 最新进度摘要(2026-09-29 继续开发)
|
||||
|
||||
**总体验收位置仍为 P0-03 完成,待复审。** 本轮继续推进 P0-10 任务事务链,不把局部代码或专项测试视为整项复审通过。
|
||||
|
||||
- [x] HTTP 证书申请任务补齐“开始执行”审计;开始审计与终态审计均关联任务创建人、项目和任务 ID。
|
||||
- [x] 开始审计写入失败时,任务和任务尝试收敛为失败并停止证书申请;专项回归测试已覆盖该异常路径。
|
||||
- [x] `go test ./internal/httpapi` 已通过;尚未据此升级 P0-10 或总体验收状态。
|
||||
- [~] P0-10 的 DNS 验证任务、批量部署结果、崩溃恢复、重试幂等及其他长耗时入口仍需继续审查。
|
||||
- [ ] P0-12 备份恢复、三数据库实库矩阵、浏览器清缓存、密码 SSH、远端部署和生产验收尚未执行。
|
||||
- [!] 不新增 `[✓]` 复审通过项,总体验收继续保持 **P0-03 完成,待复审**。
|
||||
|
||||
## 最新执行与补充约束(2026-09-29 继续开发)
|
||||
|
||||
总体验收位置继续保持 **P0-03 完成,待复审**。本轮补充 P0-10 任务归属不变量,不改变原始 44 项范围,也不提前进入生产验收。
|
||||
|
||||
Loading…
Reference in New Issue
Block a user