fix(cli): reject dangling config path escapes (#116738)

Co-authored-by: Peter Steinberger <steipete@macos.shared>
This commit is contained in:
Peter Steinberger
2026-07-31 03:16:06 -07:00
committed by GitHub
parent 7ea4129227
commit 454bf5ccd7
2 changed files with 43 additions and 2 deletions
+3 -2
View File
@@ -69,9 +69,10 @@ function parsePath(raw: string): PathSegment[] {
const ch = trimmed[i];
if (ch === "\\") {
const next = trimmed[i + 1];
if (next) {
current += next;
if (next === undefined) {
throw new Error(`Invalid path (trailing escape): ${raw}`);
}
current += next;
i += 2;
continue;
}
+40
View File
@@ -3346,6 +3346,31 @@ describe("config cli", () => {
args: ["config", "set", "gateway.[port]", "23456"],
error: "Invalid path (empty segment): gateway.[port]",
},
{
name: "rejects a trailing escape for config get before reading another key",
args: ["config", "get", "gateway.port\\"],
error: "Invalid path (trailing escape): gateway.port\\",
},
{
name: "rejects a trailing escape for config set before writing another key",
args: ["config", "set", "gateway.port\\", "23456"],
error: "Invalid path (trailing escape): gateway.port\\",
},
{
name: "rejects a trailing escape for config unset before deleting another key",
args: ["config", "unset", "gateway.port\\"],
error: "Invalid path (trailing escape): gateway.port\\",
},
{
name: "rejects a trailing escape for batch config set before writing another key",
args: [
"config",
"set",
"--batch-json",
JSON.stringify([{ path: "gateway.port\\", value: 23456 }]),
],
error: "Invalid path (trailing escape): gateway.port\\",
},
])("$name", async ({ args, error, list }) => {
if (list) {
const resolved = { agents: { list } } as unknown as OpenClawConfig;
@@ -3358,6 +3383,15 @@ describe("config cli", () => {
expect(mockWriteConfigFile).not.toHaveBeenCalled();
});
it.each(["gateway.port\\", "gateway.port\\ "])(
"rejects a trailing escape in shared config path %s",
(configPath) => {
expect(() => parseConfigSetPath(configPath)).toThrow(
`Invalid path (trailing escape): ${configPath}`,
);
},
);
it.each([
"agents.list[0]id",
"agents.list[0] id",
@@ -3396,6 +3430,12 @@ describe("config cli", () => {
["agents.list[0].id", ["agents", "list", "0", "id"]],
["agents.list[0][1]", ["agents", "list", "0", "1"]],
["[0]", ["0"]],
[" gateway.port ", ["gateway", "port"]],
["channels.discord.guilds.prod\\.guild", ["channels", "discord", "guilds", "prod.guild"]],
[
"channels.discord.guilds.prod\\\\.channels",
["channels", "discord", "guilds", "prod\\", "channels"],
],
])("preserves valid bracket path %s", (configPath, expected) => {
expect(parseConfigSetPath(configPath)).toEqual(expected);
});