Skip to content

fix(core): treat grep -n as a flag so its file reads are still checked - #14383

Merged
yiliang114 merged 2 commits into
QwenLM:mainfrom
kabishou11:fix/grep-line-number-flag
Nov 3, 2026
Merged

yiliang114 merged 2 commits into
QwenLM:mainfrom
kabishou11:fix/grep-line-number-flag

Conversation

@kabishou11

Copy link
Copy Markdown
Contributor

What this PR does

The shell permission analysis no longer treats grep -n / grep --line-number as a flag that takes a value. Running grep -n pattern file (and the same flags on egrep, fgrep, zgrep and bzgrep) is now reported as reading file, the same as grep pattern file.

Why it's needed

GNU grep's -n / --line-number only prints line numbers and takes no argument. The grep handler listed them among the flags that consume the next token. So for grep -n pattern /etc/hosts the pattern was swallowed as the flag's value, then treated as the pattern, and the file list ended up empty. Permission checks only escalate from the file operations this analysis reports, so a Read deny rule on that file did not apply to the very common line-number grep, even though plain grep pattern file was caught.

Reviewer Test Plan

How to verify

Run npx vitest run src/permissions/shell-semantics.test.ts in packages/core. The new case grep: -n is line numbers and does not consume the pattern checks that extractShellOperations('grep -n pattern /etc/hosts', cwd) returns a read_file operation for /etc/hosts.

Evidence (Before & After)

Before: extractShellOperations('grep -n pattern /etc/hosts', cwd) returns [], and the new test fails with expected [] to deeply equal [ { virtualTool: 'read_file', filePath: '/etc/hosts' } ].

After: it returns [{ virtualTool: 'read_file', filePath: '/etc/hosts' }], and the file passes (110 tests). Prettier and ESLint are clean on the changed files.

Tested on

OS Status
🍏 macOS ⚠️
🪟 Windows ⚠️
🐧 Linux ✅

Environment (optional)

N/A (unit tests only)

Risk & Scope

  • Main risk or tradeoff: none expected. Only -n / --line-number move out of the value-flag list; flags that do take a value (-e, -f, -m, -A/-B/-C, --include, ...) are unchanged, and head -n uses a different handler.
  • Not validated / out of scope: other commands' flag tables.
  • Breaking changes / migration notes: none.

Linked Issues

None.

中文说明

这个 PR 做了什么

Shell 权限分析不再把 grep -n / grep --line-number 当作带参数的选项。现在 grep -n pattern file(以及 egrep、fgrep、zgrep、bzgrep 加同样的选项)会和 grep pattern file 一样,被识别为读取 file。

为什么需要

GNU grep 的 -n / --line-number 只是打印行号,不带参数。原来的 grep 处理器把它们列进了“会吃掉下一个参数”的选项里。于是 grep -n pattern /etc/hosts 中,pattern 被当成选项的值吞掉,文件名又被当成 pattern,最后文件列表是空的。权限检查只根据这里报告的文件操作来升级,所以针对某个文件的 Read 拒绝规则拦不住最常见的带行号 grep,而普通的 grep pattern file 能拦住。

审阅者测试计划

如何验证

在 packages/core 下运行 npx vitest run src/permissions/shell-semantics.test.ts。新用例 grep: -n is line numbers and does not consume the pattern 检查 extractShellOperations('grep -n pattern /etc/hosts', cwd) 会返回对 /etc/hosts 的 read_file 操作。

证据(修改前后)

修改前:extractShellOperations('grep -n pattern /etc/hosts', cwd) 返回 [],新测试失败,报错 expected [] to deeply equal [ { virtualTool: 'read_file', filePath: '/etc/hosts' } ]。

修改后:返回 [{ virtualTool: 'read_file', filePath: '/etc/hosts' }],整个文件通过(110 个测试)。改动文件的 Prettier 和 ESLint 检查都通过。

测试平台

Linux 已测试;macOS、Windows 未在本地测试。

环境(可选)

不适用(只跑了单元测试)。

风险与范围

  • 主要风险或取舍:预计没有。只有 -n / --line-number 移出了带值选项列表;真正带值的选项(-e、-f、-m、-A/-B/-C、--include 等)不变,head -n 用的是另一个处理器。
  • 未验证 / 不在范围内:其他命令的选项表。
  • 破坏性变更 / 迁移说明:无。

