Skip to content

Chapter 12: CI/CD 与 GitHub Actions ​

学习目标 ​

  • 配置 claude-code-action 实现自动 PR Review(可直接复制粘贴的 YAML 配置)
  • 配置自动 Issue 分流:添加标签、优先级和负责人
  • 构建 CI 安全门禁,Claude 发现漏洞时阻止合并
  • 将 Claude 集成到现有 CI 流水线中,与测试套件并行运行
  • 在 CI 环境中处理 API 密钥、速率限制和成本控制

附录链接:A05 工具调用内部机制 解释了 Claude 如何选择工具和处理 JSON Schema 定义,这也是 CI 脚本中 claude -p 的底层机制。另见 A12 安全与对齐 了解 CI 中的权限绕过为何需要补偿性安全控制。

Claude Code 在 CI 中的工作方式 ​

两个集成点:

  1. claude-code-action -- 一个在 PR 和 Issue 上触发 Claude 的 GitHub Action。Claude 在云端运行,不在你的 runner 上
  2. claude -p 脚本 -- 在任何 CI 流水线中(GitHub Actions、GitLab CI、Jenkins、CircleCI)将 Claude 作为 CLI 工具运行。在 CI runner 上执行
GitHub 事件(PR 打开、Issue 创建、push)
        |
        v
+-------------------------------+
|  claude-code-action           |  云端运行,Anthropic 管理
|  - 审查 PR diff               |  需要:ANTHROPIC_API_KEY
|  - 发布审查评论               |  费用:按 token 计
|  - 从 Issue 创建 PR           |
+-------------------------------+
        or
+-------------------------------+
|  claude -p(CI 脚本中)        |  在你的 CI runner 上运行
|  - 自定义分析                 |  需要:ANTHROPIC_API_KEY + runner 配置
|  - 质量门禁                   |  费用:按 token 计 + runner 分钟数
|  - 安全扫描                   |
+-------------------------------+

Demo 31: 完整的 GitHub Actions PR Review ​

31
GitHub Actions PR Review
Intermediate~15 min

YAML 配置 ​

创建 .github/workflows/claude-review.yml:

yaml
name: Claude Code Review
on:
  pull_request:
    types: [opened, synchronize, reopened]
  issue_comment:
    types: [created]

# 必需:PR 评论的写权限
permissions:
  contents: read
  pull-requests: write
  issues: write

jobs:
  review:
    # 仅在 PR 事件或提到 @claude 的 Issue 评论时运行
    if: |
      github.event_name == 'pull_request' ||
      (github.event_name == 'issue_comment' &&
       github.event.issue.pull_request &&
       contains(github.event.comment.body, '@claude'))
    runs-on: ubuntu-latest
    steps:
      - name: Run Claude Code Review
        uses: anthropics/claude-code-action@v1
        with:
          anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }}

          # 可选:自定义 Claude 关注的重点
          review_instructions: |
            Focus your review on:
            1. Security vulnerabilities (SQL injection, XSS, auth bypass)
            2. Error handling gaps (unhandled promises, missing try/catch)
            3. Performance issues (N+1 queries, missing indexes, memory leaks)
            4. Type safety (any casts, missing null checks)

            Do NOT comment on:
            - Code style or formatting (handled by linters)
            - Import ordering
            - Minor naming preferences

            For each issue found, rate severity: critical / warning / suggestion

          # 可选:限制模型以控制成本
          model: claude-sonnet-4-6

          # 可选:设置最大 token 数防止成本失控
          max_tokens: 16384

这个配置做了什么 ​

当 PR 被打开或更新时:

  1. Claude 读取 PR diff 和所有修改的文件
  2. Claude 根据审查指令分析变更
  3. Claude 在具体行上发布 inline review 评论
  4. Claude 发布总结评论和整体评估

当有人评论 "@claude can you also check the error handling in the payment module?":

  1. Claude 读取评论和 PR 上下文
  2. Claude 执行请求的额外分析
  3. Claude 作为评论回复作出响应

