mcpField
C
codebase-doctor

codebase-doctor

本地服务
github.com/subhajitlucky安全02 天前更新

关于 codebase-doctor

codebase-doctor 是面向编码 Agent 的只读代码库审计工具,检查安全、依赖、源代码影响及其他问题。每项发现附带证据,并报告未能分析的范围,避免把覆盖不全误报为干净。

主要功能

  1. 01只读审计代码库
  2. 02检测已提交密钥与依赖问题
  3. 03检查 RLS、Dockerfile 和工作流
  4. 04分析源代码依赖影响
  5. 05报告审计覆盖限制
  6. 06生成代码审查结论

适用场景

  1. 01审查提交或拉取请求变更
  2. 02定位密钥及依赖配置问题
  3. 03评估文件变更的影响范围

配置

本地服务的配置在各客户端中通用,复制后粘贴到客户端的 MCP 配置文件即可。

mcp.json · 通用配置
{
"mcpServers": {
"subhajitlucky-codebase-doctor": {
"command": "npx",
"args": [
"-y",
"codebase-doctor"
]
}
}
}
启动命令npx -y codebase-doctor

本地服务需要在你的电脑上安装运行环境(如 Node.js 18+)。各客户端的配置文件位置不同,请参考客户端文档。

安装包
npmcodebase-doctor0.1.10

工具

4

收录的工具列表 · 更新于 2 周前

参数类型必填说明
basestring否用于从合并基点进行比较的 Git ref;需要启用 changed。与 CLI 的 --base 选项对应。
pathstring否要审计的仓库路径。默认为服务端工作目录。
formatenum否报告呈现格式:"json" 返回 schema-version-1 JSON 报告;"summary" 返回确定性文本报告。json | summary
changedboolean否审计 Git 更改(已暂存、未暂存、未跟踪和分支工作)及其选定范围,而不是整个仓库。

详细介绍

Codebase Doctor

npm version npm downloads CI

模型负责构建,Codebase Doctor 负责验证。

它会找到问题,绝不猜测。

大多数代码仓库扫描器会以两种方式之一失灵:要么产生大量误报,要么悄悄跳过棘手情况,并报告“一切正常”。Codebase Doctor 两者都不会。每条发现都有证据,每次审计都会报告无法分析的内容,而一次干净的运行意味着确实检查了目标范围。

npx -y codebase-doctor audit . --changed --format brief
codebase-doctor brief
scope=full findings=1 shown=1 coverage=incomplete score=80
[high] security/secrets/provider-token src/config.ts:12 —
  Have an authorized human or external coding agent remove the value and rotate it,
  then rerun the audit.
coverage-limitations: validation: skipped, database: skipped, security: partial

最后这句话才是重点。大多数工具只打印发现结果就结束了。这个工具每次运行都会告诉你它没有检查哪些内容。

Codebase Doctor 演示


为什么要做这个工具

编码 Agent 交付代码的速度快于审查跟进的速度。问题不在于 Agent 不会写代码,而在于代码合并前,没有任何东西验证它们写出的代码。

Codebase Doctor 就是这一步验证流程。它会构建源代码图,扫描已提交的密钥、依赖漂移、不安全的 Dockerfile、工作流注入、RLS 错误和无障碍回归,然后准确告诉你哪些内容无法验证。

以基准测试说话,而非凭感觉:17 个预置的单缺陷样例得分为规则召回率 100%,中等及以上严重程度的误报为零(结果,可通过 npm run benchmark 重现)。

经过红队测试:一个对抗性变异语料库会尝试以不同形式隐藏每个缺陷——捕获 11/11 个变异样例,7/7 个对照样例均无问题,并纳入 CI 门禁(语料库,可通过 npm run red-team 重现)。

交叉验证:两个独立编写的离线分析器(本仓库的 sql-rls 和 rls-doctor)对同一 SQL 语料库运行——匹配 10 条发现,严重程度差异为 0,有 1 项已记录的覆盖范围差异,安全的 schema 在两者下均无问题(评分表,npm run differential)。

实地研究:在 100 个配置了 Agent 的公开代码仓库中,23% 至少存在一项高严重程度发现——10% 存在损坏的导入,4% 提交了密钥材料,11% 存在高风险 Agent 配置(报告,已匿名处理且可重现)。

安装

npx -y codebase-doctor audit .          # no install
npm install -g codebase-doctor         # global

快速入门

codebase-doctor demo                             # disposable fixture: secret, broken import, blast radius
codebase-doctor bisect security/secrets/provider-token .   # when did this enter history?
codebase-doctor audit . --json                   # full audit
codebase-doctor audit . --changed --json         # just my diff
codebase-doctor audit . --changed --base main --json    # PR review
codebase-doctor audit . --format sarif           # GitHub code scanning
codebase-doctor audit . --format html > report.html     # shareable standalone report
codebase-doctor verify . --baseline before.json  # confirm fixes landed

demo 无需配置或代码仓库:它会构建一个临时的 git 样例,其中包含一个已跟踪的密钥和一个损坏的导入;随后使用真实的处理流程审计模拟的 Agent 编辑,打印影响范围,并以退出码 1 退出,以展示 CI 门禁。不会触及临时目录之外的任何内容。

选项

--run-checks          Permit configured validation commands
--changed             Audit Git changes and their affected scope (implied by review)
--base <ref>          Compare changed scope from the merge base with this ref
--json                Emit schema-versioned JSON
--format <format>     Output format: text, json, sarif, brief, or html (review adds markdown, github)
--all-findings        Review only: include findings outside the changed lines
--output <file>       Review only: write the report to a file as well as stdout
--exclude <glob>      Exclude a repository-relative path glob; repeatable
--baseline <path>     Compare with a prior Codebase Doctor JSON report
--timeout <ms>        Per-command timeout (default: 120000)
--fail-on <severity>  info|low|medium|high|critical|none (default: high)
--require-complete    Exit 2 when audit coverage is incomplete
--max-findings <n>    Cap brief output (default: 100)
--score               Print only the Repo Health score
--badge               Print a shields.io badge URL for the Repo Health score
--receipt <path>      Write a portable coverage receipt (digest-verified)
--receipt-key <path>  Sign the receipt with an Ed25519 private key (PEM)
--pheromone <path>    Write a privacy-bounded signal (rules and counts only)
--with-database       Permit live PostgreSQL catalog access
--with-advisories     Opt-in OSV advisory lookup over lockfile packages
--database-schema     Schema to inspect; repeatable (default: public)
--database-timeout    Catalog statement timeout in ms (default: 10000)

代码审查

review 是拉取请求命令。它始终审计变更范围,将发现范围缩小到新增的差异行,并输出判定结果——NO_CHANGES、APPROVE、COMMENT 或 REQUEST_CHANGES——因此,无关的旧问题不会导致 PR 检查失败,空检出也不会被视为批准:

codebase-doctor review . --base origin/main --format markdown > review.md
codebase-doctor review . --base origin/main --format github
codebase-doctor review . --format json  # includes a machine-readable review envelope
codebase-doctor review . --base origin/main --receipt review.json
codebase-doctor review . --base origin/main --receipt review.json --receipt-key key.pem
  • --format markdown 会生成可直接用于 PR 评论的正文,其中包含判定结果、发现、源代码影响和覆盖范围限制。
  • --format github 会输出 ::error / ::warning / ::notice 工作流命令,从 Actions 日志中直接标注拉取请求差异,无需网络访问。
  • 未更改行上的发现不纳入判定范围,并计为省略;完整的 audit 仍会报告该发现。--all-findings 会禁用范围缩小,--output <file> 会在写入标准输出的同时将报告写入文件。
  • 使用 --baseline 时,只有差异中的新增发现会影响判定结果。
  • 空差异会报告 NO_CHANGES,而不是 APPROVE。在 CI 中使用 --require-base,可在未提供基础引用时以失败方式处理。
  • --receipt <path> 会写入可移植的审查凭证,其中包含判定结果、差异范围计数、覆盖范围限制和发现指纹。添加 --receipt-key 可使用 Ed25519 对其签名;verify-receipt 会检查完整性并输出审查判定结果。
  • 退出码 1 表示审查请求更改;退出码 2 表示操作失败,绝不代表结果干净。将已审查的差异视为已验证或干净之前,请先检查覆盖范围。

GitHub Action

permissions:
  contents: read
  security-events: write

steps:
  - uses: actions/checkout@v4
  - uses: subhajitlucky/[email protected]
    with:
      format: sarif
      upload: "true"
      fail-on: high

发现会显示在 Security 选项卡中。请参阅 docs/github-action.md。


检查内容

密钥 — 工作树和历史记录

以精确为先,不求穷尽:它会检测私钥材料、服务商令牌特征、成对的 AWS 凭证、包含凭证的 URL,以及高置信度的敏感赋值。被 Git 忽略的 .env 文件属于正常存储,不会被判定为问题;包含真实凭证且已跟踪的 .env 文件则会。

security/secrets-history 会捕获最重要的情况:密钥已提交,之后又从工作树中删除,因此表面上已轮换密钥的代码库不会掩盖泄露。它会检查所有分支最近的 200 次提交,且绝不会检出、改写或执行仓库内容。变更审计会将历史日志范围限定为已更改的路径,因此,删除泄露文件也不会让审查结果变为干净。

匹配到的值不会出现在任何发现、指纹、错误或报告中。 Codebase Doctor 绝不会打印你的密钥——包括在其自身的 SARIF 中。必须由获授权的外部人员或 Agent 修复可共享内容,并轮换或撤销凭证,然后重新运行同一项审计。

依赖项

security/dependencies 仅支持只读和离线操作。支持感知锁文件的 npm 锁文件版本 2 和 3、pnpm(v5+)、Yarn(classic 和 Berry)、Bun,以及 Python poetry 和 uv 锁文件。其余生态系统明确标记为不支持,不会猜测检测结果。

规则类别:security/dependencies/missing-lockfile、security/dependencies/manifest-lock-drift、security/dependencies/insecure-source、security/dependencies/mutable-git-source、security/dependencies/missing-integrity、security/dependencies/workspace-registry-resolution、security/dependencies/competing-npm-lockfiles 和 security/dependencies/competing-lockfiles。

如果锁文件内容一致,普通的 semver 范围(例如 ^5.0.0)不会被报告为问题。原始依赖项规范和解析后的 URL 不会写入报告,也不会纳入指纹。必须由经授权的外部人员或 Agent 修正元数据,并重新运行相同范围的检查。在认定依赖关系图干净或已验证之前,请先检查覆盖情况。

此工具不会调用 npm、其他包管理器、shell、安装程序或生命周期脚本,也不会发出网络请求。它本身不会对 CVE 或安全公告作出判断。Python 覆盖范围使用有界行扫描器解析 poetry.lock 和 uv.lock 中的包块,以及 pyproject.toml 中的 Poetry 和 PEP 621 声明(不依赖 TOML 库):会报告不安全的传输方式、未固定的 git 引用、缺失的哈希证据、缺失的锁文件、冲突的锁文件,以及可判定的清单与锁文件不一致;无法判定的说明符、标记、直接 URL 不一致、仅传递依赖的条目,以及仅包含 requirements 文件的布局,则会作为部分覆盖情况保留。

--with-advisories 会针对已解析的包执行一次有界 OSV 查询。只有名称、版本和生态系统信息会离开本机。

源码影响——更改此文件会破坏什么

repository/source-graph 使用真正的语法解析器(绝不会执行你的代码),为 JS/TS、Python、Go、Java 和 Rust 构建静态导入图。在变更模式下,它会沿反向边遍历,并报告从每个变更文件出发的确定性最短影响路径。

变更模式按医生模块采用混合范围,而不是通用的文件过滤器:Project Doctor 结构规则会使用完整的仓库快照运行,因此可能报告变更路径之外的问题,涉及清单文件、锁文件、工作区和测试可见性。文件级医生模块(后端、前端、基础设施、Agent 接口、性能)只检查清单中存在的变更文件,因此变更审计的范围与变更规模相称。已配置的验证检查计划基于完整项目拓扑构建,然后按 affectedProjectIds 过滤。静态 SQL 会选择受影响的迁移流,并重放每个选定流的完整当前历史。只有单独请求 --with-database 时,实时数据库才会进行完整的已观测架构集审计。变更问题为零并不代表全面检查结果干净。

repository/source-graph 使用真正的语法解析器(绝不会执行仓库代码),识别 JavaScript 和 TypeScript 中的静态 import、重新导出、仅类型导入、字面量 require 和字面量动态导入边(以及 Python、Go、Java 和 Rust)。循环是有效的拓扑结构,不属于问题;此模块按设计不会产生任何问题。

一个独立且优先追求精确性的 repository/source-integrity Doctor 只报告 source/import-target-missing 规则,避免将拓扑限制误判为猜测出来的错误。它只诊断四类有明确依据的情况:带有受支持源码扩展名的显式相对目标;配置目标明确指向受支持源码文件的单一确定别名;显式入口指向受支持源码文件的唯一工作区包;以及模块路径下没有 replace 指令的内部 Go 包。

无扩展名、JSON、自定义加载器、条件式、含糊、外部和动态引用以及循环均不属于问题。它不会检查命名导出,也不会验证被引用的导出名称是否存在。

完整模式会检查所有符合条件的边;变更模式会检查变更导入方以及所有完整反向受影响的导入方。目标被删除或重命名时,会选中未变更的导入方。

每次审计最多报告 1,000 个问题;当达到此上限或存在任何上游图限制时,都会报告覆盖不完整。覆盖不完整并不代表源码完整性检查结果干净。问题中不会公开原始导入说明符和源码文本,只会显示规范化路径、导入类型、依据类别和安全位置。

外部授权的人类或 Agent 必须修正或恢复预期目标,并以相同范围重新运行检查。

codebase-doctor audit . --changed --base main
src/db/schema.ts → src/repositories/user.ts → src/api/users/[id]/route.ts
→ src/app/dashboard/page.tsx → tests/integration/user.test.ts

循环是有效的拓扑结构,不属于问题。图模块不会有意报告任何错误——repository/source-graph 按设计不会产生任何问题;独立且优先追求精确性的 repository/source-integrity Doctor 只会报告有明确依据的缺失导入目标,因此不会将拓扑限制误判为猜测出来的错误。

Schema-1 报告可能包含 sourceImpact(架构 1)。变更模式会遍历反向内部边,将受影响的项目加入 affectedProjectIds,并为每个变更源码根报告确定性最短影响路径。报告会保留完整的受影响文件计数,但序列化时只包含有限数量的影响记录。路径只能证明静态边链,并不能证明被依赖项中存在错误。原始导入说明符和源码文本不会公开;此模块不使用插件、网络请求或写入操作。

