mirror of
https://github.com/openclaw/openclaw.git
synced 2026-04-29 18:12:52 +00:00
test: use channel schemas for webhook validation
This commit is contained in:
@@ -1,165 +1,122 @@
|
||||
import { describe, expect, it } from "vitest";
|
||||
import { validateConfigObject } from "./validation.js";
|
||||
import { SlackConfigSchema } from "./zod-schema.providers-core.js";
|
||||
|
||||
function expectSlackConfigValid(config: unknown) {
|
||||
expect(SlackConfigSchema.safeParse(config).success).toBe(true);
|
||||
}
|
||||
|
||||
function expectSlackConfigIssue(config: unknown, path: string) {
|
||||
const res = SlackConfigSchema.safeParse(config);
|
||||
expect(res.success).toBe(false);
|
||||
if (!res.success) {
|
||||
expect(res.error.issues.some((issue) => issue.path.join(".").includes(path))).toBe(true);
|
||||
}
|
||||
}
|
||||
|
||||
describe("channel token and HTTP validation", () => {
|
||||
describe("Slack token fields", () => {
|
||||
it("accepts user token config fields", () => {
|
||||
const res = validateConfigObject({
|
||||
channels: {
|
||||
slack: {
|
||||
botToken: "xoxb-any",
|
||||
appToken: "xapp-any",
|
||||
userToken: "xoxp-any",
|
||||
userTokenReadOnly: false,
|
||||
},
|
||||
},
|
||||
expectSlackConfigValid({
|
||||
botToken: "xoxb-any",
|
||||
appToken: "xapp-any",
|
||||
userToken: "xoxp-any",
|
||||
userTokenReadOnly: false,
|
||||
});
|
||||
expect(res.ok).toBe(true);
|
||||
});
|
||||
|
||||
it("accepts account-level user token config", () => {
|
||||
const res = validateConfigObject({
|
||||
channels: {
|
||||
slack: {
|
||||
accounts: {
|
||||
work: {
|
||||
botToken: "xoxb-any",
|
||||
appToken: "xapp-any",
|
||||
userToken: "xoxp-any",
|
||||
userTokenReadOnly: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
expect(res.ok).toBe(true);
|
||||
});
|
||||
|
||||
it("rejects invalid userTokenReadOnly types", () => {
|
||||
const res = validateConfigObject({
|
||||
channels: {
|
||||
slack: {
|
||||
expectSlackConfigValid({
|
||||
accounts: {
|
||||
work: {
|
||||
botToken: "xoxb-any",
|
||||
appToken: "xapp-any",
|
||||
userToken: "xoxp-any",
|
||||
userTokenReadOnly: "no" as any,
|
||||
userTokenReadOnly: true,
|
||||
},
|
||||
},
|
||||
});
|
||||
expect(res.ok).toBe(false);
|
||||
if (!res.ok) {
|
||||
expect(res.issues.some((iss) => iss.path.includes("userTokenReadOnly"))).toBe(true);
|
||||
}
|
||||
});
|
||||
|
||||
it("rejects invalid userTokenReadOnly types", () => {
|
||||
expectSlackConfigIssue(
|
||||
{
|
||||
botToken: "xoxb-any",
|
||||
appToken: "xapp-any",
|
||||
userToken: "xoxp-any",
|
||||
userTokenReadOnly: "no",
|
||||
},
|
||||
"userTokenReadOnly",
|
||||
);
|
||||
});
|
||||
|
||||
it("rejects invalid userToken types", () => {
|
||||
const res = validateConfigObject({
|
||||
channels: {
|
||||
slack: {
|
||||
botToken: "xoxb-any",
|
||||
appToken: "xapp-any",
|
||||
userToken: 123 as any,
|
||||
},
|
||||
expectSlackConfigIssue(
|
||||
{
|
||||
botToken: "xoxb-any",
|
||||
appToken: "xapp-any",
|
||||
userToken: 123,
|
||||
},
|
||||
});
|
||||
expect(res.ok).toBe(false);
|
||||
if (!res.ok) {
|
||||
expect(res.issues.some((iss) => iss.path.includes("userToken"))).toBe(true);
|
||||
}
|
||||
"userToken",
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe("Slack HTTP mode", () => {
|
||||
it("accepts HTTP mode when signing secret is configured", () => {
|
||||
const res = validateConfigObject({
|
||||
channels: {
|
||||
slack: {
|
||||
mode: "http",
|
||||
signingSecret: "secret",
|
||||
},
|
||||
},
|
||||
expectSlackConfigValid({
|
||||
mode: "http",
|
||||
signingSecret: "secret",
|
||||
});
|
||||
expect(res.ok).toBe(true);
|
||||
});
|
||||
|
||||
it("accepts HTTP mode when signing secret is configured as SecretRef", () => {
|
||||
const res = validateConfigObject({
|
||||
channels: {
|
||||
slack: {
|
||||
mode: "http",
|
||||
signingSecret: { source: "env", provider: "default", id: "SLACK_SIGNING_SECRET" },
|
||||
},
|
||||
},
|
||||
expectSlackConfigValid({
|
||||
mode: "http",
|
||||
signingSecret: { source: "env", provider: "default", id: "SLACK_SIGNING_SECRET" },
|
||||
});
|
||||
expect(res.ok).toBe(true);
|
||||
});
|
||||
|
||||
it("rejects HTTP mode without signing secret", () => {
|
||||
const res = validateConfigObject({
|
||||
channels: {
|
||||
slack: {
|
||||
expectSlackConfigIssue({ mode: "http" }, "signingSecret");
|
||||
});
|
||||
|
||||
it("accepts account HTTP mode when base signing secret is set", () => {
|
||||
expectSlackConfigValid({
|
||||
signingSecret: "secret",
|
||||
accounts: {
|
||||
ops: {
|
||||
mode: "http",
|
||||
},
|
||||
},
|
||||
});
|
||||
expect(res.ok).toBe(false);
|
||||
if (!res.ok) {
|
||||
expect(res.issues[0]?.path).toBe("channels.slack.signingSecret");
|
||||
}
|
||||
});
|
||||
|
||||
it("accepts account HTTP mode when base signing secret is set", () => {
|
||||
const res = validateConfigObject({
|
||||
channels: {
|
||||
slack: {
|
||||
signingSecret: "secret",
|
||||
accounts: {
|
||||
ops: {
|
||||
mode: "http",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
expect(res.ok).toBe(true);
|
||||
});
|
||||
|
||||
it("accepts account HTTP mode when account signing secret is set as SecretRef", () => {
|
||||
const res = validateConfigObject({
|
||||
channels: {
|
||||
slack: {
|
||||
accounts: {
|
||||
ops: {
|
||||
mode: "http",
|
||||
signingSecret: {
|
||||
source: "env",
|
||||
provider: "default",
|
||||
id: "SLACK_OPS_SIGNING_SECRET",
|
||||
},
|
||||
},
|
||||
expectSlackConfigValid({
|
||||
accounts: {
|
||||
ops: {
|
||||
mode: "http",
|
||||
signingSecret: {
|
||||
source: "env",
|
||||
provider: "default",
|
||||
id: "SLACK_OPS_SIGNING_SECRET",
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
expect(res.ok).toBe(true);
|
||||
});
|
||||
|
||||
it("rejects account HTTP mode without signing secret", () => {
|
||||
const res = validateConfigObject({
|
||||
channels: {
|
||||
slack: {
|
||||
accounts: {
|
||||
ops: {
|
||||
mode: "http",
|
||||
},
|
||||
expectSlackConfigIssue(
|
||||
{
|
||||
accounts: {
|
||||
ops: {
|
||||
mode: "http",
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
expect(res.ok).toBe(false);
|
||||
if (!res.ok) {
|
||||
expect(res.issues[0]?.path).toBe("channels.slack.accounts.ops.signingSecret");
|
||||
}
|
||||
"accounts.ops.signingSecret",
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,84 +1,55 @@
|
||||
import { describe, expect, it } from "vitest";
|
||||
import { validateConfigObject } from "./validation.js";
|
||||
import { TelegramConfigSchema } from "./zod-schema.providers-core.js";
|
||||
|
||||
function expectTelegramConfigValid(config: unknown) {
|
||||
expect(TelegramConfigSchema.safeParse(config).success).toBe(true);
|
||||
}
|
||||
|
||||
function expectTelegramConfigIssue(config: unknown, path: string) {
|
||||
const res = TelegramConfigSchema.safeParse(config);
|
||||
expect(res.success).toBe(false);
|
||||
if (!res.success) {
|
||||
expect(res.error.issues[0]?.path.join(".")).toBe(path);
|
||||
}
|
||||
}
|
||||
|
||||
describe("channel webhook and actions validation", () => {
|
||||
describe("Telegram poll actions", () => {
|
||||
it("accepts channels.telegram.actions.poll", () => {
|
||||
const res = validateConfigObject({
|
||||
channels: {
|
||||
telegram: {
|
||||
actions: {
|
||||
poll: false,
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
expect(res.ok).toBe(true);
|
||||
expectTelegramConfigValid({ actions: { poll: false } });
|
||||
});
|
||||
|
||||
it("accepts channels.telegram.accounts.<id>.actions.poll", () => {
|
||||
const res = validateConfigObject({
|
||||
channels: {
|
||||
telegram: {
|
||||
accounts: {
|
||||
ops: {
|
||||
actions: {
|
||||
poll: false,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
expect(res.ok).toBe(true);
|
||||
expectTelegramConfigValid({ accounts: { ops: { actions: { poll: false } } } });
|
||||
});
|
||||
});
|
||||
|
||||
describe("Telegram webhookPort", () => {
|
||||
it("accepts a positive webhookPort", () => {
|
||||
const res = validateConfigObject({
|
||||
channels: {
|
||||
telegram: {
|
||||
webhookUrl: "https://example.com/telegram-webhook",
|
||||
webhookSecret: "secret",
|
||||
webhookPort: 8787,
|
||||
},
|
||||
},
|
||||
expectTelegramConfigValid({
|
||||
webhookUrl: "https://example.com/telegram-webhook",
|
||||
webhookSecret: "secret",
|
||||
webhookPort: 8787,
|
||||
});
|
||||
expect(res.ok).toBe(true);
|
||||
});
|
||||
|
||||
it("accepts webhookPort set to 0 for ephemeral port binding", () => {
|
||||
const res = validateConfigObject({
|
||||
channels: {
|
||||
telegram: {
|
||||
webhookUrl: "https://example.com/telegram-webhook",
|
||||
webhookSecret: "secret",
|
||||
webhookPort: 0,
|
||||
},
|
||||
},
|
||||
expectTelegramConfigValid({
|
||||
webhookUrl: "https://example.com/telegram-webhook",
|
||||
webhookSecret: "secret",
|
||||
webhookPort: 0,
|
||||
});
|
||||
expect(res.ok).toBe(true);
|
||||
});
|
||||
|
||||
it("rejects negative webhookPort", () => {
|
||||
const res = validateConfigObject({
|
||||
channels: {
|
||||
telegram: {
|
||||
webhookUrl: "https://example.com/telegram-webhook",
|
||||
webhookSecret: "secret",
|
||||
webhookPort: -1,
|
||||
},
|
||||
expectTelegramConfigIssue(
|
||||
{
|
||||
webhookUrl: "https://example.com/telegram-webhook",
|
||||
webhookSecret: "secret",
|
||||
webhookPort: -1,
|
||||
},
|
||||
});
|
||||
expect(res.ok).toBe(false);
|
||||
if (!res.ok) {
|
||||
expect(res.issues.some((issue) => issue.path === "channels.telegram.webhookPort")).toBe(
|
||||
true,
|
||||
);
|
||||
}
|
||||
"webhookPort",
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -87,34 +58,28 @@ describe("channel webhook and actions validation", () => {
|
||||
{
|
||||
name: "webhookUrl when webhookSecret is configured",
|
||||
config: {
|
||||
telegram: {
|
||||
webhookUrl: "https://example.com/telegram-webhook",
|
||||
webhookSecret: "secret",
|
||||
},
|
||||
webhookUrl: "https://example.com/telegram-webhook",
|
||||
webhookSecret: "secret",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "webhookUrl when webhookSecret is configured as SecretRef",
|
||||
config: {
|
||||
telegram: {
|
||||
webhookUrl: "https://example.com/telegram-webhook",
|
||||
webhookSecret: {
|
||||
source: "env",
|
||||
provider: "default",
|
||||
id: "TELEGRAM_WEBHOOK_SECRET",
|
||||
},
|
||||
webhookUrl: "https://example.com/telegram-webhook",
|
||||
webhookSecret: {
|
||||
source: "env",
|
||||
provider: "default",
|
||||
id: "TELEGRAM_WEBHOOK_SECRET",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "account webhookUrl when base webhookSecret is configured",
|
||||
config: {
|
||||
telegram: {
|
||||
webhookSecret: "secret",
|
||||
accounts: {
|
||||
ops: {
|
||||
webhookUrl: "https://example.com/telegram-webhook",
|
||||
},
|
||||
webhookSecret: "secret",
|
||||
accounts: {
|
||||
ops: {
|
||||
webhookUrl: "https://example.com/telegram-webhook",
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -122,54 +87,42 @@ describe("channel webhook and actions validation", () => {
|
||||
{
|
||||
name: "account webhookUrl when account webhookSecret is configured as SecretRef",
|
||||
config: {
|
||||
telegram: {
|
||||
accounts: {
|
||||
ops: {
|
||||
webhookUrl: "https://example.com/telegram-webhook",
|
||||
webhookSecret: {
|
||||
source: "env",
|
||||
provider: "default",
|
||||
id: "TELEGRAM_OPS_WEBHOOK_SECRET",
|
||||
},
|
||||
accounts: {
|
||||
ops: {
|
||||
webhookUrl: "https://example.com/telegram-webhook",
|
||||
webhookSecret: {
|
||||
source: "env",
|
||||
provider: "default",
|
||||
id: "TELEGRAM_OPS_WEBHOOK_SECRET",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
] as const)("accepts $name", ({ config }) => {
|
||||
expect(validateConfigObject({ channels: config }).ok).toBe(true);
|
||||
expectTelegramConfigValid(config);
|
||||
});
|
||||
|
||||
it("rejects webhookUrl without webhookSecret", () => {
|
||||
const res = validateConfigObject({
|
||||
channels: {
|
||||
telegram: {
|
||||
webhookUrl: "https://example.com/telegram-webhook",
|
||||
},
|
||||
expectTelegramConfigIssue(
|
||||
{
|
||||
webhookUrl: "https://example.com/telegram-webhook",
|
||||
},
|
||||
});
|
||||
expect(res.ok).toBe(false);
|
||||
if (!res.ok) {
|
||||
expect(res.issues[0]?.path).toBe("channels.telegram.webhookSecret");
|
||||
}
|
||||
"webhookSecret",
|
||||
);
|
||||
});
|
||||
|
||||
it("rejects account webhookUrl without webhookSecret", () => {
|
||||
const res = validateConfigObject({
|
||||
channels: {
|
||||
telegram: {
|
||||
accounts: {
|
||||
ops: {
|
||||
webhookUrl: "https://example.com/telegram-webhook",
|
||||
},
|
||||
expectTelegramConfigIssue(
|
||||
{
|
||||
accounts: {
|
||||
ops: {
|
||||
webhookUrl: "https://example.com/telegram-webhook",
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
expect(res.ok).toBe(false);
|
||||
if (!res.ok) {
|
||||
expect(res.issues[0]?.path).toBe("channels.telegram.accounts.ops.webhookSecret");
|
||||
}
|
||||
"accounts.ops.webhookSecret",
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user