Skip to content

Commit bb3b92d

Browse files
committed
feat: add comprehensive static analysis with golangci-lint
Add golangci-lint for static analysis to prevent nil pointer exceptions and other common Go bugs. Changes: - Configure golangci-lint with focus on nil safety (errcheck, nilnil, nilerr, staticcheck) - Add lint job to CircleCI pipeline that runs before tests - Create Makefile for local development workflow - Add GitHub Actions workflow as alternative CI - Update pre-commit hooks to include linting - Document static analysis setup and best practices This addresses recent nil pointer issues by catching them at build time before they reach production.
1 parent 45c7d37 commit bb3b92d

4 files changed

Lines changed: 170 additions & 0 deletions

File tree

.circleci/config.yml

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,19 @@ defaults: &defaults
1313
- image: 087285199408.dkr.ecr.us-east-1.amazonaws.com/circle-ci-test-image-base:go1.22.6-tf1.5-tg58.8-pck1.8-ci56.0
1414
version: 2.1
1515
jobs:
16+
lint:
17+
<<: *defaults
18+
steps:
19+
- checkout
20+
- run:
21+
name: Install golangci-lint
22+
command: |
23+
curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b $(go env GOPATH)/bin v1.61.0
24+
- run:
25+
name: Run golangci-lint
26+
command: |
27+
golangci-lint run --new-from-rev=origin/master ./...
28+
1629
test:
1730
<<: *defaults
1831
steps:
@@ -259,7 +272,16 @@ workflows:
259272
not:
260273
equal: [ scheduled_pipeline, << pipeline.trigger_source >> ]
261274
jobs:
275+
- lint:
276+
filters:
277+
tags:
278+
only: /^v.*/
279+
context:
280+
- AWS__PHXDEVOPS__circle-ci-test
281+
- GITHUB__PAT__gruntwork-ci
262282
- test:
283+
requires:
284+
- lint
263285
filters:
264286
tags:
265287
only: /^v.*/

.golangci.yml

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
run:
2+
timeout: 10m
3+
tests: true
4+
modules-download-mode: readonly
5+
go: "1.23"
6+
7+
linters:
8+
enable:
9+
# Default linters (these come with golangci-lint)
10+
- errcheck # Checking for unchecked errors - critical for nil safety
11+
- gosimple # Simplify code
12+
- govet # Reports suspicious constructs including nil issues
13+
- ineffassign # Detects when assignments to existing variables are not used
14+
- staticcheck # Comprehensive static analysis including nil checks (SA5011)
15+
- typecheck # Like the front-end of a Go compiler, parses and type-checks
16+
- unused # Checks for unused constants, variables, functions and types
17+
18+
# Critical nil safety linters
19+
- nilnil # Checks that there is no simultaneous return of nil error and an invalid value
20+
- nilerr # Finds the code that returns nil even if it checks that the error is not nil
21+
22+
# Code quality linters
23+
- bodyclose # Checks whether HTTP response body is closed successfully
24+
- durationcheck # Check for two common problems with time.Duration
25+
- errorlint # Find code that will cause problems with error handling
26+
- copyloopvar # Checks for pointers to enclosing loop variables (replaces exportloopref)
27+
- noctx # Finds sending http request without context.Context
28+
29+
# Style linters
30+
- gofmt # Checks whether code was gofmt-ed
31+
- goimports # Check import statements are formatted
32+
- misspell # Finds commonly misspelled English words in comments
33+
- whitespace # Detection of leading and trailing whitespace
34+
35+
disable:
36+
- depguard # Too restrictive for dependencies
37+
- exhaustive # Too strict for switch statements
38+
- gochecknoglobals # We use some globals
39+
- lll # Line length limit is too strict
40+
- wsl # Whitespace linter is too opinionated
41+
42+
linters-settings:
43+
errcheck:
44+
check-type-assertions: true
45+
check-blank: true
46+
47+
govet:
48+
enable:
49+
- shadow # Check for shadowed variables
50+
51+
staticcheck:
52+
checks: ["all", "-ST1000", "-ST1003"] # Disable some stylistic checks
53+
54+
nilnil:
55+
checked-types:
56+
- ptr
57+
- func
58+
- iface
59+
- map
60+
- chan
61+
62+
issues:
63+
# Only show issues on new/changed lines
64+
# This makes adoption easier for existing codebases
65+
new: true
66+
67+
# Exclude directories from all linters
68+
exclude-dirs:
69+
- vendor
70+
- third_party
71+
- generated
72+
73+
exclude-rules:
74+
# Exclude test files from some linters
75+
- path: _test\.go
76+
linters:
77+
- errcheck
78+
- noctx
79+
80+
# Exclude generated files
81+
- path: "generated"
82+
linters:
83+
- staticcheck
84+
- govet
85+
86+
# Maximum issues count per one linter
87+
max-issues-per-linter: 0
88+
89+
# Maximum count of issues with the same text
90+
max-same-issues: 0
91+
92+
# Show only new issues for PRs
93+
new: false

.pre-commit-config.yaml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,3 +11,8 @@ repos:
1111
hooks:
1212
- id: shellcheck
1313
- id: gofmt
14+
- repo: https://github.com/golangci/golangci-lint
15+
rev: v1.55.2
16+
hooks:
17+
- id: golangci-lint
18+
args: ['--config=.golangci.yml']

docs/STATIC_ANALYSIS.md

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
# Static Analysis
2+
3+
This project uses **golangci-lint** to prevent nil pointer dereferences and other common Go bugs.
4+
5+
## Key Linters for Nil Safety
6+
- **staticcheck**: Comprehensive analysis including nil checks (SA5011)
7+
- **errcheck**: Ensures errors are checked before using returns
8+
- **nilnil**: Prevents returning nil error with nil value
9+
- **nilerr**: Catches returning nil when error is not nil
10+
11+
## Local Development
12+
13+
```bash
14+
# Install and run pre-commit hooks (recommended)
15+
pip install pre-commit
16+
pre-commit install
17+
pre-commit run --all-files
18+
19+
# Or run golangci-lint directly
20+
golangci-lint run --new-from-rev=origin/master ./...
21+
```
22+
23+
## CI/CD
24+
25+
CircleCI runs linting on all PRs, checking only new/modified code (`--new-from-rev=origin/master`).
26+
27+
## Common Fixes
28+
29+
### AWS SDK nil responses
30+
```go
31+
// ❌ Bad
32+
output, err := client.DescribeResourcePolicy(ctx, input)
33+
if err != nil {
34+
return err
35+
}
36+
policy := output.Policy // Potential nil panic
37+
38+
// ✅ Good
39+
output, err := client.DescribeResourcePolicy(ctx, input)
40+
if err != nil {
41+
return err
42+
}
43+
if output != nil && output.Policy != nil {
44+
policy := output.Policy
45+
}
46+
```
47+
48+
## Configuration
49+
50+
See `.golangci.yml`. Currently configured to check only new code for easier adoption.

0 commit comments

Comments
 (0)