Bảo mật quy trình CI/CD bằng CodeMender

1. Trước khi bắt đầu

Chào mừng bạn đến với lớp học lập trình thực tế về Bảo mật quy trình CI/CD bằng CodeMender.

Trong quy trình phân phối phần mềm hiện đại, các công cụ phân tích tĩnh (chẳng hạn như CodeQL) là yếu tố cần thiết để phát hiện các mẫu cú pháp đã biết, nhưng thường bỏ sót các lỗ hổng bảo mật tinh vi ẩn sâu trong logic kinh doanh và tạo ra các cảnh báo gây nhiễu, chưa được xác minh.

CodeMender (tệp thực thi CLI: cm) cải thiện quy trình CI/CD của bạn (hoạt động cùng với các công cụ SAST hiện có) bằng cách triển khai các tác nhân suy luận bảo mật dựa trên Gemini của Google để:

Phát hiện các lỗi logic nghiệp vụ phức tạp: Lý giải về bối cảnh ứng dụng và luồng dữ liệu kiến trúc ngoài các quy tắc mẫu tĩnh cứng nhắc.

Giảm đáng kể số trường hợp dương tính giả thông qua quy trình xác minh tự khai thác: Chứng minh khả năng khai thác một cách linh động trong môi trường hộp cát trước khi cảnh báo cho nhà phát triển.

Tự động khắc phục các kết quả đã xác minh: Tổng hợp các bản vá mã, xác thực dựa trên bộ kiểm thử để ngăn chặn lỗi hồi quy và gửi các yêu cầu kéo sẵn sàng để xem xét.

Trong lớp học lập trình này, bạn sẽ tích hợp CodeMender vào kho lưu trữ OWASP Juice Shop bằng GitHub Actions và Liên kết danh tính cho khối lượng công việc (WIF) không dùng khoá của Google Cloud.

Điều kiện tiên quyết

  • Nên có: Hiểu biết cơ bản về các khái niệm của CodeMender (được đề cập trong bài viết Bảo mật ứng dụng bằng CodeMender)
  • Hiểu biết cơ bản về quy trình công việc, điều kiện kích hoạt và cú pháp YAML của GitHub Actions
  • Hiểu biết cơ bản về các lệnh Git và quy trình xem xét yêu cầu lấy dữ liệu
  • Kiến thức cơ bản về các khái niệm Cloud IAM của Google Cloud (Tài khoản dịch vụ, Vai trò và API)
  • Quen thuộc với các lỗ hổng bảo mật thường gặp trong ứng dụng web (chẳng hạn như Chèn SQL và XSS)

Kiến thức bạn sẽ học được

  • Cách định cấu hình phương thức xác thực không cần khoá theo mô hình không tin tưởng bất cứ điều gì giữa GitHub Actions và Google Cloud thông qua Workload Identity Federation (WIF)
  • Cách xây dựng quy trình quét lỗ hổng bảo mật tự động bằng CodeMender và gemini-3.8-flash
  • Cách xuất bản báo cáo bảo mật hữu ích bằng OASIS SARIF phiên bản 2.1.0 và Tóm tắt công việc của GitHub Actions gốc
  • Cách xây dựng quy trình khắc phục tự động để tạo các bản vá mã đã được kiểm thử và mở yêu cầu kéo để nhân viên đánh giá xem xét
  • Cách thực thi các cổng cứng tự động về chất lượng (--fail-on) và lưu vào bộ nhớ đệm quy trình để đảm bảo tính bảo mật liên tục ở tốc độ cao

Bạn cần có

  • Một dự án trên đám mây của Google Cloud đã bật tính năng thanh toán và có quyền của Chủ sở hữu/Người chỉnh sửa dự án
  • Tài khoản GitHub có quyền tạo kho lưu trữ, định cấu hình Bí mật và quản lý Hành động (bạn phân nhánh Kho lưu trữ GitHub OWASP Juice Shop ở Bước 3 bằng GitHub CLI).

2. Tìm hiểu về cấu trúc CI/CD của CodeMender

Trong DevSecOps hiện đại của doanh nghiệp, bảo mật dựa trên AI không chỉ là một công cụ thủ công trên máy tính. Công cụ này phải hoạt động như một người gác cổng tự động (chặn các yêu cầu kéo không an toàn) và một nhà đồng phát triển tự động (đề xuất các bản vá đã xác minh trực tiếp vào Git).

Để đạt được mục tiêu này, bạn sẽ triển khai Kiến trúc quy trình làm việc kép dựa trên Workload Identity Federation (WIF) của Google Cloud và các mô hình suy luận của Gemini Enterprise.

Kiến trúc quy trình công việc kép

Kiến trúc quy trình CI/CD tự động của CodeMender

Thay vì nhồi nhét quy trình phát hiện và khắc phục vào một tập lệnh nguyên khối duy nhất, quy trình này tách biệt bảo mật thành hai quy trình riêng biệt, được xây dựng theo mục đích:

Quy trình làm việc

Điều kiện kích hoạt chính

Trách nhiệm cốt lõi

Ngưỡng chất lượng nghiêm ngặt

1. Trình quét lỗ hổng bảo mật(codemender-scan.yml)

Yêu cầu lấy dữ liệu, Đẩy dữ liệu chính, Cron hằng tuần, Gửi thủ công

• Chạy nhanh các bản quét AST vi sai trên PR (~15 giây), quét nhanh theo đường cơ sở khi đẩy (–quick) và kiểm tra sâu đồng thời theo lịch biểu• Xác thực trước trạng thái sẵn sàng thông qua cm health –strict• Tạo Tóm tắt công việc của Actions gốc và tải OASIS SARIF lên thẻ Bảo mật của GitHub

Chặn hợp nhất PR nếu phát hiện lỗ hổng bảo mật mới ở mức Cao hoặc Nghiêm trọng (–fail-on)

2. Autonomous Remediator(codemender-remediate.yml)

Kích hoạt thủ công (workflow_dispatch), Cron hằng đêm

• Tiếp tục trạng thái từ cấu phần phần mềm quét (cm report import) và state.db• Tổng hợp các bản vá bằng lý luận của Gemini• Duy trì ranh giới không gian làm việc sạch sẽ và gửi các Yêu cầu kéo sẵn sàng để xem xét

