Skip to content
File

Blob: tests/worker/webhooks/private/lifecycle.test.ts

typescript101 lines
1import { describe, expect, it } from "vitest";
2 
3import { readProjectDoRows } from "../../../helpers/runtime";
4import { registerWorkerRuntimeHooks } from "../../../helpers/worker-hooks";
5 
6import { createOwnedProjectContext, deleteWebhook, getWebhooks, putWebhook, rotateWebhookSecret } from "../helpers";
7 
8describe("webhook private routes", () => {
9 registerWorkerRuntimeHooks();
10 
11 describe("provider lifecycle", () => {
12 it("rotates webhook secrets and deletes provider config", async () => {
13 const context = await createOwnedProjectContext({
14 user: {
15 email: "webhook-private-rotate@example.com",
16 slug: "webhook-private-rotate",
17 },
18 project: {
19 projectSlug: "rotate-project",
20 repoUrl: "https://gitea.example.com:8443/git/example/rotate-project",
21 },
22 });
23 
24 const created = await putWebhook(context.sessionId, context.project.id, "gitea", {
25 enabled: true,
26 config: {
27 instanceUrl: "https://gitea.example.com:8443/git",
28 },
29 secret: "initial-gitea-secret",
30 });
31 expect(created.status).toBe(201);
32 
33 const beforeRotate = await readProjectDoRows(context.project.id);
34 expect(beforeRotate.webhooks).toHaveLength(1);
35 
36 const rotated = await rotateWebhookSecret(context.sessionId, context.project.id, "gitea");
37 expect(rotated.status).toBe(200);
38 expect(rotated.body?.secret).toEqual(expect.any(String));
39 expect(rotated.body?.secret).not.toBe("initial-gitea-secret");
40 
41 const afterRotate = await readProjectDoRows(context.project.id);
42 expect(afterRotate.webhooks).toHaveLength(1);
43 expect(afterRotate.webhooks[0]?.secretCiphertext).not.toEqual(beforeRotate.webhooks[0]?.secretCiphertext);
44 expect(afterRotate.webhooks[0]?.secretNonce).not.toEqual(beforeRotate.webhooks[0]?.secretNonce);
45 
46 const deleted = await deleteWebhook(context.sessionId, context.project.id, "gitea");
47 expect(deleted.status).toBe(204);
48 
49 const listed = await getWebhooks(context.sessionId, context.project.id);
50 expect(listed.status).toBe(200);
51 expect(listed.body?.webhooks).toEqual([]);
52 
53 const afterDelete = await readProjectDoRows(context.project.id);
54 expect(afterDelete.webhooks).toEqual([]);
55 });
56 
57 it("manages multiple providers on the same project independently", async () => {
58 const context = await createOwnedProjectContext({
59 user: {
60 email: "webhook-private-multi-provider@example.com",
61 slug: "webhook-private-multi-provider",
62 },
63 project: {
64 projectSlug: "multi-provider-project",
65 repoUrl: "https://gitlab.example.com/example/multi-provider-project",
66 },
67 });
68 
69 const gitlabCreated = await putWebhook(context.sessionId, context.project.id, "gitlab", {
70 enabled: true,
71 config: { instanceUrl: "https://gitlab.example.com" },
72 secret: "gitlab-multi-secret",
73 });
74 expect(gitlabCreated.status).toBe(201);
75 
76 const giteaCreated = await putWebhook(context.sessionId, context.project.id, "gitea", {
77 enabled: true,
78 config: { instanceUrl: "https://gitlab.example.com" },
79 secret: "gitea-multi-secret",
80 });
81 expect(giteaCreated.status).toBe(201);
82 
83 const listed = await getWebhooks(context.sessionId, context.project.id);
84 expect(listed.status).toBe(200);
85 expect(listed.body?.webhooks).toHaveLength(2);
86 const providers = listed.body!.webhooks.map((w) => w.provider).sort();
87 expect(providers).toEqual(["gitea", "gitlab"]);
88 
89 await deleteWebhook(context.sessionId, context.project.id, "gitlab");
90 const afterDelete = await getWebhooks(context.sessionId, context.project.id);
91 expect(afterDelete.status).toBe(200);
92 expect(afterDelete.body?.webhooks).toHaveLength(1);
93 expect(afterDelete.body?.webhooks[0]?.provider).toBe("gitea");
94 
95 const rows = await readProjectDoRows(context.project.id);
96 expect(rows.webhooks).toHaveLength(1);
97 expect(rows.webhooks[0]?.provider).toBe("gitea");
98 });
99 });
100});