ocra

威胁模型

恶意 PR 能尝试什么、由什么挡住,以及 ocra 不防什么。

ocra 的设计目标是审查陌生人提交的 PR。本页列出这样的 PR 能尝试什么、每种尝试由什么挡住、哪些风险仍然由你承担,方便你决定在哪里运行 ocra。各项机制的细节见安全与隐私。

本页适用于 PR 审查(GitHub Action 和 ocra review --pr)、GitLab Merge Request 审查(ocra review --mr),以及带 --no-repo-config 的本地审查。普通的本地审查会信任代码目录里的 .ocra/config.json,包括其中的插件:审查不信任的代码时请加上 --no-repo-config。

保护什么

  • **你的密钥:**模型供应商的 key、GitHub token,以及不在被审查版本里、或看起来像密钥的任何文件。
  • **你的 runner 或机器:**ocra 不会执行 PR 里的任何东西。
  • **你的仓库:**ocra 只发布审查评论,并在配置了的情况下请求修改或撤回修改请求,不写入其他任何东西。
  • **ocra 发布的内容:**PR 无法让 ocra 的评论隐藏链接的真实目标、显示图片、@ 提及他人、夹带隐藏标记或下达命令。
  • **你的花费:**每个调用模型的循环都有上限。

不承诺:结论正确。模型会读到 PR 的内容,所以可能被诱导,也可能出错。

谁会发起攻击

谁能控制什么
PR 的作者(来自 fork 或分支)diff 和 head 上的每个文件(包括 .ocra/、.opencode/ 和 AGENTS.md)、文件名、提交信息、标题和描述
任何能发表评论的人PR 上的回复和评审意见
对你的仓库有推送权限的人(在 GitLab 上是 Developer 角色)上面的全部,以及他们的分支所运行的流水线:GitHub 上他们推送的任何 workflow,GitLab 上 Merge Request 的 .gitlab-ci.yml(见谁掌控流水线)
模型供应商ocra 发给它的全部内容(发送了什么)
被攻破的软件包或 registry 账号ocra 安装的代码

攻击方式与防护

PR 试图由什么挡住
执行代码:.ocra/config.json 里的插件、.opencode/ 里的 OpenCode 插件或工具、安装脚本、git 驱动配置、规则、记忆和 AGENTS.md 都从 base 提交读取,审查 PR 时从不加载仓库插件。OpenCode 的项目配置被关闭,所以 .opencode/ 和 opencode.json 里的东西都不会加载。ocra 从不检出、安装或构建 PR,git 读取它时关闭了外部 diff 驱动和文本转换。
借审查员读取密钥审查员没有 shell、编辑文件或访问网络的工具,只能读取被审查的版本。路径被限制在仓库之内,不跟随符号链接,疑似密钥文件和 .git/ 都会被拒绝。OpenCode 进程只拿到系统基础变量和模型供应商的凭据(以及你在 OCRA_RUNTIME_ENV 里列出的变量),从不包括 GITHUB_TOKEN 或其他 CI 变量。
让密钥出现在 ocra 的评论里密钥从不进入提示词,所以没有模型能复述它。
藏起问题,或说服 Judge 丢掉问题(提示词注入)PR 文本、代码、回复和模型输出都作为数据交给模型,可能冒充 ocra 自己分区的文字会被改写。只有经核查确认的 critical 问题才能阻止合并,而且 Judge 既不能丢掉也不能降级它们。这限制了诱导的效果,但不能阻止诱导(见下文)。
伪造命令或驳回命令或驳回只有来自作者以外、有写权限的人才算数,被别人编辑过的评论不算。override 必须写出完整的 head 提交 id。ocra 的讨论串只有在其中 ocra 的评论没被别人编辑过时才算数,所以无法把它指向另一个问题。
在 ocra 的评论里埋入标记或链接模型写的文字无法闭合 ocra 的标记、嵌入图片或 HTML、@ 提及他人(通过 @ 这样的字符引用也不行)、写出 ocra 的命令、以斜杠开头一行(GitLab 会把 /merge 这样的行当作快捷操作执行),也无法变成链接:其中任何协议的地址都会显示为纯文字,所以 PR 无法让 ocra 把它挑选的网址作为链接发出来。问题里引用的代码(反引号围栏或行内代码)原样发出,因为代码段里这些都不会被渲染;不成对的反引号按文字处理并转义,使它无法与评论后面的反引号配成代码段。
篡改 ocra 在汇总评论里保存的状态只有评论由 ocra 的账号发布、并且最后一次编辑也来自它时,状态才算数;状态会被校验,大小也有上限。
改写你的终端(本地运行)ocra 打印的所有内容和它输出的 JSON 里,控制字符、转义序列和双向文本控制符都会被替换。
刷高你的模型账单每个任务 30 步、每次运行 60 个任务、有上限的文件读取和工具返回、每个任务最多 50 条问题,以及每次运行的 --max-cost-usd。在 CI 里还要限制谁能触发审查(来自 fork 的 PR)。