Đảm bảo các điểm khác biệt trong bản phát hành chính thức được rõ ràng trước khi mở PR

Ba nguyên tắc thiết kế cốt lõi cho doanh nghiệp

Khi bạn xây dựng các quy trình công việc này trong các phần sắp tới, hãy lưu ý đến 3 trụ cột kiến trúc nền tảng sau:

🔑 Xác thực không cần khoá theo nguyên tắc Zero-Trust và xác thực trước khi gửi yêu cầu:

Không có khoá JSON dài hạn nào của Tài khoản dịch vụ Google Cloud được lưu trữ trong GitHub Secrets. Trình chạy tạo mã thông báo OIDC ngắn hạn được trao đổi qua Google Cloud STS để lấy thông tin xác thực tạm thời trong 1 giờ, đặt persist-credentials: false trên các lần kiểm tra Git và chạy cm health --strict để xác minh thông tin xác thực, khả năng kết nối mạng và quyền IAM trước khi sử dụng hạn mức mô hình.

⚡ Định tuyến quét thích ứng và khử tiếng ồn cũ:

Thay vì chạy quy trình kiểm tra toàn bộ kho lưu trữ chậm chạp trên mọi yêu cầu kéo, CodeMender sẽ định tuyến từng sự kiện CI đến chế độ quét tối ưu: Yêu cầu kéo sẽ kích hoạt quy trình phân tích AST vi sai (--diff="origin/$BASE_REF") trên các tệp đã sửa đổi và phương thức gọi 1 bước trong chưa đầy 15 giây; các lệnh đẩy nhánh chính sẽ chạy quy trình quét cơ sở nhanh trong một phiên (--quick); và lịch biểu hằng tuần sẽ chạy quy trình kiểm tra sâu đồng thời theo từng tệp (mặc định là cm find .). Các lỗ hổng bảo mật đã có từ trước trong cơ sở mã mà yêu cầu kéo không tác động đến sẽ được gắn nhãn [LEGACY / UNTOUCHED]; các lỗ hổng này sẽ xuất hiện trong báo cáo SARIF để dễ nhận biết, nhưng không chặn cổng hợp nhất yêu cầu kéo và không kích hoạt tính năng tự động sửa lỗi.

🛡️ Khả năng ghi nhận bảo mật không chặn linh hoạt:

Ngay cả khi --fail-on thoát bằng mã 1 để chặn một PR không an toàn, việc bảo vệ các bước xuất báo cáo và tải SARIF lên bằng steps.scan.outputs.completed == 'true' và hashFiles('results.sarif') != '' sẽ đảm bảo rằng các cảnh báo OASIS SARIF và Tóm tắt công việc vẫn được xuất bản, đồng thời bỏ qua bước xuất và tải lên nếu một lần chạy bị huỷ hoặc bị huỷ do lỗi thiết lập hoặc lỗi dung lượng (10–60).

3. Xác thực và chuẩn bị kho lưu trữ đích trong Cloud Shell

Để thiết lập quy trình xác thực không cần khoá và chạy quy trình bảo mật tự động, bạn cần có một kho lưu trữ GitHub mục tiêu mà bạn sở hữu và có thể truy cập. Trong lớp học lập trình này, bạn sẽ sử dụng OWASP Juice Shop (một ứng dụng web Node.js có lỗ hổng bảo mật có chủ đích) làm môi trường thử nghiệm bảo mật chìa khoá trao tay.

Bạn sẽ sử dụng GitHub CLI (gh) được cài đặt sẵn trong Google Cloud Shell để xác thực với GitHub, tự động thu thập thông tin chi tiết về người dùng và chuẩn bị kho lưu trữ trong một quy trình tinh gọn.

Bước 1: Mở Cloud Shell và xác thực GitHub CLI

Mở Google Cloud Console và kích hoạt Cloud Shell (biểu tượng >_ trong thanh điều hướng trên cùng).

Xác thực GitHub CLI (gh) để định cấu hình quản lý thông tin xác thực Git:

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

Làm theo hướng dẫn trên màn hình:

Sao chép mã dùng một lần gồm 8 ký tự được in trong Cloud Shell (ví dụ: 1234-ABCD).

Nhấn phím Enter để mở https://github.com/login/device trong trình duyệt.

Dán mã rồi nhấp vào Authorize github (Uỷ quyền cho GitHub).

Bước 2: Xuất biến động và phân nhánh OWASP Juice Shop

Chạy các lệnh sau trong Cloud Shell để tự động ghi lại tên người dùng GitHub của bạn và chuẩn bị kho lưu trữ:

# 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. Định cấu hình tính năng Liên kết Workload Identity của Google Cloud thông qua gcloud

Trong bước này, bạn sẽ sử dụng CLI gcloud trong Google Cloud Shell để bật các API cần thiết, tạo Tài khoản dịch vụ CI/CD chuyên dụng, thiết lập Workload Identity Pool và thiết lập mối quan hệ tin cậy OIDC với kho lưu trữ GitHub (${GITHUB_REPOSITORY}).

Bước 1: Thiết lập biến môi trường Google Cloud

Trong cửa sổ dòng lệnh Cloud Shell (bên trong không gian làm việc của kho lưu trữ đã sao chép), hãy ghi lại Mã dự án Google Cloud đang hoạt động, xác minh biến kho lưu trữ GitHub và xác định tên tài nguyên 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

Bước 2: Bật các Cloud APIs của Google Cloud cần thiết

Bật IAM API, Security Token Service API, IAM Credentials API, Agent Platform API và Resource Manager API:

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

Bước 3: Tạo tài khoản dịch vụ CI/CD chuyên dụng

Tạo một Tài khoản dịch vụ Google Cloud có đặc quyền tối thiểu dành riêng cho việc thực thi quy trình CI/CD (sử dụng lại một cách an toàn nếu tài khoản đó đã tồn tại):

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}"

Bước 4: Cấp quyền IAM cho Nền tảng tác nhân

Cấp vai trò roles/aiplatform.user (Người dùng nền tảng tác nhân) cho Tài khoản dịch vụ để tài khoản này có thể giao tiếp với Nền tảng tác nhân Gemini Enterprise:

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