本地 tsconfig 和 jsconfig 文件会提供一个确定性的相对别名子集;这并不等同于完整的 Node 或 TypeScript 模块解析。非字面量动态导入、含糊目标、不受支持的配置或语法、无法读取的输入以及图规模上限都属于覆盖限制,不属于问题。

工作流与基础设施

script-injection(run: 步骤中由攻击者控制的 ${{ github.event.* }})、pull-request-target-checkout、write-all-permissions、未固定的操作引用、未固定的 Docker 基础镜像、pipe-to-shell、root-user 和全局可写文件。工作流不会被触发,镜像也不会被构建。

PostgreSQL 和 Supabase RLS

发现受支持的 PostgreSQL 迁移流时,会自动运行离线 database/sql-rls:无需凭据,不会发起网络请求,也不会执行迁移 SQL,而是根据受支持的迁移重建预期的表、策略、RLS 和授权状态。覆盖不完整不代表静态 SQL 检查结果无问题。

实时 database/rls 通过只读目录检查数据库的实际状态,包括策略、权限、角色、成员关系、强制执行和绕过路径;使用环境凭据通过 --with-database 单独授权,并在只读的可重复读事务中运行。

database/rls-drift 对比两者——迁移中预期的状态与实时观察到的状态——并报告 table-missing-live、rls-disabled-live、force-rls-disabled-live、policy-missing-live、grant-missing-live、rls-enabled-live-only 和 policy-unmanaged-live。

database/rls-probe 是行为检查层。使用 --probe-db 时,它会在只读且回滚的事务中模拟每个 --app-roles 身份;还可以选择为每个 --subjects UUID 设置 Supabase request.jwt.claims,并验证该角色是否能跨所有权或租户边界读取行:

codebase-doctor audit . --with-database --probe-db \
  --app-roles authenticated \
  --subjects 00000000-0000-0000-0000-000000000001,00000000-0000-0000-0000-000000000002 \
  --owner-columns owner_id,tenant_id \
  --database-schema public

跨主体或跨所有者读取属于高严重性问题。探测器绝不会写入或提交,并且始终会回滚。

数据库和 Drizzle 隐患

只读、离线的 database/drizzle 模块及其 database/drizzle/raw-sql-date-parameter 规则会捕获一种运行时边界情况:插入原始 Drizzle sql 模板中的 JavaScript Date 可能绕过列的时间戳编码器,因此 postgres-js 可能抛出 ERR_INVALID_ARG_TYPE,而等效 SQL 在 psql 中仍可能正常运行。

// Before: raw interpolation can bypass the timestamp column encoder.
const rows = await db.execute(sql`select * from jobs where run_at <= ${date}`);

// After: guidance for a human or separately authorized external coding agent.
const rows = await db.select().from(jobs).where(lte(jobs.runAt, date));

适用范围要求精确导入 drizzle-orm/postgres-js 适配器,或同时存在 drizzle-orm 和 postgres 的限定所有者/工作区证据。它只报告静态证据能够证明的 Date 流,不会根据变量名进行推断。问题严重性为中,置信度为高。

以下情况不构成问题:Date()、Date.now()、经过编码的 toISOString() 字符串、lte(column, date) 等类型化比较,以及直接传入 sql.param(value, encoder) 的全新内联编码器对象。即使编码器标识符和别名声明为 const,也无法通过静态分析证明其安全,因为对象可能在其他位置被修改;因此,这些插值和未解析的流会被视为覆盖不完整的限制,而不是臆测的问题。覆盖不完整不代表 Drizzle 审计结果无问题。原始 SQL 和参数值不会出现在问题、指纹或报告中。必须由获得授权的外部人员或 Agent 修复,并使用相同范围重新运行检查。

Agent 攻击面——最新的攻击目标

审计 Agent 配置面,不会执行或联系其中的任何内容:

  • MCP 客户端配置:未固定的软件包运行器、Shell 命令、内联凭据、宽泛的文件系统授权
  • SKILL.md:未限定范围的 allowed-tools 授权(Bash(*)、裸写 Write)
  • 权限绕过:bypassPermissions、--dangerously-skip-permissions、--yolo、yes-always、宽泛的 permissions.allow
前端

检查 JSX/TSX 和静态 HTML 的无障碍功能(img-missing-alt、iframe-missing-title、html-missing-lang、positive-tabindex)以及静态 SEO(missing-title、missing-meta-description)。不使用浏览器,也不进行构建。

frontend/security 以只读、离线方式检查 JSX 源码:对于无法证明调用了净化器(DOMPurify.sanitize、sanitizeHtml)的动态计算值,会触发 dangerously-set-inner-html。静态字面量是安全的,展开属性会跳过此检查。

后端与身份验证

