278 lines · 12.4 KB
import { describe, expect, mock, test } from "bun:test";
import { generateKeyPairSync } from "node:crypto";
import { hmacSha256Hex } from "../crypto";
import { signPayload, verifyLinearSignature, verifySha256Signature, verifySlackSignature } from "./signatures";
import { escapeSlack, googleChatDigest, googleChatMessage, slackDigest, slackMessage } from "./format";
import { branchMatches, passesFilters, summarizeEvent } from "./summarize";
import type { EventSummary } from "./summarize";
import { extractIssueKeys } from "./linear-keys";
import { DEFAULT_FILTERS } from "~/lib/integrations";

const fakeEnv = { PUBLIC_URL: "https://gitfor.example.com", INTEGRATIONS_ALLOW_LOOPBACK: "false", SECRETS_KEY: "test" };
mock.module("cloudflare:workers", () => ({
  env: fakeEnv,
  waitUntil: () => undefined,
  WorkflowEntrypoint: class {},
  DurableObject: class {},
  WorkerEntrypoint: class {},
}));

const repo = { fullName: "acme/web", url: "https://gitfor.example.com/acme/web", defaultBranch: "main" };

describe("signatures", () => {
  test("outbound HMAC round-trips and rejects tampering", async () => {
    const header = await signPayload("s3cret", '{"a":1}');
    expect(header).toBe(`sha256=${await hmacSha256Hex("s3cret", '{"a":1}')}`);
    expect(await verifySha256Signature("s3cret", '{"a":1}', header)).toBe(true);
    expect(await verifySha256Signature("s3cret", '{"a":2}', header)).toBe(false);
    expect(await verifySha256Signature("other", '{"a":1}', header)).toBe(false);
    expect(await verifySha256Signature("s3cret", '{"a":1}', null)).toBe(false);
    expect(await verifySha256Signature("", '{"a":1}', header)).toBe(false);
  });

  test("Slack v0 signatures are verified with a replay window", async () => {
    const nowMs = 1_700_000_000_000;
    const timestamp = String(nowMs / 1000);
    const body = "token=x&team_id=T1&text=status+acme%2Fweb";
    const signature = `v0=${await hmacSha256Hex("signing", `v0:${timestamp}:${body}`)}`;
    const base = { signingSecret: "signing", body, timestamp, signature, nowMs };
    expect(await verifySlackSignature(base)).toBe(true);
    expect(await verifySlackSignature({ ...base, body: `${body}&x=1` })).toBe(false);