fix(shell): support safe descriptor redirects and attribute denial rule source - #14086
fix(shell): support safe descriptor redirects and attribute denial rule source#14086maoxin1234 wants to merge 2 commits into
Conversation
|
|
||
| // kilocode_change start | ||
| function isSafeDescriptorRedirect(text: string): boolean { | ||
| return /^\d*\s*(?:>\s*&|<\s*&)\s*(?:\d+|-)$/.test(text.trim()) || /^&>\s*(?:\d+|-)$/.test(text.trim()) |
There was a problem hiding this comment.
[WARNING]: &>N / &>- are file redirects, not descriptor duplications
In bash, &>word always redirects both stdout and stderr to a file named by word. The descriptor-duplication special case only applies to the >&word form, and only when word is a number or - (bash manual, "Redirecting Standard Output and Standard Error"). So &>1, &>0, and &>- create files named 1, 0, and -, but the second alternative here classifies them as safe descriptor redirects.
That matters because source() now strips any redirect that passes this check: echo secret &>1 is evaluated as echo secret, so its pattern no longer contains > and no longer matches the *>* deny rule used by readOnlyBash. For cat file &>1, access() also reports "read". That is a permission bypass for writes to numeric/- filenames.
Every legitimate duplication (2>&1, >&2, <&0, 2>&-, ...) is already covered by the first alternative, so the &> branch can be dropped:
| return /^\d*\s*(?:>\s*&|<\s*&)\s*(?:\d+|-)$/.test(text.trim()) || /^&>\s*(?:\d+|-)$/.test(text.trim()) | |
| return /^\d*\s*(?:>\s*&|<\s*&)\s*(?:\d+|-)$/.test(text.trim()) |
Reply with @kilocode-bot fix it to have Kilo Code address this issue.
|
|
||
| function source(node: Node) { | ||
| return (node.parent?.type === "redirected_statement" ? node.parent.text : node.text).trim() | ||
| if (node.parent?.type === "redirected_statement" && !onlySafeRedirects(node.parent)) { |
There was a problem hiding this comment.
[SUGGESTION]: Missing changeset for a user-visible fix
This PR changes user-facing behavior: read-only/plan mode now accepts safe descriptor redirects like 2>&1, and denial messages now attribute agent/global policy. No .changeset/*.md file is included. Per repo conventions, user-facing fixes should ship a changeset so the change appears in the release notes, e.g. "Allow safe file descriptor redirects (e.g. 2>&1) in read-only bash and clarify the source of permission denials".
Reply with @kilocode-bot fix it to have Kilo Code address this issue.
| }) { | ||
| override get message() { | ||
| const rules = Array.isArray(this.ruleset) ? this.ruleset : [this.ruleset] | ||
| const source = rules.find((r) => r && typeof r === "object" && "source" in r)?.source |
There was a problem hiding this comment.
[SUGGESTION]: Fork-merge hygiene on a shared file
packages/core/src/v1/permission.ts is shared upstream code, while the source marker on the ruleset ("agent" | "global" | "project" | ...) is Kilo-only, defined in packages/opencode/src/kilocode/permission/provenance.ts. Reading that Kilo-specific marker for the message wording enlarges the upstream diff. Consider wrapping the added block in // kilocode_change start / // kilocode_change end markers (or moving the wording into a Kilo-owned helper) so the next upstream merge resolves cleanly.
Reply with @kilocode-bot fix it to have Kilo Code address this issue.
Code Review SummaryStatus: 1 Issue Found | Recommendation: Address before merge Overview
Issue Details (click to expand)SUGGESTION
Incremental review of Files Reviewed (3 files)
Fix these issues in Kilo Cloud Previous Review Summary (commit 6aae503)Current summary above is authoritative. Previous snapshots are kept for context only. Previous review (commit 6aae503)Status: 3 Issues Found | Recommendation: Address before merge Overview
Issue Details (click to expand)WARNING
SUGGESTION
Files Reviewed (3 files)
Reviewed by deepseek-v4.1-flash · Input: 0 · Output: 0 · Cached: 0 Review guidance: REVIEW.md from base branch |
Description
Closes #14062.
When running read-only diagnostic commands with standard stderr redirects (such as
ls -la ~/.kilo/plans 2>&1orgit status 2>&1) in plan mode (or other modes withreadOnlyBash), the tool evaluation previously treated the entire redirected statement as a candidate pattern containing>and&. This caused:*>*(and*&*) inreadOnlyBash, unconditionally denying safe diagnostic commands that do not write to files.DeniedError.messageunconditionally claimed"The user has specified a rule which prevents you from using this specific tool call."even when the denial originated from built-in agent (action.source=agent) or global (action.source=global) policy, which confused users into thinking their own config caused the denial.Fix
packages/opencode/src/tool/shell.ts:isSafeDescriptorRedirectandonlySafeRedirectshelpers to recognize safe file descriptor duplications and closures (2>&1,>&2,1>&2,2>&-, etc.) which do not write to files on disk.source(node)returns the base command text so permission rules evaluate against the underlying command without triggering*>*file-redirection blocks.ls > out.txt 2>&1) continue to be preserved and caught by*>*/ marked access unknown.packages/core/src/v1/permission.ts:DeniedError.messageto accurately reflect rule provenance:"This agent's policy prevents you from using this specific tool call..."whensource === "agent""A global policy prevents you from using this specific tool call..."whensource === "global""The user has specified a rule which prevents you from using this specific tool call..."when specified by the user or default fallback.Testing
packages/opencode/test/kilocode/permission/bash-redirect-permission.test.ts:DeniedError.messageaccurately attributes agent, global, and user sources.2>&1strips the redirect from evaluated pattern while preserving base command.> out.txtpreserves redirect in pattern to be caught by policy.packages/opencode/test/kilocode/permission/withbun test(all 120 passed).