关联 Issue

无。

# Conflicts:
#	packages/core/src/permissions/shell-semantics.test.ts
@qwen-code-review-bot

qwen-code-review-bot commented Oct 16, 2026 •

Copy link
Copy Markdown
Collaborator

✅ Qwen Triage finished — CI landed green on 1bda967 and the deferred approval was posted. finalize run

✅ Qwen Triage 已完成 —— 1bda967 的 CI 全绿,延迟审批已提交。查看 finalize 运行

@qwen-code-review-bot

Copy link
Copy Markdown
Collaborator

Thanks for the PR!

Template looks good ✓

Problem: real and reproduced, not theoretical. -n / --line-number were listed among the grep flags that consume the next token, so in grep -n pattern /etc/hosts the pattern was eaten as the flag's value, the filename became the pattern, and the analysis reported no file operation at all. I traced this through getPositionalArgs and confirmed it — positional ends up as just the filename, slice(1) drops it, and the handler returns []. Since permission checks only escalate from the operations this analysis reports, a Read deny rule on that path never fired for the most common form of grep. GNU grep's -n genuinely takes no argument, so the entry was simply wrong. The before/after in the description plus the new unit test are a proper reproduction.

Direction: aligned. This is a correctness fix in permission analysis, and it fails in the safe direction — the analysis now reports more file operations, so more commands get checked rather than fewer. It does not expand what the shell tool can do.

Size: touches core (packages/core/src/permissions/). 4 production lines (2 added, 2 removed in shell-semantics.ts), 5 test lines, 0 generated/schema. Far below any escalation threshold — no maintainer awareness flag needed on size.

Approach: the scope is right. Deleting two entries from one flag set is the minimal fix, and the comment left behind explains why they must not come back — worth the two lines, since -n taking a value is exactly the mistake someone would re-introduce by analogy with head -n. I checked that head keeps its own separate handler with its own -n, so head -n 10 is unaffected. egrep/fgrep/zgrep/bzgrep delegate to the same handler and inherit the fix, which is also correct — their -n takes no argument either.

One consequence worth naming, not a blocker: combined short flags change too. grep -rn pattern dir previously matched -n through the combined-flag path and swallowed the pattern, reporting nothing; now the pattern stays positional and dir is reported. That is an improvement, but isRecursive only matches exact -r/-R/--recursive tokens, so -rn resolves to read_file rather than list_directory. That is a pre-existing gap this PR makes visible rather than introduces — reasonable to leave for a follow-up.

Risk: no elevated risk signals — neither changed file matches the revert-correlated paths.

Moving on to code review. 🔍

中文说明

感谢贡献!

模板完整 ✓

问题: 真实且可复现,不是理论性加固。-n / --line-number 被列进了 grep「会吃掉下一个 token」的选项里,于是 grep -n pattern /etc/hosts 中 pattern 被当作选项的值吞掉,文件名变成了 pattern,分析结果完全不报告任何文件操作。我顺着 getPositionalArgs 跟了一遍,确认了这个行为——positional 最后只剩文件名,slice(1) 把它丢掉,handler 返回 []。由于权限检查只依据这里报告的文件操作来升级,针对该路径的 Read 拒绝规则对最常见的带行号 grep 根本不会生效。GNU grep 的 -n 确实不带参数,所以这两个条目本身就是错的。描述里的 before/after 加上新增单测构成了完整的复现。

方向: 对齐。这是权限分析的正确性修复,而且失败方向是安全的——分析现在会报告更多文件操作,被检查的命令变多而不是变少,不会扩大 shell 工具的能力边界。

规模: 触及核心路径(packages/core/src/permissions/)。生产代码 4 行(shell-semantics.ts 增 2 删 2),测试 5 行,生成/schema 0 行。远低于任何升级阈值,无需因规模提醒维护者。

方案: 范围合适。从一个选项集合里删掉两个条目就是最小修复;留下的注释说明了为什么不能加回来——这两行是值得的,因为「-n 带值」正是别人参照 head -n 很容易重新引入的错误。我确认了 head 有自己独立的 handler 和独立的 -n,所以 head -n 10 不受影响。egrep/fgrep/zgrep/bzgrep 都委托给同一个 handler,会一并继承这个修复,这也是对的——它们的 -n 同样不带参数。

