import { describe, expect, mock, test } from "bun:test"; const fakeEnv: Record = { PUBLIC_URL: "https://gitfor.example.com", INTEGRATIONS_ALLOW_LOOPBACK: "false", SECRETS_KEY: "test-master-key", WEBHOOKS_ALLOW_HTTP: undefined, }; const dbCalls: Array<{ sql: string; params: unknown[] }> = []; mock.module("cloudflare:workers", () => ({ env: fakeEnv, waitUntil: () => undefined, WorkflowEntrypoint: class {}, DurableObject: class {}, WorkerEntrypoint: class {}, })); mock.module("../db", () => ({ run: async (sql: string, ...params: unknown[]) => { dbCalls.push({ sql, params }); return { meta: { changes: 1 } }; }, first: async () => null, all: async () => [], stmt: () => ({}), batch: async () => [], placeholders: (count: number) => Array.from({ length: count }, () => "?").join(", "), MAX_IN_LIST: 90, chunks: (items: T[]) => [items], })); const { collaboratorCanPush, mirrorPushConfigured } = await import("./github-sync"); const { assertOutboundUrl } = await import("./outbound"); const { assertWebhookUrl, isSealedSecret, openWebhookSecret, sealWebhookSecret, replayableBody } = await import("../webhooks/legacy"); describe("INT-A1 push mirror gate", () => { const base = { githubLogin: "alice", githubInstallationId: 42, githubRepo: "Org/Private" }; test("requires the installer to have recorded push on the selected repo", () => { expect(mirrorPushConfigured({ ...base, githubPushRepos: ["org/private"] })).toMatchObject({ ok: true }); expect(mirrorPushConfigured({ ...base, githubPushRepos: ["org/other"] })).toMatchObject({ ok: false }); expect(mirrorPushConfigured({ ...base, githubPushRepos: [] })).toMatchObject({ ok: false }); }); test("integrations installed before logins were recorded must be reinstalled", () => { expect( mirrorPushConfigured({ githubInstallationId: 42, githubRepo: "org/private", githubPushRepos: ["org/private"] }), ).toMatchObject({ ok: false, reason: expect.stringContaining("reinstall") }); }); test("GitHub's live collaborator answer must grant push", () => { expect(collaboratorCanPush({ permission: "read" })).toBe(false); expect(collaboratorCanPush({ permission: "none" })).toBe(false); expect(collaboratorCanPush({})).toBe(false); expect(collaboratorCanPush({ permission: "write" })).toBe(true); expect(collaboratorCanPush({ permission: "maintain" })).toBe(true); expect(collaboratorCanPush({ permission: "admin" })).toBe(true); expect(collaboratorCanPush({ permission: "triage", user: { permissions: { push: true } } })).toBe(true); }); }); describe("INT-A3 legacy webhook URL guard", () => { test("plain http is refused unless the operator opts in, and host rules still apply", () => { fakeEnv.WEBHOOKS_ALLOW_HTTP = undefined; expect(() => assertWebhookUrl("http://hooks.example.com/x")).toThrow(); expect(() => assertWebhookUrl("https://user:pw@hooks.example.com/x")).toThrow(); expect(() => assertWebhookUrl("https://10.0.0.1/x")).toThrow(); expect(() => assertWebhookUrl("https://evil.gitfor.example.com/x")).toThrow(); expect(assertWebhookUrl("https://hooks.example.com/x").hostname).toBe("hooks.example.com"); fakeEnv.WEBHOOKS_ALLOW_HTTP = "true"; expect(assertWebhookUrl("http://hooks.example.com/x").protocol).toBe("http:"); expect(() => assertWebhookUrl("http://169.254.169.254/latest")).toThrow(); expect(() => assertWebhookUrl("http://localhost/x")).toThrow(); expect(() => assertWebhookUrl("http://user:pw@hooks.example.com/x")).toThrow(); fakeEnv.WEBHOOKS_ALLOW_HTTP = undefined; }); test("the generic outbound guard never accepts http even when webhooks do", () => { fakeEnv.WEBHOOKS_ALLOW_HTTP = "true"; expect(() => assertOutboundUrl("http://hooks.example.com/x")).toThrow(); fakeEnv.WEBHOOKS_ALLOW_HTTP = undefined; }); test("truncated deliveries cannot be replayed", () => { expect(replayableBody('{"a":1}')).toEqual({ a: 1 }); expect(() => replayableBody('{"truncated":true,"event":"push"}')).toThrow(/too large/); expect(() => replayableBody("[1,2]")).toThrow(); }); }); describe("INT-A4 legacy webhook secrets", () => { test("secrets are sealed with the SECRETS_KEY envelope and round-trip", async () => { const sealed = await sealWebhookSecret("hunter22"); expect(sealed).not.toBeNull(); expect(isSealedSecret(sealed)).toBe(true); expect(sealed).not.toContain("hunter22"); expect(await openWebhookSecret({ id: "w1", url: "https://x.example", secret: sealed })).toBe("hunter22"); expect(await sealWebhookSecret(null)).toBeNull(); }); test("plaintext rows are re-sealed in place on first read", async () => { dbCalls.length = 0; expect(await openWebhookSecret({ id: "w2", url: "https://x.example", secret: "legacy-plain" })).toBe( "legacy-plain", ); expect(dbCalls).toHaveLength(1); expect(dbCalls[0].sql).toContain("UPDATE webhooks SET secret"); expect(isSealedSecret(String(dbCalls[0].params[0]))).toBe(true); expect(dbCalls[0].params.slice(1)).toEqual(["w2", "legacy-plain"]); }); });