Bước 5: Tạo nhóm Workload Identity

Tạo nhóm Workload Identity để quản lý các câu nhận định về danh tính của GitHub Actions (hoặc tự động khôi phục và bật nhóm này nếu nhóm đã tồn tại trong dự án của bạn):

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

Bước 6: Tạo nhà cung cấp Workload Identity bằng GitHub OIDC

Tạo (hoặc cập nhật) Nhà cung cấp OIDC trong nhóm, liên kết URL của tổ chức phát hành https://token.actions.githubusercontent.com và liên kết các câu nhận định về mã thông báo GitHub với các thuộc tính STS của Google:

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

Bước 7: Cho phép kho lưu trữ GitHub mạo danh tài khoản dịch vụ

Liên kết vai trò roles/iam.workloadIdentityUser để cho phép mã thông báo bắt nguồn từ kho lưu trữ của bạn mạo danh Tài khoản dịch vụ của trình chạy CI và xác minh liên kết chính sách:

# 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

Bước 8: Truy xuất các giá trị cấu hình cho khoá bí mật của GitHub

Truy xuất tên tài nguyên đầy đủ của Workload Identity Provider và lưu trữ tên đó trong một biến môi trường để đăng ký tự động ở bước tiếp theo:

# 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. Định cấu hình khoá bí mật của kho lưu trữ GitHub và quyền đối với quy trình công việc

Sau khi cấp phép cho Google Cloud WIF, bạn sẽ định cấu hình Bí mật của kho lưu trữ GitHub và cấp các quyền cần thiết cho quy trình công việc để quét bảo mật tự động và tự động khắc phục các Yêu cầu kéo.

Bạn có thể định cấu hình các chế độ cài đặt này ngay trong Cloud Shell bằng GitHub CLI (gh), hoàn toàn không cần sao chép và dán tên tài nguyên dài theo cách thủ công.

Bước 1: Đặt khoá bí mật của kho lưu trữ bằng GitHub CLI

Trong dòng lệnh Cloud Shell, hãy chạy các lệnh sau để đặt hai kho lưu trữ bí mật bắt buộc một cách an toàn bằng cách sử dụng các biến môi trường đang hoạt động:

# 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}"

Bước 2: Cấp quyền cho quy trình làm việc đối với PR tự động

Theo mặc định, quy trình GitHub Actions chạy với quyền chỉ đọc và không thể tạo Yêu cầu lấy dữ liệu. Ở Bước 9, CodeMender sẽ tự động tạo và gửi các Yêu cầu kéo khắc phục đã được xác minh.

Cấp quyền ghi và cho phép tạo yêu cầu gộp trực tiếp thông qua API GitHub:

