Skip to content

Commit 98eee63

Browse files
committed
Fix: Prevent color-forcing env vars from being forwarded when stdout is not a TTY
This fixes a bug where FORCE_COLOR, NO_COLOR, CLICOLOR, and CLICOLOR_FORCE were being forwarded from the host environment into containers even when stdout was redirected. This undermined the ANSI-leak fix by causing tools to emit ANSI escape codes despite the absence of a TTY. The fix conditionally skips forwarding these color-forcing variables when stdout is not a TTY, preventing ANSI codes from appearing in redirected output (e.g., 'lando composer show > file.txt'). User-provided environment variables (via userEnv parameter) still override this behavior, preserving explicit user intent.
1 parent 3ccf16c commit 98eee63

2 files changed

Lines changed: 30 additions & 3 deletions

File tree

test/build-exec-environment.spec.js

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,27 @@ describe('build-exec-environment', () => {
6464
const env = buildEnvironment(ctx);
6565
expect(env.TZ).to.equal('America/New_York');
6666
});
67+
68+
it('should not forward FORCE_COLOR when stdout is not a TTY', () => {
69+
process.env.FORCE_COLOR = '1';
70+
const ctx = {stdout: {isTTY: false, columns: 80, rows: 24}, stderr: {isTTY: false}, noColor: false};
71+
const env = buildEnvironment(ctx);
72+
expect(env).to.not.have.property('FORCE_COLOR');
73+
});
74+
75+
it('should not forward NO_COLOR when stdout is not a TTY', () => {
76+
process.env.NO_COLOR = '1';
77+
const ctx = {stdout: {isTTY: false, columns: 80, rows: 24}, stderr: {isTTY: false}, noColor: false};
78+
const env = buildEnvironment(ctx);
79+
expect(env).to.not.have.property('NO_COLOR');
80+
});
81+
82+
it('should forward FORCE_COLOR when stdout is a TTY', () => {
83+
process.env.FORCE_COLOR = '1';
84+
const ctx = {stdout: {isTTY: true}, stderr: {isTTY: true}, noColor: false};
85+
const env = buildEnvironment(ctx);
86+
expect(env.FORCE_COLOR).to.equal('1');
87+
});
6788
});
6889

6990
describe('synthetic vars', () => {
@@ -88,11 +109,12 @@ describe('build-exec-environment', () => {
88109
expect(env).to.not.have.property('CLICOLOR_FORCE');
89110
});
90111

91-
it('should not override inherited CLICOLOR_FORCE with synthetic', () => {
112+
it('should not forward CLICOLOR_FORCE when stdout is not a TTY', () => {
92113
process.env.CLICOLOR_FORCE = '3';
93114
const ctx = {stdout: {isTTY: false, columns: 80, rows: 24}, stderr: {isTTY: true}, noColor: false};
94115
const env = buildEnvironment(ctx);
95-
expect(env.CLICOLOR_FORCE).to.equal('3');
116+
// Color-forcing vars are skipped when stdout is not a TTY to prevent ANSI leakage
117+
expect(env).to.not.have.property('CLICOLOR_FORCE');
96118
});
97119
});
98120

utils/build-exec-environment.js

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,12 @@ const forwardKeys = [
2323
module.exports = (context, userEnv = {}) => {
2424
const inherited = {};
2525
for (const key of forwardKeys) {
26-
if (process.env[key] !== undefined) inherited[key] = process.env[key];
26+
if (process.env[key] !== undefined) {
27+
// Skip color-forcing vars when stdout is not a TTY to prevent ANSI leakage
28+
const colorVars = ['NO_COLOR', 'FORCE_COLOR', 'CLICOLOR', 'CLICOLOR_FORCE'];
29+
if (!context.stdout.isTTY && colorVars.includes(key)) continue;
30+
inherited[key] = process.env[key];
31+
}
2732
}
2833

2934
const synthetic = {};

0 commit comments

Comments
 (0)