backend/auth 会离线只读地分析 JavaScript 和 TypeScript 源码,以及用于 OAuth 回调绑定规则的 Go 源码。它不会启动服务、发送请求或签发令牌,只会读取源码文本。

规则:cors-wildcard-origin-with-credentials(通配符 origin: "*"、反射式 origin: true,或包含 * 的允许列表,同时启用凭据)、session-cookie-security-disabled(cookie 的 secure 或 httpOnly 明确设为 false)、jwt-decode-without-verify(文件中存在 decode 调用,但没有 verify 调用)、jwt-verify-algorithm-unrestricted(没有 algorithms 允许列表),以及 oauth-callback-session-binding(回调路由读取查询字符串中的会话标识符,并在没有浏览器绑定的状态 cookie 时将令牌分配给该会话)。OAuth 规则会解析 JS/TS 的 Babel AST;对于 Go,则使用有界的分词器和跨文件函数索引。未解析的回调处理程序或 Go 分析缺口会作为覆盖范围限制报告,绝不会作为发现项。CORS、会话 cookie 和 JWT 规则仅适用于 JavaScript/TypeScript。

backend/api 会离线只读地分析相同的源码:当拼接或插值的 SQL 文本传入可确认绑定的 pg、postgres、mysql、mysql2、better-sqlite3 或 sqlite3 查询调用时,触发 sql-string-concat-query(带有 values 数组的参数化查询是安全的);当非静态命令传入可确认绑定的 child_process exec/execSync 时,触发 child-process-exec-dynamic(包括带有 shell: true 的 spawn),而 execFile 和普通 spawn 不会触发。通过 new Pool() 这类方式构造的实例调用,可像直接导入一样解析。无法解析的查询文本会作为覆盖范围限制处理。

只有当被调用项可通过导入声明或 CommonJS require 明确解析为受审计的包时,规则才会触发,因此不会报告名为 cors 或 decode 的无关本地辅助函数。无法通过静态方式解析的配置——非字面量选项表达式、计算得出的 cookie 标志,或可能提供该值的展开属性——属于覆盖范围限制,绝不猜测为发现项,因此在判定代码库干净之前,请检查 backend 覆盖范围。decode 和算法规则按文件限定:另一个文件中的中间件 verify 调用不会抑制这些规则。配置中的 origin 和密钥字面量不会显示在报告中,也不会纳入指纹。

未涵盖:API 形状验证、worker、webhook、cron 和速率限制分析。由获得授权的外部人员或 Agent 修正配置,然后重新运行相同范围的检查。


当前覆盖范围与北极星目标

这是大多数扫描器都会跳过的部分。

这里有一个统一的审计器——它是整个代码库的医生,而不是一系列彼此独立的产品。框架和领域专属知识以内置的内部审计模块形式存在其中。

完整审计会针对适用的已实现模块,检查所请求的完整仓库范围。它并不完整或通用——并未覆盖所有领域的分析器。在将代码库称为已验证或干净之前,请先检查 coverage。

每份报告都包含 domainCoverage——一份涵盖九个领域的清单,将适用性与状态区分开来,因此,未检测到不同于已检测到但不受支持、已跳过、失败或未选择;清单还包含模块级状态详情、证据和限制。coverageComplete 并不表示代码没有错误或完全正确。

这意味着:

  • 干净的运行结果表示已实际检查所涵盖的范围。
  • --require-complete 会以 2 退出,而不会让被跳过的区域被报告为干净。
  • 被截断或受限的扫描会在 coverageSummary 中说明,并提供精确的 total / emitted / omitted 数量和确定性样例路径。
领域当前源码覆盖范围北极星目标
仓库结构清点、框架检测、清单、工作区、锁文件、测试可见性、JS/TS + Python + Go + Java + Rust 影响图跨语言依赖和行为拓扑
配置的验证JS/TS 和 Python 命令规划;仅在使用 --run-checks 时执行跨生态系统的沙盒验证
数据库离线迁移 RLS、Drizzle Date 隐患、实时 RLS、静态与实时差异模式、查询、权限、更多引擎
前端JSX/HTML 无障碍、静态 HTML SEO 和原始 HTML 注入点React、Next.js、打包分析、更广泛的无障碍检查
后端和授权在 JS/TS 中只读、离线分析 backend/auth(CORS、会话 Cookie、JWT、OAuth 回调绑定;JS/TS 和 Go OAuth)以及 backend/api(SQL 拼接、Shell 执行);NestJS 检测Worker、Webhook、cron、速率限制分析
安全密钥(目录树 + 历史记录)、依赖规则、选择启用的 OSV密钥、权限、漏洞、供应链
基础设施Dockerfile 和 GitHub Actions托管和部署分析
性能静态文件检查:已提交的构建产物、过大的源文件缓存、查询、内存、性能分析
AI 系统Agent 表面审计:MCP 配置、SKILL.md 授权、权限设置提示词、令牌、依据分析

