fix(daemon): scope TMPDIR forwarding to macOS services

This commit is contained in:
Gustavo Madeira Santana
2026-02-18 21:04:55 -05:00
parent db73297759
commit 4507a64d22
3 changed files with 58 additions and 5 deletions

View File

@@ -151,6 +151,26 @@ describe("launchd install", () => {
expect(bootstrapIndex).toBeGreaterThanOrEqual(0);
expect(enableIndex).toBeLessThan(bootstrapIndex);
});
it("writes TMPDIR to LaunchAgent environment when provided", async () => {
const env: Record<string, string | undefined> = {
HOME: "/Users/test",
OPENCLAW_PROFILE: "default",
};
const tmpDir = "/var/folders/xy/abc123/T/";
await installLaunchAgent({
env,
stdout: new PassThrough(),
programArguments: ["node", "-e", "process.exit(0)"],
environment: { TMPDIR: tmpDir },
});
const plistPath = resolveLaunchAgentPlistPath(env);
const plist = state.files.get(plistPath) ?? "";
expect(plist).toContain("<key>EnvironmentVariables</key>");
expect(plist).toContain("<key>TMPDIR</key>");
expect(plist).toContain(`<string>${tmpDir}</string>`);
});
});
describe("resolveLaunchAgentPlistPath", () => {

View File

@@ -1,5 +1,5 @@
import path from "node:path";
import { describe, expect, it } from "vitest";
import { afterEach, describe, expect, it } from "vitest";
import { resolveGatewayStateDir } from "./paths.js";
import {
buildMinimalServicePath,
@@ -9,6 +9,16 @@ import {
getMinimalServicePathPartsFromEnv,
} from "./service-env.js";
const originalPlatform = process.platform;
function setPlatform(platform: NodeJS.Platform): void {
Object.defineProperty(process, "platform", { value: platform, configurable: true });
}
afterEach(() => {
Object.defineProperty(process, "platform", { value: originalPlatform, configurable: true });
});
describe("getMinimalServicePathParts - Linux user directories", () => {
it("includes user bin directories when HOME is set on Linux", () => {
const result = getMinimalServicePathParts({
@@ -282,7 +292,8 @@ describe("buildServiceEnvironment", () => {
}
});
it("forwards TMPDIR from the host environment", () => {
it("forwards TMPDIR from the host environment on macOS", () => {
setPlatform("darwin");
const env = buildServiceEnvironment({
env: { HOME: "/home/user", TMPDIR: "/var/folders/xw/abc123/T/" },
port: 18789,
@@ -290,6 +301,15 @@ describe("buildServiceEnvironment", () => {
expect(env.TMPDIR).toBe("/var/folders/xw/abc123/T/");
});
it("does not forward TMPDIR on non-macOS services", () => {
setPlatform("linux");
const env = buildServiceEnvironment({
env: { HOME: "/home/user", TMPDIR: "/tmp/custom" },
port: 18789,
});
expect(env.TMPDIR).toBeUndefined();
});
it("omits TMPDIR when not set in host environment", () => {
const env = buildServiceEnvironment({
env: { HOME: "/home/user" },
@@ -318,12 +338,21 @@ describe("buildNodeServiceEnvironment", () => {
expect(env.HOME).toBe("/home/user");
});
it("forwards TMPDIR for node services", () => {
it("forwards TMPDIR for node services on macOS", () => {
setPlatform("darwin");
const env = buildNodeServiceEnvironment({
env: { HOME: "/home/user", TMPDIR: "/tmp/custom" },
});
expect(env.TMPDIR).toBe("/tmp/custom");
});
it("does not forward TMPDIR for node services on non-macOS platforms", () => {
setPlatform("linux");
const env = buildNodeServiceEnvironment({
env: { HOME: "/home/user", TMPDIR: "/tmp/custom" },
});
expect(env.TMPDIR).toBeUndefined();
});
});
describe("resolveGatewayStateDir", () => {

View File

@@ -212,9 +212,11 @@ export function buildServiceEnvironment(params: {
const systemdUnit = `${resolveGatewaySystemdServiceName(profile)}.service`;
const stateDir = env.OPENCLAW_STATE_DIR;
const configPath = env.OPENCLAW_CONFIG_PATH;
// launchd on macOS does not inherit shell TMPDIR by default; forward it explicitly there.
const tmpDir = process.platform === "darwin" ? env.TMPDIR : undefined;
return {
HOME: env.HOME,
TMPDIR: env.TMPDIR,
TMPDIR: tmpDir,
PATH: buildMinimalServicePath({ env }),
OPENCLAW_PROFILE: profile,
OPENCLAW_STATE_DIR: stateDir,
@@ -235,9 +237,11 @@ export function buildNodeServiceEnvironment(params: {
const { env } = params;
const stateDir = env.OPENCLAW_STATE_DIR;
const configPath = env.OPENCLAW_CONFIG_PATH;
// Keep TMPDIR propagation scoped to macOS launchd installs.
const tmpDir = process.platform === "darwin" ? env.TMPDIR : undefined;
return {
HOME: env.HOME,
TMPDIR: env.TMPDIR,
TMPDIR: tmpDir,
PATH: buildMinimalServicePath({ env }),
OPENCLAW_STATE_DIR: stateDir,
OPENCLAW_CONFIG_PATH: configPath,