From 2fe233c2f0c69f8989665be30d6985f1f5965b42 Mon Sep 17 00:00:00 2001 From: rome-xi <2685138823@qq.com> Date: Fri, 25 Sep 2026 09:58:33 +0800 Subject: [PATCH] fix(roots): expand leading tilde before cwd join in resolveAllowedPath Fixes #369 --- src/roots.test.ts | 39 +++++++++++++++++++++++++++++++++++++-- src/roots.ts | 3 ++- 2 files changed, 39 insertions(+), 3 deletions(-) diff --git a/src/roots.test.ts b/src/roots.test.ts index 90bdaa243..69cfb5be0 100644 --- a/src/roots.test.ts +++ b/src/roots.test.ts @@ -21,8 +21,43 @@ assert.equal( ); assert.equal( - resolveAllowedPath("~/file.txt", "/workspace", ["/workspace"]), - resolve("/workspace", "~/file.txt"), + resolveAllowedPath("~/personal/devspace", "/some/other/cwd", [join(home, "personal")]), + resolve(home, "personal", "devspace"), +); + +assert.equal( + resolveAllowedPath("~/personal/devspace", home, [join(home, "personal")]), + resolve(home, "personal", "devspace"), +); + +assert.equal( + resolveAllowedPath("~/personal/devspace", "/some/other/cwd", ["~/personal"]), + resolve(home, "personal", "devspace"), +); + +assert.throws( + () => resolveAllowedPath("~/outside", home, [join(home, "personal")]), + /Path is outside allowed roots/, +); + +assert.throws( + () => resolveAllowedPath("~/file.txt", "/workspace", ["/workspace"]), + /Path is outside allowed roots/, +); + +assert.equal( + resolveAllowedPath("relative/path", "/workspace", ["/workspace"]), + resolve("/workspace", "relative/path"), +); + +assert.equal( + resolveAllowedPath("./file.txt", join(home, "personal"), [join(home, "personal")]), + resolve(home, "personal", "file.txt"), +); + +assert.throws( + () => resolveAllowedPath("../outside", join(home, "personal"), [join(home, "personal")]), + /Path is outside allowed roots/, ); if (process.platform === "win32") { diff --git a/src/roots.ts b/src/roots.ts index 284726f49..28118f2c9 100644 --- a/src/roots.ts +++ b/src/roots.ts @@ -42,7 +42,8 @@ export function assertAllowedPath(path: string, allowedRoots: string[]): string } export function resolveAllowedPath(inputPath: string, cwd: string, allowedRoots: string[]): string { - const absolutePath = resolve(cwd, inputPath); + const expanded = expandHomePath(inputPath); + const absolutePath = isAbsolute(expanded) ? resolve(expanded) : resolve(cwd, expanded); return assertAllowedPath(absolutePath, allowedRoots); }