
qwen-code 仓库审查上下文清单.qwen/review-context.json的声明式契约、信任边界与 fail-closed 实现【免费下载链接】qwen-codeAn open-source AI coding agent that lives in your terminal.项目地址: https://gitcode.com/GitHub_Trending/qw/qwen-code导读qwen-code 的代码审查流水线qwen review需要一种**有界bounded**的方式让每个仓库在不修改共享审查逻辑的前提下声明自己的审查指引——例如推荐测试、必需配置、专属审查角色。本文以设计文档 docs/design/review-repository-context.md 为核心完整讲解.qwen/review-context.json清单的字段语义、glob 语法约束、各类上限与校验规则并结合 manifest-repository-context.ts 等实现源码深入剖析其安全信任边界PR 审查只读 merge-base、本地审查读 worktree与 fail-closed 原则。读完你不仅能正确编写自己的审查上下文清单还能理解它为何在恶意仓库面前依然安全。问题背景为什么仓库需要有界的审查声明审查流水线在多个环节共享 roster角色清单、prompt提示词、coverage覆盖检查和 composition审查编排逻辑。若让这些共享代码去逐个了解每个项目的特殊约定会造成严重的耦合与维护负担。更关键的是安全维度对于拉取请求PR审查被审查分支本身是不可信的——如果审查逻辑直接读取 PR 头head分支上的配置文件那么攻击者提交的恶意分支就可以选择加入或移除可信上下文从而操纵审查结果。因此仓库声明的审查指引必须有严格的 schema 与边界不能无限膨胀、不能拖垮审查步骤在 PR 场景下只允许从可信的 merge-base 提交读取任何异常都fail-closed宁可报错中止也不静默降级成该仓库没有上下文。设计文档给出的解法是一个固定路径的严格 JSON 清单.qwen/review-context.json由静态注册的 manifest provider 解析并以统一的RepositoryContext结构输出给下游。Manifest 规范字段、示例与解析约束顶层结构清单必须是严格 JSON无注释、无尾逗号顶层字段恰好为version、label、rules三个多一个或少一个都会被拒绝{ version: 1, label: Example repository, rules: [ { paths: [packages/*/src/**], relatedPaths: [packages/cli/src/commands/review/**], domains: [runtime], recommendedTests: [test:runtime], requiredConfigurations: [debug], requiredAgents: [test-matrix], unverifiedDimensions: [Alternate configuration], verificationNotes: [Run the repository-native focused tests] } ] }顶层与规则的合法键集合在 manifest-repository-context.ts 中被固定为常量顶层是label/rules/version规则是domains/paths/relatedPaths/recommendedTests/requiredAgents/requiredConfigurations/unverifiedDimensions/verificationNotes通过hasExactKeys做精确键匹配L109-L118。规则字段语义字段必填语义paths是命中规则的条件任一变更路径匹配其中任一 glob则规则生效relatedPaths否相关文件 glob命中后会从 worktree 展开为实际文件列表加入上下文domains否该代码域的领域标签供审查方定位知识recommendedTests否推荐运行的测试命令交给 build-and-test 角色requiredConfigurations否必需配置项同样交给 build-and-test 角色requiredAgents否必须加入 roster 的审查角色 ID必须是受支持的角色unverifiedDimensions否未验证维度作为非阻塞的证明边界proof boundary披露verificationNotes否验证说明例如运行仓库原生聚焦测试其余字段全部可选。规则顺序被保留规则之间不排序但数组内部的值是人工书写的、允许任意顺序——provider 会先合并、去重、排序再交给 wire 格式的严格排序且唯一校验从而避免配置文件没排序导致整个审查失败的坑见 manifest-repository-context.ts 与测试用例accepts unsorted manifest arrays and sorts the merged output。合并语义当多条规则同时命中时各规则数组字段relatedPaths、domains、recommendedTests等的取值会合并、去重、排序后返回保持唯一性paths的总量、合并后的relatedPaths总量、以及每个合并字段都受上限约束见下节。值得注意示例中relatedPaths的通配范围刻意限定在单个子系统packages/cli/src/commands/review/**因为通配relatedPaths受 256 个解析文件的硬上限约束像packages/*/src/**这种仓库级范围在当前仓库规模下会直接超限。无命中时的行为如果没有任何规则命中任何变更路径provider 返回null无上下文空变更集同样返回null。这意味着清单的声明是按变更路径触发的而非仓库存在清单就全局附加上下文。Glob 语法约束小而安全paths与relatedPaths使用仓库相对路径、以/分隔的 glob支持的元字符*、?、以及完整的**路径段**必须独占一个段a**这类混用会被拒绝大小写敏感在所有平台一律区分大小写?的语义消耗一个 UTF-16 code unit而非一个字符这对非 BMP 字符有意义拒绝项绝对路径、反斜杠、空段、./..段、!否定、花括号展开、字符类、扩展 glob 语法以及以通配符开头导致展开可能从仓库级通配开始的relatedPaths通配relatedPaths必须以非通配目录段开头。validateGlob在 manifest-repository-context.ts 中逐段校验并额外拒绝任何深度进入依赖目录或构建输出目录的 glob大小写不敏感地比较——这样绝不进入跳过目录的不变量对扫描根和递归都成立。通配匹配的算法安全值得注意的实现细节glob 段匹配使用了多项式时间的迭代匹配器segmentMatchesL322-L346而不是回溯正则——注释明确指出被替换的正则在一个段含多个*时会指数级退化一个合法清单模式加上一个合法长文件名就能让单次test()调用近乎永远挂起在不可信仓库中这两半都是攻击者可控的。跨段匹配globMatches则带 memo 缓存。这是审查步骤不能被恶意清单卡死这一目标的直接体现。边界与上限每个维度都 fail-closed所有上限集中定义于 repository-context.ts 与 manifest-repository-context.ts并由共享的validateRepositoryContext校验器统一执行常量值作用对象MAX_IDENTITY_BYTES1 MiB单次身份文件读取worktree 读取按 stat 大小、解析按内容长度双重强制MAX_ARRAY_ITEMS256单个数组项数、合并后relatedPathsglob 总数、paths总数MAX_RULES128清单规则条数MAX_LABEL_LENGTH120label长度MAX_TOKEN_LENGTH160domains/recommendedTests/requiredConfigurations/requiredAgents单项长度MAX_NOTE_LENGTH512unverifiedDimensions/verificationNotes单项长度MAX_PATH_LENGTH512glob 模式长度MAX_GLOB_CANDIDATES16384单次relatedPaths展开的访问条目数文件目录含不匹配项MAX_MATCH_WORK1 GiB单位pattern 长度 × 路径长度单阶段匹配工作量预算规则过滤与展开两处都计费其中MAX_GLOB_CANDIDATES依据本仓库安装后 checkout 校准整个packages/树都在该上限之内因此诚实的子树范围永远不触发失败而病态的扫描必定结束。MAX_MATCH_WORK则防止合法 schema 但恶意形态的匹配风暴——因为**匹配对段长是二次复杂度只按段数计费挡不住 schema 合法的卡死形态所以每次尝试的模式匹配都要按pattern.length × path.length扣预算匹配爆发时 fail-closed 而非拖垮步骤见 manifest-repository-context.ts 的详细注释。展开过程本身以点文件开启、目录结果禁用、符号链接遍历禁用、大小写敏感方式遍历 worktree已变更路径从结果中剔除解析出的文件必须停留在 worktree 内绝不进入依赖与构建输出树——跳过集合SKIPPED_DIRECTORIES固定为.git、.next、.playwright、.turbo、coverage、dist、node_modules、out、playwright-report、target、test-resultsL67-L79。完全静态的relatedPaths条目在作为常规文件存在时解析为自身。信任边界PR 只读 merge-base本地读 worktree身份文件的两种读取模式repo-context命令通过RepositoryContextProviderInput.readIdentityFile读取固定清单路径.qwen/review-context.json定义于 manifest-repository-context.ts身份读取的语义在 repository-context.ts 中有明确契约PR 计划清单只来自 fetch 阶段记录的可信 merge-base 提交baseTreeEntryreadBaseBlob用git ls-tree/git show读取该提交下的 blob。PR 头不能选择加入、不能选择退出、不能修改规则。本地计划清单来自当前 worktree经安全相对路径校验与 realpath 包含性检查后读取。两种模式返回相同形态CRLF 规范化为 LF、首尾空白裁剪见normalizeIdentityContent且读取上限 1 MiB、fail-closed文件缺失返回null但文件存在却不可读或超限则抛错——绝不把读取失败伪装成这不是本仓库。三种必须记录的残余residuals设计文档明确承认三个残余以免过度宣称保证PR 下规则来自 merge-base但relatedPaths是在 head worktree 上展开的——head 仍决定 base 的 glob 解析到哪些文件影响低因为审查者本来就读 head 树。本地审查从当前 worktree 读清单——审查一个不可信仓库时该仓库可以向每个代码审查简报注入一个 label 加六个受限数组的有界、无控制字符的指引块1 MiB 读取上限、校验边界和惰性渲染inert rendering是缓解手段。两种模式用不同引擎解析身份符号链接PR 读取器绝不穿过符号链接的中间路径组件worktree 读取器会穿过且身份符号链接链最多 16 跳内核可解析约 40 跳超限直接抛错而非降级。因此仓库把.qwen本身提交为指向树内目录的符号链接这一情形会在本地审查附加上下文、而 PR 审查永远不附加——方向是 fail-safe严格更少、绝不更多。运维若遇到上下文本地能附加、PR 永不附加应知道这是构造使然见 repo-context.ts 的readBaseIdentity注释。merge-base 解析失败时的降级trustedMergeBaserepo-context.ts定义了三种来源local未记录 merge base、base可信且已解析的 merge base、none无来源。后两种 PR 状态由流水线自身降级fetch-pr记录mergeBaseSha: null、或 base fetch 失败留下可能过期的 sha 时repo-context会直接写入nullartifact完全不 consult worktree——因为回退到 worktree 就等于从 PR 头读取清单那正是信任边界所禁止的读取而过期 sha 同样不是可信来源。Provider 注册与统一校验manifest provider 以静态方式进程内注册REPOSITORY_CONTEXT_PROVIDERS固定为[manifestRepositoryContextProvider]见 repo-context.ts输出provider: manifest的通用RepositoryContext形态。其完整输出在下游使用前必须通过共享的validateRepositoryContext校验器repository-context.ts该校验器要求精确键集合、版本匹配、provider匹配安全正则、每个数组排序且唯一wire 格式由构造确定化。不支持动态插件注册、shell 执行、模板或任意不透明 payload。审查工作流集成repo-context命令与角色编排命令调用在 review skillpackages/core/src/skills/bundled/review/SKILL.md中medium 与 high 努力的本地及同仓库 PR 审查在捕获审查计划capture plan之后、emit-workflow之前调用repo-context${QWEN_CODE_CLI:-qwen} review repo-context \ --plan absolute-plan-path \ --worktree absolute-worktree-path \ --out absolute-context-path要点均来自 SKILL.md三个参数必须是绝对路径以免后续 agent 的工作目录改变其含义low 努力的审查与跨仓库轻量审查跳过此命令它们不运行完整本地树工作流nullartifact无清单或无命中规则不是错误非零退出码是 fail-closed——必须停止审查并报告不能静默跳过该步骤继续必须在emit-workflow之前运行因为 roster 与每个 brief 都会烘焙该上下文——运行晚了会静默丢失清单要求的角色与指引。下游消费代码审查 agent 接收以 label 为标题的通用上下文build-and-test 角色接收recommendedTests、requiredConfigurations、verificationNotes。必需角色requiredAgents合并进正常 roster 且不重复且仅当该审查的努力级别、拓扑与模式本就允许时才生效——例如清单不能把 medium 审查膨胀出对抗性角色、不能给分块 fan-out 重新加回全 diff 走查者、不能向无树的审查要求树遍历角色。编排层把unverifiedDimensions作为非阻塞的证明边界披露而存在但无效的上下文会让所有下游消费者 fail-closed绝不会在任何环节被静默丢弃。实现与测试验证核心实现位于 packages/cli/src/commands/review/repo-context.ts命令入口611 行plan 解析、merge-base 可信来源判定、base 树身份读取、符号链接链解析、readIdentityFile的两种模式实现lib/manifest-repository-context.ts620 行清单解析、glob 校验、多项式匹配器、related 展开、全部上限常量lib/repository-context.ts278 行通用RepositoryContext契约、共享校验器、边界常量与安全路径工具。测试覆盖相当系统化lib/manifest-repository-context.test.ts1024 行另有 repo-context.test.ts 与 lib/repository-context.test.ts包括规则匹配、字段合并与 related 文件展开无清单/无命中/空变更集返回null规则数超MAX_RULES、paths总量超限、合并字段超 wire 边界时 fail-closed拒绝进入依赖/构建输出树的 globrelated 文件与目录的符号链接逃逸排除恰好落在 resolved-file 上限256与 visited-entry 上限16384的合法扫描被接受超限立即 fail-closed含静态分支未排序清单数组被接受、合并输出被排序嵌套 related glob 展开不重复计数被包含的根。现状与采用方式设计文档的 Status 明确指出这是地基——契约、命令与下游消费者由单元测试和 review skill 验证。本次变更并未随仓库发布任何.qwen/review-context.json因此除测试外尚无端到端运行实例直到某个仓库自行采纳清单为止。这也意味着如果你的团队希望在自己的 qwen-code 仓库中启用仓库级审查指引只需在仓库根目录创建.qwen/review-context.json并按上文 schema 声明规则——本地 medium/high 审查与同仓库 PR 审查便会自动附加对应上下文无需修改 qwen-code 的任何共享代码。【免费下载链接】qwen-codeAn open-source AI coding agent that lives in your terminal.项目地址: https://gitcode.com/GitHub_Trending/qw/qwen-code创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考