Bumps [github.com/golangci/golangci-lint/v2](https://github.com/golangci/golangci-lint) from 2.9.0 to 2.11.4. - [Release notes](https://github.com/golangci/golangci-lint/releases) - [Changelog](https://github.com/golangci/golangci-lint/blob/main/CHANGELOG.md) - [Commits](https://github.com/golangci/golangci-lint/compare/v2.9.0...v2.11.4) --- updated-dependencies: - dependency-name: github.com/golangci/golangci-lint/v2 dependency-version: 2.11.4 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] <support@github.com>
13 KiB
Development
Table of Contents
- Local workflow
- Contributing: adding rules and analyzers
- AI-generated rule workflow (Copilot)
- AI-generated bug fix workflow (Copilot)
- AI-supported Go version update workflow (Copilot)
- Rule development utilities
- SARIF types generation
- Performance regression guard
- Generate TLS rule data
- Release
- Docker image
Local workflow
- Go version:
1.25+(seego.mod) - Build:
make - Run all checks used in CI (format, vet, security scan, vulnerability scan, tests):
make test - Run linter only:
make golangci
Contributing: adding rules and analyzers
gosec supports three implementation styles:
- AST rules (
gosec.Rule) for node-level checks inrules/ - SSA analyzers (
analysis.Analyzer) for whole-program context inanalyzers/ - Taint analyzers for source-to-sink data-flow checks in
analyzers/viataint.NewGosecAnalyzer
Add an AST rule
- Create a new file in
rules/(for example, userules/unsafe.goas a simple template). - Implement your rule constructor and
Matchlogic. - Register the rule in
rules/rulelist.go. - Add rule-to-CWE mapping in
issue/issue.go(and add CWE data incwe/data.goonly if needed). - Add tests and samples:
- sample code in
testutils/ - rule tests in
rules/or integration tests inanalyzer_test.go
- sample code in
Add an SSA analyzer
- Create a new file in
analyzers/. - Define the analyzer and require
buildssa.Analyzer. - Read SSA input using
ssautil.GetSSAResult(pass). - Return findings as
[]*issue.Issue. - Register in
analyzers/analyzerslist.go. - Add rule-to-CWE mapping in
issue/issue.go. - Add tests and sample code in
analyzers/andtestutils/.
Minimal skeleton:
package analyzers
import (
"fmt"
"golang.org/x/tools/go/analysis"
"golang.org/x/tools/go/analysis/passes/buildssa"
"github.com/securego/gosec/v2/internal/ssautil"
"github.com/securego/gosec/v2/issue"
)
func newMyAnalyzer(id, description string) *analysis.Analyzer {
return &analysis.Analyzer{
Name: id,
Doc: description,
Run: runMyAnalyzer,
Requires: []*analysis.Analyzer{buildssa.Analyzer},
}
}
func runMyAnalyzer(pass *analysis.Pass) (interface{}, error) {
ssaResult, err := ssautil.GetSSAResult(pass)
if err != nil {
return nil, fmt.Errorf("getting SSA result: %w", err)
}
_ = ssaResult
var issues []*issue.Issue
return issues, nil
}
Creating taint analysis rules
gosec taint analyzers track data flow from untrusted sources to dangerous sinks. Current taint rules include SQL injection, command injection, path traversal, SSRF, XSS, log injection, and SMTP injection.
Steps
- Create a new analyzer file in
analyzers/(for exampleanalyzers/newvuln.go) with both:- the taint
Config(sources, sinks, optional sanitizers) - the analyzer constructor that returns
taint.NewGosecAnalyzer(...)
- the taint
package analyzers
import (
"golang.org/x/tools/go/analysis"
"github.com/securego/gosec/v2/taint"
)
func NewVulnerability() taint.Config {
return taint.Config{
Sources: []taint.Source{
{Package: "net/http", Name: "Request", Pointer: true},
{Package: "os", Name: "Args", IsFunc: true},
},
Sinks: []taint.Sink{
{Package: "dangerous/package", Method: "DangerousFunc"},
},
}
}
func newNewVulnAnalyzer(id string, description string) *analysis.Analyzer {
config := NewVulnerability()
rule := NewVulnerabilityRule
rule.ID = id
rule.Description = description
return taint.NewGosecAnalyzer(&rule, &config)
}
- Register the analyzer in
analyzers/analyzerslist.go:
var defaultAnalyzers = []AnalyzerDefinition{
// ... existing analyzers ...
{"G7XX", "Description of vulnerability", newNewVulnAnalyzer},
}
-
Add sample programs in
testutils/g7xx_samples.go. -
Add the analyzer test in
analyzers/analyzers_test.go:
It("should detect your new vulnerability", func() {
runner("G7XX", testutils.SampleCodeG7XX)
})
Each taint analyzer keeps its configuration function in the same file as the analyzer. Reference implementations:
analyzers/sqlinjection.go(G701)analyzers/commandinjection.go(G702)analyzers/pathtraversal.go(G703)
Taint configuration reference
Sources
Sources define where untrusted data starts:
Package: import path (for example"net/http")Name: type or function name (for example"Request","Getenv")Pointer: settruefor pointer types (for example*http.Request)IsFunc: settruewhen the source is a function that returns tainted data
Sinks
Sinks define where tainted data must not reach:
PackageReceiver: method receiver type, empty for package functionsMethodPointer: whether receiver is a pointerCheckArgs: optional argument indexes to inspect; if omitted, all args are inspected
Example:
// For *sql.DB.Query, Args[1] is the query string.
{Package: "database/sql", Receiver: "DB", Method: "Query", Pointer: true, CheckArgs: []int{1}}
// Skip writer arg in fmt.Fprintf and check the rest.
{Package: "fmt", Method: "Fprintf", CheckArgs: []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}}
Sanitizers
Sanitizers break taint flow after validation/escaping:
PackageReceiverMethodPointer
If data passes through a configured sanitizer, it is treated as safe for subsequent sinks.
Common taint sources
| Source Type | Package | Type/Method | Pointer | IsFunc |
|---|---|---|---|---|
| HTTP Request | net/http |
Request |
true |
false |
| Command Line Args | os |
Args |
false |
true |
| Environment Variables | os |
Getenv |
false |
true |
| File Content | bufio |
Reader |
true |
false |
AI-generated rule workflow (Copilot)
This repository includes a reusable Copilot skill and prompt for creating new gosec rules from an issue description.
- Skill file:
.github/skills/gosec-new-rule/SKILL.md - Prompt file:
.github/prompts/create-gosec-rule.prompt.md
Use via /prompt (recommended)
- In VS Code Copilot Chat, run
/promptand select Create Gosec Rule. - Fill in the issue fields (
Summary, repro steps, versions, environment, expected, actual). - Submit the prompt.
- First response should only propose:
- rule ID
- implementation approach (SSA / taint / AST)
- relevance for Go
1.25and1.26 - confirmation request
- Reply with explicit confirmation (for example:
Confirmed. Proceed with implementation.).
Use the skill directly (without /prompt)
Send this in Copilot Chat:
Use the skill "Create New Gosec Rule" from .github/skills/gosec-new-rule/SKILL.md.
Then paste the same issue template fields and confirm after the proposal step.
If /prompt does not list the prompt
- Ensure the workspace root is this repository.
- Confirm the file exists at
.github/prompts/create-gosec-rule.prompt.md. - Reload VS Code window and start a new chat session.
- As fallback, open the prompt file and send its content directly in chat.
AI-generated bug fix workflow (Copilot)
This repository also includes a Copilot skill and prompt for fixing bugs described in GitHub issues.
- Skill file:
.github/skills/gosec-fix-issue/SKILL.md - Prompt file:
.github/prompts/fix-gosec-bug-from-issue.prompt.md
Use via /prompt (recommended)
- In VS Code Copilot Chat, run
/promptand select Fix Gosec Bug From Issue. - Fill in at least the
GitHub issue URLfield (other fields are optional but useful). - Submit the prompt.
- First response should only include:
- reproduction status on
master(or clear blocker) - root cause analysis
- detailed fix plan
- confirmation request
- reproduction status on
- Reply with explicit confirmation (for example:
Confirmed. Proceed with fix.).
Use the skill directly (without /prompt)
Send this in Copilot Chat:
Use the skill "Fix Gosec Bug From Issue" from .github/skills/gosec-fix-issue/SKILL.md.
Then provide the GitHub issue URL and confirm after the analysis and plan step.
Expected implementation guardrails
After confirmation, the workflow should:
- keep the fix small and isolated to the problem
- use idiomatic Go and good design
- add positive and negative tests
- add or update
testutils/code samples when appropriate for reproducing/validating the issue - validate with build, tests,
golangci-lint, and agosecCLI run against a sample
AI-supported Go version update workflow (Copilot)
This repository includes a Copilot skill and prompt to update supported Go versions to the latest patch versions of the two newest major Go series.
- Skill file:
.github/skills/gosec-update-go-versions/SKILL.md - Prompt file:
.github/prompts/update-supported-go-versions.prompt.md
Use via /prompt (recommended)
- In VS Code Copilot Chat, run
/promptand select Update Supported Go Versions. - Submit the prompt (no additional fields required).
- The workflow should:
- read
https://go.dev/doc/devel/release - detect latest two supported Go series and latest patch for each
- update all active repository locations where supported Go versions are configured or documented
- run validation checks
- create branch, commit, push, and open a PR
- read
Use the skill directly (without /prompt)
Send this in Copilot Chat:
Use the skill "Update Supported Go Versions" from .github/skills/gosec-update-go-versions/SKILL.md.
Expected outputs
The result should include:
- detected versions (
previous_patch,latest_patch,previous_minor,latest_minor) - grouped file update summary
- test command result
- branch, commit SHA, PR title, and PR URL
Rule development utilities
Use these tools while building or debugging rules:
- Dump SSA with
ssadump:
ssadump -build F main.go
- Inspect AST/types/defs/imports with
gosecutil:
gosecutil -tool ast main.go
Valid -tool values: ast, callobj, uses, types, defs, comments, imports.
SARIF types generation
Install schema-generate:
go install github.com/a-h/generate/cmd/schema-generate@latest
Generate types:
schema-generate -i sarif-schema-2.1.0.json -o path/to/types.go
Most MarshalJSON/UnmarshalJSON helpers can be removed after generation, except PropertyBag where inlined additional properties are useful.
Performance regression guard
CI includes a taint benchmark guard based on BenchmarkTaintPackageAnalyzers_SharedCache.
- Baseline and thresholds:
.github/benchmarks/taint_benchmark_baseline.env - Guard script:
tools/check_taint_benchmark.sh
Run locally:
bash tools/check_taint_benchmark.sh
Update baseline after intentional changes:
BENCH_COUNT=10 bash tools/check_taint_benchmark.sh --update-baseline
If you update the baseline, commit both the benchmark-related code and the baseline file.
Generate TLS rule data
The TLS rule data is generated from Mozilla recommendations.
From the repository root:
go generate ./...
If go generate fails with exec: "tlsconfig": executable file not found in $PATH, install the local generator and add $(go env GOPATH)/bin to PATH:
export PATH="$(go env GOPATH)/bin:$PATH"
go install ./cmd/tlsconfig
go generate ./...
This updates rules/tls_config.go.
If you need to install the generator binary outside this repository:
go install github.com/securego/gosec/v2/cmd/tlsconfig@latest
Release
Tag and push:
git tag v1.0.0 -m "Release version v1.0.0"
git push origin v1.0.0
The release workflow builds binaries and Docker images, then signs artifacts.
Verify signatures:
cosign verify --key cosign.pub ghcr.io/securego/gosec:<TAG>
cosign verify-blob --key cosign.pub --signature gosec_<VERSION>_darwin_amd64.tar.gz.sig gosec_<VERSION>_darwin_amd64.tar.gz
Docker image
Build locally:
make image
Run against a local project:
docker run --rm -it -w /<PROJECT>/ -v <YOUR_PROJECT_PATH>/<PROJECT>:/<PROJECT> ghcr.io/securego/gosec:latest /<PROJECT>/...
Set -w so module dependencies resolve from the mounted project root.