diff --git a/src/commands/status-all.ts b/src/commands/status-all.ts index 99a4e8bdc9e..fed39420cbd 100644 --- a/src/commands/status-all.ts +++ b/src/commands/status-all.ts @@ -14,7 +14,7 @@ import type { GatewayService } from "../daemon/service.js"; import { resolveGatewayService } from "../daemon/service.js"; import { buildGatewayConnectionDetails, callGateway } from "../gateway/call.js"; import { normalizeControlUiBasePath } from "../gateway/control-ui-shared.js"; -import { resolveGatewayProbeAuthSafe } from "../gateway/probe-auth.js"; +import { resolveGatewayProbeAuthSafeWithSecretInputs } from "../gateway/probe-auth.js"; import { probeGateway } from "../gateway/probe.js"; import { collectChannelStatusIssues } from "../infra/channels-status-issues.js"; import { resolveOpenClawPackageRoot } from "../infra/openclaw-root.js"; @@ -124,8 +124,16 @@ export async function statusAllCommand( const remoteUrlMissing = isRemoteMode && !remoteUrlRaw; const gatewayMode = isRemoteMode ? "remote" : "local"; - const localProbeAuthResolution = resolveGatewayProbeAuthSafe({ cfg, mode: "local" }); - const remoteProbeAuthResolution = resolveGatewayProbeAuthSafe({ cfg, mode: "remote" }); + const localProbeAuthResolution = await resolveGatewayProbeAuthSafeWithSecretInputs({ + cfg, + mode: "local", + env: process.env, + }); + const remoteProbeAuthResolution = await resolveGatewayProbeAuthSafeWithSecretInputs({ + cfg, + mode: "remote", + env: process.env, + }); const probeAuthResolution = isRemoteMode && !remoteUrlMissing ? remoteProbeAuthResolution : localProbeAuthResolution; const probeAuth = probeAuthResolution.auth; diff --git a/src/gateway/probe-auth.test.ts b/src/gateway/probe-auth.test.ts index bbf034c882f..b95eebf58db 100644 --- a/src/gateway/probe-auth.test.ts +++ b/src/gateway/probe-auth.test.ts @@ -2,6 +2,7 @@ import { describe, expect, it } from "vitest"; import type { OpenClawConfig } from "../config/config.js"; import { resolveGatewayProbeAuthSafe, + resolveGatewayProbeAuthSafeWithSecretInputs, resolveGatewayProbeAuthWithSecretInputs, } from "./probe-auth.js"; @@ -107,6 +108,60 @@ describe("resolveGatewayProbeAuthSafe", () => { }); }); +describe("resolveGatewayProbeAuthSafeWithSecretInputs", () => { + it("resolves env SecretRef token via async secret-inputs path", async () => { + const result = await resolveGatewayProbeAuthSafeWithSecretInputs({ + cfg: { + gateway: { + auth: { + mode: "token", + token: { source: "env", provider: "default", id: "OPENCLAW_GATEWAY_TOKEN" }, + }, + }, + secrets: { + providers: { + default: { source: "env" }, + }, + }, + } as OpenClawConfig, + mode: "local", + env: { + OPENCLAW_GATEWAY_TOKEN: "test-token-from-env", + } as NodeJS.ProcessEnv, + }); + + expect(result.warning).toBeUndefined(); + expect(result.auth).toEqual({ + token: "test-token-from-env", + password: undefined, + }); + }); + + it("returns warning and empty auth when SecretRef cannot be resolved via async path", async () => { + const result = await resolveGatewayProbeAuthSafeWithSecretInputs({ + cfg: { + gateway: { + auth: { + mode: "token", + token: { source: "env", provider: "default", id: "MISSING_TOKEN_XYZ" }, + }, + }, + secrets: { + providers: { + default: { source: "env" }, + }, + }, + } as OpenClawConfig, + mode: "local", + env: {} as NodeJS.ProcessEnv, + }); + + expect(result.auth).toEqual({}); + expect(result.warning).toContain("gateway.auth.token"); + expect(result.warning).toContain("unresolved"); + }); +}); + describe("resolveGatewayProbeAuthWithSecretInputs", () => { it("resolves local probe SecretRef values before shared credential selection", async () => { const auth = await resolveGatewayProbeAuthWithSecretInputs({ diff --git a/src/gateway/probe-auth.ts b/src/gateway/probe-auth.ts index 2c624acaa00..fe14fdabd64 100644 --- a/src/gateway/probe-auth.ts +++ b/src/gateway/probe-auth.ts @@ -50,6 +50,40 @@ export async function resolveGatewayProbeAuthWithSecretInputs(params: { }); } +export async function resolveGatewayProbeAuthSafeWithSecretInputs(params: { + cfg: OpenClawConfig; + mode: "local" | "remote"; + env?: NodeJS.ProcessEnv; + explicitAuth?: ExplicitGatewayAuth; +}): Promise<{ + auth: { token?: string; password?: string }; + warning?: string; +}> { + const explicitToken = params.explicitAuth?.token?.trim(); + const explicitPassword = params.explicitAuth?.password?.trim(); + if (explicitToken || explicitPassword) { + return { + auth: { + ...(explicitToken ? { token: explicitToken } : {}), + ...(explicitPassword ? { password: explicitPassword } : {}), + }, + }; + } + + try { + const auth = await resolveGatewayProbeAuthWithSecretInputs(params); + return { auth }; + } catch (error) { + if (!isGatewaySecretRefUnavailableError(error)) { + throw error; + } + return { + auth: {}, + warning: `${error.path} SecretRef is unresolved in this command path; probing without configured auth credentials.`, + }; + } +} + export function resolveGatewayProbeAuthSafe(params: { cfg: OpenClawConfig; mode: "local" | "remote";