From 99f6455d3eff230e7f0983adf1ef9a55ca79e751 Mon Sep 17 00:00:00 2001 From: Wout Stiens <71498452+StiensWout@users.noreply.github.com> Date: Thu, 30 Jul 2026 15:23:58 +0200 Subject: [PATCH 1/2] fix(server): restore PR detection without HOME --- apps/server/src/os-jank.test.ts | 27 +++++++++++++++++++++++++++ apps/server/src/os-jank.ts | 13 +++++++++++-- 2 files changed, 38 insertions(+), 2 deletions(-) create mode 100644 apps/server/src/os-jank.test.ts diff --git a/apps/server/src/os-jank.test.ts b/apps/server/src/os-jank.test.ts new file mode 100644 index 00000000000..ee003b7cf8a --- /dev/null +++ b/apps/server/src/os-jank.test.ts @@ -0,0 +1,27 @@ +import { assert, it } from "@effect/vitest"; + +import { hydratePosixHome } from "./os-jank.ts"; + +it("hydrates HOME for minimal service environments", () => { + const env: NodeJS.ProcessEnv = {}; + + hydratePosixHome(env, "/home/service-user"); + + assert.equal(env.HOME, "/home/service-user"); +}); + +it("hydrates a blank HOME value", () => { + const env: NodeJS.ProcessEnv = { HOME: " " }; + + hydratePosixHome(env, "/home/service-user"); + + assert.equal(env.HOME, "/home/service-user"); +}); + +it("preserves an explicitly configured HOME", () => { + const env: NodeJS.ProcessEnv = { HOME: "/custom/home" }; + + hydratePosixHome(env, "/home/service-user"); + + assert.equal(env.HOME, "/custom/home"); +}); diff --git a/apps/server/src/os-jank.ts b/apps/server/src/os-jank.ts index bc72758bc71..6c3bd8cabce 100644 --- a/apps/server/src/os-jank.ts +++ b/apps/server/src/os-jank.ts @@ -36,6 +36,12 @@ function hydratePosixPath(env: NodeJS.ProcessEnv, platform: NodeJS.Platform): vo } } +export function hydratePosixHome(env: NodeJS.ProcessEnv, homeDir = NodeOS.homedir()): void { + if ((env.HOME?.trim() ?? "").length === 0 && homeDir.length > 0) { + env.HOME = homeDir; + } +} + export const fixPath = Effect.fn("fixPath")(function* (): Effect.fn.Return< void, never, @@ -63,10 +69,13 @@ export const fixPath = Effect.fn("fixPath")(function* (): Effect.fn.Return< if (platform !== "darwin" && platform !== "linux") return; - yield* Effect.sync(() => hydratePosixPath(env, platform)).pipe( + yield* Effect.sync(() => { + hydratePosixHome(env); + hydratePosixPath(env, platform); + }).pipe( Effect.catchDefect((defect) => Effect.sync(() => { - logPathHydrationWarning("Failed to hydrate PATH from the user environment.", defect); + logPathHydrationWarning("Failed to hydrate the user environment.", defect); }), ), ); From 643f981636c9dc367ed0778f175d67a9d180c1a4 Mon Sep 17 00:00:00 2001 From: Wout Stiens <71498452+StiensWout@users.noreply.github.com> Date: Thu, 30 Jul 2026 15:44:15 +0200 Subject: [PATCH 2/2] fix(server): harden HOME hydration --- apps/server/src/os-jank.test.ts | 31 ++++++++++++++++++++++--------- apps/server/src/os-jank.ts | 24 +++++++++++++++++------- 2 files changed, 39 insertions(+), 16 deletions(-) diff --git a/apps/server/src/os-jank.test.ts b/apps/server/src/os-jank.test.ts index ee003b7cf8a..a157efb665f 100644 --- a/apps/server/src/os-jank.test.ts +++ b/apps/server/src/os-jank.test.ts @@ -1,27 +1,40 @@ -import { assert, it } from "@effect/vitest"; +import * as NodeOS from "node:os"; +import { assert, it } from "vite-plus/test"; import { hydratePosixHome } from "./os-jank.ts"; -it("hydrates HOME for minimal service environments", () => { +it("hydrates HOME for minimal service environments from the user account", () => { const env: NodeJS.ProcessEnv = {}; - hydratePosixHome(env, "/home/service-user"); + hydratePosixHome(env); - assert.equal(env.HOME, "/home/service-user"); + assert.equal(env.HOME, NodeOS.userInfo().homedir); }); -it("hydrates a blank HOME value", () => { +it("hydrates HOME independently of a blank process HOME", () => { + const originalHome = process.env.HOME; const env: NodeJS.ProcessEnv = { HOME: " " }; - hydratePosixHome(env, "/home/service-user"); - - assert.equal(env.HOME, "/home/service-user"); + try { + process.env.HOME = " "; + hydratePosixHome(env); + } finally { + if (originalHome === undefined) { + delete process.env.HOME; + } else { + process.env.HOME = originalHome; + } + } + + assert.equal(env.HOME, NodeOS.userInfo().homedir); }); it("preserves an explicitly configured HOME", () => { const env: NodeJS.ProcessEnv = { HOME: "/custom/home" }; - hydratePosixHome(env, "/home/service-user"); + hydratePosixHome(env, () => { + throw new Error("HOME lookup should not run"); + }); assert.equal(env.HOME, "/custom/home"); }); diff --git a/apps/server/src/os-jank.ts b/apps/server/src/os-jank.ts index 6c3bd8cabce..18ddbc66c0c 100644 --- a/apps/server/src/os-jank.ts +++ b/apps/server/src/os-jank.ts @@ -36,8 +36,14 @@ function hydratePosixPath(env: NodeJS.ProcessEnv, platform: NodeJS.Platform): vo } } -export function hydratePosixHome(env: NodeJS.ProcessEnv, homeDir = NodeOS.homedir()): void { - if ((env.HOME?.trim() ?? "").length === 0 && homeDir.length > 0) { +export function hydratePosixHome( + env: NodeJS.ProcessEnv, + resolveHomeDir = () => NodeOS.userInfo().homedir, +): void { + if ((env.HOME?.trim() ?? "").length > 0) return; + + const homeDir = resolveHomeDir(); + if (homeDir.length > 0) { env.HOME = homeDir; } } @@ -69,13 +75,17 @@ export const fixPath = Effect.fn("fixPath")(function* (): Effect.fn.Return< if (platform !== "darwin" && platform !== "linux") return; - yield* Effect.sync(() => { - hydratePosixHome(env); - hydratePosixPath(env, platform); - }).pipe( + yield* Effect.sync(() => hydratePosixHome(env)).pipe( + Effect.catchDefect((defect) => + Effect.sync(() => { + logPathHydrationWarning("Failed to hydrate HOME from the user account.", defect); + }), + ), + ); + yield* Effect.sync(() => hydratePosixPath(env, platform)).pipe( Effect.catchDefect((defect) => Effect.sync(() => { - logPathHydrationWarning("Failed to hydrate the user environment.", defect); + logPathHydrationWarning("Failed to hydrate PATH from the user environment.", defect); }), ), );