CodeMender で CI / CD パイプラインを保護する

1. 始める前に

CodeMender で CI / CD パイプラインを保護するのハンズオン Codelab へようこそ。

最新のソフトウェア デリバリーでは、既知の構文パターンを検出するために静的分析ツール(CodeQL など)が不可欠ですが、ビジネス ロジックの奥深くに隠された微妙な脆弱性を見逃し、ノイズの多い未検証のアラートを生成することがよくあります。

CodeMender(CLI 実行可能ファイル: cm)は、既存の SAST ツールと並行して動作し、Google の Gemini を活用したセキュリティ推論エージェントをデプロイすることで、CI / CD パイプラインを強化します。

複雑なビジネス ロジックの欠陥を検出する: 厳格な静的パターンルールを超えて、アプリケーション コンテキストとアーキテクチャ データフローを推論します。

自己エクスプロイト検証により誤検知を大幅に削減: デベロッパーにアラートを送信する前に、サンドボックス環境でエクスプロイト可能性を動的に検証します。

検証済みの検出結果を自律的に修復する: コードパッチを合成し、テストスイートで検証して回帰を防ぎ、レビュー可能な pull リクエストを送信します。

この Codelab では、GitHub Actions とキーレスの Google Cloud Workload Identity 連携(WIF)を使用して、CodeMender を OWASP Juice Shop リポジトリに統合します。

前提条件

  • 推奨: CodeMender のコンセプトに関する基本的な知識(CodeMender でアプリケーションを保護するで説明)
  • GitHub Actions のワークフロー、トリガー、YAML 構文に関する基本的な理解
  • Git コマンドと pull リクエストのレビュー ワークフローに関する基本的な知識
  • Google Cloud IAM のコンセプト(サービス アカウント、ロール、API)に関する基本的な知識
  • 一般的なウェブ アプリケーションの脆弱性(SQL インジェクションや XSS など)に関する知識

学習内容

  • Workload Identity 連携(WIF)を介して GitHub Actions と Google Cloud の間にゼロトラストのキーレス認証を構成する方法
  • CodeMender と gemini-3.8-flash を使用して脆弱性スキャンの自動ワークフローを構築する方法
  • OASIS SARIF v2.1.0 とネイティブの GitHub Actions ジョブの概要を使用して、実用的なセキュリティ レポートを公開する方法
  • テストで検証されたコードパッチを生成し、人間によるレビューのために pull リクエストを開く自律的な修復ワークフローを構築する方法
  • 高速な継続的セキュリティを実現するために、自動化された品質ハードゲート(--fail-on)とパイプライン キャッシュを適用する方法

必要なもの

  • 課金が有効になっている Google Cloud プロジェクトと、プロジェクト オーナー / 編集者の権限
  • リポジトリの作成、シークレットの構成、アクションの管理を行う権限を持つ GitHub アカウント(ステップ 3 で GitHub CLI を使用して OWASP Juice Shop GitHub リポジトリをフォークします)。

2. CodeMender CI / CD アーキテクチャを理解する

最新のエンタープライズ DevSecOps では、AI を活用したセキュリティは単なる手動のデスクトップ ツールではありません。自動化されたゲートキーパー(安全でない pull リクエストをブロックする)と自律的な共同開発者(検証済みのパッチを Git に直接提案する)として機能する必要があります。

これを実現するために、Google Cloud Workload Identity 連携(WIF)と Gemini Enterprise 推論モデルを活用したデュアル ワークフロー アーキテクチャを実装します。

デュアル ワークフロー アーキテクチャ

CodeMender 自律型 CI / CD パイプラインのアーキテクチャ

このパイプラインでは、検出と修復を 1 つのモノリシックなスクリプトに詰め込むのではなく、セキュリティを 2 つの独立した専用ワークフローに分割します。

ワークフロー

メインのトリガー

主な責任

品質ハードゲート

1. 脆弱性スキャナ(codemender-scan.yml)

pull リクエスト、メインの push、週次 cron、手動ディスパッチ

• PR で高速な差分 AST スキャン(約 15 秒)、push で迅速なベースライン スキャン(–quick)、スケジュールで同時ディープ監査を実行• cm health –strict を介して事前に準備状況を検証• ネイティブの Actions ジョブの概要を生成し、OASIS SARIF を GitHub の [Security] タブにアップロード

PR のマージをブロック: 新たに導入された重大度「高」または「重大」の脆弱性が検出された場合(–fail-on)

2. 自律型修復ツール(codemender-remediate.yml)

手動トリガー(workflow_dispatch)、夜間 cron

• スキャン アーティファクト(cm report import)と state.db から状態を再開• Gemini の推論を使用してパッチを合成• クリーンなワークスペース境界を維持し、レビュー可能な pull リクエストを送信

PR を開く前に本番環境の差分をクリーンに保つ

エンタープライズ設計の 3 つの基本原則

以降のセクションでこれらのワークフローを構築する際は、次の 3 つの基本的なアーキテクチャの柱を念頭に置いてください。

🔑 ゼロトラストのキーレス認証と事前検証:

有効期間の長い Google Cloud サービス アカウントの JSON キーは GitHub Secrets に保存されません。ランナーは、Google Cloud STS を介して交換される有効期間の短い OIDC トークンを生成して、1 時間有効な一時的な認証情報を取得します。また、Git チェックアウトで persist-credentials: false を設定し、cm health --strict を実行して、認証情報、Network Reachability、IAM 権限を確認してから、使用量モデルの割り当てを消費します。

⚡ アダプティブ スキャン ルーティングと従来のノイズ サプレッション:

CodeMender は、すべての pull リクエストに対して時間のかかるフルリポジトリ監査を実行するのではなく、各 CI イベントを最適なスキャンモードにルーティングします。pull リクエストは、変更されたファイルと 1 ホップの呼び出し元に対して、15 秒未満で差分 AST 分析(--diff="origin/$BASE_REF")をトリガーします。メインブランチの push は、単一セッションのクイック ベースライン スキャン(--quick)を実行します。週次スケジュールは、ファイルごとの同時ディープ監査(デフォルトは cm find .)を実行します。PR で変更されていない既存のコードベースの脆弱性には [LEGACY / UNTOUCHED] というラベルが付けられます。これらは SARIF レポートに表示されて可視化されますが、PR マージゲートをブロックせず、自動修正をトリガーしません。

🛡️ 復元力のある非ブロッキング セキュリティ オブザーバビリティ:

--fail-on がコード 1 で終了して安全でない PR をブロックする場合でも、steps.scan.outputs.completed == 'true' と hashFiles('results.sarif') != '' を使用してレポートのエクスポートと SARIF のアップロード ステップを保護することで、OASIS SARIF アラートとジョブの概要が引き続き公開されます。また、実行がキャンセルされた場合や、セットアップ エラーまたは容量エラー(10~60)で中止された場合は、エクスポートとアップロードがクリーンにスキップされます。

3. Cloud Shell でターゲット リポジトリを認証して準備する

キーレス認証を確立して自動セキュリティ パイプラインを実行するには、所有しているアクセス可能なターゲット GitHub リポジトリが必要です。この Codelab では、OWASP Juice Shop(意図的に脆弱性を持たせた Node.js ウェブ アプリケーション)を、すぐに使えるセキュリティ プレイグラウンドとして使用します。

Google Cloud Shell にプリインストールされている GitHub CLI(gh)を使用して、GitHub で認証し、ユーザーの詳細を自動的にキャプチャして、1 つの合理化されたフローでリポジトリを準備します。

ステップ 1: Cloud Shell を開き、GitHub CLI を認証する

Google Cloud コンソールを開き、Cloud Shell(上部のナビゲーション バーにあるアイコン >_)をアクティブにします。

GitHub CLI(gh)を認証して、Git 認証情報マネージャーを構成します。

gh auth login --hostname github.com --git-protocol https --web

画面上の指示に沿って操作します。

Cloud Shell に出力された 8 文字のワンタイム コード(例: 1234-ABCD)をコピーします。

Enter キーを押して、ブラウザで https://github.com/login/device を開きます。

コードを貼り付けて、[Authorize github] をクリックします。

ステップ 2: 変数を動的にエクスポートして OWASP Juice Shop をフォークする

Cloud Shell で次のコマンドを実行して、GitHub ユーザー名を自動的に取得し、リポジトリを準備します。

# 1. Automatically capture your GitHub username (customize GITHUB_REPO if desired)
export GITHUB_ORG=$(gh api user -q .login)
export GITHUB_REPO="${GITHUB_REPO:-juice-shop}"
export GITHUB_REPOSITORY="${GITHUB_ORG:+${GITHUB_ORG}/${GITHUB_REPO}}"
echo "Authenticated as: ${GITHUB_REPOSITORY}"

# 2. Fork on GitHub server using GITHUB_REPO as the fork name
gh repo fork juice-shop/juice-shop --fork-name "${GITHUB_REPO}" --default-branch-only --clone=false 2>/dev/null || true

# 3. Shallow clone your fork (downloads only ~15 MB in 3-5 seconds, skipping heavy upstream git history)
[ -d ~/"${GITHUB_REPO}" ] || git clone --depth=1 "https://github.com/${GITHUB_REPOSITORY}.git" ~/"${GITHUB_REPO}" || \
 (sleep 2 && git clone --depth=1 "https://github.com/${GITHUB_REPOSITORY}.git" ~/"${GITHUB_REPO}")
cd ~/"${GITHUB_REPO}"

# 4. Confirm you are in the repository directory
git status

4. gcloud を使用して Google Cloud Workload Identity 連携を構成する

このステップでは、Google Cloud Shell で gcloud CLI を使用して、必要な API の有効化、専用の CI / CD サービス アカウントの作成、Workload Identity プールの設定、GitHub リポジトリ(${GITHUB_REPOSITORY})との OIDC 信頼の確立を行います。

ステップ 1: Google Cloud 環境変数を設定する

Cloud Shell ターミナル(クローンを作成したリポジトリ ワークスペース内)で、アクティブな Google Cloud プロジェクト ID をキャプチャし、GitHub リポジトリ変数を確認して、WIF リソース名を定義します。

# Capture active Google Cloud Project ID and verify GitHub repository
export PROJECT_ID=$(gcloud config get-value project)
export GITHUB_USER=$(gh api user -q ".login")
export GITHUB_REPO="${GITHUB_REPO:-$(git remote get-url origin 2>/dev/null | sed -E 's#^.*/##; s#\.git$##')}"
export GITHUB_REPO="${GITHUB_REPO:-juice-shop}"
export GITHUB_REPOSITORY="${GITHUB_USER:+${GITHUB_USER}/${GITHUB_REPO}}"

# Define WIF and Service Account resource names
export WORKLOAD_IDENTITY_POOL="codemender-github-pool"
export WORKLOAD_IDENTITY_PROVIDER="codemender-github-provider"
export SERVICE_ACCOUNT_NAME="codemender-ci-runner"

if [ -z "${PROJECT_ID}" ] || [ -z "${GITHUB_REPOSITORY}" ]; then
 echo "ERROR: PROJECT_ID ('${PROJECT_ID}') or GITHUB_REPOSITORY ('${GITHUB_REPOSITORY}') is empty. Check 'gcloud config get-value project' and 'gh auth status'."
else
 echo "Project ID:        ${PROJECT_ID}"
 echo "GitHub Repository: ${GITHUB_REPOSITORY}"
fi

ステップ 2: 必要な Google Cloud APIs を有効にする

IAM API、Security Token Service API、IAM Credentials API、Agent Platform API、Resource Manager API を有効にします。

gcloud services enable \
 iam.googleapis.com \
 iamcredentials.googleapis.com \
 sts.googleapis.com \
 aiplatform.googleapis.com \
 cloudresourcemanager.googleapis.com \
 --project=${PROJECT_ID}

ステップ 3: 専用の CI / CD サービス アカウントを作成する

CI / CD パイプラインの実行専用の最小権限の Google Cloud サービス アカウントを作成します(すでに存在する場合は安全に再利用します)。

export SERVICE_ACCOUNT_EMAIL="${SERVICE_ACCOUNT_NAME}@${PROJECT_ID}.iam.gserviceaccount.com"

gcloud iam service-accounts describe "${SERVICE_ACCOUNT_EMAIL}" \
 --project="${PROJECT_ID}" >/dev/null 2>&1 || \
gcloud iam service-accounts create "${SERVICE_ACCOUNT_NAME}" \
 --display-name="CodeMender CI/CD Pipeline Runner" \
 --project="${PROJECT_ID}"

echo "Service Account Email: ${SERVICE_ACCOUNT_EMAIL}"

ステップ 4: Agent Platform の IAM 権限を付与する

サービス アカウントに roles/aiplatform.user(Agent Platform ユーザー)ロールを付与して、Gemini Enterprise Agent Platform と通信できるようにします。

gcloud projects add-iam-policy-binding ${PROJECT_ID} \
 --member="serviceAccount:${SERVICE_ACCOUNT_EMAIL}" \
 --role="roles/aiplatform.user"

ステップ 5: Workload Identity プールを作成する

GitHub Actions の ID アサーションを管理する Workload Identity プールを作成します(プロジェクトにすでに存在する場合は、自動的に復元して有効にします)。

POOL_STATE=$(gcloud iam workload-identity-pools list \
 --location="global" \
 --show-deleted \
 --project="${PROJECT_ID}" \
 --filter="name ~ /${WORKLOAD_IDENTITY_POOL}$" \
 --format="value(state)")

if [ -z "${POOL_STATE}" ]; then
 gcloud iam workload-identity-pools create "${WORKLOAD_IDENTITY_POOL}" \
   --location="global" \
   --display-name="CodeMender GitHub Pool" \
   --project="${PROJECT_ID}"
else
 [ "${POOL_STATE}" = "DELETED" ] && gcloud iam workload-identity-pools undelete "${WORKLOAD_IDENTITY_POOL}" \
   --location="global" \
   --project="${PROJECT_ID}"
 gcloud iam workload-identity-pools update "${WORKLOAD_IDENTITY_POOL}" \
   --location="global" \
   --no-disabled \
   --project="${PROJECT_ID}"
fi

ステップ 6: GitHub OIDC を使用して Workload Identity プロバイダを作成する

プール内に OIDC プロバイダを作成(または更新)し、発行元 URL https://token.actions.githubusercontent.com をバインドして、GitHub トークン アサーションを Google STS 属性にマッピングします。

PROVIDER_STATE=$(gcloud iam workload-identity-pools providers list \
 --workload-identity-pool="${WORKLOAD_IDENTITY_POOL}" \
 --location="global" \
 --show-deleted \
 --project="${PROJECT_ID}" \
 --filter="name ~ /${WORKLOAD_IDENTITY_PROVIDER}$" \
 --format="value(state)")

if [ -z "${GITHUB_REPOSITORY}" ]; then
 echo "ERROR: GITHUB_REPOSITORY is empty. Re-run Step 1 before configuring the OIDC provider."
elif [ -z "${PROVIDER_STATE}" ]; then
 gcloud iam workload-identity-pools providers create-oidc "${WORKLOAD_IDENTITY_PROVIDER}" \
   --workload-identity-pool="${WORKLOAD_IDENTITY_POOL}" \
   --location="global" \
   --display-name="CodeMender GitHub Provider" \
   --issuer-uri="https://token.actions.githubusercontent.com" \
   --attribute-mapping="google.subject=assertion.sub,attribute.actor=assertion.actor,attribute.repository=assertion.repository,attribute.repository_owner=assertion.repository_owner" \
   --attribute-condition="assertion.repository == '${GITHUB_REPOSITORY}'" \
   --project="${PROJECT_ID}"
else
 [ "${PROVIDER_STATE}" = "DELETED" ] && gcloud iam workload-identity-pools providers undelete "${WORKLOAD_IDENTITY_PROVIDER}" \
   --workload-identity-pool="${WORKLOAD_IDENTITY_POOL}" \
   --location="global" \
   --project="${PROJECT_ID}"
 gcloud iam workload-identity-pools providers update-oidc "${WORKLOAD_IDENTITY_PROVIDER}" \
   --workload-identity-pool="${WORKLOAD_IDENTITY_POOL}" \
   --location="global" \
   --issuer-uri="https://token.actions.githubusercontent.com" \
   --attribute-mapping="google.subject=assertion.sub,attribute.actor=assertion.actor,attribute.repository=assertion.repository,attribute.repository_owner=assertion.repository_owner" \
   --attribute-condition="assertion.repository == '${GITHUB_REPOSITORY}'" \
   --no-disabled \
   --project="${PROJECT_ID}"
fi

ステップ 7: GitHub リポジトリにサービス アカウントの権限借用を許可する

roles/iam.workloadIdentityUser ロールをバインドして、リポジトリから送信されたトークンが CI ランナー サービス アカウントの権限を借用できるようにし、ポリシー バインディングを確認します。

# Retrieve the canonical Workload Identity Pool resource ID
export POOL_ID=$(gcloud iam workload-identity-pools describe "${WORKLOAD_IDENTITY_POOL}" \
 --project="${PROJECT_ID}" \
 --location="global" \
 --format="value(name)")

if [ -z "${POOL_ID}" ] || [ -z "${GITHUB_REPOSITORY}" ]; then
 echo "ERROR: POOL_ID ('${POOL_ID}') or GITHUB_REPOSITORY ('${GITHUB_REPOSITORY}') is empty. Re-run Step 1 and Step 5."
else
 # Bind Workload Identity User role to the principalSet of your repository
 gcloud iam service-accounts add-iam-policy-binding "${SERVICE_ACCOUNT_EMAIL}" \
   --project="${PROJECT_ID}" \
   --role="roles/iam.workloadIdentityUser" \
   --member="principalSet://iam.googleapis.com/${POOL_ID}/attribute.repository/${GITHUB_REPOSITORY}"

 # Verify the principalSet binding on the Service Account
 gcloud iam service-accounts get-iam-policy "${SERVICE_ACCOUNT_EMAIL}" \
   --project="${PROJECT_ID}"
fi

ステップ 8: GitHub シークレットの構成値を取得する

Workload Identity プロバイダの完全なリソース名を取得し、次のステップで自動登録するために環境変数に保存します。

# Retrieve full Workload Identity Provider name
export WORKLOAD_PROVIDER_NAME=$(gcloud iam workload-identity-pools providers describe ${WORKLOAD_IDENTITY_PROVIDER} \
 --workload-identity-pool=${WORKLOAD_IDENTITY_POOL} \
 --location="global" \
 --project=${PROJECT_ID} \
 --format="value(name)")

echo "=========================================================="
echo "WIF CONFIGURATION READY:"
echo "=========================================================="
echo "GCP_WORKLOAD_IDENTITY_PROVIDER: ${WORKLOAD_PROVIDER_NAME}"
echo "GCP_SERVICE_ACCOUNT:            ${SERVICE_ACCOUNT_EMAIL}"
echo "=========================================================="

5. GitHub リポジトリのシークレットとワークフローの権限を構成する

Google Cloud WIF がプロビジョニングされたので、GitHub リポジトリ シークレットを構成し、自動セキュリティ スキャンと自動修復の pull リクエストに必要なワークフロー権限を付与します。

これらの設定は、GitHub CLI(gh)を使用して Cloud Shell から直接構成できるため、長いリソース名を手動でコピーして貼り付ける必要がなくなります。

ステップ 1: GitHub CLI を使用してリポジトリ シークレットを設定する

Cloud Shell ターミナルで次のコマンドを実行して、アクティブな環境変数を使用して、必要な 2 つのリポジトリ シークレットを安全に設定します。

# 1. Set the Workload Identity Provider resource name
gh secret set GCP_WORKLOAD_IDENTITY_PROVIDER \
 --body "${WORKLOAD_PROVIDER_NAME}" \
 --repo "${GITHUB_REPOSITORY}"

# 2. Set the CI/CD Service Account email
gh secret set GCP_SERVICE_ACCOUNT \
 --body "${SERVICE_ACCOUNT_EMAIL}" \
 --repo "${GITHUB_REPOSITORY}"

# 3. Verify the secrets are registered
gh secret list --repo "${GITHUB_REPOSITORY}"

ステップ 2: 自動 PR のワークフロー権限を付与する

デフォルトでは、GitHub Actions ワークフローは読み取り専用権限で実行され、pull リクエストを作成できません。ステップ 9 では、CodeMender が検証済みの修正 pull リクエストを自律的に生成して送信します。

書き込み権限を付与し、GitHub API を介して pull リクエストを直接作成できるようにします。

[ -d .git ] || cd ~/"${GITHUB_REPO:-juice-shop}"
export GITHUB_REPOSITORY="${GITHUB_REPOSITORY:-$(git remote get-url origin 2>/dev/null | sed -E 's#^.*github\.com[:/]##; s#\.git$##')}"

