Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
78 changes: 72 additions & 6 deletions src/lib/actions/sandbox/channel-status-config-core.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,12 @@ describe("showSandboxChannelStatus config comparison", () => {
telegram: {
accounts: {
default: {
groupPolicy: "allowlist",
groupPolicy: "open",
},
},
groups: {
"*": {
requireMention: true,
},
},
},
Expand Down Expand Up @@ -51,7 +56,7 @@ describe("showSandboxChannelStatus config comparison", () => {
required: false,
sourceEnv: "TELEGRAM_GROUP_POLICY",
statePath: "telegramConfig.groupPolicy",
value: "allowlist",
value: "open",
},
],
}),
Expand All @@ -68,19 +73,80 @@ describe("showSandboxChannelStatus config comparison", () => {
signals.find((signal) => signal.label === "Telegram group policy (TELEGRAM_GROUP_POLICY)"),
).toMatchObject({
severity: "ok",
detail: "allowlist",
detail: "open",
});
expect(
signals.find(
(signal) => signal.label === "Telegram group mention mode (TELEGRAM_REQUIRE_MENTION)",
),
).toBeUndefined();
).toMatchObject({
severity: "ok",
detail: "yes",
});
const dump = out_lines.join("\n");
expect(dump).toMatch(/Telegram group policy \(TELEGRAM_GROUP_POLICY\):\s+allowlist/);
expect(dump).toMatch(/Telegram group policy \(TELEGRAM_GROUP_POLICY\):\s+open/);
expect(dump).toMatch(/Telegram group mention mode \(TELEGRAM_REQUIRE_MENTION\):\s+yes/);
expect(dump).not.toMatch(/Telegram Bot Token/);
expect(dump).not.toMatch(/TELEGRAM_BOT_TOKEN/);
});

it("marks Telegram all-message mode ok when OpenClaw omits the groups stanza (#5691)", async () => {
const { deps } = makeDeps({
exec: () => ({
status: 0,
stdout: JSON.stringify({
channels: {
telegram: {
accounts: {
default: {
groupPolicy: "open",
},
},
},
},
}),
stderr: "",
}),
sandbox: entry(["telegram"], [], {
telegram: [
{
channelId: "telegram",
inputId: "requireMention",
kind: "config",
required: false,
sourceEnv: "TELEGRAM_REQUIRE_MENTION",
statePath: "telegramConfig.requireMention",
value: "0",
},
{
channelId: "telegram",
inputId: "groupPolicy",
kind: "config",
required: false,
sourceEnv: "TELEGRAM_GROUP_POLICY",
statePath: "telegramConfig.groupPolicy",
value: "open",
},
],
}),
appliedPresets: ["telegram"],
});
const result = await showSandboxChannelStatus("alpha", {
deps,
channel: "telegram",
});

const signals = result && "signals" in result ? result.signals : [];
expect(
signals.find(
(signal) => signal.label === "Telegram group mention mode (TELEGRAM_REQUIRE_MENTION)",
),
).toMatchObject({
severity: "ok",
detail: "no",
});
});

