mirror of
https://github.com/moltbot/moltbot.git
synced 2026-03-07 22:44:16 +00:00
fix(config): add actionable guidance for dmPolicy open allowFrom mismatch
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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({
|
||||
|
||||
Reference in New Issue
Block a user