test: extract outbound policy coverage

This commit is contained in:
Peter Steinberger 2026-03-13 20:51:45 +00:00
parent 9747da8682
commit cd72fa6e77
2 changed files with 127 additions and 62 deletions

View File

@ -0,0 +1,127 @@
import { describe, expect, it } from "vitest";
import type { OpenClawConfig } from "../../config/config.js";
import {
applyCrossContextDecoration,
buildCrossContextDecoration,
enforceCrossContextPolicy,
shouldApplyCrossContextMarker,
} from "./outbound-policy.js";
const slackConfig = {
channels: {
slack: {
botToken: "xoxb-test",
appToken: "xapp-test",
},
},
} as OpenClawConfig;
const discordConfig = {
channels: {
discord: {},
},
} as OpenClawConfig;
describe("outbound policy helpers", () => {
it("allows cross-provider sends when enabled", () => {
const cfg = {
...slackConfig,
tools: {
message: { crossContext: { allowAcrossProviders: true } },
},
} as OpenClawConfig;
expect(() =>
enforceCrossContextPolicy({
cfg,
channel: "telegram",
action: "send",
args: { to: "telegram:@ops" },
toolContext: { currentChannelId: "C12345678", currentChannelProvider: "slack" },
}),
).not.toThrow();
});
it("blocks cross-provider sends when not allowed", () => {
expect(() =>
enforceCrossContextPolicy({
cfg: slackConfig,
channel: "telegram",
action: "send",
args: { to: "telegram:@ops" },
toolContext: { currentChannelId: "C12345678", currentChannelProvider: "slack" },
}),
).toThrow(/target provider "telegram" while bound to "slack"/);
});
it("blocks same-provider cross-context sends when allowWithinProvider is false", () => {
const cfg = {
...slackConfig,
tools: {
message: { crossContext: { allowWithinProvider: false } },
},
} as OpenClawConfig;
expect(() =>
enforceCrossContextPolicy({
cfg,
channel: "slack",
action: "send",
args: { to: "C999" },
toolContext: { currentChannelId: "C123", currentChannelProvider: "slack" },
}),
).toThrow(/target="C999" while bound to "C123"/);
});
it("uses components when available and preferred", async () => {
const decoration = await buildCrossContextDecoration({
cfg: discordConfig,
channel: "discord",
target: "123",
toolContext: { currentChannelId: "C12345678", currentChannelProvider: "discord" },
});
expect(decoration).not.toBeNull();
const applied = applyCrossContextDecoration({
message: "hello",
decoration: decoration!,
preferComponents: true,
});
expect(applied.usedComponents).toBe(true);
expect(applied.componentsBuilder).toBeDefined();
expect(applied.componentsBuilder?.("hello").length).toBeGreaterThan(0);
expect(applied.message).toBe("hello");
});
it("returns null when decoration is skipped and falls back to text markers", async () => {
await expect(
buildCrossContextDecoration({
cfg: discordConfig,
channel: "discord",
target: "123",
toolContext: {
currentChannelId: "C12345678",
currentChannelProvider: "discord",
skipCrossContextDecoration: true,
},
}),
).resolves.toBeNull();
const applied = applyCrossContextDecoration({
message: "hello",
decoration: { prefix: "[from ops] ", suffix: " [cc]" },
preferComponents: true,
});
expect(applied).toEqual({
message: "[from ops] hello [cc]",
usedComponents: false,
});
});
it("marks only supported cross-context actions", () => {
expect(shouldApplyCrossContextMarker("send")).toBe(true);
expect(shouldApplyCrossContextMarker("thread-reply")).toBe(true);
expect(shouldApplyCrossContextMarker("thread-create")).toBe(false);
});
});

View File

@ -16,11 +16,6 @@ import {
moveToFailed,
recoverPendingDeliveries,
} from "./delivery-queue.js";
import {
applyCrossContextDecoration,
buildCrossContextDecoration,
enforceCrossContextPolicy,
} from "./outbound-policy.js";
import { resolveOutboundSessionRoute } from "./outbound-session.js";
import { runResolveOutboundTargetCoreTests } from "./targets.shared-test.js";
@ -603,63 +598,6 @@ describe("delivery-queue", () => {
});
});
const slackConfig = {
channels: {
slack: {
botToken: "xoxb-test",
appToken: "xapp-test",
},
},
} as OpenClawConfig;
const discordConfig = {
channels: {
discord: {},
},
} as OpenClawConfig;
describe("outbound policy", () => {
it("allows cross-provider sends when enabled", () => {
const cfg = {
...slackConfig,
tools: {
message: { crossContext: { allowAcrossProviders: true } },
},
} as OpenClawConfig;
expect(() =>
enforceCrossContextPolicy({
cfg,
channel: "telegram",
action: "send",
args: { to: "telegram:@ops" },
toolContext: { currentChannelId: "C12345678", currentChannelProvider: "slack" },
}),
).not.toThrow();
});
it("uses components when available and preferred", async () => {
const decoration = await buildCrossContextDecoration({
cfg: discordConfig,
channel: "discord",
target: "123",
toolContext: { currentChannelId: "C12345678", currentChannelProvider: "discord" },
});
expect(decoration).not.toBeNull();
const applied = applyCrossContextDecoration({
message: "hello",
decoration: decoration!,
preferComponents: true,
});
expect(applied.usedComponents).toBe(true);
expect(applied.componentsBuilder).toBeDefined();
expect(applied.componentsBuilder?.("hello").length).toBeGreaterThan(0);
expect(applied.message).toBe("hello");
});
});
describe("resolveOutboundSessionRoute", () => {
const baseConfig = {} as OpenClawConfig;