PR Review 在 GitHub 上的效果:

terminal
  GitHub PR #203: "Add user search endpoint"

  claude-code-action (bot) reviewed 3 minutes ago

  src/api/users.ts line 42:
  +---------------------------------------------------------------+
  | WARNING: SQL injection risk                                    |
  |                                                                |
  | The search query is interpolated directly into the SQL string: |
  |   const results = await db.query(                              |
  |     `SELECT * FROM users WHERE name LIKE '%${query}%'`        |
  |   );                                                           |
  |                                                                |
  | Use parameterized queries instead:                             |
  |   const results = await db.query(                              |
  |     'SELECT * FROM users WHERE name LIKE $1',                  |
  |     [`%${query}%`]                                             |
  |   );                                                           |
  +---------------------------------------------------------------+

  src/api/users.ts line 58:
  +---------------------------------------------------------------+
  | SUGGESTION: Missing error handling                             |
  |                                                                |
  | The database query has no try/catch. If the query fails,       |
  | the error will propagate as an unhandled promise rejection.    |
  | Wrap in try/catch and return a proper 500 response.            |
  +---------------------------------------------------------------+

  Summary:
  +---------------------------------------------------------------+
  | Found 1 warning and 1 suggestion in 3 files scanned.          |
  |                                                                |
  | The SQL injection on line 42 should be fixed before merging.   |
  | The missing error handling is a good practice improvement.     |
  +---------------------------------------------------------------+

刚才发生了什么? ​

1
GitHub API
PR diff and changed files
↓
2
Read
review_instructions from YAML
↓
3
Analysis
each changed file
↓
4
GitHub API
post inline review comments

存储 API 密钥 ​

bash
# 在你的仓库设置中:
# Settings > Secrets and variables > Actions > New repository secret
# Name: ANTHROPIC_API_KEY
# Value: sk-ant-...

Demo 32: 自动 Issue 分流 ​

32
Auto-Triage Incoming Issues
Intermediate~15 min

YAML 配置 ​

创建 .github/workflows/claude-triage.yml:

yaml
name: Claude Issue Triage
on:
  issues:
    types: [opened]

permissions:
  contents: read
  issues: write

jobs:
  triage:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout code
        uses: actions/checkout@v4

      - name: Triage with Claude
        uses: anthropics/claude-code-action@v1
        with:
          anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }}
          model: claude-sonnet-4-6

          # Claude 读取 Issue 和代码库,然后分流
          direct_prompt: |
            Analyze this GitHub issue and triage it.

            Issue title: ${{ github.event.issue.title }}
            Issue body: ${{ github.event.issue.body }}

            Steps:
            1. Read the issue carefully
            2. Search the codebase to understand if this is a real bug,
               a feature request, or a question
            3. Determine:
               - Type: bug | feature | question | documentation
               - Priority: P0-critical | P1-high | P2-medium | P3-low
               - Component: which part of the codebase is affected
               - Assignee suggestion: based on git blame of affected files

            4. Add appropriate labels using the GitHub MCP tools
            5. If it is a bug, check if there is an obvious fix and mention it
            6. Post a comment summarizing the triage decision

            Label mapping:
            - Type labels: bug, enhancement, question, documentation
            - Priority labels: P0-critical, P1-high, P2-medium, P3-low
            - Component labels: api, frontend, database, auth, infra

          allowed_tools: |
            Read
            Glob
            Grep
            Bash(git log *)
            Bash(git blame *)
            mcp__github__*

实际效果 ​

有人提交了一个 Issue:

Title: Login fails when email contains a plus sign

Body: When I try to log in with john+test@gmail.com, I get a 400 error. This worked last week. Using Chrome 124 on macOS.

