fix(update): suppress handoff newer-config warning (#81235)

Merged via squash.

Prepared head SHA: 61a5c975bf
Co-authored-by: giodl73-repo <giodl@microsoft.com>
Co-authored-by: galiniliev <5711535+galiniliev@users.noreply.github.com>
Reviewed-by: @galiniliev
This commit is contained in:
Gio Della-Libera
2026-05-12 22:01:21 -07:00
committed by GitHub
parent 94fdc56b64
commit f141a086fc
4 changed files with 25 additions and 5 deletions

View File

@@ -14,6 +14,7 @@ Docs: https://docs.openclaw.ai
- Limit hook CLI tool authority [AI]. (#81065) Thanks @pgondhi987.
- Require admin scope for node device token management [AI]. (#81067) Thanks @pgondhi987.
- Restrict chat sender allowlist matching [AI]. (#80898) Thanks @pgondhi987.
- Update: suppress the false newer-config warning during restart health probing after an update handoff, while keeping future-version mutation guards intact. (#78652)
- Sessions: redact persisted tool result detail metadata before writing transcripts so diagnostic secrets do not survive tool output redaction. (#80444) Thanks @nimbleenigma.
- Codex runtime: allow the official installed `@openclaw/codex` package to use its private task-runtime SDK helper, fixing `MODULE_NOT_FOUND` during migrated OpenAI/Codex beta runs.
- Codex migration: make Enter activate the highlighted checkbox row before continuing, so `Skip for now` and bulk-selection rows work even when planned items start preselected.

View File

@@ -8,6 +8,7 @@ const classifyPortListener = vi.hoisted(() =>
vi.fn<(_listener: unknown, _port: number) => PortListenerKind>(() => "gateway"),
);
const probeGateway = vi.hoisted(() => vi.fn());
const createConfigIO = vi.hoisted(() => vi.fn());
const readBestEffortConfig = vi.hoisted(() => vi.fn(async () => ({})));
const resolveGatewayProbeAuthSafeWithSecretInputs = vi.hoisted(() =>
vi.fn<(_opts: unknown) => Promise<{ auth: { token?: string; password?: string } }>>(async () => ({
@@ -26,9 +27,7 @@ vi.mock("../../gateway/probe.js", () => ({
}));
vi.mock("../../config/io.js", () => ({
createConfigIO: () => ({
readBestEffortConfig: () => readBestEffortConfig(),
}),
createConfigIO: (opts: unknown) => createConfigIO(opts),
}));
vi.mock("../../gateway/probe-auth.js", () => ({
@@ -139,6 +138,10 @@ describe("inspectGatewayRestart", () => {
inspectPortUsage.mockReset();
readBestEffortConfig.mockReset();
readBestEffortConfig.mockResolvedValue({});
createConfigIO.mockReset();
createConfigIO.mockReturnValue({
readBestEffortConfig: () => readBestEffortConfig(),
});
resolveGatewayProbeAuthSafeWithSecretInputs.mockReset();
resolveGatewayProbeAuthSafeWithSecretInputs.mockResolvedValue({ auth: {} });
inspectPortUsage.mockResolvedValue({
@@ -442,6 +445,13 @@ describe("inspectGatewayRestart", () => {
expect(authResolveInput.cfg?.gateway?.auth?.mode).toBe("token");
expect(authResolveInput.cfg?.gateway?.auth?.token).toBe("probe-token");
expect(authResolveInput.mode).toBe("local");
expect(createConfigIO).toHaveBeenCalledWith(
expect.objectContaining({
env: serviceEnv,
pluginValidation: "skip",
suppressFutureVersionWarning: true,
}),
);
const probeInput = firstCallArg(probeGateway) as {
auth?: { token?: string; password?: string };
env?: NodeJS.ProcessEnv;
@@ -637,6 +647,8 @@ describe("inspectGatewayRestart", () => {
});
it("annotates stopped-free early exits with the actual elapsed time", async () => {
Object.defineProperty(process, "platform", { value: "linux", configurable: true });
const snapshot = await waitForStoppedFreeGatewayRestart();
expect(snapshot.healthy).toBe(false);

View File

@@ -274,6 +274,7 @@ async function resolveGatewayRestartProbeAuth(
const cfg = await createConfigIO({
env: mergedEnv,
pluginValidation: "skip",
suppressFutureVersionWarning: true,
})
.readBestEffortConfig()
.catch((): OpenClawConfig => ({}));

View File

@@ -878,6 +878,7 @@ export type ConfigIoDeps = {
configPath?: string;
logger?: Pick<typeof console, "error" | "warn">;
measure?: ConfigSnapshotReadMeasure;
suppressFutureVersionWarning?: boolean;
};
function warnOnConfigMiskeys(raw: unknown, logger: Pick<typeof console, "warn">): void {
@@ -936,6 +937,7 @@ function normalizeDeps(overrides: ConfigIoDeps = {}): Required<ConfigIoDeps> {
configPath: overrides.configPath ?? "",
logger: overrides.logger ?? console,
measure: overrides.measure ?? (async (_name, run) => await run()),
suppressFutureVersionWarning: overrides.suppressFutureVersionWarning ?? false,
};
}
@@ -1609,7 +1611,9 @@ export function createConfigIO(
.join("\n");
deps.logger.warn(`Config warnings:\n${details}`);
}
warnIfConfigFromFuture(validated.config, deps.logger);
if (!deps.suppressFutureVersionWarning) {
warnIfConfigFromFuture(validated.config, deps.logger);
}
const cfg = retainRuntimeOnlyShippedPluginInstallConfigRecords(
materializeRuntimeConfig(validated.config, "load", {
manifestRegistry: pluginMetadataSnapshot?.manifestRegistry,
@@ -1816,7 +1820,9 @@ export function createConfigIO(
});
}
warnIfConfigFromFuture(validated.config, deps.logger);
if (!deps.suppressFutureVersionWarning) {
warnIfConfigFromFuture(validated.config, deps.logger);
}
const snapshotConfig = await deps.measure("config.snapshot.read.materialize", () =>
retainRuntimeOnlyShippedPluginInstallConfigRecords(
materializeRuntimeConfig(validated.config, "snapshot", {