1. 事前準備
歡迎參加「使用 CodeMender 保護 CI/CD 管道」程式碼實驗室。
在現代軟體推送流程中,靜態分析工具 (例如 CodeQL) 是找出已知語法模式的必備工具,但往往會遺漏隱藏在商業邏輯深處的細微安全漏洞,並產生大量未經驗證的警示。
CodeMender (CLI 執行檔:cm) 可與現有的 SAST 工具搭配運作,部署 Google 的 Gemini 輔助安全推論代理,強化 CI/CD 管道:
找出複雜的商業邏輯缺陷:推論應用程式背景資訊和架構資料流程,不受限於僵化的靜態模式規則。
透過自我漏洞利用驗證,大幅減少偽陽性:在沙箱環境中動態驗證漏洞是否可遭利用,然後再向開發人員發出警示。
自動修復經驗證的發現項目:合成程式碼修補程式、根據測試套件進行驗證以防止迴歸,並提交可供審查的提取要求。
在本程式碼實驗室中,您將使用 GitHub Actions 和無金鑰 Google Cloud Workload Identity Federation (WIF),將 CodeMender 整合至 OWASP Juice Shop 存放區。
必要條件
- 建議:熟悉 CodeMender 的基本概念 (請參閱「使用 CodeMender 保護應用程式」)
- 對 GitHub Actions 工作流程、觸發條件和 YAML 語法有基本瞭解
- 熟悉 Git 指令和提取要求審查工作流程
- 具備 Google Cloud IAM 概念的基本知識 (服務帳戶、角色和 API)
- 熟悉常見的網頁應用程式安全漏洞 (例如 SQL 注入和 XSS)
課程內容
- 如何透過 Workload Identity Federation (WIF),在 GitHub Actions 和 Google Cloud 之間設定零信任無金鑰驗證
- 如何使用 CodeMender 和
gemini-3.8-flash建構自動化安全漏洞掃描工作流程 - 如何使用 OASIS SARIF v2.1.0 和原生 GitHub Actions 工作摘要發布可做為行動依據的安全性報告
- 如何建構自主修復工作流程,生成經過測試驗證的程式碼修補程式,並開啟提取要求供人工審查
- 如何強制執行自動化品質硬閘道 (
--fail-on) 和管道快取,實現高速持續安全
軟硬體需求
- 已啟用計費功能的 Google Cloud 專案,且具備專案擁有者/編輯者權限
- GitHub 帳戶,具備建立存放區、設定密鑰和管理動作的權限 (在步驟 3 中,您會使用 GitHub CLI 建立 OWASP Juice Shop GitHub 存放區的分支版本)。
2. 瞭解 CodeMender CI/CD 架構
在現代企業的 DevSecOps 中,AI 輔助資安功能不能只是手動桌面工具,必須同時扮演自動化守門員 (封鎖不安全的提取要求) 和自主共同開發人員 (直接在 Git 提出經過驗證的修補程式) 的角色。
為此,您將採用雙工作流程架構,並運用 Google Cloud Workload Identity Federation (WIF) 和 Gemini Enterprise 推論模型。
雙工作流程架構

