Skip to content

Commit b3efc7b

Browse files
committed
Fix node interception issue with spaces in paths on Windows
Previously if the path to the overrides directory contained spaces (e.g. because your username had a space) then we quoted the path in NODE_OPTIONS, and some combination of Node + Git Bash behaviour ended up treating all Windows backslashes as escape characters and breaking the string entirely. There's a few possible solutions, but the easiest one is to avoid using backslashes entirely, and just stick to fully supported POSIX paths instead.
1 parent 84c9463 commit b3efc7b

File tree

5 files changed

+33
-21
lines changed

5 files changed

+33
-21
lines changed

src/interceptors/docker/docker-interception-services.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,8 @@ export async function startDockerInterceptionServices(
107107
// container connecting to a network):
108108
prepareDockerTunnel(),
109109
// Create a Docker volume, containing our cert and the override files:
110-
ensureDockerInjectionVolumeExists(httpsConfig.certContent)]);
110+
ensureDockerInjectionVolumeExists(httpsConfig.certContent)
111+
]);
111112
}
112113

113114
export async function ensureDockerServicesRunning(proxyPort: number) {

src/interceptors/terminal/existing-terminal-interceptor.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@ export class ExistingTerminalInterceptor implements Interceptor {
8383

8484
const serverState = { server, isActive: false };
8585

86-
const posixEnvVars = getTerminalEnvVars(proxyPort, this.config.https, 'posix-runtime-inherit', {});
86+
const posixEnvVars = getTerminalEnvVars(proxyPort, this.config.https, 'posix-runtime-inherit');
8787

8888
// Endpoints for each of the various setup scripts:
8989
await server.forGet('/setup').thenReply(200,
@@ -99,7 +99,7 @@ export class ExistingTerminalInterceptor implements Interceptor {
9999
{ "content-type": "application/x-fish" }
100100
);
101101

102-
const powerShellEnvVars = getTerminalEnvVars(proxyPort, this.config.https, 'powershell-runtime-inherit', {});
102+
const powerShellEnvVars = getTerminalEnvVars(proxyPort, this.config.https, 'powershell-runtime-inherit');
103103
await server.forGet('/ps-setup').thenReply(200,
104104
getPowerShellScript(server.urlFor('/success'), powerShellEnvVars),
105105
{ "content-type": "text/plain" }

src/interceptors/terminal/fresh-terminal-interceptor.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -228,7 +228,7 @@ export class FreshTerminalInterceptor implements Interceptor {
228228
_.assign(options || {}, {
229229
env: {
230230
...currentEnv,
231-
...getTerminalEnvVars(proxyPort, this.config.https, currentEnv, {}),
231+
...getTerminalEnvVars(proxyPort, this.config.https, currentEnv),
232232
},
233233
cwd: currentEnv.HOME || currentEnv.USERPROFILE
234234
})

src/interceptors/terminal/terminal-env-overrides.ts

Lines changed: 20 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -25,17 +25,19 @@ export function getTerminalEnvVars(
2525
| { [key: string]: string | undefined }
2626
| 'posix-runtime-inherit'
2727
| 'powershell-runtime-inherit',
28-
targetEnvConfig: {
29-
httpToolkitHost?: string,
30-
overridePath?: string,
31-
targetPlatform?: NodeJS.Platform
32-
} = {}
28+
29+
// All 3 of the below must be overriden together, or not at all, to avoid
30+
// mixing platforms & default (platform-specific) paths
31+
targetEnvConfig?: {
32+
httpToolkitHost: string,
33+
overridePath: string,
34+
targetPlatform: NodeJS.Platform
35+
}
3336
): { [key: string]: string } {
34-
const { overridePath, targetPlatform, httpToolkitHost } = {
37+
const { overridePath, targetPlatform, httpToolkitHost } = targetEnvConfig ?? {
3538
httpToolkitHost: '127.0.0.1',
3639
overridePath: OVERRIDES_DIR,
37-
targetPlatform: process.platform,
38-
...targetEnvConfig
40+
targetPlatform: process.platform
3941
};
4042

4143
const runtimeInherit = currentEnv === 'posix-runtime-inherit'
@@ -63,7 +65,16 @@ export function getTerminalEnvVars(
6365
const rubyGemsPath = joinPath(overridePath, RUBY_OVERRIDE_DIR);
6466
const pythonPath = joinPath(overridePath, PYTHON_OVERRIDE_DIR);
6567
const phpPath = joinPath(overridePath, PHP_OVERRIDE_DIR);
66-
const nodePrependScript = joinPath(overridePath, ...NODE_PREPEND_SCRIPT);
68+
69+
// Node supports POSIX paths everywhere, and using those solves some weird issues
70+
// when combining backslashes with quotes in Git Bash on Windows:
71+
const nodePrependScript = path.posix.join(
72+
...(targetPlatform === 'win32'
73+
? overridePath.split(path.win32.sep)
74+
: [overridePath]
75+
),
76+
...NODE_PREPEND_SCRIPT
77+
);
6778
const nodePrependOption = `--require ${
6879
// Avoid quoting except when necessary, because node 8 doesn't support quotes here
6980
nodePrependScript.includes(' ')

test/integration/interceptors/docker-terminal-interception.spec.ts

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ describe('Docker CLI interception', function () {
6464
const { server, httpsConfig} = await testSetup;
6565
const mainRule = await server.forGet('https://example.test').thenReply(200);
6666

67-
const terminalEnvOverrides = getTerminalEnvVars(server.port, httpsConfig, process.env, {});
67+
const terminalEnvOverrides = getTerminalEnvVars(server.port, httpsConfig, process.env);
6868

6969
childProc.spawn(
7070
'docker', ['run', '--rm', imageId, 'https://example.test'],
@@ -95,7 +95,7 @@ describe('Docker CLI interception', function () {
9595

9696
const mainRule = await server.forGet("https://example.test").thenReply(200);
9797

98-
const terminalEnvOverrides = getTerminalEnvVars(server.port, httpsConfig, process.env, {});
98+
const terminalEnvOverrides = getTerminalEnvVars(server.port, httpsConfig, process.env);
9999

100100
const { exitCode, stdout, stderr } = await spawnToResult(
101101
'docker', ['run', '--rm', 'node:14', '-e', `require("https").get("https://example.test")`],
@@ -119,7 +119,7 @@ describe('Docker CLI interception', function () {
119119

120120
const mainRule = await server.forAnyRequest().thenReply(200, "Mock response\n");
121121

122-
const terminalEnvOverrides = getTerminalEnvVars(server.port, httpsConfig, process.env, {});
122+
const terminalEnvOverrides = getTerminalEnvVars(server.port, httpsConfig, process.env);
123123

124124
const { exitCode, stdout, stderr } = await spawnToResult('docker', ['build', '.'], {
125125
env: { ...process.env, ...terminalEnvOverrides },
@@ -185,7 +185,7 @@ Successfully built <hash>
185185
it("should support proxying 'docker exec'", async function () {
186186
const { server, httpsConfig } = await testSetup;
187187

188-
const terminalEnvOverrides = getTerminalEnvVars(server.port, httpsConfig, process.env, {});
188+
const terminalEnvOverrides = getTerminalEnvVars(server.port, httpsConfig, process.env);
189189

190190
// Launch a background Node.js container that stays running for 10 seconds
191191
const runResult = await spawnToResult(
@@ -232,7 +232,7 @@ Successfully built <hash>
232232
true
233233
);
234234

235-
const terminalEnvOverrides = getTerminalEnvVars(server.port, httpsConfig, process.env, {});
235+
const terminalEnvOverrides = getTerminalEnvVars(server.port, httpsConfig, process.env);
236236

237237
// "DC Up" the same project, but in an intercepted env. Should ignore the existing containers,
238238
// create new intercepted containers, and then up those as normal.
@@ -281,7 +281,7 @@ Successfully built <hash>
281281
true
282282
);
283283

284-
const terminalEnvOverrides = getTerminalEnvVars(server.port, httpsConfig, process.env, {});
284+
const terminalEnvOverrides = getTerminalEnvVars(server.port, httpsConfig, process.env);
285285

286286
// "DC Up" the same project, but in an intercepted env. Should ignore the existing containers,
287287
// create new intercepted containers, and then up those as normal.
@@ -316,7 +316,7 @@ Successfully built <hash>
316316
it("should clean up containers after shutdown", async () => {
317317
const { server, httpsConfig } = await testSetup;
318318

319-
const terminalEnvOverrides = getTerminalEnvVars(server.port, httpsConfig, process.env, {});
319+
const terminalEnvOverrides = getTerminalEnvVars(server.port, httpsConfig, process.env);
320320

321321
const uninterceptedResult = await spawnToResult('docker', ['create', 'node:14']);
322322

@@ -358,7 +358,7 @@ Successfully built <hash>
358358
const { server, httpsConfig } = await testSetup;
359359
const docker = new Docker();
360360

361-
const terminalEnvOverrides = getTerminalEnvVars(server.port, httpsConfig, process.env, {});
361+
const terminalEnvOverrides = getTerminalEnvVars(server.port, httpsConfig, process.env);
362362

363363
// Tunnel doesn't start preemptively:
364364
await delay(500);

0 commit comments

Comments
 (0)