Skip to content

Commit d0d5120

Browse files
fix(e2e): preserve host command execution boundary (#10439)
## Summary Keeps the host PATH when ShellProbe merges an explicit command environment, without inheriting ambient workflow secrets. Also keeps the fixture shell-quoting helper self-contained so the independent tsx cleanup controller does not cross the CommonJS source compiler boundary. ## Related Issue Refs #9880 ## Verification - Focused E2E support tests: 93 passed - Independent cleanup controller loads and exits successfully without an ownership receipt - CLI build and TypeScript passed - Commit and push hooks passed Signed-off-by: Julie Yaunches <jyaunches@nvidia.com> <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit - **Bug Fixes** - Improved shell-based workload execution by preserving the host `PATH` while still applying command-specific environment overrides. - Enhanced handling of shell-quoted values, including inputs containing apostrophes. - **Tests** - Added end-to-end coverage confirming commands can be resolved through the preserved `PATH` and receive custom environment variables correctly. <!-- end of auto-generated comment: release notes by coderabbit.ai --> Signed-off-by: Julie Yaunches <jyaunches@nvidia.com> Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
1 parent a2a719b commit d0d5120

2 files changed

Lines changed: 27 additions & 1 deletion

File tree

test/e2e/fixtures/clients/command.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,9 @@ import type {
77
TrustedShellCommand,
88
} from "../shell-probe.ts";
99

10-
export { shellQuote } from "../../../../src/lib/core/shell-quote.ts";
10+
export function shellQuote(value: unknown): string {
11+
return `'${String(value).replace(/'/g, `'\\''`)}'`;
12+
}
1113

1214
export interface CommandRunner {
1315
run(command: TrustedShellCommand, options?: ShellProbeRunOptions): Promise<ShellProbeResult>;

test/e2e/support/e2e-fixture-context.test.ts

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -331,6 +331,30 @@ describe("E2E fixture primitives", () => {
331331
}
332332
});
333333

334+
it("shell probe inherits the host PATH when command options add environment variables", async () => {
335+
const tmp = fs.mkdtempSync(path.join(os.tmpdir(), "nemoclaw-e2e-shell-probe-path-"));
336+
try {
337+
const probe = new ShellProbe({
338+
artifacts: new ArtifactSink(tmp),
339+
progress: supportProgress(),
340+
redact: (text) => text,
341+
signal: new AbortController().signal,
342+
});
343+
const result = await probe.run(
344+
trustedShellCommand({
345+
command: "node",
346+
args: ["-e", "process.stdout.write(process.env.PROBE_VALUE ?? '')"],
347+
reason: "verify ShellProbe keeps PATH while merging command environment",
348+
}),
349+
{ env: { PROBE_VALUE: "present" }, timeoutMs: 5_000 },
350+
);
351+
expect(result.exitCode).toBe(0);
352+
expect(result.stdout).toBe("present");
353+
} finally {
354+
fs.rmSync(tmp, { recursive: true, force: true });
355+
}
356+
});
357+
334358
it("shell probe reports child liveness to the shared observer without duplicating it", async () => {
335359
const tmp = fs.mkdtempSync(path.join(os.tmpdir(), "nemoclaw-e2e-shell-observer-"));
336360
try {

0 commit comments

Comments
 (0)