mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-06 06:30:42 +00:00
perf(infra): fast path posix containment checks
This commit is contained in:
@@ -6,6 +6,7 @@ Docs: https://docs.openclaw.ai
|
||||
|
||||
### Changes
|
||||
|
||||
- Infra/path-guards: add a fast path for canonical absolute POSIX containment checks, avoiding repeated `path.resolve` and `path.relative` work in hot filesystem walkers. Refs #75895, #75575, and #68782. Thanks @Enderfga.
|
||||
- Tools: add a platform-level tool descriptor planner for descriptor-first visibility, generic availability checks, and executor references. Thanks @shakkernerd.
|
||||
- Docs/Codex: clarify that ChatGPT/Codex subscription setups should use `openai/gpt-*` with `agentRuntime.id: "codex"` for native Codex runtime, while `openai-codex/*` remains the PI OAuth route. Thanks @pashpashpash.
|
||||
- Plugins/source checkout: load bundled plugins from the `extensions/*` pnpm workspace tree in source checkouts, so plugin-local dependencies and edits are used directly while packaged installs keep using the built runtime tree. Thanks @vincentkoc.
|
||||
|
||||
@@ -74,6 +74,15 @@ describe("isPathInside", () => {
|
||||
["/workspace/root", "/workspace/root/nested/file.txt", true],
|
||||
["/workspace/root", "/workspace/root/..file.txt", true],
|
||||
["/workspace/root", "/workspace/root/../escape.txt", false],
|
||||
["/workspace/root", "/workspace/rootless/file.txt", false],
|
||||
["/workspace/root", "/workspace/root/a/b/c/d/e/file.txt", true],
|
||||
["/workspace/root", "/workspace/root/a/..", true],
|
||||
["/workspace/root", "/workspace/root/a/../..", false],
|
||||
["/workspace/root", "/workspace/root/a/b/../../../escape", false],
|
||||
["/", "/anything/at/all", true],
|
||||
["/", "/", true],
|
||||
["foo", "foo/bar", true],
|
||||
["foo", "../escape", false],
|
||||
])("checks posix containment %s -> %s", (basePath, targetPath, expected) => {
|
||||
expect(isPathInside(basePath, targetPath)).toBe(expected);
|
||||
});
|
||||
|
||||
@@ -4,6 +4,7 @@ import { normalizeLowercaseStringOrEmpty } from "../shared/string-coerce.js";
|
||||
const NOT_FOUND_CODES = new Set(["ENOENT", "ENOTDIR"]);
|
||||
const SYMLINK_OPEN_CODES = new Set(["ELOOP", "EINVAL", "ENOTSUP"]);
|
||||
const PARENT_SEGMENT_PREFIX = /^\.\.(?:[\\/]|$)/u;
|
||||
const POSIX_SEPARATOR_CHAR_CODE = 0x2f;
|
||||
|
||||
export function normalizeWindowsPathForComparison(input: string): string {
|
||||
let normalized = path.win32.normalize(input);
|
||||
@@ -44,6 +45,18 @@ export function isPathInside(root: string, target: string): boolean {
|
||||
);
|
||||
}
|
||||
|
||||
if (
|
||||
root.length > 0 &&
|
||||
root.charCodeAt(0) === POSIX_SEPARATOR_CHAR_CODE &&
|
||||
target.length >= root.length &&
|
||||
target.charCodeAt(0) === POSIX_SEPARATOR_CHAR_CODE &&
|
||||
!target.includes("/..") &&
|
||||
(target === root ||
|
||||
(target.startsWith(root) && target.charCodeAt(root.length) === POSIX_SEPARATOR_CHAR_CODE))
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
|
||||
const resolvedRoot = path.resolve(root);
|
||||
const resolvedTarget = path.resolve(target);
|
||||
const relative = path.relative(resolvedRoot, resolvedTarget);
|
||||
|
||||
Reference in New Issue
Block a user