code-review-graph 本地优先与隐私模型:数据边界、零遥测承诺与安全配置全解析
【免费下载链接】code-review-graphLocal-first code intelligence graph for MCP and CLI. Builds a persistent map of your codebase so AI coding tools read only what matters, with benchmarked context reductions on reviews and large-repo workflows.项目地址: https://gitcode.com/GitHub_Trending/co/code-review-graph
本篇技术指南围绕 docs/LEGAL.md 展开,系统梳理 code-review-graph 的许可证、隐私与数据边界设计,并结合仓库源码(code_review_graph/embeddings.py、code_review_graph/main.py、code_review_graph/http_origin_guard.py、SECURITY.md)逐一印证:什么数据留在本地、什么数据在何种条件下才会出境、如何通过环境变量主动确认云嵌入,以及 MCP HTTP 传输的默认绑定策略。读完你将能判断在敏感代码库中如何配置嵌入提供方,并掌握CRG_ACCEPT_CLOUD_EMBEDDINGS等关键开关的确切行为。
一、项目定位:本地优先的代码智能图
code-review-graph 是一款 local-first(本地优先)的代码智能图工具,为 MCP(Model Context Protocol)与 CLI 提供持久化的代码库结构地图,使 AI 编码工具只读取真正相关的代码片段。其官方 docs/LEGAL.md 在法律与隐私层面明确承诺:
- 零遥测(Zero telemetry):不采集任何使用数据回传;
- 本地存储:全部图数据保存在
.code-review-graph/graph.db; - 本地运行:核心图构建、评审、搜索以及 CLI/MCP 工作流均在本地完成;
- 按需出境:只有显式选择云嵌入提供方时,被嵌入的源码片段才会发送给所配置的提供方;
- 显式确认:远程嵌入提供方会打印出站警告(egress warning),除非设置
CRG_ACCEPT_CLOUD_EMBEDDINGS=1; - 本地绑定:Streamable HTTP MCP 传输默认绑定 localhost。
这些承诺与 SECURITY.md 中的威胁模型一致:该工具被定义为"本地开发工具","在正常的图构建与评审工作流中不发起任何网络调用",且"只读取经过校验的仓库根目录内的源文件"。
二、许可证:MIT 开源许可
docs/LEGAL.md明确声明项目采用MIT License,许可证全文位于仓库根目录 LICENSE。MIT 许可属于宽松型开源协议,允许使用、复制、修改、合并、出版发行、再许可和销售软件副本,仅要求保留版权声明与许可声明。仓库中 code_review_graph/docs/LLM-OPTIMIZED-REFERENCE.md 也以机器可读的简写形式重申了该许可条款。
从供应链安全角度看,SECURITY.md 还补充说明依赖均带有上界约束(pinned with upper bounds),且uv.lock记录了 SHA256 哈希,这是 MIT 开源许可之外、与依赖分发安全相关的配套机制。
三、数据边界:什么留在本机,什么可能出境
3.1 核心图数据:始终留在本机
图数据统一保存在项目根目录下的.code-review-graph/graph.db,这是一个 SQLite 数据库(WAL 模式)。从源码可以确认其固定位置:
- code_review_graph/cli.py 中
db_path = Path(args.data_dir).expanduser().resolve() / "graph.db"与默认的repo_root / ".code-review-graph" / "graph.db"两条路径解析逻辑; - code_review_graph/daemon.py 的监听守护进程同样使用
Path(repo.path) / ".code-review-graph" / "graph.db"; - code_review_graph/incremental.py 还实现了从旧版顶层
.code-review-graph.db到新目录结构的自动迁移; - docs/FEATURES.md 说明该目录会被自动加入 gitignore。
CLAUDE.md 进一步确认数据库以 SQLite WAL 模式运行,节点、边与向量均存放在这一单个 SQLite 文件中。这意味着代码库的结构图谱、调用关系、评审上下文等核心资产完全落在开发者自己的机器上,不经过任何第三方服务器。
3.2 本地嵌入:默认离线路径
语义搜索所用的向量嵌入默认走local提供方(sentence-transformers)。code_review_graph/embeddings.py 中定义了合法提供方集合:
_VALID_PROVIDERS = {"local", "openai", "google", "minimax", "voyage"}local 提供方完全在本地计算嵌入,无需 API Key、不产生网络请求。其唯一例外是:首次使用时会从 HuggingFace 下载一次 sentence-transformers 模型(默认模型all-MiniLM-L6-v2,见 README.md 环境变量表)。SECURITY.md 将此列为唯一与本地嵌入相关的网络调用:"首次使用 sentence-transformers 时从 HuggingFace 一次性下载模型"。若需要完全离线的环境,可预先下载并配置模型路径,使后续运行不再触碰网络。
3.3 云嵌入:显式选择才出境
当用户显式选择云嵌入提供方时,被嵌入的源码片段会被发送到对应提供方,并在该提供方的服务条款下处理。docs/LEGAL.md明确指出:openai、google、minimax、voyage四个云提供方仅在"显式选择"时生效。
README 对"被发送的内容"给出了精确边界(README.md):code-review-graph 嵌入的是标识符、签名、结构上下文以及受限的第一段 docstring/doc 注释摘要,并不传输函数体(function bodies)。因此即使启用云嵌入,外发的是代码的"骨架与摘要"而非完整实现文本,但仍属于源码衍生内容,读者应据此评估合规风险。
各云提供方的激活条件(依据 README.md 环境变量表与 code_review_graph/embeddings.py):
| 提供方 | 必需配置 | 备注 |
|---|---|---|
| local | 无 | 默认离线,模型来自 sentence-transformers |
| openai | CRG_OPENAI_BASE_URL、CRG_OPENAI_API_KEY、CRG_OPENAI_MODEL | 兼容 OpenAI、Azure 及任意自托管网关(vLLM / LiteLLM / LocalAI 等) |
GOOGLE_API_KEY | 需显式 opt-in,Gemini 模型 | |
| minimax | MINIMAX_API_KEY | 需显式 opt-in |
| voyage | VOYAGE_API_KEY | 默认模型voyage-code-3,维度 1024 |
从 code_review_graph/embeddings.py 的get_provider()逻辑可见,未知提供方名称会抛出ValueError而非静默回退到本地,避免用户误以为仍在离线状态;当未显式指定提供方但已配置 OpenAI 兼容凭据时,会默认采用 openai 提供方(行为记录于该文件#551注释),这一点在配置敏感环境时需要留意。
四、出站警告机制:一次显式确认,可脚本化豁免
4.1 警告触发与内容
在返回任意云提供方之前,code_review_graph/embeddings.py 的_warn_cloud_egress()会向stderr打印警告,内容包括:
- 即将通过哪个云提供方对代码做嵌入;
- 源码(函数名、docstring、文件路径)将被发送到外部 API;
- 如需跳过后续警告,可设置
CRG_ACCEPT_CLOUD_EMBEDDINGS=1; - 若要完全离线,请改用默认的 local 提供方。
值得强调的是,警告只写 stderr,绝不写 stdout、也不读 stdin。这是为 MCP stdio 传输专门设计的:任何写入 stdout 的额外字节都会污染 JSON-RPC 协议流。对应测试 tests/test_embeddings.py 中的TestCloudProviderWarning明确断言"不应写入 stdout(否则会破坏 MCP stdio)",并校验captured.out == ""。
4.2 豁免方式一:环境变量
设置CRG_ACCEPT_CLOUD_EMBEDDINGS=1可抑制警告。源码实现(code_review_graph/embeddings.py):
if os.environ.get("CRG_ACCEPT_CLOUD_EMBEDDINGS", "").strip() == "1": return该机制面向脚本化 / CI 工作流:在命令行中一次性显式确认,后续运行不再重复提醒。典型用法(README.md):
export VOYAGE_API_KEY=pa-... export CRG_ACCEPT_CLOUD_EMBEDDINGS=1 code-review-graph embed --provider voyage --model voyage-code-3README.md 环境变量表中将其描述为"在显式确认后抑制云嵌入出站警告",默认值为空(未设置时不抑制)。
4.3 豁免方式二:localhost 端点自动跳过
docs/LEGAL.md与 README 还共同指向一个精细设计:当 OpenAI 兼容端点指向 localhost 时,出站警告自动跳过。code_review_graph/embeddings.py 的_is_localhost_url()使用urlparse().hostname提取真实主机名,与{"127.0.0.1", "localhost", "0.0.0.0", "::1"}比对——注意是基于主机名精确比较,而非子串匹配,可避免https://my-openai.127.0.0.1.nip.io这类伪装域名被误判为本地。语义很清晰:指向本机网关(如 vLLM、LocalAI、Ollama openai 模式)的请求根本没有数据出境,自然无需警告:
export CRG_OPENAI_BASE_URL=http://127.0.0.1:3000/v1 export CRG_OPENAI_API_KEY=sk-... export CRG_OPENAI_MODEL=text-embedding-3-small五、MCP 传输与本地绑定策略
5.1 stdio 与 Streamable HTTP 两种传输
code-review-graph 作为 MCP 服务器,默认通过stdio与 MCP 客户端通信(code_review_graph/main.py 模块文档),这是 MCP 的标准进程内传输,天然不产生网络端口暴露。也可通过code-review-graph serve --http启动Streamable HTTP服务,默认绑定 localhost 的 5555 端口。
从 code_review_graph/cli.py 的命令行定义可以确认:
code-review-graph serve [--http] [--host HOST] [--port PORT]--host帮助文本明确"绑定地址(默认:127.0.0.1)";- 服务端代码中
host = args.host if args.host is not None else "127.0.0.1",确认默认仅回环地址可达。
5.2 为什么 loopback 绑定还不够:DNS Rebinding 防御
docs/LEGAL.md指出"Streamable HTTP MCP 传输绑定到 localhost 是默认行为"。但仓库中的 code_review_graph/http_origin_guard.py 指出一个容易被忽视的安全细节:loopback 绑定本身并不能构成浏览器场景下的访问控制——攻击者可以诱导用户访问一个将域名解析到 127.0.0.1 的恶意页面(DNS rebinding),从而驱动本机 MCP 工具读取用户源码。
该模块的防御手段是对Host与Origin两个请求头做校验:
Host:被 rebind 的请求携带的是攻击者控制的域名而非127.0.0.1/localhost,基于 allow-list 拒绝;Origin:跨站请求携带发起站点来源;普通 MCP 客户端不是浏览器、不发送Origin,因此"存在 Origin 时要求其必须指向 loopback 端点"不会影响正常客户端。
此外,is_loopback_host()使用ipaddress做数值校验,覆盖整个127.0.0.0/8段,而非仅信任127.0.0.1字符串。该守卫仅在绑定 loopback 地址(默认情形)时生效;显式--host 0.0.0.0属于主动暴露端点的决策,守卫会让位于操作者自己的主机名策略。
六、隐私模型的行为验证:测试即文档
仓库测试 tests/test_embeddings.py 将隐私行为固化为可回归验证的断言,可作为理解docs/LEGAL.md条款的"活文档":
test_minimax_triggers_stderr_warning/test_google_triggers_stderr_warning:使用云提供方时,stderr 出现 provider 名与 "cloud"、"sent to an external API" 等字样,且 stdout 为空;test_accept_env_var_suppresses_warning:设置CRG_ACCEPT_CLOUD_EMBEDDINGS=1后 stderr 与 stdout 均为空;test_local_provider_never_warns:本地提供方永远不触发云警告。
这些测试与 CHANGELOG.md 中记录的 PR #228(关闭 issue #174)对应:该变更引入"云嵌入 stderr 警告",并明确"警告仅在 stderr,绝不写 stdout、不读 stdin,因此 MCP stdio 传输不会被污染"。
七、数据生命周期与担保声明
7.1 数据处置
docs/LEGAL.md的 "Data" 一节总结:核心图数据始终留在本机;只有当你选择云嵌入提供方时,被嵌入的文本才会在该提供方条款下离开本机。此外,code_review_graph/uninstall.py 提供了完整的卸载清理路径,涵盖.code-review-graph目录及遗留的旧版数据库文件(.code-review-graph.db、-wal、-shm),帮助用户在不需要时彻底移除本地图数据。
7.2 免责担保
最后,docs/LEGAL.md以标准免责声明收尾:软件按现状(as-is)提供,不附带任何形式的担保。这是 MIT 许可协议的常规组成部分,意味着项目不承诺特定功能在特定环境下的适销性或适用性;对于生产或敏感环境,应在部署前结合 docs/TROUBLESHOOTING.md、docs/FAQ.md 与 SECURITY.md 完成自测。
八、实践清单:让本地优先落到实处
结合docs/LEGAL.md与源码证据,给出敏感代码库中的可执行配置清单:
- 默认即可离线:不做任何嵌入配置时,
local提供方 + 图数据本地 SQLite 存储,核心工作流零网络调用; - 首次使用前预置模型:如需完全离线,预先下载 sentence-transformers 模型并设置
CRG_EMBEDDING_MODEL,避免首次运行时访问 HuggingFace; - 云嵌入三要素:只有显式配置
provider="openai|google|minimax|voyage"并补齐对应 API Key / 端点环境变量才会出境,且默认会收到 stderr 警告; - 确认出站:在脚本或 CI 中,用
CRG_ACCEPT_CLOUD_EMBEDDINGS=1完成一次性确认;本地自托管网关(127.0.0.1)自动豁免; - 外发内容知情:云嵌入外发的是标识符、签名、结构上下文与受限 docstring 摘要,不含函数体(见 README.md);
- HTTP 服务保持默认绑定:非必要不修改
serve --http的默认 127.0.0.1 绑定,以保留Host/Origin校验对 DNS rebinding 的防护; - 卸载可清理:需要退出时,通过卸载流程连同
.code-review-graph目录一并移除本地数据(code_review_graph/uninstall.py)。
以上每一项均可从 docs/LEGAL.md、SECURITY.md 与本文引用的源码文件中得到直接印证,是理解 code-review-graph 隐私模型最可靠的依据。
【免费下载链接】code-review-graphLocal-first code intelligence graph for MCP and CLI. Builds a persistent map of your codebase so AI coding tools read only what matters, with benchmarked context reductions on reviews and large-repo workflows.项目地址: https://gitcode.com/GitHub_Trending/co/code-review-graph
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考