From 16e187ba0fb80715ddec12a35940a2e605ef30cb Mon Sep 17 00:00:00 2001 From: Gustavo Madeira Santana Date: Fri, 17 Apr 2026 02:31:59 -0400 Subject: [PATCH] CLI: sanitize channel removal labels --- CHANGELOG.md | 1 + src/commands/configure.channels.test.ts | 33 +++++++++++++++++++++++++ src/commands/configure.channels.ts | 3 ++- 3 files changed, 36 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7a2544280d2..2ac54687b96 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -26,6 +26,7 @@ Docs: https://docs.openclaw.ai - Matrix: fix `sessions_spawn --thread` subagent session spawning — thread binding creation, cleanup on session end, and completion-message delivery target resolution now work end-to-end. (#67643) Thanks @eejohnso-ops and @gumadeiras. - macOS/webchat: enable Undo and Redo in the composer text input by turning on the native `NSTextView` undo manager. (#34962) Thanks @tylerbittner. - macOS/remote SSH: require an already-trusted host key on the macOS remote command, gateway probe, port tunnel, and pairing probe paths by switching `StrictHostKeyChecking=accept-new` to `StrictHostKeyChecking=yes` and centralizing the shared SSH option fragments in `CommandResolver`, so first-time macOS remote connections no longer silently accept an unknown host key and must be trusted ahead of time via `~/.ssh/known_hosts`. (#68199) +- CLI/configure: show the channel picker before probing statuses and let remove mode delete configured channel blocks directly from config. (#68007) Thanks @gumadeiras. ## 2026.4.15 diff --git a/src/commands/configure.channels.test.ts b/src/commands/configure.channels.test.ts index f4d19533b08..7653a3675be 100644 --- a/src/commands/configure.channels.test.ts +++ b/src/commands/configure.channels.test.ts @@ -79,4 +79,37 @@ describe("removeChannelConfigWizard", () => { "Channel removed", ); }); + + it("sanitizes unknown channel keys before rendering prompts", async () => { + const unsafeChannel = "bad\u001B[31m\nkey\u0007"; + select.mockResolvedValueOnce(unsafeChannel).mockResolvedValueOnce("done"); + + const next = await removeChannelConfigWizard( + { + channels: { + [unsafeChannel]: { token: "secret" }, + telegram: { token: "secret" }, + }, + } as never, + {} as never, + ); + + expect(select).toHaveBeenCalledWith( + expect.objectContaining({ + options: expect.arrayContaining([ + expect.objectContaining({ value: unsafeChannel, label: "bad\\nkey" }), + ]), + }), + ); + expect(confirm).toHaveBeenCalledWith( + expect.objectContaining({ + message: "Delete bad\\nkey configuration from ~/.openclaw/openclaw.json?", + }), + ); + expect(next.channels).toEqual({ telegram: { token: "secret" } }); + expect(note).toHaveBeenCalledWith( + "bad\\nkey removed from config.\nNote: credentials/sessions on disk are unchanged.", + "Channel removed", + ); + }); }); diff --git a/src/commands/configure.channels.ts b/src/commands/configure.channels.ts index f221d761e43..4d5e5a0943f 100644 --- a/src/commands/configure.channels.ts +++ b/src/commands/configure.channels.ts @@ -4,6 +4,7 @@ import { CONFIG_PATH } from "../config/config.js"; import type { OpenClawConfig } from "../config/types.openclaw.js"; import type { RuntimeEnv } from "../runtime.js"; import { note } from "../terminal/note.js"; +import { sanitizeTerminalText } from "../terminal/safe-text.js"; import { shortenHomePath } from "../utils.js"; import { confirm, select } from "./configure.shared.js"; import { guardCancel } from "./onboard-helpers.js"; @@ -24,7 +25,7 @@ function listConfiguredChannelRemovalChoices( return Object.keys(channels) .map((id) => ({ id, - label: labelsById.get(id) ?? id, + label: labelsById.get(id) ?? sanitizeTerminalText(id), })) .toSorted(compareChannelRemovalChoices); }