ใช้ส่วนขยายความปลอดภัยของ Gemini CLI สำหรับการรีวิว PR ใน GitHub

1. บทนำ

ส่วนขยายความปลอดภัยของ Gemini CLI เป็นส่วนขยาย Gemini CLI แบบโอเพนซอร์สที่ Google สร้างขึ้น ซึ่งจะวิเคราะห์โค้ดเพื่อหาความเสี่ยงและช่องโหว่ด้านความปลอดภัย คุณใช้ส่วนขยายความปลอดภัยกับ Gemini CLI เพื่อระบุปัญหาด้านความปลอดภัยในเครื่องได้เช่นเดียวกับส่วนขยาย Gemini CLI อื่นๆ นอกจากนี้ คุณยังเรียกใช้เพื่อตรวจสอบคำขอ Pull ใน GitHub ได้ด้วย ในโค้ดแล็บนี้ เราจะอธิบายวิธีใช้ส่วนขยายความปลอดภัยในที่เก็บ GitHub

สิ่งที่คุณต้องทำ

  • กำหนดค่าการตรวจสอบสิทธิ์ที่ปลอดภัยจาก GitHub ไปยัง Google Cloud
  • สร้างเวิร์กโฟลว์ GitHub Actions ที่เรียกใช้ส่วนขยายความปลอดภัยของ Gemini CLI
  • เรียกใช้การตรวจสอบความปลอดภัยใน PR ใหม่หรือที่มีอยู่โดยใช้ GitHub Actions

สิ่งที่คุณจะได้เรียนรู้

  • วิธีใช้การเชื่อมโยงข้อมูลประจำตัวของเวิร์กโหลดสำหรับการตรวจสอบสิทธิ์ที่ปลอดภัยจาก GitHub Actions ไปยัง Google Cloud
  • ดูประโยชน์ของการใช้ Workload Identity Pool และผู้ให้บริการ Workload Identity แทนคีย์ Gemini API สำหรับการตรวจสอบสิทธิ์
  • วิธีทำการตรวจสอบความปลอดภัยด้วยคำขอให้รวมการเปลี่ยนแปลง
  • วิธีตีความการตรวจสอบความปลอดภัยที่ส่วนขยายความปลอดภัยส่งคืน

สิ่งที่คุณต้องมี

  • เว็บเบราว์เซอร์
  • บัญชีและที่เก็บ GitHub
  • โปรเจ็กต์ Google Cloud

Codelab นี้ออกแบบมาสำหรับนักพัฒนาซอฟต์แวร์ที่คุ้นเคยกับเวิร์กโฟลว์ CI/CD ใน GitHub คุณไม่จำเป็นต้องมีความคุ้นเคยกับ Gemini CLI หรือส่วนขยาย Gemini CLI หากต้องการดูวิธีการทำงานของส่วนขยาย โปรดดู Codelab เริ่มต้นใช้งานส่วนขยาย Gemini CLI

ในโค้ดแล็บนี้ คุณจะได้เรียนรู้วิธีตั้งค่าส่วนขยายความปลอดภัยของ Gemini CLI ในที่เก็บ GitHub เราจะไม่แนะนำโค้ดให้คุณเปิดคำขอส่งต่อที่เทียบกับที่เก็บเพื่อทริกเกอร์การค้นหาช่องโหว่ด้านความปลอดภัย

2. ก่อนเริ่มต้น

สร้างหรือเลือกโปรเจ็กต์

  1. ใน Google Cloud Console ให้เลือกหรือสร้างโปรเจ็กต์ Google Cloud ในหน้าตัวเลือกโปรเจ็กต์
  2. ตรวจสอบว่าได้เปิดใช้การเรียกเก็บเงินสำหรับโปรเจ็กต์ Cloud แล้ว ดูวิธียืนยันการเรียกเก็บเงิน
  3. เปิด Cloud Shell ซึ่งเป็นสภาพแวดล้อมบรรทัดคำสั่งที่ทำงานใน Google Cloud คลิกเปิดใช้งาน Cloud Shell ที่ด้านบนของคอนโซล Google Cloud

