UNPKG

openclaw

Version:

Multi-channel AI gateway with extensible messaging integrations

98 lines (97 loc) 3.66 kB
import { y as resolveStateDir } from "./paths-mvMm5bYV.js"; import { a as normalizeEnvVarKey, n as isDangerousHostEnvOverrideVarName, r as isDangerousHostEnvVarName } from "./host-env-security-RnaFYKhk.js"; import { n as collectConfigServiceEnvVars } from "./config-env-vars-DeC7to2c.js"; import fs from "node:fs"; import path from "node:path"; import dotenv from "dotenv"; //#region src/config/state-dir-dotenv.ts function isBlockedServiceEnvVar(key) { return isDangerousHostEnvVarName(key) || isDangerousHostEnvOverrideVarName(key); } function unwrapMatchingLiteralQuotes(value) { if (value.length < 2) return value; const first = value[0]; const last = value.at(-1); if ((first === `"` || first === `'`) && first === last) return value.slice(1, -1); return value; } /** Returns true when a dotenv value is only a shell reference, not an expanded secret. */ function isUnresolvedShellReference(value) { const candidate = unwrapMatchingLiteralQuotes(value.trim()); return /^\$[A-Z_][A-Z0-9_]*$/.test(candidate) || /^\$\{[A-Z_][A-Z0-9_]*[^}]*\}$/.test(candidate) || /^\$\([^)]*\)$/.test(candidate); } function parseStateDirDotEnvContent(content) { const parsed = dotenv.parse(content); const entries = {}; const skippedShellReferenceKeys = []; for (const [rawKey, value] of Object.entries(parsed)) { if (!value?.trim()) continue; const key = normalizeEnvVarKey(rawKey, { portable: true }); if (!key) continue; if (isBlockedServiceEnvVar(key)) continue; if (isUnresolvedShellReference(value)) { skippedShellReferenceKeys.push(key); continue; } entries[key] = value; } return { entries, skippedShellReferenceKeys }; } /** Reads a specific state directory `.env` as managed service env vars. */ function readStateDirDotEnvVarsFromStateDir(stateDir) { return readStateDirDotEnvFromStateDir(stateDir).entries; } /** * Read and parse the state-dir `.env`, returning both the persisted entries and * the keys that were skipped because they held unresolved shell references. The * skipped keys are surfaced so generated service env files can remove stale * literal references for keys OpenClaw previously managed. */ function readStateDirDotEnvFromStateDir(stateDir) { const dotEnvPath = path.join(stateDir, ".env"); try { return parseStateDirDotEnvContent(fs.readFileSync(dotEnvPath, "utf8")); } catch { return { entries: {}, skippedShellReferenceKeys: [] }; } } /** * Read and parse `~/.openclaw/.env` (or `$OPENCLAW_STATE_DIR/.env`), returning * a filtered record of key-value pairs suitable for a managed service * environment source. */ function readStateDirDotEnvVars(env) { return readStateDirDotEnvVarsFromStateDir(resolveStateDir(env)); } /** Collects durable service env vars from state-dir `.env` and config, preserving each source. */ function collectDurableServiceEnvVarSources(params) { const stateDirDotEnvEnvironment = readStateDirDotEnvVars(params.env); const configEnvironment = collectConfigServiceEnvVars(params.config); return { stateDirDotEnvEnvironment, configEnvironment, durableEnvironment: { ...stateDirDotEnvEnvironment, ...configEnvironment } }; } /** * Durable service env sources survive beyond the invoking shell and are safe to * persist into owner-only gateway service environment sources. * * Precedence: * 1. state-dir `.env` file vars * 2. config service env vars */ function collectDurableServiceEnvVars(params) { return collectDurableServiceEnvVarSources(params).durableEnvironment; } //#endregion export { readStateDirDotEnvFromStateDir as i, collectDurableServiceEnvVars as n, isUnresolvedShellReference as r, collectDurableServiceEnvVarSources as t };