test: use channel schemas for webhook validation

This commit is contained in:
Peter Steinberger
2026-04-11 05:16:51 +01:00
parent feef387a75
commit 97c9a362f7
2 changed files with 131 additions and 221 deletions

View File

@@ -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",
);
});
});
});

View File

@@ -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",
);
});
});
});