2 分钟内,Claude:

  1. 搜索代码库中的邮箱验证逻辑
  2. 找到 src/auth/validators.ts 中不处理 + 的正则表达式
  3. 检查 git log 发现该正则在 3 天前的 PR #189 中被修改
  4. 添加标签:bug、P1-high、auth
  5. 发布评论:
terminal
  GitHub Issue #210: "Login fails when email contains a plus sign"

  Labels added: bug, P1-high, auth

  claude-code-action (bot) commented 2 minutes ago:
  +---------------------------------------------------------------+
  | Triage Summary                                                |
  |                                                                |
  | Type: Bug | Priority: P1-high | Component: auth                |
  |                                                                |
  | The email validation regex in src/auth/validators.ts:42 was    |
  | updated in PR #189 (3 days ago) and no longer allows + in the  |
  | local part of email addresses.                                 |
  |                                                                |
  | Current regex: ^[a-zA-Z0-9.]+@                                 |
  | Should be:     ^[a-zA-Z0-9.+]+@                                |
  |                                                                |
  | Suggested assignee: @alice (last modified this file)            |
  |                                                                |
  | This is likely a quick fix. The regex change in PR #189 was    |
  | intended to block special characters for security, but + is a  |
  | valid RFC 5321 character in email local parts.                 |
  +---------------------------------------------------------------+

刚才发生了什么? ​

1
Grep
email validation patterns in src/
↓
2
Read
src/auth/validators.ts
↓
3
Bash
git log src/auth/validators.ts
↓
4
Bash
git blame src/auth/validators.ts
↓
5
MCP (GitHub)
add labels and post comment

Demo 33: CI 安全门禁 ​

33
CI Security Gate
Advanced~20 min

目标 ​

添加一个 CI 检查,在每个 PR 上运行,如果 Claude 在变更代码中发现安全漏洞,就阻止合并。与现有测试套件并行运行。

YAML 配置 ​

创建 .github/workflows/claude-security.yml:

yaml
name: Claude Security Scan
on:
  pull_request:
    types: [opened, synchronize, reopened]

permissions:
  contents: read
  pull-requests: write

