Dependencies
| Field | Value |
|---|---|
| Type | Skill Resource |
| Source | ~/.copilot/skills/backend/references/dependencies.md |
| Description | Not specified |
Source Content
Dependencies
A third-party dependency is a maintenance and security liability accepted deliberately, not added reflexively. Every module in go.mod is code your team now ships, patches, and answers for as if you’d written it yourselves — even though you didn’t.
Ask before adding a new one
Upgrading an existing dependency needs no check-in — that’s routine maintenance. Pulling in a new module, especially a new direct dependency, is different: the whole team now transitively trusts its code, its maintainers, and its own dependency tree. Ask before adding a genuinely new third-party dependency to go.mod. A quick “I want to pull in X for Y, alternatives considered were Z” is enough; it just has to happen before the go get, not after.
The tool directive replaces tools.go (Go 1.24+)
Pinning the version of a build-time tool — oapi-codegen (references/openapi.md), golangci-lint — used to mean a tools.go file with a //go:build tools tag and a blank import per tool, purely to convince go mod tidy not to prune it. Go 1.24+ replaces that hack with a first-class tool directive in go.mod.
go get -tool github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen// go.mod (excerpt)tool ( github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen github.com/golangci/golangci-lint/v2/cmd/golangci-lint)Run a pinned tool with go tool <name> — no tools.go, no blank import, no separate build tag to keep in sync.
govulncheck narrows to reachable CVEs
Run govulncheck ./... in CI. Its distinguishing feature over a blanket scanner is that it walks your binary’s actual call graph and reports only the CVEs whose vulnerable function your code can actually reach — not every CVE that exists anywhere in your transitive dependency tree regardless of whether you ever call the affected code.
govulncheck ./...This is why a CVE can show up in a general-purpose dependency scanner and stay silent in govulncheck: the vulnerable function is in a code path you never call. Cite this when a reviewer flags a scanner alert that govulncheck doesn’t — it isn’t being lax, it’s telling you the exposure doesn’t reach your binary.
go.work for local multi-module development
When developing this service alongside a shared internal library in a sibling checkout, go.work lets local edits in the library be picked up without a replace directive in go.mod or a round-trip through a tagged release.
go work init ./billing ./internal-lib- Never commit
go.work.sum— it’s a local development artifact, not part of the module’s published dependency graph. - Strip any
replacedirective before publishing or tagging a release; areplacepointing at a local filesystem path breaks the module for every downstream consumer.
CI auto-merge policy for dependency bumps
Automated dependency bumps (Dependabot, Renovate) do not all carry the same risk, so they don’t all get the same review gate:
- Patch and minor version bumps auto-merge once CI passes green.
- Major version bumps always require manual review — a major bump can change behavior or break an API this service depends on.
- Security-patch bumps auto-merge regardless of version-bump size — a security fix waiting on manual review is a window left open on purpose.