Skip to content

Commit 1e3dce5

Browse files
🤖 fix: add NON_INTERACTIVE_ENV_VARS to SSHRuntime.exec() (#812)
_Generated with `mux`_ Prevents git operations from blocking on editor/credential prompts when running in SSH workspaces, matching LocalRuntime behavior. ## Changes - Import and apply `NON_INTERACTIVE_ENV_VARS` in `SSHRuntime.exec()` - Add test verifying env vars are set for both runtime types ## Before `SSHRuntime.exec()` only exported `options.env`, so SSH workspaces could hang when git tried to open an editor or prompt for credentials. ## After Both `LocalRuntime` and `SSHRuntime` now apply `NON_INTERACTIVE_ENV_VARS` (`GIT_EDITOR`, `GIT_TERMINAL_PROMPT`, etc.) to prevent blocking prompts.
1 parent 7087ef4 commit 1e3dce5

File tree

2 files changed

+20
-5
lines changed

2 files changed

+20
-5
lines changed

src/node/runtime/SSHRuntime.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import { RuntimeError as RuntimeErrorClass } from "./Runtime";
1818
import { EXIT_CODE_ABORTED, EXIT_CODE_TIMEOUT } from "@/common/constants/exitCodes";
1919
import { log } from "@/node/services/log";
2020
import { checkInitHookExists, createLineBufferedLoggers, getInitHookEnv } from "./initHook";
21+
import { NON_INTERACTIVE_ENV_VARS } from "@/common/constants/env";
2122
import { streamProcessToLogger } from "./streamProcess";
2223
import { expandTildeForSSH, cdCommandForSSH } from "./tildeExpansion";
2324
import { getProjectName } from "@/node/utils/runtime/helpers";
@@ -106,11 +107,10 @@ export class SSHRuntime implements Runtime {
106107
// Add cd command if cwd is specified
107108
parts.push(cdCommandForSSH(options.cwd));
108109

109-
// Add environment variable exports
110-
if (options.env) {
111-
for (const [key, value] of Object.entries(options.env)) {
112-
parts.push(`export ${key}=${shescape.quote(value)}`);
113-
}
110+
// Add environment variable exports (user env first, then non-interactive overrides)
111+
const envVars = { ...options.env, ...NON_INTERACTIVE_ENV_VARS };
112+
for (const [key, value] of Object.entries(envVars)) {
113+
parts.push(`export ${key}=${shescape.quote(value)}`);
114114
}
115115

116116
// Add the actual command

tests/runtime/runtime.test.ts

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,21 @@ describeIntegration("Runtime integration tests", () => {
113113
expect(result.stdout.trim()).toBe("test-value");
114114
});
115115

116+
test.concurrent("sets NON_INTERACTIVE_ENV_VARS to prevent prompts", async () => {
117+
const runtime = createRuntime();
118+
await using workspace = await TestWorkspace.create(runtime, type);
119+
120+
// Verify GIT_TERMINAL_PROMPT is set to 0 (prevents credential prompts)
121+
const result = await execBuffered(
122+
runtime,
123+
'echo "GIT_TERMINAL_PROMPT=$GIT_TERMINAL_PROMPT GIT_EDITOR=$GIT_EDITOR"',
124+
{ cwd: workspace.path, timeout: 30 }
125+
);
126+
127+
expect(result.stdout).toContain("GIT_TERMINAL_PROMPT=0");
128+
expect(result.stdout).toContain("GIT_EDITOR=true");
129+
});
130+
116131
test.concurrent("handles empty output", async () => {
117132
const runtime = createRuntime();
118133
await using workspace = await TestWorkspace.create(runtime, type);

0 commit comments

Comments
 (0)