รูปภาพปุ่มเปิดใช้งาน Cloud Shell

  1. เมื่อเชื่อมต่อกับ Cloud Shell แล้ว ให้ตรวจสอบว่าคุณได้รับการตรวจสอบสิทธิ์และตั้งค่าโปรเจ็กต์เป็นรหัสโปรเจ็กต์ของคุณโดยใช้คำสั่งต่อไปนี้
gcloud auth list
  1. เรียกใช้คำสั่งต่อไปนี้เพื่อยืนยันว่าได้กำหนดค่าคำสั่ง gcloud ให้ใช้โปรเจ็กต์ของคุณแล้ว
gcloud config list project
  1. หากไม่ได้ตั้งค่าโปรเจ็กต์ ให้ใช้คำสั่งต่อไปนี้เพื่อตั้งค่า
gcloud config set project ${GOOGLE_CLOUD_PROJECT}

3. ตั้งค่าการตรวจสอบสิทธิ์จาก GitHub ไปยัง Google Cloud

วิธีการทำงาน

เวิร์กโฟลว์ GitHub Actions

การรวมระบบข้อมูลประจำตัวของเวิร์กโหลดเป็นวิธีที่แนะนำในการตรวจสอบสิทธิ์จาก GitHub Actions ไปยัง Google Cloud

  1. สำหรับเวิร์กโฟลว์ รัน งานของ GitHub Actions ทุกรายการ GitHub ในฐานะผู้ให้บริการข้อมูลประจำตัวภายนอกจะออก JWT (JSON Web Token) ที่ลงชื่อแล้ว โทเค็นนี้มี "การอ้างสิทธิ์" เช่น repository, workflow และ job_workflow_ref ซึ่งทำหน้าที่เป็นบัตรประจำตัวดิจิทัลสำหรับนักวิ่งคนนั้นๆ ในแล็บนี้ คุณจะได้สร้างเวิร์กโฟลว์ GitHub Actions ที่มีงานซึ่งใช้การดำเนินการ google-github-actions/run-gemini-cli ซึ่งจะขอ JWT จาก GitHub และส่งโทเค็นนี้ไปยัง Security Token Service (STS) ใน Google Cloud
  2. คุณจะกำหนดค่า Workload Identity Pool และผู้ให้บริการใน Google Cloud ได้โดยการตั้งค่า URL ผู้ออกเป็น URL ของบริการโทเค็น GitHub อย่างเป็นทางการ https://token.actions.githubusercontent.com และกำหนด "การแมปแอตทริบิวต์" ซึ่งโดยปกติจะรวมถึงชื่อที่เก็บและชื่อสาขา STS ของ Google Cloud จะตรวจสอบ JWT กับกฎของพูล Workload Identity หากทุกอย่างเป็นไปตามที่คาดไว้ รวมถึงการแมปแอตทริบิวต์ STS จะแลกเปลี่ยนโทเค็น GitHub เป็น Google Cloud Federated Access Token ที่มีอายุสั้น
  3. ตอนนี้การดำเนินการ google-github-actions/run-gemini-cli ในเวิร์กโฟลว์ GitHub Actions สามารถใช้ Google Cloud Federated Access Token ที่มีอายุสั้นเพื่อ "แอบอ้าง" บัญชีบริการที่เชื่อมต่อกับ Workload Identity Pool ได้แล้ว บัญชีบริการที่เชื่อมต่อต้องมีบทบาทและสิทธิ์ IAM ที่จำเป็นในการเข้าถึงทรัพยากรและบริการของ Google Cloud

ประโยชน์ของการใช้การเชื่อมโยงข้อมูลประจำตัวของเวิร์กโหลดผ่านคีย์ Gemini API