這個管道不會將偵測和修復作業塞進單一龐大的指令碼,而是將安全性分為兩個獨立的專屬工作流程:
工作流程 | 主要觸發條件 | 核心職責 | 品質硬性限制 |
1. 安全漏洞掃描程式( | 提取要求、主要推送、每週 Cron、手動調度 | • 針對 PR 快速執行差異 AST 掃描 (約 15 秒),針對推送快速執行基準掃描 ( | 如果偵測到新引入的高或重大安全漏洞,則封鎖 PR 合併 ( |
2. Autonomous Remediator( | 手動觸發 ( | • 從掃描構件 ( | 在開啟 PR 前,確保正式環境差異乾淨 |
三大核心企業設計原則
在後續章節建構這些工作流程時,請牢記以下三大基礎架構要素:
🔑 零信任無金鑰驗證和預檢驗證:
GitHub Secrets 中未儲存任何長期有效的 Google Cloud 服務帳戶 JSON 金鑰。執行器會產生短期 OIDC 權杖,並透過 Google Cloud STS 換取效期 1 小時的臨時憑證、在 Git 簽出作業設定 persist-credentials: false,以及執行 cm health --strict 來驗證憑證、網路連線能力和 IAM 權限,然後才會使用模型配額。
⚡ 自動調整掃描路徑和舊版雜訊抑制:
CodeMender 不會對每個提取要求執行緩慢的完整存放區稽核,而是將每個 CI 事件轉送至最佳掃描模式:提取要求會在 15 秒內對修改過的檔案和 1 跳呼叫端觸發差異 AST 分析 (--diff="origin/$BASE_REF");主分支推送會執行單一工作階段快速基準掃描 (--quick);每週排程則會執行並行逐檔案深度稽核 (預設 cm find .)。提取要求未觸及的現有程式碼集安全漏洞會標示為 [LEGACY / UNTOUCHED];這些漏洞會顯示在 SARIF 報表中,但不會阻擋提取要求合併閘道,也不會觸發自動修正。
🛡️ 強韌、不中斷的安全觀測能力:
即使 --fail-on 結束並傳回代碼 1,封鎖不安全的 PR,使用 steps.scan.outputs.completed == 'true' 和 hashFiles('results.sarif') != '' 保護報告匯出和 SARIF 上傳步驟,仍可確保 OASIS SARIF 警告和工作摘要正常發布。如果執行作業因設定或容量錯誤而取消或中止 (10–60),則會直接略過匯出和上傳步驟。
3. 在 Cloud Shell 驗證並準備目標存放區
如要建立無金鑰驗證機制並執行自動化安全性管道,您必須擁有可存取的目標 GitHub 存放區。在本程式碼實驗室中,您將使用 OWASP Juice Shop (刻意設計成有安全漏洞的 Node.js 網頁應用程式),做為現成的安全性測試環境。
您將使用 Google Cloud Shell 預先安裝的 GitHub CLI (gh) 向 GitHub 驗證、自動擷取使用者詳細資料,並透過流暢的流程準備存放區。
步驟 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 Federation
在這個步驟中,您將在 Google Cloud Shell 使用 gcloud CLI 啟用必要的 API、建立專屬的 CI/CD 服務帳戶、設定 workload identity pool,並與 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 API
啟用 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 服務帳戶
建立具備最小權限的 Google Cloud 服務帳戶,專門用於執行 CI/CD 管道 (如果已有這類帳戶,可安全重複使用):
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 pool
建立 workload identity pool,管理 GitHub Actions 身分聲明 (如果專案中已有該集區,則會自動還原並啟用):
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 提供者,繫結核發者網址 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 Provider 的完整資源名稱,並儲存為環境變數,以便在下一個步驟中自動註冊:
# 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 存放區密鑰,並授予必要的自動化安全性掃描和自動修復提取要求工作流程權限。
您可以使用 GitHub CLI (gh),直接在 Cloud Shell 中調整這些設定,完全不必手動複製及貼上冗長的資源名稱。
步驟 1:使用 GitHub CLI 設定存放區 Secret
在 Cloud Shell 終端機執行下列指令,使用現行環境變數安全設定兩個必要的存放區 Secret:
# 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 工作流程會以唯讀權限執行,無法建立提取要求。在步驟 9,CodeMender 會自主生成並提交經過驗證的修復提取要求。
授予寫入權限,並直接透過 GitHub API 啟用提取要求建立功能:
[ -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),以及上游貢獻者 PR 範本,該範本會自動關閉以 master 為目標的 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 建構自動化安全漏洞掃描工作流程
在這個步驟中,您將編寫主要持續安全性掃描工作流程 (.github/workflows/codemender-scan.yml),對分支推送執行基準掃描、對提取要求執行差異閘道,以及將 SARIF 匯出至 GitHub 程式碼掃描。
步驟 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:修訂、推送及觸發 CI 掃描
提交工作流程變更,並直接推送至存放區的主要分支版本 (Juice Shop 的 master 或 main):
# 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)。
按一下頂端導覽列中的「動作」分頁標籤。
在左側欄的「Workflows」下方,選取「CodeMender Security Scan & SARIF Export」。
觸發或查看工作流程執行作業:
自動觸發:如果畫面上列出推送作業觸發的自動執行作業,請直接點選該作業,監控即時執行情況。
手動隨選觸發條件 (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 Setup ( 第 27 至 117 行):略過不受信任的外部分支和 dependabot[bot] PR、使用 persist-credentials: false 簽出、快取 ~/.local/bin/cm 和 ~/.codemender/state.db,並在耗用模型計費模式配額前執行 cm health --strict。
Headless Sandbox Boundaries (--sandbox=false --yes --bypass-warning):停用 Linux 使用者命名空間隔離功能 (在無權限的 GitHub Actions 容器內受限),同時保留工作區路徑邊界 (project_paths) 和 command_policy.yaml。
Exit-Code Guarded SARIF & Artifact Export ( 第 147 至 194 行):只有在 cm find 結束時傳回 0 (乾淨) 或 1 (達到 --fail-on 門檻) 時,才會設定 steps.scan.outputs.completed=true。這樣一來,即使 --fail-on 封鎖 PR,系統仍會發布 SARIF 報告 (cm report -f sarif,含 CVSS 嚴重程度分數)、$GITHUB_STEP_SUMMARY 表格 (cm report -f md) 和 codemender-findings.json 構件,但會略過設定或容量錯誤 (10–60) 的匯出作業,因此空白 SARIF 檔案不會關閉現有警示。
7. 檢查 GitHub 程式碼掃描警示和安全性資訊主頁
基準推送工作流程完成後,GitHub 會處理上傳的 SARIF 檔案,並填入 Actions 執行摘要和存放區的「Security」(安全性) 分頁。
步驟 1:檢查 GitHub Actions 的原生工作摘要
每次執行工作流程時,系統都會直接在 GitHub Actions 執行總覽中附加 Markdown 摘要表格 (cm report -f md):
在 GitHub 存放區中,按一下「Actions」分頁標籤。
選取已完成的 CodeMender Security Scan & SARIF Export 執行作業 (基準分支版本推送稽核作業會在發布 SARIF 發現項目後,顯示綠色 ✅ 勾號)。
向下捲動至「🛡️ CodeMender Security Scan Summary」部分,查看發現項目細目:
🔒 CodeMender 安全性報告
摘要
發現項目總數:28
嚴重性 | Count |
🔴 重大 | 6 |
🟠 高 | 16 |
🟡 中 | 6 |
狀態 | Count |
🔴 開放中 | 28 |
發現項目
ID | 嚴重性 | 信心 | 狀態 | 修正 | 檔案 | 標題 |
| 🔴 重大 | 100% | 開啟 | — |
| 在使用者個人資料中插入伺服器端程式碼,藉此執行遠端程式碼 |
| 🔴 重大 | 100% | 開啟 | — |
| 使用者驗證路徑中的 SQL 注入 |
| 🔴 重大 | 100% | 開啟 | — |
| 在 B2B 訂單處理中透過沙箱逸出執行程式碼 |
步驟 2:探索集中式程式碼掃描資訊主頁
在 GitHub 存放區頂端導覽列中,按一下「Security and quality」(安全性與品質) (或「Security」(安全性)) 分頁標籤。
在左側欄的「Findings」下方,選取「Code scanning」。
如果有多項工具處於啟用狀態,請將「工具」篩選器設為「CodeMender」 (is:open branch:master tool:CodeMender),檢查對應至原生 CVSS 嚴重性徽章的警告:
嚴重性徽章 | 安全漏洞標題 | 偵測到的位置 | 分支版本 |
🔴 重大 | 在使用者個人資料中插入伺服器端程式碼,藉此執行遠端程式碼 |
|
|
🔴 最高 | 使用者驗證路徑中的 SQL 注入 |
|
|
🔴 最高 | 在 B2B 訂單處理中透過沙箱逸出執行程式碼 |
|
|
按一下「SQL Injection in User Authentication Route」 (routes/login.ts:34),查看 Gemini 彙整的受感染資料流和根本原因分析。
8. 使用差異掃描功能封鎖不安全的提取要求
基準掃描在 OWASP Juice Shop 中發現 28 個既有安全漏洞。如果使用傳統靜態分析器,這 28 項舊有發現項目會導致日後所有提取要求失敗,直到所有待處理項目都修正為止,迫使團隊停用合併封鎖功能。
現在,您將測試 CodeMender 的 PR Differential AST Gate (--diff + --fail-on="CRITICAL,HIGH") 實際運作情形:開啟會引入新安全漏洞的提取要求,並觀察 CodeMender 如何隔離差異、在約 15 到 25 秒內封鎖合併,並標註確切的違規行。
步驟 1:開啟提取要求,引入指令插入漏洞
在 Cloud Shell (複製的存放區工作區) 建立功能分支版本,新增含有 OS 指令插入安全漏洞的 Express 路徑,然後對分支版本開啟提取要求:
[ -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 註解
開啟終端機輸出內容結尾處的提取要求網址。
捲動至提取要求對話頁面底部的「Checks」方塊,然後查看「Autonomous Code Vulnerability Scan」:
差異速度:cm find . --diff="origin/${PRIMARY_BRANCH}" 不會掃描存放區中所有 680 多個檔案 (約 3 到 5 分鐘),而是嚴格限制分析範圍,只掃描 routes/diagnostics.ts (和任何 1 躍點呼叫端),在約 15 到 25 秒內完成掃描。
隔離舊有技術債並禁止合併:Juice Shop 有 28 個未處理的舊有安全漏洞,但全數通過檢查,只有新引入的 CRITICAL 指令插入會觸發 --fail-on="CRITICAL,HIGH",並以狀態碼 1 (紅色 ❌) 結束,禁止合併 PR!
按一下提取要求頂端的「Files changed」分頁標籤:
由於工作流程的結束代碼防護機制 (steps.scan.outputs.completed == 'true') 仍會在 --fail-on 結束時匯出並上傳 results.sarif (代碼為 1),GitHub 程式碼掃描功能會直接在 routes/diagnostics.ts 的 execSync 下方,顯示內嵌的「CodeMender — Critical」安全性註解!
步驟 3:清理測試 PR 並返回主要分支版本
將 Cloud Shell 工作區切換回主要分支版本,並關閉不安全的測試提取要求,再繼續進行自主修復:
[ -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 工作流程
提取要求閘道已能防止新的安全漏洞進入程式碼集,接下來您將部署自主修復 (.github/workflows/codemender-remediate.yml),主動修正現有安全漏洞,並開啟可供審查的提取要求。
步驟 1:下載修復工作流程檔案
CodeMender 提供兩種修復範本,視存放區瀏覽權限而定:
公開/開放原始碼存放區 (codemender-remediate.yml):負責任揭露模式 - 連結至 GitHub 程式碼掃描 SARIF 警告,不公開揭露原始漏洞向量。
私人/企業存放區 (codemender-remediate-private-repo.yml):內部稽核證據模式 - 將驗證構件 (PLAN.md、REPORT.md、exploit.sh) 嵌入可收合的 PR 區段,同時從 Git 提交中排除。
將公開安全修復工作流程下載到存放區:
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:提交並觸發自主修復工作流程
提交修復工作流程並推送至主要分支版本:
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」分頁。
在左側欄的「Workflows」下方,選取「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 分鐘);如果指定單一 ID,則可在約 45 到 60 秒內完成。
按一下彈出式視窗中的綠色「Run workflow」按鈕,然後開啟執行中的工作。

codemender-remediate.yml 內部:自動合成修補程式
CodeMender 在雲端合成修補程式時 (約 30 到 45 秒),請查看 codemender-remediate.yml (第 111 到 184 行) 如何在執行器中自動執行修復作業:
Zero-Scan Resume (cm report import):從掃描工作流程下載 codemender-findings.json 構件,並匯入工作區 (cm report import -f codemender-findings.json),只有在沒有先前構件時,才會改用 cm find . --quick。
Headless Patch Synthesis (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/ 和暫存檔案,嚴格提交正式版程式碼變更:
--- 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 requests」分頁,開啟新的提取要求 (例如 🛡️ [CodeMender] Fix: SQL Injection in User Authentication Route)。
按一下「Files changed」,確認只有 routes/login.ts 經過修改,且所有內部執行階段中繼資料都已排除。
查看 PR 說明,其中直接連結至 GitHub 程式碼掃描 (SARIF) 警告,供維護人員簽核。
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,封存 HTML 報表構件,而非上傳 SARIF:
產生獨立 HTML 報表:在 Export Security Reports & Publish Job Summary 步驟中,使用 cm report -f html > codemender-audit-report.html 匯出 HTML 資訊主頁和 Markdown 摘要。
將報表封存為工作流程構件:將 Upload SARIF Report to GitHub Code Scanning (github/codeql-action/upload-sarif@v4) 步驟替換為 actions/upload-artifact@v4,並設定為上傳 codemender-audit-report.html (例如在構件名稱 codemender-security-report 下)。
在任何瀏覽器中本機檢查:直接從 GitHub Actions 工作流程執行摘要頁面下載 codemender-security-report.zip,解壓縮並在任何網路瀏覽器中開啟 codemender-audit-report.html,以便進行視覺分類。
私有存放區自主修復,並嵌入稽核證據
在私人企業存放區中,工程和資安團隊需要全面掌握根本原因分析、漏洞概念驗證和修復計畫,不必使用外部工具資訊主頁。不過,如果將漏洞利用指令碼 (exploit.sh) 或內部 Markdown 檔案 (PLAN.md、LOG.md) 提交至存放區分支版本,會導致 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。
Embedded PR Audit Collapsibles:將 REPORT.md、PLAN.md 和 exploit.sh 擷取至 /tmp/codemender-evidence/,並直接在 <details open> 可收合區塊中,將這些內容格式化為提取要求說明,方便審查人員一鍵檢查。
證據封存:透過 actions/upload-artifact@v4 封存完整的證據資料夾。
原始 Git 修訂版本:清除所有執行階段中繼資料和 .exploit 目錄,讓提取要求 Git 修訂版本僅包含正式版程式碼變更。
Workload Identity Federation (WIF) 疑難排解檢查清單
根據預設,google-github-actions/auth@v2 會在設定期間寫入本機聯合憑證設定檔,而實際的 OAuth 2.0 權杖交換作業會在 cm health --strict 或 cm find 啟動時進行。請使用下方檢查清單,診斷 HTTP 400 或 HTTP 403 驗證錯誤:
錯誤症狀 | 常見根本原因 | 驗證與修正 |
HTTP 403 ( | 服務帳戶缺少 | 確認 |
HTTP 400 ( | OIDC | 重新執行步驟 4 (步驟 1 和 6),確保 |
HTTP 400 (權杖交換時發生 | OIDC 提供者的 | 確認 |
設定完成後立即出現暫時性 HTTP 403 | 新建立的繫結可能需要 1 到 5 分鐘,才能完成全域 IAM 和 Workload Identity Federation 傳播。 | 等待 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 管道可立即區分安全性發現項目與設定或服務錯誤:
結束代碼 | 類別 | 常見根本原因和修復方式 |
| 成功 | 通過健康狀態檢查,或掃描完成且未發現任何阻礙。 |
| 發現項目 / 一般 |
|
|
| 無法交換 WIF OAuth/ADC 權杖 ( |
|
|
|
|
| 執行工具無法連上 |
|
| 服務帳戶在目標專案中缺少 |
|
| 預檢 |
|
| 代理已達並行活動任務上限,請稍後再重新執行工作流程。 |
如需其他執行階段錯誤的資訊,例如 Git 差異基準分支解析 (fetch-depth: 0)、資源傳播延遲,或 GitHub Actions 提取要求建立權限,請參閱官方 CodeMender CI/CD 疑難排解指南。
11. 清除資源
如要避免持續消耗資源,或想清除 Google Cloud 和 GitHub 環境中的測試設定,請按照下列步驟操作。
步驟 1:透過 gh CLI 移除 GitHub 存放區 Secret 並停用工作流程
使用 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 Federation 資源
Workload Identity 集區、提供者和服務帳戶在未交換權杖時,不會產生閒置費用。選擇符合工作流程的清除模式:
選項 A:暫停存取權 (如果打算在這個專案中重新執行,建議採用此選項):立即停用 OIDC 權杖交換,不會觸發 Google Cloud IAM 的 30 天虛刪除保留期,或服務帳戶 uniqueId 傳播延遲:
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 管道」程式碼實驗室!
您已成功使用 Google Cloud Workload Identity Federation、CodeMender 和 GitHub Actions,設計、建構及自動化正式環境等級的零信任 DevSecOps 管道。
您已瞭解的內容
零信任無金鑰驗證:透過 Workload Identity Federation (WIF),將臨時 GitHub OIDC 權杖繫結至 Google Cloud IAM,消除高風險、效期長的服務帳戶 JSON 金鑰。
PR 差異 AST 掃描和舊版雜訊抑制:將持續掃描範圍限定在修改過的檔案和依附元件 (--diff="origin/$BASE_REF"),隔離舊版技術債 ([LEGACY / UNTOUCHED]),將開發人員意見回饋循環時間控制在 15 秒內。
跨格式報表和原生工作摘要:結合 OASIS SARIF v2.1.0 集中管理 GitHub 程式碼掃描,並使用原生 Markdown (cm report -f md >> $GITHUB_STEP_SUMMARY) 格式,讓管理人員直接在 CI 工作流程執行頁面,即時查看相關資訊。
自主修復與人工介入迴路審查:從被動警示通知,轉為主動修復管道,自主合成建議的程式碼修補程式、根據迴歸測試套件進行驗證,並開啟含有稽核構件的審查提取要求,供工程師簽核。
自動化品質硬閘門:強制執行嚴格的分支保護和合併閘門 (--fail-on),防止危險安全漏洞進入正式環境。
構件導向狀態轉移和工作區隔離:使用 cm report import 在 CI 工作之間順暢轉移發現項目,同時使用 .git/info/exclude 保留原始 Git 記錄,並防止憑證外洩。
開發人員思維轉變
傳統 DevSecOps 做法 | CodeMender Autonomous CI/CD 管道 |
被動式警告傾印:掃描器會列印原始終端機記錄或靜態錯誤清單,將分類工作完全轉移給開發人員。 | Active Co-developer:整合經過驗證的程式碼修補程式,並開啟可合併的提取要求,供工程師簽署。 |
偽陽性率高:靜態 AST 啟發式演算法會標記數千個理論上的安全漏洞,但沒有可利用性的證據。 | 雙層漏洞驗證:動態沙箱測試生成 ( |
Secret 儲存空間有風險:儲存在 CI Secret 中的長期服務帳戶 JSON 金鑰,可能意外外洩,並導致憑證氾濫。 | 零信任 WIF:透過臨時 OIDC 權杖進行無金鑰驗證,並視需要與 Google Cloud STS 交換。 |
單體式重新掃描:每次修訂都會觸發完整存放區稽核,導致 CI 工作流程延遲,並浪費昂貴的權杖。 | 事件感知 AST 轉送:提取要求會執行 15 秒的差異 AST 掃描 ( |
存放區歷史記錄遭汙染:臨時漏洞利用指令碼和攻擊記錄直接提交至存放區分支。 | 企業工作區整潔:攻擊證據會乾淨地嵌入 PR 說明和工作流程構件中,保持程式碼提交純淨。 |
後續步驟
🚀 繼續 CodeMender 學習之旅:
第 1 部分:使用 CodeMender 保護應用程式 - 掌握自主存放區安全漏洞探索、PoC 漏洞利用驗證,以及本機修補程式合成。
在本機左移和無伺服器雲端原生 CI/CD:探索官方 CI/CD 指南的參考實作,瞭解 Google Cloud Build (cloudbuild.yaml) 和本機 Git 預先修訂掛鉤 (cm find . --diff --staged)。
📖 探索說明文件和資源:
官方 Google Cloud CodeMender CI/CD 整合指南
Google Cloud CodeMender 官方說明文件
CodeMender GitHub Actions Starter Template Repository
Google Cloud Workload Identity Federation 說明文件
💡 套用至自己的存放區:
建立入門工作流程的分支版本,並使用 CodeMender 保護貴組織的 Python、Go、Java、Rust 和 Node.js 存放區!