[ -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

Bước 3: Tắt các quy trình công việc Juice Shop kế thừa từ thượng nguồn

Việc phân nhánh OWASP Juice Shop sẽ chuyển hơn 16 quy trình CI ngược dòng (chẳng hạn như PR Compliance Check, CI/CD Pipeline và CodeQL Scan) cùng với mẫu PR của người đóng góp ngược dòng tự động đóng các PR nhắm đến master. Tắt tất cả quy trình công việc không phải của CodeMender thông qua GitHub CLI và xoá các tệp ngược dòng trên máy để nhánh của bạn chỉ chạy các quy trình công việc của 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. Xây dựng quy trình quét lỗ hổng bảo mật tự động bằng SARIF

Trong bước này, bạn sẽ tạo quy trình quét bảo mật liên tục chính (.github/workflows/codemender-scan.yml) để chạy quy trình quét cơ sở khi đẩy nhánh, cổng vi sai trên Yêu cầu kéo và xuất SARIF sang GitHub Code Scanning.

Bước 1: Tải quy trình quét của CodeMender xuống

Tải codemender-scan.yml xuống từ kho lưu trữ khởi đầu vào .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

Bước 2: Cam kết, đẩy và kích hoạt tính năng quét CI

Xác nhận các thay đổi về quy trình công việc và đẩy trực tiếp vào nhánh chính của kho lưu trữ (master cho Juice Shop hoặc 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)

Trên trình duyệt:

Chuyển đến kho lưu trữ GitHub đã phân nhánh của bạn: https://github.com/YOUR_GITHUB_USER/juice-shop (ví dụ: https://github.com/octocat/juice-shop).

Nhấp vào thẻ Actions (Hành động) trong thanh điều hướng trên cùng.

Trong thanh bên trái, trong phần Workflows, hãy chọn Quét bảo mật CodeMender và xuất SARIF.

Kích hoạt hoặc xem quá trình thực thi quy trình công việc:

Trình kích hoạt tự động: Nếu một lần chạy tự động do lệnh đẩy của bạn kích hoạt được liệt kê, hãy nhấp trực tiếp vào lần chạy đó để theo dõi quá trình thực thi trực tiếp.

Trình kích hoạt theo yêu cầu thủ công (workflow_dispatch): Nếu chưa có lần chạy nào bắt đầu, hãy nhấp vào nút Run workflow ▾ (Chạy quy trình công việc ▾) ở bên phải, đảm bảo bạn đã chọn Branch: master (bỏ đánh dấu hộp deep_scan để chạy quy trình quét nhanh --quick theo tiêu chuẩn cơ sở) rồi nhấp vào nút Run workflow (Chạy quy trình công việc) màu xanh lục.

Nhấp vào lần chạy đang thực thi rồi chọn Autonomous Code Vulnerability Scan (Quét lỗ hổng bảo mật tự động trong mã) để xem quy trình làm việc khởi động theo thời gian thực.

Bên trong codemender-scan.yml: Định tuyến quét dựa trên sự kiện

Trong khi quá trình quét cơ sở --quick chạy trên đám mây (khoảng 3 đến 5 phút), hãy kiểm tra cách codemender-scan.yml (dòng 118 đến 155) định tuyến từng sự kiện GitHub đến chế độ quét chuyên dụng bên trong trình chạy:

# 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

Thiết lập trình chạy được tăng cường bảo mật ( dòng 27–117): Bỏ qua nhánh bên ngoài không đáng tin cậy và PR dependabot[bot], kiểm tra bằng persist-credentials: false, lưu ~/.local/bin/cm và ~/.codemender/state.db vào bộ nhớ đệm, đồng thời chạy cm health --strict trước khi sử dụng hạn mức mô hình.

Headless Sandbox Boundaries (--sandbox=false --yes --bypass-warning): Tắt tính năng tách biệt không gian tên người dùng Linux (bị hạn chế trong các vùng chứa GitHub Actions không có đặc quyền) trong khi vẫn thực thi ranh giới đường dẫn không gian làm việc (project_paths) và command_policy.yaml.

Xuất SARIF và cấu phần phần mềm được bảo vệ bằng mã thoát ( dòng 147–194): Đặt steps.scan.outputs.completed=true một cách nghiêm ngặt khi cm find thoát bằng 0 (sạch) hoặc 1 (đạt ngưỡng --fail-on). Điều này đảm bảo rằng các báo cáo SARIF (cm report -f sarif có điểm mức độ nghiêm trọng theo CVSS), bảng $GITHUB_STEP_SUMMARY (cm report -f md) và cấu phần phần mềm codemender-findings.json vẫn xuất bản khi --fail-on chặn một PR, đồng thời bỏ qua việc xuất khi có lỗi thiết lập hoặc lỗi dung lượng (10–60) để các tệp SARIF trống không bao giờ đóng các cảnh báo hiện có.

7. Kiểm tra cảnh báo quét mã và trang tổng quan bảo mật của GitHub

Sau khi quy trình đẩy cơ sở hoàn tất, GitHub sẽ xử lý tệp SARIF đã tải lên và điền cả phần tóm tắt về quá trình chạy Hành động và thẻ Bảo mật của kho lưu trữ.

Bước 1: Kiểm tra bản tóm tắt công việc gốc trên GitHub Actions

Mỗi lần chạy quy trình làm việc sẽ thêm một bảng tóm tắt Markdown (cm report -f md) trực tiếp vào thông tin tổng quan về lần chạy GitHub Actions:

Trong kho lưu trữ GitHub, hãy nhấp vào thẻ Actions (Hành động).

Chọn lần chạy CodeMender Security Scan & SARIF Export (Quét bảo mật và xuất SARIF bằng CodeMender) đã hoàn tất (quá trình kiểm tra đẩy nhánh cơ sở sẽ kết thúc bằng dấu kiểm ✅ màu xanh lục sau khi xuất bản kết quả SARIF).

Di chuyển xuống phần 🛡️ Tóm tắt kết quả quét bảo mật của CodeMender để kiểm tra thông tin chi tiết về kết quả:

🔒 Báo cáo bảo mật của CodeMender

Tóm tắt

Tổng số phát hiện: 28

Mức độ nghiêm trọng

Số lượng

🔴 QUAN TRỌNG

6

🟠 CAO

16

🟡 TRUNG BÌNH

6

Trạng thái

Số lượng

🔴 MỞ

28

Kết quả

Mã nhận dạng

Mức độ nghiêm trọng

Độ tin cậy

Trạng thái

Khắc phục

Tệp

Tiêu đề

c1b96b9a

🔴 QUAN TRỌNG

100%

MỞ

—

routes/userProfile.ts

Thực thi mã từ xa thông qua việc chèn mã phía máy chủ trong hồ sơ người dùng

cd47b38a

🔴 QUAN TRỌNG

100%

MỞ

—

routes/login.ts

Chèn SQL vào tuyến xác thực người dùng

a47a9e45

🔴 QUAN TRỌNG

100%

MỞ

—

routes/b2bOrder.ts

Thực thi mã từ xa thông qua Sandbox Escape trong quy trình xử lý đơn đặt hàng B2B

Bước 2: Khám phá trang tổng quan tập trung về tính năng Quét mã

Trên thanh điều hướng trên cùng của kho lưu trữ GitHub, hãy nhấp vào thẻ Security and quality (Bảo mật và chất lượng) (hoặc Security (Bảo mật)).

Trong thanh bên trái, trong phần Findings (Kết quả), hãy chọn Code scanning (Quét mã).

Nếu có nhiều công cụ đang hoạt động, hãy lọc Công cụ thành CodeMender (is:open branch:master tool:CodeMender) để kiểm tra các cảnh báo được liên kết với huy hiệu mức độ nghiêm trọng CVSS gốc:

Huy hiệu mức độ nghiêm trọng

Tiêu đề lỗ hổng bảo mật

Vị trí được phát hiện

Branch

🔴 Rất quan trọng

Thực thi mã từ xa thông qua việc chèn mã phía máy chủ trong hồ sơ người dùng

routes/userProfile.ts:58

master

🔴 Rất quan trọng

Chèn SQL vào tuyến xác thực người dùng

routes/login.ts:34

master

🔴 Rất quan trọng

Thực thi mã từ xa thông qua Sandbox Escape trong quy trình xử lý đơn đặt hàng B2B

routes/b2bOrder.ts:21

master

Nhấp vào SQL Injection in User Authentication Route (Chèn SQL trong tuyến xác thực người dùng) (routes/login.ts:34) để xem xét luồng dữ liệu bị can thiệp và thông tin Phân tích nguyên nhân gốc do Gemini tổng hợp.

8. Chặn một Yêu cầu lấy dữ liệu không an toàn bằng tính năng quét vi sai

Quá trình quét cơ sở đã phát hiện 28 lỗ hổng bảo mật tồn tại từ trước trong OWASP Juice Shop. Với các trình phân tích tĩnh truyền thống, 28 kết quả cũ đó sẽ khiến mọi Yêu cầu gộp trong tương lai đều không thành công cho đến khi toàn bộ tồn đọng được khắc phục, buộc các nhóm phải tắt tính năng chặn hợp nhất.

Bây giờ, bạn sẽ thử nghiệm Cổng AST vi sai cho yêu cầu kéo (--diff + --fail-on="CRITICAL,HIGH") của CodeMender trong thực tế: mở một Yêu cầu kéo gây ra lỗ hổng bảo mật mới và xem CodeMender tách biệt phần khác biệt, chặn việc hợp nhất trong khoảng 15–25 giây và chú thích chính xác các dòng vi phạm.

Bước 1: Mở một Yêu cầu kéo có chứa lỗi chèn lệnh

Trong Cloud Shell (bên trong không gian làm việc của kho lưu trữ được sao chép), hãy tạo một nhánh tính năng, thêm một tuyến Express mới chứa lỗ hổng Chèn lệnh hệ điều hành và mở một Yêu cầu kéo đối với nhánh của bạn:

[ -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."

Bước 2: Xác minh cổng hợp nhất khác biệt và chú thích PR cùng dòng

Mở URL của Yêu cầu lấy dữ liệu được in ở cuối kết quả của dòng lệnh.

Di chuyển đến hộp Checks (Kiểm tra) ở cuối trang cuộc trò chuyện về Yêu cầu lấy dữ liệu và xem Autonomous Code Vulnerability Scan (Quét lỗ hổng bảo mật mã tự động):

Tốc độ Delta: Thay vì quét tất cả hơn 680 tệp trong kho lưu trữ (khoảng 3 – 5 phút), cm find . --diff="origin/${PRIMARY_BRANCH}" sẽ giới hạn phạm vi phân tích nghiêm ngặt ở routes/diagnostics.ts (và mọi phương thức gọi 1 bước), hoàn tất quá trình quét trong khoảng 15 – 25 giây.

Cách ly nợ kỹ thuật cũ và chặn hợp nhất: Không có lỗ hổng bảo mật cũ nào trong số 28 lỗ hổng bảo mật cũ chưa được xử lý của Juice Shop không vượt qua được quy trình kiểm tra. Chỉ có lỗ hổng Chèn lệnh mới được thêm vào CRITICAL kích hoạt --fail-on="CRITICAL,HIGH", thoát với mã trạng thái 1 (❌ màu đỏ) để chặn việc hợp nhất PR!

Nhấp vào thẻ Files changed (Tệp đã thay đổi) ở đầu Yêu cầu lấy dữ liệu:

Vì trình bảo vệ mã thoát của quy trình công việc (steps.scan.outputs.completed == 'true') vẫn xuất và tải results.sarif lên khi --fail-on thoát bằng mã 1, nên tính năng Quét mã của GitHub sẽ hiển thị chú thích bảo mật CodeMender — Nghiêm trọng ngay dưới execSync trong routes/diagnostics.ts!

Bước 3: Dọn dẹp PR thử nghiệm và quay lại nhánh chính

Chuyển không gian làm việc Cloud Shell của bạn về nhánh chính và đóng Yêu cầu kéo thử nghiệm không an toàn trước khi tiếp tục khắc phục tự động:

[ -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. Xây dựng quy trình khắc phục tự động và PR tự động

Giờ đây, khi cổng Yêu cầu kéo đã ngăn các lỗ hổng bảo mật mới xâm nhập vào toàn bộ mã nguồn, bạn sẽ triển khai tính năng Khắc phục tự động (.github/workflows/codemender-remediate.yml) để chủ động khắc phục các lỗ hổng bảo mật hiện có và mở các Yêu cầu kéo đã sẵn sàng để xem xét.

Bước 1: Tải tệp quy trình khắc phục xuống

CodeMender cung cấp hai mẫu khắc phục tuỳ thuộc vào chế độ hiển thị của kho lưu trữ:

Kho lưu trữ công khai/nguồn mở (codemender-remediate.yml): Chế độ tiết lộ có trách nhiệm – liên kết đến các cảnh báo SARIF của tính năng Quét mã trên GitHub mà không công khai các vectơ khai thác thô.

Kho lưu trữ riêng tư/doanh nghiệp (codemender-remediate-private-repo.yml): Chế độ bằng chứng kiểm tra nội bộ – nhúng các cấu phần xác minh (PLAN.md, REPORT.md, exploit.sh) vào các phần yêu cầu kéo có thể thu gọn, đồng thời loại trừ các cấu phần này khỏi các lệnh git commit.

Tải quy trình khắc phục an toàn công khai xuống kho lưu trữ của bạn:

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

Bước 2: Cam kết và kích hoạt quy trình khắc phục tự động

Cam kết và đẩy quy trình khắc phục vào nhánh chính:

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

Trong trình duyệt, hãy chuyển đến thẻ Actions (Hành động) trong kho lưu trữ GitHub.

Trong thanh bên trái, trong phần Workflows (Quy trình công việc), hãy chọn CodeMender Autonomous Security Remediation & Auto-PR (Khắc phục bảo mật tự động và PR tự động của CodeMender).

Nhấp vào trình đơn thả xuống Run workflow (Chạy quy trình công việc) màu xanh lục ở bên phải:

Use workflow from (Sử dụng quy trình làm việc từ): Đảm bảo bạn đã chọn nhánh mặc định (master).

Mã nhận dạng hoặc tiền tố cụ thể của kết quả cần khắc phục: Nhập tiền tố gồm 8 ký tự cho routes/login.ts đã ghi chú ở Bước 7 (ví dụ: cd47b38a). Nếu bạn để trống trường này, hệ thống sẽ chạy quy trình khắc phục hàng loạt cho tất cả các kết quả Nghiêm trọng và Cao đang mở (mất khoảng 10 đến 15 phút); nếu bạn nhắm đến một mã nhận dạng duy nhất, quy trình này sẽ hoàn tất trong khoảng 45 đến 60 giây.

Nhấp vào nút Run workflow (Chạy quy trình công việc) màu xanh lục bên trong cửa sổ bật lên rồi mở lần chạy đang thực thi.

Kích hoạt quy trình Khắc phục bảo mật tự động của CodeMender thông qua trình đơn thả xuống Chạy quy trình công việc

Bên trong codemender-remediate.yml: Tổng hợp bản vá tự động

Trong khi CodeMender tổng hợp bản vá trên đám mây (khoảng 30–45 giây), hãy kiểm tra cách codemender-remediate.yml (dòng 111–184) điều phối việc khắc phục bên trong trình chạy:

Tiếp tục không quét (cm report import): Tải cấu phần phần mềm codemender-findings.json xuống từ quy trình quét và nhập cấu phần phần mềm đó vào không gian làm việc (cm report import -f codemender-findings.json), chỉ quay lại cm find . --quick nếu không có cấu phần phần mềm nào trước đó.

Tổng hợp bản vá không có giao diện người dùng (cm fix): Ghim project_paths vào $GITHUB_WORKSPACE, chuyển < /dev/null để ngăn chặn tình trạng treo tương tác và truyền --no-reset trong các vòng lặp theo lô để các bản sửa lỗi tích luỹ được giữ nguyên trên các kết quả:

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

Clean Production Commits ( dòng 155–252): Xoá .cm_project, .exploit/ và các tệp tạm thời thông qua .git/info/exclude trước khi peter-evans/create-pull-request@v8 mở nhánh (codemender/auto-remediation-${{ github.run_id }}), chỉ cam kết các thay đổi về mã phát hành chính thức:

--- 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
+    })

Bước 3: Xem lại Yêu cầu lấy dữ liệu mới mở trên GitHub

Chuyển đến thẻ Pull requests (Yêu cầu lấy dữ liệu) trong kho lưu trữ của bạn rồi mở Pull Request (Yêu cầu lấy dữ liệu) mới (ví dụ: 🛡️ [CodeMender] Fix: SQL Injection in User Authentication Route).

Nhấp vào Files changed (Tệp đã thay đổi) để xác nhận rằng chỉ có routes/login.ts được sửa đổi, không bao gồm tất cả siêu dữ liệu thời gian chạy nội bộ.

Xem lại nội dung mô tả về yêu cầu kéo liên kết trực tiếp đến cảnh báo Quét mã GitHub (SARIF) để người bảo trì phê duyệt.

10. Khắc phục sự cố về các trường hợp hiếm gặp và kho lưu trữ riêng tư

Kho lưu trữ riêng tư không có GitHub Advanced Security (GHAS)

Các kho lưu trữ công khai trên GitHub được sử dụng miễn phí và không giới hạn tính năng nhập SARIF của GitHub Code Scanning. Tuy nhiên, nếu bạn triển khai quy trình này cho một Kho lưu trữ doanh nghiệp riêng tư không có giấy phép GitHub Advanced Security (GHAS) đang hoạt động, thì bước upload-sarif sẽ không thành công và có thông báo:

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

Giải pháp: Dự phòng báo cáo HTML tương tác độc lập

Trình tạo báo cáo HTML tích hợp sẵn của CodeMender (cm report -f html) tạo ra một trang tổng quan về bảo mật độc lập, có tính tương tác, bao gồm các thẻ chỉ số về mức độ nghiêm trọng, đoạn mã được làm nổi bật cú pháp kèm theo số dòng và trình xem khác biệt về bản vá cùng dòng mà không phụ thuộc vào web bên ngoài.

Để hỗ trợ các kho lưu trữ riêng tư không có giấy phép GHAS, hãy cập nhật .github/workflows/codemender-scan.yml để lưu trữ cấu phần phần mềm báo cáo HTML thay vì tải SARIF lên:

Tạo báo cáo HTML độc lập: Trong bước Export Security Reports & Publish Job Summary, hãy xuất trang tổng quan HTML cùng với bản tóm tắt Markdown bằng cm report -f html > codemender-audit-report.html.

Lưu trữ báo cáo dưới dạng cấu phần phần mềm của quy trình công việc: Thay thế bước Upload SARIF Report to GitHub Code Scanning (github/codeql-action/upload-sarif@v4) bằng actions/upload-artifact@v4 được định cấu hình để tải codemender-audit-report.html lên (ví dụ: dưới tên cấu phần phần mềm codemender-security-report).

Kiểm tra cục bộ trong bất kỳ trình duyệt nào: Tải codemender-security-report.zip trực tiếp từ trang tóm tắt về quá trình chạy quy trình GitHub Actions, giải nén và mở codemender-audit-report.html trong bất kỳ trình duyệt web nào để phân loại trực quan.

Tự động khắc phục kho lưu trữ riêng tư bằng bằng chứng kiểm tra được nhúng

Trong kho lưu trữ riêng tư của công ty, các nhóm kỹ thuật và bảo mật cần có thông tin đầy đủ về việc phân tích nguyên nhân gốc, bằng chứng về tính khả thi của việc khai thác và kế hoạch khắc phục mà không cần đến trang tổng quan của công cụ bên ngoài. Tuy nhiên, việc đưa tập lệnh khai thác (exploit.sh) hoặc tệp markdown nội bộ (PLAN.md, LOG.md) vào nhánh kho lưu trữ sẽ làm lộn xộn nhật ký git và có thể kích hoạt cảnh báo sai từ các trình quét bảo mật khác.

Để giải quyết vấn đề này, hãy triển khai Quy trình khắc phục kho lưu trữ riêng tư (codemender-remediate-private-repo.yml) chuyên biệt:

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)

