fix(win32): normalize paths at permission boundaries (#14738)
This commit is contained in:
@@ -18,7 +18,7 @@ export async function assertExternalDirectory(ctx: Tool.Context, target?: string
|
|||||||
|
|
||||||
const kind = options?.kind ?? "file"
|
const kind = options?.kind ?? "file"
|
||||||
const parentDir = kind === "directory" ? target : path.dirname(target)
|
const parentDir = kind === "directory" ? target : path.dirname(target)
|
||||||
const glob = path.join(parentDir, "*")
|
const glob = path.join(parentDir, "*").replaceAll("\\", "/")
|
||||||
|
|
||||||
await ctx.ask({
|
await ctx.ask({
|
||||||
permission: "external_directory",
|
permission: "external_directory",
|
||||||
|
|||||||
@@ -2,6 +2,8 @@ import { sortBy, pipe } from "remeda"
|
|||||||
|
|
||||||
export namespace Wildcard {
|
export namespace Wildcard {
|
||||||
export function match(str: string, pattern: string) {
|
export function match(str: string, pattern: string) {
|
||||||
|
if (str) str = str.replaceAll("\\", "/")
|
||||||
|
if (pattern) pattern = pattern.replaceAll("\\", "/")
|
||||||
let escaped = pattern
|
let escaped = pattern
|
||||||
.replace(/[.+^${}()|[\]\\]/g, "\\$&") // escape special regex chars
|
.replace(/[.+^${}()|[\]\\]/g, "\\$&") // escape special regex chars
|
||||||
.replace(/\*/g, ".*") // * becomes .*
|
.replace(/\*/g, ".*") // * becomes .*
|
||||||
@@ -13,7 +15,8 @@ export namespace Wildcard {
|
|||||||
escaped = escaped.slice(0, -3) + "( .*)?"
|
escaped = escaped.slice(0, -3) + "( .*)?"
|
||||||
}
|
}
|
||||||
|
|
||||||
return new RegExp("^" + escaped + "$", "s").test(str)
|
const flags = process.platform === "win32" ? "si" : "s"
|
||||||
|
return new RegExp("^" + escaped + "$", flags).test(str)
|
||||||
}
|
}
|
||||||
|
|
||||||
export function all(input: string, patterns: Record<string, any>) {
|
export function all(input: string, patterns: Record<string, any>) {
|
||||||
|
|||||||
@@ -203,8 +203,8 @@ describe("tool.bash permissions", () => {
|
|||||||
|
|
||||||
await bash.execute(
|
await bash.execute(
|
||||||
{
|
{
|
||||||
command: "rm tmpfile",
|
command: `rm -rf ${path.join(tmp.path, "nested")}`,
|
||||||
description: "Remove tmpfile",
|
description: "remove nested dir",
|
||||||
},
|
},
|
||||||
testCtx,
|
testCtx,
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -74,7 +74,7 @@ describe("tool.read external_directory permission", () => {
|
|||||||
await read.execute({ filePath: path.join(outerTmp.path, "secret.txt") }, testCtx)
|
await read.execute({ filePath: path.join(outerTmp.path, "secret.txt") }, testCtx)
|
||||||
const extDirReq = requests.find((r) => r.permission === "external_directory")
|
const extDirReq = requests.find((r) => r.permission === "external_directory")
|
||||||
expect(extDirReq).toBeDefined()
|
expect(extDirReq).toBeDefined()
|
||||||
expect(extDirReq!.patterns.some((p) => p.includes(outerTmp.path))).toBe(true)
|
expect(extDirReq!.patterns.some((p) => p.includes(outerTmp.path.replaceAll("\\", "/")))).toBe(true)
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
@@ -100,7 +100,7 @@ describe("tool.read external_directory permission", () => {
|
|||||||
await read.execute({ filePath: path.join(outerTmp.path, "external") }, testCtx)
|
await read.execute({ filePath: path.join(outerTmp.path, "external") }, testCtx)
|
||||||
const extDirReq = requests.find((r) => r.permission === "external_directory")
|
const extDirReq = requests.find((r) => r.permission === "external_directory")
|
||||||
expect(extDirReq).toBeDefined()
|
expect(extDirReq).toBeDefined()
|
||||||
expect(extDirReq!.patterns).toContain(path.join(outerTmp.path, "external", "*"))
|
expect(extDirReq!.patterns).toContain(path.join(outerTmp.path, "external", "*").replaceAll("\\", "/"))
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -73,3 +73,18 @@ test("allStructured handles sed flags", () => {
|
|||||||
expect(Wildcard.allStructured({ head: "sed", tail: ["-n", "1p", "file"] }, rules)).toBe("allow")
|
expect(Wildcard.allStructured({ head: "sed", tail: ["-n", "1p", "file"] }, rules)).toBe("allow")
|
||||||
expect(Wildcard.allStructured({ head: "sed", tail: ["-i", "-n", "/./p", "myfile.txt"] }, rules)).toBe("ask")
|
expect(Wildcard.allStructured({ head: "sed", tail: ["-i", "-n", "/./p", "myfile.txt"] }, rules)).toBe("ask")
|
||||||
})
|
})
|
||||||
|
|
||||||
|
test("match normalizes slashes for cross-platform globbing", () => {
|
||||||
|
expect(Wildcard.match("C:\\Windows\\System32\\*", "C:/Windows/System32/*")).toBe(true)
|
||||||
|
expect(Wildcard.match("C:/Windows/System32/drivers", "C:\\Windows\\System32\\*")).toBe(true)
|
||||||
|
})
|
||||||
|
|
||||||
|
test("match handles case-insensitivity on Windows", () => {
|
||||||
|
if (process.platform === "win32") {
|
||||||
|
expect(Wildcard.match("C:\\windows\\system32\\hosts", "C:/Windows/System32/*")).toBe(true)
|
||||||
|
expect(Wildcard.match("c:/windows/system32/hosts", "C:\\Windows\\System32\\*")).toBe(true)
|
||||||
|
} else {
|
||||||
|
// Unix paths are case-sensitive
|
||||||
|
expect(Wildcard.match("/users/test/file", "/Users/test/*")).toBe(false)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|||||||
Reference in New Issue
Block a user