it("does not compare Hermes Telegram group policy when the manifest does not render it", async () => {
const { deps } = makeDeps({
exec: (_sandbox, command) =>
Expand Down Expand Up @@ -160,7 +226,7 @@ describe("showSandboxChannelStatus config comparison", () => {
),
).toMatchObject({
severity: "ok",
detail: "1",
detail: "yes",
});
expect(
signals.find((signal) => signal.label === "Telegram group policy (TELEGRAM_GROUP_POLICY)"),
Expand Down
28 changes: 22 additions & 6 deletions src/lib/actions/sandbox/channel-status-config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,11 @@ import type {
} from "../../messaging/manifest";
import type { DiagnosticSignal } from "../../sandbox/whatsapp-diagnostics";
import * as registry from "../../state/registry";
import { configInputDetail, configValuesEqual } from "./channel-status-config-values";
import {
booleanConfigValue,
configInputDetail,
configValuesEqual,
} from "./channel-status-config-values";

const CONFIG_STATUS_TIMEOUT_MS = 5_000;
const CONFIG_STATUS_MAX_SOURCE_BYTES = 64 * 1024;
Expand Down Expand Up @@ -107,7 +111,7 @@ function configInputSignal(
}

const comparisons = sources.map((source) =>
compareConfigSource(expected, source, sourceReads.sourceValues),
compareConfigSource(input, expected, source, sourceReads.sourceValues),
);
const checkedComparisons = comparisons.filter((comparison) => comparison.checked);
const hasMismatch = checkedComparisons.some((comparison) => !comparison.matches);
Expand Down Expand Up @@ -159,7 +163,7 @@ function expectedConfigValue(
if (planInputHasValue(planInput)) {
return {
value: planInput.value,
detail: configInputDetail(planInput.value),
detail: configInputDisplayDetail(input, planInput.value),
hasValue: true,
};
}
Expand All @@ -168,18 +172,29 @@ function expectedConfigValue(
if (defaultValue) {
return {
value: defaultValue,
detail: `${configInputDetail(defaultValue)} (default)`,
detail: `${configInputDisplayDetail(input, defaultValue)} (default)`,
hasValue: true,
};
}

return {
value: undefined,
detail: configInputDetail(undefined),
detail: configInputDisplayDetail(input, undefined),
hasValue: false,
};
}

function configInputDisplayDetail(
input: ChannelConfigInputSpec,
value: MessagingSerializableValue | undefined,
): string {
if (input.id === "requireMention" && input.envKey === "TELEGRAM_REQUIRE_MENTION") {
const booleanValue = value === undefined || value === null ? null : booleanConfigValue(value);
if (booleanValue !== null) return booleanValue ? "yes" : "no";
}
return configInputDetail(value);
}

interface ConfigRenderSource extends RenderedConfigVisibilityKey {
readonly resolvedTarget: string;
}
Expand Down Expand Up @@ -372,6 +387,7 @@ function parseRenderedConfigSource(
}

function compareConfigSource(
input: ChannelConfigInputSpec,
expected: ExpectedConfigValue,
source: ConfigRenderSource,
sourceValues: ReadonlyMap<string, ConfigSourceRead>,
Expand All @@ -397,7 +413,7 @@ function compareConfigSource(
matches,
detail: matches
? expected.detail
: `expected ${expected.detail}; rendered ${configInputDetail(actual.value)}`,
: `expected ${expected.detail}; rendered ${configInputDisplayDetail(input, actual.value)}`,
};
}

Expand Down
13 changes: 12 additions & 1 deletion src/lib/actions/sandbox/channel-status-telegram-policy.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,11 @@ describe("showSandboxChannelStatus Telegram group policy", () => {
groupPolicy: "open",
},
},
groups: {
"*": {
requireMention: true,
},
},
},
},
}),
Expand All @@ -41,10 +46,16 @@ describe("showSandboxChannelStatus Telegram group policy", () => {
signals.find(
(signal) => signal.label === "Telegram group mention mode (TELEGRAM_REQUIRE_MENTION)",
),
).toBeUndefined();
).toMatchObject({
severity: "ok",
detail: "yes (default)",
});
const dump = out_lines.join("\n");
expect(dump).toMatch(/Telegram User ID \(for DM access\) \(TELEGRAM_ALLOWED_IDS\):\s+not set/);
expect(dump).toMatch(/Telegram group policy \(TELEGRAM_GROUP_POLICY\):\s+open \(default\)/);
expect(dump).toMatch(
/Telegram group mention mode \(TELEGRAM_REQUIRE_MENTION\):\s+yes \(default\)/,
);
});

it("accepts Telegram disabled group policy from rendered config", async () => {
Expand Down
108 changes: 108 additions & 0 deletions src/lib/messaging/channels/telegram/rendered-config-parser.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
// SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
// SPDX-License-Identifier: Apache-2.0

import { describe, expect, it } from "vitest";

import { telegramManifest } from "./manifest";
import { telegramRenderedConfigParser } from "./rendered-config-parser";

describe("telegram rendered config parser", () => {
const openClawContext = {
agentId: "openclaw" as const,
manifest: telegramManifest,
inputs: [],
};

it("extracts OpenClaw wildcard group mention mode (#5691)", () => {
const requireMentionKey = telegramRenderedConfigParser
.listConfigVisibilityKeys(openClawContext)
.find((key) => key.key === "openclawGroupRequireMention");

expect(requireMentionKey).toBeDefined();
expect(
telegramRenderedConfigParser.getValue(requireMentionKey!, {
kind: "structured",
value: {
channels: {
telegram: {
accounts: {
default: {
groupPolicy: "open",
},
},
groups: {
"*": {
requireMention: true,
},
},
},
},
},
}),
).toBe(true);
});

it("treats missing OpenClaw groups as all-message mode when group policy is open (#5691)", () => {
const requireMentionKey = telegramRenderedConfigParser
.listConfigVisibilityKeys(openClawContext)
.find((key) => key.key === "openclawGroupRequireMention");

expect(requireMentionKey).toBeDefined();
expect(
telegramRenderedConfigParser.getValue(requireMentionKey!, {
kind: "structured",
value: {
channels: {
telegram: {
accounts: {
default: {
groupPolicy: "open",
},
},
},
},
},
}),
).toBe(false);
});

it("treats missing OpenClaw group policy as unknown mention mode (#5691)", () => {
const requireMentionKey = telegramRenderedConfigParser
.listConfigVisibilityKeys(openClawContext)
.find((key) => key.key === "openclawGroupRequireMention");

expect(requireMentionKey).toBeDefined();
expect(
telegramRenderedConfigParser.getValue(requireMentionKey!, {
kind: "structured",
value: {
channels: {
telegram: {
accounts: {
default: {},
},
},
},
},
}),
).toBeUndefined();
});

it("does not expose OpenClaw mention mode when group policy is not open", () => {
const keys = telegramRenderedConfigParser.listConfigVisibilityKeys({
...openClawContext,
inputs: [
{
channelId: "telegram",
inputId: "groupPolicy",
kind: "config",
required: false,
statePath: "telegramConfig.groupPolicy",
value: "allowlist",
},
],
});

expect(keys.find((key) => key.key === "openclawGroupRequireMention")).toBeUndefined();
});
});
Loading
Loading