import { describe, expect, mock, test } from "bun:test"; import type { Permission, RepoRow } from "~/lib/types"; mock.module("cloudflare:workers", () => ({ env: {}, waitUntil: () => undefined, WorkflowEntrypoint: class {}, DurableObject: class {}, WorkerEntrypoint: class {}, })); const grants = new Map(); const users = new Set(["u-bob"]); mock.module("../auth", () => ({ loadUserById: async (id: string) => (users.has(id) ? { id, name: id, email: `${id}@x`, is_admin: 0 } : null), toViewer: (user: { id: string; name: string; email: string }) => ({ ...user, displayName: null, isAdmin: false }), })); mock.module("../repos", () => ({ hasPermission: (actual: Permission, needed: Permission) => { const rank = { none: 0, read: 1, write: 2, admin: 3 }; return rank[actual] >= rank[needed]; }, repoPermission: async (repo: RepoRow, viewer: { id: string } | null) => viewer ? (grants.get(`${repo.id}:${viewer.id}`) ?? (repo.visibility === "public" ? "read" : "none")) : "none", })); const { canBridge, isPullHeadRepo, pullHeadAccessible } = await import("./bridge-policy"); function repo(overrides: Partial): RepoRow { return { id: "r", owner_id: "o", visibility: "private", fork_of_id: null, detached: 0, ...overrides, } as RepoRow; } const base = repo({ id: "A", owner_id: "u-alice" }); const fork = repo({ id: "B", owner_id: "u-bob", fork_of_id: "A" }); const pull = { author_id: "u-bob" }; describe("bridge policy (GIT-A1)", () => { test("canBridge never widens visibility", () => { expect(canBridge(repo({ visibility: "private" }), repo({ visibility: "public" }))).toBe(false); expect(canBridge(repo({ visibility: "public" }), repo({ visibility: "public" }))).toBe(true); expect(canBridge(repo({ visibility: "private" }), repo({ visibility: "private" }))).toBe(true); }); test("only the base itself or a live direct fork can be a pull request head", () => { expect(isPullHeadRepo(base, base)).toBe(true); expect(isPullHeadRepo(base, fork)).toBe(true); expect(isPullHeadRepo(fork, base)).toBe(false); expect(isPullHeadRepo(base, repo({ ...fork, detached: 1 }))).toBe(false); expect(isPullHeadRepo(base, repo({ id: "C", fork_of_id: "Z" }))).toBe(false); }); test("the author must still read both repositories at bridge time", async () => { grants.set("A:u-bob", "read"); grants.set("B:u-bob", "admin"); expect(await pullHeadAccessible(pull, base, fork)).toBe(true); grants.delete("A:u-bob"); expect(await pullHeadAccessible(pull, base, fork)).toBe(false); }); test("a pull request whose head is the parent is refused regardless of access", async () => { grants.set("A:u-bob", "read"); grants.set("B:u-bob", "admin"); expect(await pullHeadAccessible(pull, fork, base)).toBe(false); }); test("a deleted author cannot vouch for the bridge", async () => { grants.set("A:u-bob", "read"); expect(await pullHeadAccessible({ author_id: "u-gone" }, base, fork)).toBe(false); }); test("same-repository pull requests are unaffected", async () => { expect(await pullHeadAccessible({ author_id: "u-gone" }, base, base)).toBe(true); }); });