有一个值得点明的连带影响,但不是阻塞项:组合短选项的行为也变了。grep -rn pattern dir 之前会通过组合选项分支匹配到 -n 并吞掉 pattern,什么都不报告;现在 pattern 保留为位置参数,dir 会被报告出来。这是改进,但 isRecursive 只精确匹配 -r/-R/--recursive,所以 -rn 会被解析成 read_file 而不是 list_directory。这是本 PR 让它变得可见、而非由它引入的既有缺口——留到后续处理是合理的。

风险: 无升级风险信号——两个改动文件都不匹配与 revert 相关的高风险路径。

进入代码审查 🔍

— Qwen Code · qwen3.8-max-2026-09-02

Reviewed at 1bda9676a2b7f13f5a534a01b3b6114f4dc696c8 · re-run with @qwen-code /triage

@qwen-code-review-bot

qwen-code-review-bot commented Oct 16, 2026 •

Copy link
Copy Markdown
Collaborator

Code review

No blocking issues. I read the change against getPositionalArgs rather than taking the description's word for it, and the diagnosis holds exactly as stated.

The fix is correct. With -n in the value-flag set, grep -n pattern /etc/hosts skips pattern as the flag's value, leaving positional = ['/etc/hosts']; since there is no -e/-f, slice(1) drops the only real path and the handler returns []. With -n removed it falls through as a plain flag, positional = ['pattern', '/etc/hosts'], and slice(1) yields the file. The direction of the error is the one that matters for a permission gate: the old code under-reported, so a Read deny rule silently did not apply.

It also fixes a second case the description does not mention. grep -n -e pattern file previously consumed -e as -n's value, which left hasPatternFlag true while the pattern stayed positional — so the analysis reported a bogus read_file on the literal string pattern. That goes away too.

Consumers checked. This is a core path, so I traced everything downstream rather than assuming:

  • head has its own handler with its own -n set (line 521) — head -n 10 is unaffected, confirming the description's claim.
  • egrep/fgrep/zgrep/bzgrep delegate to the same handler and inherit the fix, correctly — their -n takes no argument either.
  • rg has a separate flag set and is untouched.
  • --line-number appears exactly once in packages/ (the line being removed), so no other code path depends on it.
  • The real consumers are permission-manager.ts (4 call sites) and autoMode.ts, both via extractShellOperationsAcrossCommand. The change can only add operations to the returned list, so the effect is strictly more checking, never less. Fail-safe.
  • No existing test asserts the old behavior — nothing in the permissions suite uses grep with an n-bearing flag, and the neighbouring cat -n / head -n 10 cases use different handlers.

Two tests outside the permissions suite use grep -rn, and this PR changes what that resolves to. Previously -rn matched -n through the combined-short-flag branch and swallowed the pattern, so the analysis returned nothing; now the pattern stays positional and the trailing directory is reported. I checked both and neither should break:

  • daemon-git-worktree-guard.test.ts asserts grep -rn 'git reset' src is allowed: true. That guard keys on git relocation markers and unrecognized program words, not on grep's file ops, and the new op is a relative in-workspace path — so the assertion should still hold. Worth a glance when CI lands, since it is the one place a newly-reported op could plausibly interact with a guard decision.
  • session-pr-service.test.ts asserts runs("grep -rn 'gh pr create' .") is false. runs() does program-word detection, not file-op extraction — unaffected.

Non-blocking suggestions, neither of which should hold the PR:

  • The diff removes both -n and --line-number but only adds a test for -n. One more row for the long form would be nearly free and would stop a future edit from reintroducing it.
  • As noted in the gate comment, grep -rn pattern dir now reports read_file on dir rather than list_directory, because isRecursive only matches exact -r/-R/--recursive tokens and not combined forms. Pre-existing gap, newly visible, fine as a follow-up.

The comment left in the set is the right call — -n taking a value is precisely the mistake someone would reintroduce by analogy with head -n.

Test evidence

Unattended CI run — I did not build or execute any PR code. The evidence below is this PR's own CI on the reviewed commit, fetched once via the API. The unit suite had not finished at the time of this review, so there is no green result to quote yet; the pending jobs are listed as pending rather than guessed at.

Final CI results for 1bda967 (auto-updated by the triage finalize job after CI completed):