jobs:
  security-scan:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout code
        uses: actions/checkout@v4
        with:
          fetch-depth: 0  # Need full history for diff

      - name: Install Claude Code
        run: npm install -g @anthropic-ai/claude-code

      - name: Get changed files
        id: changed
        run: |
          FILES=$(git diff --name-only origin/${{ github.base_ref }}...HEAD \
            | grep -E '\.(ts|tsx|js|jsx|py|go|rs|java)$' \
            | head -50)
          echo "files=$FILES" >> $GITHUB_OUTPUT

      - name: Run Security Scan
        id: scan
        env:
          ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
        run: |
          cat > /tmp/security-prompt.txt << 'PROMPT'
          You are a security auditor. Analyze the following code changes for
          security vulnerabilities.

          Check for:
          1. SQL injection (string concatenation in queries)
          2. XSS (unescaped user input in HTML/JSX)
          3. Authentication bypass (missing auth checks on endpoints)
          4. Path traversal (unsanitized file paths from user input)
          5. Secrets in code (hardcoded API keys, passwords, tokens)
          6. Insecure deserialization
          7. SSRF (user-controlled URLs in server-side requests)
          8. Command injection (user input in shell commands)

          For each vulnerability found, output a JSON object:
          {
            "file": "path/to/file.ts",
            "line": 42,
            "severity": "critical|high|medium|low",
            "type": "sql-injection",
            "description": "User input concatenated into SQL query without parameterization",
            "suggestion": "Use parameterized queries: db.query('SELECT * FROM users WHERE id = $1', [userId])"
          }

          If no vulnerabilities are found, output:
          {"status": "clean", "files_scanned": 5}

          Output ONLY valid JSON (one object per line, no other text).
          PROMPT

          # Get the diff and pipe it to Claude
          git diff origin/${{ github.base_ref }}...HEAD -- ${{ steps.changed.outputs.files }} \
            | claude -p "$(cat /tmp/security-prompt.txt)" \
              --permission-mode bypassPermissions \
              --output-format json \
              --max-tokens 8192 \
            > /tmp/security-results.json

          # Check for critical or high severity findings
          if grep -q '"severity": "critical"' /tmp/security-results.json; then
            echo "has_critical=true" >> $GITHUB_OUTPUT
          else
            echo "has_critical=false" >> $GITHUB_OUTPUT
          fi

          if grep -q '"severity": "high"' /tmp/security-results.json; then
            echo "has_high=true" >> $GITHUB_OUTPUT
          else
            echo "has_high=false" >> $GITHUB_OUTPUT
          fi

      - name: Post Results as PR Comment
        if: always()
        uses: actions/github-script@v7
        with:
          script: |
            const fs = require('fs');
            const results = fs.readFileSync('/tmp/security-results.json', 'utf8');

            let body = '## Security Scan Results\n\n';

            const lines = results.trim().split('\n').filter(l => l.trim());
            const findings = lines.map(l => {
              try { return JSON.parse(l); } catch { return null; }
            }).filter(Boolean);

            if (findings.length === 1 && findings[0].status === 'clean') {
              body += 'No security vulnerabilities found. Files scanned: ' +
                findings[0].files_scanned + '\n';
            } else {
              body += '| Severity | File | Line | Type | Description |\n';
              body += '|----------|------|------|------|-------------|\n';
              for (const f of findings) {
                if (f.severity) {
                  const icon = f.severity === 'critical' ? '🔴' :
                    f.severity === 'high' ? '🟠' :
                    f.severity === 'medium' ? '🟡' : '🟢';
                  body += `| ${icon} ${f.severity} | ${f.file} | ${f.line} | ` +
                    `${f.type} | ${f.description} |\n`;
                }
              }
              body += '\n---\n';
              for (const f of findings) {
                if (f.suggestion) {
                  body += `\n**${f.file}:${f.line}** - ${f.suggestion}\n`;
                }
              }
            }

            await github.rest.issues.createComment({
              owner: context.repo.owner,
              repo: context.repo.repo,
              issue_number: context.issue.number,
              body: body
            });

      - name: Fail on Critical Findings
        if: steps.scan.outputs.has_critical == 'true'
        run: |
          echo "CRITICAL security vulnerabilities found. Blocking merge."
          echo "Review the PR comment for details."
          exit 1

      - name: Warn on High Findings
        if: steps.scan.outputs.has_high == 'true'
        run: |
          echo "::warning::HIGH severity security findings detected. Review recommended before merge."

CI 输出效果 ​

发现漏洞时(阻止合并):

terminal
  GitHub Actions: Claude Security Scan

  Run Security Scan .............. 45s
    Scanning 8 changed files...
    Analyzing diff against security checklist...

  Post Results as PR Comment ..... 2s
    Posted security scan results as PR comment

  Fail on Critical Findings ...... FAILED
    CRITICAL security vulnerabilities found. Blocking merge.
    Review the PR comment for details.

  ========================================
  Job failed. 1 critical finding must be resolved before merge.

安全门禁在 PR 上发布的评论:

terminal
  GitHub PR #215: "Add admin API endpoints"

  github-actions (bot) commented 1 minute ago:

  ## Security Scan Results

  | Severity | File           | Line | Type           | Description                    |
  |----------|----------------|------|----------------|--------------------------------|
  | CRITICAL | src/admin.ts   | 23   | auth-bypass    | Admin endpoint has no auth     |
  |          |                |      |                | middleware check                |
  | HIGH     | src/admin.ts   | 45   | sql-injection  | User input in query string     |
  | MEDIUM   | src/admin.ts   | 67   | missing-rate   | No rate limiting on admin      |
  |          |                |      |                | endpoints                      |

  ---

  src/admin.ts:23 - Add authentication middleware:
    router.use('/admin', authMiddleware, adminRouter)

  src/admin.ts:45 - Use parameterized queries:
    db.query('SELECT * FROM users WHERE role = $1', [role])

  src/admin.ts:67 - Add rate limiting:
    router.use('/admin', rateLimit({ windowMs: 15*60*1000, max: 100 }))