คุณสามารถตรวจสอบสิทธิ์การเรียกใช้ Gemini CLI ที่มาจาก GitHub Actions ได้โดยใช้คีย์ Gemini API ซึ่งเกี่ยวข้องกับการสร้างความลับของ GitHub Actions ใหม่ชื่อ GEMINI_API_KEY ที่มีค่าคีย์ที่เหมาะสม แต่เราไม่แนะนำให้ทำด้วยเหตุผลด้านความปลอดภัยต่อไปนี้

  • คีย์ API ของ Gemini อาจมีสิทธิ์แบบกว้างจากการเชื่อมโยงบทบาท IAM ที่เกี่ยวข้อง เมื่อถูกบุกรุกแล้ว ก็จะเปิดสิทธิ์เข้าถึงทรัพยากรและบริการของ Google Cloud ได้อย่างกว้างขวาง การรวมศูนย์ของ Workload Identity ใช้บัญชีบริการและโทเค็นเพื่อการเข้าถึงที่มีอายุสั้น ซึ่งจะช่วยเพิ่มความปลอดภัยในการตรวจสอบสิทธิ์ได้อย่างมาก
  • นอกจากนี้ การจัดการคีย์ API ของ Gemini ในวงกว้างยังเป็นเรื่องท้าทายด้วย การระบุว่าเวิร์กโฟลว์ใดใช้คีย์ที่เปิดเผยต้องใช้เวลา การหมุนเวียนคีย์ด้วยตนเองก็ใช้เวลาเช่นกัน ในทางกลับกัน คุณสามารถค้นหา แก้ไข และลบพูลและผู้ให้บริการ Workload Identity ที่เชื่อมโยงกับที่เก็บได้อย่างง่ายดายจาก Cloud Console
  • เมื่อใช้คีย์ API ของ Gemini คุณต้องตรวจสอบอีกครั้งเสมอว่าไม่ได้เปิดเผยคีย์โดยไม่ตั้งใจในบันทึกการเข้าถึงหรือบันทึกการแก้ไขข้อบกพร่อง เมื่อใช้การเชื่อมโยงข้อมูลประจำตัวของเวิร์กโหลด คุณจะไม่ต้องจัดเก็บข้อมูลลับของเวิร์กโฟลว์ GitHub Actions แต่จะจัดเก็บตัวแปรแทน ซึ่งมีความละเอียดอ่อนน้อยกว่าโดยธรรมชาติ

กำหนดค่า GitHub Actions และ Google Cloud

  1. ใน Cloud Shell ให้เข้าสู่ระบบบัญชี GitHub
gh auth login
  1. สร้างไฟล์ใหม่ setup_workload_identity.sh แล้วคัดลอกและวางโค้ดด้านล่างลงในไฟล์
set -e

# Colors for output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color

# Helper functions
print_info() {
    echo -e "${BLUE}ℹ️  $1${NC}"
}

print_success() {
    echo -e "${GREEN}✅ $1${NC}"
}

print_warning() {
    echo -e "${YELLOW}⚠️  $1${NC}"
}

print_error() {
    echo -e "${RED}❌ $1${NC}"
}

print_header() {
    echo -e "${BLUE}🚀 $1${NC}"
}

# Default values
GOOGLE_CLOUD_PROJECT=""
GOOGLE_CLOUD_LOCATION="global"
GITHUB_REPO=""
POOL_NAME=""
PROVIDER_NAME=""

# Show help
show_help() {
    cat << EOF
Universal Direct Workload Identity Federation Setup for GitHub Actions

USAGE:
    $0 --repo OWNER/REPO [OPTIONS]

REQUIRED:
    -r, --repo OWNER/REPO       GitHub repository (e.g., google/my-repo)
    -p, --project GOOGLE_CLOUD_PROJECT    Google Cloud project ID

OPTIONS:
    --pool-name NAME           Custom workload identity pool name (default: auto-generated)
    --provider-name NAME       Custom workload identity provider name (default: auto-generated)
    -h, --help                 Show this help

EXAMPLES:
    # Basic setup for a repository
    $0 --repo google/my-repo --project my-gcp-project

    # Custom pool name
    $0 --repo google/my-repo --project my-gcp-project --pool-name my-pool

    # Custom pool and provider names
    $0 --repo google/my-repo --project my-gcp-project --pool-name my-pool --provider-name my-provider

ABOUT DIRECT WORKLOAD IDENTITY FEDERATION:
    This script sets up Direct Workload Identity Federation (preferred method).
    - No intermediate service accounts required
    - Direct authentication from GitHub Actions to GCP resources
    - Maximum token lifetime of 10 minutes
    - You grant permissions directly to the Workload Identity Pool on GCP resources

EOF
}