Check Conclusion
Classify PR ✅ success
Integration Tests (no-AK, No Sandbox) ✅ success
Lint & Static (ubuntu-latest, Node 22.x) ✅ success
Test (ubuntu-latest, Node 22.x) ✅ success
web-shell E2E Smoke (ubuntu-latest, Node 22.x) ✅ success

One row per check name (latest run); skipped checks omitted; failures sort first. / 每个检查名一行(取最新一次运行),省略 skipped,失败项排在最前。

No check has failed, so there is no log excerpt to quote. macOS and Windows unit jobs are skipped by this repo's workflow config, not by anything in the PR — and since the change is pure string-token parsing with no platform-dependent branch, the Linux job is the meaningful signal here. The author reports testing on Linux only; that is the author's claim, not independently re-run, and the change has no OS-specific path that would make it load-bearing.

The new unit test does pin the change — it asserts the exact read_file operation that the old code failed to produce, so removing the fix turns it red. That is a real pin, not a suite that passes either way.

Sandboxed verification would still settle the part the unit test cannot: @qwen-code /verify — that a Read deny rule on a file now actually blocks grep -n pattern <file> end-to-end through the permission manager. The unit test pins extractShellOperations returning the operation; nothing here demonstrates the deny path engaging on it, and that user-visible consequence is the whole point of the PR. The author has read-only access, so this would be a sponsored run — a maintainer's @qwen-code /verify comment approves the head it was written against, and that run carries a pre-execution risk screen and a full workspace wipe. Read the resulting report with the same skepticism as the fork's own CI logs: the code under verification is adversarial input and can shape what the report says, even though the sandbox bounds what it can do.

Real-scenario testing

N/A on this run — unattended CI, so no tmux session was driven and PR code was never executed. The live-behaviour gap is named above with the lane that would close it.

中文说明

代码审查

没有阻塞性问题。我是对照 getPositionalArgs 逐行读的,没有直接采信描述——结论与描述完全一致。

修复是正确的。 -n 在带值选项集合里时,grep -n pattern /etc/hosts 会把 pattern 当作选项的值跳过,positional 只剩 ['/etc/hosts'];因为没有 -e/-f,slice(1) 把唯一真实的路径丢掉,handler 返回 []。移除 -n 后它作为普通选项被跳过,positional = ['pattern', '/etc/hosts'],slice(1) 正确得到文件。出错的方向正是权限门禁最在乎的那种:旧代码少报,导致 Read 拒绝规则静默失效。

它还顺带修好了描述里没提到的第二种情况。grep -n -e pattern file 之前会把 -e 当成 -n 的值吃掉,于是 hasPatternFlag 为真而 pattern 仍留在位置参数里——分析结果会对字面量字符串 pattern 报一个虚假的 read_file。这个问题也一并消失了。

下游消费方已核查。 这是核心路径,所以我逐个追踪而非假设:

  • head 有自己独立的 handler 和独立的 -n 集合(521 行)——head -n 10 不受影响,证实了描述的说法。
  • egrep/fgrep/zgrep/bzgrep 委托同一 handler,一并继承修复,这是对的——它们的 -n 同样不带参数。
  • rg 用独立的选项集合,未被触及。
  • --line-number 在 packages/ 下只出现一次(就是被删的那行),没有其他代码路径依赖它。
  • 真正的消费方是 permission-manager.ts(4 处调用)和 autoMode.ts,都经由 extractShellOperationsAcrossCommand。这个改动只可能增加返回列表里的操作,因此效果严格是「检查更多」而非更少,失败方向安全。
  • 没有任何现有测试断言旧行为——permissions 测试套件里没有一处对 grep 使用含 n 的选项,相邻的 cat -n / head -n 10 用例走的是不同 handler。

permissions 套件之外有两个测试用了 grep -rn,而本 PR 改变了它的解析结果。 之前 -rn 会通过组合短选项分支匹配到 -n 并吞掉 pattern,分析结果为空;现在 pattern 保留为位置参数,末尾的目录会被报告出来。两个我都看过,都不应该被打破:

  • daemon-git-worktree-guard.test.ts 断言 grep -rn 'git reset' src 为 allowed: true。该 guard 关注 git 重定位标记和无法识别的程序词,而不是 grep 的文件操作,且新增的操作是工作区内的相对路径——断言应当依然成立。CI 出结果后值得扫一眼,因为这是新增操作唯一有可能与 guard 决策相互影响的地方。
  • session-pr-service.test.ts 断言 runs("grep -rn 'gh pr create' .") 为 false。runs() 做的是程序词识别,不是文件操作提取——不受影响。

