fix(config): add actionable guidance for dmPolicy open allowFrom mismatch

This commit is contained in:
chilu18
2026-02-23 20:18:26 +00:00
parent 5a475259bb
commit d3bfbdec5d
2 changed files with 52 additions and 1 deletions

View File

@@ -71,6 +71,9 @@ const SHELL_ENV_EXPECTED_KEYS = [
"OPENCLAW_GATEWAY_PASSWORD",
];
const OPEN_DM_POLICY_ALLOW_FROM_RE =
/^(?<policyPath>[a-z0-9_.-]+)\s*=\s*"open"\s+requires\s+(?<allowPath>[a-z0-9_.-]+)(?:\s+\(or\s+[a-z0-9_.-]+\))?\s+to include "\*"$/i;
const CONFIG_AUDIT_LOG_FILENAME = "config-audit.jsonl";
const loggedInvalidConfigs = new Set<string>();
@@ -136,6 +139,27 @@ function hashConfigRaw(raw: string | null): string {
.digest("hex");
}
function formatConfigValidationFailure(pathLabel: string, issueMessage: string): string {
const match = issueMessage.match(OPEN_DM_POLICY_ALLOW_FROM_RE);
const policyPath = match?.groups?.policyPath?.trim();
const allowPath = match?.groups?.allowPath?.trim();
if (!policyPath || !allowPath) {
return `Config validation failed: ${pathLabel}: ${issueMessage}`;
}
return [
`Config validation failed: ${pathLabel}`,
"",
`Configuration mismatch: ${policyPath} is "open", but ${allowPath} does not include "*".`,
"",
"Fix with:",
` openclaw config set ${allowPath} '["*"]'`,
"",
"Or switch policy:",
` openclaw config set ${policyPath} "pairing"`,
].join("\n");
}
function isNumericPathSegment(raw: string): boolean {
return /^[0-9]+$/.test(raw);
}
@@ -999,7 +1023,8 @@ export function createConfigIO(overrides: ConfigIoDeps = {}) {
if (!validated.ok) {
const issue = validated.issues[0];
const pathLabel = issue?.path ? issue.path : "<root>";
throw new Error(`Config validation failed: ${pathLabel}: ${issue?.message ?? "invalid"}`);
const issueMessage = issue?.message ?? "invalid";
throw new Error(formatConfigValidationFailure(pathLabel, issueMessage));
}
if (validated.warnings.length > 0) {
const details = validated.warnings

View File

@@ -96,6 +96,32 @@ describe("config io write", () => {
});
});
it('shows actionable guidance for dmPolicy="open" without wildcard allowFrom', async () => {
await withTempHome("openclaw-config-io-", async (home) => {
const io = createConfigIO({
env: {} as NodeJS.ProcessEnv,
homedir: () => home,
logger: silentLogger,
});
const invalidConfig = {
channels: {
telegram: {
dmPolicy: "open",
allowFrom: [],
},
},
};
await expect(io.writeConfigFile(invalidConfig)).rejects.toThrow(
"openclaw config set channels.telegram.allowFrom '[\"*\"]'",
);
await expect(io.writeConfigFile(invalidConfig)).rejects.toThrow(
'openclaw config set channels.telegram.dmPolicy "pairing"',
);
});
});
it("honors explicit unset paths when schema defaults would otherwise reappear", async () => {
await withTempHome("openclaw-config-io-", async (home) => {
const { configPath, io, snapshot } = await writeConfigAndCreateIo({