mirror of
https://github.com/openclaw/openclaw.git
synced 2026-03-12 07:20:45 +00:00
refactor: reuse shared gateway probe auth
This commit is contained in:
@@ -283,6 +283,38 @@ describe("gatherDaemonStatus", () => {
|
||||
);
|
||||
});
|
||||
|
||||
it("keeps remote probe auth strict when remote token is missing", async () => {
|
||||
daemonLoadedConfig = {
|
||||
gateway: {
|
||||
mode: "remote",
|
||||
remote: {
|
||||
url: "wss://gateway.example",
|
||||
password: "remote-password", // pragma: allowlist secret
|
||||
},
|
||||
auth: {
|
||||
mode: "token",
|
||||
token: "local-token",
|
||||
password: "local-password", // pragma: allowlist secret
|
||||
},
|
||||
},
|
||||
};
|
||||
process.env.OPENCLAW_GATEWAY_TOKEN = "env-token";
|
||||
process.env.OPENCLAW_GATEWAY_PASSWORD = "env-password"; // pragma: allowlist secret
|
||||
|
||||
await gatherDaemonStatus({
|
||||
rpc: {},
|
||||
probe: true,
|
||||
deep: false,
|
||||
});
|
||||
|
||||
expect(callGatewayStatusProbe).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
token: undefined,
|
||||
password: "env-password", // pragma: allowlist secret
|
||||
}),
|
||||
);
|
||||
});
|
||||
|
||||
it("skips TLS runtime loading when probe is disabled", async () => {
|
||||
const status = await gatherDaemonStatus({
|
||||
rpc: {},
|
||||
|
||||
@@ -9,10 +9,6 @@ import type {
|
||||
GatewayBindMode,
|
||||
GatewayControlUiConfig,
|
||||
} from "../../config/types.js";
|
||||
import {
|
||||
hasConfiguredSecretInput,
|
||||
normalizeSecretInputString,
|
||||
} from "../../config/types.secrets.js";
|
||||
import { readLastGatewayErrorLine } from "../../daemon/diagnostics.js";
|
||||
import type { FindExtraGatewayServicesOptions } from "../../daemon/inspect.js";
|
||||
import { findExtraGatewayServices } from "../../daemon/inspect.js";
|
||||
@@ -20,13 +16,9 @@ import type { ServiceConfigAudit } from "../../daemon/service-audit.js";
|
||||
import { auditGatewayServiceConfig } from "../../daemon/service-audit.js";
|
||||
import type { GatewayServiceRuntime } from "../../daemon/service-runtime.js";
|
||||
import { resolveGatewayService } from "../../daemon/service.js";
|
||||
import {
|
||||
readGatewayPasswordEnv,
|
||||
readGatewayTokenEnv,
|
||||
trimToUndefined,
|
||||
} from "../../gateway/credentials.js";
|
||||
import { trimToUndefined } from "../../gateway/credentials.js";
|
||||
import { resolveGatewayBindHost } from "../../gateway/net.js";
|
||||
import { resolveRequiredConfiguredSecretRefInputString } from "../../gateway/resolve-configured-secret-input-string.js";
|
||||
import { resolveGatewayProbeAuthWithSecretInputs } from "../../gateway/probe-auth.js";
|
||||
import { parseStrictPositiveInteger } from "../../infra/parse-finite-number.js";
|
||||
import {
|
||||
formatPortDiagnostics,
|
||||
@@ -258,92 +250,6 @@ async function inspectDaemonPortStatuses(params: {
|
||||
};
|
||||
}
|
||||
|
||||
async function resolveDaemonProbeToken(params: {
|
||||
daemonCfg: OpenClawConfig;
|
||||
mergedDaemonEnv: Record<string, string | undefined>;
|
||||
explicitToken?: string;
|
||||
explicitPassword?: string;
|
||||
}): Promise<string | undefined> {
|
||||
const explicitToken = trimToUndefined(params.explicitToken);
|
||||
if (explicitToken) {
|
||||
return explicitToken;
|
||||
}
|
||||
const envToken = readGatewayTokenEnv(params.mergedDaemonEnv as NodeJS.ProcessEnv);
|
||||
if (envToken) {
|
||||
return envToken;
|
||||
}
|
||||
const defaults = params.daemonCfg.secrets?.defaults;
|
||||
const configured = params.daemonCfg.gateway?.auth?.token;
|
||||
const authMode = params.daemonCfg.gateway?.auth?.mode;
|
||||
if (authMode === "password" || authMode === "none" || authMode === "trusted-proxy") {
|
||||
return undefined;
|
||||
}
|
||||
if (authMode !== "token") {
|
||||
const passwordCandidate =
|
||||
trimToUndefined(params.explicitPassword) ||
|
||||
readGatewayPasswordEnv(params.mergedDaemonEnv as NodeJS.ProcessEnv) ||
|
||||
(hasConfiguredSecretInput(params.daemonCfg.gateway?.auth?.password, defaults)
|
||||
? "__configured__"
|
||||
: undefined);
|
||||
if (passwordCandidate) {
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
const resolvedToken = await resolveRequiredConfiguredSecretRefInputString({
|
||||
config: params.daemonCfg,
|
||||
env: params.mergedDaemonEnv as NodeJS.ProcessEnv,
|
||||
value: configured,
|
||||
path: "gateway.auth.token",
|
||||
});
|
||||
if (resolvedToken) {
|
||||
return resolvedToken;
|
||||
}
|
||||
return normalizeSecretInputString(configured);
|
||||
}
|
||||
|
||||
async function resolveDaemonProbePassword(params: {
|
||||
daemonCfg: OpenClawConfig;
|
||||
mergedDaemonEnv: Record<string, string | undefined>;
|
||||
explicitToken?: string;
|
||||
explicitPassword?: string;
|
||||
}): Promise<string | undefined> {
|
||||
const explicitPassword = trimToUndefined(params.explicitPassword);
|
||||
if (explicitPassword) {
|
||||
return explicitPassword;
|
||||
}
|
||||
const envPassword = readGatewayPasswordEnv(params.mergedDaemonEnv as NodeJS.ProcessEnv);
|
||||
if (envPassword) {
|
||||
return envPassword;
|
||||
}
|
||||
const defaults = params.daemonCfg.secrets?.defaults;
|
||||
const configured = params.daemonCfg.gateway?.auth?.password;
|
||||
const authMode = params.daemonCfg.gateway?.auth?.mode;
|
||||
if (authMode === "token" || authMode === "none" || authMode === "trusted-proxy") {
|
||||
return undefined;
|
||||
}
|
||||
if (authMode !== "password") {
|
||||
const tokenCandidate =
|
||||
trimToUndefined(params.explicitToken) ||
|
||||
readGatewayTokenEnv(params.mergedDaemonEnv as NodeJS.ProcessEnv) ||
|
||||
(hasConfiguredSecretInput(params.daemonCfg.gateway?.auth?.token, defaults)
|
||||
? "__configured__"
|
||||
: undefined);
|
||||
if (tokenCandidate) {
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
const resolvedPassword = await resolveRequiredConfiguredSecretRefInputString({
|
||||
config: params.daemonCfg,
|
||||
env: params.mergedDaemonEnv as NodeJS.ProcessEnv,
|
||||
value: configured,
|
||||
path: "gateway.auth.password",
|
||||
});
|
||||
if (resolvedPassword) {
|
||||
return resolvedPassword;
|
||||
}
|
||||
return normalizeSecretInputString(configured);
|
||||
}
|
||||
|
||||
export async function gatherDaemonStatus(
|
||||
opts: {
|
||||
rpc: GatewayRpcOpts;
|
||||
@@ -395,28 +301,23 @@ export async function gatherDaemonStatus(
|
||||
const tlsRuntime = shouldUseLocalTlsRuntime
|
||||
? await loadGatewayTlsRuntime(daemonCfg.gateway?.tls)
|
||||
: undefined;
|
||||
const daemonProbePassword = opts.probe
|
||||
? await resolveDaemonProbePassword({
|
||||
daemonCfg,
|
||||
mergedDaemonEnv,
|
||||
explicitToken: opts.rpc.token,
|
||||
explicitPassword: opts.rpc.password,
|
||||
})
|
||||
: undefined;
|
||||
const daemonProbeToken = opts.probe
|
||||
? await resolveDaemonProbeToken({
|
||||
daemonCfg,
|
||||
mergedDaemonEnv,
|
||||
explicitToken: opts.rpc.token,
|
||||
explicitPassword: opts.rpc.password,
|
||||
const daemonProbeAuth = opts.probe
|
||||
? await resolveGatewayProbeAuthWithSecretInputs({
|
||||
cfg: daemonCfg,
|
||||
mode: daemonCfg.gateway?.mode === "remote" ? "remote" : "local",
|
||||
env: mergedDaemonEnv as NodeJS.ProcessEnv,
|
||||
explicitAuth: {
|
||||
token: opts.rpc.token,
|
||||
password: opts.rpc.password,
|
||||
},
|
||||
})
|
||||
: undefined;
|
||||
|
||||
const rpc = opts.probe
|
||||
? await probeGatewayStatus({
|
||||
url: gateway.probeUrl,
|
||||
token: daemonProbeToken,
|
||||
password: daemonProbePassword,
|
||||
token: daemonProbeAuth?.token,
|
||||
password: daemonProbeAuth?.password,
|
||||
tlsFingerprint:
|
||||
shouldUseLocalTlsRuntime && tlsRuntime?.enabled
|
||||
? tlsRuntime.fingerprintSha256
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
import { describe, expect, it } from "vitest";
|
||||
import type { OpenClawConfig } from "../config/config.js";
|
||||
import { resolveGatewayProbeAuthSafe } from "./probe-auth.js";
|
||||
import {
|
||||
resolveGatewayProbeAuthSafe,
|
||||
resolveGatewayProbeAuthWithSecretInputs,
|
||||
} from "./probe-auth.js";
|
||||
|
||||
describe("resolveGatewayProbeAuthSafe", () => {
|
||||
it("returns probe auth credentials when available", () => {
|
||||
@@ -79,3 +82,32 @@ describe("resolveGatewayProbeAuthSafe", () => {
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("resolveGatewayProbeAuthWithSecretInputs", () => {
|
||||
it("resolves local probe SecretRef values before shared credential selection", async () => {
|
||||
const auth = await resolveGatewayProbeAuthWithSecretInputs({
|
||||
cfg: {
|
||||
gateway: {
|
||||
auth: {
|
||||
mode: "token",
|
||||
token: { source: "env", provider: "default", id: "DAEMON_GATEWAY_TOKEN" },
|
||||
},
|
||||
},
|
||||
secrets: {
|
||||
providers: {
|
||||
default: { source: "env" },
|
||||
},
|
||||
},
|
||||
} as OpenClawConfig,
|
||||
mode: "local",
|
||||
env: {
|
||||
DAEMON_GATEWAY_TOKEN: "resolved-daemon-token",
|
||||
} as NodeJS.ProcessEnv,
|
||||
});
|
||||
|
||||
expect(auth).toEqual({
|
||||
token: "resolved-daemon-token",
|
||||
password: undefined,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
import type { OpenClawConfig } from "../config/config.js";
|
||||
import { resolveGatewayCredentialsWithSecretInputs } from "./call.js";
|
||||
import {
|
||||
type ExplicitGatewayAuth,
|
||||
isGatewaySecretRefUnavailableError,
|
||||
resolveGatewayCredentialsFromConfig,
|
||||
} from "./credentials.js";
|
||||
@@ -18,6 +20,22 @@ export function resolveGatewayProbeAuth(params: {
|
||||
});
|
||||
}
|
||||
|
||||
export async function resolveGatewayProbeAuthWithSecretInputs(params: {
|
||||
cfg: OpenClawConfig;
|
||||
mode: "local" | "remote";
|
||||
env?: NodeJS.ProcessEnv;
|
||||
explicitAuth?: ExplicitGatewayAuth;
|
||||
}): Promise<{ token?: string; password?: string }> {
|
||||
return await resolveGatewayCredentialsWithSecretInputs({
|
||||
config: params.cfg,
|
||||
env: params.env,
|
||||
explicitAuth: params.explicitAuth,
|
||||
modeOverride: params.mode,
|
||||
includeLegacyEnv: false,
|
||||
remoteTokenFallback: "remote-only",
|
||||
});
|
||||
}
|
||||
|
||||
export function resolveGatewayProbeAuthSafe(params: {
|
||||
cfg: OpenClawConfig;
|
||||
mode: "local" | "remote";
|
||||
|
||||
Reference in New Issue
Block a user