Skip to content

CI/CD 設計

このページの内容

必須ステータスチェックを高速に保ちつつ、pending で固まらせない仕組み — 集中化された変更検知分類器によるステップレベルのゲーティング。

ワークフロー一覧

ワークフロートリガー目的
ci.yamlmain への push、全 PR必須: changes, lint, test, build, docs, chart
e2e.yamlmain への push、全 PRKWOK ベース Karpenter e2e(単一 e2e ジョブ)
release.yamlv* タグの pushマルチアーキイメージ + Helm chart OCI + attestation + GitHub Release
pages.yamlmain への push(docs パス)、手動VitePress サイト → GitHub Pages

pending の罠

なぜ重要か

結論のない必須チェックは "green" ではなく pending で固まる。必須チェックが 1 つでもその状態なら PR は絶対にマージできない。

main のブランチ保護は必須ステータスチェックを名前で指定している。ワークフローやジョブが 完全にスキップ された場合(paths-ignore やジョブ単位の if: により)、GitHub は結論を報告しない → pending で固まる。

解決策: ジョブ は常に実行し、関係する変更がない場合に高コストな ステップ のみスキップ。

  • 重要な各ステップにステップ単位の if: を付与
  • 入力が変わっていなければジョブは数秒で実際の結論(成功)に到達
  • 関連ファイルが変更された場合のみフルワークを実行

これが paths-ignore やジョブ単位の if:使わない 理由。

ci.yaml: changes ジョブ

仕組み

  1. 専用の changes ジョブがゲーティングフラグを計算(常に実行、if: なし)
  2. linttestbuilddocschartneeds: changes を宣言しその出力を読む
  3. 分類ロジックは 1 箇所に集約(DRY)

分類器は .github/scripts/detect-ci-changes.sh:

  • 小さく純粋なシェルスクリプト(git も GitHub Actions コンテキストも使わない)
  • 標準入力から改行区切りの変更パスを読む
  • 5 つの真偽値を出力

入力ソース

コンテキスト入力
Pull requestgit diff --name-only "$BASE_SHA" HEAD
main への push全フラグ true(diff のベースなし; 常にすべて実行)

セルフテスト

.github/scripts/detect-ci-changes.test.sh がサンプルパス集合のテーブルに 対して分類器をユニットテスト。CI 実行のたびに走るため、ゲーティングロジック 自体が気づかれずに壊れることはない。

同じ常時実行 job で .github/scripts/check-release-version-sync.sh も実行。 chart、README EN/JA、agent/contributor 向けステータス、runbook EN/JA の current release バージョンが異なる PR は通過できない。

パス → フラグ → ジョブ

パスパターンフラグゲートされるジョブ/ステップ
*.go, go.mod, go.sum, api/, config/, .golangci.ymlgolint, test, build
charts/**chartchart
Dockerfile, .dockerignoredockerbuild
docs/**, README*.md, package ファイル、simulator Go sourcedocsdocs
Makefile, aqua.yaml, aqua-policy.yaml, aqua/**, .github/workflows/ci.yaml, .github/scripts/**infralint, test, build, chart

結果のステップゲート

ジョブ実ステップ実行条件
lintgo || infra
testgo || infra
buildgo || docker || infra
docsdocs
chartchart || infra
  • infra は意図的に広い: CI ワークフロー、共有 Makefile、aqua ツールチェーン固定バージョンの変更は docs 以外の 4 job すべてに影響しうるため、推測せず波及。docs flag は docs site と simulator の入力を別に追跡し、wasm モジュールを生成する共有ビルドツールチェーンのファイル(go.mod, go.sum, Makefile, aqua.yaml)も含む — これらは goinfra に加えて docs も立てる。

e2e.yaml: 単一ジョブ内での変更検知

ci.yaml とは意図的に異なる形:

  • 1 ジョブe2e)= 1 つの必須チェック
  • 変更検知はジョブの 最初のステップ として実行(別の上流ジョブではない)
  • 消費者が 1 つしかないため、別の changes ジョブによる DRY の恩恵なし

検知スコープ

e2e に関係するパスの diff を検査:

  • internal/, cmd/, charts/, test/e2e/
  • go.mod, go.sum, Makefile, Dockerfile, aqua.yaml
  • .github/workflows/e2e.yaml
  • 純粋な Markdown 変更を除外

動作

コンテキスト結果
これらのパスに触れない PRe2e: success を数秒で報告
関連パスに触れる PRフル ~45 分スイート
main への push常にフルスイート

release.yaml: タグ駆動の OCI 公開

v* タグの push のみでトリガー — ブランチ保護の対象外のため pending チェックのリスクなし。

4 つの逐次ジョブ

ジョブ目的
guardタグ、chart、current-release marker が不一致なら失敗
imageマルチアーキビルド + push + SBOM + SLSA provenance + attest + cosign
chartHelm chart パッケージ → OCI push + attest + cosign
releaseGitHub Release 作成(chart + SBOM 添付)

image ジョブの詳細

公開前に guard が両方のバージョンチェックを実行:

  • check-chart-version.sh: tag == chart version == appVersion を要求
  • check-release-version-sync.sh: README EN/JA、AGENTS.mdCONTRIBUTING.md、runbook EN/JA の current-release marker 一致を要求

同じ sync check は全 PR ですでに実行されるため、release-preparation の更新漏れは 通常 merge 前に検出され、公開前にも再検査される。

  • アーキテクチャ: linux/amd64, linux/arm64
  • レジストリ: ghcr.io/akashisn/node-rotation-controller
  • ハイフン付きプレリリース(例: v0.4.0-rc.1)でない限り latest タグを付与
  • レジストリ内 SBOM + SLSA provenance
  • push された index ダイジェストに attestation + キーレス cosign 署名
  • Release 用 SPDX SBOM を生成

chart ジョブの詳細

  • Helm chart をパッケージ → oci://ghcr.io/akashisn/charts
  • push されたマニフェストダイジェストに attestation + キーレス署名

release ジョブの詳細

  • パッケージ済み chart + SPDX SBOM をダウンロード
  • 両方を添付した GitHub Release を作成
  • ハイフン付きタグの場合はプレリリースとしてマーク

権限

ジョブ単位でスコープ(ワークフローレベルではない):

ジョブ権限
image, chartid-token, attestations, packages: write
releasecontents: write

attestation はプレリリースタグに対しても実行。利用者側の検証手順は SECURITY.md を参照。

pages.yaml: ドキュメントデプロイ

本 VitePress サイトを npm run docs:build でビルドし GitHub Pages にデプロイ。

トリガー

  • main への push で以下に触れた場合: docs/**, README.md, README.ja.md, package.json, package-lock.json, またはワークフローファイル自身
  • workflow_dispatch で手動実行

必須チェックではない

このワークフローはドキュメントを公開するのみ — マージをゲートしない。変更検知ゲーティングは不要。