Exec: mark child command env with OPENCLAW_CLI (#41411)
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
import { describe, expect, it } from "vitest";
|
||||
import { OPENCLAW_CLI_ENV_VALUE } from "../infra/openclaw-exec-env.js";
|
||||
import { buildSandboxCreateArgs } from "./sandbox/docker.js";
|
||||
import type { SandboxDockerConfig } from "./sandbox/types.js";
|
||||
|
||||
@@ -113,7 +114,14 @@ describe("buildSandboxCreateArgs", () => {
|
||||
"1.5",
|
||||
]),
|
||||
);
|
||||
expect(args).toEqual(expect.arrayContaining(["--env", "LANG=C.UTF-8"]));
|
||||
expect(args).toEqual(
|
||||
expect.arrayContaining([
|
||||
"--env",
|
||||
"LANG=C.UTF-8",
|
||||
"--env",
|
||||
`OPENCLAW_CLI=${OPENCLAW_CLI_ENV_VALUE}`,
|
||||
]),
|
||||
);
|
||||
|
||||
const ulimitValues: string[] = [];
|
||||
for (let i = 0; i < args.length; i += 1) {
|
||||
|
||||
@@ -162,6 +162,7 @@ export function execDockerRaw(
|
||||
}
|
||||
|
||||
import { formatCliCommand } from "../../cli/command-format.js";
|
||||
import { markOpenClawExecEnv } from "../../infra/openclaw-exec-env.js";
|
||||
import { defaultRuntime } from "../../runtime.js";
|
||||
import { computeSandboxConfigHash } from "./config-hash.js";
|
||||
import { DEFAULT_SANDBOX_IMAGE } from "./constants.js";
|
||||
@@ -365,7 +366,7 @@ export function buildSandboxCreateArgs(params: {
|
||||
if (params.cfg.user) {
|
||||
args.push("--user", params.cfg.user);
|
||||
}
|
||||
const envSanitization = sanitizeEnvVars(params.cfg.env ?? {});
|
||||
const envSanitization = sanitizeEnvVars(markOpenClawExecEnv(params.cfg.env ?? {}));
|
||||
if (envSanitization.blocked.length > 0) {
|
||||
log.warn(`Blocked sensitive environment variables: ${envSanitization.blocked.join(", ")}`);
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@ import { shouldSkipRespawnForArgv } from "./cli/respawn-policy.js";
|
||||
import { normalizeWindowsArgv } from "./cli/windows-argv.js";
|
||||
import { isTruthyEnvValue, normalizeEnv } from "./infra/env.js";
|
||||
import { isMainModule } from "./infra/is-main.js";
|
||||
import { ensureOpenClawExecMarkerOnProcess } from "./infra/openclaw-exec-env.js";
|
||||
import { installProcessWarningFilter } from "./infra/warning-filter.js";
|
||||
import { attachChildProcessBridge } from "./process/child-process-bridge.js";
|
||||
|
||||
@@ -41,6 +42,7 @@ if (
|
||||
// Imported as a dependency — skip all entry-point side effects.
|
||||
} else {
|
||||
process.title = "openclaw";
|
||||
ensureOpenClawExecMarkerOnProcess();
|
||||
installProcessWarningFilter();
|
||||
normalizeEnv();
|
||||
if (!isTruthyEnvValue(process.env.NODE_DISABLE_COMPILE_CACHE)) {
|
||||
|
||||
@@ -10,6 +10,7 @@ import {
|
||||
sanitizeHostExecEnv,
|
||||
sanitizeSystemRunEnvOverrides,
|
||||
} from "./host-env-security.js";
|
||||
import { OPENCLAW_CLI_ENV_VALUE } from "./openclaw-exec-env.js";
|
||||
|
||||
describe("isDangerousHostEnvVarName", () => {
|
||||
it("matches dangerous keys and prefixes case-insensitively", () => {
|
||||
@@ -40,6 +41,7 @@ describe("sanitizeHostExecEnv", () => {
|
||||
});
|
||||
|
||||
expect(env).toEqual({
|
||||
OPENCLAW_CLI: OPENCLAW_CLI_ENV_VALUE,
|
||||
PATH: "/usr/bin:/bin",
|
||||
OK: "1",
|
||||
});
|
||||
@@ -68,6 +70,7 @@ describe("sanitizeHostExecEnv", () => {
|
||||
});
|
||||
|
||||
expect(env.PATH).toBe("/usr/bin:/bin");
|
||||
expect(env.OPENCLAW_CLI).toBe(OPENCLAW_CLI_ENV_VALUE);
|
||||
expect(env.BASH_ENV).toBeUndefined();
|
||||
expect(env.GIT_SSH_COMMAND).toBeUndefined();
|
||||
expect(env.EDITOR).toBeUndefined();
|
||||
@@ -91,6 +94,7 @@ describe("sanitizeHostExecEnv", () => {
|
||||
});
|
||||
|
||||
expect(env.PATH).toBe("/usr/bin:/bin");
|
||||
expect(env.OPENCLAW_CLI).toBe(OPENCLAW_CLI_ENV_VALUE);
|
||||
expect(env.OK).toBe("1");
|
||||
expect(env.SHELLOPTS).toBeUndefined();
|
||||
expect(env.PS4).toBeUndefined();
|
||||
@@ -109,6 +113,7 @@ describe("sanitizeHostExecEnv", () => {
|
||||
});
|
||||
|
||||
expect(env.GOOD_KEY).toBe("ok");
|
||||
expect(env.OPENCLAW_CLI).toBe(OPENCLAW_CLI_ENV_VALUE);
|
||||
expect(env[" BAD KEY"]).toBeUndefined();
|
||||
expect(env["NOT-PORTABLE"]).toBeUndefined();
|
||||
});
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import HOST_ENV_SECURITY_POLICY_JSON from "./host-env-security-policy.json" with { type: "json" };
|
||||
import { markOpenClawExecEnv } from "./openclaw-exec-env.js";
|
||||
|
||||
const PORTABLE_ENV_VAR_KEY = /^[A-Za-z_][A-Za-z0-9_]*$/;
|
||||
|
||||
@@ -101,7 +102,7 @@ export function sanitizeHostExecEnv(params?: {
|
||||
}
|
||||
|
||||
if (!overrides) {
|
||||
return merged;
|
||||
return markOpenClawExecEnv(merged);
|
||||
}
|
||||
|
||||
for (const [rawKey, value] of Object.entries(overrides)) {
|
||||
@@ -124,7 +125,7 @@ export function sanitizeHostExecEnv(params?: {
|
||||
merged[key] = value;
|
||||
}
|
||||
|
||||
return merged;
|
||||
return markOpenClawExecEnv(merged);
|
||||
}
|
||||
|
||||
export function sanitizeSystemRunEnvOverrides(params?: {
|
||||
|
||||
16
src/infra/openclaw-exec-env.ts
Normal file
16
src/infra/openclaw-exec-env.ts
Normal file
@@ -0,0 +1,16 @@
|
||||
export const OPENCLAW_CLI_ENV_VAR = "OPENCLAW_CLI";
|
||||
export const OPENCLAW_CLI_ENV_VALUE = "1";
|
||||
|
||||
export function markOpenClawExecEnv<T extends Record<string, string | undefined>>(env: T): T {
|
||||
return {
|
||||
...env,
|
||||
[OPENCLAW_CLI_ENV_VAR]: OPENCLAW_CLI_ENV_VALUE,
|
||||
};
|
||||
}
|
||||
|
||||
export function ensureOpenClawExecMarkerOnProcess(
|
||||
env: NodeJS.ProcessEnv = process.env,
|
||||
): NodeJS.ProcessEnv {
|
||||
env[OPENCLAW_CLI_ENV_VAR] = OPENCLAW_CLI_ENV_VALUE;
|
||||
return env;
|
||||
}
|
||||
@@ -3,6 +3,7 @@ import { EventEmitter } from "node:events";
|
||||
import fs from "node:fs";
|
||||
import process from "node:process";
|
||||
import { describe, expect, it, vi } from "vitest";
|
||||
import { OPENCLAW_CLI_ENV_VALUE } from "../infra/openclaw-exec-env.js";
|
||||
import { attachChildProcessBridge } from "./child-process-bridge.js";
|
||||
import { resolveCommandEnv, runCommandWithTimeout, shouldSpawnWithShell } from "./exec.js";
|
||||
|
||||
@@ -31,6 +32,7 @@ describe("runCommandWithTimeout", () => {
|
||||
expect(resolved.OPENCLAW_BASE_ENV).toBe("base");
|
||||
expect(resolved.OPENCLAW_TEST_ENV).toBe("ok");
|
||||
expect(resolved.OPENCLAW_TO_REMOVE).toBeUndefined();
|
||||
expect(resolved.OPENCLAW_CLI).toBe(OPENCLAW_CLI_ENV_VALUE);
|
||||
});
|
||||
|
||||
it("suppresses npm fund prompts for npm argv", async () => {
|
||||
|
||||
@@ -4,6 +4,7 @@ import path from "node:path";
|
||||
import process from "node:process";
|
||||
import { promisify } from "node:util";
|
||||
import { danger, shouldLogVerbose } from "../globals.js";
|
||||
import { markOpenClawExecEnv } from "../infra/openclaw-exec-env.js";
|
||||
import { logDebug, logError } from "../logger.js";
|
||||
import { resolveCommandStdio } from "./spawn-utils.js";
|
||||
|
||||
@@ -213,7 +214,7 @@ export function resolveCommandEnv(params: {
|
||||
resolvedEnv.npm_config_fund = "false";
|
||||
}
|
||||
}
|
||||
return resolvedEnv;
|
||||
return markOpenClawExecEnv(resolvedEnv);
|
||||
}
|
||||
|
||||
export async function runCommandWithTimeout(
|
||||
|
||||
Reference in New Issue
Block a user