Cách hoạt động của tính năng khắc phục kho lưu trữ riêng tư

Xác minh PoC động (cm verify): Tổng hợp và kiểm thử một lỗ hổng bảo mật đang hoạt động trước khi tạo bản sửa lỗi để xác nhận khả năng khai thác, tự động bỏ qua cm fix nếu quy trình xác minh đánh dấu một phát hiện không thể khai thác là DISMISSED.

Embedded PR Audit Collapsibles: Trích xuất REPORT.md, PLAN.md và exploit.sh vào /tmp/codemender-evidence/ và định dạng trực tiếp vào nội dung mô tả Yêu cầu kéo bên trong các khối có thể thu gọn <details open> để người đánh giá kiểm tra bằng một lần nhấp.

Lưu trữ cấu phần phần mềm: Lưu trữ toàn bộ thư mục bằng chứng thông qua actions/upload-artifact@v4.

Pristine Git Commits (Xác nhận Git nguyên sơ): Xoá tất cả siêu dữ liệu thời gian chạy và thư mục .exploit để lệnh xác nhận git của Yêu cầu kéo chỉ chứa các thay đổi về mã phát hành chính thức.

Danh sách kiểm tra để khắc phục sự cố về Liên kết Workload Identity (WIF)

Theo mặc định, google-github-actions/auth@v2 sẽ ghi tệp cấu hình thông tin xác thực liên kết cục bộ trong quá trình thiết lập và quá trình trao đổi mã thông báo OAuth 2.0 thực tế sẽ diễn ra khi cm health --strict hoặc cm find bắt đầu. Hãy sử dụng danh sách kiểm tra bên dưới để chẩn đoán lỗi xác thực HTTP 400 hoặc HTTP 403:

Dấu hiệu lỗi

Nguyên nhân gốc phổ biến

Xác minh và khắc phục

HTTP 403 (iam.serviceAccounts.getAccessToken bị từ chối)

Thiếu liên kết roles/iam.workloadIdentityUser trên Tài khoản dịch vụ, mật khẩu GCP_SERVICE_ACCOUNT không chính xác hoặc iamcredentials.googleapis.com chưa được bật.

Xác nhận GCP_SERVICE_ACCOUNT khớp với codemender-ci-runner@.iam.gserviceaccount.com và chạy quy trình kiểm tra chính sách IAM bên dưới để xác minh mối liên kết principalSet.

HTTP 400 (unauthorized_client hoặc điều kiện thuộc tính bị từ chối)

Tên kho lưu trữ OIDC –attribute-condition (hoặc cách viết hoa) không khớp với kho lưu trữ GitHub kích hoạt quy trình công việc hoặc nhà cung cấp WIF bị vô hiệu hoá.

Chạy lại Bước 4 (Bước 1 và 6) để đảm bảo ${GITHUB_REPOSITORY} khớp chính xác với kiểu viết hoa owner/repo của bạn trên GitHub và –no-disabled được áp dụng.

HTTP 400 (invalid_grant khi trao đổi mã thông báo)

