mirror of
https://github.com/openclaw/openclaw.git
synced 2026-08-25 20:05:46 -06:00
fix: centralize dotenv env cleanup
This commit is contained in:
+24
-34
@@ -12,6 +12,7 @@ import { resolveInstalledPluginIndexPolicyHash } from "../plugins/installed-plug
|
||||
import type { PluginManifestRecord } from "../plugins/manifest-registry.js";
|
||||
import type { PluginMetadataSnapshot } from "../plugins/plugin-metadata-snapshot.types.js";
|
||||
import { listKnownProviderAuthEnvVarNames } from "../secrets/provider-env-vars.js";
|
||||
import { captureFullEnv, deleteTestEnvValue, setTestEnvValue } from "../test-utils/env.js";
|
||||
import { loadDotEnv, loadWorkspaceDotEnvFile } from "./dotenv.js";
|
||||
|
||||
const loggerMocks = vi.hoisted(() => ({
|
||||
@@ -80,7 +81,7 @@ async function writeEnvFile(filePath: string, contents: string) {
|
||||
|
||||
function clearEnv(keys: readonly string[]) {
|
||||
for (const key of keys) {
|
||||
delete process.env[key];
|
||||
deleteTestEnvValue(key);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -91,23 +92,12 @@ function expectEnvUndefined(keys: readonly string[]) {
|
||||
}
|
||||
|
||||
async function withIsolatedEnvAndCwd(run: () => Promise<void>) {
|
||||
const prevEnv = { ...process.env };
|
||||
const envSnapshot = captureFullEnv();
|
||||
try {
|
||||
await run();
|
||||
} finally {
|
||||
vi.restoreAllMocks();
|
||||
for (const key of Object.keys(process.env)) {
|
||||
if (!(key in prevEnv)) {
|
||||
delete process.env[key];
|
||||
}
|
||||
}
|
||||
for (const [key, value] of Object.entries(prevEnv)) {
|
||||
if (value === undefined) {
|
||||
delete process.env[key];
|
||||
} else {
|
||||
process.env[key] = value;
|
||||
}
|
||||
}
|
||||
envSnapshot.restore();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -169,7 +159,7 @@ async function withDotEnvFixture(run: (fixture: DotEnvFixture) => Promise<void>)
|
||||
const base = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-dotenv-test-"));
|
||||
const cwdDir = path.join(base, "cwd");
|
||||
const stateDir = path.join(base, "state");
|
||||
process.env.OPENCLAW_STATE_DIR = stateDir;
|
||||
setTestEnvValue("OPENCLAW_STATE_DIR", stateDir);
|
||||
await fs.mkdir(cwdDir, { recursive: true });
|
||||
await fs.mkdir(stateDir, { recursive: true });
|
||||
await run({ base, cwdDir, stateDir });
|
||||
@@ -228,9 +218,9 @@ describe("loadDotEnv", () => {
|
||||
it("loads the Ubuntu gateway.env compatibility fallback after ~/.openclaw/.env", async () => {
|
||||
await withIsolatedEnvAndCwd(async () => {
|
||||
await withDotEnvFixture(async ({ base, cwdDir }) => {
|
||||
process.env.HOME = base;
|
||||
setTestEnvValue("HOME", base);
|
||||
const defaultStateDir = path.join(base, ".openclaw");
|
||||
process.env.OPENCLAW_STATE_DIR = defaultStateDir;
|
||||
setTestEnvValue("OPENCLAW_STATE_DIR", defaultStateDir);
|
||||
await writeEnvFile(path.join(defaultStateDir, ".env"), "FOO=from-global\n");
|
||||
await writeEnvFile(
|
||||
path.join(base, ".config", "openclaw", "gateway.env"),
|
||||
@@ -259,7 +249,7 @@ describe("loadDotEnv", () => {
|
||||
it("does not warn about dotenv conflicts when the key is already set", async () => {
|
||||
await withIsolatedEnvAndCwd(async () => {
|
||||
await withDotEnvFixture(async ({ base, cwdDir, stateDir }) => {
|
||||
process.env.HOME = base;
|
||||
setTestEnvValue("HOME", base);
|
||||
process.env.FOO = "from-shell";
|
||||
await writeEnvFile(path.join(stateDir, ".env"), "FOO=from-global\n");
|
||||
await writeEnvFile(
|
||||
@@ -314,7 +304,7 @@ describe("loadDotEnv", () => {
|
||||
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;
|
||||
deleteTestEnvValue("OPENCLAW_CONFIG_PATH");
|
||||
delete process.env.ANTHROPIC_BASE_URL;
|
||||
delete process.env.CLOUDSDK_PYTHON;
|
||||
delete process.env.EXAMPLE_API_HOST;
|
||||
@@ -396,9 +386,9 @@ describe("loadDotEnv", () => {
|
||||
].join("\n"),
|
||||
);
|
||||
|
||||
delete process.env.OPENCLAW_STATE_DIR;
|
||||
deleteTestEnvValue("OPENCLAW_STATE_DIR");
|
||||
delete process.env.STATE_DIRECTORY;
|
||||
delete process.env.OPENCLAW_CONFIG_PATH;
|
||||
deleteTestEnvValue("OPENCLAW_CONFIG_PATH");
|
||||
|
||||
loadWorkspaceDotEnvFile(path.join(cwdDir, ".env"), { quiet: true });
|
||||
|
||||
@@ -453,7 +443,7 @@ describe("loadDotEnv", () => {
|
||||
].join("\n"),
|
||||
);
|
||||
|
||||
delete process.env.OPENCLAW_AGENT_DIR;
|
||||
deleteTestEnvValue("OPENCLAW_AGENT_DIR");
|
||||
delete process.env.OPENCLAW_BUNDLED_PLUGINS_DIR;
|
||||
delete process.env.OPENCLAW_OAUTH_DIR;
|
||||
delete process.env.PI_CODING_AGENT_DIR;
|
||||
@@ -548,7 +538,7 @@ describe("loadDotEnv", () => {
|
||||
await withDotEnvFixture(async ({ cwdDir }) => {
|
||||
await writeEnvFile(path.join(cwdDir, ".env"), `${key}=./evil/npm-cli.js\n`);
|
||||
|
||||
delete process.env[key];
|
||||
deleteTestEnvValue(key);
|
||||
|
||||
loadWorkspaceDotEnvFile(path.join(cwdDir, ".env"), { quiet: true });
|
||||
|
||||
@@ -656,7 +646,7 @@ describe("loadCliDotEnv", () => {
|
||||
|
||||
// Delete the fixture-provided value so the blocking must come from
|
||||
// the workspace blocklist, not the "already set" skip.
|
||||
delete process.env.OPENCLAW_STATE_DIR;
|
||||
deleteTestEnvValue("OPENCLAW_STATE_DIR");
|
||||
vi.spyOn(process, "cwd").mockReturnValue(cwdDir);
|
||||
|
||||
loadCliDotEnv({ quiet: true });
|
||||
@@ -669,9 +659,9 @@ describe("loadCliDotEnv", () => {
|
||||
it("loads the gateway.env compatibility fallback during CLI startup", async () => {
|
||||
await withIsolatedEnvAndCwd(async () => {
|
||||
await withDotEnvFixture(async ({ base, cwdDir }) => {
|
||||
process.env.HOME = base;
|
||||
setTestEnvValue("HOME", base);
|
||||
const defaultStateDir = path.join(base, ".openclaw");
|
||||
process.env.OPENCLAW_STATE_DIR = defaultStateDir;
|
||||
setTestEnvValue("OPENCLAW_STATE_DIR", defaultStateDir);
|
||||
await writeEnvFile(path.join(defaultStateDir, ".env"), "FOO=from-global\n");
|
||||
await writeEnvFile(
|
||||
path.join(base, ".config", "openclaw", "gateway.env"),
|
||||
@@ -693,9 +683,9 @@ describe("loadCliDotEnv", () => {
|
||||
it("can defer global dotenv while loading only workspace env", async () => {
|
||||
await withIsolatedEnvAndCwd(async () => {
|
||||
await withDotEnvFixture(async ({ base, cwdDir }) => {
|
||||
process.env.HOME = base;
|
||||
setTestEnvValue("HOME", base);
|
||||
const defaultStateDir = path.join(base, ".openclaw");
|
||||
process.env.OPENCLAW_STATE_DIR = defaultStateDir;
|
||||
setTestEnvValue("OPENCLAW_STATE_DIR", defaultStateDir);
|
||||
await writeEnvFile(path.join(cwdDir, ".env"), "BAZ=from-workspace\n");
|
||||
await writeEnvFile(path.join(defaultStateDir, ".env"), "FOO=from-global\n");
|
||||
await writeEnvFile(
|
||||
@@ -721,8 +711,8 @@ describe("loadCliDotEnv", () => {
|
||||
await withIsolatedEnvAndCwd(async () => {
|
||||
await withDotEnvFixture(async ({ base, cwdDir }) => {
|
||||
const customStateDir = path.join(base, "custom-state");
|
||||
process.env.HOME = base;
|
||||
process.env.OPENCLAW_STATE_DIR = customStateDir;
|
||||
setTestEnvValue("HOME", base);
|
||||
setTestEnvValue("OPENCLAW_STATE_DIR", customStateDir);
|
||||
await writeEnvFile(
|
||||
path.join(base, ".config", "openclaw", "gateway.env"),
|
||||
"FOO=from-gateway\n",
|
||||
@@ -745,8 +735,8 @@ describe("loadCliDotEnv", () => {
|
||||
const base = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-dotenv-legacy-"));
|
||||
const cwdDir = path.join(base, "cwd");
|
||||
const legacyStateDir = path.join(base, ".clawdbot");
|
||||
process.env.HOME = base;
|
||||
delete process.env.OPENCLAW_STATE_DIR;
|
||||
setTestEnvValue("HOME", base);
|
||||
deleteTestEnvValue("OPENCLAW_STATE_DIR");
|
||||
delete process.env.OPENCLAW_TEST_FAST;
|
||||
await fs.mkdir(cwdDir, { recursive: true });
|
||||
await writeEnvFile(path.join(legacyStateDir, ".env"), "LEGACY_ONLY=from-legacy\n");
|
||||
@@ -800,7 +790,7 @@ describe("loadCliDotEnv", () => {
|
||||
|
||||
vi.spyOn(process, "cwd").mockReturnValue(cwdDir);
|
||||
delete process.env.SAFE_KEY;
|
||||
delete process.env.OPENCLAW_CONFIG_PATH;
|
||||
deleteTestEnvValue("OPENCLAW_CONFIG_PATH");
|
||||
delete process.env.OPENCLAW_BUNDLED_PLUGINS_DIR;
|
||||
delete process.env.NODE_OPTIONS;
|
||||
delete process.env.NODE_REDIRECT_WARNINGS;
|
||||
@@ -970,7 +960,7 @@ describe("workspace .env blocklist completeness", () => {
|
||||
);
|
||||
|
||||
for (const key of runtimeControlKeys) {
|
||||
delete process.env[key];
|
||||
deleteTestEnvValue(key);
|
||||
}
|
||||
|
||||
loadWorkspaceDotEnvFile(path.join(cwdDir, ".env"), { quiet: true });
|
||||
|
||||
Reference in New Issue
Block a user