mirror of
https://github.com/pacnpal/Roo-Code.git
synced 2025-12-20 04:11:10 -05:00
Throw FileRestrictionErrors sooner
This commit is contained in:
5
.changeset/late-moose-watch.md
Normal file
5
.changeset/late-moose-watch.md
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
---
|
||||||
|
"roo-cline": patch
|
||||||
|
---
|
||||||
|
|
||||||
|
Throw errors sooner when a mode tries to write a restricted file
|
||||||
@@ -1144,25 +1144,22 @@ export class Cline {
|
|||||||
await this.browserSession.closeBrowser()
|
await this.browserSession.closeBrowser()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Only validate complete tool uses
|
// Validate tool use before execution
|
||||||
if (!block.partial) {
|
const { mode, customModes } = (await this.providerRef.deref()?.getState()) ?? {}
|
||||||
const { mode } = (await this.providerRef.deref()?.getState()) ?? {}
|
try {
|
||||||
const { customModes } = (await this.providerRef.deref()?.getState()) ?? {}
|
validateToolUse(
|
||||||
try {
|
block.name as ToolName,
|
||||||
validateToolUse(
|
mode ?? defaultModeSlug,
|
||||||
block.name as ToolName,
|
customModes ?? [],
|
||||||
mode ?? defaultModeSlug,
|
{
|
||||||
customModes ?? [],
|
apply_diff: this.diffEnabled,
|
||||||
{
|
},
|
||||||
apply_diff: this.diffEnabled,
|
block.params,
|
||||||
},
|
)
|
||||||
block.params,
|
} catch (error) {
|
||||||
)
|
this.consecutiveMistakeCount++
|
||||||
} catch (error) {
|
pushToolResult(formatResponse.toolError(error.message))
|
||||||
this.consecutiveMistakeCount++
|
break
|
||||||
pushToolResult(formatResponse.toolError(error.message))
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (block.name) {
|
switch (block.name) {
|
||||||
|
|||||||
@@ -31,12 +31,14 @@ describe("isToolAllowedForMode", () => {
|
|||||||
// Test markdown editor mode
|
// Test markdown editor mode
|
||||||
const mdResult = isToolAllowedForMode("write_to_file", "markdown-editor", customModes, undefined, {
|
const mdResult = isToolAllowedForMode("write_to_file", "markdown-editor", customModes, undefined, {
|
||||||
path: "test.md",
|
path: "test.md",
|
||||||
|
content: "# Test",
|
||||||
})
|
})
|
||||||
expect(mdResult).toBe(true)
|
expect(mdResult).toBe(true)
|
||||||
|
|
||||||
// Test CSS editor mode
|
// Test CSS editor mode
|
||||||
const cssResult = isToolAllowedForMode("write_to_file", "css-editor", customModes, undefined, {
|
const cssResult = isToolAllowedForMode("write_to_file", "css-editor", customModes, undefined, {
|
||||||
path: "styles.css",
|
path: "styles.css",
|
||||||
|
content: ".test { color: red; }",
|
||||||
})
|
})
|
||||||
expect(cssResult).toBe(true)
|
expect(cssResult).toBe(true)
|
||||||
})
|
})
|
||||||
@@ -44,41 +46,83 @@ describe("isToolAllowedForMode", () => {
|
|||||||
it("rejects editing non-matching files", () => {
|
it("rejects editing non-matching files", () => {
|
||||||
// Test markdown editor mode with non-markdown file
|
// Test markdown editor mode with non-markdown file
|
||||||
expect(() =>
|
expect(() =>
|
||||||
isToolAllowedForMode("write_to_file", "markdown-editor", customModes, undefined, { path: "test.js" }),
|
isToolAllowedForMode("write_to_file", "markdown-editor", customModes, undefined, {
|
||||||
|
path: "test.js",
|
||||||
|
content: "console.log('test')",
|
||||||
|
}),
|
||||||
).toThrow(FileRestrictionError)
|
).toThrow(FileRestrictionError)
|
||||||
expect(() =>
|
expect(() =>
|
||||||
isToolAllowedForMode("write_to_file", "markdown-editor", customModes, undefined, { path: "test.js" }),
|
isToolAllowedForMode("write_to_file", "markdown-editor", customModes, undefined, {
|
||||||
|
path: "test.js",
|
||||||
|
content: "console.log('test')",
|
||||||
|
}),
|
||||||
).toThrow(/\\.md\$/)
|
).toThrow(/\\.md\$/)
|
||||||
|
|
||||||
// Test CSS editor mode with non-CSS file
|
// Test CSS editor mode with non-CSS file
|
||||||
expect(() =>
|
expect(() =>
|
||||||
isToolAllowedForMode("write_to_file", "css-editor", customModes, undefined, { path: "test.js" }),
|
isToolAllowedForMode("write_to_file", "css-editor", customModes, undefined, {
|
||||||
|
path: "test.js",
|
||||||
|
content: "console.log('test')",
|
||||||
|
}),
|
||||||
).toThrow(FileRestrictionError)
|
).toThrow(FileRestrictionError)
|
||||||
expect(() =>
|
expect(() =>
|
||||||
isToolAllowedForMode("write_to_file", "css-editor", customModes, undefined, { path: "test.js" }),
|
isToolAllowedForMode("write_to_file", "css-editor", customModes, undefined, {
|
||||||
|
path: "test.js",
|
||||||
|
content: "console.log('test')",
|
||||||
|
}),
|
||||||
).toThrow(/\\.css\$/)
|
).toThrow(/\\.css\$/)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
it("handles partial streaming cases (path only, no content/diff)", () => {
|
||||||
|
// Should allow path-only for matching files (no validation yet since content/diff not provided)
|
||||||
|
expect(
|
||||||
|
isToolAllowedForMode("write_to_file", "markdown-editor", customModes, undefined, {
|
||||||
|
path: "test.js",
|
||||||
|
}),
|
||||||
|
).toBe(true)
|
||||||
|
|
||||||
|
expect(
|
||||||
|
isToolAllowedForMode("apply_diff", "markdown-editor", customModes, undefined, {
|
||||||
|
path: "test.js",
|
||||||
|
}),
|
||||||
|
).toBe(true)
|
||||||
|
|
||||||
|
// Should allow path-only for ask mode too
|
||||||
|
expect(
|
||||||
|
isToolAllowedForMode("write_to_file", "ask", [], undefined, {
|
||||||
|
path: "test.js",
|
||||||
|
}),
|
||||||
|
).toBe(true)
|
||||||
|
})
|
||||||
|
|
||||||
it("applies restrictions to both write_to_file and apply_diff", () => {
|
it("applies restrictions to both write_to_file and apply_diff", () => {
|
||||||
// Test write_to_file
|
// Test write_to_file
|
||||||
const writeResult = isToolAllowedForMode("write_to_file", "markdown-editor", customModes, undefined, {
|
const writeResult = isToolAllowedForMode("write_to_file", "markdown-editor", customModes, undefined, {
|
||||||
path: "test.md",
|
path: "test.md",
|
||||||
|
content: "# Test",
|
||||||
})
|
})
|
||||||
expect(writeResult).toBe(true)
|
expect(writeResult).toBe(true)
|
||||||
|
|
||||||
// Test apply_diff
|
// Test apply_diff
|
||||||
const diffResult = isToolAllowedForMode("apply_diff", "markdown-editor", customModes, undefined, {
|
const diffResult = isToolAllowedForMode("apply_diff", "markdown-editor", customModes, undefined, {
|
||||||
path: "test.md",
|
path: "test.md",
|
||||||
|
diff: "- old\n+ new",
|
||||||
})
|
})
|
||||||
expect(diffResult).toBe(true)
|
expect(diffResult).toBe(true)
|
||||||
|
|
||||||
// Test both with non-matching file
|
// Test both with non-matching file
|
||||||
expect(() =>
|
expect(() =>
|
||||||
isToolAllowedForMode("write_to_file", "markdown-editor", customModes, undefined, { path: "test.js" }),
|
isToolAllowedForMode("write_to_file", "markdown-editor", customModes, undefined, {
|
||||||
|
path: "test.js",
|
||||||
|
content: "console.log('test')",
|
||||||
|
}),
|
||||||
).toThrow(FileRestrictionError)
|
).toThrow(FileRestrictionError)
|
||||||
|
|
||||||
expect(() =>
|
expect(() =>
|
||||||
isToolAllowedForMode("apply_diff", "markdown-editor", customModes, undefined, { path: "test.js" }),
|
isToolAllowedForMode("apply_diff", "markdown-editor", customModes, undefined, {
|
||||||
|
path: "test.js",
|
||||||
|
diff: "- old\n+ new",
|
||||||
|
}),
|
||||||
).toThrow(FileRestrictionError)
|
).toThrow(FileRestrictionError)
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -100,11 +144,13 @@ describe("isToolAllowedForMode", () => {
|
|||||||
expect(() =>
|
expect(() =>
|
||||||
isToolAllowedForMode("write_to_file", "docs-editor", customModesWithDescription, undefined, {
|
isToolAllowedForMode("write_to_file", "docs-editor", customModesWithDescription, undefined, {
|
||||||
path: "test.js",
|
path: "test.js",
|
||||||
|
content: "console.log('test')",
|
||||||
}),
|
}),
|
||||||
).toThrow(FileRestrictionError)
|
).toThrow(FileRestrictionError)
|
||||||
expect(() =>
|
expect(() =>
|
||||||
isToolAllowedForMode("write_to_file", "docs-editor", customModesWithDescription, undefined, {
|
isToolAllowedForMode("write_to_file", "docs-editor", customModesWithDescription, undefined, {
|
||||||
path: "test.js",
|
path: "test.js",
|
||||||
|
content: "console.log('test')",
|
||||||
}),
|
}),
|
||||||
).toThrow(/Documentation files only/)
|
).toThrow(/Documentation files only/)
|
||||||
|
|
||||||
@@ -112,11 +158,13 @@ describe("isToolAllowedForMode", () => {
|
|||||||
expect(() =>
|
expect(() =>
|
||||||
isToolAllowedForMode("apply_diff", "docs-editor", customModesWithDescription, undefined, {
|
isToolAllowedForMode("apply_diff", "docs-editor", customModesWithDescription, undefined, {
|
||||||
path: "test.js",
|
path: "test.js",
|
||||||
|
diff: "- old\n+ new",
|
||||||
}),
|
}),
|
||||||
).toThrow(FileRestrictionError)
|
).toThrow(FileRestrictionError)
|
||||||
expect(() =>
|
expect(() =>
|
||||||
isToolAllowedForMode("apply_diff", "docs-editor", customModesWithDescription, undefined, {
|
isToolAllowedForMode("apply_diff", "docs-editor", customModesWithDescription, undefined, {
|
||||||
path: "test.js",
|
path: "test.js",
|
||||||
|
diff: "- old\n+ new",
|
||||||
}),
|
}),
|
||||||
).toThrow(/Documentation files only/)
|
).toThrow(/Documentation files only/)
|
||||||
|
|
||||||
@@ -124,30 +172,55 @@ describe("isToolAllowedForMode", () => {
|
|||||||
expect(
|
expect(
|
||||||
isToolAllowedForMode("write_to_file", "docs-editor", customModesWithDescription, undefined, {
|
isToolAllowedForMode("write_to_file", "docs-editor", customModesWithDescription, undefined, {
|
||||||
path: "test.md",
|
path: "test.md",
|
||||||
|
content: "# Test",
|
||||||
}),
|
}),
|
||||||
).toBe(true)
|
).toBe(true)
|
||||||
|
|
||||||
expect(
|
expect(
|
||||||
isToolAllowedForMode("write_to_file", "docs-editor", customModesWithDescription, undefined, {
|
isToolAllowedForMode("write_to_file", "docs-editor", customModesWithDescription, undefined, {
|
||||||
path: "test.txt",
|
path: "test.txt",
|
||||||
|
content: "Test content",
|
||||||
|
}),
|
||||||
|
).toBe(true)
|
||||||
|
|
||||||
|
// Test partial streaming cases
|
||||||
|
expect(
|
||||||
|
isToolAllowedForMode("write_to_file", "docs-editor", customModesWithDescription, undefined, {
|
||||||
|
path: "test.js",
|
||||||
}),
|
}),
|
||||||
).toBe(true)
|
).toBe(true)
|
||||||
})
|
})
|
||||||
|
|
||||||
it("allows ask mode to edit markdown files only", () => {
|
it("allows ask mode to edit markdown files only", () => {
|
||||||
// Should allow editing markdown files
|
// Should allow editing markdown files
|
||||||
expect(isToolAllowedForMode("write_to_file", "ask", [], undefined, { path: "test.md" })).toBe(true)
|
expect(
|
||||||
|
isToolAllowedForMode("write_to_file", "ask", [], undefined, {
|
||||||
|
path: "test.md",
|
||||||
|
content: "# Test",
|
||||||
|
}),
|
||||||
|
).toBe(true)
|
||||||
|
|
||||||
// Should allow applying diffs to markdown files
|
// Should allow applying diffs to markdown files
|
||||||
expect(isToolAllowedForMode("apply_diff", "ask", [], undefined, { path: "readme.md" })).toBe(true)
|
expect(
|
||||||
|
isToolAllowedForMode("apply_diff", "ask", [], undefined, {
|
||||||
|
path: "readme.md",
|
||||||
|
diff: "- old\n+ new",
|
||||||
|
}),
|
||||||
|
).toBe(true)
|
||||||
|
|
||||||
// Should reject non-markdown files
|
// Should reject non-markdown files
|
||||||
expect(() => isToolAllowedForMode("write_to_file", "ask", [], undefined, { path: "test.js" })).toThrow(
|
expect(() =>
|
||||||
FileRestrictionError,
|
isToolAllowedForMode("write_to_file", "ask", [], undefined, {
|
||||||
)
|
path: "test.js",
|
||||||
expect(() => isToolAllowedForMode("write_to_file", "ask", [], undefined, { path: "test.js" })).toThrow(
|
content: "console.log('test')",
|
||||||
/Markdown files only/,
|
}),
|
||||||
)
|
).toThrow(FileRestrictionError)
|
||||||
|
expect(() =>
|
||||||
|
isToolAllowedForMode("write_to_file", "ask", [], undefined, {
|
||||||
|
path: "test.js",
|
||||||
|
content: "console.log('test')",
|
||||||
|
}),
|
||||||
|
).toThrow(/Markdown files only/)
|
||||||
|
|
||||||
// Should maintain read capabilities
|
// Should maintain read capabilities
|
||||||
expect(isToolAllowedForMode("read_file", "ask", [])).toBe(true)
|
expect(isToolAllowedForMode("read_file", "ask", [])).toBe(true)
|
||||||
|
|||||||
@@ -196,11 +196,13 @@ export function isToolAllowedForMode(
|
|||||||
// For the edit group, check file regex if specified
|
// For the edit group, check file regex if specified
|
||||||
if (groupName === "edit" && options.fileRegex) {
|
if (groupName === "edit" && options.fileRegex) {
|
||||||
const filePath = toolParams?.path
|
const filePath = toolParams?.path
|
||||||
// Only validate regex if a path is provided
|
if (
|
||||||
if (filePath && !doesFileMatchRegex(filePath, options.fileRegex)) {
|
filePath &&
|
||||||
|
(toolParams.diff || toolParams.content) &&
|
||||||
|
!doesFileMatchRegex(filePath, options.fileRegex)
|
||||||
|
) {
|
||||||
throw new FileRestrictionError(mode.name, options.fileRegex, options.description, filePath)
|
throw new FileRestrictionError(mode.name, options.fileRegex, options.description, filePath)
|
||||||
}
|
}
|
||||||
return true
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return true
|
return true
|
||||||
|
|||||||
Reference in New Issue
Block a user