mirror of
https://github.com/openclaw/openclaw.git
synced 2026-07-21 10:16:44 +00:00
Block unsafe Node runtime env overrides [AI] (#87308)
* fix: block unsafe node runtime env overrides * fix: block node env path redirects * docs: add changelog entry for PR merge
This commit is contained in:
@@ -11,6 +11,7 @@ Docs: https://docs.openclaw.ai
|
||||
|
||||
### Fixes
|
||||
|
||||
- Block unsafe Node runtime env overrides [AI]. (#87308) Thanks @pgondhi987.
|
||||
- Telegram: route `sendMessage` action replies through durable outbound delivery so completed agent responses remain retryable when the gateway send path times out. (#87261) Thanks @mbelinky.
|
||||
|
||||
## 2026.5.26
|
||||
|
||||
@@ -135,6 +135,10 @@ enum HostEnvSecurityPolicy {
|
||||
"NODE_AUTH_TOKEN",
|
||||
"NODE_OPTIONS",
|
||||
"NODE_PATH",
|
||||
"NODE_REDIRECT_WARNINGS",
|
||||
"NODE_REPL_EXTERNAL_MODULE",
|
||||
"NODE_REPL_HISTORY",
|
||||
"NODE_V8_COVERAGE",
|
||||
"NPM_TOKEN",
|
||||
"OBJC_INCLUDE_PATH",
|
||||
"OPENSSL_CONF",
|
||||
@@ -267,6 +271,10 @@ enum HostEnvSecurityPolicy {
|
||||
"MYVIMRC",
|
||||
"NODE_OPTIONS",
|
||||
"NODE_PATH",
|
||||
"NODE_REDIRECT_WARNINGS",
|
||||
"NODE_REPL_EXTERNAL_MODULE",
|
||||
"NODE_REPL_HISTORY",
|
||||
"NODE_V8_COVERAGE",
|
||||
"PACKER_PLUGIN_PATH",
|
||||
"PERL5LIB",
|
||||
"PERL5OPT",
|
||||
|
||||
+1
-1
@@ -441,7 +441,7 @@ Launches a local child process and communicates over stdin/stdout.
|
||||
<Warning>
|
||||
**Stdio env safety filter**
|
||||
|
||||
OpenClaw rejects interpreter-startup env keys that can alter how a stdio MCP server starts up before the first RPC, even if they appear in a server's `env` block. Blocked keys include `NODE_OPTIONS`, `PYTHONSTARTUP`, `PYTHONPATH`, `PERL5OPT`, `RUBYOPT`, `SHELLOPTS`, `PS4`, and similar runtime-control variables. Startup rejects these with a configuration error so they cannot inject an implicit prelude, swap the interpreter, or enable a debugger against the stdio process. Ordinary credential, proxy, and server-specific env vars (`GITHUB_TOKEN`, `HTTP_PROXY`, custom `*_API_KEY`, etc.) are unaffected.
|
||||
OpenClaw rejects interpreter-startup env keys that can alter how a stdio MCP server starts up before the first RPC, even if they appear in a server's `env` block. Blocked keys include `NODE_OPTIONS`, `NODE_REDIRECT_WARNINGS`, `NODE_REPL_EXTERNAL_MODULE`, `NODE_REPL_HISTORY`, `NODE_V8_COVERAGE`, `PYTHONSTARTUP`, `PYTHONPATH`, `PERL5OPT`, `RUBYOPT`, `SHELLOPTS`, `PS4`, and similar runtime-control variables. Startup rejects these with a configuration error so they cannot inject an implicit prelude, swap the interpreter, enable a debugger, or redirect runtime output against the stdio process. Ordinary credential, proxy, and server-specific env vars (`GITHUB_TOKEN`, `HTTP_PROXY`, custom `*_API_KEY`, etc.) are unaffected.
|
||||
|
||||
If your MCP server genuinely needs one of the blocked variables, set it on the gateway host process instead of under the stdio server's `env`.
|
||||
</Warning>
|
||||
|
||||
+1
-1
@@ -376,7 +376,7 @@ Notes:
|
||||
- For allow-always decisions in allowlist mode, known dispatch wrappers (`env`, `nice`, `nohup`, `stdbuf`, `timeout`) persist inner executable paths instead of wrapper paths. If unwrapping is not safe, no allowlist entry is persisted automatically.
|
||||
- On Windows node hosts in allowlist mode, shell-wrapper runs via `cmd.exe /c` require approval (allowlist entry alone does not auto-allow the wrapper form).
|
||||
- `system.notify` supports `--priority <passive|active|timeSensitive>` and `--delivery <system|overlay|auto>`.
|
||||
- Node hosts ignore `PATH` overrides and strip dangerous startup/shell keys (`DYLD_*`, `LD_*`, `NODE_OPTIONS`, `PYTHON*`, `PERL*`, `RUBYOPT`, `SHELLOPTS`, `PS4`). If you need extra PATH entries, configure the node host service environment (or install tools in standard locations) instead of passing `PATH` via `--env`.
|
||||
- Node hosts ignore `PATH` overrides and strip dangerous startup/shell keys (`DYLD_*`, `LD_*`, `NODE_OPTIONS`, `NODE_REDIRECT_WARNINGS`, `NODE_REPL_EXTERNAL_MODULE`, `NODE_REPL_HISTORY`, `NODE_V8_COVERAGE`, `PYTHON*`, `PERL*`, `RUBYOPT`, `SHELLOPTS`, `PS4`). If you need extra PATH entries, configure the node host service environment (or install tools in standard locations) instead of passing `PATH` via `--env`.
|
||||
- On macOS node mode, `system.run` is gated by exec approvals in the macOS app (Settings → Exec approvals).
|
||||
Ask/allowlist/full behave the same as the headless node host; denied prompts return `SYSTEM_RUN_DENIED`.
|
||||
- On headless node host, `system.run` is gated by exec approvals (`~/.openclaw/exec-approvals.json`).
|
||||
|
||||
@@ -105,7 +105,7 @@ Notes:
|
||||
- `allowlist` entries are glob patterns for resolved binary paths, or bare command names for PATH-invoked commands.
|
||||
- Raw shell command text that contains shell control or expansion syntax (`&&`, `||`, `;`, `|`, `` ` ``, `$`, `<`, `>`, `(`, `)`) is treated as an allowlist miss and requires explicit approval (or allowlisting the shell binary).
|
||||
- Choosing "Always Allow" in the prompt adds that command to the allowlist.
|
||||
- `system.run` environment overrides are filtered (drops `PATH`, `DYLD_*`, `LD_*`, `NODE_OPTIONS`, `PYTHON*`, `PERL*`, `RUBYOPT`, `SHELLOPTS`, `PS4`) and then merged with the app's environment.
|
||||
- `system.run` environment overrides are filtered (drops `PATH`, `DYLD_*`, `LD_*`, `NODE_OPTIONS`, `NODE_REDIRECT_WARNINGS`, `NODE_REPL_EXTERNAL_MODULE`, `NODE_REPL_HISTORY`, `NODE_V8_COVERAGE`, `PYTHON*`, `PERL*`, `RUBYOPT`, `SHELLOPTS`, `PS4`) and then merged with the app's environment.
|
||||
- For shell wrappers (`bash|sh|zsh ... -c/-lc`), request-scoped environment overrides are reduced to a small explicit allowlist (`TERM`, `LANG`, `LC_*`, `COLORTERM`, `NO_COLOR`, `FORCE_COLOR`).
|
||||
- For allow-always decisions in allowlist mode, known dispatch wrappers (`env`, `nice`, `nohup`, `stdbuf`, `timeout`) persist inner executable paths instead of wrapper paths. If unwrapping is not safe, no allowlist entry is persisted automatically.
|
||||
|
||||
|
||||
+53
-22
@@ -691,35 +691,66 @@ describe("applySkillEnvOverrides", () => {
|
||||
|
||||
it("blocks dangerous host env overrides even when declared", () => {
|
||||
const entries = envSkillEntries("dangerous-env-skill", {
|
||||
requires: { env: ["BASH_ENV", "SHELL"] },
|
||||
requires: {
|
||||
env: [
|
||||
"BASH_ENV",
|
||||
"SHELL",
|
||||
"NODE_REDIRECT_WARNINGS",
|
||||
"NODE_REPL_EXTERNAL_MODULE",
|
||||
"NODE_REPL_HISTORY",
|
||||
"NODE_V8_COVERAGE",
|
||||
],
|
||||
},
|
||||
});
|
||||
|
||||
withClearedEnv(["BASH_ENV", "SHELL"], () => {
|
||||
const restore = applySkillEnvOverrides({
|
||||
skills: entries,
|
||||
config: {
|
||||
skills: {
|
||||
entries: {
|
||||
"dangerous-env-skill": {
|
||||
env: {
|
||||
BASH_ENV: "/tmp/pwn.sh",
|
||||
SHELL: "/tmp/evil-shell",
|
||||
withClearedEnv(
|
||||
[
|
||||
"BASH_ENV",
|
||||
"SHELL",
|
||||
"NODE_REDIRECT_WARNINGS",
|
||||
"NODE_REPL_EXTERNAL_MODULE",
|
||||
"NODE_REPL_HISTORY",
|
||||
"NODE_V8_COVERAGE",
|
||||
],
|
||||
() => {
|
||||
const restore = applySkillEnvOverrides({
|
||||
skills: entries,
|
||||
config: {
|
||||
skills: {
|
||||
entries: {
|
||||
"dangerous-env-skill": {
|
||||
env: {
|
||||
BASH_ENV: "/tmp/pwn.sh",
|
||||
SHELL: "/tmp/evil-shell",
|
||||
NODE_REDIRECT_WARNINGS: "/tmp/node-warnings.log",
|
||||
NODE_REPL_EXTERNAL_MODULE: "/tmp/pwn.js",
|
||||
NODE_REPL_HISTORY: "/tmp/node-repl-history",
|
||||
NODE_V8_COVERAGE: "/tmp/coverage",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
try {
|
||||
expect(process.env.BASH_ENV).toBeUndefined();
|
||||
expect(process.env.SHELL).toBeUndefined();
|
||||
} finally {
|
||||
restore();
|
||||
expect(process.env.BASH_ENV).toBeUndefined();
|
||||
expect(process.env.SHELL).toBeUndefined();
|
||||
}
|
||||
});
|
||||
try {
|
||||
expect(process.env.BASH_ENV).toBeUndefined();
|
||||
expect(process.env.SHELL).toBeUndefined();
|
||||
expect(process.env.NODE_REDIRECT_WARNINGS).toBeUndefined();
|
||||
expect(process.env.NODE_REPL_EXTERNAL_MODULE).toBeUndefined();
|
||||
expect(process.env.NODE_REPL_HISTORY).toBeUndefined();
|
||||
expect(process.env.NODE_V8_COVERAGE).toBeUndefined();
|
||||
} finally {
|
||||
restore();
|
||||
expect(process.env.BASH_ENV).toBeUndefined();
|
||||
expect(process.env.SHELL).toBeUndefined();
|
||||
expect(process.env.NODE_REDIRECT_WARNINGS).toBeUndefined();
|
||||
expect(process.env.NODE_REPL_EXTERNAL_MODULE).toBeUndefined();
|
||||
expect(process.env.NODE_REPL_HISTORY).toBeUndefined();
|
||||
expect(process.env.NODE_V8_COVERAGE).toBeUndefined();
|
||||
}
|
||||
},
|
||||
);
|
||||
});
|
||||
|
||||
it("blocks override-only host env overrides in skill config", () => {
|
||||
|
||||
@@ -229,6 +229,10 @@ describe("loadDotEnv", () => {
|
||||
[
|
||||
"SAFE_KEY=from-cwd",
|
||||
"NODE_OPTIONS=--require ./evil.js",
|
||||
"NODE_REDIRECT_WARNINGS=./warnings.log",
|
||||
"NODE_REPL_EXTERNAL_MODULE=./evil-repl.js",
|
||||
"NODE_REPL_HISTORY=./repl-history",
|
||||
"NODE_V8_COVERAGE=./coverage",
|
||||
"OPENCLAW_STATE_DIR=./evil-state",
|
||||
"OPENCLAW_CONFIG_PATH=./evil-config.json",
|
||||
"ANTHROPIC_BASE_URL=https://evil.example.com/v1",
|
||||
@@ -249,6 +253,10 @@ describe("loadDotEnv", () => {
|
||||
vi.spyOn(process, "cwd").mockReturnValue(cwdDir);
|
||||
delete process.env.SAFE_KEY;
|
||||
delete process.env.NODE_OPTIONS;
|
||||
delete process.env.NODE_REDIRECT_WARNINGS;
|
||||
delete process.env.NODE_REPL_EXTERNAL_MODULE;
|
||||
delete process.env.NODE_REPL_HISTORY;
|
||||
delete process.env.NODE_V8_COVERAGE;
|
||||
delete process.env.OPENCLAW_CONFIG_PATH;
|
||||
delete process.env.ANTHROPIC_BASE_URL;
|
||||
delete process.env.CLOUDSDK_PYTHON;
|
||||
@@ -267,6 +275,10 @@ describe("loadDotEnv", () => {
|
||||
expect(process.env.SAFE_KEY).toBe("from-cwd");
|
||||
expect(process.env.BAR).toBe("from-global");
|
||||
expect(process.env.NODE_OPTIONS).toBeUndefined();
|
||||
expect(process.env.NODE_REDIRECT_WARNINGS).toBeUndefined();
|
||||
expect(process.env.NODE_REPL_EXTERNAL_MODULE).toBeUndefined();
|
||||
expect(process.env.NODE_REPL_HISTORY).toBeUndefined();
|
||||
expect(process.env.NODE_V8_COVERAGE).toBeUndefined();
|
||||
expect(process.env.OPENCLAW_STATE_DIR).toBe(stateDir);
|
||||
expect(process.env.OPENCLAW_CONFIG_PATH).toBeUndefined();
|
||||
expect(process.env.ANTHROPIC_BASE_URL).toBeUndefined();
|
||||
@@ -691,6 +703,10 @@ describe("loadCliDotEnv", () => {
|
||||
"OPENCLAW_CONFIG_PATH=./evil-config.json",
|
||||
`OPENCLAW_BUNDLED_PLUGINS_DIR=${bundledPluginsDir}`,
|
||||
"NODE_OPTIONS=--require ./evil.js",
|
||||
"NODE_REDIRECT_WARNINGS=./warnings.log",
|
||||
"NODE_REPL_EXTERNAL_MODULE=./evil-repl.js",
|
||||
"NODE_REPL_HISTORY=./repl-history",
|
||||
"NODE_V8_COVERAGE=./coverage",
|
||||
"ANTHROPIC_BASE_URL=https://evil.example.com/v1",
|
||||
"UV_PYTHON=./attacker-python",
|
||||
"uv_python=./attacker-python-lower",
|
||||
@@ -703,6 +719,10 @@ describe("loadCliDotEnv", () => {
|
||||
delete process.env.OPENCLAW_CONFIG_PATH;
|
||||
delete process.env.OPENCLAW_BUNDLED_PLUGINS_DIR;
|
||||
delete process.env.NODE_OPTIONS;
|
||||
delete process.env.NODE_REDIRECT_WARNINGS;
|
||||
delete process.env.NODE_REPL_EXTERNAL_MODULE;
|
||||
delete process.env.NODE_REPL_HISTORY;
|
||||
delete process.env.NODE_V8_COVERAGE;
|
||||
delete process.env.ANTHROPIC_BASE_URL;
|
||||
delete process.env.UV_PYTHON;
|
||||
delete process.env.uv_python;
|
||||
@@ -716,6 +736,10 @@ describe("loadCliDotEnv", () => {
|
||||
expect(process.env.OPENCLAW_CONFIG_PATH).toBeUndefined();
|
||||
expect(process.env.OPENCLAW_BUNDLED_PLUGINS_DIR).toBeUndefined();
|
||||
expect(process.env.NODE_OPTIONS).toBeUndefined();
|
||||
expect(process.env.NODE_REDIRECT_WARNINGS).toBeUndefined();
|
||||
expect(process.env.NODE_REPL_EXTERNAL_MODULE).toBeUndefined();
|
||||
expect(process.env.NODE_REPL_HISTORY).toBeUndefined();
|
||||
expect(process.env.NODE_V8_COVERAGE).toBeUndefined();
|
||||
expect(process.env.ANTHROPIC_BASE_URL).toBeUndefined();
|
||||
expect(process.env.UV_PYTHON).toBeUndefined();
|
||||
expect(process.env.uv_python).toBeUndefined();
|
||||
|
||||
@@ -2,6 +2,10 @@
|
||||
"blockedEverywhereKeys": [
|
||||
"NODE_OPTIONS",
|
||||
"NODE_PATH",
|
||||
"NODE_REDIRECT_WARNINGS",
|
||||
"NODE_REPL_EXTERNAL_MODULE",
|
||||
"NODE_REPL_HISTORY",
|
||||
"NODE_V8_COVERAGE",
|
||||
"PYTHONHOME",
|
||||
"PYTHONPATH",
|
||||
"PERL5LIB",
|
||||
|
||||
@@ -67,6 +67,10 @@
|
||||
"MYVIMRC",
|
||||
"NODE_OPTIONS",
|
||||
"NODE_PATH",
|
||||
"NODE_REDIRECT_WARNINGS",
|
||||
"NODE_REPL_EXTERNAL_MODULE",
|
||||
"NODE_REPL_HISTORY",
|
||||
"NODE_V8_COVERAGE",
|
||||
"PACKER_PLUGIN_PATH",
|
||||
"PERL5LIB",
|
||||
"PERL5OPT",
|
||||
@@ -244,5 +248,5 @@
|
||||
"YARN_RC_FILENAME",
|
||||
"ZDOTDIR"
|
||||
],
|
||||
"expectedTotalReportedEntries": 239
|
||||
"expectedTotalReportedEntries": 243
|
||||
}
|
||||
|
||||
@@ -91,7 +91,7 @@ describe("host env reported baseline coverage", () => {
|
||||
baseline.reportedDangerousEverywhereKeys.length +
|
||||
baseline.reportedDangerousOverrideOnlyKeys.length,
|
||||
).toBe(baseline.expectedTotalReportedEntries);
|
||||
expect(baseline.expectedTotalReportedEntries).toBe(239);
|
||||
expect(baseline.expectedTotalReportedEntries).toBe(243);
|
||||
expect(sortUniqueUpper(baseline.reportedDangerousEverywhereKeys)).toEqual(
|
||||
baseline.reportedDangerousEverywhereKeys,
|
||||
);
|
||||
|
||||
@@ -191,6 +191,14 @@ describe("isDangerousHostEnvVarName", () => {
|
||||
expect(isDangerousHostEnvVarName("maven_opts")).toBe(true);
|
||||
expect(isDangerousHostEnvVarName("MAKEFLAGS")).toBe(true);
|
||||
expect(isDangerousHostEnvVarName("makeflags")).toBe(true);
|
||||
expect(isDangerousHostEnvVarName("NODE_REDIRECT_WARNINGS")).toBe(true);
|
||||
expect(isDangerousHostEnvVarName("node_redirect_warnings")).toBe(true);
|
||||
expect(isDangerousHostEnvVarName("NODE_REPL_EXTERNAL_MODULE")).toBe(true);
|
||||
expect(isDangerousHostEnvVarName("node_repl_external_module")).toBe(true);
|
||||
expect(isDangerousHostEnvVarName("NODE_REPL_HISTORY")).toBe(true);
|
||||
expect(isDangerousHostEnvVarName("node_repl_history")).toBe(true);
|
||||
expect(isDangerousHostEnvVarName("NODE_V8_COVERAGE")).toBe(true);
|
||||
expect(isDangerousHostEnvVarName("node_v8_coverage")).toBe(true);
|
||||
expect(isDangerousHostEnvVarName("MFLAGS")).toBe(true);
|
||||
expect(isDangerousHostEnvVarName("mflags")).toBe(true);
|
||||
expect(isDangerousHostEnvVarName("SBT_OPTS")).toBe(true);
|
||||
@@ -328,6 +336,10 @@ describe("sanitizeHostExecEnv", () => {
|
||||
DOCKER_CONTEXT: "trusted-remote",
|
||||
DOCKER_HOST: "tcp://docker.example.test:2376",
|
||||
LD_PRELOAD: "/tmp/pwn.so",
|
||||
NODE_REDIRECT_WARNINGS: "/tmp/node-warnings.log",
|
||||
NODE_REPL_EXTERNAL_MODULE: "/tmp/pwn.js",
|
||||
NODE_REPL_HISTORY: "/tmp/node-repl-history",
|
||||
NODE_V8_COVERAGE: "/tmp/coverage",
|
||||
OK: "1",
|
||||
},
|
||||
});
|
||||
@@ -418,6 +430,10 @@ describe("sanitizeHostExecEnv", () => {
|
||||
CPLUS_INCLUDE_PATH: "/tmp/evil-cpp-headers",
|
||||
OBJC_INCLUDE_PATH: "/tmp/evil-objc-headers",
|
||||
HELM_HOME: "/tmp/override-helm",
|
||||
NODE_REDIRECT_WARNINGS: "/tmp/node-warnings.log",
|
||||
NODE_REPL_EXTERNAL_MODULE: "/tmp/pwn.js",
|
||||
NODE_REPL_HISTORY: "/tmp/node-repl-history",
|
||||
NODE_V8_COVERAGE: "/tmp/coverage",
|
||||
NODE_EXTRA_CA_CERTS: "/tmp/evil-ca.pem",
|
||||
SSL_CERT_FILE: "/tmp/evil-cert.pem",
|
||||
SSL_CERT_DIR: "/tmp/evil-cert-dir",
|
||||
@@ -528,6 +544,10 @@ describe("sanitizeHostExecEnv", () => {
|
||||
expect(env.GOPATH).toBeUndefined();
|
||||
expect(env.CARGO_HOME).toBeUndefined();
|
||||
expect(env.HELM_HOME).toBeUndefined();
|
||||
expect(env.NODE_REDIRECT_WARNINGS).toBeUndefined();
|
||||
expect(env.NODE_REPL_EXTERNAL_MODULE).toBeUndefined();
|
||||
expect(env.NODE_REPL_HISTORY).toBeUndefined();
|
||||
expect(env.NODE_V8_COVERAGE).toBeUndefined();
|
||||
expect(env.PYTHONUSERBASE).toBeUndefined();
|
||||
expect(env.VIRTUAL_ENV).toBeUndefined();
|
||||
expect(env.SAFE).toBe("ok");
|
||||
@@ -982,6 +1002,10 @@ describe("sanitizeHostExecEnvWithDiagnostics", () => {
|
||||
MAKEFLAGS: "--eval=$(shell touch /tmp/pwned)",
|
||||
MFLAGS: "--eval=$(shell touch /tmp/pwned-too)",
|
||||
HELM_HOME: "/tmp/evil-helm",
|
||||
NODE_REDIRECT_WARNINGS: "/tmp/node-warnings.log",
|
||||
NODE_REPL_EXTERNAL_MODULE: "/tmp/pwn.js",
|
||||
NODE_REPL_HISTORY: "/tmp/node-repl-history",
|
||||
NODE_V8_COVERAGE: "/tmp/coverage",
|
||||
PYTHONUSERBASE: "/tmp/evil-python-userbase",
|
||||
RUSTC_WRAPPER: "/tmp/evil-rustc-wrapper",
|
||||
RUSTFLAGS: "-C link-args=-l/tmp/evil.so",
|
||||
@@ -1043,7 +1067,11 @@ describe("sanitizeHostExecEnvWithDiagnostics", () => {
|
||||
"MAKEFLAGS",
|
||||
"MFLAGS",
|
||||
"NODE_EXTRA_CA_CERTS",
|
||||
"NODE_REDIRECT_WARNINGS",
|
||||
"NODE_REPL_EXTERNAL_MODULE",
|
||||
"NODE_REPL_HISTORY",
|
||||
"NODE_TLS_REJECT_UNAUTHORIZED",
|
||||
"NODE_V8_COVERAGE",
|
||||
"OBJC_INCLUDE_PATH",
|
||||
"PATH",
|
||||
"PIP_CONFIG_FILE",
|
||||
@@ -1124,6 +1152,10 @@ describe("sanitizeHostExecEnvWithDiagnostics", () => {
|
||||
expect(result.env.CARGO_HOME).toBeUndefined();
|
||||
expect(result.env.HGRCPATH).toBeUndefined();
|
||||
expect(result.env.HELM_HOME).toBeUndefined();
|
||||
expect(result.env.NODE_REDIRECT_WARNINGS).toBeUndefined();
|
||||
expect(result.env.NODE_REPL_EXTERNAL_MODULE).toBeUndefined();
|
||||
expect(result.env.NODE_REPL_HISTORY).toBeUndefined();
|
||||
expect(result.env.NODE_V8_COVERAGE).toBeUndefined();
|
||||
expect(result.env.HTTPS_PROXY).toBeUndefined();
|
||||
expect(result.env.JAVA_OPTS).toBeUndefined();
|
||||
expect(result.env.MAKEFLAGS).toBeUndefined();
|
||||
|
||||
Reference in New Issue
Block a user