# Parse command line arguments
while [[ $# -gt 0 ]]; do
    case $1 in
        -r|--repo)
            GITHUB_REPO="$2"
            shift 2
            ;;
        -p|--project)
            GOOGLE_CLOUD_PROJECT="$2"
            shift 2
            ;;
        --pool-name)
            POOL_NAME="$2"
            shift 2
            ;;
        --provider-name)
            PROVIDER_NAME="$2"
            shift 2
            ;;
        -l|--location)
            GOOGLE_CLOUD_LOCATION="$2"
            shift 2
            ;;
        -h|--help)
            show_help
            exit 0
            ;;
        *)
            print_error "Unknown option: $1"
            echo "Use --help for usage information."
            exit 1
            ;;
    esac
done

# Validate required arguments
if [[ -z "${GITHUB_REPO}" ]]; then
    print_error "Repository is required. Use --repo OWNER/REPO"
    echo ""
    echo "💡 To find your repository name:"
    echo "   1. Go to your GitHub repository"
    echo "   2. The URL shows: https://github.com/OWNER/REPOSITORY"
    echo "   3. Use: OWNER/REPOSITORY (e.g., google/golang)"
    echo ""
    echo "Use --help for usage information."
    exit 1
fi
if [[ -z "${GOOGLE_CLOUD_PROJECT}" ]]; then
    print_error "GCP project is required. Use --project GOOGLE_CLOUD_PROJECT"
    echo ""
    echo "💡 To find your project ID:"
    echo "   1. Go to your Google Cloud console"
    echo "   2. The URL displays: https://console.cloud.google.com/welcome?project=GOOGLE_CLOUD_PROJECT"
    echo ""
    echo "Use --help for usage information."
    exit 1
fi

# Validate repository format
if [[ ! "${GITHUB_REPO}" =~ ^[a-zA-Z0-9._-]+/[a-zA-Z0-9._-]+$ ]]; then
    print_error "Invalid repository format '${GITHUB_REPO}'"
    echo "Expected format: owner/repo (e.g., google/my-repo)"
    exit 1
fi

# Extract repository components
REPO_OWNER=$(echo "${GITHUB_REPO}" | cut -d'/' -f1)

# Generate unique names based on repository
REPO_HASH_INPUT=$(echo -n "${GITHUB_REPO}")
REPO_HASH_SHA=$(echo "${REPO_HASH_INPUT}" | shasum -a 256)
REPO_HASH=$(echo "${REPO_HASH_SHA}" | cut -c1-8)

# Use custom pool name if provided, otherwise generate one
if [[ -z "${POOL_NAME}" ]]; then
    POOL_NAME="github-${REPO_HASH}"
fi

# Use custom provider name if provided, otherwise generate one
if [[ -z "${PROVIDER_NAME}" ]]; then
    PROVIDER_NAME="gh-${REPO_HASH}"
fi

print_header "Starting Direct Workload Identity Federation setup"
echo "📦 Repository: ${GITHUB_REPO}"
echo "☁️ Project: ${GOOGLE_CLOUD_PROJECT}"
echo "🏊 Pool: ${POOL_NAME}"
echo "🆔 Provider: ${PROVIDER_NAME}"
echo ""

# Verify gcloud authentication
print_info "Verifying gcloud authentication..."
GCLOUD_AUTH_LIST_RAW=$(gcloud auth list --filter=status:ACTIVE --format="value(account)")
GCLOUD_AUTH_LIST=$(echo "${GCLOUD_AUTH_LIST_RAW}" | head -1)
if [[ -z "${GCLOUD_AUTH_LIST}" ]]; then
    print_error "No active gcloud authentication found"
    echo "Please run: gcloud auth login"
    exit 1
fi

# Test project access
if ! gcloud projects describe "${GOOGLE_CLOUD_PROJECT}" > /dev/null 2>&1; then
    print_error "Cannot access project '${GOOGLE_CLOUD_PROJECT}'"
    echo "Please verify:"
    echo "  1. Project ID is correct"
    echo "  2. You have permissions on this project"
    echo "  3. Project exists and is not deleted"
    exit 1
fi

print_success "Authentication and project access verified"