扫描通过时:

terminal
  GitHub Actions: Claude Security Scan

  Run Security Scan .............. 32s
    Scanning 3 changed files...
    Analyzing diff against security checklist...

  Post Results as PR Comment ..... 2s

  ## Security Scan Results
  No security vulnerabilities found. Files scanned: 3

刚才发生了什么? ​

1
Bash
git diff to get changed files
↓
2
Bash
claude -p with security prompt
↓
3
GitHub API
post PR comment
↓
4
CI gate
exit 1 on critical

设为必需检查 ​

在 GitHub 仓库设置中:

  1. 进入 Settings,然后 Branches,然后 Branch protection rules
  2. 编辑(或创建)main 的规则
  3. 启用 "Require status checks to pass before merging"
  4. 搜索 "Claude Security Scan" 并添加为必需检查

现在有 critical 级别安全漏洞的 PR 在问题解决前无法合并。

成本控制 ​

安全扫描使用 claude -p(管道模式),以 diff 作为输入。这很高效:

  • 只分析变更的代码,不是整个代码库
  • --max-tokens 8192 限制响应成本
  • 默认使用 Sonnet(比 Opus 便宜)
  • 每个 PR 平均成本:$0.02-0.15,取决于 diff 大小

对于大型仓库,添加文件数限制:

yaml
# Only scan the first 50 changed files
FILES=$(git diff --name-only origin/main...HEAD | head -50)

组合使用:完整的 CI 流水线 ​

三个工作流如何配合:

yaml
# .github/workflows/claude-ci.yml
name: Claude CI Pipeline
on:
  pull_request:
    types: [opened, synchronize, reopened]
  issues:
    types: [opened]
  issue_comment:
    types: [created]

permissions:
  contents: read
  pull-requests: write
  issues: write

jobs:
  # Job 1: 审查 PR
  pr-review:
    if: github.event_name == 'pull_request'
    runs-on: ubuntu-latest
    steps:
      - uses: anthropics/claude-code-action@v1
        with:
          anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }}
          model: claude-sonnet-4-6
          review_instructions: |
            Focus on correctness, security, and error handling.
            Skip style comments.

  # Job 2: 安全门禁(critical 发现时阻止合并)
  security-gate:
    if: github.event_name == 'pull_request'
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
        with:
          fetch-depth: 0
      - run: npm install -g @anthropic-ai/claude-code
      - run: |
          git diff origin/${{ github.base_ref }}...HEAD \
            | claude -p "Scan for security vulnerabilities. Output JSON." \
              --permission-mode bypassPermissions \
            | tee /tmp/results.json
          grep -q '"severity": "critical"' /tmp/results.json && exit 1 || true
        env:
          ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}

  # Job 3: 分流新 Issue
  issue-triage:
    if: github.event_name == 'issues'
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: anthropics/claude-code-action@v1
        with:
          anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }}
          model: claude-sonnet-4-6
          direct_prompt: |
            Triage this issue. Add type and priority labels.
            Issue: ${{ github.event.issue.title }}
            Body: ${{ github.event.issue.body }}

  # Job 4: 响应 PR 评论中的 @claude 提及
  claude-assist:
    if: |
      github.event_name == 'issue_comment' &&
      contains(github.event.comment.body, '@claude')
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: anthropics/claude-code-action@v1
        with:
          anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }}

组合流水线在 GitHub Actions 标签页中的样子:

