mirror of https://github.com/openclaw/openclaw.git
refactor: share mattermost test harnesses
This commit is contained in:
parent
48853f875b
commit
ba2d57d024
|
|
@ -16,6 +16,35 @@ const accountFixture: ResolvedMattermostAccount = {
|
|||
config: {},
|
||||
};
|
||||
|
||||
function authorizeGroupCommand(senderId: string) {
|
||||
return authorizeMattermostCommandInvocation({
|
||||
account: {
|
||||
...accountFixture,
|
||||
config: {
|
||||
groupPolicy: "allowlist",
|
||||
allowFrom: ["trusted-user"],
|
||||
},
|
||||
},
|
||||
cfg: {
|
||||
commands: {
|
||||
useAccessGroups: true,
|
||||
},
|
||||
},
|
||||
senderId,
|
||||
senderName: senderId,
|
||||
channelId: "chan-1",
|
||||
channelInfo: {
|
||||
id: "chan-1",
|
||||
type: "O",
|
||||
name: "general",
|
||||
display_name: "General",
|
||||
},
|
||||
storeAllowFrom: [],
|
||||
allowTextCommands: true,
|
||||
hasControlCommand: true,
|
||||
});
|
||||
}
|
||||
|
||||
describe("mattermost monitor authz", () => {
|
||||
it("keeps DM allowlist merged with pairing-store entries", () => {
|
||||
const resolved = resolveMattermostEffectiveAllowFromLists({
|
||||
|
|
@ -72,32 +101,7 @@ describe("mattermost monitor authz", () => {
|
|||
});
|
||||
|
||||
it("denies group control commands when the sender is outside the allowlist", () => {
|
||||
const decision = authorizeMattermostCommandInvocation({
|
||||
account: {
|
||||
...accountFixture,
|
||||
config: {
|
||||
groupPolicy: "allowlist",
|
||||
allowFrom: ["trusted-user"],
|
||||
},
|
||||
},
|
||||
cfg: {
|
||||
commands: {
|
||||
useAccessGroups: true,
|
||||
},
|
||||
},
|
||||
senderId: "attacker",
|
||||
senderName: "attacker",
|
||||
channelId: "chan-1",
|
||||
channelInfo: {
|
||||
id: "chan-1",
|
||||
type: "O",
|
||||
name: "general",
|
||||
display_name: "General",
|
||||
},
|
||||
storeAllowFrom: [],
|
||||
allowTextCommands: true,
|
||||
hasControlCommand: true,
|
||||
});
|
||||
const decision = authorizeGroupCommand("attacker");
|
||||
|
||||
expect(decision).toMatchObject({
|
||||
ok: false,
|
||||
|
|
@ -107,32 +111,7 @@ describe("mattermost monitor authz", () => {
|
|||
});
|
||||
|
||||
it("authorizes group control commands for allowlisted senders", () => {
|
||||
const decision = authorizeMattermostCommandInvocation({
|
||||
account: {
|
||||
...accountFixture,
|
||||
config: {
|
||||
groupPolicy: "allowlist",
|
||||
allowFrom: ["trusted-user"],
|
||||
},
|
||||
},
|
||||
cfg: {
|
||||
commands: {
|
||||
useAccessGroups: true,
|
||||
},
|
||||
},
|
||||
senderId: "trusted-user",
|
||||
senderName: "trusted-user",
|
||||
channelId: "chan-1",
|
||||
channelInfo: {
|
||||
id: "chan-1",
|
||||
type: "O",
|
||||
name: "general",
|
||||
display_name: "General",
|
||||
},
|
||||
storeAllowFrom: [],
|
||||
allowTextCommands: true,
|
||||
hasControlCommand: true,
|
||||
});
|
||||
const decision = authorizeGroupCommand("trusted-user");
|
||||
|
||||
expect(decision).toMatchObject({
|
||||
ok: true,
|
||||
|
|
|
|||
|
|
@ -14,6 +14,28 @@ describe("mattermost reactions", () => {
|
|||
resetMattermostReactionBotUserCacheForTests();
|
||||
});
|
||||
|
||||
async function addReactionWithFetch(
|
||||
fetchMock: ReturnType<typeof createMattermostReactionFetchMock>,
|
||||
) {
|
||||
return addMattermostReaction({
|
||||
cfg: createMattermostTestConfig(),
|
||||
postId: "POST1",
|
||||
emojiName: "thumbsup",
|
||||
fetchImpl: fetchMock as unknown as typeof fetch,
|
||||
});
|
||||
}
|
||||
|
||||
async function removeReactionWithFetch(
|
||||
fetchMock: ReturnType<typeof createMattermostReactionFetchMock>,
|
||||
) {
|
||||
return removeMattermostReaction({
|
||||
cfg: createMattermostTestConfig(),
|
||||
postId: "POST1",
|
||||
emojiName: "thumbsup",
|
||||
fetchImpl: fetchMock as unknown as typeof fetch,
|
||||
});
|
||||
}
|
||||
|
||||
it("adds reactions by calling /users/me then POST /reactions", async () => {
|
||||
const fetchMock = createMattermostReactionFetchMock({
|
||||
mode: "add",
|
||||
|
|
@ -21,12 +43,7 @@ describe("mattermost reactions", () => {
|
|||
emojiName: "thumbsup",
|
||||
});
|
||||
|
||||
const result = await addMattermostReaction({
|
||||
cfg: createMattermostTestConfig(),
|
||||
postId: "POST1",
|
||||
emojiName: "thumbsup",
|
||||
fetchImpl: fetchMock as unknown as typeof fetch,
|
||||
});
|
||||
const result = await addReactionWithFetch(fetchMock);
|
||||
|
||||
expect(result).toEqual({ ok: true });
|
||||
expect(fetchMock).toHaveBeenCalled();
|
||||
|
|
@ -41,12 +58,7 @@ describe("mattermost reactions", () => {
|
|||
body: { id: "err", message: "boom" },
|
||||
});
|
||||
|
||||
const result = await addMattermostReaction({
|
||||
cfg: createMattermostTestConfig(),
|
||||
postId: "POST1",
|
||||
emojiName: "thumbsup",
|
||||
fetchImpl: fetchMock as unknown as typeof fetch,
|
||||
});
|
||||
const result = await addReactionWithFetch(fetchMock);
|
||||
|
||||
expect(result.ok).toBe(false);
|
||||
if (!result.ok) {
|
||||
|
|
@ -61,12 +73,7 @@ describe("mattermost reactions", () => {
|
|||
emojiName: "thumbsup",
|
||||
});
|
||||
|
||||
const result = await removeMattermostReaction({
|
||||
cfg: createMattermostTestConfig(),
|
||||
postId: "POST1",
|
||||
emojiName: "thumbsup",
|
||||
fetchImpl: fetchMock as unknown as typeof fetch,
|
||||
});
|
||||
const result = await removeReactionWithFetch(fetchMock);
|
||||
|
||||
expect(result).toEqual({ ok: true });
|
||||
expect(fetchMock).toHaveBeenCalled();
|
||||
|
|
|
|||
|
|
@ -10,6 +10,25 @@ import {
|
|||
} from "./slash-commands.js";
|
||||
|
||||
describe("slash-commands", () => {
|
||||
async function registerSingleStatusCommand(
|
||||
request: (path: string, init?: { method?: string }) => Promise<unknown>,
|
||||
) {
|
||||
const client = { request } as unknown as MattermostClient;
|
||||
return registerSlashCommands({
|
||||
client,
|
||||
teamId: "team-1",
|
||||
creatorUserId: "bot-user",
|
||||
callbackUrl: "http://gateway/callback",
|
||||
commands: [
|
||||
{
|
||||
trigger: "oc_status",
|
||||
description: "status",
|
||||
autoComplete: true,
|
||||
},
|
||||
],
|
||||
});
|
||||
}
|
||||
|
||||
it("parses application/x-www-form-urlencoded payloads", () => {
|
||||
const payload = parseSlashCommandPayload(
|
||||
"token=t1&team_id=team&channel_id=ch1&user_id=u1&command=%2Foc_status&text=now",
|
||||
|
|
@ -101,21 +120,7 @@ describe("slash-commands", () => {
|
|||
}
|
||||
throw new Error(`unexpected request path: ${path}`);
|
||||
});
|
||||
const client = { request } as unknown as MattermostClient;
|
||||
|
||||
const result = await registerSlashCommands({
|
||||
client,
|
||||
teamId: "team-1",
|
||||
creatorUserId: "bot-user",
|
||||
callbackUrl: "http://gateway/callback",
|
||||
commands: [
|
||||
{
|
||||
trigger: "oc_status",
|
||||
description: "status",
|
||||
autoComplete: true,
|
||||
},
|
||||
],
|
||||
});
|
||||
const result = await registerSingleStatusCommand(request);
|
||||
|
||||
expect(result).toHaveLength(1);
|
||||
expect(result[0]?.managed).toBe(false);
|
||||
|
|
@ -144,21 +149,7 @@ describe("slash-commands", () => {
|
|||
}
|
||||
throw new Error(`unexpected request path: ${path}`);
|
||||
});
|
||||
const client = { request } as unknown as MattermostClient;
|
||||
|
||||
const result = await registerSlashCommands({
|
||||
client,
|
||||
teamId: "team-1",
|
||||
creatorUserId: "bot-user",
|
||||
callbackUrl: "http://gateway/callback",
|
||||
commands: [
|
||||
{
|
||||
trigger: "oc_status",
|
||||
description: "status",
|
||||
autoComplete: true,
|
||||
},
|
||||
],
|
||||
});
|
||||
const result = await registerSingleStatusCommand(request);
|
||||
|
||||
expect(result).toHaveLength(0);
|
||||
expect(request).toHaveBeenCalledTimes(1);
|
||||
|
|
|
|||
|
|
@ -58,6 +58,23 @@ const accountFixture: ResolvedMattermostAccount = {
|
|||
config: {},
|
||||
};
|
||||
|
||||
async function runSlashRequest(params: {
|
||||
commandTokens: Set<string>;
|
||||
body: string;
|
||||
method?: string;
|
||||
}) {
|
||||
const handler = createSlashCommandHttpHandler({
|
||||
account: accountFixture,
|
||||
cfg: {} as OpenClawConfig,
|
||||
runtime: {} as RuntimeEnv,
|
||||
commandTokens: params.commandTokens,
|
||||
});
|
||||
const req = createRequest({ method: params.method, body: params.body });
|
||||
const response = createResponse();
|
||||
await handler(req, response.res);
|
||||
return response;
|
||||
}
|
||||
|
||||
describe("slash-http", () => {
|
||||
it("rejects non-POST methods", async () => {
|
||||
const handler = createSlashCommandHttpHandler({
|
||||
|
|
@ -93,36 +110,20 @@ describe("slash-http", () => {
|
|||
});
|
||||
|
||||
it("fails closed when no command tokens are registered", async () => {
|
||||
const handler = createSlashCommandHttpHandler({
|
||||
account: accountFixture,
|
||||
cfg: {} as OpenClawConfig,
|
||||
runtime: {} as RuntimeEnv,
|
||||
const response = await runSlashRequest({
|
||||
commandTokens: new Set<string>(),
|
||||
});
|
||||
const req = createRequest({
|
||||
body: "token=tok1&team_id=t1&channel_id=c1&user_id=u1&command=%2Foc_status&text=",
|
||||
});
|
||||
const response = createResponse();
|
||||
|
||||
await handler(req, response.res);
|
||||
|
||||
expect(response.res.statusCode).toBe(401);
|
||||
expect(response.getBody()).toContain("Unauthorized: invalid command token.");
|
||||
});
|
||||
|
||||
it("rejects unknown command tokens", async () => {
|
||||
const handler = createSlashCommandHttpHandler({
|
||||
account: accountFixture,
|
||||
cfg: {} as OpenClawConfig,
|
||||
runtime: {} as RuntimeEnv,
|
||||
const response = await runSlashRequest({
|
||||
commandTokens: new Set(["known-token"]),
|
||||
});
|
||||
const req = createRequest({
|
||||
body: "token=unknown&team_id=t1&channel_id=c1&user_id=u1&command=%2Foc_status&text=",
|
||||
});
|
||||
const response = createResponse();
|
||||
|
||||
await handler(req, response.res);
|
||||
|
||||
expect(response.res.statusCode).toBe(401);
|
||||
expect(response.getBody()).toContain("Unauthorized: invalid command token.");
|
||||
|
|
|
|||
Loading…
Reference in New Issue