Repository navigation
fix(core): treat grep -n as a flag so its file reads are still checked - #14383
Conversation
# Conflicts: # packages/core/src/permissions/shell-semantics.test.ts
|
✅ Qwen Triage finished — CI landed green on ✅ Qwen Triage 已完成 —— |
|
Thanks for the PR! Template looks good ✓ Problem: real and reproduced, not theoretical. 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 ( 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 One consequence worth naming, not a blocker: combined short flags change too. Risk: no elevated risk signals — neither changed file matches the revert-correlated paths. Moving on to code review. 🔍 中文说明感谢贡献! 模板完整 ✓ 问题: 真实且可复现,不是理论性加固。 方向: 对齐。这是权限分析的正确性修复,而且失败方向是安全的——分析现在会报告更多文件操作,被检查的命令变多而不是变少,不会扩大 shell 工具的能力边界。 规模: 触及核心路径( 方案: 范围合适。从一个选项集合里删掉两个条目就是最小修复;留下的注释说明了为什么不能加回来——这两行是值得的,因为「 有一个值得点明的连带影响,但不是阻塞项:组合短选项的行为也变了。 风险: 无升级风险信号——两个改动文件都不匹配与 revert 相关的高风险路径。 进入代码审查 🔍 — Qwen Code · qwen3.8-max-2026-09-02 Reviewed at |
Code reviewNo blocking issues. I read the change against The fix is correct. With It also fixes a second case the description does not mention. Consumers checked. This is a core path, so I traced everything downstream rather than assuming:
Two tests outside the permissions suite use
Non-blocking suggestions, neither of which should hold the PR:
The comment left in the set is the right call — Test evidenceUnattended 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
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 Sandboxed verification would still settle the part the unit test cannot: Real-scenario testingN/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. 中文说明代码审查没有阻塞性问题。我是对照 修复是正确的。 它还顺带修好了描述里没提到的第二种情况。 下游消费方已核查。 这是核心路径,所以我逐个追踪而非假设:
permissions 套件之外有两个测试用了
非阻塞建议,两条都不该卡住这个 PR:
集合里保留的那条注释是恰当的判断——「 测试证据无人值守 CI 运行——我没有构建或执行任何 PR 代码。下面的证据来自本 PR 自己在被审 commit 上的 CI,通过 API 一次性拉取。审查时单元测试尚未跑完,因此没有绿色结果可引用;未完成的 job 如实列为 pending,不做猜测。 CI 表格见上方标记区域(由 finalize 工作流在 CI 结束后原地更新)。 没有任何 check 失败,所以没有日志片段可引用。macOS 和 Windows 的单测 job 是本仓库 workflow 配置本身跳过的,与 PR 无关——而且这个改动是纯粹的字符串 token 解析,没有平台相关分支,Linux job 就是这里有意义的信号。作者只在 Linux 上测试过;这是作者的声明,未经独立复跑,但改动不含任何与操作系统相关的路径,因此该声明并非关键依据。 新增单测确实钉住了这个改动——它断言的正是旧代码未能产生的那个 沙箱验证仍能补上单测覆盖不到的部分: 真实场景测试本次运行 N/A——无人值守 CI,未驱动 tmux 会话,也从未执行 PR 代码。上述已点名可弥补该实机行为缺口的验证通道。 — Qwen Code · qwen3.8-max-2026-09-02 Reviewed at |
|
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 Stepping back: my independent read of the problem before opening the diff was that 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 ( On the "does this problem actually exist" question: yes, and it is checkable by reading the code rather than trusting a report. I walked Two reservations, neither blocking:
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 中文说明信心:4/5 —— 修复正确、改动最小、失败方向安全;仅有的两个小问题是长选项缺少测试,以及本 PR 顺带暴露出的 退一步看:在读 diff 之前,我对这个问题的独立判断就是「 之所以敢在核心路径上放行,是因为这个改动只可能增加分析所报告的操作。我追踪到的每一个消费方( 关于「这个问题是否真实存在」:是,而且可以通过读代码来验证,不必采信报告。我逐 token 走了一遍 两点保留意见,均不阻塞:
唯一无法从 diff 判定的是:Read 拒绝规则是否真的会在新报告的操作上端到端生效。单测钉住的是提取器,不是执行路径。这一点已在审查评论中点名,并附上了可弥补它的验证通道。 基于以上判断予以批准。该 commit 的 CI 尚未跑完——批准将延后至其在 — Qwen Code · qwen3.8-max-2026-09-02 Reviewed at |
qwen-code-review-bot
left a comment
There was a problem hiding this comment.
LGTM, looks ready to ship — CI landed green after the review. ✅
qwen-code-review-bot
left a comment
There was a problem hiding this comment.
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.
— [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 轮。
— [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
left a comment
There was a problem hiding this comment.
EN
Approving at head 1bda9676a2b7f13f5a534a01b3b6114f4dc696c8.
Verified independently at this head:
packages/core/src/permissions/shell-semantics.ts:895-896removes-nand--line-numberfrom 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 againstmainat this head and confirmedmainstill 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/hostsinshell-semantics.test.tscovers 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,且远低于规模门槛。
|
Released in v0.26.7. |
What this PR does
The shell permission analysis no longer treats
grep -n/grep --line-numberas a flag that takes a value. Runninggrep -n pattern file(and the same flags on egrep, fgrep, zgrep and bzgrep) is now reported as readingfile, the same asgrep pattern file.Why it's needed
GNU grep's
-n/--line-numberonly prints line numbers and takes no argument. The grep handler listed them among the flags that consume the next token. So forgrep -n pattern /etc/hoststhe 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 plaingrep pattern filewas caught.Reviewer Test Plan
How to verify
Run
npx vitest run src/permissions/shell-semantics.test.tsinpackages/core. The new casegrep: -n is line numbers and does not consume the patternchecks thatextractShellOperations('grep -n pattern /etc/hosts', cwd)returns aread_fileoperation for/etc/hosts.Evidence (Before & After)
Before:
extractShellOperations('grep -n pattern /etc/hosts', cwd)returns[], and the new test fails withexpected [] 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
Environment (optional)
N/A (unit tests only)
Risk & Scope
-n/--line-numbermove out of the value-flag list; flags that do take a value (-e,-f,-m,-A/-B/-C,--include, ...) are unchanged, andhead -nuses a different handler.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
无。