go-ci について
go-ci は Go プロジェクトのメンテナー向けに、ビルド、vet と lint、競合検出付きテスト、脆弱性スキャンからなる CI パイプラインを解説するスキルです。GitHub Actions の設定、ローカル検査との整合、リポジトリのセキュリティ対策も扱います。
主な機能
- 01CI の4つの基本ゲート
- 02GitHub Actions ワークフローの指針
- 03golangci-lint の設定
- 04競合テストとカバレッジゲート
- 05セキュリティスキャンと依存更新
活用シーン
- 01Go CI パイプラインの構築
- 02ローカル検査と CI の整合
- 03競合・カバレッジ検査の追加
- 04リポジトリ自動化の強化
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ eduardo-sl/ go-agent-skills --skill go-ciインストール後、Claude Code で/go-ciを入力して読み込まれたか確認します。
同梱ファイルreferences/security-and-automation.md
詳細
Go CI
Go パイプラインのゲートは、ビルド、vet/lint、race detector を使ったテスト、脆弱性スキャンの4つだけです。それ以外はすべて最適化です。
詳細な参考資料は、必要に応じて読み込みます。
references/security-and-automation.md— CodeQL と gosec の SARIF、Dependabot の設定、SHA ピン留め、リポジトリの強化、Trivy、AI レビューのワークフロー。
以下の概要だけでは不十分な場合にのみ、参考ファイルを読んでください。
1. GitHub Actions の基本ワークフロー
name: ci
on:
push:
branches: [main]
pull_request:
permissions:
contents: read
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v7
- uses: actions/setup-go@v7
with:
go-version-file: go.mod # single source of truth
cache: true # caches module + build cache
- run: go build ./...
- run: go vet ./...
- run: go test -race -shuffle=on -coverprofile=coverage.out ./...
lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v7
- uses: actions/setup-go@v7
with:
go-version-file: go.mod
- uses: golangci/golangci-lint-action@v9 # v7+ runs golangci-lint v2
with:
version: v2.6 # pin a minor; v2.6+ has `modernize`
vuln:
runs-on: ubuntu-latest
steps:
- uses: golang/govulncheck-action@v1
with:
go-version-file: go.mod
アクションのメジャーバージョンは年に数回更新されます。上記のバージョンはスナップショットとして扱い、手動で編集するのではなく、Dependabot の github-actions エコシステムで最新の状態を維持してください。
主な判断事項は次のとおりです。
go-version-file: go.mod— Go のバージョンを2か所にハードコードしないでください。- setup-go の
cache: trueでモジュールキャッシュとビルドキャッシュが処理されます。これに加えて Go 用の手動actions/cacheステップを追加しないでください。 -race -shuffle=on— データ競合や実行順序に依存するテストは、本番環境ではなく CI で失敗するようにします。permissions: contents: read— デフォルトで最小権限にします。- lint は別ジョブにします — 早期に失敗し、テストと並列実行できます。
2. golangci-lint の設定
.golangci.yml をコミットしてください。設定されていないリンターはノイズになります。
version: "2" # required: golangci-lint v2 rejects v1 files
linters:
default: standard # errcheck, govet, ineffassign, staticcheck, unused
enable:
- errorlint # %w misuse, == on errors
- gosec # security patterns
- revive # style, replaces golint
- misspell
exclusions:
rules:
- path: _test\.go
linters: [gosec] # test code may use weak randomness etc.
golangci-lint v2 では除外設定が issues.exclude-rules から
linters.exclusions.rules に移動し、version キーが必須になりました。v1 のファイルは読み込みに失敗しますが、golangci-lint migrate を実行するとその場で変換できます。
この小さな設定から始め、リンターは慎重に追加してください。すべてを有効にすると、誰も対応しない何百もの指摘が発生します。nolint ディレクティブには理由が必要です。例://nolint:gosec // G404: jitter, not crypto
3. ビルドマトリックス — リリースする場合のみ
strategy:
matrix:
go: [oldstable, stable] # the two releases the Go team supports
os: [ubuntu-latest, macos-latest, windows-latest]
ライブラリ:サポート対象の Go リリース2つでテストします。setup-go は実行時に
stable/oldstable を解決するため、マトリックスが古くなりません。
Linux にデプロイするサービスでは OS マトリックスを省略します — リリースしないプラットフォームまでテストするとコストが倍になります。エミュレーションよりクロスコンパイルのほうが低コストです。
GOOS=windows go build ./... で、ほとんどの移植性の問題を検出できます。
4. カバレッジのゲート
- run: go test -race -coverprofile=coverage.out ./...
- name: enforce coverage floor
run: |
total=$(go tool cover -func=coverage.out | awk '/^total:/ {sub(/%/,"",$3); print $3}')
echo "coverage: ${total}%"
awk -v t="$total" 'BEGIN { exit (t < 70.0) }'
不正に利用されやすい目標値ではなく、段階的に引き上げる下限値をゲートに設定してください。生成コードは下限値を下げて除外するのではなく、//go:generate で生成されるファイルのビルドタグや grep フィルターで除外します。
5. Makefile — CI をローカルで再現
CI では開発者が実行するものと同じ処理を実行する必要があります。定義は1つ、呼び出し元は2つです。
.PHONY: build lint test vuln ci
build:
go build ./...
lint:
golangci-lint run
test:
go test -race -shuffle=on -coverprofile=coverage.out ./...
vuln:
go tool govulncheck ./... # pinned via `go get -tool` (Go 1.24+)
ci: build lint test vuln
CI が make ci にない処理を実行すると、開発者はプッシュ後に初めて失敗に気づきます。同じ内容にしてください。
6. 速度に関するルール
- lint/test/vuln を並列ジョブに分割します(§1 のとおり)。
go test ./...はすでにパッケージ単位で並列実行するため、小規模なリポジトリでは分割しないでください。- ビルドタグを使う統合テストは、別のジョブまたはスケジュール実行にして、プッシュのたびには実行しません。
go test -tags=integration ./...。 - ビルドキャッシュが頻繁にミスする場合は、
go.sumがキャッシュキーの入力になっていること(setup-go はそうします)と、ジョブがgo.sumを変更していないことを確認してください。
7. セキュリティゲート
govulncheck に加えて、CodeQL(security-extended)と gosec の結果を SARIF として Security タブにアップロードし、ビルドするコンテナーイメージには Trivy を実行します。まず gosec を -no-fail で実行してベースラインを収集し、その後、新たな指摘が PR を失敗させるようにします。
8. 依存関係の更新とアクションのピン留め
gomodとgithub-actionsの両方に Dependabot を設定し、マイナー更新とパッチ更新を週次で1つの PR にまとめます。メジャー更新は別にします — 変更履歴を読む必要があります。- サードパーティ製アクションは、コメントにバージョンを記載してコミット SHA でピン留めします。タグは悪意のあるコードに差し替えられる可能性がありますが、Dependabot は SHA ピン留めを更新します。
9. ワークフローとリポジトリの強化
- 読み取り専用をデフォルトとし、ジョブごとに権限を設定します。
- シークレットを利用できる状態でフォークのコードをチェックアウトして実行する
pull_request_targetワークフローを設けません。 - ブランチ保護を設定します。必須チェックとレビューを設定し、強制プッシュを禁止します。
- go-code-review スキルを読み込んだ AI レビュアーは追加のレビュアーとして使用し、単独で承認できるチェックにはしません。
セクション 7〜9 のスニペット:references/security-and-automation.md。
タグをトリガーとするリリース — GoReleaser、署名、SBOM、来歴 — は go-build-release スキルが担当します。
検証チェックリスト
- パイプラインに build、vet+lint、test -race、govulncheck の 4 つのゲートがすべて含まれている
- Go のバージョンは重複して指定せず、go.mod から取得する(
go-version-file) - ワークフローレベルで
permissions: contents: readを設定している - テストを
-race -shuffle=on付きで実行する - 厳選したリンターセットを含む
.golangci.ymlをコミットしている - すべての
nolintにリンター名と理由を記載している - マトリックスを実際にサポートするバージョン/プラットフォームに限定している
- カバレッジの下限を適用し、生成コードを除外している
make ciでパイプラインをローカルにバイト単位で再現できる- 統合テストをタグで分離し、プッシュのたびに実行して遅延を招かないようにしている
- CodeQL/gosec の結果を SARIF としてアップロードし、イメージをプッシュ前にスキャンしている
- Dependabot でモジュールとアクションを管理し、サードパーティ製アクションを SHA で固定している
- ジョブごとに権限を設定し、シークレットを利用できる状態でフォークのコードを実行しない