news 2026/10/15 3:41:49

eve/extensions/git 深度解析:为 eve Agent 构建安全可审计的 GitHub 工作流

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
eve/extensions/git 深度解析:为 eve Agent 构建安全可审计的 GitHub 工作流
  • 人工智能
  • AI Agent
  • Agent 框架
  • 后端
  • 工具调用

【免费下载链接】eve

The Open Framework for Building Agents

项目地址:https://gitcode.com/gh_mirrors/eve28/eve
点击查看免费下载

eve/extensions/git是 eve(The Open Framework for Building Agents)官方自带的 GitHub 扩展,它向 Agent 注入 GitHub 操作指令与pr(Pull Request)技能,并可在配置github后通过 Connect 代理为 Agent 提供带签名提交能力的认证gh工具。本文以 packages/eve-git/README.md 为骨架,结合 packages/eve-git 包源码与测试,讲解两种挂载方式、凭证租约与防火墙交换机制、fail-closed 的输入校验、gh-signed-commit签名提交原理,以及验证命令,帮助你为 Agent 搭建安全且可复现的 GitHub 提交流程。

扩展定位:GitHub 事项的单一责任模块

eve/extensions/git负责一切与 GitHub 相关的能力:它贡献 GitHub 指令(instructions)和pr技能,并在配置github后贡献一个认证的gh工具(支持签名提交)。与eve/extensions/code(编码与沙箱工具)明确分工——packages/eve-code/README.md 明确指出 "GitHub instructions, theprskill, and the authenticatedghtool live ineve/extensions/git";@eve/code中的github配置项已被标记为 deprecated,GitHub 相关能力统一收敛到本扩展。

随 eve 包发布,私有 workspace 包为源

该扩展随eve主包一起分发。位于 packages/eve-git 的私有 workspace 包@eve/git(见 packages/eve-git/package.json)是它的源头:eve 的构建过程把extension/目录复制进packages/eve/src/extensions/git/extension,编译进 eve 包,并发布以下入口点:

  • eve/extensions/git:扩展本身(挂载入口)
  • eve/extensions/git/tools:gh工具,供直接挂载该工具的场景使用
  • eve/extensions/git/sandbox:GitHub shell 执行、签名提交与指导类辅助函数

从源码结构看,@eve/git依赖eve(workspace 依赖)与zod,因此它不对外独立发布,而是作为 eve 包内建扩展存在;eve侧的同名目录 packages/eve/src/extensions/git 即为构建产物,其中 packages/eve/src/extensions/git/tools.ts 直接复用extension/lib/gh-tool.ts的defineGhTool绑定挂载配置。

两种运行模式概览

模式配置凭证来源工具贡献
Shell 凭证模式git({})Agent shell 中已有的 GitHub 凭证无工具,走gh/gitCLI
Connect 代理模式git({ github: { connector, org, broker } })Connect 按仓库签发、防火墙交换git__gh工具 + 签名提交流程

这两种模式由扩展配置动态切换,影响指令文案、pr技能内容与工具注册,详见下文。

挂载方式一:Shell 凭证模式git({})

在 Agent 项目中创建agent/extensions/git.ts:

// agent/extensions/git.ts import git from "eve/extensions/git"; export default git({});

git({})假定 Agent 的 shell 已经配置好 GitHub 凭证。此时扩展:

  • 注入指令,让 Agent 在bash中使用gh和gitCLI 完成 GitHub 操作;
  • 提供git__pr技能:提交、推送,并用gh pr create --draft打开草稿 Pull Request;
  • 不贡献任何工具。

这一模式适合沙箱进程自身持有凭证的场景(如预置了 PAT 的沙箱)。指令文案由 packages/eve-git/extension/lib/github-guidance.ts 中的SHELL_INSTRUCTIONS定义,核心约束是:使用 shell 中已配置的凭证、绝不把凭证写进 URL 或命令参数、访问被拒时如实报告并停止。

挂载方式二:Connect 代理模式git({ github })

若要通过 Connect 代理 GitHub 访问,则为扩展配置github,它需要connector、org以及一个必需的broker(sandbox, rules)回调:

// agent/extensions/git.ts import git from "eve/extensions/git"; export default git({ github: { connector: "github/acme-bot", // Connect 连接器标识 org: "acme", // 限定组织 broker: async (sandbox, rules) => { // 将 rules 合入你自己的网络策略;rules 为 null 时移除租约 }, }, });

配置 schema 定义在 packages/eve-git/extension/extension.ts:github为可选对象,三个字段均非空:

  • connector: z.string().min(1):Connect 连接器标识,用于向 Connect 请求令牌;
  • org: z.string().min(1):GitHub 组织名,令牌的服务器端授权范围被限定在该组织;
  • broker: fn<GitHubLeaseBroker>():回调函数,签名见 packages/eve-git/extension/lib/github-shell.ts 中的GitHubConfig((sandbox, rules: Record<string, GitHubLeaseRule[]> | null) => Promise<void>)。

配置后,扩展在session.started事件中动态贡献两个能力(实现见 packages/eve-git/extension/tools/gh.ts 与 packages/eve-git/extension/skills/pr.ts):

  1. git__gh工具:每次命令为恰好一个该组织内的仓库申请令牌;
  2. git__pr技能:对要求验证签名(verified signatures)的仓库切换到gh-signed-commit流程。

对应地,指令文案切换为CONNECT_INSTRUCTIONS:告知 Agent GitHub 凭证对普通bash不可用,所有认证 GitHub 操作必须走gh工具。

broker 回调的职责

broker在每次命令执行时被调用两次:

  • 执行前:收到包含 GitHub header-transform 规则的rules对象,需将其安装到沙箱网络策略(例如setNetworkPolicy)中,同时保留消费者自己的其他网络规则;
  • 执行后:收到null,用于移除刚才的租约(释放凭证交换规则)。

测试 packages/eve-git/test/integration/github-shell.test.ts 中的CONFIG.broker给出了最小实现范式:rules非空时把规则映射为allow策略,rules为null时恢复allow-all。若不实现 broker 的合并逻辑,覆盖凭证交换的规则会覆盖(甚至清空)消费者原有网络策略。

核心安全机制一:占位令牌 + 防火墙交换的凭证租约

Connect 代理模式最重要的设计是真实凭证永不进入沙箱进程。其执行流程(见 packages/eve-git/extension/lib/github-shell.ts 的executeGitHubShell):

  1. 校验输入:validateGitHubShellInput在沙箱访问与令牌签发之前完成 fail-closed 校验(详见下一节);
  2. 解析目标仓库:通过assertCommandTargets确认命令目标(--repo/-R参数、git remote get-url origin等)必须属于声明仓库,repositoryNames进一步校验仓库必须属于配置的org;
  3. 申请令牌:以ConnectTokenParams(authorizationDetails: [{ type: "github_app_installation", org, repositories }]、subject: { type: "app" })调用getToken(connector, params),向 Connect 申请仅覆盖该仓库的 app-subject 令牌;
  4. 构造占位凭证:生成随机placeholder = eve-github-<uuid>与其 Basic 编码的placeholderAuthorization,沙箱进程只拿到占位GH_TOKEN和占位 Authorization,真实令牌只存在于防火墙规则中;
  5. 安装租约并执行:withGitHubCredentialLease以会话 ID 为键将同一会话内的命令串行化(leaseQueuesmap),随后调用broker(sandbox, rules)安装两条 header-transform 规则:
    • 对api.github.com:匹配authorization为^(?:token|Bearer) <placeholder>$的请求,变换为Bearer <真实token>;
    • 对github.com:匹配authorization为占位 Basic 值的请求,变换为真实 Basic 凭证;
  6. 执行并清理:sandbox.run运行命令,finally中调用broker(sandbox, null)移除租约,并删除临时GH_CONFIG_DIR;输出经sanitizeOutput把真实 token / authorization 全部替换为[redacted],超过MAX_OUTPUT_BYTES = 100_000字节时截断尾部。

