lint/catalog/go-correctness.yaml
Snider bc159163e8 feat: seed catalog with 18 patterns from ecosystem sweep
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-09 10:59:33 +00:00

122 lines
3.8 KiB
YAML

- id: go-cor-001
title: "Goroutine launched without synchronisation"
severity: medium
languages: [go]
tags: [correctness, concurrency]
pattern: 'go\s+func\s*\('
exclude_pattern: 'wg\.|\.Go\(|context\.|done\s*<-|select\s*\{'
fix: "Use a WaitGroup, errgroup, or context cancellation to track goroutine lifecycle"
found_in: [go-process]
example_bad: 'go func() { doWork() }()'
example_good: 'wg.Add(1); go func() { defer wg.Done(); doWork() }()'
first_seen: "2026-03-09"
detection: regex
auto_fixable: false
- id: go-cor-002
title: "WaitGroup.Wait without timeout or context"
severity: low
languages: [go]
tags: [correctness, concurrency]
pattern: '\.Wait\(\)'
exclude_pattern: 'select\s*\{|ctx\.Done|context\.With|time\.After'
fix: "Wrap Wait() in a select with context.Done() or time.After() to prevent indefinite blocking"
found_in: [go-process]
example_bad: 'wg.Wait()'
example_good: |
done := make(chan struct{})
go func() { wg.Wait(); close(done) }()
select {
case <-done:
case <-ctx.Done():
}
first_seen: "2026-03-09"
detection: regex
auto_fixable: false
- id: go-cor-003
title: "Silent error swallowing with blank identifier"
severity: medium
languages: [go]
tags: [correctness, errors]
pattern: '^\s*_\s*=\s*\w+\.\w+\('
exclude_pattern: 'defer|Close\(|Flush\('
fix: "Handle the error explicitly — log it, return it, or document why it is safe to discard"
found_in: [go-store, go-cache]
example_bad: '_ = service.Process(data)'
example_good: |
if err := service.Process(data); err != nil {
return fmt.Errorf("processing: %w", err)
}
first_seen: "2026-03-09"
detection: regex
auto_fixable: false
- id: go-cor-004
title: "Panic in library code"
severity: high
languages: [go]
tags: [correctness, panic]
pattern: '\bpanic\('
exclude_pattern: '_test\.go|// unreachable|Must\w+\('
fix: "Return an error instead of panicking — panics in libraries crash the caller"
found_in: [go-io, go-config]
example_bad: 'panic("unexpected state")'
example_good: 'return fmt.Errorf("unexpected state: %v", state)'
first_seen: "2026-03-09"
detection: regex
auto_fixable: false
- id: go-cor-005
title: "File deletion without path validation"
severity: high
languages: [go]
tags: [correctness, filesystem]
pattern: 'os\.Remove(All)?\('
exclude_pattern: 'filepath\.Clean|ValidatePath|strings\.Contains.*\.\.'
fix: "Validate the path before deletion to prevent removing unintended files or directories"
found_in: [go-io]
example_bad: 'os.RemoveAll(userProvidedPath)'
example_good: |
cleanPath := filepath.Clean(userProvidedPath)
if !strings.HasPrefix(cleanPath, safeBase) {
return fmt.Errorf("path outside safe directory")
}
os.RemoveAll(cleanPath)
first_seen: "2026-03-09"
detection: regex
auto_fixable: false
- id: go-cor-006
title: "HTTP response error discarded"
severity: high
languages: [go]
tags: [correctness, errors, http]
pattern: 'resp,\s*_\s*:=.*\.(Get|Post|Do|Send)\('
fix: "Always check the error from HTTP calls — network failures are common"
found_in: [go-api]
example_bad: 'resp, _ := http.Get(url)'
example_good: |
resp, err := http.Get(url)
if err != nil {
return fmt.Errorf("fetching %s: %w", url, err)
}
defer resp.Body.Close()
first_seen: "2026-03-09"
detection: regex
auto_fixable: false
- id: go-cor-007
title: "Wrong signal type (syscall.Signal instead of os.Signal)"
severity: low
languages: [go]
tags: [correctness, portability]
pattern: 'syscall\.Signal\b'
exclude_pattern: 'os\.Signal'
fix: "Use os.Signal for portable signal handling across platforms"
found_in: [go-process]
example_bad: 'ch := make(chan syscall.Signal, 1)'
example_good: 'ch := make(chan os.Signal, 1)'
first_seen: "2026-03-09"
detection: regex
auto_fixable: true