修复DNS验证取消后的临时凭据回收
补充DNS在线验证上下文取消检查,避免取消请求继续测试或发布验证令牌;凭据保存后取消时执行临时凭据回收,并同步更新四份任务清单进度。
This commit is contained in:
parent
55fba4861a
commit
debcc67fb7
@ -123,6 +123,9 @@ func (m *DNSVerificationManager) Verify(ctx context.Context, input DNSVerificati
|
||||
if err != nil {
|
||||
return DNSVerificationResult{}, err
|
||||
}
|
||||
if err := ctx.Err(); err != nil {
|
||||
return DNSVerificationResult{}, err
|
||||
}
|
||||
if err := m.reserveVerificationSlot(); err != nil {
|
||||
return DNSVerificationResult{}, err
|
||||
}
|
||||
@ -139,6 +142,12 @@ func (m *DNSVerificationManager) Verify(ctx context.Context, input DNSVerificati
|
||||
Err: err,
|
||||
}
|
||||
}
|
||||
if err := ctx.Err(); err != nil {
|
||||
return DNSVerificationResult{TestReport: testReport}, &DNSVerificationError{
|
||||
Report: testReport,
|
||||
Err: err,
|
||||
}
|
||||
}
|
||||
verificationToken, err := secureToken(32)
|
||||
if err != nil {
|
||||
return DNSVerificationResult{}, fmt.Errorf("生成 DNS 验证令牌失败:%w", err)
|
||||
@ -156,6 +165,20 @@ func (m *DNSVerificationManager) Verify(ctx context.Context, input DNSVerificati
|
||||
}
|
||||
return DNSVerificationResult{}, fmt.Errorf("加密保存 DNS 凭据失败:%w", err)
|
||||
}
|
||||
if err := ctx.Err(); err != nil {
|
||||
cleanupErr := m.deleteCredential(credentialRef)
|
||||
if cleanupErr != nil {
|
||||
m.logCleanupFailure()
|
||||
return DNSVerificationResult{TestReport: testReport}, errors.Join(
|
||||
err,
|
||||
fmt.Errorf("DNS 在线验证取消后临时凭据回收失败:%w", cleanupErr),
|
||||
)
|
||||
}
|
||||
return DNSVerificationResult{TestReport: testReport}, &DNSVerificationError{
|
||||
Report: testReport,
|
||||
Err: err,
|
||||
}
|
||||
}
|
||||
expiresAt := m.now().UTC().Add(dnsVerificationLifetime)
|
||||
m.mu.Lock()
|
||||
expiredRefs := m.clearExpiredLocked(m.now().UTC())
|
||||
|
||||
@ -56,6 +56,19 @@ type memorySecretWriter struct {
|
||||
deleteErr error
|
||||
}
|
||||
|
||||
type cancellingSecretWriter struct {
|
||||
memorySecretWriter
|
||||
cancel context.CancelFunc
|
||||
}
|
||||
|
||||
func (s *cancellingSecretWriter) Put(ctx context.Context, reference string, value map[string]string) error {
|
||||
if err := s.memorySecretWriter.Put(ctx, reference, value); err != nil {
|
||||
return err
|
||||
}
|
||||
s.cancel()
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *memorySecretWriter) Put(_ context.Context, reference string, value map[string]string) error {
|
||||
m.mu.Lock()
|
||||
defer m.mu.Unlock()
|
||||
@ -265,6 +278,48 @@ func TestDNSVerificationManagerDeletesCredentialWhenPutReportsFailure(t *testing
|
||||
}
|
||||
}
|
||||
|
||||
func TestDNSVerificationManagerRejectsAlreadyCancelledContextBeforeTesting(t *testing.T) {
|
||||
tester := &countingDNSTester{}
|
||||
store := &memorySecretWriter{}
|
||||
manager := NewDNSVerificationManager(tester, store)
|
||||
ctx, cancel := context.WithCancel(t.Context())
|
||||
cancel()
|
||||
|
||||
_, err := manager.Verify(ctx, DNSVerificationInput{
|
||||
ProviderID: "cloudflare", TestDomain: "example.com",
|
||||
Credentials: map[string]string{"api_token": "secret"},
|
||||
})
|
||||
if !errors.Is(err, context.Canceled) {
|
||||
t.Fatalf("已取消上下文应返回 context.Canceled:%v", err)
|
||||
}
|
||||
if tester.CallCount() != 0 || len(store.values) != 0 {
|
||||
t.Fatalf("已取消上下文不应执行测试或保存凭据:calls=%d values=%v", tester.CallCount(), store.values)
|
||||
}
|
||||
}
|
||||
|
||||
func TestDNSVerificationManagerCleansCredentialWhenContextCancelsAfterStore(t *testing.T) {
|
||||
ctx, cancel := context.WithCancel(t.Context())
|
||||
store := &cancellingSecretWriter{cancel: cancel}
|
||||
manager := NewDNSVerificationManager(fakeDNSTester{}, store)
|
||||
|
||||
result, err := manager.Verify(ctx, DNSVerificationInput{
|
||||
ProviderID: "cloudflare", TestDomain: "example.com",
|
||||
Credentials: map[string]string{"api_token": "secret"},
|
||||
})
|
||||
if !errors.Is(err, context.Canceled) {
|
||||
t.Fatalf("保存凭据后取消应返回 context.Canceled:%v", err)
|
||||
}
|
||||
if result.CredentialRef != "" || result.VerificationToken != "" {
|
||||
t.Fatalf("取消的 DNS 验证不应发布令牌:%+v", result)
|
||||
}
|
||||
if len(store.values) != 0 {
|
||||
t.Fatalf("保存后取消未回收临时凭据:%v", store.values)
|
||||
}
|
||||
if len(store.deleted) != 1 {
|
||||
t.Fatalf("保存后取消未执行临时凭据回收:%v", store.deleted)
|
||||
}
|
||||
}
|
||||
|
||||
type countingDNSTester struct {
|
||||
mu sync.Mutex
|
||||
calls int
|
||||
|
||||
@ -3747,3 +3747,14 @@ Linux Ubuntu 22.04 上的 `Scert-admin` 手动启停、无开机自启动、无
|
||||
- [~] 进行中:DNS 验证任务、其他 P0-10 任务链、跨数据库实机矩阵、崩溃恢复、重试幂等和统一复审。
|
||||
- [ ] 未开始:P0-12 备份恢复、浏览器清缓存、密码 SSH、远端部署及最终生产门禁。
|
||||
- [!] 总体验收不得升级:仍为 **P0-03:完成,待复审**,没有新增 `[✓]`;提交推送遇到 `Authentication failed`。
|
||||
|
||||
## 本轮开发进度(2026-09-30,P0-10 DNS 验证取消与临时凭据回收)
|
||||
|
||||
总体验收继续保持 **P0-03:完成,待复审**,本轮继续先开发、后统一测试。
|
||||
|
||||
- [x] 已完成,等待复审:DNS 在线验证在进入测试器前响应上下文取消,阻止已取消请求继续执行。
|
||||
- [x] 已完成,等待复审:凭据写入后检测取消状态,失败时删除临时凭据,不创建验证会话或一次性令牌。
|
||||
- [x] 已完成:新增取消前置和保存后回收回归测试;后端全量测试、静态检查和差异检查均通过。
|
||||
- [~] 进行中:DNS 清理失败与初始化回滚矩阵、其他 P0-10 任务链、跨数据库实机验证和统一复审。
|
||||
- [ ] 未开始:P0-12、真实数据库清理初始化、密码 SSH、远端多服务器部署及最终生产门禁。
|
||||
- [!] 不得标记 `[✓]`,总体验收仍为 **P0-03:完成,待复审**。
|
||||
|
||||
@ -1052,3 +1052,14 @@ P0-05 从 `[!]` 调整为 `[~]`,并未标记完成;P0-04 剩余门禁和全
|
||||
- [~] 进行中:P0-10 其他任务链、DNS、跨数据库实机、崩溃恢复、重试幂等及统一复审。
|
||||
- [ ] 未开始:P0-12 备份恢复、浏览器缓存清理、密码 SSH、远端部署及最终生产门禁。
|
||||
- [!] 当前不得升级验收状态,仍为 **P0-03:完成,待复审**,不得新增 `[✓]`。
|
||||
|
||||
## 本轮执行记录(2026-09-30,P0-10 DNS 验证取消与临时凭据回收)
|
||||
|
||||
本轮按“先开发、后统一测试”执行,总体验收仍保持 **P0-03:完成,待复审**。
|
||||
|
||||
- [x] DNS 验证上下文在测试前已取消时不调用服务商适配器,且不保存临时凭据。
|
||||
- [x] DNS 凭据保存成功后请求被取消时,已删除临时凭据并阻止令牌发布,避免未绑定密钥残留。
|
||||
- [x] `go test ./...`、`go vet ./...`、`git diff --check` 已通过;本轮仅完成本地开发与自动化回归。
|
||||
- [~] 继续执行:DNS 清理失败、令牌生命周期、初始化回滚、任务链、三数据库实机矩阵和统一复审。
|
||||
- [ ] 尚未执行:P0-12、真实生产数据库清理、密码 SSH、远端部署、真实 HTTPS/DNS/ACME 和最终生产门禁。
|
||||
- [!] 不新增 `[✓]`;总体验收继续为 **P0-03:完成,待复审**。
|
||||
|
||||
@ -1700,3 +1700,14 @@ P0-11 生产验收门禁
|
||||
- [~] 进行中:P0-10 其他任务入口、DNS 验证、跨数据库实机矩阵、崩溃恢复、重试幂等和统一复审仍需继续。
|
||||
- [ ] 未开始:P0-12 备份恢复、浏览器清缓存、密码 SSH、远端部署、真实 DNS/ACME 和最终生产门禁仍未完成。
|
||||
- [!] 总体验收不得升级:当前仍为 **P0-03:完成,待复审**,没有新增 `[✓]` 复审通过项;`415d504` 推送时遇到 `Authentication failed`,不作为测试失败依据。
|
||||
|
||||
## 本轮开发进度(2026-09-30,P0-10 DNS 验证取消与临时凭据回收)
|
||||
|
||||
总体验收位置继续保持 **P0-03:完成,待复审**;本轮仅补齐 DNS 在线验证的请求取消边界,不代表 P0-10 统一复审通过或生产部署验收通过。
|
||||
|
||||
- [x] 已完成,等待复审:DNS 验证开始前检查请求上下文,已取消请求不会调用 DNS 服务商测试器,也不会写入临时凭据。
|
||||
- [x] 已完成,等待复审:DNS 测试成功但请求在凭据写入后取消时,回收临时凭据且不发布验证令牌,避免遗留可用的临时密钥。
|
||||
- [x] 已完成:新增两条 DNS 生命周期回归测试;后端 `go test ./...`、`go vet ./...` 和 `git diff --check` 通过。
|
||||
- [~] 进行中:P0-10 DNS 清理失败、令牌消费、任务链、跨数据库实机矩阵、崩溃恢复、重试幂等和统一复审仍需继续。
|
||||
- [ ] 未开始:P0-12 备份恢复、浏览器清缓存、密码 SSH、远端部署、真实 HTTPS/DNS/ACME 和最终生产门禁仍未完成。
|
||||
- [!] 总体验收不得升级:仍为 **P0-03:完成,待复审**,本轮没有新增 `[✓]` 复审通过项。
|
||||
|
||||
@ -627,3 +627,13 @@ P0-06 与 P0-07 均维持 `[~]`,六阶段中的隔离、生产和最终验收
|
||||
- [x] `go test ./...`、`go vet ./...`、定向任务测试和 `git diff --check` 均通过,代码提交 `415d504`。
|
||||
- [~] P0-10 其他任务入口、DNS 验证、跨数据库实机行为、崩溃恢复、重试幂等和统一复审继续进行。
|
||||
- [!] 本地结果不得替代真实 DNS/ACME、多服务器推送、密码 SSH 和最终生产门禁;总体验收不得离开 **P0-03:完成,待复审**。
|
||||
|
||||
## 本轮规格执行记录(2026-09-30,P0-10 DNS 验证取消与临时凭据回收)
|
||||
|
||||
本轮仅补齐 DNS 在线验证请求取消边界,总体验收继续保持 **P0-03:完成,待复审**。
|
||||
|
||||
- [x] DNS 验证必须在开始服务商调用前检查上下文取消,取消请求不得触发权限测试或临时凭据写入。
|
||||
- [x] 临时凭据写入后若上下文取消,必须回收凭据并阻止一次性验证令牌进入后续初始化流程。
|
||||
- [x] 已新增对应回归测试,并通过后端全量测试、静态检查和差异检查。
|
||||
- [~] DNS 清理失败、初始化回滚、令牌消费及 P0-10 其他任务链继续开发和统一复审。
|
||||
- [!] 本地自动化结果不得替代真实 DNS/ACME、密码 SSH、远端多服务器部署和最终生产门禁;不得新增 `[✓]`。
|
||||
|
||||
Loading…
Reference in New Issue
Block a user