测试对上述机制做了逐项断言(packages/eve-git/test/integration/github-shell.test.ts):

  • 沙箱进程环境变量中不包含真实令牌(assert.doesNotMatch(JSON.stringify(runs[4]?.env), /secret-token/)),而防火墙策略policies[0]中包含它;
  • GH_TOKEN形如eve-github-前缀的占位值;
  • 命令git push被重写为显式 HTTPS URL(-c protocol.allow=never -c protocol.https.allow=always push https://github.com/...git),并注入GIT_CONFIG_KEY_0/GIT_CONFIG_VALUE_0的http.https://github.com/.extraheader与core.hooksPath=/dev/null;
  • 输出中的令牌被替换为[redacted]。

命令执行的参数白名单

validateGitHubShellInput对可执行程序做出严格限制:

  • gh:必须有子命令,完整 gh CLI 面可用(issue、PR、review、Actions、CI、auth、alias、extension、API 请求等),但gh的别名与扩展命令可能执行本地代码——仍被沙箱隔离;
  • git:仅允许fetch、ls-remote、pull、push四个远端命令(ALLOWED_GIT_REMOTE_COMMANDS),且必须使用经过校验的originremote;克隆请使用gh repo clone;
  • gh-signed-commit:签名提交专用,必须显式给出--repo;
  • 其余程序一律拒绝。

本地 Git 操作(status、diff、add、commit、rebase)不需要 GitHub 凭证,作为普通bash命令使用。

核心安全机制二:fail-closed 的 gh 工具输入校验

git__gh工具的输入 schema 定义在 packages/eve-git/extension/lib/github-shell-schema.ts:

字段约束
command非空、trim 后 1–20,000 字符
permissions恰好 1 个元素;provider必须为"github",repositories恰好 1 个owner/name,access必须为"write"
description非空、1–500 字符,描述命令预期的 GitHub 侧结果
workingDirectory可选,1–1,000 字符,默认/workspace

只支持 argv 语法,拒绝 shell 元字符

parseCommand(packages/eve-git/extension/lib/github-shell.ts)手写实现了一个极简 argv 解析器:支持单引号、双引号与反斜杠转义,但拒绝管道|、重定向>、分号;、&、<、$、反引号、()、{}等一切 shell 运算符,双引号内的$与反引号直接报错。测试"parses simple argv quoting without enabling a shell language"验证了gh pr comment 1 --body "it's ready"被正确解析,而gh pr view 1 | cat、gh pr view $(printenv)、gh pr view 1 > out、gh pr view 1; env全部抛错。

声明仓库强制校验

assertCommandTargets对三类命令的目标做一致性校验,目标不在声明仓库内时在签发令牌之前即拒绝:

  • git:要求argv[2] === "origin",并通过git remote get-url --push origin解析远端,仅接受规范的https://github.com/owner/name.git或git@github.com:owner/name.git形式;
  • gh-signed-commit:要求显式--repo owner/name;
  • gh:解析所有--repo、-R、--repo=参数,以及gh repo clone/view/fork的仓库位置参数。

canonicalRepository用^[A-Za-z0-9-]+\/[A-Za-z0-9._-]+$校验仓库格式;repositoryNames校验仓库的 owner 必须等于配置的org(大小写不敏感),否则拒绝并提示 "outside "。测试"rejects explicit command targets outside the declared repository before minting"遍历 7 种越权命令,断言均以/not in the declared repositories/拒绝且tokenRequested === false。

权限与工作目录约束

  • githubShellApproval是工具级的审批钩子:输入合法时返回"not-applicable"(免审批),不合法时返回{ type: "denied", reason }——permissions为空/多个、provider非 github、access非"write"都会导致 denied;
  • resolveWorkingDirectory要求工作目录解析后必须落在沙箱 workspace 之内,../outside这类逃逸路径被拒绝;
  • validateRepositoryRoot(packages/eve-git/extension/lib/repository-root.ts)对git/gh-signed-commit额外要求工作目录必须是 git work tree 的根(通过git rev-parse --show-toplevel校验),并使用 NUL 分隔的realpath -e -z输出消除换行歧义。

签名提交:gh-signed-commit的工作原理

对要求 verified signatures 的仓库,普通沙箱提交会被拒绝。pr技能要求先显式暂存变更,再通过gh工具执行:

gh-signed-commit --repo owner/name --branch <branch> --base <base> -m "<headline>" [-b "<body>"]

gh-signed-commit是一个随installCodeTooling安装到受信路径/usr/local/lib/eve-code/gh-signed-commit的 Node 脚本,源码内嵌于 packages/eve-git/extension/lib/signed-commit.ts(当前版本GH_SIGNED_COMMIT_VERSION = "3")。它的执行逻辑:

  1. 安全前置检查:ensureNoUnstagedTrackedChanges拒绝存在未暂存已跟踪改动的工作区——避免覆盖用户未授权的内容,也不允许 stash/revert;
  2. 分支准备:若--branch分支不存在,以--base(缺省为仓库默认分支)创建refs/heads/<branch>;
  3. 收集暂存变更:git diff --cached --no-renames --name-status -z HEAD解析暂存区,A/M/T状态读取git show :<path>的 base64 内容作为 additions,D作为 deletions,U(未合并)直接报错;
  4. GraphQL 提交:调用 GitHub GraphQLcreateCommitOnBranchmutation(expectedHeadOid防竞态),由 GitHub 服务器侧生成带验证签名的提交;
  5. 同步本地:git fetch origin <branch>后git reset --soft FETCH_HEAD把本地 checkout 同步到已签名提交,并输出新提交 oid。

脚本要求GH_TOKEN存在——这正是 Connect 代理模式下防火墙交换进占位环境的凭证;因此gh-signed-commit必须经由gh工具调用(工具的凭证租约提供该环境),而不能在普通 bash 中运行。提交成功后,技能指引 Agent 将 PR 正文写入文件并创建草稿:

gh pr create --draft --title "<title>" --body-file <path> --base <base> --head <branch>

pr技能与 GitHub 指令:随配置动态切换

git__pr技能与git__github指令都是动态定义(defineDynamic),在session.started事件中按extension.config.github !== undefined决定内容(packages/eve-git/extension/skills/pr.ts、packages/eve-git/extension/instructions/github.ts):

能力Shell 模式Connect 模式
指令使用bash中gh/gitCLI,shell 凭证认证凭证对 bash 不可用,一切认证操作走gh工具
pr技能普通commit+push,然后gh pr create --draft先gh-signed-commit --repo ...,再创建草稿 PR
技能描述无 "signed commit" 字样含 "signed commit" 字样

集成测试 packages/eve-git/test/integration/github-guidance.test.ts 分别以extension({})与extension({ github: {...} })驱动两种模式,断言工具为null或含execute、指令文案互斥、技能 markdown 是否包含gh-signed-commit,印证了动态切换行为。

pr技能本身(packages/eve-git/extension/lib/github-guidance.ts 的prSkillMarkdown)还包含发布规范:发布前先 fetch 当前 base 并 rebase、冲突/陈旧引用/意外路径/无关回退必须停止、标题必须具体命名行为或问题(禁止prepare changes占位符)、公开元数据中不得出现密钥/私有上下文/凭证/请求者身份。PR 描述推荐按以下形状撰写(仓库有强制模板时优先模板):

[One-line summary of what changed and why] **Why** [Observed problem, evidence, and impact] **Approach** Because [cause], changing [mechanism] should [expected outcome]. **Validation** [Focused checks and results] **Relevant context** [Only the implementation or>// agent/sandbox.ts import { defineSandbox } from "eve/sandbox"; import { VercelSandbox } from "eve/sandbox/vercel"; import { installCodeTooling } from "eve/extensions/code/sandbox"; export const environment = VercelSandbox.environment({ prepare: async (sandbox) => { await installCodeTooling(sandbox, { vercel: true }); }, }); export default defineSandbox(() => environment.open());

installCodeTooling(packages/eve-code/extension/lib/sandbox.ts)会安装gh(必要时通过 apt-get 安装)、gh/vc包装器、gh-signed-commit与 TypeScript 诊断 worker;其中gh-signed-commit与工具执行路径共用同一GH_SIGNED_COMMIT_SOURCE/VERSION,并通过CODE_TOOLING_REVALIDATION_KEY(eve-code-tooling:3:<version>:<typescript-version>)驱动沙箱模板重建。在 Connect 模式下,这是git__pr技能切到gh-signed-commit的前提条件。

验证与测试

@eve/git是私有包,其验证命令在 packages/eve-git/package.json 中定义:

pnpm --filter @eve/git typecheck pnpm --filter @eve/git test pnpm --filter @eve/git test:scenario

测试分三个层级(均位于test/,不进入扩展分发产物):

  • unit(test/unit/gh-schema.test.ts):用z.toJSONSchema断言输入 schema 序列化为 draft-7 后permissions是长度为 1 的同构数组(无 root union),并验证恰好一个权限/一个仓库的约束;
  • integration(test/integration):github-guidance.test.ts验证两种配置模式下的指令/技能/工具差异;github-shell.test.ts用 fake sandbox 全面覆盖 argv 解析、令牌签发参数、占位凭证、防火墙策略、输出脱敏、工作目录逃逸拒绝、越权仓库拒绝等安全路径;
  • scenario(test/scenario/manifest.test.ts):真实构建扩展包并在临时消费者应用中挂载,断言编译后 manifest 包含动态技能git__pr、动态指令git__github、动态工具git__gh,且不包含静态工具(工具只随会话动态解析);test/scenario/tool-input-schemas.test.ts 则保证所有工具输入 schema 为 object 根(避免 root union 导致模型请求被拒)。

修改extension/源码后需重新构建 eve(pnpm --filter eve build)以同步packages/eve/src/extensions/git/extension;包内依赖说明详见 packages/eve-git/AGENTS.md。

总结:两种模式如何选型

  • Shell 凭证模式(git({})):沙箱本身已配置 GitHub 凭证、无需最小化凭证暴露的场景。实现最简,但凭证会整体暴露给沙箱进程,且无按仓库的细粒度授权。
  • Connect 代理模式(git({ github })):需要"最小权限、每次命令仅一个仓库、真实凭证不落沙箱"的场景。配合installCodeTooling与gh-signed-commit,还能覆盖要求验证签名提交的仓库。代价是必须实现broker回调,并在沙箱 provider 上维护网络策略(如setNetworkPolicy)。

两种模式共享同一套安全价值观:命令只允许 argv 语法、目标仓库必须显式声明且归属配置组织、权限必须 write、输出脱敏、凭证租约按会话串行。这套机制让 Agent 的 GitHub 操作既可审计又可在失败时安全关闭,是 eve 框架中"Agent 访问外部服务"的参考实现。

  • 人工智能
  • AI Agent
  • Agent 框架
  • 后端
  • 工具调用

【免费下载链接】eve

The Open Framework for Building Agents

项目地址:https://gitcode.com/gh_mirrors/eve28/eve
点击查看免费下载

相关推荐

上一篇:TDengine taosExplorer 无代码接入 AVEVA Historian:历史数据迁移与实时数据同步实战指南
下一篇:BepInEx 插件框架 使用指南:4 个决策点跑通全流程

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/15 3:40:17

我写了个爬虫-1000条数据5分钟抓完还不会崩

我写了个爬虫&#xff0c;1000 条数据 5 分钟抓完&#xff0c;还不会崩 需要抓取 books.toscrape.com 上 1000 本书的书名、价格、评分&#xff0c;分页共 50 页。脚本一次运行 5 分钟左右抓完&#xff0c;全程零人工干预&#xff1b;最终实收 1000 条&#xff0c;缺失 0、重复…

作者头像 李华
网站建设 2026/10/15 3:39:55

大麦网自动抢票指南:如何用 Python 脚本 4 步跑通自动购票流程

大麦网自动抢票指南&#xff1a;如何用 Python 脚本 4 步跑通自动购票流程 【免费下载链接】Automatic_ticket_purchase 大麦网抢票脚本 项目地址: https://gitcode.com/GitHub_Trending/au/Automatic_ticket_purchase 19:30:00&#xff0c;大麦网开票倒计时归零的那一刻…

作者头像 李华