terminal
  GitHub Actions: Claude CI Pipeline

  Triggered by: pull_request (opened)

  pr-review ................. PASSED  (1m 23s)
    Claude reviewed 5 files, posted 2 inline comments

  security-gate ............. PASSED  (48s)
    No critical vulnerabilities found. 5 files scanned.

  issue-triage .............. SKIPPED
    (Only runs on issue events)

  claude-assist ............. SKIPPED
    (Only runs on @claude mentions)

常见问题排查 ​

CI Token 权限不足 ​

症状:工作流在尝试发布 PR 评论或添加标签时报 403 错误。

terminal
  GitHub Actions: Claude Code Review

  Run Claude Code Review ........ FAILED

  Error: Resource not accessible by integration
  HttpError: 403 - Resource not accessible by integration

  This usually means the GITHUB_TOKEN does not have sufficient permissions.

根因:工作流 YAML 中的 permissions 块缺失或不完整。GitHub Actions 默认使用受限 token。

修复:在工作流中添加必需的权限:

yaml
permissions:
  contents: read        # Read repo files and diffs
  pull-requests: write  # Post PR review comments
  issues: write         # Add labels, post issue comments

如果你使用 fine-grained personal access token 而非默认的 GITHUB_TOKEN,确保它有:

  • 仓库访问权限:Contents (read)、Pull requests (write)、Issues (write)
  • 对于组织仓库:token 必须经组织管理员批准

API 速率限制 ​

症状:安全扫描或审查间歇性地因速率限制错误失败。

terminal
  Run Security Scan .............. FAILED

  Error: 429 Too Many Requests
  Rate limit exceeded. Please retry after 60 seconds.

  Your organization has sent too many requests to the Anthropic API.
  Current limit: 1000 requests per minute.

根因:多个 PR 同时打开,或工作流在 PR 分支每次 push 时都重新触发,耗尽了 API 速率限制。

修复——减少触发频率:

yaml
on:
  pull_request:
    types: [opened, reopened]  # Remove 'synchronize' to avoid re-running on every push
    paths:
      - 'src/**'               # Only trigger on source code changes
      - '!src/**/*.test.ts'    # Skip test-only changes

修复——添加并发控制:

yaml
concurrency:
  group: claude-review-${{ github.event.pull_request.number }}
  cancel-in-progress: true  # Cancel previous runs when new commits are pushed

修复——为瞬时故障添加重试逻辑:

yaml
      - name: Run Security Scan (with retry)
        uses: nick-fields/retry@v3
        with:
          timeout_minutes: 5
          max_attempts: 3
          retry_wait_seconds: 60
          command: |
            git diff origin/${{ github.base_ref }}...HEAD \
              | claude -p "Scan for security vulnerabilities." \
                --permission-mode bypassPermissions \
              > /tmp/security-results.json

成本控制失败 ​

症状:你每月的 Anthropic API 账单因 CI 使用而意外偏高。

terminal
  Anthropic Dashboard:
  ─────────────────────────────────
  Usage this month: $847.32
  Budget limit:     $200.00

  Top consumers:
    claude-code-action (PR review):  $312.00  (2,400 runs)
    claude -p (security scan):       $289.00  (2,400 runs)
    claude -p (issue triage):        $246.32  (1,800 runs)

根因和修复:

  1. 没有 max_tokens 限制:没有 --max-tokens,Claude 可能对大 diff 生成非常长的响应。
yaml
# Always set max_tokens in CI
max_tokens: 8192   # For claude-code-action
--max-tokens 8192  # For claude -p
  1. 使用 Opus 而不是 Sonnet:Opus 每 token 费用大约是 Sonnet 的 15 倍。对于自动化审查,Sonnet 通常就够了。
yaml
model: claude-sonnet-4-6  # Not claude-opus-4-7
  1. 每次 push 都运行:如果开发者向 PR 分支 push 了 10 次 commit,审查就运行 10 次。
yaml
# Use concurrency to cancel previous runs
concurrency:
  group: claude-${{ github.event.pull_request.number }}
  cancel-in-progress: true
  1. 没有文件过滤:扫描文档或配置变更浪费 token。
