openclaw
Version:
Multi-channel AI gateway with extensible messaging integrations
96 lines (95 loc) • 5.13 kB
JavaScript
import "./agent-scope-config-CDYpzA0r.mjs";
import { i as listAgentIds } from "./agent-roster-BXD1uMJD.mjs";
import { f as resolveEffectiveEnableState, u as normalizePluginsConfig } from "./config-state-DY_WJYue.mjs";
import "./agent-runtime-id-BZLMe-UU.mjs";
import { l as getActivePluginRegistry } from "./runtime-NsVZTERq.mjs";
import { t as resolveDefaultModelForAgent } from "./model-selection-config-BdeHEviO.mjs";
import "./model-selection-CC48fyGE.mjs";
import { s as resolveEffectiveAgentRuntime } from "./thinking-runtime--sshEpUp.mjs";
import { n as hasConfiguredGatewayAuthSecretInput } from "./auth-config-utils-G_ogHVLj.mjs";
import { a as resolvePairingGatewayUrl, i as resolveConfiguredPairingPublicUrl, t as PAIRING_GATEWAY_LOOPBACK_ERROR } from "./setup-code-B4wk7duA.mjs";
import os from "node:os";
//#region src/commands/doctor-node-hosting-preconditions.ts
const CHECK_ID = "core/doctor/node-hosting-preconditions";
function usesIdentityHeadersWithoutMachineCredentials(cfg) {
const hasToken = hasConfiguredGatewayAuthSecretInput(cfg, "gateway.auth.token");
const hasPassword = hasConfiguredGatewayAuthSecretInput(cfg, "gateway.auth.password");
if (hasToken || hasPassword) return false;
if (cfg.gateway?.auth?.mode === "trusted-proxy") return true;
return cfg.gateway?.tailscale?.mode === "serve" && cfg.gateway?.auth?.mode !== "password" && cfg.gateway?.auth?.mode !== "none" && cfg.gateway?.auth?.allowTailscale !== false;
}
async function lacksNodeOnboardingUrl(cfg) {
const bind = cfg.gateway?.bind ?? "loopback";
if (bind !== "loopback" && bind !== "auto") return false;
return (await resolvePairingGatewayUrl(cfg, {
env: process.env,
publicUrl: resolveConfiguredPairingPublicUrl(cfg),
networkInterfaces: os.networkInterfaces
})).error === PAIRING_GATEWAY_LOOPBACK_ERROR;
}
function lacksNodeOnboardingPlugin(cfg) {
return !resolveEffectiveEnableState({
id: "device-pair",
origin: "bundled",
config: normalizePluginsConfig(cfg.plugins),
rootConfig: cfg,
enabledByDefault: true
}).enabled;
}
function lacksDeviceCapableRuntimeRoute(cfg) {
const registry = getActivePluginRegistry();
return listAgentIds(cfg).every((agentId) => {
const model = resolveDefaultModelForAgent({
cfg,
agentId
});
const runtime = resolveEffectiveAgentRuntime({
cfg,
provider: model.provider,
modelId: model.model,
agentId
});
if (runtime === "openclaw") return false;
const harness = registry?.agentHarnesses.find((entry) => entry.harness.id === runtime)?.harness;
return harness !== void 0 && harness.cloudPlacement?.devicePlacement === void 0;
});
}
/** Collects config-only warnings for node authentication, onboarding, and worker ingress. */
async function collectNodeHostingPreconditionFindings(cfg) {
const findings = [];
if (lacksNodeOnboardingPlugin(cfg)) findings.push({
checkId: CHECK_ID,
severity: "warning",
message: "The device-pair plugin is not enabled; node onboarding join codes and openclaw connect are unavailable.",
path: "plugins.entries.device-pair.enabled",
requirement: "node-onboarding-plugin",
fixHint: "Set plugins.entries.device-pair.enabled: true, ensure device-pair is not denied or excluded by plugins.allow, then restart the Gateway."
});
if (lacksDeviceCapableRuntimeRoute(cfg)) findings.push({
checkId: CHECK_ID,
severity: "warning",
message: "No configured agent/model route resolves to a runtime that supports paired-device placement.",
path: "agents",
requirement: "device-session-runtime",
fixHint: "Select an agent/model route whose runtime supports paired-device placement, then ensure its plugin is enabled and its required node commands are explicitly allowed. Runtime policy is model/provider-scoped; whole-agent runtime keys are ignored. For a multi-agent roster, set agents.ownership: \"explicit\"."
});
if (usesIdentityHeadersWithoutMachineCredentials(cfg)) findings.push({
checkId: CHECK_ID,
severity: "warning",
message: "Gateway identity-header auth has no configured token/password path for machine clients; new node hosts cannot authenticate or become worker hosts.",
path: "gateway.auth",
requirement: "machine-client-auth",
fixHint: "Switch gateway.auth.mode to token and configure gateway.auth.token as a SecretRef so machine clients can authenticate as devices. Keep trusted-proxy only if machine clients use a clean loopback/direct gateway.auth.password path. For Access-fronted gateways, configure the node gateway.cloudflareAccess.clientId / clientSecret SecretInputs or set CF_ACCESS_CLIENT_ID / CF_ACCESS_CLIENT_SECRET before openclaw connect."
});
if (await lacksNodeOnboardingUrl(cfg)) findings.push({
checkId: CHECK_ID,
severity: "warning",
message: PAIRING_GATEWAY_LOOPBACK_ERROR,
path: "gateway.bind",
requirement: "node-onboarding-url",
fixHint: "If an edge proxy fronts node onboarding, allow /j/* and /__openclaw__/worker without edge identity auth, and preserve WebSocket upgrade on /__openclaw__/worker. Both routes enforce their own credentials."
});
return findings;
}
//#endregion
export { collectNodeHostingPreconditionFindings };