Skip to content

Commit 2ec2f65

Browse files
committed
fix: resolve rebase conflicts and fix flaky tests on Mac
1 parent b5d75f3 commit 2ec2f65

File tree

3 files changed

+64
-7
lines changed

3 files changed

+64
-7
lines changed

nemoclaw/src/commands/migration-state.test.ts

Lines changed: 26 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
// SPDX-License-Identifier: Apache-2.0
33

44
import { describe, it, expect, beforeEach, vi } from "vitest";
5+
import path from "node:path";
56
import type { PluginLogger } from "../index.js";
67

78
// ---------------------------------------------------------------------------
@@ -28,12 +29,28 @@ function addSymlink(p: string): void {
2829
}
2930

3031
vi.mock("node:fs", async (importOriginal) => {
31-
const original = await importOriginal();
32+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
33+
const original = (await importOriginal()) as any;
3234
return {
3335
...original,
3436
existsSync: (p: string) => store.has(p),
35-
mkdirSync: vi.fn((p: string) => {
36-
addDir(p);
37+
mkdirSync: vi.fn((p: string, options?: { recursive?: boolean }) => {
38+
if (options?.recursive) {
39+
let current = "";
40+
const parts = p.split("/");
41+
for (const part of parts) {
42+
if (!part && !current) {
43+
current = "/";
44+
continue;
45+
}
46+
current = path.join(current, part);
47+
if (!store.has(current)) {
48+
addDir(current);
49+
}
50+
}
51+
} else {
52+
addDir(p);
53+
}
3754
}),
3855
readFileSync: (p: string) => {
3956
const entry = store.get(p);
@@ -43,14 +60,16 @@ vi.mock("node:fs", async (importOriginal) => {
4360
writeFileSync: vi.fn((p: string, data: string) => {
4461
store.set(p, { type: "file", content: data });
4562
}),
63+
chmodSync: vi.fn(),
4664
copyFileSync: vi.fn((src: string, dest: string) => {
4765
const entry = store.get(src);
4866
if (!entry) throw new Error(`ENOENT: ${src}`);
4967
store.set(dest, { ...entry });
5068
}),
5169
cpSync: vi.fn((src: string, dest: string) => {
52-
// Shallow copy: copy all entries whose path starts with src
53-
for (const [k, v] of store) {
70+
// Recursive copy: find all entries starting with src
71+
const entries = [...store.entries()];
72+
for (const [k, v] of entries) {
5473
if (k === src || k.startsWith(src + "/")) {
5574
const relative = k.slice(src.length);
5675
store.set(dest + relative, { ...v });
@@ -59,7 +78,8 @@ vi.mock("node:fs", async (importOriginal) => {
5978
}),
6079
rmSync: vi.fn(),
6180
renameSync: vi.fn((oldPath: string, newPath: string) => {
62-
for (const [k, v] of store) {
81+
const entries = [...store.entries()];
82+
for (const [k, v] of entries) {
6383
if (k === oldPath || k.startsWith(oldPath + "/")) {
6484
const relative = k.slice(oldPath.length);
6585
store.set(newPath + relative, v);

test/cli.test.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ describe("CLI dispatch", () => {
7676
expect(r.out.includes("Collecting diagnostics")).toBeTruthy();
7777
expect(r.out.includes("System")).toBeTruthy();
7878
expect(r.out.includes("Done")).toBeTruthy();
79-
});
79+
}, 15000);
8080

8181
it("debug exits 1 on unknown option", () => {
8282
const r = run("debug --quik");

test/credential-isolation.test.js

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
// SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
2+
// SPDX-License-Identifier: Apache-2.0
3+
4+
import { describe, it, expect } from "vitest";
5+
import fs from "node:fs";
6+
import path from "node:path";
7+
8+
const ROOT = path.resolve(__dirname, "..");
9+
const CLI_PATH = path.join(ROOT, "bin/nemoclaw.js");
10+
11+
describe("credential-isolation (static analysis)", () => {
12+
const content = fs.readFileSync(CLI_PATH, "utf-8");
13+
14+
it("ensures setup() spreads process.env when passing NVIDIA_API_KEY", () => {
15+
// Look for: run(`bash "${SCRIPTS}/setup.sh" ${shellQuote(safeName)}`, { env: { ...process.env, NVIDIA_API_KEY: key } });
16+
const match = content.match(/async function setup\(\) \{[\s\S]*?run\(`bash "\$\{SCRIPTS\}\/setup\.sh" \$\{shellQuote\(safeName\)\}`, \{ env: \{ \.\.\.process\.env, NVIDIA_API_KEY: key \} \}\);/);
17+
expect(match, "setup() should spread process.env and pass NVIDIA_API_KEY").not.toBeNull();
18+
});
19+
20+
it("ensures setupSpark() spreads process.env when passing NVIDIA_API_KEY", () => {
21+
// Look for: run(`sudo -E bash "${SCRIPTS}/setup-spark.sh"`, { env: { ...process.env, NVIDIA_API_KEY: key } });
22+
const match = content.match(/async function setupSpark\(\) \{[\s\S]*?run\(`sudo -E bash "\$\{SCRIPTS\}\/setup-spark\.sh"`, \{ env: \{ \.\.\.process\.env, NVIDIA_API_KEY: key \} \}\);/);
23+
expect(match, "setupSpark() should spread process.env and pass NVIDIA_API_KEY").not.toBeNull();
24+
});
25+
26+
it("ensures deploy() reads NVIDIA_API_KEY from local env object", () => {
27+
// Look for: const envLines = [`NVIDIA_API_KEY=${shellQuote(env.NVIDIA_API_KEY || "")}`];
28+
const match = content.match(/const envLines = \[`NVIDIA_API_KEY=\$\{shellQuote\(env\.NVIDIA_API_KEY \|\| ""\)\}`\];/);
29+
expect(match, "deploy() should read NVIDIA_API_KEY from env.NVIDIA_API_KEY").not.toBeNull();
30+
});
31+
32+
it("ensures deploy() reads GITHUB_TOKEN from local env object", () => {
33+
// Look for: const ghToken = env.GITHUB_TOKEN;
34+
const match = content.match(/const ghToken = env\.GITHUB_TOKEN;/);
35+
expect(match, "deploy() should read GITHUB_TOKEN from env.GITHUB_TOKEN").not.toBeNull();
36+
});
37+
});

0 commit comments

Comments
 (0)