39 lines · 1.7 KB
import { describe, expect, mock, test } from "bun:test";
import type { RepoRow } from "~/lib/types";

const writers = new Set(["maintainer", "base-owner"]);
mock.module("cloudflare:workers", () => ({ DurableObject: class {}, env: {}, waitUntil: () => undefined }));
mock.module("../pull-events", () => {
  const forkRunNeedsApproval = async (baseRepo: RepoRow, headRepo: RepoRow, actorId: string | null) =>
    baseRepo.id !== headRepo.id && !(actorId !== null && writers.has(actorId));
  return {
    forkRunNeedsApproval,
    forkPullNeedsApproval: async (baseRepo: RepoRow, headRepo: RepoRow, authorId: string) =>
      (await forkRunNeedsApproval(baseRepo, headRepo, authorId)) ||
      forkRunNeedsApproval(baseRepo, headRepo, headRepo.owner_id),
  };
});

const { forkPushNeedsApproval } = await import("./fork-approval");

function repo(id: string, ownerId: string): RepoRow {
  return Object.assign(Object.create(null), { id, owner_id: ownerId });
}

const base = repo("base", "base-owner");

describe("fork push approval", () => {
  test("a trusted pusher can't approve an untrusted author's fork", async () => {
    expect(await forkPushNeedsApproval(base, repo("fork", "stranger"), "stranger", "maintainer")).toBe(true);
  });

  test("an untrusted pusher can't ride a trusted author's fork", async () => {
    expect(await forkPushNeedsApproval(base, repo("fork", "maintainer"), "maintainer", "stranger")).toBe(true);
  });

  test("everyone trusted, or same-repo pulls, run without approval", async () => {
    expect(await forkPushNeedsApproval(base, repo("fork", "maintainer"), "maintainer", "maintainer")).toBe(false);
    expect(await forkPushNeedsApproval(base, base, "stranger", "stranger")).toBe(false);
  });
});