import { describe, expect, mock, test } from "bun:test"; class StubEntrypoint {} mock.module("cloudflare:workers", () => ({ env: {}, waitUntil: () => undefined, WorkflowEntrypoint: StubEntrypoint, DurableObject: StubEntrypoint, WorkerEntrypoint: StubEntrypoint, })); mock.module("./db", () => ({ all: async () => [], first: async () => null, run: async () => ({ meta: { changes: 0 } }), batch: async () => [], stmt: () => ({}), placeholders: () => "", chunks: (items: T[]) => [items], MAX_IN_LIST: 90, })); mock.module("./merge-automation", () => ({ onCommitStatus: async () => undefined })); /** Workflow file content by commit sha; the "store" exposes one file at `.gitfor/workflows/ci.yml`. */ const WORKFLOW_PATH = ".gitfor/workflows/ci.yml"; const OLD_SHA = "a".repeat(40); const TIP_SHA = "b".repeat(40); const OLD_SOURCE = "name: CI\non: pull_request\njobs:\n test:\n steps:\n - run: echo ok\n"; const TIP_SOURCE = "name: CI\non: pull_request\njobs:\n test:\n steps:\n - run: npm test\n"; const filesAt: Record = { [OLD_SHA]: OLD_SOURCE, [TIP_SHA]: TIP_SOURCE }; mock.module("./git/store", () => ({ ZERO_SHA: "0".repeat(40), withStore: async (_name: string, fn: (store: unknown) => Promise) => fn({ commit: async (sha: string) => (filesAt[sha] ? { treeSha: `tree:${sha}` } : null), entryAtPath: async (treeSha: string, path: string) => path === WORKFLOW_PATH ? { type: "blob", sha: `blob:${treeSha.slice("tree:".length)}` } : null, blob: async (sha: string) => new TextEncoder().encode(filesAt[sha.slice("blob:".length)] ?? ""), }), })); mock.module("./ci/scheduler", () => ({ readWorkflowFiles: async (_repo: unknown, sha: string) => filesAt[sha] ? [{ path: WORKFLOW_PATH, source: filesAt[sha], tooLarge: false }] : [], })); const { requiredCheckResults } = await import("./statuses"); const { sha256Hex } = await import("./crypto"); const repo = { id: "r1", artifacts_name: "r1" } as never; function ciStatus(hash: string, state = "success") { return { id: "s1", repo_id: "r1", sha: "c".repeat(40), context: "CI / test", state, description: null, target_url: null, workflow_path: WORKFLOW_PATH, workflow_hash: hash, source: "ci", created_at: 0, updated_at: 0, } as never; } describe("requiredCheckResults", () => { test("accepts a success bound to the workflow at the current base tip", async () => { const results = await requiredCheckResults(repo, TIP_SHA, [ciStatus(await sha256Hex(TIP_SOURCE))], ["CI / test"]); expect(results).toEqual(["success"]); }); test("rejects a success bound to an older workflow version from base history (merge base)", async () => { const results = await requiredCheckResults(repo, TIP_SHA, [ciStatus(await sha256Hex(OLD_SOURCE))], ["CI / test"]); expect(results).toEqual(["stale"]); }); test("is untrusted when the base tip has no such workflow file", async () => { const results = await requiredCheckResults( repo, TIP_SHA, [{ ...(ciStatus(await sha256Hex(TIP_SOURCE)) as object), workflow_path: ".gitfor/workflows/other.yml" } as never], ["CI / test"], ); expect(results).toEqual(["untrusted"]); }); test("is untrusted without a base sha", async () => { const results = await requiredCheckResults(repo, null, [ciStatus(await sha256Hex(TIP_SOURCE))], ["CI / test"]); expect(results).toEqual(["untrusted"]); }); test("passes through non-success states and reports missing contexts", async () => { const results = await requiredCheckResults( repo, TIP_SHA, [ciStatus(await sha256Hex(TIP_SOURCE), "pending")], ["CI / test", "CI / lint"], ); expect(results).toEqual(["pending", "missing"]); }); test("api statuses cannot satisfy a context the base workflow reports", async () => { const api = { ...(ciStatus("x") as object), source: "api", workflow_path: null, workflow_hash: null } as never; expect(await requiredCheckResults(repo, TIP_SHA, [api], ["CI / test"])).toEqual(["untrusted"]); const external = { ...(api as object), context: "external/scan" } as never; expect(await requiredCheckResults(repo, TIP_SHA, [external], ["external/scan"])).toEqual(["success"]); }); });