# Step 1: Enable required APIs
print_header "Step 1: Enabling required Google Cloud APIs"
required_apis=(
    "aiplatform.googleapis.com"
    "cloudaicompanion.googleapis.com"
    "cloudresourcemanager.googleapis.com"
    "cloudtrace.googleapis.com"
    "iam.googleapis.com"
    "iamcredentials.googleapis.com"
    "logging.googleapis.com"
    "monitoring.googleapis.com"
    "sts.googleapis.com"
)
gcloud services enable "${required_apis[@]}" --project="${GOOGLE_CLOUD_PROJECT}"
print_success "APIs enabled successfully."

# Step 2: Create Workload Identity Pool
print_header "Step 2: Creating Workload Identity Pool"

if ! gcloud iam workload-identity-pools describe "${POOL_NAME}" \
    --project="${GOOGLE_CLOUD_PROJECT}" \
    --location="${GOOGLE_CLOUD_LOCATION}" &> /dev/null; then
    print_info "Creating Workload Identity Pool: ${POOL_NAME}"
    gcloud iam workload-identity-pools create "${POOL_NAME}" \
        --project="${GOOGLE_CLOUD_PROJECT}" \
        --location="${GOOGLE_CLOUD_LOCATION}" \
        --display-name="GitHub Actions Pool"
    print_success "Workload Identity Pool created"
else
    print_info "Workload Identity Pool '${POOL_NAME}' exists. Verifying state..."
    # Fetch the current state of the existing pool.
    POOL_STATE=$(gcloud iam workload-identity-pools describe "${POOL_NAME}" \
        --project="${GOOGLE_CLOUD_PROJECT}" \
        --location="${GOOGLE_CLOUD_LOCATION}" \
        --format="value(state)")

    if [[ "${POOL_STATE}" == "ACTIVE" ]]; then
        # Pool exists and is in the correct state.
        print_success "Workload Identity Pool already exists and is ACTIVE."
    else
        if [[ "${POOL_STATE}" == "DELETED" ]]; then
        # Pool exists but is DELETED. Undelete the pool. 
        print_warning "Workload Identity Pool already exists but is in a DELETED state. Running 'undelete'."
        gcloud iam workload-identity-pools undelete "${POOL_NAME}" \
            --project="${GOOGLE_CLOUD_PROJECT}" \
            --location="${GOOGLE_CLOUD_LOCATION}"
        else
        # Pool exists but is in an unexpected state.
        print_error "Pool '${POOL_NAME}' is in an unexpected state: '${POOL_STATE}'. Expected states are: {'ACTIVE', 'DELETED'}. Exiting"
        exit 1

        fi
    fi
fi

# Get the pool ID
WIF_POOL_ID=$(gcloud iam workload-identity-pools describe "${POOL_NAME}" \
    --project="${GOOGLE_CLOUD_PROJECT}" \
    --location="${GOOGLE_CLOUD_LOCATION}" \
    --format="value(name)")

# Step 3: Create Workload Identity Provider
print_header "Step 3: Creating Workload Identity Provider"
ATTRIBUTE_CONDITION="assertion.repository_owner == '${REPO_OWNER}'"

if ! gcloud iam workload-identity-pools providers describe "${PROVIDER_NAME}" \
    --project="${GOOGLE_CLOUD_PROJECT}" \
    --location="${GOOGLE_CLOUD_LOCATION}" \
    --workload-identity-pool="${POOL_NAME}" &> /dev/null; then
    print_info "Creating Workload Identity Provider: ${PROVIDER_NAME}"
    gcloud iam workload-identity-pools providers create-oidc "${PROVIDER_NAME}" \
        --project="${GOOGLE_CLOUD_PROJECT}" \
        --location="${GOOGLE_CLOUD_LOCATION}" \
        --workload-identity-pool="${POOL_NAME}" \
        --display-name="${PROVIDER_NAME}" \
        --attribute-mapping="google.subject=assertion.sub,attribute.actor=assertion.actor,attribute.repository=assertion.repository,attribute.repository_owner=assertion.repository_owner" \
        --attribute-condition="${ATTRIBUTE_CONDITION}" \
        --issuer-uri="https://token.actions.githubusercontent.com"
    print_success "Workload Identity Provider created"
