mirror of
https://github.com/RooVetGit/Roo-Code.git
synced 2026-09-06 08:18:39 +00:00
fix: enforce read_file fileRegex when files is JSON string
This commit is contained in:
parent
ceb026efd9
commit
249013522b
2 changed files with 93 additions and 10 deletions
|
|
@ -206,6 +206,29 @@ describe("mode-validator", () => {
|
|||
).not.toThrow()
|
||||
})
|
||||
|
||||
it("enforces read fileRegex restrictions when toolParams.files is a JSON string", () => {
|
||||
const customModes: ModeConfig[] = [
|
||||
{
|
||||
slug: "md-reader",
|
||||
name: "Markdown Reader",
|
||||
roleDefinition: "Read markdown only",
|
||||
groups: [["read", { fileRegex: "\\.md$" }]] as const,
|
||||
},
|
||||
]
|
||||
|
||||
expect(() =>
|
||||
validateToolUse("read_file", "md-reader", customModes, undefined, {
|
||||
files: '[{"path":"src/index.ts"}]',
|
||||
}),
|
||||
).toThrow(/can only read files matching pattern/)
|
||||
|
||||
expect(() =>
|
||||
validateToolUse("read_file", "md-reader", customModes, undefined, {
|
||||
files: '[{"path":"README.md"}]',
|
||||
}),
|
||||
).not.toThrow()
|
||||
})
|
||||
|
||||
it("throws error when tool requirement is not met", () => {
|
||||
const requirements = { apply_diff: false }
|
||||
expect(() => validateToolUse("apply_diff", codeMode, [], requirements)).toThrow(
|
||||
|
|
|
|||
|
|
@ -78,6 +78,75 @@ function doesFileMatchRegex(filePath: string, pattern: string): boolean {
|
|||
}
|
||||
}
|
||||
|
||||
function tryParseJson(value: string): unknown | undefined {
|
||||
const trimmed = value.trim()
|
||||
if (!trimmed) {
|
||||
return undefined
|
||||
}
|
||||
|
||||
// Avoid attempting to parse arbitrary strings.
|
||||
if (!(trimmed.startsWith("{") || trimmed.startsWith("[") || trimmed.startsWith('"'))) {
|
||||
return undefined
|
||||
}
|
||||
|
||||
try {
|
||||
return JSON.parse(trimmed) as unknown
|
||||
} catch {
|
||||
return undefined
|
||||
}
|
||||
}
|
||||
|
||||
function parseJsonStringDeep(value: string, maxDepth = 2): unknown {
|
||||
let current: unknown = value
|
||||
for (let i = 0; i < maxDepth; i++) {
|
||||
if (typeof current !== "string") {
|
||||
break
|
||||
}
|
||||
const parsed = tryParseJson(current)
|
||||
if (parsed === undefined) {
|
||||
break
|
||||
}
|
||||
current = parsed
|
||||
}
|
||||
return current
|
||||
}
|
||||
|
||||
function extractReadPathsFromFilesValue(value: unknown, paths: string[]): void {
|
||||
if (Array.isArray(value)) {
|
||||
for (const entry of value) {
|
||||
if (typeof entry === "string" && entry.trim().length > 0) {
|
||||
paths.push(entry.trim())
|
||||
continue
|
||||
}
|
||||
|
||||
if (typeof entry === "object" && entry !== null) {
|
||||
const p = (entry as { path?: unknown }).path
|
||||
if (typeof p === "string" && p.trim().length > 0) {
|
||||
paths.push(p.trim())
|
||||
}
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Support mis-typed payloads like: files: "[{ \"path\": \"README.md\" }]".
|
||||
if (typeof value === "string") {
|
||||
const parsed = parseJsonStringDeep(value)
|
||||
if (parsed !== value) {
|
||||
extractReadPathsFromFilesValue(parsed, paths)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Support nested payloads like: files: "{ \"files\": [...] }".
|
||||
if (typeof value === "object" && value !== null) {
|
||||
const nested = (value as { files?: unknown }).files
|
||||
if (nested !== undefined) {
|
||||
extractReadPathsFromFilesValue(nested, paths)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function extractReadFilePaths(toolParams: Record<string, unknown> | undefined): string[] {
|
||||
if (!toolParams) {
|
||||
return []
|
||||
|
|
@ -87,16 +156,7 @@ function extractReadFilePaths(toolParams: Record<string, unknown> | undefined):
|
|||
|
||||
// Native protocol read_file: { files: [{ path: string }] }
|
||||
const files = (toolParams as { files?: unknown }).files
|
||||
if (Array.isArray(files)) {
|
||||
for (const entry of files) {
|
||||
if (typeof entry === "object" && entry !== null) {
|
||||
const p = (entry as { path?: unknown }).path
|
||||
if (typeof p === "string" && p.trim().length > 0) {
|
||||
paths.push(p.trim())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
extractReadPathsFromFilesValue(files, paths)
|
||||
|
||||
// Legacy single-path read_file: { path: string }
|
||||
const legacyPath = (toolParams as { path?: unknown }).path
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue