Skip to content

Commit e3fe6a5

Browse files
committed
fix(test): Windows compat — USERPROFILE + npx.cmd in PR-3 tests
PR #129's three new test files (cursor-auth-config, agent-sdk-factory, hooks-workspace-fallback) failed on windows-latest CI for two mechanical reasons. Linux/macOS were fine. 1) HOME env override is a no-op on Windows ------------------------------------------- `os.homedir()` reads `process.env.USERPROFILE` on win32, not `HOME`. Overriding only `process.env.HOME` in beforeEach() worked on POSIX but not Windows, so `authConfigPath()` resolved to the user's real home dir, polluted/got polluted across tests. Fix: override BOTH USERPROFILE and HOME on win32; restore both in afterEach. 2) spawnSync("npx", ...) doesn't resolve on Windows ---------------------------------------------------- npm/npx ship as `.cmd` shims on Windows. Bare "npx" fails ENOENT. Plus `.cmd` files cannot be spawned directly with arguments on recent Node due to CVE-2024-27980 — must use shell mode. Fix in test/hooks-workspace-fallback.test.ts: use "npx.cmd" + shell: true on win32, "npx" on POSIX. No product code changes. Pure test infrastructure fix. Tests still pass 604/604 on Linux locally. #!axme pr=129 repo=AxmeAI/axme-code
1 parent d267b82 commit e3fe6a5

3 files changed

Lines changed: 30 additions & 19 deletions

File tree

test/agent-sdk-factory.test.ts

Lines changed: 12 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,18 @@ import { mkdirSync, rmSync, writeFileSync } from "node:fs";
44
import { join } from "node:path";
55

66
const SANDBOX_HOME = "/tmp/axme-agent-sdk-factory-test";
7-
const ORIGINAL_HOME = process.env.HOME;
8-
const ORIGINAL_AXME_IDE = process.env.AXME_IDE;
9-
const ORIGINAL_API_KEY = process.env.ANTHROPIC_API_KEY;
10-
const ORIGINAL_CURSOR_KEY = process.env.CURSOR_API_KEY;
7+
// On Windows os.homedir() reads USERPROFILE, not HOME — override both
8+
// for cross-platform sandboxing.
9+
const HOME_VARS = process.platform === "win32" ? ["USERPROFILE", "HOME"] : ["HOME"];
10+
const ORIGINAL: Record<string, string | undefined> = {};
11+
for (const v of [...HOME_VARS, "AXME_IDE", "ANTHROPIC_API_KEY", "CURSOR_API_KEY"]) {
12+
ORIGINAL[v] = process.env[v];
13+
}
1114

1215
beforeEach(() => {
1316
rmSync(SANDBOX_HOME, { recursive: true, force: true });
1417
mkdirSync(SANDBOX_HOME, { recursive: true });
15-
process.env.HOME = SANDBOX_HOME;
18+
for (const v of HOME_VARS) process.env[v] = SANDBOX_HOME;
1619
delete process.env.AXME_IDE;
1720
delete process.env.CURSOR_API_KEY;
1821
// Keep ANTHROPIC_API_KEY out so factory falls into the "neither" path
@@ -22,14 +25,10 @@ beforeEach(() => {
2225

2326
afterEach(() => {
2427
rmSync(SANDBOX_HOME, { recursive: true, force: true });
25-
if (ORIGINAL_HOME === undefined) delete process.env.HOME;
26-
else process.env.HOME = ORIGINAL_HOME;
27-
if (ORIGINAL_AXME_IDE === undefined) delete process.env.AXME_IDE;
28-
else process.env.AXME_IDE = ORIGINAL_AXME_IDE;
29-
if (ORIGINAL_API_KEY === undefined) delete process.env.ANTHROPIC_API_KEY;
30-
else process.env.ANTHROPIC_API_KEY = ORIGINAL_API_KEY;
31-
if (ORIGINAL_CURSOR_KEY === undefined) delete process.env.CURSOR_API_KEY;
32-
else process.env.CURSOR_API_KEY = ORIGINAL_CURSOR_KEY;
28+
for (const v of [...HOME_VARS, "AXME_IDE", "ANTHROPIC_API_KEY", "CURSOR_API_KEY"]) {
29+
if (ORIGINAL[v] === undefined) delete process.env[v];
30+
else process.env[v] = ORIGINAL[v];
31+
}
3332
});
3433

3534
describe("createAgentSdk — IDE selection", () => {

test/cursor-auth-config.test.ts

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,20 +3,26 @@ import assert from "node:assert/strict";
33
import { mkdirSync, rmSync, writeFileSync, statSync, existsSync } from "node:fs";
44
import { join } from "node:path";
55

6-
// Override $HOME so the auth-config module reads from a sandboxed path.
6+
// Override the home-dir env var so auth-config (which calls os.homedir())
7+
// reads from a sandboxed path. On Windows os.homedir() reads USERPROFILE,
8+
// not HOME — set both for cross-platform safety.
79
const SANDBOX_HOME = "/tmp/axme-cursor-auth-test-home";
8-
const ORIGINAL_HOME = process.env.HOME;
10+
const HOME_VARS = process.platform === "win32" ? ["USERPROFILE", "HOME"] : ["HOME"];
11+
const ORIGINAL: Record<string, string | undefined> = {};
12+
for (const v of HOME_VARS) ORIGINAL[v] = process.env[v];
913

1014
beforeEach(() => {
1115
rmSync(SANDBOX_HOME, { recursive: true, force: true });
1216
mkdirSync(SANDBOX_HOME, { recursive: true });
13-
process.env.HOME = SANDBOX_HOME;
17+
for (const v of HOME_VARS) process.env[v] = SANDBOX_HOME;
1418
});
1519

1620
afterEach(() => {
1721
rmSync(SANDBOX_HOME, { recursive: true, force: true });
18-
if (ORIGINAL_HOME === undefined) delete process.env.HOME;
19-
else process.env.HOME = ORIGINAL_HOME;
22+
for (const v of HOME_VARS) {
23+
if (ORIGINAL[v] === undefined) delete process.env[v];
24+
else process.env[v] = ORIGINAL[v];
25+
}
2026
});
2127

2228
describe("auth.yaml round-trip with cursor_sdk mode", () => {

test/hooks-workspace-fallback.test.ts

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,13 +29,19 @@ afterEach(() => {
2929
});
3030

3131
function spawnHook(hookName: "pre-tool-use" | "post-tool-use" | "session-end", argv: string[], stdinJson: object) {
32+
// On Windows npm/npx ship as .cmd shims; spawnSync won't resolve bare "npx".
33+
// Use the .cmd extension on win32 and spawn through cmd.exe to avoid
34+
// CVE-2024-27980 EINVAL when invoking .cmd directly with arguments.
35+
const isWin = process.platform === "win32";
36+
const npxBin = isWin ? "npx.cmd" : "npx";
3237
const args = ["tsx", "src/cli.ts", "hook", hookName, ...argv];
33-
const result = spawnSync("npx", args, {
38+
const result = spawnSync(npxBin, args, {
3439
cwd: REPO_ROOT,
3540
input: JSON.stringify(stdinJson),
3641
encoding: "utf-8",
3742
env: { ...process.env, AXME_TELEMETRY_DISABLED: "1" },
3843
timeout: 15000,
44+
shell: isWin, // .cmd on Windows requires shell mode
3945
});
4046
return result;
4147
}

0 commit comments

Comments
 (0)