后端与全仓代码质量清理(golangci 扩展集 · 测试质量 · 并发安全 · 文档同步)

代码质量全量清理,零行为变化:golangci 扩展集 13 类 linter(gosec/modernize/perfsprint/canonicalheader/usestdlibvars/wastedassign/intrange/errorlint/forcetypeassert/recvcheck/exhaustive/unparam)全量修复,测试代码质量(testifylint/thelper/usetesting)25→0,frpc 进程生命周期真 bug(进程组击杀)、全仓 go test -race 6 类数据竞争(含 1 个生产竞争)、SPDX license 头补齐 131 文件、前端测试套件 next-intl 迁移后 44 失败→全绿、过期 swagger 文档重新生成、pnpm-workspace 构建审批。

Experiments: #2-#17, #18, #20, #21, #23
Metric: total_issues 108 → 8 (-92.6%)
This commit is contained in:
ryan
2026-08-16 21:23:37 +08:00
parent 5a8722ff07
commit 2f60329886
292 changed files with 1362 additions and 793 deletions
+1 -1
View File
@@ -173,7 +173,7 @@ func SetupDNSProvider(client *lego.Client, dnsType, dnsAuth string, dns1, dns2 s
case "cloudflare":
var creds map[string]string
if err := json.Unmarshal([]byte(dnsAuth), &creds); err != nil {
return fmt.Errorf("failed to parse cloudflare credentials: %v", err)
return fmt.Errorf("failed to parse cloudflare credentials: %w", err)
}
config := cloudflare.NewDefaultConfig()
@@ -5,7 +5,6 @@ package tls
import (
"context"
"strings"
"testing"
"time"
@@ -51,10 +50,19 @@ func TestApplyCertificateReturnsApplying(t *testing.T) {
})
require.NoError(t, err)
obtainDone := make(chan struct{})
restore := SetObtainCertificateFuncForTest(func(ctx context.Context, cert *model.TLSCertificate) error {
defer close(obtainDone)
return updateCertError(ctx, cert, "dns challenge failed")
})
defer restore()
defer func() {
select {
case <-obtainDone:
case <-time.After(2 * time.Second):
t.Fatal("async certificate obtain did not finish")
}
restore()
}()
cert, err := ApplyCertificate(ctx, ApplyInput{
Name: "Test ACME Cert",
@@ -126,7 +134,7 @@ func TestConvertCertificateToACMEPreservesUploadOnFailure(t *testing.T) {
assert.Equal(t, "error", finalCert.ApplyStatus)
assert.Equal(t, originalStoredCertPEM, finalCert.CertPEM)
assert.Equal(t, originalStoredKeyPEM, finalCert.KeyPEM)
assert.True(t, strings.Contains(finalCert.ApplyMessage, "dns challenge failed"))
assert.Contains(t, finalCert.ApplyMessage, "dns challenge failed")
}
func TestConvertCertificateToACMERejectsInvalidStates(t *testing.T) {
+14 -5
View File
@@ -197,12 +197,17 @@ func ApplyCertificate(ctx context.Context, input ApplyInput) (*model.TLSCertific
return nil, err
}
// 先取响应快照再启动异步续签:sanitize 会整体拷贝 cert,若与异步 goroutine
// 的字段写入并发会构成数据竞争(生产真实问题)。
returned := sanitizeCertificateForResponse(cert)
obtainFn := obtainTLSCertificate // 捕获当前实现,避免 goroutine 内读可变包变量(测试热替换)
go func(c *model.TLSCertificate) {
asyncCtx := context.WithoutCancel(ctx)
_ = obtainTLSCertificate(asyncCtx, c)
_ = obtainFn(asyncCtx, c)
}(cert)
return sanitizeCertificateForResponse(cert), nil
return returned, nil
}
// UpdateACMECertificate 更新 ACME 证书配置。
@@ -225,12 +230,15 @@ func UpdateACMECertificate(ctx context.Context, id uint, input ApplyInput) (*mod
return nil, err
}
returned := sanitizeCertificateForResponse(cert)
obtainFn := obtainTLSCertificate // 捕获当前实现,避免 goroutine 内读可变包变量(测试热替换)
go func(c *model.TLSCertificate) {
asyncCtx := context.WithoutCancel(ctx)
_ = obtainTLSCertificate(asyncCtx, c)
_ = obtainFn(asyncCtx, c)
}(cert)
return sanitizeCertificateForResponse(cert), nil
return returned, nil
}
// ConvertCertificateToACME 将上传证书转为 ACME 管理。
@@ -257,9 +265,10 @@ func ConvertCertificateToACME(ctx context.Context, id uint, input ApplyInput) (*
return nil, err
}
obtainFn := obtainTLSCertificate // 捕获当前实现,避免 goroutine 内读可变包变量(测试热替换)
go func(c *model.TLSCertificate) {
asyncCtx := context.WithoutCancel(ctx)
if err := obtainTLSCertificate(asyncCtx, c); err != nil {
if err := obtainFn(asyncCtx, c); err != nil {
return
}
latest, err := repository.GetTLSCertificateByID(asyncCtx, c.ID)
+1 -1
View File
@@ -123,7 +123,7 @@ func splitAcmeDomains(primaryDomain, otherDomains string) []string {
if !strings.Contains(otherDomains, "\n") && strings.Contains(otherDomains, ",") {
separator = ","
}
for _, domain := range strings.Split(otherDomains, separator) {
for domain := range strings.SplitSeq(otherDomains, separator) {
domain = strings.TrimSpace(domain)
if domain != "" {
domains = append(domains, domain)