mirror of https://github.com/openclaw/openclaw.git
fix(tools): land #31015 from @haosenwang1018
Co-authored-by: haosenwang1018 <1293965075@qq.com>
This commit is contained in:
parent
ac3e1e769b
commit
da80e22d89
|
|
@ -20,6 +20,7 @@ Docs: https://docs.openclaw.ai
|
|||
|
||||
### Fixes
|
||||
|
||||
- Tools/Edit workspace boundary errors: preserve the real `Path escapes workspace root` failure path instead of surfacing a misleading access/file-not-found error when editing outside workspace roots. Landed from contributor PR #31015 by @haosenwang1018. Thanks @haosenwang1018.
|
||||
- Sandbox/mkdirp boundary checks: allow directory-safe boundary validation for existing in-boundary subdirectories, preventing false `cannot create directories` failures in sandbox write mode. (#30610) Thanks @glitch418x.
|
||||
- Android/Voice screen TTS: stream assistant speech via ElevenLabs WebSocket in Talk Mode, stop cleanly on speaker mute/barge-in, and ignore stale out-of-order stream events. (#29521) Thanks @gregmousseau.
|
||||
- Web UI/Cron: include configured agent model defaults/fallbacks in cron model suggestions so scheduled-job model autocomplete reflects configured models. (#29709) Thanks @Sid-Qin.
|
||||
|
|
|
|||
|
|
@ -43,7 +43,7 @@ describe("createHostWorkspaceEditTool host access mapping", () => {
|
|||
});
|
||||
|
||||
it.runIf(process.platform !== "win32")(
|
||||
"maps outside-workspace safe-open failures to EACCES",
|
||||
"silently passes access for outside-workspace paths so readFile reports the real error",
|
||||
async () => {
|
||||
tmpDir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-edit-access-test-"));
|
||||
const workspaceDir = path.join(tmpDir, "workspace");
|
||||
|
|
@ -58,9 +58,13 @@ describe("createHostWorkspaceEditTool host access mapping", () => {
|
|||
createHostWorkspaceEditTool(workspaceDir, { workspaceOnly: true });
|
||||
expect(mocks.operations).toBeDefined();
|
||||
|
||||
// access must NOT throw for outside-workspace paths; the upstream
|
||||
// library replaces any access error with a misleading "File not found".
|
||||
// By resolving silently the subsequent readFile call surfaces the real
|
||||
// "Path escapes workspace root" / "outside-workspace" error instead.
|
||||
await expect(
|
||||
mocks.operations!.access(path.join(workspaceDir, "escape", "secret.txt")),
|
||||
).rejects.toMatchObject({ code: "EACCES" });
|
||||
).resolves.toBeUndefined();
|
||||
},
|
||||
);
|
||||
});
|
||||
|
|
|
|||
|
|
@ -843,7 +843,17 @@ function createHostEditOperations(root: string, options?: { workspaceOnly?: bool
|
|||
});
|
||||
},
|
||||
access: async (absolutePath: string) => {
|
||||
const relative = toRelativePathInRoot(root, absolutePath);
|
||||
let relative: string;
|
||||
try {
|
||||
relative = toRelativePathInRoot(root, absolutePath);
|
||||
} catch {
|
||||
// Path escapes workspace root. Don't throw here – the upstream
|
||||
// library replaces any `access` error with a misleading "File not
|
||||
// found" message. By returning silently the subsequent `readFile`
|
||||
// call will throw the same "Path escapes workspace root" error
|
||||
// through a code-path that propagates the original message.
|
||||
return;
|
||||
}
|
||||
try {
|
||||
const opened = await openFileWithinRoot({
|
||||
rootDir: root,
|
||||
|
|
@ -855,7 +865,9 @@ function createHostEditOperations(root: string, options?: { workspaceOnly?: bool
|
|||
throw createFsAccessError("ENOENT", absolutePath);
|
||||
}
|
||||
if (error instanceof SafeOpenError && error.code === "outside-workspace") {
|
||||
throw createFsAccessError("EACCES", absolutePath);
|
||||
// Don't throw here – see the comment above about the upstream
|
||||
// library swallowing access errors as "File not found".
|
||||
return;
|
||||
}
|
||||
throw error;
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue