Skip to content

Commit 19f5c0b

Browse files
Copiloticlanton
andauthored
Address PR review feedback on RUSH_ env trim plugin
Co-authored-by: iclanton <5010588+iclanton@users.noreply.github.com>
1 parent 99e7cf2 commit 19f5c0b

5 files changed

Lines changed: 27 additions & 18 deletions

File tree

common/changes/@microsoft/rush-lib/trim-rush-env-vars-experiment_2026-08-28-05-20.json renamed to common/changes/@microsoft/rush/trim-rush-env-vars-experiment_2026-08-28-05-20.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"changes": [
33
{
4-
"packageName": "@microsoft/rush-lib",
4+
"packageName": "@microsoft/rush",
55
"comment": "Add a new `trimRushEnvironmentVariablesForOperations` experiment that, when enabled, omits environment variables whose names begin with `RUSH_` from the environment forwarded to operation processes (e.g. \"build\", \"test\").",
66
"type": "minor"
77
}

libraries/rush-lib/assets/rush-init/common/config/rush/experiments.json

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -141,5 +141,14 @@
141141
* must implement the optional file-based methods for this to take effect; otherwise it falls back to the
142142
* buffer-based approach.
143143
*/
144-
/*[LINE "HYPOTHETICAL"]*/ "useDirectFileTransfersForBuildCache": true
144+
/*[LINE "HYPOTHETICAL"]*/ "useDirectFileTransfersForBuildCache": true,
145+
146+
/**
147+
* By default, Rush forwards its entire process environment (minus a small denylist) to the shell
148+
* commands it invokes for operations (e.g. 'build', 'test'). If true, environment variables whose
149+
* names begin with `RUSH_` will additionally be omitted from that forwarded environment. This can
150+
* help prevent operation scripts from accidentally depending on Rush's own internal environment
151+
* variables.
152+
*/
153+
/*[LINE "HYPOTHETICAL"]*/ "trimRushEnvironmentVariablesForOperations": true
145154
}

libraries/rush-lib/src/api/EnvironmentConfiguration.ts

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -255,6 +255,12 @@ export const EnvironmentVariableNames = {
255255
RUSH_QUIET_MODE: 'RUSH_QUIET_MODE'
256256
} as const;
257257

258+
/**
259+
* Matches the names of environment variables that are reserved for use by Rush itself.
260+
* @internal
261+
*/
262+
export const RUSH_ENVIRONMENT_VARIABLE_NAME_REGEXP: RegExp = /^RUSH_/i;
263+
258264
let _hasBeenValidated: boolean = false;
259265

260266
let _rushTempFolderOverride: string | undefined;
@@ -496,7 +502,7 @@ export class EnvironmentConfiguration {
496502

497503
const unknownEnvVariables: string[] = [];
498504
for (const envVarName in process.env) {
499-
if (process.env.hasOwnProperty(envVarName) && envVarName.match(/^RUSH_/i)) {
505+
if (process.env.hasOwnProperty(envVarName) && envVarName.match(RUSH_ENVIRONMENT_VARIABLE_NAME_REGEXP)) {
500506
const value: string | undefined = process.env[envVarName];
501507
// Environment variables are only case-insensitive on Windows
502508
const normalizedEnvVarName: string = IS_WINDOWS ? envVarName.toUpperCase() : envVarName;

libraries/rush-lib/src/logic/operations/TrimRushEnvironmentVariablesPlugin.ts

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,12 @@
11
// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.
22
// See LICENSE in the project root for license information.
33

4+
import { RUSH_ENVIRONMENT_VARIABLE_NAME_REGEXP } from '../../api/EnvironmentConfiguration';
45
import type { IPhasedCommandPlugin, PhasedCommandHooks } from '../../pluginFramework/PhasedCommandHooks';
56
import type { IEnvironment } from '../../utilities/Utilities';
67

78
const PLUGIN_NAME: 'TrimRushEnvironmentVariablesPlugin' = 'TrimRushEnvironmentVariablesPlugin';
89

9-
/**
10-
* Prefix used by environment variables that Rush itself defines and consumes.
11-
*/
12-
const RUSH_ENVIRONMENT_VARIABLE_NAME_PREFIX: 'RUSH_' = 'RUSH_';
13-
1410
/**
1511
* Phased command plugin that removes environment variables whose names begin with `RUSH_` before
1612
* they are forwarded to operation processes. Enabled via the `trimRushEnvironmentVariablesForOperations`
@@ -20,13 +16,14 @@ export class TrimRushEnvironmentVariablesPlugin implements IPhasedCommandPlugin
2016
public apply(hooks: PhasedCommandHooks): void {
2117
hooks.onGraphCreatedAsync.tap(PLUGIN_NAME, (graph) => {
2218
graph.hooks.createEnvironmentForOperation.tap(PLUGIN_NAME, (env: IEnvironment) => {
19+
const trimmedEnv: IEnvironment = {};
2320
for (const key of Object.getOwnPropertyNames(env)) {
24-
if (key.toUpperCase().startsWith(RUSH_ENVIRONMENT_VARIABLE_NAME_PREFIX)) {
25-
delete env[key];
21+
if (!RUSH_ENVIRONMENT_VARIABLE_NAME_REGEXP.test(key)) {
22+
trimmedEnv[key] = env[key];
2623
}
2724
}
2825

29-
return env;
26+
return trimmedEnv;
3027
});
3128
});
3229
}

libraries/rush-lib/src/logic/operations/test/TrimRushEnvironmentVariablesPlugin.test.ts

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ describe(TrimRushEnvironmentVariablesPlugin.name, () => {
4141
);
4242

4343
const rushConfiguration = RushConfiguration.loadFromConfigurationFile(rushJsonFile);
44-
const commandLineJson: ICommandLineJson = JsonFile.load(commandLineJsonFile);
44+
const commandLineJson: ICommandLineJson = await JsonFile.loadAsync(commandLineJsonFile);
4545

4646
const commandLineConfiguration = new CommandLineConfiguration(commandLineJson);
4747
const buildCommand: IPhasedCommandConfig = commandLineConfiguration.commands.get(
@@ -67,16 +67,13 @@ describe(TrimRushEnvironmentVariablesPlugin.name, () => {
6767

6868
const operations: Set<Operation> = await hooks.createOperationsAsync.promise(
6969
new Set(),
70-
fakeCreateOperationsContext as unknown as ICreateOperationsContext
70+
fakeCreateOperationsContext as ICreateOperationsContext
7171
);
7272

7373
// Set up a mock graph and invoke onGraphCreatedAsync so the plugin registers its graph hooks
7474
const graphHooks: OperationGraphHooks = new OperationGraphHooks();
75-
const fakeGraph: IOperationGraph = { hooks: graphHooks } as unknown as IOperationGraph;
76-
await hooks.onGraphCreatedAsync.promise(
77-
fakeGraph,
78-
fakeCreateOperationsContext as unknown as IOperationGraphContext
79-
);
75+
const fakeGraph: IOperationGraph = { hooks: graphHooks } as IOperationGraph;
76+
await hooks.onGraphCreatedAsync.promise(fakeGraph, fakeCreateOperationsContext as IOperationGraphContext);
8077

8178
const operation = Array.from(operations)[0];
8279
expect(operation).toBeDefined();

0 commit comments

Comments
 (0)