Initial commit: GitHub-GCC WeCom bot for Gitea
This commit is contained in:
@@ -0,0 +1,169 @@
|
||||
import assert from "node:assert/strict";
|
||||
import test from "node:test";
|
||||
import type { AppConfig } from "../src/config.js";
|
||||
import { signBody } from "../src/signature.js";
|
||||
import { handleRequest } from "../src/worker.js";
|
||||
import { testEnv } from "./helpers.js";
|
||||
|
||||
test("health check returns ok", async () => {
|
||||
const response = await handleRequest(new Request("https://worker.test/healthz"), testEnv());
|
||||
|
||||
assert.equal(response.status, 200);
|
||||
assert.deepEqual(await response.json(), { ok: true });
|
||||
});
|
||||
|
||||
test("accepts a valid push webhook and sends one WeCom message", async () => {
|
||||
const sent: string[] = [];
|
||||
const response = await postGitHubEvent("push", "delivery-1", {
|
||||
ref: "refs/heads/main",
|
||||
repository: { full_name: "acme/app", owner: { login: "acme" } },
|
||||
pusher: { name: "alice" },
|
||||
commits: []
|
||||
}, async (_config, message) => {
|
||||
sent.push(message);
|
||||
});
|
||||
|
||||
assert.equal(response.status, 202);
|
||||
assert.deepEqual(await response.json(), { sent: true });
|
||||
assert.equal(sent.length, 1);
|
||||
assert.match(sent[0] ?? "", /📁 acme\/app/);
|
||||
});
|
||||
|
||||
test("rejects invalid signatures", async () => {
|
||||
const body = JSON.stringify({ repository: { full_name: "acme/app" } });
|
||||
const response = await handleRequest(
|
||||
new Request("https://worker.test/github/webhook", {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"content-type": "application/json",
|
||||
"x-github-event": "push",
|
||||
"x-github-delivery": "bad-sig",
|
||||
"x-hub-signature-256": "sha256=bad"
|
||||
},
|
||||
body
|
||||
}),
|
||||
testEnv(),
|
||||
undefined,
|
||||
async () => {
|
||||
throw new Error("should not send");
|
||||
}
|
||||
);
|
||||
|
||||
assert.equal(response.status, 401);
|
||||
});
|
||||
|
||||
test("deduplicates GitHub delivery ids", async () => {
|
||||
const sent: string[] = [];
|
||||
const payload = {
|
||||
ref: "refs/heads/main",
|
||||
repository: { full_name: "acme/app", owner: { login: "acme" } },
|
||||
commits: []
|
||||
};
|
||||
|
||||
const first = await postGitHubEvent("push", "same-delivery", payload, async (_config, message) => {
|
||||
sent.push(message);
|
||||
});
|
||||
const second = await postGitHubEvent("push", "same-delivery", payload, async (_config, message) => {
|
||||
sent.push(message);
|
||||
});
|
||||
|
||||
assert.equal(first.status, 202);
|
||||
assert.equal(second.status, 202);
|
||||
assert.deepEqual(await second.json(), { duplicate: true });
|
||||
assert.equal(sent.length, 1);
|
||||
});
|
||||
|
||||
test("ignores events outside the allowed organization list", async () => {
|
||||
const sent: string[] = [];
|
||||
const response = await postGitHubEvent(
|
||||
"push",
|
||||
"wrong-org",
|
||||
{
|
||||
ref: "refs/heads/main",
|
||||
repository: { full_name: "other/app", owner: { login: "other" } },
|
||||
commits: []
|
||||
},
|
||||
async (_config, message) => {
|
||||
sent.push(message);
|
||||
},
|
||||
{ ALLOWED_ORGS: "acme" }
|
||||
);
|
||||
|
||||
assert.equal(response.status, 202);
|
||||
assert.equal((await response.json() as { ignored: boolean }).ignored, true);
|
||||
assert.equal(sent.length, 0);
|
||||
});
|
||||
|
||||
test("accepts Gitea event headers on the Gitea webhook path", async () => {
|
||||
const sent: string[] = [];
|
||||
const payload = {
|
||||
ref: "refs/heads/main",
|
||||
repository: { full_name: "gcc/app", owner: { username: "gcc" } },
|
||||
pusher: { username: "alice" },
|
||||
commits: []
|
||||
};
|
||||
const body = JSON.stringify(payload);
|
||||
const signature = await signBody("test-secret", new TextEncoder().encode(body));
|
||||
|
||||
const response = await handleRequest(
|
||||
new Request("https://worker.test/gitea/webhook", {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"content-type": "application/json",
|
||||
"x-gitea-event": "push",
|
||||
"x-gitea-delivery": "gitea-delivery-1",
|
||||
"x-gitea-signature": signature.slice("sha256=".length)
|
||||
},
|
||||
body
|
||||
}),
|
||||
testEnv(),
|
||||
undefined,
|
||||
async (_config, message) => {
|
||||
sent.push(message);
|
||||
}
|
||||
);
|
||||
|
||||
assert.equal(response.status, 202);
|
||||
assert.deepEqual(await response.json(), { sent: true });
|
||||
assert.equal(sent.length, 1);
|
||||
assert.match(sent[0] ?? "", /📁 gcc\/app/);
|
||||
});
|
||||
|
||||
test("returns 500 when sending to WeCom fails so GitHub can retry", async () => {
|
||||
const response = await postGitHubEvent("push", "send-fails", {
|
||||
ref: "refs/heads/main",
|
||||
repository: { full_name: "acme/app", owner: { login: "acme" } },
|
||||
commits: []
|
||||
}, async () => {
|
||||
throw new Error("WeCom failed");
|
||||
});
|
||||
|
||||
assert.equal(response.status, 500);
|
||||
});
|
||||
|
||||
async function postGitHubEvent(
|
||||
eventName: string,
|
||||
deliveryId: string,
|
||||
payload: Record<string, unknown>,
|
||||
sender: (config: AppConfig, message: string) => Promise<unknown>,
|
||||
envOverrides: Record<string, unknown> = {}
|
||||
) {
|
||||
const body = JSON.stringify(payload);
|
||||
const signature = await signBody("test-secret", new TextEncoder().encode(body));
|
||||
|
||||
return handleRequest(
|
||||
new Request("https://worker.test/github/webhook", {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"content-type": "application/json",
|
||||
"x-github-event": eventName,
|
||||
"x-github-delivery": deliveryId,
|
||||
"x-hub-signature-256": signature
|
||||
},
|
||||
body
|
||||
}),
|
||||
testEnv(envOverrides),
|
||||
undefined,
|
||||
sender
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user