mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-07 21:41:24 +00:00
fix(paths): structurally resolve home dir to prevent Windows path bugs (#12125)
* fix(paths): structurally resolve home dir to prevent Windows path bugs
Extract resolveRawHomeDir as a private function and gate the public
resolveEffectiveHomeDir through a single path.resolve() exit point.
This makes it structurally impossible for unresolved paths (missing
drive letter on Windows) to escape the function, regardless of how
many return paths exist in the raw lookup logic.
Simplify resolveRequiredHomeDir to only resolve the process.cwd()
fallback, since resolveEffectiveHomeDir now returns resolved values.
Fix shortenMeta in tool-meta.ts: the colon-based split for file:line
patterns (e.g. file.txt:12) conflicts with Windows drive letters
(C:\...) because indexOf(":") matches the drive colon first.
shortenHomeInString already handles file:line patterns correctly via
split/join, so the colon split was both unnecessary and harmful.
Update test assertions across all affected files to use path.resolve()
in expected values and input strings so they match the now-correct
resolved output on both Unix and Windows.
Fixes #12119
* fix(changelog): add paths Windows fix entry (#12125)
---------
Co-authored-by: Sebastian <19554889+sebslight@users.noreply.github.com>
This commit is contained in:
@@ -1,3 +1,4 @@
|
||||
import path from "node:path";
|
||||
import { describe, expect, it } from "vitest";
|
||||
import { expandHomePrefix, resolveEffectiveHomeDir, resolveRequiredHomeDir } from "./home-dir.js";
|
||||
|
||||
@@ -9,17 +10,21 @@ describe("resolveEffectiveHomeDir", () => {
|
||||
USERPROFILE: "C:/Users/other",
|
||||
} as NodeJS.ProcessEnv;
|
||||
|
||||
expect(resolveEffectiveHomeDir(env, () => "/fallback")).toBe("/srv/openclaw-home");
|
||||
expect(resolveEffectiveHomeDir(env, () => "/fallback")).toBe(
|
||||
path.resolve("/srv/openclaw-home"),
|
||||
);
|
||||
});
|
||||
|
||||
it("falls back to HOME then USERPROFILE then homedir", () => {
|
||||
expect(resolveEffectiveHomeDir({ HOME: "/home/alice" } as NodeJS.ProcessEnv)).toBe(
|
||||
"/home/alice",
|
||||
path.resolve("/home/alice"),
|
||||
);
|
||||
expect(resolveEffectiveHomeDir({ USERPROFILE: "C:/Users/alice" } as NodeJS.ProcessEnv)).toBe(
|
||||
"C:/Users/alice",
|
||||
path.resolve("C:/Users/alice"),
|
||||
);
|
||||
expect(resolveEffectiveHomeDir({} as NodeJS.ProcessEnv, () => "/fallback")).toBe(
|
||||
path.resolve("/fallback"),
|
||||
);
|
||||
expect(resolveEffectiveHomeDir({} as NodeJS.ProcessEnv, () => "/fallback")).toBe("/fallback");
|
||||
});
|
||||
|
||||
it("expands OPENCLAW_HOME when set to ~", () => {
|
||||
@@ -28,7 +33,7 @@ describe("resolveEffectiveHomeDir", () => {
|
||||
HOME: "/home/alice",
|
||||
} as NodeJS.ProcessEnv;
|
||||
|
||||
expect(resolveEffectiveHomeDir(env)).toBe("/home/alice/svc");
|
||||
expect(resolveEffectiveHomeDir(env)).toBe(path.resolve("/home/alice/svc"));
|
||||
});
|
||||
});
|
||||
|
||||
@@ -41,6 +46,14 @@ describe("resolveRequiredHomeDir", () => {
|
||||
).toBe(process.cwd());
|
||||
});
|
||||
|
||||
it("returns a fully resolved path for OPENCLAW_HOME", () => {
|
||||
const result = resolveRequiredHomeDir(
|
||||
{ OPENCLAW_HOME: "/custom/home" } as NodeJS.ProcessEnv,
|
||||
() => "/fallback",
|
||||
);
|
||||
expect(result).toBe(path.resolve("/custom/home"));
|
||||
});
|
||||
|
||||
it("returns cwd when OPENCLAW_HOME is tilde-only and no fallback home exists", () => {
|
||||
expect(
|
||||
resolveRequiredHomeDir({ OPENCLAW_HOME: "~" } as NodeJS.ProcessEnv, () => {
|
||||
@@ -55,7 +68,7 @@ describe("expandHomePrefix", () => {
|
||||
const value = expandHomePrefix("~/x", {
|
||||
env: { OPENCLAW_HOME: "/srv/openclaw-home" } as NodeJS.ProcessEnv,
|
||||
});
|
||||
expect(value).toBe("/srv/openclaw-home/x");
|
||||
expect(value).toBe(`${path.resolve("/srv/openclaw-home")}/x`);
|
||||
});
|
||||
|
||||
it("keeps non-tilde values unchanged", () => {
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import os from "node:os";
|
||||
import path from "node:path";
|
||||
|
||||
function normalize(value: string | undefined): string | undefined {
|
||||
const trimmed = value?.trim();
|
||||
@@ -9,6 +10,11 @@ export function resolveEffectiveHomeDir(
|
||||
env: NodeJS.ProcessEnv = process.env,
|
||||
homedir: () => string = os.homedir,
|
||||
): string | undefined {
|
||||
const raw = resolveRawHomeDir(env, homedir);
|
||||
return raw ? path.resolve(raw) : undefined;
|
||||
}
|
||||
|
||||
function resolveRawHomeDir(env: NodeJS.ProcessEnv, homedir: () => string): string | undefined {
|
||||
const explicitHome = normalize(env.OPENCLAW_HOME);
|
||||
if (explicitHome) {
|
||||
if (explicitHome === "~" || explicitHome.startsWith("~/") || explicitHome.startsWith("~\\")) {
|
||||
@@ -47,7 +53,7 @@ export function resolveRequiredHomeDir(
|
||||
env: NodeJS.ProcessEnv = process.env,
|
||||
homedir: () => string = os.homedir,
|
||||
): string {
|
||||
return resolveEffectiveHomeDir(env, homedir) ?? process.cwd();
|
||||
return resolveEffectiveHomeDir(env, homedir) ?? path.resolve(process.cwd());
|
||||
}
|
||||
|
||||
export function expandHomePrefix(
|
||||
|
||||
Reference in New Issue
Block a user