全栈应用服务器

  • 全栈应用服务器 > 使用指南 > 沙箱服务概述 > Git 集成

    Git 集成

    最近更新时间: 2026-05-12 15:27:35

    概述

    沙箱 SDK 内置了一组 Git 操作方法(通过 sandbox.git 调用),覆盖仓库克隆、分支管理、提交、推送拉取等常见工作流,无需自行拼接 git 命令。

    除了沙箱内运行时的 Git 操作,平台还提供两种与 Git 协同的安全能力(详见 GitHub 密钥注入与仓库资源):

    • GithubInjection 密钥注入:Token 仅由平台在网关侧注入,不会以明文进入沙箱,沙箱内的 git 命令对 github.com / api.github.com 的 HTTPS 请求自动鉴权
    • GitRepositoryResource 资源挂载:沙箱启动前由平台拉取仓库快照并挂载到指定路径,适合”开箱即用”的代码消费场景

    适用场景包括:

    • AI Agent 自动完成代码改造并提交回远程仓库
    • 在沙箱内拉取项目代码进行构建、测试或代码审查
    • 自动化的代码迁移、批量改造任务

    沙箱内 Git 操作

    以下章节描述沙箱内通过 SDK 直接驱动的 Git 操作。所有示例使用 @e2b/code-interpreter,Python 等其他 SDK 接口一致,仅命名风格不同(snake_case)。

    认证与身份

    Git 仓库的读写通常需要凭证。沙箱提供以下几种方式管理认证信息,推荐优先选择 GitHub 密钥注入,因为它能让 token 完全不进入沙箱。

    方式 1:GitHub 密钥注入(推荐)

    通过创建沙箱时配置 GithubInjection,Token 仅由平台在网关侧持有并注入到出站请求,沙箱内进程无法读取 token 内容。沙箱内直接执行 git push / git pull 即可,不需要传递任何凭证。

    完整示例见下文 GitHub 密钥注入与仓库资源

    方式 2:内联凭证

    在调用 pushpull 时直接传入 usernamepassword (Token)。Token 在请求结束后不会持久化到沙箱磁盘。使用 Token 认证时 username 仍然是必填项

    import { Sandbox } from '@e2b/code-interpreter'
    
    async function main() {
      const sandbox = await Sandbox.create()
    
      await sandbox.git.clone('https://github.com/owner/repo.git', { path: '/home/user/repo' })
    
      // 后续 push / pull 显式传递凭证
      await sandbox.git.push('/home/user/repo', {
        username: 'my-bot',
        password: process.env.GIT_TOKEN,
      })
    
      await sandbox.kill()
    }
    
    main()
    

    方式 3:凭证助手(一次认证,全程复用)

    通过 dangerouslyAuthenticate() 将凭证写入沙箱内的 git credential helper,之后所有基于 HTTPS 的 Git 操作都会自动使用该凭证。

    await sandbox.git.dangerouslyAuthenticate({
      username: 'my-bot',
      password: process.env.GIT_TOKEN,
      // 可选: 针对自托管 Git 服务指定 host 和 protocol
      // host: 'git.example.com',
      // protocol: 'https',
    })
    

    ⚠️ 安全提醒: dangerouslyAuthenticate 会将凭证以明文形式存储在沙箱磁盘上。任何有权访问该沙箱的进程或 Agent 都能读取这些凭证。仅在受信任的沙箱中使用,并确保沙箱在使用后及时销毁。如需运行 AI Agent 等不可信代码,请改用 GitHub 密钥注入

    方式 4:在远端 URL 中保留凭证

    默认情况下,即便在克隆时把 Token 拼到 URL 中,沙箱也会在克隆完成后从 .git/config 中剥离凭证,避免泄露。如果确实需要保留,可通过 dangerouslyStoreCredentials: true 显式开启。

    await sandbox.git.clone('https://my-bot:TOKEN@github.com/owner/repo.git', {
      path: '/home/user/repo',
      dangerouslyStoreCredentials: true,
    })
    

    ⚠️ 安全提醒: 启用该选项后,凭证将持久化在仓库的 .git/config 中。如果该仓库随后被复制、打包或上传,凭证会一同泄露。

    配置 Git 身份

    提交前需要配置作者姓名和邮箱。可以设置为全局或仅作用于特定仓库。

    import { Sandbox } from '@e2b/code-interpreter'
    
    async function main() {
      const sandbox = await Sandbox.create()
    
      // 全局设置
      await sandbox.git.configureUser('AI Bot', 'bot@example.com')
    
      // 仅作用于本仓库
      await sandbox.git.configureUser('AI Bot', 'bot@example.com', {
        scope: 'local',
        path: '/home/user/repo',
      })
    
      await sandbox.kill()
    }
    
    main()
    

    克隆仓库

    clone 支持指定本地路径、分支以及浅克隆深度。

    import { Sandbox } from '@e2b/code-interpreter'
    
    async function main() {
      const sandbox = await Sandbox.create()
    
      // 克隆默认分支
      await sandbox.git.clone('https://github.com/owner/repo.git', { path: '/home/user/repo' })
    
      // 克隆指定分支
      await sandbox.git.clone('https://github.com/owner/repo.git', {
        path: '/home/user/repo',
        branch: 'main',
      })
    
      // 浅克隆,只拉取最近 1 次提交
      await sandbox.git.clone('https://github.com/owner/repo.git', {
        path: '/home/user/repo',
        depth: 1,
      })
    
      await sandbox.kill()
    }
    
    main()
    

    仓库状态与分支信息

    status 返回结构化的仓库状态,包括当前分支、相对上游的 ahead/behind 数量以及文件变更列表。branches 返回所有本地分支及当前所在分支。

    const status = await sandbox.git.status('/home/user/repo')
    console.log(status.currentBranch, status.ahead, status.behind, status.fileStatus)
    
    const branches = await sandbox.git.branches('/home/user/repo')
    console.log(branches.currentBranch, branches.branches)
    

    分支管理

    操作 方法
    创建并切换 createBranch(path, name)
    切换分支 checkoutBranch(path, name)
    删除分支 deleteBranch(path, name)
    强制删除 deleteBranch(path, name, { force: true })
    await sandbox.git.createBranch(repoPath, 'feature/auto-fix')
    await sandbox.git.checkoutBranch(repoPath, 'main')
    await sandbox.git.deleteBranch(repoPath, 'feature/auto-fix', { force: true })
    

    暂存与提交

    // 暂存所有变更
    await sandbox.git.add(repoPath)
    
    // 仅暂存指定文件
    await sandbox.git.add(repoPath, { files: ['README.md', 'src/index.ts'] })
    
    // 创建提交
    await sandbox.git.commit(repoPath, 'feat: add new feature')
    
    // 指定作者并允许空提交
    await sandbox.git.commit(repoPath, 'chore: trigger CI', {
      authorName: 'AI Bot',
      authorEmail: 'bot@example.com',
      allowEmpty: true,
    })
    

    推送与拉取

    // 推送到上游,如果尚未关联远端则建立追踪关系
    await sandbox.git.push(repoPath, {
      remote: 'origin',
      branch: 'feature/auto-fix',
      setUpstream: true,
    })
    
    // 拉取最新变更
    await sandbox.git.pull(repoPath, { remote: 'origin', branch: 'main' })
    

    如果未使用 dangerouslyAuthenticate 或 GitHub 密钥注入,也可以在 push / pull 中通过 usernamepassword 直接传入凭证。

    管理远端

    remoteAdd 用于添加新的远端,支持以下可选参数:

    • fetch: true — 添加后立即执行一次 fetch
    • overwrite: true — 如果远端名称已存在,覆盖其 URL
    await sandbox.git.remoteAdd(repoPath, 'upstream', 'https://github.com/upstream/repo.git', {
      fetch: true,
      overwrite: true,
    })
    

    Git 配置读写

    可以读取或写入 Git 配置项,支持全局或本仓库作用域。

    // 全局设置
    await sandbox.git.setConfig('pull.rebase', 'false')
    const value = await sandbox.git.getConfig('pull.rebase')
    
    // 仅作用于该仓库
    await sandbox.git.setConfig('user.signingkey', 'KEYID', {
      scope: 'local',
      path: repoPath,
    })
    

    GitHub 密钥注入与仓库资源

    平台为 GitHub 协作提供了两个密切相关的能力,二者可以独立使用,也可以组合使用以获得最佳安全性与开发体验。

    能力 配置位置 作用
    GithubInjection CreateParams.Injections 沙箱运行时,自动为出站 github.com / api.github.com 的 HTTPS 请求注入 GitHub Token。Token 不会以明文进入沙箱
    GitRepositoryResource CreateParams.Resources 沙箱启动前由平台克隆指定的 GitHub 仓库快照,并挂载到沙箱内的绝对路径。

    平台首次拉取后会缓存仓库快照,后续创建的沙箱可能复用该快照而不会刷新到最新 HEAD。如果对最新性敏感,可在沙箱内通过 sandbox.git.pull 主动刷新。

    GitHub 注入与仓库资源相关能力由七牛 Go SDK v7.26.11+ 提供。下面所有 Go 示例均依赖 github.com/qiniu/go-sdk/v7/sandbox 包,stringPtr 辅助函数与现有 docs/developer/example/test-injection-rules.go 保持一致。

    工作原理

    启动前: 平台克隆 GitHub 仓库快照 ──▶ 挂载到沙箱内 MountPath
    
    运行时: Sandbox ── HTTPS ──▶ 沙箱平台 ── 注入 GitHub Token ──▶ github.com
           (无真实 token)        (按规则注入)
    
    • 沙箱内进程发起的 HTTPS 请求被网关拦截,仅当目标域名命中 github.comapi.github.com 时,网关会注入 Authorization: Bearer <token>
    • Token 由平台保管,沙箱内无法通过任何方式读取
    • git clone / git push / git pull 等命令底层走的就是 HTTPS,因此沙箱内可以直接使用 sandbox.git.* API 操作私有仓库,无需任何凭证

    仅启用 GitHub 密钥注入

    适合”沙箱内的 AI Agent 自主决定要不要拉取或推送代码”的场景。Token 不会以任何形式进入沙箱。

    package main
    
    import (
        "context"
        "log"
        "os"
    
        "github.com/qiniu/go-sdk/v7/sandbox"
    )
    
    func stringPtr(s string) *string { return &s }
    
    func main() {
        ctx := context.Background()
    
        client, err := sandbox.NewClient(&sandbox.Config{
            APIKey:   os.Getenv("QINIU_API_KEY"),
            Endpoint: os.Getenv("QINIU_SANDBOX_API_URL"),
        })
        if err != nil {
            log.Fatal(err)
        }
    
        sb, _, err := client.CreateAndWait(ctx, sandbox.CreateParams{
            TemplateID: "base",
            Injections: &[]sandbox.SandboxInjectionSpec{
                {
                    // GitHub 注入:仅平台持有 token,沙箱内的 git 请求自动鉴权
                    Github: &sandbox.GithubInjection{
                        Token: stringPtr(os.Getenv("GITHUB_TOKEN")),
                    },
                },
            },
        })
        if err != nil {
            log.Fatal(err)
        }
        defer sb.Kill(ctx)
    
        // 沙箱内无需任何凭证,即可克隆私有仓库
        result, err := sb.Commands().Run(ctx,
            "git clone https://github.com/owner/private-repo.git /workspace/repo && "+
                "cd /workspace/repo && echo 'change' >> README.md && "+
                "git -c user.email=bot@example.com -c user.name=AI-Bot commit -am 'docs: update' && "+
                "git push origin HEAD")
        if err != nil {
            log.Fatal(err)
        }
        log.Println(result.Stdout)
    }
    

    要点:

    • 沙箱内没有 GitHub Token,即便沙箱被 Agent 滥用、被 dump 文件系统,Token 也不会泄露
    • 平台只在命中 github.com / api.github.com 时注入,其他出站请求保持透传
    • 同一沙箱中所有 GitHub 仓库共用同一个 Token

    启用 GitHub 仓库资源(预克隆)

    适合”沙箱启动即拥有仓库代码,直接进行构建 / 测试 / 代码审查”的场景。平台在沙箱启动前完成克隆,沙箱启动后即可直接访问挂载路径。

    sb, _, err := client.CreateAndWait(ctx, sandbox.CreateParams{
        TemplateID: "base",
        Resources: &[]sandbox.SandboxResourceSpec{
            {
                GitRepository: &sandbox.GitRepositoryResource{
                    Type:               sandbox.GitRepositoryTypeGithub,
                    URL:                "https://github.com/owner/private-repo.git",
                    MountPath:          "/workspace/repo",
                    AuthorizationToken: stringPtr(os.Getenv("GITHUB_TOKEN")),
                },
            },
        },
    })
    if err != nil {
        log.Fatal(err)
    }
    defer sb.Kill(ctx)
    
    // /workspace/repo 已经包含仓库内容
    sb.Commands().Run(ctx, "ls -la /workspace/repo")
    

    要点:

    • URL 支持 HTTPS (https://github.com/owner/repo.git) 与 SSH (git@github.com:owner/repo.git) 两种写法
    • MountPath 必须是绝对路径
    • AuthorizationToken 当前必填(即使是公共仓库)。平台会用它克隆仓库,并自动派生一个运行时的 GitHub 注入,让沙箱内对 github.com / api.github.com 的 HTTPS 请求继续可用
    • 同一沙箱内多个仓库资源当前必须共用同一个 token
    • 平台首次拉取的快照可能被后续沙箱复用,如需最新提交,沙箱启动后执行 sandbox.git.pull

    组合使用:预克隆 + 运行时推送

    最常见的 AI Agent 工作流:启动时拉取仓库快照,沙箱内 Agent 改完代码后直接推送回 GitHub。整个过程中 Token 始终由平台持有。

    重要:当 CreateParams.Resources 已经包含 GitRepository 资源时,不要再显式传入 GithubInjection——服务端会拒绝这种组合并返回 400 github_repository resources do not support explicit github injections。平台会根据资源里的 AuthorizationToken 自动派生运行时的 GitHub 注入,沙箱内对 github.com / api.github.com 的 HTTPS 请求会自动鉴权。

    sb, _, err := client.CreateAndWait(ctx, sandbox.CreateParams{
        TemplateID: "base",
        Resources: &[]sandbox.SandboxResourceSpec{
            {
                GitRepository: &sandbox.GitRepositoryResource{
                    Type:      sandbox.GitRepositoryTypeGithub,
                    URL:       "https://github.com/owner/private-repo.git",
                    MountPath: "/workspace/repo",
                    // 同一 token 既用于预克隆,也由平台自动派生为运行时 GitHub 注入
                    AuthorizationToken: stringPtr(os.Getenv("GITHUB_TOKEN")),
                },
            },
        },
    })
    if err != nil {
        log.Fatal(err)
    }
    defer sb.Kill(ctx)
    
    // Agent 在 /workspace/repo 改完代码后,直接推送
    // 平台自动派生的 GitHub 注入会为出站请求注入 token,沙箱内无需任何凭证
    sb.Commands().Run(ctx, `
        cd /workspace/repo &&
        git checkout -b feature/auto-fix &&
        git -c user.email=bot@example.com -c user.name=AI-Bot commit -am 'feat: auto fix' &&
        git push -u origin feature/auto-fix
    `)
    

    如果工作流不需要预克隆、只希望沙箱内自行 git clone 拉取代码,改用 GitHub 密钥注入与仓库资源 中“仅启用 GitHub 密钥注入”的写法,显式配置 GithubInjection

    更多资源挂载示例可参考 Go SDK 仓库的 examples/sandbox_resources/main.go

    与已保存注入规则配合

    GitHub 注入同样可以保存为可复用的命名规则,使用 client.CreateInjectionRule 创建后,通过 ID 引用:

    rule, err := client.CreateInjectionRule(ctx, sandbox.CreateInjectionRuleParams{
        Name: "github-bot-token",
        Injection: sandbox.InjectionSpec{
            Github: &sandbox.GithubInjection{
                Token: stringPtr(os.Getenv("GITHUB_TOKEN")),
            },
        },
    })
    if err != nil {
        log.Fatal(err)
    }
    
    sb, _, err := client.CreateAndWait(ctx, sandbox.CreateParams{
        TemplateID: "base",
        Injections: &[]sandbox.SandboxInjectionSpec{
            {ByID: &rule.RuleID},
        },
    })
    

    完整的注入规则管理(创建、列出、更新、删除)请参考 密钥注入

    安全建议

    • 优先使用 GitHub 密钥注入:AI Agent 场景下避免任何形式的 token 进入沙箱
    • 使用具备最小权限的 Token (例如 GitHub Fine-grained PAT),仅授予所需仓库的读写权限
    • 谨慎使用 dangerouslyAuthenticatedangerouslyStoreCredentials,只在你完全控制沙箱生命周期且不会将其镜像或快照外泄时启用
    • 沙箱使用完毕后立即调用 sandbox.kill() 销毁实例,避免凭证或克隆出的代码长期驻留
    以上内容是否对您有帮助?