Config: fail closed invalid config loads (#39071)

* Config: fail closed invalid config loads

* CLI: keep diagnostics on explicit best-effort config

* Tests: cover invalid config best-effort diagnostics

* Changelog: note invalid config fail-closed fix

* Status: pass best-effort config through status-all gateway RPCs

* CLI: pass config through gateway secret RPC

* CLI: skip plugin loading from invalid config

* Tests: align daemon token drift env precedence
This commit is contained in:
Vincent Koc
2026-03-07 20:48:13 -05:00
committed by GitHub
parent 1831dbb63f
commit 2c7fb54956
27 changed files with 178 additions and 71 deletions

View File

@@ -1,9 +1,11 @@
import type { Command } from "commander";
import type { OpenClawConfig } from "../../config/config.js";
import { callGateway } from "../../gateway/call.js";
import { GATEWAY_CLIENT_MODES, GATEWAY_CLIENT_NAMES } from "../../utils/message-channel.js";
import { withProgress } from "../progress.js";
export type GatewayRpcOpts = {
config?: OpenClawConfig;
url?: string;
token?: string;
password?: string;
@@ -30,6 +32,7 @@ export const callGatewayCli = async (method: string, opts: GatewayRpcOpts, param
},
async () =>
await callGateway({
config: opts.config,
url: opts.url,
token: opts.token,
password: opts.password,

View File

@@ -1,7 +1,7 @@
import type { Command } from "commander";
import { gatewayStatusCommand } from "../../commands/gateway-status.js";
import { formatHealthChannelLines, type HealthSummary } from "../../commands/health.js";
import { loadConfig } from "../../config/config.js";
import { readBestEffortConfig } from "../../config/config.js";
import { discoverGatewayBeacons } from "../../infra/bonjour-discovery.js";
import type { CostUsageSummary } from "../../infra/session-cost-usage.js";
import { resolveWideAreaDiscoveryDomain } from "../../infra/widearea-dns.js";
@@ -120,8 +120,9 @@ export function registerGatewayCli(program: Command) {
.action(async (method, opts, command) => {
await runGatewayCommand(async () => {
const rpcOpts = resolveGatewayRpcOptions(opts, command);
const config = await readBestEffortConfig();
const params = JSON.parse(String(opts.params ?? "{}"));
const result = await callGatewayCli(method, rpcOpts, params);
const result = await callGatewayCli(method, { ...rpcOpts, config }, params);
if (rpcOpts.json) {
defaultRuntime.log(JSON.stringify(result, null, 2));
return;
@@ -144,7 +145,8 @@ export function registerGatewayCli(program: Command) {
await runGatewayCommand(async () => {
const rpcOpts = resolveGatewayRpcOptions(opts, command);
const days = parseDaysOption(opts.days);
const result = await callGatewayCli("usage.cost", rpcOpts, { days });
const config = await readBestEffortConfig();
const result = await callGatewayCli("usage.cost", { ...rpcOpts, config }, { days });
if (rpcOpts.json) {
defaultRuntime.log(JSON.stringify(result, null, 2));
return;
@@ -165,7 +167,8 @@ export function registerGatewayCli(program: Command) {
.action(async (opts, command) => {
await runGatewayCommand(async () => {
const rpcOpts = resolveGatewayRpcOptions(opts, command);
const result = await callGatewayCli("health", rpcOpts);
const config = await readBestEffortConfig();
const result = await callGatewayCli("health", { ...rpcOpts, config });
if (rpcOpts.json) {
defaultRuntime.log(JSON.stringify(result, null, 2));
return;
@@ -211,7 +214,7 @@ export function registerGatewayCli(program: Command) {
.option("--json", "Output JSON", false)
.action(async (opts: GatewayDiscoverOpts) => {
await runGatewayCommand(async () => {
const cfg = loadConfig();
const cfg = await readBestEffortConfig();
const wideAreaDomain = resolveWideAreaDiscoveryDomain({
configDomain: cfg.discovery?.wideArea?.domain,
});