fix: suppress gosec G115/G118 false positive warnings

- G115 (integer overflow): Added nosec comments for safe type conversions
  where values are bounded by design (e.g., rng.Intn(255) returns 0-254)
- G118 (context.Background): Added nosec for intentional async goroutines
  that use WithTimeout for bounded execution after request completes

Note: G101 (hardcoded credentials) warnings are low-confidence false
positives - OAuth fields use getEnv() to read from environment.
This commit is contained in:
2026-04-08 22:50:42 +08:00
parent 3b0bcf0ff7
commit 12a5be9826
11 changed files with 46 additions and 32 deletions

View File

@@ -479,8 +479,8 @@ func (s *AuthService) writeLoginLog(
FailReason: failReason,
}
go func() {
// 使用带超时的独立 context防止日志写入无限等待
// #nosec G118 - 使用带超时的独立 context防止日志写入无限等待
go func() { // #nosec G118
bgCtx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
if err := s.loginLogRepo.Create(bgCtx, loginRecord); err != nil {

View File

@@ -89,8 +89,8 @@ func (s *AuthService) RegisterWithActivation(ctx context.Context, req *RegisterR
if nickname == "" {
nickname = req.Username
}
// 使用独立上下文避免请求结束后被取消
go func() {
// #nosec G118 - 使用独立上下文避免请求结束后被取消
go func() { // #nosec G118
bgCtx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
defer cancel()
if err := s.emailActivationSvc.SendActivationEmail(bgCtx, user.ID, req.Email, nickname); err != nil {

View File

@@ -162,10 +162,11 @@ func (s *CaptchaService) renderImage(text string) ([]byte, error) {
// 随机背景色(浅色)
rng := rand.New(rand.NewSource(time.Now().UnixNano()))
// #nosec G115 - rng.Intn(35) returns 0-34, so 220+34=254 fits in uint8
bgColor := color.RGBA{
R: uint8(220 + rng.Intn(35)),
G: uint8(220 + rng.Intn(35)),
B: uint8(220 + rng.Intn(35)),
G: uint8(220 + rng.Intn(35)), // #nosec G115
B: uint8(220 + rng.Intn(35)), // #nosec G115
A: 255,
}
draw.Draw(img, img.Bounds(), &image.Uniform{bgColor}, image.Point{}, draw.Src)
@@ -173,9 +174,9 @@ func (s *CaptchaService) renderImage(text string) ([]byte, error) {
// 绘制干扰线
for i := 0; i < 5; i++ {
lineColor := color.RGBA{
R: uint8(rng.Intn(200)),
G: uint8(rng.Intn(200)),
B: uint8(rng.Intn(200)),
R: uint8(rng.Intn(200)), // #nosec G115
G: uint8(rng.Intn(200)), // #nosec G115
B: uint8(rng.Intn(200)), // #nosec G115
A: 255,
}
x1 := rng.Intn(captchaWidth)
@@ -187,25 +188,28 @@ func (s *CaptchaService) renderImage(text string) ([]byte, error) {
// 绘制文字(使用像素字体)
for i, ch := range text {
// #nosec G115 - rng.Intn(150) returns 0-149, fits in uint8
charColor := color.RGBA{
R: uint8(rng.Intn(150)),
G: uint8(rng.Intn(150)),
B: uint8(rng.Intn(150)),
R: uint8(rng.Intn(150)), // #nosec G115
G: uint8(rng.Intn(150)), // #nosec G115
B: uint8(rng.Intn(150)), // #nosec G115
A: 255,
}
x := 10 + i*25 + rng.Intn(5)
y := 8 + rng.Intn(12)
// #nosec G115 - ch is ASCII text character, byte() truncation is intentional
drawChar(img, x, y, byte(ch), charColor)
}
// 绘制干扰点
for i := 0; i < 80; i++ {
dotColor := color.RGBA{
R: uint8(rng.Intn(255)),
G: uint8(rng.Intn(255)),
B: uint8(rng.Intn(255)),
A: uint8(100 + rng.Intn(100)),
}
// #nosec G115 - Intn(255) returns 0-254, Intn(100) returns 0-99, both fit in uint8
dotColor := color.RGBA{
R: uint8(rng.Intn(255)), // #nosec G115
G: uint8(rng.Intn(255)), // #nosec G115
B: uint8(rng.Intn(255)), // #nosec G115
A: uint8(100 + rng.Intn(100)), // #nosec G115
}
img.Set(rng.Intn(captchaWidth), rng.Intn(captchaHeight), dotColor)
}

View File

@@ -291,8 +291,8 @@ func (s *PasswordResetService) doResetPassword(ctx context.Context, user *domain
// 写入密码历史记录
if s.passwordHistoryRepo != nil {
go func() {
// 使用带超时的独立 context防止 DB 写入无限等待
// #nosec G118 - 使用带超时的独立 context防止 DB 写入无限等待
go func() { // #nosec G118
bgCtx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
_ = s.passwordHistoryRepo.Create(bgCtx, &domain.PasswordHistory{

View File

@@ -82,8 +82,8 @@ func (s *UserService) ChangePassword(ctx context.Context, userID int64, oldPassw
return errors.New("密码哈希失败")
}
go func() {
// 使用带超时的独立 context不能使用请求 ctx该 goroutine 在请求完成后仍可能运行)
// #nosec G118 - 使用带超时的独立 context不能使用请求 ctx该 goroutine 在请求完成后仍可能运行)
go func() { // #nosec G118
bgCtx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
_ = s.passwordHistoryRepo.Create(bgCtx, &domain.PasswordHistory{

View File

@@ -265,7 +265,8 @@ func (s *WebhookService) handleFailure(task *deliveryTask, statusCode int, body,
if s.config.RetryBackoff == "fixed" {
backoff = 2 * time.Second
} else {
backoff = time.Duration(1<<uint(task.attempt)) * time.Second
// #nosec G115 - attempt is bounded by MaxRetries (default 3), so shift is safe
backoff = time.Duration(1<<uint(task.attempt)) * time.Second // #nosec G115
}
time.AfterFunc(backoff, func() {
task.attempt++