@agent-vm/openclaw-gateway 0.0.94 → 0.0.96

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","names":[],"sources":["../src/openclaw-lifecycle.ts"],"mappings":";;;cAiiBa,iBAAA,EAAmB,gBAAA"}
1
+ {"version":3,"file":"index.d.ts","names":[],"sources":["../src/openclaw-lifecycle.ts"],"mappings":";;;cAmrBa,iBAAA,EAAmB,gBAAA"}
package/dist/index.js CHANGED
@@ -1,7 +1,9 @@
1
- import { chmod, mkdir, readFile } from "node:fs/promises";
1
+ import { randomUUID } from "node:crypto";
2
+ import { chmod, lstat, mkdir, readFile, rm } from "node:fs/promises";
2
3
  import path from "node:path";
3
4
  import { FORCE_IPV4_EGRESS_NODE_OPTIONS, buildGatewaySessionLabel, composeNodeOptions, controllerVmHost, gatewayVmAllowedHosts, mergeRuntimeGatewaySecrets, splitResolvedGatewaySecrets } from "@agent-vm/gateway-interface";
4
5
  import { writeFileAtomically } from "@agent-vm/gondolin-adapter";
6
+ import { redactOnePasswordReferences } from "@agent-vm/secret-management";
5
7
  //#region src/openclaw-lifecycle.ts
6
8
  const effectiveOpenClawConfigFileName = "effective-openclaw.json";
7
9
  const effectiveOpenClawConfigVmPath = `/home/openclaw/.openclaw/state/${effectiveOpenClawConfigFileName}`;
@@ -68,6 +70,19 @@ chmod 644 ${openClawShellEnvFilePath} && ` + secretsFileCommand + `chmod 600 ${o
68
70
  function getEffectiveOpenClawConfigHostPath(zone) {
69
71
  return path.join(zone.gateway.stateDir, effectiveOpenClawConfigFileName);
70
72
  }
73
+ async function assertEffectiveConfigPathWritable(zone, content) {
74
+ const effectiveConfigPath = getEffectiveOpenClawConfigHostPath(zone);
75
+ if ((await lstat(effectiveConfigPath).catch((error) => {
76
+ if (isObjectRecord(error) && error.code === "ENOENT") return;
77
+ throw error;
78
+ }))?.isDirectory()) throw new Error(`Effective OpenClaw config path '${effectiveConfigPath}' is a directory.`);
79
+ const preflightPath = path.join(zone.gateway.stateDir, `.agent-vm-effective-openclaw-preflight-${process.pid}-${randomUUID()}.json`);
80
+ try {
81
+ await writeFileAtomically(preflightPath, content, { mode: 384 });
82
+ } finally {
83
+ await rm(preflightPath, { force: true });
84
+ }
85
+ }
71
86
  function shellQuote(value) {
72
87
  return `'${value.replace(/'/gu, `'\\''`)}'`;
73
88
  }
@@ -128,11 +143,14 @@ function toSecretRef(secret) {
128
143
  function describeSecretReference(secret) {
129
144
  switch (secret.source) {
130
145
  case "environment": return secret.envVar;
131
- case "1password": return secret.ref;
146
+ case "1password": return redactOnePasswordReferences(secret.ref);
132
147
  case "config": return "config value";
133
148
  default: throw new Error(`Unsupported secret source: ${JSON.stringify(secret)}`);
134
149
  }
135
150
  }
151
+ function formatSafeOpenClawErrorMessage(error) {
152
+ return redactOnePasswordReferences(error instanceof Error ? error.message : String(error));
153
+ }
136
154
  function buildEffectiveSecretsConfig(parsedBaseConfig) {
137
155
  const existingSecretsConfig = isObjectRecord(parsedBaseConfig.secrets) ? parsedBaseConfig.secrets : {};
138
156
  const existingProvidersConfig = isObjectRecord(existingSecretsConfig.providers) ? existingSecretsConfig.providers : {};
@@ -188,37 +206,74 @@ function buildEffectiveLoggingConfig(parsedBaseConfig) {
188
206
  };
189
207
  }
190
208
  async function writeAuthProfilesIfConfigured(zone, secretResolver) {
209
+ const resolvedAuthProfiles = await resolveAuthProfilesIfConfigured(zone, secretResolver);
210
+ const writeErrors = (await Promise.allSettled(resolvedAuthProfiles.map(async ({ agentId, authProfiles }) => {
211
+ const authProfilesDirectory = path.join(zone.gateway.stateDir, "agents", agentId, "agent");
212
+ await mkdir(authProfilesDirectory, {
213
+ recursive: true,
214
+ mode: 448
215
+ });
216
+ await chmod(authProfilesDirectory, 448);
217
+ await writeFileAtomically(path.join(authProfilesDirectory, "auth-profiles.json"), authProfiles, { mode: 384 });
218
+ }))).filter((result) => result.status === "rejected").map((result) => result.reason instanceof Error ? result.reason : new Error(String(result.reason)));
219
+ if (writeErrors.length > 0) throw new AggregateError(writeErrors, `Failed to write ${String(writeErrors.length)} OpenClaw auth profile file(s) for zone '${zone.id}'.`);
220
+ }
221
+ async function assertAuthProfilePathWritable(zone, agentId) {
222
+ const authProfilesDirectory = path.join(zone.gateway.stateDir, "agents", agentId, "agent");
223
+ const authProfilesPath = path.join(authProfilesDirectory, "auth-profiles.json");
224
+ if ((await lstat(authProfilesPath).catch((error) => {
225
+ if (isObjectRecord(error) && error.code === "ENOENT") return;
226
+ throw error;
227
+ }))?.isDirectory()) throw new Error(`OpenClaw auth profiles path '${authProfilesPath}' is a directory.`);
228
+ const preflightPath = path.join(authProfilesDirectory, `.agent-vm-auth-profiles-preflight-${process.pid}-${randomUUID()}.json`);
229
+ try {
230
+ await mkdir(authProfilesDirectory, {
231
+ recursive: true,
232
+ mode: 448
233
+ });
234
+ await chmod(authProfilesDirectory, 448);
235
+ await writeFileAtomically(preflightPath, "{}\n", { mode: 384 });
236
+ } finally {
237
+ await rm(preflightPath, { force: true });
238
+ }
239
+ }
240
+ async function preflightAuthProfilesIfConfigured(zone, secretResolver) {
241
+ const resolvedAuthProfiles = await resolveAuthProfilesIfConfigured(zone, secretResolver);
242
+ const writeErrors = (await Promise.allSettled(resolvedAuthProfiles.map(async ({ agentId }) => {
243
+ await assertAuthProfilePathWritable(zone, agentId);
244
+ }))).filter((result) => result.status === "rejected").map((result) => result.reason instanceof Error ? result.reason : new Error(String(result.reason)));
245
+ if (writeErrors.length > 0) throw new AggregateError(writeErrors, `Failed to preflight ${String(writeErrors.length)} OpenClaw auth profile file write(s) for zone '${zone.id}'.`);
246
+ }
247
+ async function resolveAuthProfilesIfConfigured(zone, secretResolver) {
191
248
  const authProfilesByAgent = {
192
249
  ...zone.gateway.authProfilesRef ? { main: zone.gateway.authProfilesRef } : {},
193
250
  ...zone.gateway.type === "openclaw" ? zone.gateway.authProfilesByAgent ?? {} : {}
194
251
  };
195
- const writeErrors = (await Promise.allSettled(Object.entries(authProfilesByAgent).map(async ([agentId, authProfilesSecretCandidate]) => {
252
+ const resolveResults = await Promise.allSettled(Object.entries(authProfilesByAgent).map(async ([agentId, authProfilesSecretCandidate]) => {
196
253
  if (!isSourceAwareSecretReference(authProfilesSecretCandidate)) throw new Error(`Zone '${zone.id}' has an invalid auth profile shape for agent '${agentId}'.`);
197
254
  const authProfilesSecret = authProfilesSecretCandidate;
198
255
  try {
199
- const authProfilesDirectory = path.join(zone.gateway.stateDir, "agents", agentId, "agent");
200
- await mkdir(authProfilesDirectory, {
201
- recursive: true,
202
- mode: 448
203
- });
204
- await chmod(authProfilesDirectory, 448);
205
- const authProfiles = await secretResolver.resolve(toSecretRef(authProfilesSecret));
206
- await writeFileAtomically(path.join(authProfilesDirectory, "auth-profiles.json"), authProfiles, { mode: 384 });
256
+ return {
257
+ agentId,
258
+ authProfiles: await secretResolver.resolve(toSecretRef(authProfilesSecret))
259
+ };
207
260
  } catch (error) {
208
- const message = error instanceof Error ? error.message : String(error);
209
- throw new Error(`Failed to write OpenClaw auth profiles for zone '${zone.id}' agent '${agentId}' from '${describeSecretReference(authProfilesSecret)}': ${message}`, { cause: error });
261
+ const message = formatSafeOpenClawErrorMessage(error);
262
+ throw new Error(`Failed to resolve OpenClaw auth profiles for zone '${zone.id}' agent '${agentId}' from '${describeSecretReference(authProfilesSecret)}': ${message}`, { cause: error });
210
263
  }
211
- }))).filter((result) => result.status === "rejected").map((result) => result.reason instanceof Error ? result.reason : new Error(String(result.reason)));
212
- if (writeErrors.length > 0) throw new AggregateError(writeErrors, `Failed to write ${String(writeErrors.length)} OpenClaw auth profile file(s) for zone '${zone.id}'.`);
264
+ }));
265
+ const resolveErrors = resolveResults.filter((result) => result.status === "rejected").map((result) => result.reason instanceof Error ? result.reason : new Error(String(result.reason)));
266
+ if (resolveErrors.length > 0) throw new AggregateError(resolveErrors, `Failed to resolve ${String(resolveErrors.length)} OpenClaw auth profile secret(s) for zone '${zone.id}'.`);
267
+ return resolveResults.filter((result) => result.status === "fulfilled").map((result) => result.value);
213
268
  }
214
- async function writeEffectiveOpenClawConfig(zone) {
269
+ async function buildEffectiveOpenClawConfigContent(zone) {
215
270
  if (zone.gateway.type !== "openclaw") throw new Error(`OpenClaw lifecycle cannot build gateway type '${zone.gateway.type}'.`);
216
271
  const gatewayTokenSecretName = zone.gateway.controlAuth.secret;
217
272
  const gatewayTokenSecret = zone.secrets[gatewayTokenSecretName];
218
- if (!gatewayTokenSecret) throw new Error(`Zone '${zone.id}' secret '${gatewayTokenSecretName}' is missing. Add an explicit 1Password or environment reference such as 'op://agent-vm/${zone.id}-gateway-auth/password'.`);
273
+ if (!gatewayTokenSecret) throw new Error(`Zone '${zone.id}' secret '${gatewayTokenSecretName}' is missing. Add an explicit 1Password or environment reference for the gateway token.`);
219
274
  if (!isSourceAwareSecretReference(gatewayTokenSecret)) throw new Error(`Zone '${zone.id}' secret '${gatewayTokenSecretName}' has an invalid shape.`);
220
275
  try {
221
- if (gatewayTokenSecret.source === "1password" && !gatewayTokenSecret.ref) throw new Error(`Zone '${zone.id}' secret '${gatewayTokenSecretName}' is missing 'ref'. Add an explicit 1Password reference such as 'op://agent-vm/${zone.id}-gateway-auth/password'.`);
276
+ if (gatewayTokenSecret.source === "1password" && !gatewayTokenSecret.ref) throw new Error(`Zone '${zone.id}' secret '${gatewayTokenSecretName}' is missing 'ref'. Add an explicit 1Password reference for the gateway token.`);
222
277
  if (gatewayTokenSecret.source === "environment" && !gatewayTokenSecret.envVar) throw new Error(`Zone '${zone.id}' secret '${gatewayTokenSecretName}' is missing 'envVar'. Add an explicit environment variable name.`);
223
278
  const openClawGatewayTokenSecretRef = {
224
279
  id: gatewayTokenSecretName,
@@ -263,16 +318,39 @@ async function writeEffectiveOpenClawConfig(zone) {
263
318
  plugins: buildEffectivePluginsConfig(parsedBaseConfig, runtimePluginConfigs),
264
319
  secrets: buildEffectiveSecretsConfig(parsedBaseConfig)
265
320
  };
321
+ return `${JSON.stringify(effectiveConfig, null, 2)}\n`;
322
+ } catch (error) {
323
+ const message = formatSafeOpenClawErrorMessage(error);
324
+ throw new Error(`Failed to build effective OpenClaw config for zone '${zone.id}' from '${zone.gateway.config}' using secret '${describeSecretReference(gatewayTokenSecret)}': ${message}`, { cause: error });
325
+ }
326
+ }
327
+ async function writeEffectiveOpenClawConfig(zone) {
328
+ const content = await buildEffectiveOpenClawConfigContent(zone);
329
+ try {
266
330
  const effectiveConfigPath = getEffectiveOpenClawConfigHostPath(zone);
267
331
  await mkdir(zone.gateway.stateDir, {
268
332
  recursive: true,
269
333
  mode: 448
270
334
  });
271
335
  await chmod(zone.gateway.stateDir, 448);
272
- await writeFileAtomically(effectiveConfigPath, `${JSON.stringify(effectiveConfig, null, 2)}\n`, { mode: 384 });
336
+ await writeFileAtomically(effectiveConfigPath, content, { mode: 384 });
337
+ } catch (error) {
338
+ const message = error instanceof Error ? error.message : String(error);
339
+ throw new Error(`Failed to write effective OpenClaw config for zone '${zone.id}': ${message}`, { cause: error });
340
+ }
341
+ }
342
+ async function preflightEffectiveOpenClawConfig(zone) {
343
+ const content = await buildEffectiveOpenClawConfigContent(zone);
344
+ try {
345
+ await mkdir(zone.gateway.stateDir, {
346
+ recursive: true,
347
+ mode: 448
348
+ });
349
+ await chmod(zone.gateway.stateDir, 448);
350
+ await assertEffectiveConfigPathWritable(zone, content);
273
351
  } catch (error) {
274
352
  const message = error instanceof Error ? error.message : String(error);
275
- throw new Error(`Failed to write effective OpenClaw config for zone '${zone.id}' from '${zone.gateway.config}' using secret '${describeSecretReference(gatewayTokenSecret)}': ${message}`, { cause: error });
353
+ throw new Error(`Failed to preflight effective OpenClaw config for zone '${zone.id}': ${message}`, { cause: error });
276
354
  }
277
355
  }
278
356
  const openclawLifecycle = {
@@ -353,6 +431,11 @@ const openclawLifecycle = {
353
431
  port: 18789,
354
432
  path: "/readyz"
355
433
  },
434
+ serviceHealthCheck: {
435
+ type: "http",
436
+ port: 18789,
437
+ path: "/health"
438
+ },
356
439
  guestListenPort: 18789,
357
440
  logPath: openClawGatewayBootLogFileVmPath
358
441
  };
@@ -360,6 +443,10 @@ const openclawLifecycle = {
360
443
  async prepareHostState(zone, secretResolver) {
361
444
  await writeEffectiveOpenClawConfig(zone);
362
445
  await writeAuthProfilesIfConfigured(zone, secretResolver);
446
+ },
447
+ async preflightHostState(zone, secretResolver) {
448
+ await preflightEffectiveOpenClawConfig(zone);
449
+ await preflightAuthProfilesIfConfigured(zone, secretResolver);
363
450
  }
364
451
  };
365
452
  //#endregion
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":["exhaustiveCheck","buildGatewaySessionLabelValue"],"sources":["../src/openclaw-lifecycle.ts"],"sourcesContent":["import { chmod, mkdir, readFile } from 'node:fs/promises';\nimport path from 'node:path';\n\nimport type {\n\tBuildGatewayVmSpecOptions,\n\tGatewayLifecycle,\n\tGatewayProcessSpec,\n\tGatewayZoneConfig,\n\tGatewayVmSpec,\n\tSplitResolvedGatewaySecretsResult,\n} from '@agent-vm/gateway-interface';\nimport {\n\tbuildGatewaySessionLabel as buildGatewaySessionLabelValue,\n\tcomposeNodeOptions,\n\tcontrollerVmHost,\n\tFORCE_IPV4_EGRESS_NODE_OPTIONS,\n\tgatewayVmAllowedHosts,\n\tmergeRuntimeGatewaySecrets,\n\tsplitResolvedGatewaySecrets,\n} from '@agent-vm/gateway-interface';\nimport { writeFileAtomically } from '@agent-vm/gondolin-adapter';\nimport type { SecretRef, SecretResolver } from '@agent-vm/secret-management';\n\nconst effectiveOpenClawConfigFileName = 'effective-openclaw.json';\nconst effectiveOpenClawConfigVmPath = `/home/openclaw/.openclaw/state/${effectiveOpenClawConfigFileName}`;\nconst openClawStateDirVmPath = '/home/openclaw/.openclaw/state';\nconst openClawCacheDirVmPath = '/home/openclaw/.openclaw/cache';\nconst openClawZoneFilesDirVmPath = '/zone';\nconst agentVmLogsDirVmPath = '/agent-vm/logs';\nconst openClawRuntimeLogFileVmPath = `${agentVmLogsDirVmPath}/openclaw-YYYY-MM-DD.log`;\nconst openClawGatewayBootLogFileVmPath = `${agentVmLogsDirVmPath}/gateway-boot-latest.log`;\nconst openClawShellEnvFilePath = '/etc/profile.d/openclaw-env.sh';\nconst openClawRuntimeSecretsEnvFilePath = '/run/openclaw/secrets.env';\nconst openClawGatewayTokenEnvFilePath = '/run/openclaw/gateway-token.env';\nconst openClawCommandVmPath = '/usr/local/bin/openclaw';\nconst openClawGatewayGuestPath =\n\t'/pnpm:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin';\n\ninterface OpenClawSecretRef {\n\treadonly id: string;\n\treadonly provider: string;\n\treadonly source: 'env';\n}\n\nfunction isObjectRecord(value: unknown): value is Record<string, unknown> {\n\treturn typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n\nfunction buildGatewayTcpHosts(\n\tzone: GatewayZoneConfig,\n\tcontrollerPort: number,\n\ttcpPool: { readonly basePort: number; readonly size: number },\n): Record<string, string> {\n\tconst tcpHosts: Record<string, string> = {\n\t\t[`${controllerVmHost}:18800`]: `127.0.0.1:${controllerPort}`,\n\t};\n\n\tfor (let slot = 0; slot < tcpPool.size; slot += 1) {\n\t\ttcpHosts[`tool-${slot}.vm.host:22`] = `127.0.0.1:${tcpPool.basePort + slot}`;\n\t}\n\n\tfor (const websocketHost of zone.websocketBypass) {\n\t\ttcpHosts[websocketHost] = websocketHost;\n\t}\n\n\treturn tcpHosts;\n}\n\nfunction buildOpenClawBootstrapCommand(\n\tzone: GatewayZoneConfig,\n\tresolvedSecrets: Record<string, string>,\n): string {\n\tif (zone.gateway.type !== 'openclaw') {\n\t\tthrow new Error(`OpenClaw lifecycle cannot build gateway type '${zone.gateway.type}'.`);\n\t}\n\tconst { environmentSecrets } = mergeRuntimeGatewaySecrets(\n\t\tsplitAllowedOpenClawGatewaySecrets(zone, resolvedSecrets, 'openclaw-bootstrap-raw-env-secrets'),\n\t\t{\n\t\t\tlogPrefix: 'openclaw-bootstrap-runtime-secrets',\n\t\t\truntimeEnvironment: zone.runtimeEnvironment,\n\t\t\truntimeMediatedSecrets: zone.runtimeMediatedSecrets,\n\t\t},\n\t);\n\tassertAllowedOpenClawEnvironmentSecrets(\n\t\tzone,\n\t\tenvironmentSecrets,\n\t\t'openclaw-bootstrap-runtime-raw-env-secrets',\n\t);\n\tconst environmentLines = [\n\t\t'export OPENCLAW_HOME=/home/openclaw',\n\t\t`export OPENCLAW_CONFIG_PATH=${effectiveOpenClawConfigVmPath}`,\n\t\t`export OPENCLAW_STATE_DIR=${openClawStateDirVmPath}`,\n\t\t'export PNPM_HOME=/pnpm',\n\t\t'export PATH=/pnpm:$PATH',\n\t\t'export TMPDIR=/work/tmp',\n\t\t'export TMP=/work/tmp',\n\t\t'export TEMP=/work/tmp',\n\t\t'export npm_config_cache=/work/cache/npm',\n\t\t'export pnpm_config_store_dir=/work/cache/pnpm/store',\n\t\t'export PIP_CACHE_DIR=/work/cache/pip',\n\t\t'export UV_CACHE_DIR=/work/cache/uv',\n\t\t'export NODE_EXTRA_CA_CERTS=/run/gondolin/ca-certificates.crt',\n\t\t// Prepend each forced IPv4-preference flag only when it is not\n\t\t// already present. The VM env normally carries these flags\n\t\t// already; the profile keeps interactive shells safe without\n\t\t// duplicating the boot-log value.\n\t\t...FORCE_IPV4_EGRESS_NODE_OPTIONS.split(' ').map(\n\t\t\t(nodeOptionFlag) =>\n\t\t\t\t`case \" \\${NODE_OPTIONS:-} \" in *\" ${nodeOptionFlag} \"*) ;; *) export NODE_OPTIONS=\"${nodeOptionFlag}\\${NODE_OPTIONS:+ \\${NODE_OPTIONS}}\";; esac`,\n\t\t),\n\t];\n\tconst secretEnvironmentNames = Object.entries({\n\t\t...environmentSecrets,\n\t\t...zone.runtimeEnvironment,\n\t}).map(([secretName, secretValue]) => {\n\t\tassertShellSafeEnvName(secretName);\n\t\tassertShellProfileSafeSecretValue(secretName, secretValue);\n\t\treturn secretName;\n\t});\n\tconst secretsFileCommand =\n\t\tsecretEnvironmentNames.length === 0\n\t\t\t? `: > ${openClawRuntimeSecretsEnvFilePath} && `\n\t\t\t: `{ ${secretEnvironmentNames.map(runtimeSecretLiteralExportCommand).join('; ')}; } > ${openClawRuntimeSecretsEnvFilePath} && `;\n\tconst gatewayTokenSecretName = zone.gateway.controlAuth.secret;\n\tconst gatewayTokenFileCommand = secretEnvironmentNames.includes(gatewayTokenSecretName)\n\t\t? `{ ${runtimeSecretLiteralExportCommand(gatewayTokenSecretName)}; } > ${openClawGatewayTokenEnvFilePath} && `\n\t\t: `: > ${openClawGatewayTokenEnvFilePath} && `;\n\tconst sshConfigLines = ['Host tool-*.vm.host', ' AddressFamily inet'];\n\tconst sshConfigCommand =\n\t\t`mkdir -p /root/.ssh /home/openclaw/.ssh && ` +\n\t\t`printf '%s\\\\n' ${sshConfigLines.map((line) => shellQuote(line)).join(' ')} > /root/.ssh/config && ` +\n\t\t'cp /root/.ssh/config /home/openclaw/.ssh/config && ' +\n\t\t'chown -R openclaw:openclaw /home/openclaw/.ssh && ' +\n\t\t'chmod 700 /root/.ssh /home/openclaw/.ssh && ' +\n\t\t'chmod 600 /root/.ssh/config /home/openclaw/.ssh/config && ';\n\n\treturn (\n\t\t`mkdir -p /root /etc/profile.d /run/openclaw /work/tmp /work/cache/npm /work/cache/pnpm/store /work/cache/pip /work/cache/uv && chown -R openclaw:openclaw /work && cat > ${openClawShellEnvFilePath} << 'ENVEOF'\\n` +\n\t\tenvironmentLines.join('\\n') +\n\t\t'\\nENVEOF\\n' +\n\t\t`chmod 644 ${openClawShellEnvFilePath} && ` +\n\t\tsecretsFileCommand +\n\t\t`chmod 600 ${openClawRuntimeSecretsEnvFilePath} && ` +\n\t\tgatewayTokenFileCommand +\n\t\t`chmod 600 ${openClawGatewayTokenEnvFilePath} && ` +\n\t\tsshConfigCommand +\n\t\t'touch /root/.bashrc && ' +\n\t\t`grep -qxF 'source ${openClawShellEnvFilePath}' /root/.bashrc || echo 'source ${openClawShellEnvFilePath}' >> /root/.bashrc && ` +\n\t\t'touch /root/.bash_profile && ' +\n\t\t\"grep -qxF 'source /root/.bashrc' /root/.bash_profile || echo 'source /root/.bashrc' >> /root/.bash_profile\"\n\t);\n}\n\nfunction getEffectiveOpenClawConfigHostPath(zone: GatewayZoneConfig): string {\n\treturn path.join(zone.gateway.stateDir, effectiveOpenClawConfigFileName);\n}\n\nfunction shellQuote(value: string): string {\n\treturn `'${value.replace(/'/gu, `'\\\\''`)}'`;\n}\n\nfunction includesShellUnsafeControlByte(value: string): boolean {\n\tfor (const character of value) {\n\t\tconst codePoint = character.codePointAt(0);\n\t\tif (codePoint !== undefined && (codePoint <= 0x1f || codePoint === 0x7f)) {\n\t\t\treturn true;\n\t\t}\n\t}\n\treturn false;\n}\n\nfunction assertShellSafeEnvName(secretName: string): void {\n\tif (!/^[_A-Za-z][_0-9A-Za-z]*$/u.test(secretName)) {\n\t\tthrow new Error(\n\t\t\t`OpenClaw env-injected gateway secret '${secretName}' must be a shell-safe environment variable name.`,\n\t\t);\n\t}\n}\n\nfunction assertShellProfileSafeSecretValue(secretName: string, value: string): void {\n\tif (includesShellUnsafeControlByte(value)) {\n\t\tthrow new Error(\n\t\t\t`OpenClaw env-injected gateway secret '${secretName}' must be a single-line value without control bytes. Use http-mediation for secrets that require structured transport.`,\n\t\t);\n\t}\n}\n\nfunction runtimeSecretLiteralExportCommand(secretName: string): string {\n\tconst runtimeSecretValue = `\"\\${${secretName}?missing runtime secret ${secretName}}\"`;\n\treturn `secret_value=${runtimeSecretValue} && escaped_secret_value=\"$(printf '%s' \"$secret_value\" | sed 's/[\"\\\\\\\\$\\`]/\\\\\\\\&/g')\" && printf 'export ${secretName}=\"%s\"\\\\n' \"$escaped_secret_value\"`;\n}\n\nfunction assertAllowedOpenClawEnvironmentSecrets(\n\tzone: GatewayZoneConfig,\n\tenvironmentSecrets: Readonly<Record<string, string>>,\n\tlogPrefix: string,\n): void {\n\tif (zone.gateway.type !== 'openclaw') {\n\t\tthrow new Error(`OpenClaw lifecycle cannot build gateway type '${zone.gateway.type}'.`);\n\t}\n\tconst allowedRawEnvSecrets = new Set([\n\t\tzone.gateway.controlAuth.secret,\n\t\t...(zone.gateway.rawEnvSecrets ?? []),\n\t]);\n\tfor (const secretName of Object.keys(environmentSecrets)) {\n\t\tif (allowedRawEnvSecrets.has(secretName)) {\n\t\t\tcontinue;\n\t\t}\n\t\tthrow new Error(\n\t\t\t`[${logPrefix}] OpenClaw env secret '${secretName}' must be listed in gateway.rawEnvSecrets or use injection 'http-mediation'.`,\n\t\t);\n\t}\n}\n\nfunction splitAllowedOpenClawGatewaySecrets(\n\tzone: GatewayZoneConfig,\n\tresolvedSecrets: Record<string, string>,\n\tlogPrefix: string,\n): SplitResolvedGatewaySecretsResult {\n\tconst splitSecrets = splitResolvedGatewaySecrets(zone, resolvedSecrets);\n\tassertAllowedOpenClawEnvironmentSecrets(zone, splitSecrets.environmentSecrets, logPrefix);\n\treturn splitSecrets;\n}\n\ntype SourceAwareSecretReference =\n\t| {\n\t\t\treadonly source: 'environment';\n\t\t\treadonly envVar: string;\n\t }\n\t| {\n\t\t\treadonly source: '1password';\n\t\t\treadonly ref: string;\n\t }\n\t| {\n\t\t\treadonly source: 'config';\n\t\t\treadonly value: string;\n\t };\n\nfunction isSourceAwareSecretReference(value: unknown): value is SourceAwareSecretReference {\n\tif (typeof value !== 'object' || value === null) {\n\t\treturn false;\n\t}\n\n\tif (!('source' in value) || typeof value.source !== 'string') {\n\t\treturn false;\n\t}\n\n\tif (value.source === 'environment') {\n\t\treturn 'envVar' in value && typeof value.envVar === 'string';\n\t}\n\n\tif (value.source === '1password') {\n\t\treturn 'ref' in value && typeof value.ref === 'string';\n\t}\n\n\tif (value.source === 'config') {\n\t\treturn 'value' in value && typeof value.value === 'string';\n\t}\n\n\treturn false;\n}\n\nfunction toSecretRef(secret: SourceAwareSecretReference): SecretRef {\n\tswitch (secret.source) {\n\t\tcase 'environment':\n\t\t\treturn {\n\t\t\t\tsource: 'environment',\n\t\t\t\tref: secret.envVar,\n\t\t\t};\n\t\tcase '1password':\n\t\t\treturn {\n\t\t\t\tsource: '1password',\n\t\t\t\tref: secret.ref,\n\t\t\t};\n\t\tcase 'config':\n\t\t\treturn {\n\t\t\t\tsource: 'config',\n\t\t\t\tvalue: secret.value,\n\t\t\t};\n\t\tdefault: {\n\t\t\tconst exhaustiveCheck: never = secret;\n\t\t\tthrow new Error(`Unsupported secret source: ${JSON.stringify(exhaustiveCheck)}`);\n\t\t}\n\t}\n}\n\nfunction describeSecretReference(secret: SourceAwareSecretReference): string {\n\tswitch (secret.source) {\n\t\tcase 'environment':\n\t\t\treturn secret.envVar;\n\t\tcase '1password':\n\t\t\treturn secret.ref;\n\t\tcase 'config':\n\t\t\treturn 'config value';\n\t\tdefault: {\n\t\t\tconst exhaustiveCheck: never = secret;\n\t\t\tthrow new Error(`Unsupported secret source: ${JSON.stringify(exhaustiveCheck)}`);\n\t\t}\n\t}\n}\n\nfunction buildEffectiveSecretsConfig(\n\tparsedBaseConfig: Record<string, unknown>,\n): Record<string, unknown> {\n\tconst existingSecretsConfig = isObjectRecord(parsedBaseConfig.secrets)\n\t\t? parsedBaseConfig.secrets\n\t\t: {};\n\tconst existingProvidersConfig = isObjectRecord(existingSecretsConfig.providers)\n\t\t? existingSecretsConfig.providers\n\t\t: {};\n\n\treturn {\n\t\t...existingSecretsConfig,\n\t\tproviders: {\n\t\t\t...existingProvidersConfig,\n\t\t\tdefault: {\n\t\t\t\tsource: 'env',\n\t\t\t},\n\t\t},\n\t};\n}\n\nfunction buildEffectiveMcpPortalPluginConfig(\n\t_existingPluginConfig: Record<string, unknown>,\n\truntimeConfig: Readonly<Record<string, unknown>>,\n): Record<string, unknown> {\n\treturn {\n\t\t...runtimeConfig,\n\t};\n}\n\nfunction buildEffectivePluginsConfig(\n\tparsedBaseConfig: Record<string, unknown>,\n\truntimePluginConfigs: Readonly<Record<string, Readonly<Record<string, unknown>>>> | undefined,\n): Record<string, unknown> {\n\tconst existingPluginsConfig = isObjectRecord(parsedBaseConfig.plugins)\n\t\t? parsedBaseConfig.plugins\n\t\t: {};\n\tconst existingEntriesConfig = isObjectRecord(existingPluginsConfig.entries)\n\t\t? existingPluginsConfig.entries\n\t\t: {};\n\tconst runtimeEntriesConfig = Object.fromEntries(\n\t\tObject.entries(runtimePluginConfigs ?? {}).map(([pluginId, runtimeConfig]) => {\n\t\t\tconst existingEntryConfig = isObjectRecord(existingEntriesConfig[pluginId])\n\t\t\t\t? existingEntriesConfig[pluginId]\n\t\t\t\t: {};\n\t\t\tconst existingPluginConfig = isObjectRecord(existingEntryConfig.config)\n\t\t\t\t? existingEntryConfig.config\n\t\t\t\t: {};\n\t\t\tconst config =\n\t\t\t\tpluginId === 'mcp-portal'\n\t\t\t\t\t? buildEffectiveMcpPortalPluginConfig(existingPluginConfig, runtimeConfig)\n\t\t\t\t\t: {\n\t\t\t\t\t\t\t...existingPluginConfig,\n\t\t\t\t\t\t\t...runtimeConfig,\n\t\t\t\t\t\t};\n\t\t\treturn [\n\t\t\t\tpluginId,\n\t\t\t\t{\n\t\t\t\t\t...existingEntryConfig,\n\t\t\t\t\tconfig,\n\t\t\t\t},\n\t\t\t] as const;\n\t\t}),\n\t);\n\n\treturn {\n\t\t...existingPluginsConfig,\n\t\tentries: {\n\t\t\t...existingEntriesConfig,\n\t\t\t...runtimeEntriesConfig,\n\t\t},\n\t};\n}\n\nfunction buildEffectiveMcpConfig(\n\tparsedBaseConfig: Record<string, unknown>,\n\truntimeMcpServers: Readonly<Record<string, unknown>> | undefined,\n): Record<string, unknown> {\n\tconst existingMcpConfig = isObjectRecord(parsedBaseConfig.mcp) ? parsedBaseConfig.mcp : {};\n\tconst existingServersConfig = isObjectRecord(existingMcpConfig.servers)\n\t\t? existingMcpConfig.servers\n\t\t: {};\n\treturn {\n\t\t...existingMcpConfig,\n\t\tservers: {\n\t\t\t...existingServersConfig,\n\t\t\t...runtimeMcpServers,\n\t\t},\n\t};\n}\n\nfunction buildEffectiveLoggingConfig(\n\tparsedBaseConfig: Record<string, unknown>,\n): Record<string, unknown> {\n\tconst existingLoggingConfig = isObjectRecord(parsedBaseConfig.logging)\n\t\t? parsedBaseConfig.logging\n\t\t: {};\n\n\treturn {\n\t\tfile: openClawRuntimeLogFileVmPath,\n\t\t...existingLoggingConfig,\n\t};\n}\n\nasync function writeAuthProfilesIfConfigured(\n\tzone: GatewayZoneConfig,\n\tsecretResolver: SecretResolver,\n): Promise<void> {\n\tconst authProfilesByAgent = {\n\t\t...(zone.gateway.authProfilesRef ? { main: zone.gateway.authProfilesRef } : {}),\n\t\t...(zone.gateway.type === 'openclaw' ? (zone.gateway.authProfilesByAgent ?? {}) : {}),\n\t};\n\n\tconst writeResults = await Promise.allSettled(\n\t\tObject.entries(authProfilesByAgent).map(async ([agentId, authProfilesSecretCandidate]) => {\n\t\t\tif (!isSourceAwareSecretReference(authProfilesSecretCandidate)) {\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`Zone '${zone.id}' has an invalid auth profile shape for agent '${agentId}'.`,\n\t\t\t\t);\n\t\t\t}\n\t\t\tconst authProfilesSecret = authProfilesSecretCandidate;\n\n\t\t\ttry {\n\t\t\t\tconst authProfilesDirectory = path.join(zone.gateway.stateDir, 'agents', agentId, 'agent');\n\t\t\t\tawait mkdir(authProfilesDirectory, { recursive: true, mode: 0o700 });\n\t\t\t\tawait chmod(authProfilesDirectory, 0o700);\n\t\t\t\tconst authProfiles = await secretResolver.resolve(toSecretRef(authProfilesSecret));\n\t\t\t\tawait writeFileAtomically(\n\t\t\t\t\tpath.join(authProfilesDirectory, 'auth-profiles.json'),\n\t\t\t\t\tauthProfiles,\n\t\t\t\t\t{ mode: 0o600 },\n\t\t\t\t);\n\t\t\t} catch (error) {\n\t\t\t\tconst message = error instanceof Error ? error.message : String(error);\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`Failed to write OpenClaw auth profiles for zone '${zone.id}' agent '${agentId}' from '${describeSecretReference(authProfilesSecret)}': ${message}`,\n\t\t\t\t\t{ cause: error },\n\t\t\t\t);\n\t\t\t}\n\t\t}),\n\t);\n\tconst writeErrors = writeResults\n\t\t.filter((result): result is PromiseRejectedResult => result.status === 'rejected')\n\t\t.map((result) =>\n\t\t\tresult.reason instanceof Error ? result.reason : new Error(String(result.reason)),\n\t\t);\n\tif (writeErrors.length > 0) {\n\t\tthrow new AggregateError(\n\t\t\twriteErrors,\n\t\t\t`Failed to write ${String(writeErrors.length)} OpenClaw auth profile file(s) for zone '${zone.id}'.`,\n\t\t);\n\t}\n}\n\nasync function writeEffectiveOpenClawConfig(zone: GatewayZoneConfig): Promise<void> {\n\tif (zone.gateway.type !== 'openclaw') {\n\t\tthrow new Error(`OpenClaw lifecycle cannot build gateway type '${zone.gateway.type}'.`);\n\t}\n\tconst gatewayTokenSecretName = zone.gateway.controlAuth.secret;\n\tconst gatewayTokenSecret = zone.secrets[gatewayTokenSecretName];\n\tif (!gatewayTokenSecret) {\n\t\tthrow new Error(\n\t\t\t`Zone '${zone.id}' secret '${gatewayTokenSecretName}' is missing. Add an explicit 1Password or environment reference such as 'op://agent-vm/${zone.id}-gateway-auth/password'.`,\n\t\t);\n\t}\n\tif (!isSourceAwareSecretReference(gatewayTokenSecret)) {\n\t\tthrow new Error(`Zone '${zone.id}' secret '${gatewayTokenSecretName}' has an invalid shape.`);\n\t}\n\n\ttry {\n\t\tif (gatewayTokenSecret.source === '1password' && !gatewayTokenSecret.ref) {\n\t\t\tthrow new Error(\n\t\t\t\t`Zone '${zone.id}' secret '${gatewayTokenSecretName}' is missing 'ref'. Add an explicit 1Password reference such as 'op://agent-vm/${zone.id}-gateway-auth/password'.`,\n\t\t\t);\n\t\t}\n\t\tif (gatewayTokenSecret.source === 'environment' && !gatewayTokenSecret.envVar) {\n\t\t\tthrow new Error(\n\t\t\t\t`Zone '${zone.id}' secret '${gatewayTokenSecretName}' is missing 'envVar'. Add an explicit environment variable name.`,\n\t\t\t);\n\t\t}\n\t\tconst openClawGatewayTokenSecretRef: OpenClawSecretRef = {\n\t\t\tid: gatewayTokenSecretName,\n\t\t\tprovider: 'default',\n\t\t\tsource: 'env',\n\t\t};\n\t\tconst rawBaseConfig = await readFile(zone.gateway.config, 'utf8');\n\t\tconst parsedBaseConfig: unknown = JSON.parse(rawBaseConfig);\n\t\tif (!isObjectRecord(parsedBaseConfig)) {\n\t\t\tthrow new Error(`OpenClaw config at '${zone.gateway.config}' must be a JSON object.`);\n\t\t}\n\t\tconst runtimePluginConfigs = {\n\t\t\t...zone.runtimePluginConfigs,\n\t\t\tgondolin: {\n\t\t\t\tcontrollerUrl: `http://${controllerVmHost}:18800`,\n\t\t\t\tgatewayControlLinkMonitor: {\n\t\t\t\t\tbaseIntervalMs: 10_000,\n\t\t\t\t\tenabled: true,\n\t\t\t\t\tmaxIntervalMs: 120_000,\n\t\t\t\t},\n\t\t\t\tzoneId: zone.id,\n\t\t\t\t...(isObjectRecord(zone.runtimePluginConfigs?.gondolin)\n\t\t\t\t\t? zone.runtimePluginConfigs.gondolin\n\t\t\t\t\t: {}),\n\t\t\t},\n\t\t};\n\t\tconst config = isObjectRecord(parsedBaseConfig.gateway) ? parsedBaseConfig.gateway : {};\n\t\tconst existingAuthConfig = isObjectRecord(config.auth) ? config.auth : {};\n\t\tconst effectiveConfig = {\n\t\t\t...parsedBaseConfig,\n\t\t\tlogging: buildEffectiveLoggingConfig(parsedBaseConfig),\n\t\t\tgateway: {\n\t\t\t\t...config,\n\t\t\t\tauth: {\n\t\t\t\t\t...existingAuthConfig,\n\t\t\t\t\tmode: 'token',\n\t\t\t\t\ttoken: openClawGatewayTokenSecretRef,\n\t\t\t\t},\n\t\t\t},\n\t\t\tmeta: {\n\t\t\t\t...(isObjectRecord(parsedBaseConfig.meta) ? parsedBaseConfig.meta : {}),\n\t\t\t\tlastTouchedAt: new Date().toISOString(),\n\t\t\t\tlastTouchedVersion: 'agent-vm',\n\t\t\t},\n\t\t\tmcp: buildEffectiveMcpConfig(parsedBaseConfig, zone.runtimeMcpServers),\n\t\t\tplugins: buildEffectivePluginsConfig(parsedBaseConfig, runtimePluginConfigs),\n\t\t\tsecrets: buildEffectiveSecretsConfig(parsedBaseConfig),\n\t\t};\n\t\tconst effectiveConfigPath = getEffectiveOpenClawConfigHostPath(zone);\n\t\tawait mkdir(zone.gateway.stateDir, { recursive: true, mode: 0o700 });\n\t\tawait chmod(zone.gateway.stateDir, 0o700);\n\t\tawait writeFileAtomically(\n\t\t\teffectiveConfigPath,\n\t\t\t`${JSON.stringify(effectiveConfig, null, 2)}\\n`,\n\t\t\t{ mode: 0o600 },\n\t\t);\n\t} catch (error) {\n\t\tconst message = error instanceof Error ? error.message : String(error);\n\t\tthrow new Error(\n\t\t\t`Failed to write effective OpenClaw config for zone '${zone.id}' from '${zone.gateway.config}' using secret '${describeSecretReference(gatewayTokenSecret)}': ${message}`,\n\t\t\t{ cause: error },\n\t\t);\n\t}\n}\n\nexport const openclawLifecycle: GatewayLifecycle = {\n\tauthConfig: {\n\t\tlistProvidersCommand: 'openclaw models auth list --format plain 2>/dev/null || echo \"\"',\n\t\tbuildLoginCommand: (\n\t\t\tprovider: string,\n\t\t\toptions: {\n\t\t\t\treadonly agentId?: string;\n\t\t\t\treadonly deviceCode?: boolean;\n\t\t\t\treadonly setDefault?: boolean;\n\t\t\t} = {},\n\t\t): string =>\n\t\t\t[\n\t\t\t\t'openclaw models auth',\n\t\t\t\t...(options.agentId ? [`--agent ${shellQuote(options.agentId)}`] : []),\n\t\t\t\t`login --provider ${shellQuote(provider)}`,\n\t\t\t\t...(options.deviceCode === true ? ['--device-code'] : []),\n\t\t\t\t...(options.setDefault === true ? ['--set-default'] : []),\n\t\t\t].join(' '),\n\t},\n\n\tbuildVmSpec({\n\t\tcontrollerPort,\n\t\tgatewayCacheDir,\n\t\tprojectNamespace,\n\t\tresolvedSecrets,\n\t\truntimeDir,\n\t\ttcpPool,\n\t\tzone,\n\t}: BuildGatewayVmSpecOptions): GatewayVmSpec {\n\t\tif (zone.gateway.type !== 'openclaw') {\n\t\t\tthrow new Error(`OpenClaw lifecycle cannot build gateway type '${zone.gateway.type}'.`);\n\t\t}\n\t\tconst configDirectory = path.dirname(path.resolve(zone.gateway.config));\n\t\tconst { environmentSecrets, mediatedSecrets } = mergeRuntimeGatewaySecrets(\n\t\t\tsplitAllowedOpenClawGatewaySecrets(zone, resolvedSecrets, 'openclaw-vm-raw-env-secrets'),\n\t\t\t{\n\t\t\t\tlogPrefix: 'openclaw-vm-runtime-secrets',\n\t\t\t\truntimeEnvironment: zone.runtimeEnvironment,\n\t\t\t\truntimeMediatedSecrets: zone.runtimeMediatedSecrets,\n\t\t\t},\n\t\t);\n\t\tassertAllowedOpenClawEnvironmentSecrets(\n\t\t\tzone,\n\t\t\tenvironmentSecrets,\n\t\t\t'openclaw-vm-runtime-raw-env-secrets',\n\t\t);\n\n\t\treturn {\n\t\t\tallowedHosts: gatewayVmAllowedHosts(zone.egressHosts),\n\t\t\tenvironment: {\n\t\t\t\tHOME: '/home/openclaw',\n\t\t\t\tNODE_EXTRA_CA_CERTS: '/run/gondolin/ca-certificates.crt',\n\t\t\t\tOPENCLAW_CONFIG_PATH: effectiveOpenClawConfigVmPath,\n\t\t\t\tOPENCLAW_HOME: '/home/openclaw',\n\t\t\t\tOPENCLAW_STATE_DIR: openClawStateDirVmPath,\n\t\t\t\tPATH: openClawGatewayGuestPath,\n\t\t\t\tPIP_CACHE_DIR: '/work/cache/pip',\n\t\t\t\tPNPM_HOME: '/pnpm',\n\t\t\t\tTEMP: '/work/tmp',\n\t\t\t\tTMP: '/work/tmp',\n\t\t\t\tTMPDIR: '/work/tmp',\n\t\t\t\tUV_CACHE_DIR: '/work/cache/uv',\n\t\t\t\tnpm_config_cache: '/work/cache/npm',\n\t\t\t\tpnpm_config_store_dir: '/work/cache/pnpm/store',\n\t\t\t\t...environmentSecrets,\n\t\t\t\t// NODE_OPTIONS goes AFTER the spread so a user-supplied\n\t\t\t\t// NODE_OPTIONS in environmentSecrets cannot drop the\n\t\t\t\t// forced IPv4-preference flags. composeNodeOptions\n\t\t\t\t// preserves the user value as additional flags.\n\t\t\t\tNODE_OPTIONS: composeNodeOptions(environmentSecrets.NODE_OPTIONS),\n\t\t\t},\n\t\t\tmediatedSecrets: {\n\t\t\t\t...mediatedSecrets,\n\t\t\t},\n\t\t\trootfsMode: 'cow',\n\t\t\t...(zone.gateway.runtimeRootfsSize\n\t\t\t\t? { runtimeRootfsSize: zone.gateway.runtimeRootfsSize }\n\t\t\t\t: {}),\n\t\t\tsessionLabel: buildGatewaySessionLabelValue(projectNamespace, zone.id),\n\t\t\ttcpHosts: buildGatewayTcpHosts(zone, controllerPort, tcpPool),\n\t\t\tvfsMounts: {\n\t\t\t\t'/home/openclaw/.openclaw/config': {\n\t\t\t\t\thostPath: configDirectory,\n\t\t\t\t\tkind: 'realfs',\n\t\t\t\t},\n\t\t\t\t[openClawCacheDirVmPath]: {\n\t\t\t\t\thostPath: gatewayCacheDir,\n\t\t\t\t\tkind: 'realfs',\n\t\t\t\t},\n\t\t\t\t'/home/openclaw/.openclaw/state': {\n\t\t\t\t\thostPath: zone.gateway.stateDir,\n\t\t\t\t\tkind: 'realfs',\n\t\t\t\t},\n\t\t\t\t[openClawZoneFilesDirVmPath]: {\n\t\t\t\t\thostPath: zone.gateway.zoneFilesDir,\n\t\t\t\t\tkind: 'realfs',\n\t\t\t\t},\n\t\t\t\t[agentVmLogsDirVmPath]: {\n\t\t\t\t\thostPath: path.join(runtimeDir, 'zones', zone.id, 'logs'),\n\t\t\t\t\tkind: 'realfs',\n\t\t\t\t},\n\t\t\t},\n\t\t};\n\t},\n\n\tbuildProcessSpec(\n\t\tzone: GatewayZoneConfig,\n\t\tresolvedSecrets: Record<string, string>,\n\t): GatewayProcessSpec {\n\t\treturn {\n\t\t\tbootstrapCommand: buildOpenClawBootstrapCommand(zone, resolvedSecrets),\n\t\t\t// printf NODE_OPTIONS into the boot log so an env-loss regression\n\t\t\t// (e.g. a future secrets.env or merge change that drops the\n\t\t\t// FORCE_IPV4_EGRESS_NODE_OPTIONS flags) is visible in the log\n\t\t\t// stream without SSHing into the VM. See\n\t\t\t// FORCE_IPV4_EGRESS_NODE_OPTIONS in @agent-vm/gateway-interface.\n\t\t\tstartCommand: `set -a && . ${openClawRuntimeSecretsEnvFilePath} && set +a && { printf 'gateway-boot: NODE_OPTIONS=%s\\\\n' \"$NODE_OPTIONS\" > ${openClawGatewayBootLogFileVmPath}; } && cd /home/openclaw && nohup ${openClawCommandVmPath} gateway --port 18789 >> ${openClawGatewayBootLogFileVmPath} 2>&1 &`,\n\t\t\thealthCheck: {\n\t\t\t\ttype: 'http',\n\t\t\t\tport: 18789,\n\t\t\t\tpath: '/readyz',\n\t\t\t},\n\t\t\tguestListenPort: 18789,\n\t\t\tlogPath: openClawGatewayBootLogFileVmPath,\n\t\t};\n\t},\n\n\tasync prepareHostState(zone: GatewayZoneConfig, secretResolver: SecretResolver): Promise<void> {\n\t\tawait writeEffectiveOpenClawConfig(zone);\n\t\tawait writeAuthProfilesIfConfigured(zone, secretResolver);\n\t},\n};\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","names":["exhaustiveCheck","buildGatewaySessionLabelValue"],"sources":["../src/openclaw-lifecycle.ts"],"sourcesContent":["import { randomUUID } from 'node:crypto';\nimport { chmod, lstat, mkdir, readFile, rm } from 'node:fs/promises';\nimport path from 'node:path';\n\nimport type {\n\tBuildGatewayVmSpecOptions,\n\tGatewayLifecycle,\n\tGatewayProcessSpec,\n\tGatewayZoneConfig,\n\tGatewayVmSpec,\n\tSplitResolvedGatewaySecretsResult,\n} from '@agent-vm/gateway-interface';\nimport {\n\tbuildGatewaySessionLabel as buildGatewaySessionLabelValue,\n\tcomposeNodeOptions,\n\tcontrollerVmHost,\n\tFORCE_IPV4_EGRESS_NODE_OPTIONS,\n\tgatewayVmAllowedHosts,\n\tmergeRuntimeGatewaySecrets,\n\tsplitResolvedGatewaySecrets,\n} from '@agent-vm/gateway-interface';\nimport { writeFileAtomically } from '@agent-vm/gondolin-adapter';\nimport {\n\tredactOnePasswordReferences,\n\ttype SecretRef,\n\ttype SecretResolver,\n} from '@agent-vm/secret-management';\n\nconst effectiveOpenClawConfigFileName = 'effective-openclaw.json';\nconst effectiveOpenClawConfigVmPath = `/home/openclaw/.openclaw/state/${effectiveOpenClawConfigFileName}`;\nconst openClawStateDirVmPath = '/home/openclaw/.openclaw/state';\nconst openClawCacheDirVmPath = '/home/openclaw/.openclaw/cache';\nconst openClawZoneFilesDirVmPath = '/zone';\nconst agentVmLogsDirVmPath = '/agent-vm/logs';\nconst openClawRuntimeLogFileVmPath = `${agentVmLogsDirVmPath}/openclaw-YYYY-MM-DD.log`;\nconst openClawGatewayBootLogFileVmPath = `${agentVmLogsDirVmPath}/gateway-boot-latest.log`;\nconst openClawShellEnvFilePath = '/etc/profile.d/openclaw-env.sh';\nconst openClawRuntimeSecretsEnvFilePath = '/run/openclaw/secrets.env';\nconst openClawGatewayTokenEnvFilePath = '/run/openclaw/gateway-token.env';\nconst openClawCommandVmPath = '/usr/local/bin/openclaw';\nconst openClawGatewayGuestPath =\n\t'/pnpm:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin';\n\ninterface OpenClawSecretRef {\n\treadonly id: string;\n\treadonly provider: string;\n\treadonly source: 'env';\n}\n\nfunction isObjectRecord(value: unknown): value is Record<string, unknown> {\n\treturn typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n\nfunction buildGatewayTcpHosts(\n\tzone: GatewayZoneConfig,\n\tcontrollerPort: number,\n\ttcpPool: { readonly basePort: number; readonly size: number },\n): Record<string, string> {\n\tconst tcpHosts: Record<string, string> = {\n\t\t[`${controllerVmHost}:18800`]: `127.0.0.1:${controllerPort}`,\n\t};\n\n\tfor (let slot = 0; slot < tcpPool.size; slot += 1) {\n\t\ttcpHosts[`tool-${slot}.vm.host:22`] = `127.0.0.1:${tcpPool.basePort + slot}`;\n\t}\n\n\tfor (const websocketHost of zone.websocketBypass) {\n\t\ttcpHosts[websocketHost] = websocketHost;\n\t}\n\n\treturn tcpHosts;\n}\n\nfunction buildOpenClawBootstrapCommand(\n\tzone: GatewayZoneConfig,\n\tresolvedSecrets: Record<string, string>,\n): string {\n\tif (zone.gateway.type !== 'openclaw') {\n\t\tthrow new Error(`OpenClaw lifecycle cannot build gateway type '${zone.gateway.type}'.`);\n\t}\n\tconst { environmentSecrets } = mergeRuntimeGatewaySecrets(\n\t\tsplitAllowedOpenClawGatewaySecrets(zone, resolvedSecrets, 'openclaw-bootstrap-raw-env-secrets'),\n\t\t{\n\t\t\tlogPrefix: 'openclaw-bootstrap-runtime-secrets',\n\t\t\truntimeEnvironment: zone.runtimeEnvironment,\n\t\t\truntimeMediatedSecrets: zone.runtimeMediatedSecrets,\n\t\t},\n\t);\n\tassertAllowedOpenClawEnvironmentSecrets(\n\t\tzone,\n\t\tenvironmentSecrets,\n\t\t'openclaw-bootstrap-runtime-raw-env-secrets',\n\t);\n\tconst environmentLines = [\n\t\t'export OPENCLAW_HOME=/home/openclaw',\n\t\t`export OPENCLAW_CONFIG_PATH=${effectiveOpenClawConfigVmPath}`,\n\t\t`export OPENCLAW_STATE_DIR=${openClawStateDirVmPath}`,\n\t\t'export PNPM_HOME=/pnpm',\n\t\t'export PATH=/pnpm:$PATH',\n\t\t'export TMPDIR=/work/tmp',\n\t\t'export TMP=/work/tmp',\n\t\t'export TEMP=/work/tmp',\n\t\t'export npm_config_cache=/work/cache/npm',\n\t\t'export pnpm_config_store_dir=/work/cache/pnpm/store',\n\t\t'export PIP_CACHE_DIR=/work/cache/pip',\n\t\t'export UV_CACHE_DIR=/work/cache/uv',\n\t\t'export NODE_EXTRA_CA_CERTS=/run/gondolin/ca-certificates.crt',\n\t\t// Prepend each forced IPv4-preference flag only when it is not\n\t\t// already present. The VM env normally carries these flags\n\t\t// already; the profile keeps interactive shells safe without\n\t\t// duplicating the boot-log value.\n\t\t...FORCE_IPV4_EGRESS_NODE_OPTIONS.split(' ').map(\n\t\t\t(nodeOptionFlag) =>\n\t\t\t\t`case \" \\${NODE_OPTIONS:-} \" in *\" ${nodeOptionFlag} \"*) ;; *) export NODE_OPTIONS=\"${nodeOptionFlag}\\${NODE_OPTIONS:+ \\${NODE_OPTIONS}}\";; esac`,\n\t\t),\n\t];\n\tconst secretEnvironmentNames = Object.entries({\n\t\t...environmentSecrets,\n\t\t...zone.runtimeEnvironment,\n\t}).map(([secretName, secretValue]) => {\n\t\tassertShellSafeEnvName(secretName);\n\t\tassertShellProfileSafeSecretValue(secretName, secretValue);\n\t\treturn secretName;\n\t});\n\tconst secretsFileCommand =\n\t\tsecretEnvironmentNames.length === 0\n\t\t\t? `: > ${openClawRuntimeSecretsEnvFilePath} && `\n\t\t\t: `{ ${secretEnvironmentNames.map(runtimeSecretLiteralExportCommand).join('; ')}; } > ${openClawRuntimeSecretsEnvFilePath} && `;\n\tconst gatewayTokenSecretName = zone.gateway.controlAuth.secret;\n\tconst gatewayTokenFileCommand = secretEnvironmentNames.includes(gatewayTokenSecretName)\n\t\t? `{ ${runtimeSecretLiteralExportCommand(gatewayTokenSecretName)}; } > ${openClawGatewayTokenEnvFilePath} && `\n\t\t: `: > ${openClawGatewayTokenEnvFilePath} && `;\n\tconst sshConfigLines = ['Host tool-*.vm.host', ' AddressFamily inet'];\n\tconst sshConfigCommand =\n\t\t`mkdir -p /root/.ssh /home/openclaw/.ssh && ` +\n\t\t`printf '%s\\\\n' ${sshConfigLines.map((line) => shellQuote(line)).join(' ')} > /root/.ssh/config && ` +\n\t\t'cp /root/.ssh/config /home/openclaw/.ssh/config && ' +\n\t\t'chown -R openclaw:openclaw /home/openclaw/.ssh && ' +\n\t\t'chmod 700 /root/.ssh /home/openclaw/.ssh && ' +\n\t\t'chmod 600 /root/.ssh/config /home/openclaw/.ssh/config && ';\n\n\treturn (\n\t\t`mkdir -p /root /etc/profile.d /run/openclaw /work/tmp /work/cache/npm /work/cache/pnpm/store /work/cache/pip /work/cache/uv && chown -R openclaw:openclaw /work && cat > ${openClawShellEnvFilePath} << 'ENVEOF'\\n` +\n\t\tenvironmentLines.join('\\n') +\n\t\t'\\nENVEOF\\n' +\n\t\t`chmod 644 ${openClawShellEnvFilePath} && ` +\n\t\tsecretsFileCommand +\n\t\t`chmod 600 ${openClawRuntimeSecretsEnvFilePath} && ` +\n\t\tgatewayTokenFileCommand +\n\t\t`chmod 600 ${openClawGatewayTokenEnvFilePath} && ` +\n\t\tsshConfigCommand +\n\t\t'touch /root/.bashrc && ' +\n\t\t`grep -qxF 'source ${openClawShellEnvFilePath}' /root/.bashrc || echo 'source ${openClawShellEnvFilePath}' >> /root/.bashrc && ` +\n\t\t'touch /root/.bash_profile && ' +\n\t\t\"grep -qxF 'source /root/.bashrc' /root/.bash_profile || echo 'source /root/.bashrc' >> /root/.bash_profile\"\n\t);\n}\n\nfunction getEffectiveOpenClawConfigHostPath(zone: GatewayZoneConfig): string {\n\treturn path.join(zone.gateway.stateDir, effectiveOpenClawConfigFileName);\n}\n\nasync function assertEffectiveConfigPathWritable(\n\tzone: GatewayZoneConfig,\n\tcontent: string,\n): Promise<void> {\n\tconst effectiveConfigPath = getEffectiveOpenClawConfigHostPath(zone);\n\tconst existingEffectiveConfig = await lstat(effectiveConfigPath).catch((error: unknown) => {\n\t\tif (isObjectRecord(error) && error.code === 'ENOENT') {\n\t\t\treturn undefined;\n\t\t}\n\t\tthrow error;\n\t});\n\tif (existingEffectiveConfig?.isDirectory()) {\n\t\tthrow new Error(`Effective OpenClaw config path '${effectiveConfigPath}' is a directory.`);\n\t}\n\n\tconst preflightPath = path.join(\n\t\tzone.gateway.stateDir,\n\t\t`.agent-vm-effective-openclaw-preflight-${process.pid}-${randomUUID()}.json`,\n\t);\n\ttry {\n\t\tawait writeFileAtomically(preflightPath, content, { mode: 0o600 });\n\t} finally {\n\t\tawait rm(preflightPath, { force: true });\n\t}\n}\n\nfunction shellQuote(value: string): string {\n\treturn `'${value.replace(/'/gu, `'\\\\''`)}'`;\n}\n\nfunction includesShellUnsafeControlByte(value: string): boolean {\n\tfor (const character of value) {\n\t\tconst codePoint = character.codePointAt(0);\n\t\tif (codePoint !== undefined && (codePoint <= 0x1f || codePoint === 0x7f)) {\n\t\t\treturn true;\n\t\t}\n\t}\n\treturn false;\n}\n\nfunction assertShellSafeEnvName(secretName: string): void {\n\tif (!/^[_A-Za-z][_0-9A-Za-z]*$/u.test(secretName)) {\n\t\tthrow new Error(\n\t\t\t`OpenClaw env-injected gateway secret '${secretName}' must be a shell-safe environment variable name.`,\n\t\t);\n\t}\n}\n\nfunction assertShellProfileSafeSecretValue(secretName: string, value: string): void {\n\tif (includesShellUnsafeControlByte(value)) {\n\t\tthrow new Error(\n\t\t\t`OpenClaw env-injected gateway secret '${secretName}' must be a single-line value without control bytes. Use http-mediation for secrets that require structured transport.`,\n\t\t);\n\t}\n}\n\nfunction runtimeSecretLiteralExportCommand(secretName: string): string {\n\tconst runtimeSecretValue = `\"\\${${secretName}?missing runtime secret ${secretName}}\"`;\n\treturn `secret_value=${runtimeSecretValue} && escaped_secret_value=\"$(printf '%s' \"$secret_value\" | sed 's/[\"\\\\\\\\$\\`]/\\\\\\\\&/g')\" && printf 'export ${secretName}=\"%s\"\\\\n' \"$escaped_secret_value\"`;\n}\n\nfunction assertAllowedOpenClawEnvironmentSecrets(\n\tzone: GatewayZoneConfig,\n\tenvironmentSecrets: Readonly<Record<string, string>>,\n\tlogPrefix: string,\n): void {\n\tif (zone.gateway.type !== 'openclaw') {\n\t\tthrow new Error(`OpenClaw lifecycle cannot build gateway type '${zone.gateway.type}'.`);\n\t}\n\tconst allowedRawEnvSecrets = new Set([\n\t\tzone.gateway.controlAuth.secret,\n\t\t...(zone.gateway.rawEnvSecrets ?? []),\n\t]);\n\tfor (const secretName of Object.keys(environmentSecrets)) {\n\t\tif (allowedRawEnvSecrets.has(secretName)) {\n\t\t\tcontinue;\n\t\t}\n\t\tthrow new Error(\n\t\t\t`[${logPrefix}] OpenClaw env secret '${secretName}' must be listed in gateway.rawEnvSecrets or use injection 'http-mediation'.`,\n\t\t);\n\t}\n}\n\nfunction splitAllowedOpenClawGatewaySecrets(\n\tzone: GatewayZoneConfig,\n\tresolvedSecrets: Record<string, string>,\n\tlogPrefix: string,\n): SplitResolvedGatewaySecretsResult {\n\tconst splitSecrets = splitResolvedGatewaySecrets(zone, resolvedSecrets);\n\tassertAllowedOpenClawEnvironmentSecrets(zone, splitSecrets.environmentSecrets, logPrefix);\n\treturn splitSecrets;\n}\n\ntype SourceAwareSecretReference =\n\t| {\n\t\t\treadonly source: 'environment';\n\t\t\treadonly envVar: string;\n\t }\n\t| {\n\t\t\treadonly source: '1password';\n\t\t\treadonly ref: string;\n\t }\n\t| {\n\t\t\treadonly source: 'config';\n\t\t\treadonly value: string;\n\t };\n\nfunction isSourceAwareSecretReference(value: unknown): value is SourceAwareSecretReference {\n\tif (typeof value !== 'object' || value === null) {\n\t\treturn false;\n\t}\n\n\tif (!('source' in value) || typeof value.source !== 'string') {\n\t\treturn false;\n\t}\n\n\tif (value.source === 'environment') {\n\t\treturn 'envVar' in value && typeof value.envVar === 'string';\n\t}\n\n\tif (value.source === '1password') {\n\t\treturn 'ref' in value && typeof value.ref === 'string';\n\t}\n\n\tif (value.source === 'config') {\n\t\treturn 'value' in value && typeof value.value === 'string';\n\t}\n\n\treturn false;\n}\n\nfunction toSecretRef(secret: SourceAwareSecretReference): SecretRef {\n\tswitch (secret.source) {\n\t\tcase 'environment':\n\t\t\treturn {\n\t\t\t\tsource: 'environment',\n\t\t\t\tref: secret.envVar,\n\t\t\t};\n\t\tcase '1password':\n\t\t\treturn {\n\t\t\t\tsource: '1password',\n\t\t\t\tref: secret.ref,\n\t\t\t};\n\t\tcase 'config':\n\t\t\treturn {\n\t\t\t\tsource: 'config',\n\t\t\t\tvalue: secret.value,\n\t\t\t};\n\t\tdefault: {\n\t\t\tconst exhaustiveCheck: never = secret;\n\t\t\tthrow new Error(`Unsupported secret source: ${JSON.stringify(exhaustiveCheck)}`);\n\t\t}\n\t}\n}\n\nfunction describeSecretReference(secret: SourceAwareSecretReference): string {\n\tswitch (secret.source) {\n\t\tcase 'environment':\n\t\t\treturn secret.envVar;\n\t\tcase '1password':\n\t\t\treturn redactOnePasswordReferences(secret.ref);\n\t\tcase 'config':\n\t\t\treturn 'config value';\n\t\tdefault: {\n\t\t\tconst exhaustiveCheck: never = secret;\n\t\t\tthrow new Error(`Unsupported secret source: ${JSON.stringify(exhaustiveCheck)}`);\n\t\t}\n\t}\n}\n\nfunction formatSafeOpenClawErrorMessage(error: unknown): string {\n\treturn redactOnePasswordReferences(error instanceof Error ? error.message : String(error));\n}\n\nfunction buildEffectiveSecretsConfig(\n\tparsedBaseConfig: Record<string, unknown>,\n): Record<string, unknown> {\n\tconst existingSecretsConfig = isObjectRecord(parsedBaseConfig.secrets)\n\t\t? parsedBaseConfig.secrets\n\t\t: {};\n\tconst existingProvidersConfig = isObjectRecord(existingSecretsConfig.providers)\n\t\t? existingSecretsConfig.providers\n\t\t: {};\n\n\treturn {\n\t\t...existingSecretsConfig,\n\t\tproviders: {\n\t\t\t...existingProvidersConfig,\n\t\t\tdefault: {\n\t\t\t\tsource: 'env',\n\t\t\t},\n\t\t},\n\t};\n}\n\nfunction buildEffectiveMcpPortalPluginConfig(\n\t_existingPluginConfig: Record<string, unknown>,\n\truntimeConfig: Readonly<Record<string, unknown>>,\n): Record<string, unknown> {\n\treturn {\n\t\t...runtimeConfig,\n\t};\n}\n\nfunction buildEffectivePluginsConfig(\n\tparsedBaseConfig: Record<string, unknown>,\n\truntimePluginConfigs: Readonly<Record<string, Readonly<Record<string, unknown>>>> | undefined,\n): Record<string, unknown> {\n\tconst existingPluginsConfig = isObjectRecord(parsedBaseConfig.plugins)\n\t\t? parsedBaseConfig.plugins\n\t\t: {};\n\tconst existingEntriesConfig = isObjectRecord(existingPluginsConfig.entries)\n\t\t? existingPluginsConfig.entries\n\t\t: {};\n\tconst runtimeEntriesConfig = Object.fromEntries(\n\t\tObject.entries(runtimePluginConfigs ?? {}).map(([pluginId, runtimeConfig]) => {\n\t\t\tconst existingEntryConfig = isObjectRecord(existingEntriesConfig[pluginId])\n\t\t\t\t? existingEntriesConfig[pluginId]\n\t\t\t\t: {};\n\t\t\tconst existingPluginConfig = isObjectRecord(existingEntryConfig.config)\n\t\t\t\t? existingEntryConfig.config\n\t\t\t\t: {};\n\t\t\tconst config =\n\t\t\t\tpluginId === 'mcp-portal'\n\t\t\t\t\t? buildEffectiveMcpPortalPluginConfig(existingPluginConfig, runtimeConfig)\n\t\t\t\t\t: {\n\t\t\t\t\t\t\t...existingPluginConfig,\n\t\t\t\t\t\t\t...runtimeConfig,\n\t\t\t\t\t\t};\n\t\t\treturn [\n\t\t\t\tpluginId,\n\t\t\t\t{\n\t\t\t\t\t...existingEntryConfig,\n\t\t\t\t\tconfig,\n\t\t\t\t},\n\t\t\t] as const;\n\t\t}),\n\t);\n\n\treturn {\n\t\t...existingPluginsConfig,\n\t\tentries: {\n\t\t\t...existingEntriesConfig,\n\t\t\t...runtimeEntriesConfig,\n\t\t},\n\t};\n}\n\nfunction buildEffectiveMcpConfig(\n\tparsedBaseConfig: Record<string, unknown>,\n\truntimeMcpServers: Readonly<Record<string, unknown>> | undefined,\n): Record<string, unknown> {\n\tconst existingMcpConfig = isObjectRecord(parsedBaseConfig.mcp) ? parsedBaseConfig.mcp : {};\n\tconst existingServersConfig = isObjectRecord(existingMcpConfig.servers)\n\t\t? existingMcpConfig.servers\n\t\t: {};\n\treturn {\n\t\t...existingMcpConfig,\n\t\tservers: {\n\t\t\t...existingServersConfig,\n\t\t\t...runtimeMcpServers,\n\t\t},\n\t};\n}\n\nfunction buildEffectiveLoggingConfig(\n\tparsedBaseConfig: Record<string, unknown>,\n): Record<string, unknown> {\n\tconst existingLoggingConfig = isObjectRecord(parsedBaseConfig.logging)\n\t\t? parsedBaseConfig.logging\n\t\t: {};\n\n\treturn {\n\t\tfile: openClawRuntimeLogFileVmPath,\n\t\t...existingLoggingConfig,\n\t};\n}\n\nasync function writeAuthProfilesIfConfigured(\n\tzone: GatewayZoneConfig,\n\tsecretResolver: SecretResolver,\n): Promise<void> {\n\tconst resolvedAuthProfiles = await resolveAuthProfilesIfConfigured(zone, secretResolver);\n\n\tconst writeResults = await Promise.allSettled(\n\t\tresolvedAuthProfiles.map(async ({ agentId, authProfiles }) => {\n\t\t\tconst authProfilesDirectory = path.join(zone.gateway.stateDir, 'agents', agentId, 'agent');\n\t\t\tawait mkdir(authProfilesDirectory, { recursive: true, mode: 0o700 });\n\t\t\tawait chmod(authProfilesDirectory, 0o700);\n\t\t\tawait writeFileAtomically(\n\t\t\t\tpath.join(authProfilesDirectory, 'auth-profiles.json'),\n\t\t\t\tauthProfiles,\n\t\t\t\t{\n\t\t\t\t\tmode: 0o600,\n\t\t\t\t},\n\t\t\t);\n\t\t}),\n\t);\n\tconst writeErrors = writeResults\n\t\t.filter((result): result is PromiseRejectedResult => result.status === 'rejected')\n\t\t.map((result) =>\n\t\t\tresult.reason instanceof Error ? result.reason : new Error(String(result.reason)),\n\t\t);\n\tif (writeErrors.length > 0) {\n\t\tthrow new AggregateError(\n\t\t\twriteErrors,\n\t\t\t`Failed to write ${String(writeErrors.length)} OpenClaw auth profile file(s) for zone '${zone.id}'.`,\n\t\t);\n\t}\n}\n\nasync function assertAuthProfilePathWritable(\n\tzone: GatewayZoneConfig,\n\tagentId: string,\n): Promise<void> {\n\tconst authProfilesDirectory = path.join(zone.gateway.stateDir, 'agents', agentId, 'agent');\n\tconst authProfilesPath = path.join(authProfilesDirectory, 'auth-profiles.json');\n\tconst existingAuthProfilesPath = await lstat(authProfilesPath).catch((error: unknown) => {\n\t\tif (isObjectRecord(error) && error.code === 'ENOENT') {\n\t\t\treturn undefined;\n\t\t}\n\t\tthrow error;\n\t});\n\tif (existingAuthProfilesPath?.isDirectory()) {\n\t\tthrow new Error(`OpenClaw auth profiles path '${authProfilesPath}' is a directory.`);\n\t}\n\n\tconst preflightPath = path.join(\n\t\tauthProfilesDirectory,\n\t\t`.agent-vm-auth-profiles-preflight-${process.pid}-${randomUUID()}.json`,\n\t);\n\ttry {\n\t\tawait mkdir(authProfilesDirectory, { recursive: true, mode: 0o700 });\n\t\tawait chmod(authProfilesDirectory, 0o700);\n\t\tawait writeFileAtomically(preflightPath, '{}\\n', { mode: 0o600 });\n\t} finally {\n\t\tawait rm(preflightPath, { force: true });\n\t}\n}\n\nasync function preflightAuthProfilesIfConfigured(\n\tzone: GatewayZoneConfig,\n\tsecretResolver: SecretResolver,\n): Promise<void> {\n\tconst resolvedAuthProfiles = await resolveAuthProfilesIfConfigured(zone, secretResolver);\n\tconst writeResults = await Promise.allSettled(\n\t\tresolvedAuthProfiles.map(async ({ agentId }) => {\n\t\t\tawait assertAuthProfilePathWritable(zone, agentId);\n\t\t}),\n\t);\n\tconst writeErrors = writeResults\n\t\t.filter((result): result is PromiseRejectedResult => result.status === 'rejected')\n\t\t.map((result) =>\n\t\t\tresult.reason instanceof Error ? result.reason : new Error(String(result.reason)),\n\t\t);\n\tif (writeErrors.length > 0) {\n\t\tthrow new AggregateError(\n\t\t\twriteErrors,\n\t\t\t`Failed to preflight ${String(writeErrors.length)} OpenClaw auth profile file write(s) for zone '${zone.id}'.`,\n\t\t);\n\t}\n}\n\nasync function resolveAuthProfilesIfConfigured(\n\tzone: GatewayZoneConfig,\n\tsecretResolver: SecretResolver,\n): Promise<readonly { readonly agentId: string; readonly authProfiles: string }[]> {\n\tconst authProfilesByAgent = {\n\t\t...(zone.gateway.authProfilesRef ? { main: zone.gateway.authProfilesRef } : {}),\n\t\t...(zone.gateway.type === 'openclaw' ? (zone.gateway.authProfilesByAgent ?? {}) : {}),\n\t};\n\n\tconst resolveResults = await Promise.allSettled(\n\t\tObject.entries(authProfilesByAgent).map(async ([agentId, authProfilesSecretCandidate]) => {\n\t\t\tif (!isSourceAwareSecretReference(authProfilesSecretCandidate)) {\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`Zone '${zone.id}' has an invalid auth profile shape for agent '${agentId}'.`,\n\t\t\t\t);\n\t\t\t}\n\t\t\tconst authProfilesSecret = authProfilesSecretCandidate;\n\n\t\t\ttry {\n\t\t\t\tconst authProfiles = await secretResolver.resolve(toSecretRef(authProfilesSecret));\n\t\t\t\treturn { agentId, authProfiles };\n\t\t\t} catch (error) {\n\t\t\t\tconst message = formatSafeOpenClawErrorMessage(error);\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`Failed to resolve OpenClaw auth profiles for zone '${zone.id}' agent '${agentId}' from '${describeSecretReference(authProfilesSecret)}': ${message}`,\n\t\t\t\t\t{ cause: error },\n\t\t\t\t);\n\t\t\t}\n\t\t}),\n\t);\n\tconst resolveErrors = resolveResults\n\t\t.filter((result): result is PromiseRejectedResult => result.status === 'rejected')\n\t\t.map((result) =>\n\t\t\tresult.reason instanceof Error ? result.reason : new Error(String(result.reason)),\n\t\t);\n\tif (resolveErrors.length > 0) {\n\t\tthrow new AggregateError(\n\t\t\tresolveErrors,\n\t\t\t`Failed to resolve ${String(resolveErrors.length)} OpenClaw auth profile secret(s) for zone '${zone.id}'.`,\n\t\t);\n\t}\n\treturn resolveResults\n\t\t.filter(\n\t\t\t(\n\t\t\t\tresult,\n\t\t\t): result is PromiseFulfilledResult<{\n\t\t\t\treadonly agentId: string;\n\t\t\t\treadonly authProfiles: string;\n\t\t\t}> => result.status === 'fulfilled',\n\t\t)\n\t\t.map((result) => result.value);\n}\n\nasync function buildEffectiveOpenClawConfigContent(zone: GatewayZoneConfig): Promise<string> {\n\tif (zone.gateway.type !== 'openclaw') {\n\t\tthrow new Error(`OpenClaw lifecycle cannot build gateway type '${zone.gateway.type}'.`);\n\t}\n\tconst gatewayTokenSecretName = zone.gateway.controlAuth.secret;\n\tconst gatewayTokenSecret = zone.secrets[gatewayTokenSecretName];\n\tif (!gatewayTokenSecret) {\n\t\tthrow new Error(\n\t\t\t`Zone '${zone.id}' secret '${gatewayTokenSecretName}' is missing. Add an explicit 1Password or environment reference for the gateway token.`,\n\t\t);\n\t}\n\tif (!isSourceAwareSecretReference(gatewayTokenSecret)) {\n\t\tthrow new Error(`Zone '${zone.id}' secret '${gatewayTokenSecretName}' has an invalid shape.`);\n\t}\n\n\ttry {\n\t\tif (gatewayTokenSecret.source === '1password' && !gatewayTokenSecret.ref) {\n\t\t\tthrow new Error(\n\t\t\t\t`Zone '${zone.id}' secret '${gatewayTokenSecretName}' is missing 'ref'. Add an explicit 1Password reference for the gateway token.`,\n\t\t\t);\n\t\t}\n\t\tif (gatewayTokenSecret.source === 'environment' && !gatewayTokenSecret.envVar) {\n\t\t\tthrow new Error(\n\t\t\t\t`Zone '${zone.id}' secret '${gatewayTokenSecretName}' is missing 'envVar'. Add an explicit environment variable name.`,\n\t\t\t);\n\t\t}\n\t\tconst openClawGatewayTokenSecretRef: OpenClawSecretRef = {\n\t\t\tid: gatewayTokenSecretName,\n\t\t\tprovider: 'default',\n\t\t\tsource: 'env',\n\t\t};\n\t\tconst rawBaseConfig = await readFile(zone.gateway.config, 'utf8');\n\t\tconst parsedBaseConfig: unknown = JSON.parse(rawBaseConfig);\n\t\tif (!isObjectRecord(parsedBaseConfig)) {\n\t\t\tthrow new Error(`OpenClaw config at '${zone.gateway.config}' must be a JSON object.`);\n\t\t}\n\t\tconst runtimePluginConfigs = {\n\t\t\t...zone.runtimePluginConfigs,\n\t\t\tgondolin: {\n\t\t\t\tcontrollerUrl: `http://${controllerVmHost}:18800`,\n\t\t\t\tgatewayControlLinkMonitor: {\n\t\t\t\t\tbaseIntervalMs: 10_000,\n\t\t\t\t\tenabled: true,\n\t\t\t\t\tmaxIntervalMs: 120_000,\n\t\t\t\t},\n\t\t\t\tzoneId: zone.id,\n\t\t\t\t...(isObjectRecord(zone.runtimePluginConfigs?.gondolin)\n\t\t\t\t\t? zone.runtimePluginConfigs.gondolin\n\t\t\t\t\t: {}),\n\t\t\t},\n\t\t};\n\t\tconst config = isObjectRecord(parsedBaseConfig.gateway) ? parsedBaseConfig.gateway : {};\n\t\tconst existingAuthConfig = isObjectRecord(config.auth) ? config.auth : {};\n\t\tconst effectiveConfig = {\n\t\t\t...parsedBaseConfig,\n\t\t\tlogging: buildEffectiveLoggingConfig(parsedBaseConfig),\n\t\t\tgateway: {\n\t\t\t\t...config,\n\t\t\t\tauth: {\n\t\t\t\t\t...existingAuthConfig,\n\t\t\t\t\tmode: 'token',\n\t\t\t\t\ttoken: openClawGatewayTokenSecretRef,\n\t\t\t\t},\n\t\t\t},\n\t\t\tmeta: {\n\t\t\t\t...(isObjectRecord(parsedBaseConfig.meta) ? parsedBaseConfig.meta : {}),\n\t\t\t\tlastTouchedAt: new Date().toISOString(),\n\t\t\t\tlastTouchedVersion: 'agent-vm',\n\t\t\t},\n\t\t\tmcp: buildEffectiveMcpConfig(parsedBaseConfig, zone.runtimeMcpServers),\n\t\t\tplugins: buildEffectivePluginsConfig(parsedBaseConfig, runtimePluginConfigs),\n\t\t\tsecrets: buildEffectiveSecretsConfig(parsedBaseConfig),\n\t\t};\n\t\treturn `${JSON.stringify(effectiveConfig, null, 2)}\\n`;\n\t} catch (error) {\n\t\tconst message = formatSafeOpenClawErrorMessage(error);\n\t\tthrow new Error(\n\t\t\t`Failed to build effective OpenClaw config for zone '${zone.id}' from '${zone.gateway.config}' using secret '${describeSecretReference(gatewayTokenSecret)}': ${message}`,\n\t\t\t{ cause: error },\n\t\t);\n\t}\n}\n\nasync function writeEffectiveOpenClawConfig(zone: GatewayZoneConfig): Promise<void> {\n\tconst content = await buildEffectiveOpenClawConfigContent(zone);\n\ttry {\n\t\tconst effectiveConfigPath = getEffectiveOpenClawConfigHostPath(zone);\n\t\tawait mkdir(zone.gateway.stateDir, { recursive: true, mode: 0o700 });\n\t\tawait chmod(zone.gateway.stateDir, 0o700);\n\t\tawait writeFileAtomically(effectiveConfigPath, content, { mode: 0o600 });\n\t} catch (error) {\n\t\tconst message = error instanceof Error ? error.message : String(error);\n\t\tthrow new Error(`Failed to write effective OpenClaw config for zone '${zone.id}': ${message}`, {\n\t\t\tcause: error,\n\t\t});\n\t}\n}\n\nasync function preflightEffectiveOpenClawConfig(zone: GatewayZoneConfig): Promise<void> {\n\tconst content = await buildEffectiveOpenClawConfigContent(zone);\n\ttry {\n\t\tawait mkdir(zone.gateway.stateDir, { recursive: true, mode: 0o700 });\n\t\tawait chmod(zone.gateway.stateDir, 0o700);\n\t\tawait assertEffectiveConfigPathWritable(zone, content);\n\t} catch (error) {\n\t\tconst message = error instanceof Error ? error.message : String(error);\n\t\tthrow new Error(\n\t\t\t`Failed to preflight effective OpenClaw config for zone '${zone.id}': ${message}`,\n\t\t\t{ cause: error },\n\t\t);\n\t}\n}\n\nexport const openclawLifecycle: GatewayLifecycle = {\n\tauthConfig: {\n\t\tlistProvidersCommand: 'openclaw models auth list --format plain 2>/dev/null || echo \"\"',\n\t\tbuildLoginCommand: (\n\t\t\tprovider: string,\n\t\t\toptions: {\n\t\t\t\treadonly agentId?: string;\n\t\t\t\treadonly deviceCode?: boolean;\n\t\t\t\treadonly setDefault?: boolean;\n\t\t\t} = {},\n\t\t): string =>\n\t\t\t[\n\t\t\t\t'openclaw models auth',\n\t\t\t\t...(options.agentId ? [`--agent ${shellQuote(options.agentId)}`] : []),\n\t\t\t\t`login --provider ${shellQuote(provider)}`,\n\t\t\t\t...(options.deviceCode === true ? ['--device-code'] : []),\n\t\t\t\t...(options.setDefault === true ? ['--set-default'] : []),\n\t\t\t].join(' '),\n\t},\n\n\tbuildVmSpec({\n\t\tcontrollerPort,\n\t\tgatewayCacheDir,\n\t\tprojectNamespace,\n\t\tresolvedSecrets,\n\t\truntimeDir,\n\t\ttcpPool,\n\t\tzone,\n\t}: BuildGatewayVmSpecOptions): GatewayVmSpec {\n\t\tif (zone.gateway.type !== 'openclaw') {\n\t\t\tthrow new Error(`OpenClaw lifecycle cannot build gateway type '${zone.gateway.type}'.`);\n\t\t}\n\t\tconst configDirectory = path.dirname(path.resolve(zone.gateway.config));\n\t\tconst { environmentSecrets, mediatedSecrets } = mergeRuntimeGatewaySecrets(\n\t\t\tsplitAllowedOpenClawGatewaySecrets(zone, resolvedSecrets, 'openclaw-vm-raw-env-secrets'),\n\t\t\t{\n\t\t\t\tlogPrefix: 'openclaw-vm-runtime-secrets',\n\t\t\t\truntimeEnvironment: zone.runtimeEnvironment,\n\t\t\t\truntimeMediatedSecrets: zone.runtimeMediatedSecrets,\n\t\t\t},\n\t\t);\n\t\tassertAllowedOpenClawEnvironmentSecrets(\n\t\t\tzone,\n\t\t\tenvironmentSecrets,\n\t\t\t'openclaw-vm-runtime-raw-env-secrets',\n\t\t);\n\n\t\treturn {\n\t\t\tallowedHosts: gatewayVmAllowedHosts(zone.egressHosts),\n\t\t\tenvironment: {\n\t\t\t\tHOME: '/home/openclaw',\n\t\t\t\tNODE_EXTRA_CA_CERTS: '/run/gondolin/ca-certificates.crt',\n\t\t\t\tOPENCLAW_CONFIG_PATH: effectiveOpenClawConfigVmPath,\n\t\t\t\tOPENCLAW_HOME: '/home/openclaw',\n\t\t\t\tOPENCLAW_STATE_DIR: openClawStateDirVmPath,\n\t\t\t\tPATH: openClawGatewayGuestPath,\n\t\t\t\tPIP_CACHE_DIR: '/work/cache/pip',\n\t\t\t\tPNPM_HOME: '/pnpm',\n\t\t\t\tTEMP: '/work/tmp',\n\t\t\t\tTMP: '/work/tmp',\n\t\t\t\tTMPDIR: '/work/tmp',\n\t\t\t\tUV_CACHE_DIR: '/work/cache/uv',\n\t\t\t\tnpm_config_cache: '/work/cache/npm',\n\t\t\t\tpnpm_config_store_dir: '/work/cache/pnpm/store',\n\t\t\t\t...environmentSecrets,\n\t\t\t\t// NODE_OPTIONS goes AFTER the spread so a user-supplied\n\t\t\t\t// NODE_OPTIONS in environmentSecrets cannot drop the\n\t\t\t\t// forced IPv4-preference flags. composeNodeOptions\n\t\t\t\t// preserves the user value as additional flags.\n\t\t\t\tNODE_OPTIONS: composeNodeOptions(environmentSecrets.NODE_OPTIONS),\n\t\t\t},\n\t\t\tmediatedSecrets: {\n\t\t\t\t...mediatedSecrets,\n\t\t\t},\n\t\t\trootfsMode: 'cow',\n\t\t\t...(zone.gateway.runtimeRootfsSize\n\t\t\t\t? { runtimeRootfsSize: zone.gateway.runtimeRootfsSize }\n\t\t\t\t: {}),\n\t\t\tsessionLabel: buildGatewaySessionLabelValue(projectNamespace, zone.id),\n\t\t\ttcpHosts: buildGatewayTcpHosts(zone, controllerPort, tcpPool),\n\t\t\tvfsMounts: {\n\t\t\t\t'/home/openclaw/.openclaw/config': {\n\t\t\t\t\thostPath: configDirectory,\n\t\t\t\t\tkind: 'realfs',\n\t\t\t\t},\n\t\t\t\t[openClawCacheDirVmPath]: {\n\t\t\t\t\thostPath: gatewayCacheDir,\n\t\t\t\t\tkind: 'realfs',\n\t\t\t\t},\n\t\t\t\t'/home/openclaw/.openclaw/state': {\n\t\t\t\t\thostPath: zone.gateway.stateDir,\n\t\t\t\t\tkind: 'realfs',\n\t\t\t\t},\n\t\t\t\t[openClawZoneFilesDirVmPath]: {\n\t\t\t\t\thostPath: zone.gateway.zoneFilesDir,\n\t\t\t\t\tkind: 'realfs',\n\t\t\t\t},\n\t\t\t\t[agentVmLogsDirVmPath]: {\n\t\t\t\t\thostPath: path.join(runtimeDir, 'zones', zone.id, 'logs'),\n\t\t\t\t\tkind: 'realfs',\n\t\t\t\t},\n\t\t\t},\n\t\t};\n\t},\n\n\tbuildProcessSpec(\n\t\tzone: GatewayZoneConfig,\n\t\tresolvedSecrets: Record<string, string>,\n\t): GatewayProcessSpec {\n\t\treturn {\n\t\t\tbootstrapCommand: buildOpenClawBootstrapCommand(zone, resolvedSecrets),\n\t\t\t// printf NODE_OPTIONS into the boot log so an env-loss regression\n\t\t\t// (e.g. a future secrets.env or merge change that drops the\n\t\t\t// FORCE_IPV4_EGRESS_NODE_OPTIONS flags) is visible in the log\n\t\t\t// stream without SSHing into the VM. See\n\t\t\t// FORCE_IPV4_EGRESS_NODE_OPTIONS in @agent-vm/gateway-interface.\n\t\t\tstartCommand: `set -a && . ${openClawRuntimeSecretsEnvFilePath} && set +a && { printf 'gateway-boot: NODE_OPTIONS=%s\\\\n' \"$NODE_OPTIONS\" > ${openClawGatewayBootLogFileVmPath}; } && cd /home/openclaw && nohup ${openClawCommandVmPath} gateway --port 18789 >> ${openClawGatewayBootLogFileVmPath} 2>&1 &`,\n\t\t\thealthCheck: {\n\t\t\t\ttype: 'http',\n\t\t\t\tport: 18789,\n\t\t\t\tpath: '/readyz',\n\t\t\t},\n\t\t\tserviceHealthCheck: {\n\t\t\t\ttype: 'http',\n\t\t\t\tport: 18789,\n\t\t\t\tpath: '/health',\n\t\t\t},\n\t\t\tguestListenPort: 18789,\n\t\t\tlogPath: openClawGatewayBootLogFileVmPath,\n\t\t};\n\t},\n\n\tasync prepareHostState(zone: GatewayZoneConfig, secretResolver: SecretResolver): Promise<void> {\n\t\tawait writeEffectiveOpenClawConfig(zone);\n\t\tawait writeAuthProfilesIfConfigured(zone, secretResolver);\n\t},\n\n\tasync preflightHostState(zone: GatewayZoneConfig, secretResolver: SecretResolver): Promise<void> {\n\t\tawait preflightEffectiveOpenClawConfig(zone);\n\t\tawait preflightAuthProfilesIfConfigured(zone, secretResolver);\n\t},\n};\n"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agent-vm/openclaw-gateway",
3
- "version": "0.0.94",
3
+ "version": "0.0.96",
4
4
  "description": "OpenClaw gateway lifecycle running inside a Gondolin VM.",
5
5
  "homepage": "https://github.com/ShravanSunder/agent-vm#readme",
6
6
  "bugs": {
@@ -29,9 +29,9 @@
29
29
  "access": "public"
30
30
  },
31
31
  "dependencies": {
32
- "@agent-vm/secret-management": "0.0.94",
33
- "@agent-vm/gondolin-adapter": "0.0.94",
34
- "@agent-vm/gateway-interface": "0.0.94"
32
+ "@agent-vm/gondolin-adapter": "0.0.96",
33
+ "@agent-vm/gateway-interface": "0.0.96",
34
+ "@agent-vm/secret-management": "0.0.96"
35
35
  },
36
36
  "scripts": {
37
37
  "build": "tsdown",