补齐证书任务开始审计链

为 HTTP 证书申请任务增加开始执行审计;审计写入失败时收敛任务和尝试状态,补充回归测试并更新四份整改清单,验收位置继续保持 P0-03 完成待复审。
This commit is contained in:
xuans 2026-09-30 02:55:42 +08:00
parent ff37ff4dec
commit d1070b699e
6 changed files with 105 additions and 6 deletions

View File

@ -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() {

View File

@ -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)
}
}

View File

@ -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 完成,待复审**;本轮继续先开发、后统一测试,不进入远端生产验收。

View File

@ -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 任务创建人和审计归属,不代表生产部署验收通过。

View File

@ -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`。

View File

@ -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 项范围,也不提前进入生产验收。