fix(review): screen content filters before the probe tree's restore too (#9558) - #9741
Closed
wenshao wants to merge 22 commits into
Closed
fix(review): screen content filters before the probe tree's restore too (#9558)#9741wenshao wants to merge 22 commits into
wenshao wants to merge 22 commits into
Conversation
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What this PR does
Replaces #9566 at its original size. Same single commit, rebased onto current
main, nothing else.scratch-treerefuses to create or reset a tree while the repository's local config defines a content filter: a checkout executesfilter.<name>.smudgewhenever it rewrites a file, and pointingcore.hooksPathat nothing covers hooks, not filters.test-efficacy's per-run restore is the same checkout one directory over —checkout --force HEAD -- .rewrites every tracked file in the probe tree, twice per probe run — and it screened nothing.Three changes: the screen runs before the probe tree's restore; it moves to
lib/worktree.tsso both callers share one implementation instead of one growing a corner the other lacks; andfilter.<name>.processjoinssmudgeandcleanas the third executable key.Why a new PR
#9566 was this commit plus six more that grew it from 5 files / +160 to 13 files / +3 054 — into
base-tree.ts,fetch-pr.tsandlib/git.ts, none of which this change is about. The point of splitting the #9221 follow-ups was that each one stay small enough to read. Opening a replacement rather than force-pushing keeps #9566's review history intact for anyone who wants it.Why repo-local only — the load-bearing part
git lfs installwritesfilter.lfs.cleaninto the user's global config. A screen over merged config would put every contributor with git-lfs into permanent refusal — the same failure as a tripwire that fires on every healthy run, which this pipeline has already shipped once (#9221 round 15:git statusreported nothing while the tripwire reported 3 957 paths).Known gap, deliberately not fixed here
git config --filedoes not expandinclude.path/includeIf— that is git's documented default for--file— while the checkouts this screen authorises read merged config, which does. A filter reached through an include directive therefore passes the screen.The finding is real. The obvious fix is not: adding
--includesmakes the screen follow aninclude.paththat names the user's own global config, which dragsfilter.lfs.cleanback in and reproduces exactly the permanent-refusal failure the paragraph above exists to avoid. Doing it correctly means resolving each hit's origin file (--show-origin) and refusing only when that origin is repo-local — which is its own change, with its own tests, and does not belong in a PR whose purpose is to be small again.Reviewer Test Plan
How to verify
cd packages/cli && npx vitest run src/commands/review→ 4 504 passed, 1 skipped, 0 failed.New coverage in
test-efficacy.test.ts: a repo-localfilter.evil.smudgemakes the mutant runinconclusivenaming the filter; the same fixture with the filter moved to the user's global config runs through without a filter refusal.scratch-tree.test.tsgains thefilter.evil.processarm.Evidence (Before & After)
Each half verified by reverting it alone and watching the test go red:
test-efficacy--filedropped)processfrom the key regexfilter.evil.processno longer refusesThe middle row is the one worth reading: it is the false-positive direction, and without a test it is the change a later round would make while "tightening" the screen.
Tested on
macOS 26.6 (Darwin 25.6.0), Node 24,
packages/clivitest 3.2.4.Risk & Scope
Small and confined to
packages/cli/src/commands/review. One new refusal path in the efficacy probe: a repository whose local config carries a content filter reportsinconclusivefor that run instead of running the filter. No user-facing surface.Linked Issues
Closes #9558. Replaces #9566. Follow-up from #9221; the class it belongs to is #9556.
中文说明
这个 PR 做了什么
以原始尺寸替代 #9566。同一个提交,重新基于当前
main,没有别的东西。scratch-tree在仓库本地配置定义了内容过滤器时拒绝创建或重置树:checkout 每次重写文件都会执行filter.<name>.smudge,而把core.hooksPath指向空处只覆盖钩子、覆盖不到过滤器。test-efficacy每次运行前的恢复是同一种 checkout 挪了一个目录——checkout --force HEAD -- .会重写探针树里每个已跟踪文件、每次探针运行两次——而它什么也没屏蔽。三处改动:屏蔽在探针树恢复之前执行;移到
lib/worktree.ts让两个调用方共用一份实现,而不是其中一个长出另一个没有的角落;filter.<name>.process作为第三个可执行键与smudge、clean并列。为什么新开 PR
#9566 是这个提交外加另外六个,把它从 5 文件 / +160 撑到 13 文件 / +3 054,摊进了
base-tree.ts、fetch-pr.ts、lib/git.ts——都不是本改动要谈的东西。拆 #9221 后续项的意义,就在于每一个都小到能读完。开替代 PR 而不是 force-push,是为了让 #9566 的评审历史对需要的人完整保留。为什么只看仓库本地——这是承重部分
git lfs install会把filter.lfs.clean写进用户的全局配置。对合并后配置做屏蔽,会让每个装了 git-lfs 的贡献者永久处于拒绝态——与"每次健康运行都触发的绊线"是同一种失败,而本流水线已经犯过一次(#9221 第 15 轮:git status一条没有,绊线报 3 957 条路径)。已知缺口,本 PR 有意不修
git config --file不会展开include.path/includeIf——这是 git 对--file的文档化默认——而本屏蔽所授权的 checkout 读的是合并后配置,是会展开的。因此经由 include 指令到达的过滤器能通过屏蔽。这条发现成立。但显而易见的那个修法不成立:加上
--includes会让屏蔽跟随一条指向用户自己全局配置的include.path,从而把filter.lfs.clean拖回来,精确复刻上一段所要避免的永久拒绝。要做对,需要解析每个命中的来源文件(--show-origin)、仅当来源是仓库本地时才拒绝——那是它自己的一次改动、有它自己的测试,不属于一个"目的就是重新变小"的 PR。审查者验证方案
如何验证
cd packages/cli && npx vitest run src/commands/review→ 4 504 通过、1 跳过、0 失败。test-efficacy.test.ts新增覆盖:仓库本地的filter.evil.smudge让突变体运行判为inconclusive并点名该过滤器;同一夹具把过滤器改放到用户全局配置后,运行照常通过、不产生过滤器拒绝。scratch-tree.test.ts增加filter.evil.process一臂。证据(Before & After)
每一半都以"单独回退该项 → 对应测试变红"验证(见上表)。中间那一行最值得看:它是误报方向;没有这条测试,它正是后来某一轮在"收紧"屏蔽时会做出的改动。
测试环境
macOS 26.6(Darwin 25.6.0)、Node 24、
packages/clivitest 3.2.4。风险与范围
小,且限于
packages/cli/src/commands/review。效力探针新增一条拒绝路径:本地配置带内容过滤器的仓库,该次运行报inconclusive而不是执行过滤器。无用户可见面。关联 Issue
Closes #9558。替代 #9566。来自 #9221 的后续;所属类别是 #9556。