





















@@ -151,7 +151,7 @@ describe("gateway tool", () => {
151151const tool = requireGatewayTool(sessionKey);
152152153153const raw =
154-'{\n agents: { defaults: { workspace: "~/openclaw" } },\n tools: { exec: { ask: "on-miss", security: "allowlist" } }\n}\n';
154+'{\n agents: { defaults: { systemPromptOverride: "You are a terse assistant." } },\n tools: { exec: { ask: "on-miss", security: "allowlist" } }\n}\n';
155155await tool.execute("call2", {
156156action: "config.apply",
157157 raw,
@@ -209,7 +209,7 @@ describe("gateway tool", () => {
209209raw: '{ tools: { exec: { safeBins: ["bash"], safeBinProfiles: { bash: { allowedValueFlags: ["-c"] } } } } }',
210210}),
211211).rejects.toThrow(
212-"gateway config.patch cannot change protected config paths: tools.exec.safeBins, tools.exec.safeBinProfiles",
212+"gateway config.patch cannot change protected config paths: tools.exec.safeBinProfiles.bash.allowedValueFlags, tools.exec.safeBins",
213213);
214214expect(callGatewayTool).toHaveBeenCalledWith("config.get", expect.any(Object), {});
215215expect(callGatewayTool).not.toHaveBeenCalledWith(
@@ -373,7 +373,7 @@ describe("gateway tool", () => {
373373await expect(
374374tool.execute("call-missing-protected", {
375375action: "config.apply",
376-raw: '{ agents: { defaults: { workspace: "~/openclaw" } } }',
376+raw: '{ agents: { defaults: { systemPromptOverride: "You are a terse assistant." } } }',
377377}),
378378).rejects.toThrow(
379379"gateway config.apply cannot change protected config paths: tools.exec.ask, tools.exec.security",
@@ -405,6 +405,44 @@ describe("gateway tool", () => {
405405);
406406});
407407408+it("rejects config.patch when it rewrites gateway.remote.url", async () => {
409+const tool = requireGatewayTool();
410+411+await expect(
412+tool.execute("call-remote-redirect", {
413+action: "config.patch",
414+raw: '{ gateway: { remote: { url: "wss://attacker.example/collect" } } }',
415+}),
416+).rejects.toThrow(
417+"gateway config.patch cannot change protected config paths: gateway.remote.url",
418+);
419+expect(callGatewayTool).toHaveBeenCalledWith("config.get", expect.any(Object), {});
420+expect(callGatewayTool).not.toHaveBeenCalledWith(
421+"config.patch",
422+expect.any(Object),
423+expect.anything(),
424+);
425+});
426+427+it("rejects config.patch when it rewrites global tools policy", async () => {
428+const tool = requireGatewayTool();
429+430+await expect(
431+tool.execute("call-tools-policy", {
432+action: "config.patch",
433+raw: '{ tools: { allow: ["exec"], elevated: { enabled: true } } }',
434+}),
435+).rejects.toThrow(
436+"gateway config.patch cannot change protected config paths: tools.allow, tools.elevated.enabled",
437+);
438+expect(callGatewayTool).toHaveBeenCalledWith("config.get", expect.any(Object), {});
439+expect(callGatewayTool).not.toHaveBeenCalledWith(
440+"config.patch",
441+expect.any(Object),
442+expect.anything(),
443+);
444+});
445+408446it("rejects config.patch that enables dangerouslyDisableDeviceAuth", async () => {
409447const tool = requireGatewayTool();
410448@@ -413,7 +451,9 @@ describe("gateway tool", () => {
413451action: "config.patch",
414452raw: "{ gateway: { controlUi: { dangerouslyDisableDeviceAuth: true } } }",
415453}),
416-).rejects.toThrow("cannot enable dangerous config flags");
454+).rejects.toThrow(
455+"gateway config.patch cannot change protected config paths: gateway.controlUi.dangerouslyDisableDeviceAuth",
456+);
417457expect(callGatewayTool).not.toHaveBeenCalledWith(
418458"config.patch",
419459expect.any(Object),
@@ -429,7 +469,9 @@ describe("gateway tool", () => {
429469action: "config.patch",
430470raw: "{ hooks: { gmail: { allowUnsafeExternalContent: true } } }",
431471}),
432-).rejects.toThrow("cannot enable dangerous config flags");
472+).rejects.toThrow(
473+"gateway config.patch cannot change protected config paths: hooks.gmail.allowUnsafeExternalContent",
474+);
433475expect(callGatewayTool).not.toHaveBeenCalledWith(
434476"config.patch",
435477expect.any(Object),
@@ -445,7 +487,9 @@ describe("gateway tool", () => {
445487action: "config.patch",
446488raw: "{ tools: { exec: { applyPatch: { workspaceOnly: false } } } }",
447489}),
448-).rejects.toThrow("cannot enable dangerous config flags");
490+).rejects.toThrow(
491+"gateway config.patch cannot change protected config paths: tools.exec.applyPatch.workspaceOnly",
492+);
449493expect(callGatewayTool).not.toHaveBeenCalledWith(
450494"config.patch",
451495expect.any(Object),
@@ -461,7 +505,9 @@ describe("gateway tool", () => {
461505action: "config.patch",
462506raw: "{ gateway: { controlUi: { allowInsecureAuth: true } } }",
463507}),
464-).rejects.toThrow("cannot enable dangerous config flags");
508+).rejects.toThrow(
509+"gateway config.patch cannot change protected config paths: gateway.controlUi.allowInsecureAuth",
510+);
465511expect(callGatewayTool).not.toHaveBeenCalledWith(
466512"config.patch",
467513expect.any(Object),
@@ -477,7 +523,9 @@ describe("gateway tool", () => {
477523action: "config.patch",
478524raw: "{ gateway: { controlUi: { dangerouslyAllowHostHeaderOriginFallback: true } } }",
479525}),
480-).rejects.toThrow("cannot enable dangerous config flags");
526+).rejects.toThrow(
527+"gateway config.patch cannot change protected config paths: gateway.controlUi.dangerouslyAllowHostHeaderOriginFallback",
528+);
481529expect(callGatewayTool).not.toHaveBeenCalledWith(
482530"config.patch",
483531expect.any(Object),
@@ -502,7 +550,7 @@ describe("gateway tool", () => {
502550);
503551});
504552505-it("allows config.patch when a dangerous flag is already enabled and stays enabled", async () => {
553+it("allows config.patch on allowlisted paths when a dangerous flag is already enabled", async () => {
506554vi.mocked(callGatewayTool).mockImplementationOnce(async (method: string) => {
507555if (method === "config.get") {
508556return {
@@ -518,8 +566,7 @@ describe("gateway tool", () => {
518566const sessionKey = "agent:main:whatsapp:dm:+15555550123";
519567const tool = requireGatewayTool(sessionKey);
520568521-const raw =
522-'{ hooks: { gmail: { allowUnsafeExternalContent: true } }, agents: { defaults: { workspace: "~/test" } } }';
569+const raw = '{ agents: { defaults: { systemPromptOverride: "You are a terse assistant." } } }';
523570await tool.execute("call-keep-dangerous", {
524571action: "config.patch",
525572 raw,
@@ -540,7 +587,9 @@ describe("gateway tool", () => {
540587action: "config.apply",
541588raw: '{ tools: { exec: { ask: "on-miss", security: "allowlist", applyPatch: { workspaceOnly: false } } } }',
542589}),
543-).rejects.toThrow("cannot enable dangerous config flags");
590+).rejects.toThrow(
591+"gateway config.apply cannot change protected config paths: tools.exec.applyPatch.workspaceOnly",
592+);
544593expect(callGatewayTool).not.toHaveBeenCalledWith(
545594"config.apply",
546595expect.any(Object),
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。