import { describe, expect, mock, test } from "bun:test"; import { Database } from "bun:sqlite"; import { applyCombinedSchema } from "./test-schema.test-helper"; import type { Viewer } from "~/lib/types"; mock.module("cloudflare:workers", () => ({ env: { PUBLIC_URL: "https://forge.example.com" }, waitUntil: () => undefined, })); const db = new Database(":memory:"); applyCombinedSchema(db); const reads: string[] = []; mock.module("./db", () => ({ first: async (sql: string, ...params: unknown[]) => { reads.push(sql); return db.query(sql).get(...(params as never[])) ?? null; }, all: async (sql: string, ...params: unknown[]) => db.query(sql).all(...(params as never[])), run: async () => ({ meta: { changes: 0 } }), batch: async () => [], stmt: (sql: string, ...params: unknown[]) => ({ sql, params }), placeholders: (count: number) => Array(count).fill("?").join(", "), chunks: (items: T[]) => [items], MAX_IN_LIST: 90, })); const { loadRepo, loadRepoFor, repoPermission } = await import("./repos"); db.exec(` INSERT INTO accounts (id, name, kind, created_at, org_default_permission) VALUES ('org', 'acme', 'org', 0, 'write'); INSERT INTO accounts (id, name, kind, created_at) VALUES ('boss', 'boss', 'user', 0), ('dev', 'dev', 'user', 0), ('guest', 'guest', 'user', 0), ('nobody', 'nobody', 'user', 0); INSERT INTO users (account_id, email, is_admin) VALUES ('boss', 'b@x', 0), ('dev', 'd@x', 0), ('guest', 'g@x', 0), ('nobody', 'n@x', 0); INSERT INTO repos (id, owner_id, name, visibility, default_branch, artifacts_name, artifacts_remote, created_at, updated_at) VALUES ('repo', 'org', 'app', 'private', 'main', 'a', 'r', 0, 0); INSERT INTO org_members (org_id, user_id, role, created_at) VALUES ('org', 'boss', 'owner', 0), ('org', 'dev', 'member', 0); INSERT INTO collaborators (repo_id, user_id, permission, created_at) VALUES ('repo', 'guest', 'read', 0); `); function viewer(id: string): Viewer { return { id, name: id, displayName: null, email: `${id}@x`, isAdmin: false, emailVerified: true }; } describe("repository access loaded with the row", () => { test("gives the same permission as the separate lookups, in one D1 read", async () => { for (const [id, expected] of [ ["boss", "admin"], ["dev", "write"], ["guest", "read"], ["nobody", "none"], ] as const) { reads.length = 0; const repo = await loadRepoFor("acme", "app", viewer(id)); if (!repo) throw new Error("repo not loaded"); expect(await repoPermission(repo, viewer(id))).toBe(expected); expect(reads).toHaveLength(1); const plain = await loadRepo("acme", "app"); if (!plain) throw new Error("repo not loaded"); expect(await repoPermission(plain, viewer(id))).toBe(expected); } }); test("a row loaded for one viewer is re-checked for another", async () => { const repo = await loadRepoFor("acme", "app", viewer("boss")); if (!repo) throw new Error("repo not loaded"); expect(await repoPermission(repo, viewer("nobody"))).toBe("none"); }); });