非阻塞建议,两条都不该卡住这个 PR:

  • diff 同时移除了 -n 和 --line-number,但只为 -n 加了测试。给长选项再补一行几乎零成本,能防止后续改动把它加回来。
  • 如门禁评论所述,grep -rn pattern dir 现在会对 dir 报 read_file 而不是 list_directory,因为 isRecursive 只精确匹配 -r/-R/--recursive,不识别组合形式。这是既有缺口、只是变得可见,留作后续处理即可。

集合里保留的那条注释是恰当的判断——「-n 带值」正是别人参照 head -n 很容易重新引入的错误。

测试证据

无人值守 CI 运行——我没有构建或执行任何 PR 代码。下面的证据来自本 PR 自己在被审 commit 上的 CI,通过 API 一次性拉取。审查时单元测试尚未跑完,因此没有绿色结果可引用;未完成的 job 如实列为 pending,不做猜测。

CI 表格见上方标记区域(由 finalize 工作流在 CI 结束后原地更新)。

没有任何 check 失败,所以没有日志片段可引用。macOS 和 Windows 的单测 job 是本仓库 workflow 配置本身跳过的,与 PR 无关——而且这个改动是纯粹的字符串 token 解析,没有平台相关分支,Linux job 就是这里有意义的信号。作者只在 Linux 上测试过;这是作者的声明,未经独立复跑,但改动不含任何与操作系统相关的路径,因此该声明并非关键依据。

新增单测确实钉住了这个改动——它断言的正是旧代码未能产生的那个 read_file 操作,所以撤掉修复该测试就会变红。这是真正的 pin,不是「改与不改都一样通过」的套件。

沙箱验证仍能补上单测覆盖不到的部分:@qwen-code /verify——针对某文件的 Read 拒绝规则现在是否真的能端到端地经权限管理器拦住 grep -n pattern <file>。单测钉住了 extractShellOperations 会返回该操作,但这里没有任何证据表明拒绝路径会因此生效,而那正是本 PR 的用户可见价值所在。作者只有只读权限,所以这将是一次受助运行(sponsored run)——维护者发一条 @qwen-code /verify 评论即可批准其所针对的 head,该运行带有执行前风险筛查和完整工作区擦除。阅读其报告时请保持与看待 fork 自身 CI 日志同等的审慎:被验证的代码是对抗性输入,尽管沙箱限制了它能做什么,它仍能影响报告说什么。

真实场景测试

本次运行 N/A——无人值守 CI,未驱动 tmux 会话,也从未执行 PR 代码。上述已点名可弥补该实机行为缺口的验证通道。

— Qwen Code · qwen3.8-max-2026-09-02

Reviewed at 1bda9676a2b7f13f5a534a01b3b6114f4dc696c8 · re-run with @qwen-code /triage

@qwen-code-review-bot

Copy link
Copy Markdown
Collaborator

Confidence: 4/5 — correct, minimal, and fails in the safe direction; the only nits are a missing test for the long-form flag and a pre-existing -rn recursion gap this PR happens to expose.

Stepping back: my independent read of the problem before opening the diff was that -n simply should not be in the value-flag set, and that is precisely the two lines this PR removes. There was no simpler path available — the fix is already the minimal one, and I could not construct an alternative that was smaller or safer.

The reason I am comfortable on a core path is that the change can only add operations to what the analysis reports. Every consumer I traced (permission-manager.ts, autoMode.ts) uses that list to decide what needs checking, so the failure mode of getting this wrong would have been under-enforcement — and that is exactly the bug being fixed, not a new one. The old behaviour silently defeated Read deny rules for the single most common way people write grep. That is worth fixing on its own merits, and the fact that it also removes a spurious read_file on the literal pattern in the -n -e form is a bonus the author did not even claim.

On the "does this problem actually exist" question: yes, and it is checkable by reading the code rather than trusting a report. I walked getPositionalArgs token by token and reproduced the empty result by hand. This is not a hypothetical hardening PR.

