关于 bouncer-gates
bouncer-gates 面向团队和编码 Agent,在代码合并前检查五类高代价错误。它可作为命令行工具、编辑器钩子、CI 检查及 MCP 服务运行。
主要功能
- 01检测机密信息和危险命令模式
- 02标记未限定租户的查询
- 03检查浮点数货币运算
- 04发现不安全的 SQL 迁移
- 05验证 Markdown 文件链接
- 06支持基线和带理由的例外
适用场景
- 01合并前在本地扫描代码变更
- 02编辑后向 Claude Code 或 Cursor 展示问题
- 03在 GitHub Actions 中阻止新问题
- 04保留已知问题并跟踪新增问题
MCP 相关
通过 MCP 服务提供检查能力,供 Agent 和其他 MCP 客户端调用。编辑后钩子也可扫描 Agent 写入的文件。
配置
本地服务的配置在各客户端中通用,复制后粘贴到客户端的 MCP 配置文件即可。
工具
本地服务需要在你的电脑上运行后才能读取工具,维护者暂未提供工具列表。
详细介绍
bouncer-gates
在代码合并前拦下五种代价高昂的错误,无论代码是由人还是 Agent 编写的。
硬编码的机密。会泄露其他客户数据的数据库查询。用于金额计算的浮点数运算。会导致正在运行的应用崩溃的迁移。指向已不存在文件的文档链接。
如今,大多数新代码都是由 Agent 编写的,而它们恰好会犯这些错误:为了让测试通过而粘贴进去的密钥;提示词从未提到租户,因此查询中没有租户筛选条件。bouncer-gates 在 Claude Code 和 Cursor 中运行,因此 Agent 编写代码的同一轮就能收到反馈;它也会在 CI 中再次运行,确保问题不会漏网。
十秒内即可在任何代码库中试用:
npx bouncer-gates
也可以将代码粘贴到在线体验区,看看这些检查如何运行。
快速开始
npx bouncer-gates --init # writes bouncer-gates.config.json, reads your Prisma schema if you have one
npx bouncer-gates --init-agents # wires the same checks into Claude Code and Cursor for this repo
npx bouncer-gates # runs every check and prints what it found
将其添加到 GitHub Actions:
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0 # needed so the migration check can see what is new
- uses: ajeermahmood/bouncer-gates@v0
with:
version: "0.5.0"
设置就这么简单。以下内容都是详细说明。
在编辑器中与 Agent 配合使用
--init-agents 会向代码库提交两项内容:一个可供 Agent 调用的 MCP 服务,以及一个用于扫描 Agent 编写的每个文件的钩子。如果文件中发现会阻止操作的问题,Agent 会在同一轮收到文件、行号、问题所在以及正确做法:
x src/orders.ts:12 scope/unscoped-query
"order" is tenant-owned, but nothing in this query mentions "tenantId", so it returns rows from every tenant.
fix: Add tenantId to the where clause, or go through a tenant-scoped client.
任何其他 MCP 客户端都可以运行 npx -y bouncer-gates --mcp,任何编辑后钩子都可以将事件通过管道传给 npx -y bouncer-gates --hook。
工作原理及其不会做的事。
检查内容
| 检查 | 捕获的问题 | 阻止问题的示例 |
|---|---|---|
| secrets | 提交到代码库中的密码、API 密钥和私钥,以及一些风险较高的写法,例如 curl ... | sh | const apiKey = "sk_live_...",或包含真实密码并已提交的 .env |
| scope | 未限定到单个租户的多租户表查询 | prisma.order.findMany({ where: { status: "paid" } }),缺少 tenantId |
| money | 使用浮点数处理货币,或假设所有货币都保留两位小数的 * 100 | Math.round(parseFloat(price) * 100) |
| migration-safety | 会破坏部署期间仍在运行的应用版本的 SQL 迁移 | 旧代码仍在读取 total 时执行 ALTER TABLE orders DROP COLUMN total |
| doc-links | 指向不存在文件的 Markdown 链接 | 文件移走后仍存在的 [setup](docs/setup.md) |
每项检查都源自一个真实且代价高昂的漏洞。没有一项是关于风格的主观意见。 检查规则参考 通过错误示例和修正示例解释每条规则。
发现问题时
每条发现都会列出文件、行号、问题所在以及正确做法:
FAIL scope
x src/orders.ts:2 scope/unscoped-query
"order" is tenant-owned, but nothing in this query mentions "tenantId", so it returns rows from every tenant.
fix: Add tenantId to the where clause, or go through a tenant-scoped client.
你有三个选项,按以下顺序排列:
- 修复问题。 通常这是正确的做法。
- 说明为什么这样做没问题。 在该行或上一行添加注释,并说明理由。必须提供理由;只写标记不起作用。
// bouncer-gates-ok(scope): nightly revenue report spans every tenant by design const all = await prisma.order.findMany(); - 记录现有问题,仅阻止新增问题。 对于已经存在问题的代码库,运行一次此命令并提交生成的文件:
旧问题将不再阻止操作,但任何新问题仍会阻止。该文件易于阅读,其中的问题数量应该只减不增。npx bouncer-gates --baseline-write
配置
bouncer-gates --init 会为你生成配置。你可以随时手动编辑。
{
"exclude": ["fixtures/**"],
"scope": {
"models": ["order", "customer"],
"tables": ["orders", "customers"],
"column": "tenantId",
"clients": ["prisma"],
"rawAccessor": "raw"
},
"doc-links": { "repoUrl": "https://github.com/you/your-repo" }
}
- exclude:完全不扫描的文件。每次运行都会显示每个模式排除了多少文件,因此列表不会悄悄变长。
- scope.models / tables:属于租户的模型和表。
--init会从 Prisma 架构中所有含有tenantId字段的模型填充这些内容。 - scope.clients:普通客户端名称,例如
prisma,其查询应检查租户列。没有作用域包装器时,请使用此项。 - scope.rawAccessor:如果你有作用域包装器,这里填写它隐藏的原始客户端名称,例如
db.raw。访问它会触发标记。 - doc-links.repoUrl:允许将指向你自己代码仓库的绝对链接也作为文件路径进行检查。
没有 scope 部分时,作用域检查会报告 skipped,而不是通过。
所有命令
npx bouncer-gates # every check, whole repository
npx bouncer-gates --init # write a starter config
npx bouncer-gates --init-agents # wire the gates into Claude Code and Cursor
npx bouncer-gates --mcp # serve the gates over MCP, for any agentic editor
npx bouncer-gates --hook # scan the file named by a hook event on stdin
npx bouncer-gates --changed # only files this branch touched
npx bouncer-gates --only scope,money # just some checks
npx bouncer-gates --explain scope # what a check does and how to excuse a case
npx bouncer-gates --baseline-write # record existing findings
npx bouncer-gates --json # machine-readable output
npx bouncer-gates --sarif # for the GitHub Security tab
退出代码 0 表示无问题,1 表示有内容阻止运行,2 表示工具本身无法运行(标志无效、配置损坏或当前目录不是 git 仓库)。CI 会有意区别对待 1 和 2:工具损坏不应被误认为代码库问题重重。
它不会做什么
坦诚说明局限,避免大家过度信任它:
- 它会匹配文本中的形状,但不会理解你的代码。检查无法识别的辅助函数中构建的租户筛选器会被报告,解决方法是在上方添加注释。
- 金额和作用域检查只读取 JavaScript 和 TypeScript。
- 迁移检查只读取
.sql文件。不会检查以 JavaScript 或 TypeScript 编写的迁移。 - 如果密钥被拆分到多行,或没有可识别的前缀,就无法找到。要扫描深层历史记录,请使用 gitleaks 或 trufflehog;这是门口的廉价守卫,不是审计工具。
prisma.$transaction(async (tx) => ...)中的查询使用了检查无法追踪的客户端。
每条规则的盲点都列在检查项参考中。
本文使用的术语
- Gate(检查项)或检查:它会查找的五类问题之一。
- 发现项:它报告的一个问题,包含文件和行号。
- 阻止运行:某项发现会使运行以
1退出。警告不会。 - 基线:用于记录你目前决定接受的问题的文件,这样只有新问题会阻止运行。
- 确认或豁免:
bouncer-gates-ok注释,用来说明特定行没有问题,并解释原因。
遥测
每天发送一次匿名 ping:随机 ID、版本、运行时、操作系统和 Node 主版本。绝不包含任何代码相关信息。设置 BOUNCER_TELEMETRY=0 可关闭遥测。它发送的所有内容。
更多信息
- 在编辑器中使用:MCP 服务和钩子、Agent 会看到什么,以及其他编辑器
- 检查项参考:每条规则、正反示例,以及它会漏掉什么
- 在现有代码库中逐步推广
- 设计说明:为什么它绝不会在开放状态下失败,为什么发现项绝不会引用密钥,误报情况,以及性能优化工作
- 架构:检查项是纯函数,因此同一份代码可以在 CLI、Cloudflare Worker 和浏览器中运行
- 部署:演练场、API 和 npm
- 贡献:如何添加检查项,以及如何判断某项内容是否应成为检查项
开发
npm install
npm test # unit tests
npm run check # bouncer-gates on itself
npm run bench -- ../some-repo # measure against a real codebase
npm run dev # the playground site
许可证
MIT。随意使用。
由 Ajeer Mohammed 构建。这些规则源自一个多租户平台的门禁检查;该平台的大多数代码由编码 Agent 编写,漏掉一条规则就可能导致商家看到其他商家的订单。 了解这一工作流如何协同运作。
评论
一个开放协议,规定了 AI 应用如何以统一方式连接外部工具与数据源。客户端负责与模型对话,MCP 服务负责提供工具、资源和提示模板,两者通过标准消息通信,同一个服务可以被不同客户端复用。