fix: handle redirected_statement treesitter node in bash permissions (#6737)
This commit is contained in:
@@ -91,6 +91,10 @@ export const BashTool = Tool.define("bash", async () => {
|
|||||||
|
|
||||||
for (const node of tree.rootNode.descendantsOfType("command")) {
|
for (const node of tree.rootNode.descendantsOfType("command")) {
|
||||||
if (!node) continue
|
if (!node) continue
|
||||||
|
|
||||||
|
// Get full command text including redirects if present
|
||||||
|
let commandText = node.parent?.type === "redirected_statement" ? node.parent.text : node.text
|
||||||
|
|
||||||
const command = []
|
const command = []
|
||||||
for (let i = 0; i < node.childCount; i++) {
|
for (let i = 0; i < node.childCount; i++) {
|
||||||
const child = node.child(i)
|
const child = node.child(i)
|
||||||
@@ -131,8 +135,8 @@ export const BashTool = Tool.define("bash", async () => {
|
|||||||
|
|
||||||
// cd covered by above check
|
// cd covered by above check
|
||||||
if (command.length && command[0] !== "cd") {
|
if (command.length && command[0] !== "cd") {
|
||||||
patterns.add(command.join(" "))
|
patterns.add(commandText)
|
||||||
always.add(BashArity.prefix(command).join(" ") + "*")
|
always.add(BashArity.prefix(command).join(" ") + " *")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -231,6 +231,49 @@ describe("tool.bash permissions", () => {
|
|||||||
},
|
},
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
test("matches redirects in permission pattern", async () => {
|
||||||
|
await using tmp = await tmpdir({ git: true })
|
||||||
|
await Instance.provide({
|
||||||
|
directory: tmp.path,
|
||||||
|
fn: async () => {
|
||||||
|
const bash = await BashTool.init()
|
||||||
|
const requests: Array<Omit<PermissionNext.Request, "id" | "sessionID" | "tool">> = []
|
||||||
|
const testCtx = {
|
||||||
|
...ctx,
|
||||||
|
ask: async (req: Omit<PermissionNext.Request, "id" | "sessionID" | "tool">) => {
|
||||||
|
requests.push(req)
|
||||||
|
},
|
||||||
|
}
|
||||||
|
await bash.execute({ command: "cat > /tmp/output.txt", description: "Redirect ls output" }, testCtx)
|
||||||
|
const bashReq = requests.find((r) => r.permission === "bash")
|
||||||
|
expect(bashReq).toBeDefined()
|
||||||
|
expect(bashReq!.patterns).toContain("cat > /tmp/output.txt")
|
||||||
|
},
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
test("always pattern has space before wildcard to not include different commands", async () => {
|
||||||
|
await using tmp = await tmpdir({ git: true })
|
||||||
|
await Instance.provide({
|
||||||
|
directory: tmp.path,
|
||||||
|
fn: async () => {
|
||||||
|
const bash = await BashTool.init()
|
||||||
|
const requests: Array<Omit<PermissionNext.Request, "id" | "sessionID" | "tool">> = []
|
||||||
|
const testCtx = {
|
||||||
|
...ctx,
|
||||||
|
ask: async (req: Omit<PermissionNext.Request, "id" | "sessionID" | "tool">) => {
|
||||||
|
requests.push(req)
|
||||||
|
},
|
||||||
|
}
|
||||||
|
await bash.execute({ command: "ls -la", description: "List" }, testCtx)
|
||||||
|
const bashReq = requests.find((r) => r.permission === "bash")
|
||||||
|
expect(bashReq).toBeDefined()
|
||||||
|
const pattern = bashReq!.always[0]
|
||||||
|
expect(pattern).toBe("ls *")
|
||||||
|
},
|
||||||
|
})
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
describe("tool.bash truncation", () => {
|
describe("tool.bash truncation", () => {
|
||||||
|
|||||||
Reference in New Issue
Block a user