Two reservations, neither blocking:

  • The diff removes both -n and --line-number but only tests the short form. Cheap to close, and it is the kind of asymmetry that lets a flag get reintroduced later without a test going red.
  • grep -rn pattern dir now reports read_file on dir instead of list_directory, because isRecursive does not recognise combined short flags. Pre-existing, out of scope here, and strictly more conservative than the old "report nothing" — but someone should file it.

The one thing I could not settle from the diff is whether a Read deny rule actually engages end-to-end on the newly-reported operation. The unit test pins the extractor; it does not pin the enforcement path. That is named in the review with the lane that would close it.

Approving on the merits. CI has not finished on this commit — approval is deferred until it lands green on 1bda9676a2b7f13f5a534a01b3b6114f4dc696c8, and will be withheld if anything goes red or the head moves.

中文说明

信心:4/5 —— 修复正确、改动最小、失败方向安全;仅有的两个小问题是长选项缺少测试,以及本 PR 顺带暴露出的 -rn 递归识别既有缺口。

退一步看:在读 diff 之前,我对这个问题的独立判断就是「-n 本来就不该出现在带值选项集合里」,而这正是本 PR 删掉的那两行。没有更简单的路径可走——它已经是最小修复,我想不出比它更小或更安全的替代方案。

之所以敢在核心路径上放行,是因为这个改动只可能增加分析所报告的操作。我追踪到的每一个消费方(permission-manager.ts、autoMode.ts)都用这份列表来决定什么需要被检查,因此判断失误的失败模式会是「执行不足」——而那恰恰是正在被修掉的 bug,不是新引入的。旧行为会让 Read 拒绝规则对人们最常用的 grep 写法静默失效。仅凭这一点就值得修;而它在 -n -e 形式下顺带消除了对字面量 pattern 的虚假 read_file,是作者自己都未声称的额外收益。

关于「这个问题是否真实存在」:是,而且可以通过读代码来验证,不必采信报告。我逐 token 走了一遍 getPositionalArgs,手工复现了那个空结果。这不是一个假设性的加固 PR。

两点保留意见,均不阻塞:

  • diff 同时移除了 -n 和 --line-number,却只测试了短选项形式。补上成本很低,而这种不对称正是日后某个选项被加回来、却没有测试变红的原因。
  • grep -rn pattern dir 现在会对 dir 报 read_file 而非 list_directory,因为 isRecursive 不识别组合短选项。这是既有问题、超出本 PR 范围,且比旧的「什么都不报」严格更保守——但值得有人开个 issue。

唯一无法从 diff 判定的是:Read 拒绝规则是否真的会在新报告的操作上端到端生效。单测钉住的是提取器,不是执行路径。这一点已在审查评论中点名,并附上了可弥补它的验证通道。

基于以上判断予以批准。该 commit 的 CI 尚未跑完——批准将延后至其在 1bda9676a2b7f13f5a534a01b3b6114f4dc696c8 上全绿之后;若有 check 变红或 head 发生移动,则不予批准。

— Qwen Code · qwen3.8-max-2026-09-02

Reviewed at 1bda9676a2b7f13f5a534a01b3b6114f4dc696c8 · re-run with @qwen-code /triage

@qwen-code-review-bot qwen-code-review-bot left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, looks ready to ship — CI landed green after the review. ✅

@qwen-code-review-bot qwen-code-review-bot left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Partially reviewed — gaps disclosed.

Not reviewed: reverse audit — stopped before round 2 by the review time budget.

Not reviewed: Step 4 verification — the review time budget refused every verifier shard, so none of the 7 deduplicated findings was adjudicated; all remain unverified and terminal-only.

Not explored to full depth (tool budget reached): "agent 1b": none — I did not run the revert-mutation (removing the fix to watch the new test go red), because it would require editing source in this shared worktree; the p….

Not reviewed: reverse audit — stopped before round 1 by the review time budget.

⚠️ 8 finding(s) still carried the — [unverified] tag when the loop ended — the verifier never ruled on them, and they are not confirmed.

Test Plan (not a blocker): src/permissions/shell-semantics.test.ts — no such file or directory.

中文说明

仅完成部分审查,审查缺口已披露。

未审查(原文为英文):reverse audit — stopped before round 2 by the review time budget.

未审查(原文为英文):Step 4 verification — the review time budget refused every verifier shard, so none of the 7 deduplicated findings was adjudicated; all remain unverified and terminal-only.

