Files
openclaw/src/config/legacy.ts
Mark L 5b06c8c6e3 fix(config): normalize gateway bind host aliases during migration (#30855)
* fix(config): normalize gateway bind host aliases during migration [AI-assisted]

* config(legacy): detect gateway.bind host aliases as legacy

* config(legacy): sanitize bind alias migration log output

* test(config): cover bind alias legacy detection and log escaping

* config(legacy): add source-literal gate to legacy rules

* config(legacy): make issue detection source-aware

* config(legacy): require source-literal gateway.bind alias detection

* config(io): pass parsed source to legacy issue detection

* test(config): cover resolved-only gateway.bind alias legacy detection

* changelog: format after #30855 rebase conflict resolution

---------

Co-authored-by: Vincent Koc <vincentkoc@ieee.org>
2026-03-01 19:53:00 -08:00

59 lines
1.8 KiB
TypeScript

import { LEGACY_CONFIG_MIGRATIONS } from "./legacy.migrations.js";
import { LEGACY_CONFIG_RULES } from "./legacy.rules.js";
import type { LegacyConfigIssue } from "./types.js";
function getPathValue(root: Record<string, unknown>, path: string[]): unknown {
let cursor: unknown = root;
for (const key of path) {
if (!cursor || typeof cursor !== "object") {
return undefined;
}
cursor = (cursor as Record<string, unknown>)[key];
}
return cursor;
}
export function findLegacyConfigIssues(raw: unknown, sourceRaw?: unknown): LegacyConfigIssue[] {
if (!raw || typeof raw !== "object") {
return [];
}
const root = raw as Record<string, unknown>;
const sourceRoot =
sourceRaw && typeof sourceRaw === "object" ? (sourceRaw as Record<string, unknown>) : root;
const issues: LegacyConfigIssue[] = [];
for (const rule of LEGACY_CONFIG_RULES) {
const cursor = getPathValue(root, rule.path);
if (cursor !== undefined && (!rule.match || rule.match(cursor, root))) {
if (rule.requireSourceLiteral) {
const sourceCursor = getPathValue(sourceRoot, rule.path);
if (sourceCursor === undefined) {
continue;
}
if (rule.match && !rule.match(sourceCursor, sourceRoot)) {
continue;
}
}
issues.push({ path: rule.path.join("."), message: rule.message });
}
}
return issues;
}
export function applyLegacyMigrations(raw: unknown): {
next: Record<string, unknown> | null;
changes: string[];
} {
if (!raw || typeof raw !== "object") {
return { next: null, changes: [] };
}
const next = structuredClone(raw) as Record<string, unknown>;
const changes: string[] = [];
for (const migration of LEGACY_CONFIG_MIGRATIONS) {
migration.apply(next, changes);
}
if (changes.length === 0) {
return { next: null, changes: [] };
}
return { next, changes };
}