else
    print_info "Workload Identity Provider '${PROVIDER_NAME}' exists. Verifying state..."
    # Fetch the current state of the existing provider.
    PROVIDER_STATE=$(gcloud iam workload-identity-pools providers describe "${PROVIDER_NAME}" \
        --project="${GOOGLE_CLOUD_PROJECT}" \
        --location="${GOOGLE_CLOUD_LOCATION}" \
        --workload-identity-pool="${POOL_NAME}" \
        --format="value(state)")

    if [[ "${PROVIDER_STATE}" == "ACTIVE" ]]; then
        # Provider exists and is in the correct state.
        print_success "Workload Identity Provider already exists and is ACTIVE."
    else
        if [[ "${PROVIDER_STATE}" == "DELETED" ]]; then
        # Provider exists but is DELETED. Undelete the provider. 
        print_warning "Workload Identity Provider already exists but is in a DELETED state. Running 'undelete'."
        gcloud iam workload-identity-pools providers undelete "${PROVIDER_NAME}" \
            --project="${GOOGLE_CLOUD_PROJECT}" \
            --location="${GOOGLE_CLOUD_LOCATION}" \
            --workload-identity-pool="${POOL_NAME}"
        else
        # Provider exists but is in an unexpected state.
        print_error "Provider '${PROVIDER_NAME}' is in an unexpected state: '${PROVIDER_STATE}'. Expected states are: {'ACTIVE', 'DELETED'}. Exiting"
        exit 1

        fi
    fi
fi

# Step 4: Grant required permissions to the Workload Identity Pool
print_header "Step 4: Granting required permissions to Workload Identity Pool"
PRINCIPAL_SET="principalSet://iam.googleapis.com/${WIF_POOL_ID}/attribute.repository/${GITHUB_REPO}"

print_info "Skipped: Granting required permissions directly to the Workload Identity Pool..."

# Step 5: Create and Configure Service Account for Gemini CLI
print_header "Step 5: Create and Configure Service Account for Gemini CLI"
SERVICE_ACCOUNT_NAME="gemini-cli-${REPO_HASH}"
SERVICE_ACCOUNT_EMAIL="${SERVICE_ACCOUNT_NAME}@${GOOGLE_CLOUD_PROJECT}.iam.gserviceaccount.com"

# Create service account if it doesn't exist
if ! gcloud iam service-accounts describe "${SERVICE_ACCOUNT_EMAIL}" --project="${GOOGLE_CLOUD_PROJECT}" &> /dev/null; then
    print_info "Creating Service Account: ${SERVICE_ACCOUNT_NAME}"
    gcloud iam service-accounts create "${SERVICE_ACCOUNT_NAME}" \
        --project="${GOOGLE_CLOUD_PROJECT}" \
        --display-name="Gemini CLI Service Account"
    print_success "Service Account created: ${SERVICE_ACCOUNT_EMAIL}"
else
    print_success "Service Account already exists: ${SERVICE_ACCOUNT_EMAIL}"
fi

# Grant permissions to the service account on the project
print_info "Granting 'Cloud AI Companion User' role to Service Account..."
gcloud projects add-iam-policy-binding "${GOOGLE_CLOUD_PROJECT}" \
    --role="roles/cloudaicompanion.user" \
    --member="serviceAccount:${SERVICE_ACCOUNT_EMAIL}" \
    --condition=None

# Allow the service account to generate an access tokens
print_info "Granting 'Service Account Token Creator' role to Service Account..."

gcloud projects add-iam-policy-binding "${GOOGLE_CLOUD_PROJECT}" \
    --role="roles/iam.serviceAccountTokenCreator" \
    --member="serviceAccount:${SERVICE_ACCOUNT_EMAIL}" \
    --condition=None

# Grant logging permissions to the service account
print_info "Granting 'Logging Writer' role to Service Account..."
gcloud projects add-iam-policy-binding "${GOOGLE_CLOUD_PROJECT}" \
    --role="roles/logging.logWriter" \
    --member="serviceAccount:${SERVICE_ACCOUNT_EMAIL}" \
    --condition=None