gh api \
 --method PUT \
 -H "Accept: application/vnd.github+json" \
 /repos/${GITHUB_REPOSITORY}/actions/permissions/workflow \
 -f default_workflow_permissions="write" \
 -F can_approve_pull_request_reviews=true

ステップ 3: 継承された上流の Juice Shop ワークフローを無効にする

OWASP Juice Shop をフォークすると、16 個を超えるアップストリーム CI ワークフロー(PR Compliance Check、CI/CD Pipeline、CodeQL Scan など)と、master をターゲットとする PR を自動的にクローズするアップストリーム コントリビューター PR テンプレートが引き継がれます。GitHub CLI を使用して CodeMender 以外のすべてのワークフローを無効にし、アップストリーム ファイルをローカルで削除して、フォークが CodeMender ワークフローのみを実行するようにします。

[ -d .git ] || cd ~/"${GITHUB_REPO:-juice-shop}"
export GITHUB_REPOSITORY="${GITHUB_REPOSITORY:-$(git remote get-url origin 2>/dev/null | sed -E 's#^.*github\.com[:/]##; s#\.git$##')}"

# 1. Disable all inherited non-CodeMender workflows in GitHub Actions (and CodeQL default setup if active)
for WF_ID in $(gh workflow list --all --limit 100 --repo "${GITHUB_REPOSITORY}" --json id,path \
 -q '.[] | select((.path | startswith(".github/workflows/")) and (.path | test("codemender-") | not)) | .id'); do
 gh workflow disable "${WF_ID}" --repo "${GITHUB_REPOSITORY}" 2>/dev/null || true
done
gh api -X PATCH "/repos/${GITHUB_REPOSITORY}/code-scanning/default-setup" \
 -f state=not-configured >/dev/null 2>&1 || true