yaml
# Only scan source code files
FILES=$(git diff --name-only origin/main...HEAD \
  | grep -E '\.(ts|tsx|js|jsx|py|go|rs|java)$' \
  | head -50)
  1. 设置预算告警:在 Anthropic 的 API 仪表盘配置支出超过阈值时的告警。

成本估算公式:

Cost per PR review = (input_tokens + output_tokens) * price_per_token
Average PR diff:    ~2,000 tokens input
Average review:     ~1,000 tokens output
Sonnet pricing:     ~$0.003 per 1K input, ~$0.015 per 1K output
Cost per review:    ~$0.006 + ~$0.015 = ~$0.02

100 PRs/week = ~$2/week = ~$8/month (review only)
Add security scan: ~$16/month total
Add issue triage:  ~$24/month total

ANTHROPIC_API_KEY Secret 未找到 ​

症状:工作流因 API 密钥不可用而立即失败。

terminal
  Run Claude Code Review ........ FAILED

  Error: ANTHROPIC_API_KEY is not set.
  Please add your API key as a repository secret.

修复:

bash
# 1. 前往你在 GitHub 上的仓库
# 2. Settings > Secrets and variables > Actions
# 3. 点击 "New repository secret"
# 4. Name: ANTHROPIC_API_KEY
# 5. Value: 你的 Anthropic API 密钥(以 sk-ant- 开头)

对于组织仓库:Secret 必须在组织级别设置,或者仓库必须被授权访问组织 secret。

对于 fork 仓库:GitHub Actions 不会将 secret 传递给来自 fork 的 pull request 触发的工作流。这是一个安全特性。如果你需要审查 fork PR,使用 pull_request_target 替代 pull_request,但要注意安全影响。


知识检测 ​

claude-code-action 和在 CI 脚本中运行 claude -p 有什么区别?
claude-code-action 在你的 CI runner 上运行;claude -p 在云端运行
claude-code-action 在云端运行并处理 GitHub 集成;claude -p 在你的 CI runner 上运行用于自定义分析
它们是同一个东西的不同名字
claude-code-action 是免费的;claude -p 需要 API 密钥
你的 CI 安全扫描阻止了一个 PR 合并。开发者说这是误报。最好的做法是什么?
为这个 PR 禁用安全扫描
临时移除分支保护规则
让开发者评论 @claude 并提供上下文解释为什么是安全的,然后重新运行扫描
从 Sonnet 切换到 Haiku 以获得更快但不太彻底的扫描
你的 CI Anthropic API 账单意外偏高。以下哪个改变会产生最大的成本影响?
添加 max_tokens: 8192 限制响应长度
添加 cancel-in-progress 的并发控制以避免重复运行
从 Sonnet 切换到 Haiku
添加 paths 过滤器只扫描源代码变更

本章小结 ​

  • claude-code-action 以最少的配置处理 PR Review 和 Issue 分流——放入 YAML 就能工作
  • CI 脚本中的 claude -p 给你完全的控制力,用于自定义分析和质量门禁
  • 安全门禁通过在 critical 发现时以退出码 1 退出来阻止合并
  • 成本控制:使用 Sonnet、限制 max tokens、添加并发控制,只分析变更的文件(不是整个仓库)
  • 三种模式(review、triage、@-mention 响应)可以从单个工作流文件运行
  • CI token 权限必须在工作流 YAML 中显式声明
  • 速率限制和成本飙升是最常见的运维问题——从第一天就添加并发控制和预算告警

延伸阅读:A05 工具调用内部机制 解释了驱动 CI 中 claude -p 的 JSON Schema 工具选择机制。A12 安全与对齐 讨论了为什么 CI 中的 bypassPermissions 需要受限 runner 环境和审计日志等补偿性控制。

下一章:Chapter 13: Agent SDK

基于 MIT 许可发布