Ánh xạ –issuer-uri không đúng định dạng hoặc thiếu attribute.repository=assertion.repository trên nhà cung cấp OIDC.

Xác nhận rằng –issuer-uri được đặt chính xác thành https://token.actions.githubusercontent.com (không có dấu gạch chéo ở cuối).

Lỗi HTTP 403 tạm thời ngay sau khi thiết lập

Quá trình truyền tải IAM toàn cầu và Liên kết Workload Identity có thể mất từ 1 đến 5 phút đối với các liên kết mới tạo.

Chờ 1 – 2 phút rồi nhấp vào Re-run failed jobs (Chạy lại các công việc không thành công) trong GitHub Actions.

Để kiểm tra mối liên kết Workload Identity đang hoạt động trên Tài khoản dịch vụ CI/CD trong Cloud Shell, hãy chạy lệnh sau:

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

Xác nhận rằng kết quả liên kết roles/iam.workloadIdentityUser với 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

Khắc phục sự cố về mã thoát CLI và kiểm tra trước CI/CD

Các lệnh CodeMender (cm health --strict, cm find, cm verify và cm fix) trả về mã thoát tất định để quy trình CI/CD có thể phân biệt ngay kết quả bảo mật với lỗi thiết lập hoặc lỗi dịch vụ:

Mã thoát

Danh mục

Nguyên nhân gốc và cách khắc phục thường gặp

0

Thành công

Đã vượt qua bước kiểm tra tình trạng hoặc hoàn tất quá trình quét mà không phát hiện vấn đề nào gây cản trở.

1

Móc, chốt, khớp nối, dây/Tổng hợp

–fail-on phát hiện thấy lỗ hổng bảo mật CRITICAL hoặc HIGH đang chặn trên một PR (dự kiến sẽ không hợp nhất được).

10

credentials

Không trao đổi được mã thông báo WIF OAuth/ADC (400/401). Hãy xác minh GCP_WORKLOAD_IDENTITY_PROVIDER, GCP_SERVICE_ACCOUNT và mối liên kết roles/iam.workloadIdentityUser ở trên.

20

config

Cú pháp .codemender/config.yaml hoặc ~/.codemender/config.yaml không đúng định dạng.

30

reachability

Trình chạy không thể kết nối với aiplatform.googleapis.com (DNS, proxy, dịch vụ ngừng hoạt động hoặc VPC Service Controls).

40

authorization

Tài khoản dịch vụ thiếu roles/aiplatform.user trong dự án mục tiêu hoặc cloudresourcemanager.googleapis.com/aiplatform.googleapis.com bị vô hiệu hoá.

50

timeout

Quá trình kiểm tra cm health trước khi gửi đã vượt quá thời hạn 30 giây.

60

capacity

Tác nhân đã đạt đến giới hạn tác vụ hoạt động đồng thời; hãy chạy lại quy trình làm việc sau một khoảng thời gian ngắn.

Đối với các lỗi thời gian chạy khác (chẳng hạn như phân giải nhánh cơ sở khác biệt của Git (fetch-depth: 0), độ trễ truyền tài nguyên hoặc quyền tạo yêu cầu kéo của GitHub Actions), hãy tham khảo Hướng dẫn khắc phục sự cố CI/CD chính thức của CodeMender.

11. Dọn dẹp tài nguyên

Để ngăn chặn việc tiêu thụ tài nguyên liên tục hoặc dọn dẹp cấu hình kiểm thử trong môi trường Google Cloud và GitHub, hãy thực hiện các bước dọn dẹp sau.

Bước 1: Xoá khoá bí mật của kho lưu trữ GitHub và tắt quy trình công việc thông qua gh CLI

Sử dụng GitHub CLI (gh) để xoá hoàn toàn các bí mật của Actions trong kho lưu trữ và tắt quy trình công việc của 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

Bước 2: Vô hiệu hoá hoặc xoá tài nguyên Workload Identity Federation trên Google Cloud

Nhóm Workload Identity, nhà cung cấp và tài khoản dịch vụ sẽ không mất phí khi không hoạt động nếu không trao đổi mã thông báo. Chọn chế độ dọn dẹp phù hợp với quy trình làm việc của bạn:

Lựa chọn A – Tạm dừng quyền truy cập (Nên dùng nếu bạn dự định chạy lại trong dự án này): Tắt ngay tính năng trao đổi mã thông báo OIDC mà không kích hoạt chính sách giữ lại dữ liệu đã xoá tạm thời trong 30 ngày của Cloud IAM trên Google Cloud hoặc độ trễ khi truyền uniqueId của Tài khoản dịch vụ:

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

Phương án B – Gỡ bỏ hoàn toàn: Xoá Nhà cung cấp WIF, Nhóm (được giữ lại ở trạng thái DELETED trong 30 ngày) và Tài khoản dịch vụ chuyên dụng:

# 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. Xin chúc mừng

Xin chúc mừng! Bạn đã hoàn thành lớp học lập trình Bảo mật quy trình CI/CD bằng CodeMender!

Bạn đã thiết kế, xây dựng và tự động hoá thành công một quy trình DevSecOps không tin tưởng, cấp độ sản xuất bằng cách sử dụng Workload Identity Liên kết trên Google Cloud, CodeMender và GitHub Actions.

Nội dung bạn đã học

Xác thực không cần khoá theo mô hình Zero-Trust: Loại bỏ các khoá JSON rủi ro, có thời hạn dài của tài khoản dịch vụ bằng cách liên kết mã thông báo OIDC tạm thời của GitHub với Google Cloud IAM thông qua Workload Identity Federation (WIF).

Quét AST vi sai trong PR và khử tiếng ồn cũ: Quét liên tục trong phạm vi các tệp đã sửa đổi và các phần phụ thuộc (--diff="origin/$BASE_REF"), tách biệt nợ kỹ thuật cũ ([LEGACY / UNTOUCHED]) để giữ cho vòng hồi tiếp của nhà phát triển dưới 15 giây.

Báo cáo nhiều định dạng và tóm tắt công việc gốc: Kết hợp OASIS SARIF phiên bản 2.1.0 để quét mã GitHub tập trung với Markdown gốc (cm report -f md >> $GITHUB_STEP_SUMMARY) để hiển thị ngay lập tức cho người điều hành trực tiếp trên các trang chạy quy trình làm việc CI.

Khắc phục tự động có sự tham gia của con người: Chuyển từ thông báo cảnh báo thụ động sang quy trình khắc phục chủ động, tự động tổng hợp các bản vá mã đề xuất, xác minh dựa trên bộ kiểm thử hồi quy và mở các yêu cầu kéo (pull request) để xem xét kèm theo các dữ liệu kiểm tra để kỹ sư phê duyệt.

Cổng kiểm soát chất lượng tự động: Thực thi các biện pháp bảo vệ nhánh nghiêm ngặt và cổng hợp nhất (--fail-on) để ngăn chặn các lỗ hổng bảo mật nguy hiểm xâm nhập vào môi trường thực tế.

Chuyển trạng thái dựa trên cấu phần phần mềm và tách biệt không gian làm việc: Chuyển các kết quả một cách liền mạch giữa các công việc CI bằng cm report import, đồng thời sử dụng .git/info/exclude để giữ nguyên nhật ký Git và ngăn chặn rò rỉ thông tin xác thực.

Thay đổi tư duy của nhà phát triển

Phương pháp DevSecOps truyền thống

Quy trình CI/CD tự động của CodeMender

Đưa ra cảnh báo thụ động: Trình quét in nhật ký thiết bị đầu cuối thô hoặc danh sách lỗi tĩnh, chuyển hoàn toàn gánh nặng phân loại sang nhà phát triển.

Active Co-developer: Tổng hợp các bản vá mã đã xác minh và mở các Yêu cầu gộp sẵn sàng để kỹ sư phê duyệt.

Tỷ lệ dương tính giả cao: Các phương pháp phỏng đoán AST tĩnh gắn cờ hàng nghìn lỗ hổng lý thuyết mà không có bằng chứng về khả năng khai thác.

Xác minh lỗ hổng bảo mật theo 2 cấp: Tạo thử nghiệm hộp cát động (cm verify) để xác nhận lỗ hổng bảo mật thực tế, loại bỏ kết quả dương tính giả.

Lưu trữ bí mật có rủi ro: Khoá JSON của tài khoản dịch vụ có thời hạn dài được lưu trữ trong bí mật CI có nguy cơ bị rò rỉ ngẫu nhiên và rò rỉ thông tin xác thực.

WIF không tin tưởng bất cứ điều gì: Xác thực không cần khoá thông qua mã thông báo OIDC tạm thời được trao đổi với STS của Google Cloud theo yêu cầu.

Quét lại toàn bộ: Mỗi lần xác nhận đều kích hoạt quy trình kiểm tra toàn bộ kho lưu trữ, làm chậm quy trình CI và lãng phí mã thông báo tốn kém.

Định tuyến AST dựa trên sự kiện: Yêu cầu kéo thực hiện quét AST vi sai trong 15 giây (–diff), trong khi cron chạy thực hiện kiểm tra sâu.

Lịch sử kho lưu trữ bị ô nhiễm: Các tập lệnh khai thác tạm thời và nhật ký tấn công được đưa trực tiếp vào các nhánh kho lưu trữ.

Vệ sinh không gian làm việc của doanh nghiệp: Bằng chứng tấn công được nhúng rõ ràng trong nội dung mô tả PR và cấu phần phần mềm của quy trình công việc, giúp các thay đổi về mã luôn rõ ràng.

Các bước tiếp theo

🚀 Tiếp tục hành trình tìm hiểu về CodeMender:

Phần 1: Bảo mật ứng dụng bằng CodeMender — Nắm vững quy trình tự động phát hiện lỗ hổng bảo mật trong kho lưu trữ, xác minh lỗ hổng bảo mật PoC và tổng hợp bản vá cục bộ.

Shift Left Locally & Serverless Cloud Native CI/CD: Khám phá các cách triển khai tham khảo trong hướng dẫn chính thức về CI/CD cho Google Cloud Build (cloudbuild.yaml) và Local Git Pre-commit Hooks (cm find . --diff --staged).

📖 Khám phá tài liệu và tài nguyên:

Hướng dẫn chính thức về cách tích hợp CodeMender của Google Cloud vào quy trình CI/CD

Tài liệu chính thức về CodeMender của Google Cloud

Kho lưu trữ mẫu khởi đầu cho GitHub Actions của CodeMender

Tài liệu về Liên kết danh tính cho khối lượng công việc trên Google Cloud

💡 Áp dụng cho kho lưu trữ của riêng bạn:

Tạo nhánh cho quy trình công việc khởi đầu và bảo mật các kho lưu trữ Python, Go, Java, Rust và Node.js của tổ chức bằng CodeMender!