这些防护都有测试,和对应的代码放在一起,见代码仓库。

谁掌控流水线

ocra 针对作者的规则(不能驳回、不能放行、不能伪造之前的审查)只有在作者既改不了运行 ocra 的任务、也读不到它的 secret 时才成立。能不能做到,取决于平台和配置方式。

**GitHub。**来自 fork 的 PR 在 on: pull_request 下拿不到 secret;在 on: pull_request_target 下,workflow 来自你的默认分支:两种情况下审查都不在作者手里。有推送权限的人则不同。他们推送的 workflow 会带着仓库的 secret 运行,而它的 GITHUB_TOKEN 以 github-actions[bot] 的身份发言,这正是 ocra 默认信任的账号,所以他们可以读到模型密钥,或者发一条 ocra 会当作自己的摘要。GitHub Pull Request 给出了让两者都不在他们手里的配置:审查运行在 pull_request_target 上,secret 放在只有默认分支能用的环境(environment)里,评论由 ocra 改为信任的 GitHub App 发出,.github/workflows 需要代码负责人审查。

**GitLab。**来自 fork 的 Merge Request 在 fork 里运行流水线,拿不到你的变量。来自你项目分支的 Merge Request 运行的是作者写的流水线,其中每个任务都能读到项目未受保护的变量:对这类 Merge Request,审查只是建议,而且作者可以伪造它(见GitLab Merge Request)。流水线执行策略(GitLab Ultimate)保护得了任务,保护不了令牌。

还没有试过,所以只是设计:一个只有维护者能改的单独审查项目,由 Merge Request 的 webhook 通过流水线触发器启动,在它受保护的默认分支上运行,令牌和模型密钥是受保护的变量,把 Merge Request 当作数据读取。开发者就既改不了审查,也读不到它的 secret。它的结果不是 Merge Request 流水线的状态,所以合并仍要靠审批规则把关。

ocra 不防什么

  • **诱导。**PR 可以把问题藏起来不让审查员看到,也可以说服 Judge 丢掉问题。干净的结论什么也证明不了。凡是绝不能漏掉的东西,请保留人工审查和安全工具。
  • **模型供应商。**它能看到被审查的代码。请选择你能接受其数据政策的供应商。
  • **ocra 及其依赖的软件本身的缺陷。**ocra、OpenCode、git 和 Node.js 都会处理 PR 的内容。其中任何一个有漏洞,都会在你的模型 key 和 GitHub token 在场的情况下被利用。请限制漏洞能触及的范围:模型 key 只用于审查,并在供应商那里设置花费上限;token 权限按示例配置。
  • **你自己的 workflow。**如果在拿得到 secret 的 job 里检出并安装、构建或测试 PR 的代码,以上所有防护都会失效。
  • **推送权限,**除非按上面的方式配置流水线:能推送的人,就能写自己分支所运行的流水线。
  • **供应链。**GitHub Action 安装已发布的 ocra,每个依赖都按它的 lockfile 固定版本,关闭安装脚本,并校验 registry 签名。ocra 的软件包带 provenance 发布;OpenCode 的版本是固定的,它的内置工具由测试核对。被盗的 npm 账号仍可能发布有问题的版本,不过使用安全密钥的双重验证让这件事很难做到。请按提交固定 Action 的版本。
在 GitHub 上编辑

本页目录