# 2. Remove upstream workflow files and PR template from the local workspace
for f in .github/workflows/*; do
 case "$f" in *codemender-*) ;; *) rm -f "$f" ;; esac
done
rm -f .github/PULL_REQUEST_TEMPLATE.md

6. SARIF を使用して自動脆弱性スキャン ワークフローを構築する

このステップでは、ブランチの push でベースライン スキャン、pull リクエストで差分ゲート、GitHub Code Scanning への SARIF エクスポートを実行する、プライマリ継続的セキュリティ スキャン ワークフロー(.github/workflows/codemender-scan.yml)を作成します。

ステップ 1: CodeMender スキャン ワークフローをダウンロードする

スターター リポジトリから codemender-scan.yml をダウンロードして .github/workflows/ に保存します。

[ -d .git ] || cd ~/"${GITHUB_REPO:-juice-shop}"
mkdir -p .github/workflows
curl -fsSL https://raw.githubusercontent.com/edwardc-gcp/codemender-github-actions/main/.github/workflows/codemender-scan.yml \
 -o .github/workflows/codemender-scan.yml

ステップ 2: commit、push、CI スキャンをトリガーする

ワークフローの変更を commit し、リポジトリのプライマリ ブランチ(Juice Shop の場合は master、または main)に直接 push します。

# Stage workflow changes, commit, and push to primary branch
git add -A .github
git commit -m "ci: add CodeMender SARIF security scanning workflow"
git push origin $(git branch --show-current)

ブラウザは次のようになります。

フォークした GitHub リポジトリ https://github.com/YOUR_GITHUB_USER/juice-shop(例: https://github.com/octocat/juice-shop)に移動します。

上部のナビゲーション バーにある [Actions] タブをクリックします。

左側のサイドバーの [Workflows] で、[CodeMender Security Scan & SARIF Export] を選択します。

ワークフローの実行をトリガーまたは表示します。

自動トリガー: push によってトリガーされた自動実行がリストされている場合は、それを直接クリックしてライブ実行をモニタリングします。

手動オンデマンド トリガー(workflow_dispatch): 実行がまだ開始されていない場合は、右側の [Run workflow ▾] ボタンをクリックし、Branch: master が選択されていることを確認します([deep_scan] チェックボックスはオフのままにして、高速な --quick ベースライン スキャンが実行されるようにします)。緑色の [Run workflow] ボタンをクリックします。

実行中の実行をクリックし、[Autonomous Code Vulnerability Scan] を選択して、ワークフローがリアルタイムでスピンアップされるのを確認します。

codemender-scan.yml の内部: イベント対応のスキャン ルーティング

--quick ベースライン スキャンがクラウドで実行されている間(約 3 ~ 5 分)、codemender-scan.yml(118 ~ 155 行目)が各 GitHub イベントをランナー内の専用スキャンモードにルーティングする方法を確認します。

# Excerpt from .github/workflows/codemender-scan.yml
if [ "${{ github.event_name }}" = "pull_request" ]; then
 cm find . \
   --diff="origin/${{ github.base_ref }}" \
   --diff-workers=16 \
   --fail-on="CRITICAL,HIGH" \
   --sandbox=false --yes --bypass-warning || status=$?
elif [ "${{ github.event_name }}" = "schedule" ] || [ "${{ github.event.inputs.deep_scan }}" = "true" ]; then
 cm find . \
   --deep-workers=8 \
   --sandbox=false --yes --bypass-warning || status=$?
else
 cm find . \
   --quick \
   --sandbox=false --yes --bypass-warning || status=$?
fi

Hardened Runner の設定(27 ~ 117 行目): 信頼できない外部フォークと dependabot[bot] PR をスキップし、persist-credentials: false でチェックアウトし、~/.local/bin/cm と ~/.codemender/state.db をキャッシュに保存し、使用量モデルの割り当てを消費する前に cm health --strict を実行します。

ヘッドレス サンドボックス境界(--sandbox=false --yes --bypass-warning): Linux ユーザー名前空間の分離(権限のない GitHub Actions コンテナ内で制限)を無効にし、ワークスペース パス境界(project_paths)と command_policy.yaml を適用したままにします。

終了コードで保護された SARIF とアーティファクトのエクスポート(147 ~ 194 行目): cm find が 0(クリーン)または 1(--fail-on しきい値に達した)で終了した場合にのみ steps.scan.outputs.completed=true を設定します。これにより、--fail-on が PR をブロックしても、SARIF レポート(CVSS 重大度スコアを含む cm report -f sarif)、$GITHUB_STEP_SUMMARY テーブル(cm report -f md)、codemender-findings.json アーティファクトが引き続き公開されます。一方、セットアップ エラーや容量エラー(10~60)が発生した場合はエクスポートがスキップされるため、空の SARIF ファイルによって既存のアラートが閉じられることはありません。

7. GitHub のコードスキャン アラートとセキュリティ ダッシュボードを調べる

ベースライン push ワークフローが完了すると、GitHub はアップロードされた SARIF ファイルを処理し、Actions の実行サマリーとリポジトリの [Security] タブの両方にデータを入力します。

ステップ 1: GitHub Actions でネイティブ ジョブの概要を調べる

ワークフローを実行するたびに、Markdown の概要テーブル(cm report -f md)が GitHub Actions の実行概要に直接追加されます。

GitHub リポジトリで [Actions] タブをクリックします。

完了した CodeMender Security Scan & SARIF Export 実行を選択します(ベースライン ブランチの push 監査は、SARIF の検出結果が公開されると緑色の ✅ チェックマークで終了します)。

[🛡️ CodeMender Security Scan Summary] セクションまで下にスクロールして、検出結果の内訳を確認します。

🔒 CodeMender セキュリティ レポート

概要

検出結果の総数: 28

重大度

数

🔴 重大

6

🟠 高

16

🟡 中

6

ステータス

数

🔴 OPEN

28

検出結果

ID

重大度

信頼度

ステータス

修正

ファイル

タイトル

c1b96b9a

🔴 重大

100%

開く

—

routes/userProfile.ts

ユーザー プロファイルでのサーバーサイド コード インジェクションによるリモートコード実行

cd47b38a

🔴 重大

100%

開く

—

routes/login.ts

ユーザー認証ルートでの SQL インジェクション

a47a9e45

🔴 重大

100%

開く

—

routes/b2bOrder.ts

B2B 注文処理におけるサンドボックス エスケープによるリモートコード実行

ステップ 2: 一元化された Code Scanning ダッシュボードを確認する

GitHub リポジトリの上部ナビゲーション バーで、[Security and quality](または [Security])タブをクリックします。

左側のサイドバーの [Findings] で、[Code scanning] を選択します。

複数のツールが有効になっている場合は、[Tool] を [CodeMender](is:open branch:master tool:CodeMender)にフィルタして、ネイティブの CVSS 重大度バッジにマッピングされたアラートを検査します。

重大度バッジ

脆弱性の見出し

検出された位置情報

Branch

🔴 重大

ユーザー プロファイルでのサーバーサイド コード インジェクションによるリモートコード実行

routes/userProfile.ts:58

master

🔴 重大

ユーザー認証ルートでの SQL インジェクション

routes/login.ts:34

master

🔴 重大

B2B 注文処理におけるサンドボックス エスケープによるリモートコード実行

routes/b2bOrder.ts:21

master

[SQL インジェクション in User Authentication Route](routes/login.ts:34)をクリックして、Gemini によって合成された、汚染されたデータフローと根本原因分析を確認します。

8. 差分スキャンで安全でない pull リクエストをブロックする

ベースライン スキャンにより、OWASP Juice Shop に 28 個の既存の脆弱性があることが判明しました。従来の静的アナライザーでは、これら 28 件のレガシーな検出結果が、バックログ全体が修正されるまで、今後のすべての pull リクエストで失敗することになります。そのため、チームはマージ ブロックを無効にせざるを得ませんでした。

次に、CodeMender の PR 差分 AST ゲート(--diff + --fail-on="CRITICAL,HIGH")を実際にテストします。新しい脆弱性を導入する pull リクエストを開き、CodeMender が差分を分離し、約 15 ~ 25 秒でマージをブロックし、問題のある行に正確にアノテーションを付ける様子を確認します。

ステップ 1: コマンド インジェクションの脆弱性を導入する pull リクエストを開く

Cloud Shell(クローンされたリポジトリ ワークスペース内)で、機能ブランチを作成し、OS コマンド インジェクションの脆弱性を含む新しい Express ルートを追加して、フォークに対して pull リクエストを開きます。

[ -d .git ] || cd ~/"${GITHUB_REPO:-juice-shop}"
export GITHUB_REPOSITORY="${GITHUB_REPOSITORY:-$(git remote get-url origin 2>/dev/null | sed -E 's#^.*github\.com[:/]##; s#\.git$##')}"
PRIMARY_BRANCH=$(git symbolic-ref --short refs/remotes/origin/HEAD | sed 's@^origin/@@')

# Reset any previous demo PR/branch so this step can be re-run cleanly
gh pr close feat/diagnostics --repo "${GITHUB_REPOSITORY}" --delete-branch 2>/dev/null || true
git checkout "${PRIMARY_BRANCH}"
git checkout -B feat/diagnostics

# Introduce an Express endpoint vulnerable to OS Command Injection (CWE-78)
cat << 'EOF' > routes/diagnostics.ts
import { execSync } from 'node:child_process'
import { type Request, type Response } from 'express'

export function systemDiagnostics () {
 return (req: Request, res: Response) => {
   const host = String(req.query.host ?? '127.0.0.1')
   const output = execSync(`ping -c 1 ${host}`).toString()
   res.status(200).json({ status: 'ok', output })
 }
}
EOF

git add routes/diagnostics.ts
git commit -m "feat: add network diagnostics endpoint"
git push -f -u origin feat/diagnostics

gh pr create \
 --repo "${GITHUB_REPOSITORY}" \
 --base "${PRIMARY_BRANCH}" \
 --head feat/diagnostics \
 --title "feat: add network diagnostics endpoint" \
 --body "Adds a ping diagnostics handler."

ステップ 2: 差分マージゲートとインライン PR アノテーションを確認する

ターミナル出力の最後に表示される pull リクエストの URL を開きます。

pull リクエストの会話ページの下部にある [Checks] ボックスまでスクロールし、[Autonomous Code Vulnerability Scan] を確認します。

デルタ速度: リポジトリ内の 680 以上のファイルすべてをスキャンする(約 3 ~ 5 分)代わりに、cm find . --diff="origin/${PRIMARY_BRANCH}" は分析の範囲を routes/diagnostics.ts(および 1 ホップの呼び出し元)に厳密に限定し、スキャンを 約 15 ~ 25 秒で完了します。

レガシー デットの分離とマージのブロック: Juice Shop の 28 個の未修正のレガシー脆弱性は、いずれもチェックに失敗しません。新しく導入された CRITICAL コマンド インジェクションのみが --fail-on="CRITICAL,HIGH" をトリガーし、ステータス コード 1(赤色の ❌)で終了して PR のマージをブロックします。

Pull Request の上部にある [Files changed] タブをクリックします。

ワークフローの終了コード ガード(steps.scan.outputs.completed == 'true')は、--fail-on がコード 1 で終了しても results.sarif をエクスポートしてアップロードするため、GitHub Code Scanning は routes/diagnostics.ts の execSync の直下にインラインの CodeMender - 重大セキュリティ アノテーションをレンダリングします。

ステップ 3: テスト PR をクリーンアップしてプライマリ ブランチに戻る

Cloud Shell ワークスペースをメイン ブランチに戻し、安全でないテスト pull リクエストを閉じてから、自律的な修復に進みます。

[ -d .git ] || cd ~/"${GITHUB_REPO:-juice-shop}"
export GITHUB_REPOSITORY="${GITHUB_REPOSITORY:-$(git remote get-url origin 2>/dev/null | sed -E 's#^.*github\.com[:/]##; s#\.git$##')}"
PRIMARY_BRANCH=$(git symbolic-ref --short refs/remotes/origin/HEAD | sed 's@^origin/@@')
git checkout "${PRIMARY_BRANCH}"
gh pr close feat/diagnostics --repo "${GITHUB_REPOSITORY}" --delete-branch
git branch -D feat/diagnostics 2>/dev/null || true

9. 自律的な修復と自動 PR ワークフローを構築する

pull リクエスト ゲートによって新しい脆弱性がコードベースに侵入するのを防ぐことができるようになったので、Autonomous Remediation(.github/workflows/codemender-remediate.yml)をデプロイして、既存の脆弱性を積極的に修正し、レビュー可能な pull リクエストを開きます。

ステップ 1: 修正ワークフロー ファイルをダウンロードする

CodeMender には、リポジトリの公開設定に応じて 2 つの修正テンプレートが用意されています。

公開 / オープンソース リポジトリ(codemender-remediate.yml): 責任ある開示モード - 未加工のエクスプロイト ベクトルを公開することなく、GitHub コードスキャン SARIF アラートにリンクします。

プライベート / エンタープライズ リポジトリ(codemender-remediate-private-repo.yml): 内部監査証拠モード - 検証アーティファクト(PLAN.md、REPORT.md、exploit.sh)を折りたたみ可能な PR セクション内に埋め込み、Git commit から除外します。

公開しても安全な修復ワークフローをリポジトリにダウンロードします。

mkdir -p .github/workflows
curl -fsSL https://raw.githubusercontent.com/edwardc-gcp/codemender-github-actions/main/.github/workflows/codemender-remediate.yml \
 -o .github/workflows/codemender-remediate.yml

ステップ 2: 自律修復ワークフローを commit してトリガーする

修復ワークフローを commit してプライマリ ブランチに push します。

git add .github/workflows/codemender-remediate.yml
git commit -m "ci: add CodeMender autonomous remediation workflow"
git push origin $(git branch --show-current)

ブラウザで、GitHub リポジトリの [Actions] タブに移動します。

左側のサイドバーの [ワークフロー] で、[CodeMender Autonomous Security Remediation & Auto-PR] を選択します。

右側にある緑色の [Run workflow] プルダウンをクリックします。

Use workflow from: デフォルト ブランチ(master)が選択されていることを確認します。

Specific Finding ID or prefix to fix: 手順 7 でメモした routes/login.ts の 8 文字の接頭辞を入力します(例: cd47b38a)。このフィールドを空白のままにすると、未解決の「重大」および「高」のすべての検出結果に対してバッチ修復が実行されます(約 10 ~ 15 分)。1 つの ID をターゲットにすると、約 45 ~ 60 秒で完了します。

ポップオーバー内の緑色の [Run workflow] ボタンをクリックし、実行中の実行を開きます。

[Run workflow] プルダウンから CodeMender Autonomous Security Remediation ワークフローをトリガーする

codemender-remediate.yml の内部: 自律的なパッチ合成

CodeMender がクラウドでパッチを合成している間(約 30 ~ 45 秒)、codemender-remediate.yml(111 ~ 184 行目)がランナー内で修復をオーケストレートする仕組みを確認します。

ゼロスキャン再開(cm report import): スキャン ワークフローから codemender-findings.json アーティファクトをダウンロードしてワークスペース(cm report import -f codemender-findings.json)にインポートします。以前のアーティファクトが存在しない場合にのみ cm find . --quick にフォールバックします。

ヘッドレス パッチ合成(cm fix): project_paths を $GITHUB_WORKSPACE に固定し、< /dev/null をパイプしてインタラクティブなハングを防ぎ、バッチループ中に --no-reset を渡して、検出結果全体で累積的な修正が保持されるようにします。

# Executed inside the GitHub Actions runner (codemender-remediate.yml)
cm fix "${SPECIFIC_TARGET}" --sandbox=false --yes --bypass-warning < /dev/null

Clean Production Commits(155 ~ 252 行目): peter-evans/create-pull-request@v8 がブランチ(codemender/auto-remediation-${{ github.run_id }})を開く前に、.git/info/exclude を介して .cm_project、.exploit/、一時ファイルをパージし、本番環境のコード変更のみを commit します。

--- a/routes/login.ts
+++ b/routes/login.ts
@@ -28,8 +28,8 @@ module.exports = function login () {
-    models.sequelize.query(`SELECT * FROM Users WHERE email = '${req.body.email || ''}' AND password = '${security.hash(req.body.password || '')}' AND deletedAt IS NULL`, { model: models.User })
+    models.sequelize.query('SELECT * FROM Users WHERE email = :email AND password = :password AND deletedAt IS NULL', {
+      replacements: { email: req.body.email || '', password: security.hash(req.body.password || '') },
+      model: models.User
+    })

ステップ 3: GitHub で新しく開かれた pull リクエストを確認する

リポジトリの [Pull requests] タブに移動し、新しい pull リクエスト(例: 🛡️ [CodeMender] Fix: SQL Injection in User Authentication Route)を開きます。

[Files changed] をクリックして、routes/login.ts のみが変更され、内部ランタイム メタデータがすべて除外されていることを確認します。

メンテナーの承認を得るために、GitHub コードスキャン(SARIF)アラートに直接リンクしている PR の説明を確認します。

10. 特殊なケースとプライベート リポジトリのトラブルシューティング

GitHub Advanced Security(GHAS)のないプライベート リポジトリ

公開 GitHub リポジトリでは、GitHub コードスキャンの SARIF 取り込みを無料で無制限に利用できます。ただし、有効な GitHub Advanced Security(GHAS)ライセンスがないプライベート エンタープライズ リポジトリにこのワークフローをデプロイすると、upload-sarif ステップは失敗し、次のエラーが発生します。

HTTP 403: Advanced Security must be enabled for this repository to use code scanning.

解決策: スタンドアロンのインタラクティブ HTML レポートのフォールバック

CodeMender の組み込み HTML レポート生成ツール(cm report -f html)は、スタンドアロンのインタラクティブなセキュリティ ダッシュボードを作成します。このダッシュボードには、重大度指標カード、行番号付きの構文がハイライト表示されたコード スニペット、インライン パッチ差分ビューアが含まれており、外部ウェブ依存関係はありません。

GHAS ライセンスなしでプライベート リポジトリをサポートするには、.github/workflows/codemender-scan.yml を更新して、SARIF をアップロードする代わりに HTML レポート アーティファクトをアーカイブします。

スタンドアロン HTML レポートを生成する: Export Security Reports & Publish Job Summary ステップで、cm report -f html > codemender-audit-report.html を使用して Markdown の概要とともに HTML ダッシュボードをエクスポートします。

レポートをワークフロー アーティファクトとしてアーカイブする: Upload SARIF Report to GitHub Code Scanning(github/codeql-action/upload-sarif@v4)ステップを、codemender-audit-report.html をアップロードするように構成された actions/upload-artifact@v4 に置き換えます(例: アーティファクト名 codemender-security-report の下)。

任意のブラウザでローカルに検査する: GitHub Actions ワークフロー実行の概要ページから codemender-security-report.zip を直接ダウンロードして抽出し、任意のウェブブラウザで codemender-audit-report.html を開いて視覚的なトリアージを行います。

監査証拠が埋め込まれたプライベート リポジトリの自律的な修復

非公開の企業リポジトリでは、エンジニアリング チームとセキュリティ チームが、外部ツールのダッシュボードを必要とせずに、根本原因分析、エクスプロイトの概念実証、修復計画を完全に把握する必要があります。ただし、エクスプロイト スクリプト(exploit.sh)や内部マークダウン ファイル(PLAN.md、LOG.md)をリポジトリ ブランチに commit すると、Git 履歴が汚染され、他のセキュリティ スキャナから誤ったアラートがトリガーされる可能性があります。

これに対処するには、専用のプライベート リポジトリ修復ワークフロー(codemender-remediate-private-repo.yml)をデプロイします。

curl -fsSL https://raw.githubusercontent.com/edwardc-gcp/codemender-github-actions/main/.github/workflows/codemender-remediate-private-repo.yml \
 -o .github/workflows/codemender-remediate.yml
git add .github/workflows/codemender-remediate.yml
git commit -m "ci: switch to private repository remediation workflow with embedded audit evidence"
git push origin $(git branch --show-current)

プライベート リポジトリの修正の仕組み

動的 PoC 検証(cm verify): 修正を生成する前に、動作するエクスプロイトを合成してテストし、悪用可能性を確認します。検証で悪用不可能な検出結果が DISMISSED とマークされた場合、cm fix は自動的にスキップされます。

埋め込み PR 監査折りたたみ可能ブロック: REPORT.md、PLAN.md、exploit.sh を /tmp/codemender-evidence/ に抽出し、<details open> 折りたたみ可能ブロック内の pull リクエストの説明に直接フォーマットして、レビュー担当者がワンクリックで検査できるようにします。

アーティファクトのアーカイブ: actions/upload-artifact@v4 を介して、完全な証拠フォルダをアーカイブします。

Pristine Git Commits: すべてのランタイム メタデータと .exploit ディレクトリをパージして、pull リクエストの Git commit に本番環境コードの変更のみが含まれるようにします。

Workload Identity 連携(WIF)のトラブルシューティング チェックリスト

デフォルトでは、google-github-actions/auth@v2 は設定時にローカルの連携認証情報構成ファイルを書き込み、実際の OAuth 2.0 トークン交換は cm health --strict または cm find の起動時に行われます。HTTP 400 または HTTP 403 の認証エラーを診断するには、以下のチェックリストを使用します。

エラーの症状

一般的な根本原因

確認と修正

HTTP 403(iam.serviceAccounts.getAccessToken が拒否されました)

サービス アカウントに roles/iam.workloadIdentityUser バインディングがない、GCP_SERVICE_ACCOUNT シークレットが正しくない、または iamcredentials.googleapis.com が有効になっていない。

GCP_SERVICE_ACCOUNT が codemender-ci-runner@.iam.gserviceaccount.com と一致することを確認し、以下の IAM ポリシー チェックを実行して principalSet バインディングを確認します。

HTTP 400(unauthorized_client または属性条件が拒否されました)

OIDC –attribute-condition リポジトリ名(または大文字と小文字の区別)が、ワークフローをトリガーする GitHub リポジトリと一致しないか、WIF プロバイダが無効になっています。

ステップ 4(ステップ 1 と 6)を再実行し、${GITHUB_REPOSITORY} が GitHub の owner/repo の大文字と小文字と完全に一致し、–no-disabled が適用されていることを確認します。

HTTP 400(トークン交換時の invalid_grant)

OIDC プロバイダで –issuer-uri の形式が正しくないか、attribute.repository=assertion.repository マッピングがありません。

–issuer-uri が https://token.actions.githubusercontent.com に厳密に設定されていることを確認します(末尾にスラッシュは付けません)。

設定直後の一時的な HTTP 403

新しく作成されたバインディングでは、グローバル IAM と Workload Identity 連携の伝播に 1 ~ 5 分かかることがあります。

1 ~ 2 分待ってから、GitHub Actions で [Re-run failed jobs] をクリックします。

Cloud Shell で CI/CD サービス アカウントのライブ Workload Identity バインディングを検査するには、次のコマンドを実行します。

gcloud iam service-accounts get-iam-policy "${SERVICE_ACCOUNT_EMAIL}" \
 --project="${PROJECT_ID}" \
 --flatten="bindings[].members" \
 --filter="bindings.role=roles/iam.workloadIdentityUser"

出力で roles/iam.workloadIdentityUser が principalSet://iam.googleapis.com/<POOL_ID>/attribute.repository/<GITHUB_USER>/<GITHUB_REPO> にバインドされていることを確認します。

---
bindings:
 members: principalSet://iam.googleapis.com/.../attribute.repository/<OWNER>/<REPO>
 role: roles/iam.workloadIdentityUser

CI / CD プリフライトと CLI 終了コードのトラブルシューティング

CodeMender コマンド(cm health --strict、cm find、cm verify、cm fix)は、CI / CD パイプラインがセキュリティ検出結果をセットアップ エラーやサービスエラーとすぐに区別できるように、決定論的な終了コードを返します。

終了コード

カテゴリ

一般的な根本原因と修復

0

成功

ヘルスチェックに合格したか、ブロックする検出結果なしでスキャンが完了しました。

1

調査結果 / 全般

–fail-on が、PR でブロックしている CRITICAL または HIGH の脆弱性を検出しました(想定されるマージゲートの失敗)。

10

credentials

WIF OAuth / ADC トークン交換に失敗しました(400/401)。GCP_WORKLOAD_IDENTITY_PROVIDER、GCP_SERVICE_ACCOUNT、上記の roles/iam.workloadIdentityUser バインディングを確認してください。

20

config

.codemender/config.yaml または ~/.codemender/config.yaml の構文が正しくありません。

30

reachability

ランナーが aiplatform.googleapis.com に到達できない(DNS、プロキシ、サービス停止、VPC Service Controls)。

40

authorization

サービス アカウントに、ターゲット プロジェクトの roles/aiplatform.user がないか、cloudresourcemanager.googleapis.com / aiplatform.googleapis.com が無効になっています。

50

timeout

プリフライト cm health チェックが 30 秒の期限を超えました。

60

capacity

エージェントが同時アクティブ タスクの上限に達しました。少し待ってからワークフローを再実行してください。

Git diff ベースブランチの解決(fetch-depth: 0)、リソース伝播の遅延、GitHub Actions の pull リクエスト作成権限など、その他のランタイム エラーについては、公式の CodeMender CI / CD トラブルシューティング ガイドをご覧ください。

11. リソースをクリーンアップする

リソースの継続的な消費を防ぐため、または Google Cloud 環境と GitHub 環境のテスト構成をクリーンアップするには、次のクリーンアップ手順を行います。

ステップ 1: GitHub リポジトリのシークレットを削除し、gh CLI を介してワークフローを無効にする

GitHub CLI(gh)を使用して、リポジトリの Actions シークレットを完全に削除し、CodeMender ワークフローを無効にします。

# Delete the repository Actions secrets
gh secret delete GCP_WORKLOAD_IDENTITY_PROVIDER --repo "${GITHUB_REPOSITORY}" 2>/dev/null || true
gh secret delete GCP_SERVICE_ACCOUNT --repo "${GITHUB_REPOSITORY}" 2>/dev/null || true

# Disable the CodeMender workflows to prevent unwanted automatic triggers
gh workflow disable codemender-scan.yml --repo "${GITHUB_REPOSITORY}" 2>/dev/null || true
gh workflow disable codemender-remediate.yml --repo "${GITHUB_REPOSITORY}" 2>/dev/null || true

ステップ 2: Google Cloud Workload Identity 連携リソースを無効にするか削除する

Workload Identity プール、プロバイダ、サービス アカウントでは、トークンを交換していないときにアイドル費用が発生しません。ワークフローに合ったクリーンアップ モードを選択します。

オプション A - アクセスを一時停止する(このプロジェクトで再実行する予定がある場合におすすめ): Google Cloud IAM の 30 日間の削除(復元可能)保持やサービス アカウント uniqueId の伝播遅延をトリガーすることなく、OIDC トークン交換を直ちに無効にします。

gcloud iam workload-identity-pools providers update-oidc "${WORKLOAD_IDENTITY_PROVIDER}" \
 --workload-identity-pool="${WORKLOAD_IDENTITY_POOL}" \
 --location="global" \
 --disabled \
 --project="${PROJECT_ID}"

オプション B - 完全な破棄: WIF プロバイダ、プール(DELETED 状態で 30 日間保持)、専用のサービス アカウントを削除します。

# Delete Workload Identity Provider
gcloud iam workload-identity-pools providers delete "${WORKLOAD_IDENTITY_PROVIDER}" \
 --workload-identity-pool="${WORKLOAD_IDENTITY_POOL}" \
 --location="global" \
 --project="${PROJECT_ID}" \
 --quiet

# Delete Workload Identity Pool
gcloud iam workload-identity-pools delete "${WORKLOAD_IDENTITY_POOL}" \
 --location="global" \
 --project="${PROJECT_ID}" \
 --quiet

# Delete CI/CD Service Account
gcloud iam service-accounts delete "${SERVICE_ACCOUNT_EMAIL}" \
 --project="${PROJECT_ID}" \
 --quiet

12. 完了

おめでとうございます!「CodeMender で CI / CD パイプラインを保護する」の Codelab を完了しました。

Google Cloud Workload Identity 連携、CodeMender、GitHub Actions を使用して、本番環境レベルのゼロトラスト DevSecOps パイプラインを設計、構築、自動化しました。

学習した内容

ゼロトラストのキーレス認証: Workload Identity 連携(WIF)を介して、有効期間の短い GitHub OIDC トークンを Google Cloud IAM にバインドすることで、リスクの高い、有効期間の長いサービス アカウントの JSON キーを排除しました。

PR 差分 AST スキャンとノイズ サプレッション: 変更されたファイルと依存関係(--diff="origin/$BASE_REF")に限定した継続的なスキャンを行い、レガシーな技術的負債([LEGACY / UNTOUCHED])を分離して、開発者のフィードバック ループを 15 秒未満に維持します。

マルチフォーマット レポートとネイティブ ジョブ サマリー: GitHub コードスキャンを一元化するための OASIS SARIF v2.1.0 と、CI ワークフロー実行ページで直接エグゼクティブに即座に可視性を提供するネイティブ Markdown(cm report -f md >> $GITHUB_STEP_SUMMARY)を組み合わせました。

人間参加型のレビューによる自律的な修復: 受動的なアラート通知から、提案されたコードパッチを自律的に合成し、回帰テストスイートに照らして検証し、エンジニアの承認を得るための監査アーティファクトを含むレビュー pull リクエストを開く、能動的な修復パイプラインに移行しました。

自動化された品質ハードゲート: 厳格なブランチ保護とマージ ゲーティング(--fail-on)を適用して、危険な脆弱性が本番環境に到達するのを阻止しました。

アーティファクト駆動型の状態転送とワークスペースの分離: cm report import を使用して CI ジョブ間で検出結果をシームレスに転送し、.git/info/exclude を使用して元の Git 履歴を保持し、認証情報の漏洩を防止しました。

デベロッパーのマインドセットの転換

従来の DevSecOps プラクティス

CodeMender 自律型 CI / CD パイプライン

受動的なアラートのダンプ: スキャナは、未加工のターミナルログや静的なエラーリストを出力し、トリアージの負担をすべて開発者に転嫁します。

アクティブな共同開発者: 検証済みのコードパッチを合成し、エンジニアの承認を得るためにマージ可能な pull リクエストを開きます。

高い誤検知率: 静的 AST のヒューリスティックは、悪用可能性の証拠がない何千もの理論上の脆弱性にフラグを立てます。

2 段階のエクスプロイト検証: 動的なサンドボックス テスト生成(cm verify)により、実際の脆弱性を確認し、誤検出を排除します。

リスクの高いシークレット ストレージ: CI シークレットに保存された有効期間の長いサービス アカウントの JSON キーは、偶発的な漏洩や認証情報の拡散のリスクがあります。

ゼロトラスト WIF: Google Cloud STS とオンデマンドで交換されるエフェメラル OIDC トークンを介したキーレス認証。

モノリシックな再スキャン: commit ごとにリポジトリ全体の監査がトリガーされるため、CI ワークフローが遅延し、高価なトークンが無駄になります。

イベント対応の AST ルーティング: pull リクエストは 15 秒の差分 AST スキャン(–diff)を実行し、cron 実行は詳細な監査を実行します。

汚染されたリポジトリ履歴: 一時的なエクスプロイト スクリプトと攻撃ログがリポジトリ ブランチに直接 commit されている。

エンタープライズ ワークスペースの健全性: 攻撃の証拠が PR の説明とワークフロー アーティファクトにきれいに埋め込まれ、コード commit が純粋に保たれます。

次のステップ

🚀 CodeMender の学習を続ける:

パート 1: CodeMender でアプリケーションを保護する - 自律的なリポジトリの脆弱性検出、PoC エクスプロイトの検証、ローカルパッチの合成をマスターします。

ローカルでのシフトレフトとサーバーレス クラウド ネイティブ CI / CD: Google Cloud Build(cloudbuild.yaml)とローカル Git の commit 前フック(cm find . --diff --staged)の公式 CI / CD ガイドのリファレンス実装を確認します。

📖 ドキュメントとリソースを確認する:

Google Cloud CodeMender CI / CD 統合公式ガイド

Google Cloud CodeMender の公式ドキュメント

CodeMender GitHub Actions スターター テンプレート リポジトリ

Google Cloud Workload Identity 連携のドキュメント

💡 独自のリポジトリに適用する:

スターター ワークフローをフォークし、CodeMender で組織の Python、Go、Java、Rust、Node.js リポジトリを保護しましょう。