Skip to content
This repository has been archived by the owner on Mar 3, 2023. It is now read-only.

Fix getEnvFromShell() to correctly handle newlines in env vars #17628

Merged
merged 7 commits into from
Sep 3, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 12 additions & 13 deletions spec/update-process-env-spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ import {
updateProcessEnv,
shouldGetEnvFromShell
} from '../src/update-process-env';
import dedent from 'dedent';
import mockSpawn from 'mock-spawn';
const temp = require('temp').track();

Expand Down Expand Up @@ -258,19 +257,19 @@ describe('updateProcessEnv(launchEnv)', function() {
spawn.setDefault(
spawn.simple(
0,
dedent`
FOO=BAR=BAZ=QUUX
TERM=xterm-something
PATH=/usr/bin:/bin:/usr/sbin:/sbin:/crazy/path
`
'FOO=BAR=BAZ=QUUX\0MULTILINE\nNAME=multiline\nvalue\0TERM=xterm-something\0PATH=/usr/bin:/bin:/usr/sbin:/sbin:/crazy/path'
)
);
await updateProcessEnv(process.env);
expect(spawn.calls.length).toBe(1);
expect(spawn.calls[0].command).toBe('/my/custom/bash');
expect(spawn.calls[0].args).toEqual(['-ilc', 'command env']);
expect(spawn.calls[0].args).toEqual([
'-ilc',
'command awk \'BEGIN{for(v in ENVIRON) printf("%s=%s%c", v, ENVIRON[v], 0)}\''
]);
expect(process.env).toEqual({
FOO: 'BAR=BAZ=QUUX',
'MULTILINE\nNAME': 'multiline\nvalue',
TERM: 'xterm-something',
PATH: '/usr/bin:/bin:/usr/sbin:/sbin:/crazy/path'
});
Expand All @@ -289,19 +288,19 @@ describe('updateProcessEnv(launchEnv)', function() {
spawn.setDefault(
spawn.simple(
0,
dedent`
FOO=BAR=BAZ=QUUX
TERM=xterm-something
PATH=/usr/bin:/bin:/usr/sbin:/sbin:/crazy/path
`
'FOO=BAR=BAZ=QUUX\0MULTILINE\nNAME=multiline\nvalue\0TERM=xterm-something\0PATH=/usr/bin:/bin:/usr/sbin:/sbin:/crazy/path'
)
);
await updateProcessEnv(process.env);
expect(spawn.calls.length).toBe(1);
expect(spawn.calls[0].command).toBe('/my/custom/bash');
expect(spawn.calls[0].args).toEqual(['-ilc', 'command env']);
expect(spawn.calls[0].args).toEqual([
'-ilc',
'command awk \'BEGIN{for(v in ENVIRON) printf("%s=%s%c", v, ENVIRON[v], 0)}\''
]);
expect(process.env).toEqual({
FOO: 'BAR=BAZ=QUUX',
'MULTILINE\nNAME': 'multiline\nvalue',
TERM: 'xterm-something',
PATH: '/usr/bin:/bin:/usr/sbin:/sbin:/crazy/path'
});
Expand Down
25 changes: 12 additions & 13 deletions src/update-process-env.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,12 @@ const ENVIRONMENT_VARIABLES_TO_PRESERVE = new Set([

const PLATFORMS_KNOWN_TO_WORK = new Set(['darwin', 'linux']);

// Shell command that returns env var=value lines separated by \0s so that
// newlines are handled properly. Note: need to use %c to inject the \0s
// to work with some non GNU awks.
const ENV_COMMAND =
'command awk \'BEGIN{for(v in ENVIRON) printf("%s=%s%c", v, ENVIRON[v], 0)}\'';

async function updateProcessEnv(launchEnv) {
let envToAssign;
if (launchEnv) {
Expand Down Expand Up @@ -78,7 +84,7 @@ async function getEnvFromShell(env) {
setTimeout(() => {
cleanup();
}, 5000);
child = childProcess.spawn(env.SHELL, ['-ilc', 'command env'], {
child = childProcess.spawn(env.SHELL, ['-ilc', ENV_COMMAND], {
encoding: 'utf8',
detached: true,
stdio: ['ignore', 'pipe', process.stderr]
Expand Down Expand Up @@ -109,7 +115,9 @@ async function getEnvFromShell(env) {
console.log(
'warning: ' +
env.SHELL +
' -ilc "command env" failed with signal (' +
' -ilc "' +
ENV_COMMAND +
'" failed with signal (' +
error.signal +
')'
);
Expand All @@ -121,22 +129,13 @@ async function getEnvFromShell(env) {
}

let result = {};
let skip = false;
for (let line of stdout.split('\n')) {
// start of shell function definition: skip full definition
if (line.includes('=() {')) {
skip = true;
}
if (!skip && line.includes('=')) {
for (let line of stdout.split('\0')) {
if (line.includes('=')) {
let components = line.split('=');
let key = components.shift();
let value = components.join('=');
result[key] = value;
}
// end of shell function definition
if (line === '}') {
skip = false;
}
}
return result;
}
Expand Down