# Grant monitoring permissions to the service account
print_info "Granting 'Monitoring Editor' role to Service Account..."
gcloud projects add-iam-policy-binding "${GOOGLE_CLOUD_PROJECT}" \
    --role="roles/monitoring.editor" \
    --member="serviceAccount:${SERVICE_ACCOUNT_EMAIL}" \
    --condition=None

# Grant tracing permissions to the service account
print_info "Granting 'Cloud Trace Agent' role to Service Account..."
gcloud projects add-iam-policy-binding "${GOOGLE_CLOUD_PROJECT}" \
    --role="roles/cloudtrace.agent" \
    --member="serviceAccount:${SERVICE_ACCOUNT_EMAIL}" \
    --condition=None

# Grant Vertex AI permissions to the service account
print_info "Granting 'Vertex AI User' role to Service Account..."
gcloud projects add-iam-policy-binding "${GOOGLE_CLOUD_PROJECT}" \
    --role="roles/aiplatform.user" \
    --member="serviceAccount:${SERVICE_ACCOUNT_EMAIL}" \
    --condition=None

# Allow the Workload Identity Pool to impersonate the Service Account
print_info "Allowing GitHub Actions from '${GITHUB_REPO}' to impersonate the Service Account..."
gcloud iam service-accounts add-iam-policy-binding "${SERVICE_ACCOUNT_EMAIL}" \
    --project="${GOOGLE_CLOUD_PROJECT}" \
    --role="roles/iam.workloadIdentityUser" \
    --member="${PRINCIPAL_SET}"

print_success "GitHub Actions can now impersonate ${SERVICE_ACCOUNT_NAME}"

# Get the full provider name for output
WIF_PROVIDER_FULL=$(gcloud iam workload-identity-pools providers describe "${PROVIDER_NAME}" \
    --project="${GOOGLE_CLOUD_PROJECT}" \
    --location="${GOOGLE_CLOUD_LOCATION}" \
    --workload-identity-pool="${POOL_NAME}" \
    --format="value(name)")


# Step 6: Output configuration

print_header "🎉 Setup Complete!"
echo ""
print_success "Direct Workload Identity Federation has been configured for your repository!"
echo ""

print_header "Permissions Granted"
echo ""
print_success "The following permissions have been automatically granted to your repository:"
echo "• roles/logging.logWriter - Write logs to Cloud Logging"
echo "• roles/monitoring.editor - Create and update metrics in Cloud Monitoring"
echo "• roles/cloudtrace.agent - Send traces to Cloud Trace"
echo "• roles/aiplatform.user - Use Vertex AI for model inference"

echo ""
print_success "A Service Account (${SERVICE_ACCOUNT_EMAIL}) was created with the following roles:"
echo "• roles/cloudaicompanion.user - Use Code Assist for model inference"
echo "• roles/iam.serviceAccountTokenCreator"
echo ""


# Check for `gh` CLI and set variables automatically if available
if command -v gh &> /dev/null; then
    print_info "The 'gh' CLI is installed. Setting variables automatically..."

    gh variable set GCP_WIF_PROVIDER --body "${WIF_PROVIDER_FULL}" --repo "${GITHUB_REPO}"
    gh variable set GOOGLE_CLOUD_PROJECT --body "${GOOGLE_CLOUD_PROJECT}" --repo "${GITHUB_REPO}"
    gh variable set GOOGLE_CLOUD_LOCATION --body "${GOOGLE_CLOUD_LOCATION}" --repo "${GITHUB_REPO}"
    gh variable set SERVICE_ACCOUNT_EMAIL --body "${SERVICE_ACCOUNT_EMAIL}" --repo "${GITHUB_REPO}"
    gh variable set GOOGLE_GENAI_USE_VERTEXAI --body "true" --repo "${GITHUB_REPO}"

    print_success "GitHub variables have been set automatically!"
else
    print_warning "The 'gh' CLI was not found. Either install it and rerun this script OR set the below variables manually."
    echo "  For manual setup, go to https://github.com/${GITHUB_REPO}/settings/variables/actions and add the following repository variables:"
    echo ""
    echo "🔑 Variable Name: GCP_WIF_PROVIDER"
    echo "   Variable Value: ${WIF_PROVIDER_FULL}"
    echo ""
    echo "☁️  Variable Name: GOOGLE_CLOUD_PROJECT"
    echo "   Variable Value: ${GOOGLE_CLOUD_PROJECT}"
    echo ""
    echo "☁️ Variable Name: GOOGLE_CLOUD_LOCATION"
    echo "   Variable Value: ${GOOGLE_CLOUD_LOCATION}"
    echo ""
    echo "☁️ Variable Name: SERVICE_ACCOUNT_EMAIL"
    echo "   Variable Value: ${SERVICE_ACCOUNT_EMAIL}"
    echo ""
fi

print_success "Setup completed successfully! 🚀"
  1. ทำให้สคริปต์เป็นไฟล์ที่เรียกใช้งานได้
chmod +x setup_workload_identity.sh
  1. เรียกใช้สคริปต์
./setup_workload_identity.sh --repo {OWNER/REPO} --project {GOOGLE_CLOUD_PROJECT}

4. สร้างเวิร์กโฟลว์ GitHub Actions

  1. ตรวจสอบที่เก็บ GitHub ที่คุณเป็นเจ้าของ
git clone {YOUR_REPO}
cd {YOUR REPO}
  1. สร้างเวิร์กโฟลว์ GitHub Actions ที่เรียกใช้คำสั่ง Slash /security:analyze-github-pr โดยคัดลอกสคริปต์เวิร์กโฟลว์ตัวอย่าง yml จากที่เก็บ /gemini-cli-extensions/security
git checkout -b workflow
mkdir .github/ && cd .github/
mkdir workflows/ && cd workflows/
curl -L https://raw.githubusercontent.com/gemini-cli-extensions/security/refs/heads/main/.github/workflows/gemini-review.yml -o gemini-review.yml
  1. พุชเวิร์กโฟลว์ GitHub Actions ไปยังต้นทางระยะไกลใน GitHub
git add .github/workflows/gemini-review.yml
git commit -m "add new gha workflow"
git push --set-upstream origin workflow

5. เรียกใช้เวิร์กโฟลว์การวิเคราะห์ความปลอดภัยในคำขอ Pull ใหม่และที่มีอยู่

เริ่ม PR ใหม่ในที่เก็บ GitHub หรือโพสต์ความคิดเห็นใหม่ "@gemini-cli /review" ในฐานะเจ้าของหรือผู้มีส่วนร่วมในที่เก็บ ซึ่งจะเริ่มการตรวจสอบความปลอดภัยในคำขอให้ผสานรวม ส่วนขยายความปลอดภัยของ Gemini CLI จากเวิร์กโฟลว์ GitHub Actions ที่คุณคอมมิตไปยังรีโปจะติดแท็กปัญหาด้านความปลอดภัยที่พบตามหมวดหมู่ความรุนแรงตั้งแต่ "ร้ายแรง" "สูง" "ปานกลาง" ไปจนถึง "ต่ำ"

ต่อไปนี้คือตัวอย่างการตรวจสอบความปลอดภัยใน PR ใหม่ และตัวอย่างการตรวจสอบความปลอดภัยใน PR ที่มีอยู่

6. สำรวจเพิ่มเติม

เราขอแนะนำให้คุณสำรวจรายการคำสั่งที่กำหนดเองที่เพิ่มขึ้นเรื่อยๆ ซึ่งมีฟีเจอร์ความปลอดภัยใหม่ๆ ในส่วนขยายความปลอดภัยของ Gemini CLI และเริ่มใช้ในเวิร์กโฟลว์ของคุณ เช่น

  • /security:scan-deps อ้างอิงโยงการขึ้นต่อกันของโปรเจ็กต์กับ OSV.dev

ดูฟีเจอร์ล่าสุดและการแก้ไขข้อบกพร่องได้ในบันทึกประจำรุ่น

7. ขอแสดงความยินดี

ขอแสดงความยินดี คุณกำหนดค่าที่เก็บ GitHub ให้ใช้ส่วนขยายความปลอดภัยของ Gemini CLI เพื่อวิเคราะห์ PR สำหรับความเสี่ยงและช่องโหว่ด้านความปลอดภัยได้สำเร็จแล้ว