北极星目标中的条目是计划中的模块,并非已发布的功能。内置的源码影响图、密钥分析和依赖分析在 0.1.4 中一同发布,不属于历史版本 0.1.3 的软件包。

精确性与有界报告契约

工作区发布条目、生成目标和由测试夹具控制的路径都属于覆盖限制,除非有独立证据证明其存在问题;它们本身不属于缺失目标问题。检测到 pnpm、Yarn 和 Bun 范围时,绝不会生成 npm 专属问题。只有与已清点的仅限 localhost 的证书进行加密匹配时,才能将私钥归类为有意用于本地测试的密钥;其他所有匹配的私钥仍属于高严重性问题。

Schema-1 报告会限制重复证据,而不会隐藏其规模:coverageSummary 保留精确的 total、emitted 和 omitted 数量;limitationGroups 保留每个原因、确定性样例路径和省略的路径数量。

在将代码库称为已验证或干净之前,请先检查 coverage。完整契约请参阅 docs/architecture.md。

天生只读

Codebase Doctor 只报告问题。它不公开直接写入目标文件的 API,没有直接写入文件系统的能力,也不包含修复执行器。它绝不会被授予直接写入目标文件或执行修复的权限,也绝不会修改、修复或修补目标文件。由人工或获得单独授权的 Agent 进行更改,然后重新运行相同范围的检查以验证。

单独授权的 --run-checks 会启动由仓库管理的验证子进程;这些进程不受文件系统或网络隔离,也可能产生副作用。这属于验证执行,而非 Doctor 的修复权限。

  • --changed 不授予命令执行、网络或数据库访问权限
  • 验证命令需要 --run-checks;访问实时数据库需要 --with-database;OSV 查询需要 --with-advisories
  • 数据库凭据来自 DATABASE_URL 或 SUPABASE_DB_URL,绝不会通过连接字符串标志传入
  • 源码分析会解析语法,绝不执行源码;锁文件分析绝不会调用包管理器
  • 除非明确请求 OSV 查询,否则不会进行外部网络调用

影子审计

shadow 会审计工作树的临时副本,包括已暂存、未暂存、已删除、已重命名和未跟踪的文件。验证命令(--run-checks)会在副本中执行,因此由仓库管理的副作用——文件写入、缓存、钩子——不会影响你的工作树:

codebase-doctor shadow . --run-checks --fail-on high --receipt shadow.json

副本会始终被删除,原始工作树绝不会被修改,回执会标记为 environment: shadow (disposable copy)。这是运行不可信验证命令的安全方式。

验证器集群

swarm 使用并行只读工作器验证多个仓库,并汇总整个集群的判定结果。判定结果在设计上如实反映情况:

  • findings — 存在达到 --fail-on 阈值或更高级别的门控问题
  • unknown — 证据已丢失:覆盖范围检查失败或不完整,或者工作器失败
  • gaps — 没有门控问题,但某些领域按设计未进行检查
  • verified — 每个适用领域均已完成检查,或不适用
codebase-doctor swarm ../api ../web ../worker --workers 4 --receipt-dir receipts/
codebase-doctor swarm ../api ../web --require-complete   # exit 2 on unknown or gaps

集群判定结果取其成员中的最差结果;证据丢失时绝不会宣称结果干净。每个工作器都可以生成覆盖范围回执。

按时间顺序二分查找

bisect 会在临时 git worktree 中按时间从早到晚审计历史,找出规则或指纹首次出现的提交:

codebase-doctor bisect security/secrets/provider-token .
codebase-doctor bisect <fingerprint> . --max-commits 500 --json

输出包含提交、作者、消息、位置、指纹以及父提交中不存在的证据:在扫描目标提交之前,刚刚扫描过其父提交,且其中不包含目标。每个提交都在临时 worktree 中进行审计;工作树绝不会被修改。--all-history 也会扫描合并提交;默认情况下仅扫描第一父提交。

Repo Health 评分

每份报告都会附带一个确定性评分:从 100 中减去严重性扣分——严重 25、高 10、中 4、低 1、信息 0——若适用的覆盖范围检查未完成,再减去 10,结果限制在 0–100 之间。等级:绿色 ≥ 80,黄色 ≥ 50,红色 < 50。已确认(已抑制)的问题绝不会计入评分,而且评分绝不会取代报告:在认定代码库已通过验证之前,请先检查 coverage。

codebase-doctor audit . --score    # Repo Health: 71/100
codebase-doctor audit . --badge    # https://img.shields.io/badge/Repo%20Health-71%2F100-yellow

--score 和 --badge 只输出评分或徽章;退出码仍由 --fail-on 决定。JSON 报告始终包含 score 对象,其中包含 findingPenalty 和 coveragePenalty 明细;简要输出的标题中会包含 score=。

退出码

代码含义
0请求的审计已完成,且没有问题达到阈值
1请求的审计已完成,且至少有一个问题达到阈值
2审计无法完成,或在 --require-complete 下覆盖范围不完整

退出码 2 表示运行失败,而非结果干净。

基线与 SARIF

--baseline 会将指纹归类为新增、未变或已解决,并且仅对新增发现应用 --fail-on。外部修复后,请确认:

codebase-doctor audit . --json > before.json
# ... fix happens elsewhere ...
codebase-doctor verify . --baseline before.json

verify 会将每个指纹报告为 resolved、unchanged、unresolved 或 new,除非所有问题都得到可验证的解决,否则退出码为 1。unresolved 表示在覆盖不完整的情况下未发现问题——绝不代表已修复。全新的 verify 扫描会运行与 audit 相同的离线审计范围,因此安全与数据库发现可以进行比较;实时数据库访问仍不会获准。

覆盖收据

每次审计都可以生成可移植的覆盖收据——记录检查了什么、未检查什么、确定性评分和发现指纹;收据包含对规范正文计算的 SHA-256 摘要,以及可选的 Ed25519 签名:

codebase-doctor audit . --receipt receipt.json
codebase-doctor audit . --receipt receipt.json --receipt-key key.pem
codebase-doctor verify-receipt receipt.json   # exit 0 valid, 2 tampered

收据会绑定主题根目录、范围、HEAD 提交、基准提交、变更路径数量,以及变更路径集合的摘要。收据绝不包含机密值或源文本。摘要可证明数据被篡改过;签名可证明密钥持有者签发了收据。参见 docs/receipts.md。

信息素信号

审计可以生成信息素信号——只包含规则、严重性和计数,绝不包含路径、指纹、源文本或仓库名称:

codebase-doctor audit . --pheromone signal.json
codebase-doctor pheromone merge signals/*.json --min-signals 3 --out index.json

merge 会验证每个信号的摘要(以及存在时的签名),遇到被篡改的输入时会采取失败关闭策略,并排除在少于 --min-signals 个信号中观测到的模式(k-匿名性)。结果是一个公开的模式索引,记录实际出现的情况,而不会泄露任何人的代码。参见 docs/pheromones.md。

意图验证

intent verify 会根据审计证据检查声明的意图——它绝不会解释散文。声明以 JSON 或 PR 正文中的围栏 intent 代码块形式存在:

```intent
{ "intentVersion": "1", "claims": [
  { "id": "no-secrets", "kind": "rule-absent", "ruleId": "security/secrets/provider-token" },
  { "id": "score", "kind": "score-at-least", "value": 90 }
] }
```
codebase-doctor intent verify pr.md . --require-verified

每项声明都会被判定为已验证、违反(附带证据位置)或未决——未决表示该声明依赖尚未完成的覆盖,且绝不会计为已验证。任何违反都会导致退出码为 1;--require-verified 在存在未决项时会以退出码 2 退出。参见 docs/intent.md。

经济验证

economy verify 会在一次性影子账本中重放交易日志——不会提交任何内容,也不会转移任何资产——并在真实价值发生变动前证明或举证经济不变量:

codebase-doctor economy verify journal.json --policy policy.json
  • non-negative-balances — 透支/双重支付,并指出确切操作
  • per-operation-limit 和 window-volume-limit — 金额与交易速度限制
  • allowlist — 转账交易对手方
  • declared-balances — 日志报告的余额必须与重放结果一致

违规项会附带举证信息(操作 ID、索引、余额快照);任何违规都会导致退出码为 1,--require-proved 在存在未决项时会以退出码 2 退出。参见 docs/economy.md。

携带证明的修复

fix 会为某项发现生成修复方案,并在一次性副本中验证后才写入任何内容:

codebase-doctor fix <fingerprint> . --patch fix.patch --receipt fix.json

对于 source/import-target-missing,它会查找明确无歧义的现有候选项(优先精确匹配文件名主干,其次优先同一目录),在影子副本中应用单行修改,再次执行审计,并且仅当该发现的指纹消失且未出现新的中等及以上严重性发现时才写入补丁。补丁是一个真实的 git diff;收据会将指纹绑定到补丁的 SHA-256,以及修复前后的判定结果。原始仓库绝不会被修改。参见 docs/repairs.md。

利用见证

witness 会将风险模式发现转化为具体的利用示例——包括载荷、由此产生的转换后接收点文本,以及它违反边界的原因:

codebase-doctor witness <fingerprint> .
# Payload:     ' OR '1'='1' --
# Transformed: select * from users where id = '' OR '1'='1' --'

支持的规则:backend/api/sql-string-concat-query、 backend/api/child-process-exec-dynamic 和 frontend/security/dangerously-set-inner-html。小型拼接求值器可处理字面量、模板字面量、+、括号和 TS 类型断言;其他情况一律标记为无法判定,绝不猜测。该产物通过摘要绑定到发现指纹,且绝不会执行任何内容。详见 docs/witness.md。

已确认的发现(抑制项)

人工审查并接受的发现可以通过行内方式确认,而不会在任何报告中将其隐藏:

const API_KEY = "..."; // codebase-doctor-ignore: security/secrets/provider-token -- rotated test credential
  • 指令可指定规则 ID、doctor ID 或 doctor/* 前缀,并适用于发现所在行或紧邻其上方的行。没有位置的发现无法通过行内方式确认,不匹配任何内容的指令会被忽略。
  • 已确认的发现会从 findings 中移除(因此可以通过失败门槛),但仍会连同原因和指令位置完整列在 suppressed 下。它们仍计为存在:基线比较会将其报告为 unchanged,而 verify 绝不会将其报告为 resolved。移除指令后,该发现会作为新发现重新出现。
  • 按设计,已抑制的发现不会上传到 SARIF;请改为在 JSON、文本或简要输出中查看 suppressed。

MCP 服务和 Agent

claude mcp add codebase-doctor --scope user -- npx -y [email protected] mcp

只读工具,均标注为 readOnlyHint: true、destructiveHint: false、idempotentHint: true:audit_codebase、review_changes、verify_changes、explain_finding、verify_intent、build_receipt、describe_capabilities。响应大小限制在约 50 KB;服务不会启用 --run-checks,也不会访问实时数据库。失败时会返回结构化 JSON,格式为 { error: { code, message, nextAction } }。Codex CLI、Gemini CLI 和通用 stdio 客户端的设置说明见 docs/agents.md。

注册表元数据随 server.json 一同发布(io.github.subhajitlucky/codebase-doctor);官方 MCP 注册表、Smithery 和 Glama 的发布步骤见 docs/mcp-registries.md。

在线列表:Glama · 官方 MCP 注册表(io.github.subhajitlucky/codebase-doctor)。

此仓库附带 Claude Code 插件(.claude-plugin/ + skills/):

/plugin marketplace add subhajitlucky/codebase-doctor
/plugin install codebase-doctor

codebase-doctor instructions 会打印可直接粘贴到 AGENTS.md、CLAUDE.md、.cursor/rules/、.windsurfrules/、.clinerules/ 和 Copilot 指令中的代码片段。它只负责打印,绝不会写入文件。

工作流:编辑后运行 audit . --changed --format brief,为 PR 评估结论运行 review . --base main --format brief,在信任边界处运行完整的 audit .,外部修复后运行 verify。

路线图

  • 内置后端、性能和 AI 语义审计覆盖范围
  • 超越全局 --require-complete 门槛的分领域覆盖保证
  • 基于同一报告架构的拉取请求注释、钩子和 Agent 插件
  • 在只读挂载或一次性副本中执行已批准的验证
  • 确定性的 doctor 基准测试(npm run benchmark,详见 docs/benchmark.md):在植入问题的测试样例上衡量召回率、中等及以上严重程度问题的误报率、审查结论和抑制准确性
  • 跨模型基准测试:发现的缺陷、验证成功率、令牌成本

自我检验

CI 使用 Codebase Doctor 本身审计此仓库:

node dist/cli.js audit . --baseline .codebase-doctor-baseline.json --format brief --fail-on high

基线记录了此仓库已接受的发现——目前没有: 自审计结果干净。任何新发现都会导致 CI 失败。所有测试样例源文件都经过拆分,因此令牌不会在工作树或历史记录中连续出现——生成的测试样例仍包含该令牌,因此 demo 仍能展示真实的秘密信息发现。

竞品扫描器成绩单

大多数基准测试都是自行运行,使用自行编写的测试样例。本基准测试也不例外,并对此作了说明,然后使用同一组测试数据分别运行独立安装的竞品扫描器:

npm run rival-differential -- --markdown docs/rival-scoreboard.md

它会用相同的 17 个确定性案例,以及建议项和对照项,为临时仓库填充数据;然后对每个仓库运行 codebase-doctor 和固定版本的 Semgrep CE、gitleaks、Trivy 和 osv-scanner,并发布带日期的快照,展示检测到的问题、漏报、在干净对照项中产生的噪声,以及范围外的项——包括 codebase-doctor 表现不佳的地方。竞品结果不会作为 CI 门禁;软件包注册表和安全公告数据库都在不断变化。

  • 快照和方法说明:docs/rival-scoreboard.md
  • 每周工作流会将最新运行结果发布到 Actions 作业摘要(.github/workflows/rival-scoreboard.yml)。

开发

npm install && npm run build && npm run typecheck && npm test

发布前会使用 npm pack 进行检查,将产物安装到一个干净的临时项目中,并通过生成的二进制文件运行。

许可证

MIT

评论

支持 Markdown

第一次接触 MCP?

从协议是什么,到在客户端里装上第一个服务,这几条回答覆盖了大多数入门问题。

一个开放协议,规定了 AI 应用如何以统一方式连接外部工具与数据源。客户端负责与模型对话,MCP 服务负责提供工具、资源和提示模板,两者通过标准消息通信,同一个服务可以被不同客户端复用。