在 GitHub Actions 中用 Docker Sandboxes 运行隔离式 AI Agent

2026-08-21 41 预计阅读时间: 1 分钟
来源: docker.com AI 摘要 Original link

Disclaimer: This article is an AI-assisted summary. Read it together with the original source when precision matters. The summary may omit context, version differences, or edge cases and is not official documentation.

预计阅读时间:10 分钟

让 AI Agent 直接修改代码、执行测试并创建 Pull Request,已经从实验性工作流变成了可以纳入 CI 的工程实践。但 Agent 需要读写仓库、安装依赖、启动服务,权限过大时会带来明显的供应链和凭据风险。

Docker Sandboxes 提供了一个更适合这类任务的边界:把 Agent 放进隔离环境,让它在沙箱中查看代码、运行 Testcontainers 测试和修改工作区,GitHub Actions 只负责调度、收集结果以及创建草稿 Pull Request。

为什么要把 Agent 放进沙箱

一个能够自主修复代码的 Agent,通常需要完成以下操作:

  • 读取整个仓库,理解项目结构和测试约定。
  • 修改源代码、测试文件或配置文件。
  • 执行构建、单元测试和集成测试。
  • 启动数据库、消息队列等临时依赖。
  • 根据失败日志继续分析并尝试修复。

如果这些操作直接发生在 GitHub Actions Runner 上,Agent 可能接触到不必要的环境变量、缓存目录或宿主机资源。尤其是工作流中存在第三方 Action、外部脚本或不受信任的输入时,风险会进一步扩大。

Docker Sandboxes 的价值不只是“再启动一个容器”。它的目标是为 Agent 提供一个相对独立的开发环境,并把工作区、网络和凭据暴露控制在明确范围内。这样可以把 Agent 的职责限定为:在指定目录中修改代码,并用允许的工具验证修改结果。

需要注意,沙箱不是自动完成的安全证明。工作流仍然需要遵循最小权限原则,避免把长期有效的云凭据、生产环境密钥或高权限 GitHub Token 直接交给 Agent。

一个可改造的 GitHub Actions 工作流

下面是一个最小化示例。它假设 Runner 已经安装了支持 Docker Sandboxes 的 Docker CLI,并且本地可以使用 docker sandbox run。不同 Docker 版本或 Agent 镜像的参数可能略有差异,实际使用时应以当前 Docker Sandboxes CLI 文档为准。

这个示例的关键点有三个:

  1. 只在拥有写权限的事件上运行 Agent。
  2. 把仓库挂载到沙箱内的固定目录。
  3. 让 Agent 先运行测试,再输出修改结果,由后续步骤决定是否创建草稿 PR。
name: AI repair proposal

on:
  workflow_dispatch:
    inputs:
      task:
        description: "修复任务,例如:修复失败的订单服务测试"
        required: true
        type: string

permissions:
  contents: write
  pull-requests: write

jobs:
  repair:
    runs-on: ubuntu-latest
    timeout-minutes: 30
    env:
      TASK: ${{ inputs.task }}

    steps:
      - name: Checkout repository
        uses: actions/checkout@v4
        with:
          fetch-depth: 0

      - name: Prepare workspace
        run: |
          git config user.name "github-actions[bot]"
          git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
          git checkout -b "agent/${GITHUB_RUN_ID}"

      - name: Run agent in Docker Sandbox
        run: |
          docker sandbox run \
            --mount-workspace "$GITHUB_WORKSPACE:/workspace" \
            --network none \
            agent-image:latest \
            sh -lc '
              cd /workspace
              printf "%s\n" "$TASK" > /tmp/task.txt
              agent run \
                --workspace /workspace \
                --task "$(cat /tmp/task.txt)" \
                --run-tests "./gradlew test"
            '

      - name: Show changes
        run: |
          git status --short
          git diff --check
          git diff --stat

      - name: Run verification outside the agent
        run: ./gradlew test

      - name: Commit and push proposal
        run: |
          if git diff --quiet; then
            echo "Agent did not change any files."
            exit 0
          fi

          git add -A
          git commit -m "chore: propose AI-assisted fix"
          git push --set-upstream origin "agent/${GITHUB_RUN_ID}"

      - name: Open draft pull request
        env:
          GH_TOKEN: ${{ github.token }}
        run: |
          if git diff HEAD^ HEAD --quiet; then
            exit 0
          fi

          gh pr create \
            --draft \
            --title "AI-assisted repair proposal" \
            --body "由隔离的 Docker Sandbox Agent 生成。请人工检查代码变更、测试覆盖率和依赖影响。" \
            --base "${GITHUB_REF_NAME}" \
            --head "agent/${GITHUB_RUN_ID}"

示例中的 agent-image:latestagent run 是占位名称,需要替换成团队实际使用的 Agent 镜像与启动命令。--network none 适合不需要访问外部服务的任务。如果 Agent 必须下载依赖或连接测试服务,应改为更受控的网络策略,而不是直接开放全部网络。

Testcontainers 与沙箱边界

Testcontainers 测试通常需要启动 Docker 容器,例如 PostgreSQL、Redis 或 Kafka。此时要区分两层能力:

  • Agent 所在的 Docker Sandbox,负责隔离 Agent 进程和工作区。
  • Testcontainers 使用的容器运行时,负责启动测试依赖。

如果沙箱禁止访问 Docker daemon,Testcontainers 可能无法创建依赖容器。工程上可以采用两种方式:

  • 在沙箱内提供受限的 Docker socket 或专用 Docker daemon。
  • 让 Agent 只负责修改代码,在沙箱外由一个独立验证步骤运行 Testcontainers 测试。

第二种方式通常更容易审计。Agent 可以先运行不依赖外部容器的快速测试,提交修改后,GitHub Actions 再执行完整的集成测试。这样即使 Agent 生成了危险的容器参数,也不会直接控制长期运行的宿主机 Docker daemon。

一个典型的分层流程如下:

# 沙箱内:快速反馈,限制网络和工具范围
agent run --task "$TASK" --run-tests "./gradlew test"

# Runner 上:由固定脚本执行,不把控制权交给 Agent
./gradlew integrationTest
./gradlew testcontainersTest

如果项目确实要求 Agent 在迭代过程中运行 Testcontainers,应明确限制以下内容:

  • 可访问的镜像仓库和网络域名。
  • Docker daemon 的权限范围。
  • 测试容器的 CPU、内存和运行时长。
  • 工作区之外的挂载目录。
  • Agent 是否能够读取 GitHub、云服务或包管理器凭据。

凭据、分支和审查流程

最容易被忽略的是 GitHub 权限。一个能够创建 PR 的 Agent 不应该同时拥有发布、删除仓库内容或访问生产资源的权限。建议把工作流设计成一次性、可追踪的修复提案:

  • 使用 workflow_dispatch 或受信任的 Issue 命令触发。
  • 只授予 contents: writepull-requests: write 等必要权限。
  • 让 Agent 推送到独立分支,不允许直接写入默认分支。
  • 一律创建 draft PR,要求人工完成最终审查。
  • 将测试结果、变更统计和 Agent 日志作为 PR 检查项保存。
  • 对任务描述、Issue 内容和用户输入设置长度与字符限制。

如果需要访问私有包仓库,优先使用短期 Token,并把凭据注入到沙箱内的专用环境变量。不要把 ${{ secrets.* }} 写进 Agent 的提示词,也不要让 Agent 负责生成或上传新的长期凭据。

什么时候值得采用

Docker Sandboxes 比普通容器多了一层运行时和权限管理成本,因此并非每个自动化脚本都需要它。以下任务比较适合:

  • 根据失败测试自动提出修复方案。
  • 批量升级依赖并生成变更说明。
  • 对多个模块执行格式化、迁移或兼容性修复。
  • 在隔离环境中分析仓库并生成草稿 PR。

如果任务只是固定的代码格式化或版本替换,普通 GitHub Actions 步骤通常更简单、更可预测。Agent 适合处理需要阅读上下文、尝试多个方案并根据测试反馈调整的工作,但它的输出仍然应当被视为未审核的代码变更。

落地时可以从一个手动触发的工作流开始:限制权限,使用独立分支,在沙箱内执行快速测试,然后在 Runner 上执行完整验证。确认日志、网络和凭据边界都符合预期后,再考虑接入定时任务或 Issue 自动触发。这样既能获得 Agent 的修复能力,也能保留现有 CI 的可审查性和失败回滚路径。


相关推荐