

























11import { beforeEach, describe, expect, it, vi } from "vitest";
22import { isCommandFlagEnabled } from "../../config/commands.js";
33import type { OpenClawConfig } from "../../config/config.js";
4+import { REDACTED_SENTINEL } from "../../config/redact-snapshot.js";
45import type { MsgContext } from "../templating.js";
56import { handleBashChatCommand } from "./bash-command.js";
67import { requireGatewayClientScope } from "./command-gates.js";
@@ -129,6 +130,14 @@ vi.mock("../../config/runtime-overrides.js", () => ({
129130unsetConfigOverride: vi.fn(() => ({ ok: true, removed: true })),
130131}));
131132133+vi.mock("../../config/runtime-schema.js", async () => {
134+const actual =
135+await vi.importActual<typeof import("../../config/schema.js")>("../../config/schema.js");
136+return {
137+loadGatewayRuntimeConfigSchema: () => actual.buildConfigSchema(),
138+};
139+});
140+132141vi.mock("../../utils/message-channel.js", () => ({
133142isInternalMessageChannel: isInternalMessageChannelMock,
134143}));
@@ -354,6 +363,169 @@ describe("command gating", () => {
354363expect(debugResult?.reply?.text).toContain("Debug overrides");
355364});
356365366+it("redacts secret-shaped fields from full /config show replies", async () => {
367+readConfigFileSnapshotMock.mockResolvedValueOnce({
368+valid: true,
369+parsed: {
370+gateway: {
371+auth: {
372+mode: "token",
373+token: "OPENCLAW_CONFIG_SHOW_CANARY_TOKEN_65623",
374+password: "OPENCLAW_CONFIG_SHOW_CANARY_PASSWORD_65623",
375+},
376+bind: "127.0.0.1",
377+port: 3210,
378+},
379+models: {
380+providers: {
381+openai: {
382+apiKey: "OPENCLAW_CONFIG_SHOW_CANARY_API_KEY_65623",
383+baseUrl: "https://api.example.test",
384+models: [{ id: "gpt-test", name: "gpt-test" }],
385+},
386+},
387+},
388+browser: {
389+cdpUrl:
390+"wss://chrome.example.test/devtools?token=OPENCLAW_CONFIG_SHOW_CANARY_CDP_TOKEN_65623&apiKey=OPENCLAW_CONFIG_SHOW_CANARY_CDP_API_KEY_65623",
391+profiles: {
392+local: {
393+cdpUrl: "ws://localhost:9222",
394+},
395+remote: {
396+cdpUrl:
397+"wss://chrome.remote.example.test/devtools?apiKey=OPENCLAW_CONFIG_SHOW_CANARY_CDP_PROFILE_API_KEY_65623",
398+},
399+},
400+},
401+talk: {
402+providers: {
403+openai: {
404+apiKey: "OPENCLAW_CONFIG_SHOW_CANARY_API_KEY_65623",
405+baseUrl: "https://api.example.test",
406+model: "gpt-test",
407+},
408+},
409+},
410+channels: {
411+telegram: {
412+botToken: "1234567890TELEGRAM_BOT_TOKEN",
413+enabled: true,
414+},
415+slack: {
416+token: {
417+source: "env",
418+provider: "default",
419+id: "SLACK_BOT_TOKEN",
420+},
421+},
422+},
423+},
424+});
425+const params = buildParams("/config show", {
426+commands: { config: true, text: true },
427+channels: { whatsapp: { allowFrom: ["*"] } },
428+} as OpenClawConfig);
429+params.command.senderIsOwner = true;
430+431+const result = await handleConfigCommand(params, true);
432+const output = result?.reply?.text ?? "";
433+434+expect(output).toContain("gateway");
435+expect(output).toContain("token");
436+expect(output).toContain("password");
437+expect(output).toContain("apiKey");
438+expect(output).toContain("browser");
439+expect(output).toContain("cdpUrl");
440+expect(output).toContain(REDACTED_SENTINEL);
441+expect(output).not.toContain("OPENCLAW_CONFIG_SHOW_CANARY_TOKEN_65623");
442+expect(output).not.toContain("OPENCLAW_CONFIG_SHOW_CANARY_PASSWORD_65623");
443+expect(output).not.toContain("OPENCLAW_CONFIG_SHOW_CANARY_API_KEY_65623");
444+expect(output).not.toContain("OPENCLAW_CONFIG_SHOW_CANARY_CDP_TOKEN_65623");
445+expect(output).not.toContain("OPENCLAW_CONFIG_SHOW_CANARY_CDP_API_KEY_65623");
446+expect(output).not.toContain("OPENCLAW_CONFIG_SHOW_CANARY_CDP_PROFILE_API_KEY_65623");
447+expect(output).toContain('"mode": "token"');
448+expect(output).toContain('"bind": "127.0.0.1"');
449+expect(output).toContain('"port": 3210');
450+expect(output).toContain('"enabled": true');
451+expect(output).toContain('"model": "gpt-test"');
452+expect(output).toContain('"baseUrl": "https://api.example.test"');
453+expect(output).toContain('"cdpUrl": "ws://localhost:9222"');
454+});
455+456+it("redacts secret-shaped values from path-specific /config show replies", async () => {
457+readConfigFileSnapshotMock.mockResolvedValueOnce({
458+valid: true,
459+parsed: {
460+gateway: {
461+auth: {
462+mode: "token",
463+token: "OPENCLAW_CONFIG_SHOW_CANARY_TOKEN_65623",
464+},
465+},
466+},
467+});
468+const params = buildParams("/config show gateway.auth.token", {
469+commands: { config: true, text: true },
470+channels: { whatsapp: { allowFrom: ["*"] } },
471+} as OpenClawConfig);
472+params.command.senderIsOwner = true;
473+474+const result = await handleConfigCommand(params, true);
475+const output = result?.reply?.text ?? "";
476+477+expect(output).toContain("Config gateway.auth.token");
478+expect(output).toContain(REDACTED_SENTINEL);
479+expect(output).not.toContain("OPENCLAW_CONFIG_SHOW_CANARY_TOKEN_65623");
480+});
481+482+it("redacts browser cdpUrl query secrets from path-specific /config show replies", async () => {
483+readConfigFileSnapshotMock.mockResolvedValueOnce({
484+valid: true,
485+parsed: {
486+browser: {
487+cdpUrl:
488+"wss://chrome.example.test/devtools?token=OPENCLAW_CONFIG_SHOW_CANARY_CDP_TOKEN_65623&apiKey=OPENCLAW_CONFIG_SHOW_CANARY_CDP_API_KEY_65623",
489+},
490+},
491+});
492+const params = buildParams("/config show browser.cdpUrl", {
493+commands: { config: true, text: true },
494+channels: { whatsapp: { allowFrom: ["*"] } },
495+} as OpenClawConfig);
496+params.command.senderIsOwner = true;
497+498+const result = await handleConfigCommand(params, true);
499+const output = result?.reply?.text ?? "";
500+501+expect(output).toContain("Config browser.cdpUrl");
502+expect(output).toContain(REDACTED_SENTINEL);
503+expect(output).not.toContain("OPENCLAW_CONFIG_SHOW_CANARY_CDP_TOKEN_65623");
504+expect(output).not.toContain("OPENCLAW_CONFIG_SHOW_CANARY_CDP_API_KEY_65623");
505+});
506+507+it("redacts secret-shaped values from /config set acknowledgements", async () => {
508+readConfigFileSnapshotMock.mockResolvedValue({
509+valid: true,
510+parsed: { gateway: { auth: { mode: "token" } } },
511+});
512+const params = buildParams(
513+'/config set gateway.auth.token="OPENCLAW_CONFIG_SET_CANARY_TOKEN_65623"',
514+{
515+commands: { config: true, text: true },
516+channels: { whatsapp: { allowFrom: ["*"] } },
517+} as OpenClawConfig,
518+);
519+params.command.senderIsOwner = true;
520+521+const result = await handleConfigCommand(params, true);
522+const output = result?.reply?.text ?? "";
523+524+expect(output).toContain("Config updated: gateway.auth.token=");
525+expect(output).toContain(REDACTED_SENTINEL);
526+expect(output).not.toContain("OPENCLAW_CONFIG_SET_CANARY_TOKEN_65623");
527+});
528+357529it("returns explicit unauthorized replies for native privileged commands", async () => {
358530const configParams = buildParams("/config show", {
359531commands: { config: true, text: true },
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。