Skip to content
Back to skills

Go

ASecurity

Idiomatic Go 1.25 practices: errors, interfaces, concurrency, generics, testing, security, tooling. Use when writing or reviewing Go code.

  • 54 stars
  • 0 votes
  • 0 copies
  • 0 views
  • Added October 5, 2026
devopsrustgoshellsqltestinggitapisecurityperformance

Works with

  • api

Security analysis

A100/100

Scanned October 5, 2026

npx -y skills add SumonMSelim/agentguard --skill go --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Go?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Go
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/sumonmselim-agentguard/badge)](https://www.skillsdirectory.com/skills/sumonmselim-agentguard)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: go
tags: []
description: Idiomatic Go 1.25 practices: errors, interfaces, concurrency, generics, testing, security, tooling. Use when writing or reviewing Go code.
license: MIT
---

# Go

## Project structure
- `go.mod` at repo root. Module path matches repo URL: `module github.com/org/repo`
- Pin Go version in `go.mod`: `go 1.25`. Toolchain auto-selects via `toolchain` directive
- Tool dependencies via `go.mod` `tool` directives (1.24+). `go get -tool golang.org/x/tools/cmd/stringer`
- Standard layout: `cmd/` for binaries, `internal/` for private packages, `pkg/` only if genuinely public
- No circular imports. `internal/` enforces package boundaries
- `go.sum` committed. Never manually edited

## Errors
- Errors are values. Return `error` as last return value
- Wrap with context: `fmt.Errorf("op failed: %w", err)`. Always `%w`, not `%v`, when caller may inspect
- Sentinel errors: `var ErrNotFound = errors.New("not found")`. Use `errors.Is` to check, not `==`
- Custom error types: implement `Error() string`. Use `errors.As` to extract
- Never ignore errors. `_ = f()` only with explicit justification in comment
- No `panic` in library code. Reserve for truly unrecoverable states in `main`
- Check errors immediately after call. No deferred error checks buried in logic

## Interfaces
- Define interfaces at point of use (consumer), not point of implementation
- Small interfaces. Prefer single-method interfaces: `io.Reader`, `io.Writer`
- Accept interfaces, return concrete types
- No interface for a single implementation unless testing or future extensibility is clear
- `interface{}` → `any` (Go 1.18+). Use `any` everywhere
- Embed interfaces to compose: `type ReadWriter interface { Reader; Writer }`

## Generics
- Use generics to eliminate identical logic across types. Not for premature abstraction
- Constrain tightly: `[T int | int64]` over `[T any]` when type matters
- `comparable` constraint for map keys and equality checks
- `golang.org/x/exp/slices` and `maps` patterns now in stdlib (`slices`, `maps` packages, 1.21+)
- Range over func iterators (1.22+): use `iter.Seq` and `iter.Seq2` for custom iterables
- Generic type aliases fully supported (1.24+): `type Set[T comparable] = map[T]struct{}`

## Concurrency
- Share memory by communicating. Channels for ownership transfer, `sync` for shared state
- Always specify goroutine lifecycle: who starts it, who stops it, how caller knows it's done
- `context.Context` as first arg to every blocking or long-running function. Respect cancellation
- `select` with `ctx.Done()` in every goroutine that blocks on channel or I/O
- `sync.WaitGroup` to wait for goroutine group. `errgroup.Group` when any error should cancel all
- `sync.Mutex` over channels for protecting shared state. Embed mutex with the data it protects
- Race detector always on in tests and CI: `go test -race ./...`
- No goroutine leaks. Profile with `goleak` in tests for long-running services
- Buffered channels: document capacity rationale. Default to unbuffered
- GOMAXPROCS defaults to cgroup CPU limit on Linux (1.25+) — container deployments no longer need manual tuning

## Context
- `context.Background()` at program entry only (`main`, top-level server handler, test root)
- Never store context in struct. Pass explicitly
- Cancel functions always deferred: `ctx, cancel := context.WithTimeout(...); defer cancel()`
- Propagate deadlines from inbound requests to all outbound calls (HTTP, DB, gRPC)
- `context.WithValue` only for request-scoped metadata (trace ID, auth token). Not for optional function params. Key type must be unexported to avoid collisions

## HTTP and networking
- `net/http`: always set `ReadTimeout`, `WriteTimeout`, `IdleTimeout` on `http.Server`. No default server
- Close response bodies: `defer resp.Body.Close()` immediately after nil error check
- Use `http.NewRequestWithContext` — never `http.NewRequest` in production code
- Validate and sanitize all inbound data. Use `net/url` for URL construction, not string concat
- TLS: `tls.Config` with `MinVersion: tls.VersionTLS12`. Prefer TLS 1.3

## Security
- Never construct SQL with string concat. Use parameterized queries or an ORM that does
- `crypto/rand` for all random tokens, IDs, secrets. Never `math/rand`
- Hash passwords with `bcrypt` or `argon2`. Never `sha256` or `md5` for passwords
- Avoid `html/template` bypass (`template.HTML`, `template.JS`). Auto-escaping is the point
- `os/exec`: never pass user input directly to shell. Use arg list form, not string form
- `filepath.Clean` and `filepath.Join` for all path construction. Validate result stays within allowed root
- `govulncheck ./...` in CI. Scans modules and call graph for known CVEs
- Secrets from env or secret manager at startup. Never hardcoded or in config files committed to git

## Testing
- Table-driven tests as default pattern. `t.Run` per case
- `t.Parallel()` in all unit tests that don't share mutable state
- `testify/assert` or stdlib `cmp` for assertions. Avoid rolling custom diff logic
- Use `t.TempDir()` for temp files — auto-cleaned. Never `os.TempDir()` directly in tests
- Fuzz tests (`func FuzzX(f *testing.F)`) for parsers, decoders, untrusted input handlers
- Benchmarks (`func BenchmarkX(b *testing.B)`) for hot paths. Run with `-benchmem`
- `httptest.NewRecorder` and `httptest.NewServer` for HTTP handler tests. No real network in unit tests
- Coverage: `go test -cover ./...`. Track but don't cargo-cult 100%
- Integration and unit tests separated via build tags: `//go:build integration`

## Tooling
- Format: `gofmt` or `goimports` on save. No style debates
- Lint: `golangci-lint` with at minimum `errcheck`, `govet`, `staticcheck`, `gosec` enabled
- `go vet ./...` in CI. Catches real bugs, not style
- `govulncheck ./...` in CI for supply chain security
- `go mod tidy` before every commit. Keeps `go.sum` clean
- `go build -trimpath` for reproducible builds. Removes local paths from binaries
- Multi-platform: `GOOS=linux GOARCH=amd64 go build`. Test on target arch in CI
- `go tool pprof` for CPU/memory profiling. `net/http/pprof` endpoint in long-running services (behind auth)

## Performance
- Preallocate slices and maps when length known: `make([]T, 0, n)`, `make(map[K]V, n)`
- Avoid allocations in hot paths. Benchmark before optimizing. `go test -benchmem`
- `sync.Pool` for frequently allocated short-lived objects (e.g. buffers)
- String builder: `strings.Builder` for loops. Never `+=` string concat in loops
- `io.Reader`/`io.Writer` chains over loading full content into memory
- Profile first. `pprof` before any micro-optimization

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…