未探索到全部深度(达到工具调用预算):"agent 1b":none — I did not run the revert-mutation (removing the fix to watch the new test go red), because it would require editing source in this shared worktree; the p…。

未审查:反向审计——评审时间预算不足,未能开始第 1 轮。

⚠️ 循环结束时仍有 8 条发现带着 — [unverified] 标记——验证者从未对它们作出裁决,它们不算已确认。

Test Plan(非阻断):src/permissions/shell-semantics.test.ts — no such file or directory。

— qwen3.8-max via Qwen Code /review (v0.25.2)

@doudouOUC doudouOUC left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

EN

Approving at head 1bda9676a2b7f13f5a534a01b3b6114f4dc696c8.

Verified independently at this head:

  • packages/core/src/permissions/shell-semantics.ts:895-896 removes -n and --line-number from grep's value-consuming flag set. Both only print line numbers and take no argument, so the pattern is no longer swallowed as a flag value and the following file operand is emitted as a virtual read. I re-read the diff against main at this head and confirmed main still carries both entries, so the fix is not superseded.
  • The resulting virtual operations go through the existing evaluateShellVirtualOps / permission matching path; removing two entries can only surface more operands for checking, never fewer, so it does not weaken Bash-rule decisions.
  • The new regression case grep -n pattern /etc/hosts in shell-semantics.test.ts covers the reported shape.

Already-recorded, non-blocking items left as-is: no --line-number regression row (only -n is pinned), the pre-existing combined-flag gap (grep -rn yields read_file rather than list_directory), and no end-to-end Read-deny test for this extractor. None is introduced by this diff.

CI at this head: Lint & Static ran and passed (lint gate freshness, ESLint, Prettier, actionlint, shellcheck, yamllint); Test (ubuntu-latest, Node 22.x) passed including shell-semantics.test.ts (110 tests); Integration Tests (no-AK, No Sandbox) and web-shell E2E Smoke passed; core subpath export and serve bundle closure checks passed. macOS/Windows unit jobs and CLI integration are skipped by workflow conditions. The only red check is the review-pr review-automation job, which is not a code lane.

Note: this is an external-contributor fix touching packages/core/src/permissions/**, so it is recorded for maintainer awareness; it is not a refactor and is far below the size gate.

中文

在 head 1bda9676a2b7f13f5a534a01b3b6114f4dc696c8 上批准。

在该 head 独立核实:

  • packages/core/src/permissions/shell-semantics.ts:895-896 把 -n 与 --line-number 从 grep 的取值 flag 集合中移除。两者只打印行号、不带参数,因此 pattern 不再被当作 flag 值吞掉,其后的文件操作数会被作为虚拟读操作发出。我按该 head 重新比对了与 main 的 diff,并确认 main 上这两项仍在,修复未被取代。
  • 生成的虚拟操作仍走既有的 evaluateShellVirtualOps / 权限匹配路径;删掉两个条目只会让更多操作数进入检查,不会更少,因此不会削弱 Bash 规则的判定。
  • shell-semantics.test.ts 新增的 grep -n pattern /etc/hosts 回归用例覆盖了被报告的形态。

已在记录中的非阻断项保持原样:缺 --line-number 的回归行(目前只钉了 -n)、既有的组合 flag 缺口(grep -rn 得到 read_file 而非 list_directory)、以及该提取器缺少端到端 Read-deny 用例。三者都不是本次 diff 引入的。

该 head 的 CI:Lint & Static 实际执行并通过(lint gate freshness、ESLint、Prettier、actionlint、shellcheck、yamllint);Test (ubuntu-latest, Node 22.x) 通过,含 shell-semantics.test.ts(110 个用例);Integration Tests (no-AK, No Sandbox) 与 web-shell E2E Smoke 通过;core subpath exports 与 serve bundle closure 检查通过。macOS/Windows 单测与 CLI 集成按工作流条件跳过。唯一红色是 review-pr 评审自动化任务,不是代码通道。

备注:这是外部贡献者触及 packages/core/src/permissions/** 的 fix,按仓库规则记录为维护者知悉;它不是 refactor,且远低于规模门槛。

@yiliang114
yiliang114 merged commit 08922b2 into QwenLM:main Nov 3, 2026
79 of 80 checks passed
@qwen-code-review-bot

Copy link
Copy Markdown
Collaborator

Released in v0.26.7.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants