diff --git a/src/commands/daemon-install-helpers.test.ts b/src/commands/daemon-install-helpers.test.ts index a05176aee9f..b564c33055b 100644 --- a/src/commands/daemon-install-helpers.test.ts +++ b/src/commands/daemon-install-helpers.test.ts @@ -86,11 +86,21 @@ function mockNodeGatewayPlanFixture( } describe("buildGatewayInstallPlan", () => { + // Prevent tests from reading the developer's real ~/.openclaw/.env when + // passing `env: {}` (which falls back to os.homedir for state-dir resolution). + let isolatedHome: string; + beforeEach(() => { + isolatedHome = fs.mkdtempSync(path.join(os.tmpdir(), "oc-plan-test-")); + }); + afterEach(() => { + fs.rmSync(isolatedHome, { recursive: true, force: true }); + }); + it("uses provided nodePath and returns plan", async () => { mockNodeGatewayPlanFixture(); const plan = await buildGatewayInstallPlan({ - env: {}, + env: { HOME: isolatedHome }, port: 3000, runtime: "node", nodePath: "/custom/node", @@ -102,7 +112,7 @@ describe("buildGatewayInstallPlan", () => { expect(mocks.resolvePreferredNodePath).not.toHaveBeenCalled(); expect(mocks.buildServiceEnvironment).toHaveBeenCalledWith( expect.objectContaining({ - env: {}, + env: { HOME: isolatedHome }, port: 3000, extraPathDirs: ["/custom"], }), @@ -113,7 +123,7 @@ describe("buildGatewayInstallPlan", () => { mockNodeGatewayPlanFixture(); await buildGatewayInstallPlan({ - env: {}, + env: { HOME: isolatedHome }, port: 3000, runtime: "node", nodePath: "node", diff --git a/src/commands/daemon-install-helpers.ts b/src/commands/daemon-install-helpers.ts index e3ad0b491ee..3797ab8ee09 100644 --- a/src/commands/daemon-install-helpers.ts +++ b/src/commands/daemon-install-helpers.ts @@ -15,6 +15,7 @@ import { buildServiceEnvironment } from "../daemon/service-env.js"; import { isDangerousHostEnvOverrideVarName, isDangerousHostEnvVarName, + normalizeEnvVarKey, } from "../infra/host-env-security.js"; import { emitDaemonInstallRuntimeWarning, @@ -49,8 +50,12 @@ export function readStateDirDotEnvVars( const parsed = dotenv.parse(content); const entries: Record = {}; - for (const [key, value] of Object.entries(parsed)) { - if (!key || !value?.trim()) { + for (const [rawKey, value] of Object.entries(parsed)) { + if (!value?.trim()) { + continue; + } + const key = normalizeEnvVarKey(rawKey, { portable: true }); + if (!key) { continue; } if (isDangerousHostEnvVarName(key) || isDangerousHostEnvOverrideVarName(key)) {