import { describe, expect, test } from "bun:test"; import { createHash } from "node:crypto"; import { parseImageReference, resolveRegistryDigest, } from "../../server/registry"; describe("OCI registry digest resolution", () => { test("parses tags, ports, defaults, and pinned references", () => { expect(parseImageReference("localhost:5000/team/image:v1")).toMatchObject({ registry: "localhost:5000", repository: "team/image", reference: "v1", }); expect( parseImageReference("registry.example.com/team/image").reference, ).toBe("latest"); const pinned = `sha256:${"a".repeat(64)}` as const; expect( parseImageReference(`registry.example.com/team/image@${pinned}`).digest, ).toBe(pinned); expect(() => parseImageReference("image:latest")).toThrow("registry host"); expect(() => parseImageReference(`registry.example.com/../image@${pinned}`), ).toThrow("Invalid image reference"); }); test("resolves an anonymous manifest using the advertised digest", async () => { const expected = `sha256:${"b".repeat(64)}` as const; const calls: Array<{ url: string; authorization: string | null }> = []; const fetcher = async ( input: string | URL | Request, init?: RequestInit, ) => { const headers = new Headers(init?.headers); calls.push({ url: String(input), authorization: headers.get("authorization"), }); return new Response("manifest", { headers: { "docker-content-digest": expected }, }); }; expect( await resolveRegistryDigest("registry.example.com/team/image:v1", { fetch: fetcher, }), ).toBe(expected); expect(calls).toEqual([ { url: "https://registry.example.com/v2/team/image/manifests/v1", authorization: null, }, ]); }); test("caches successful digest resolutions with deterministic expiry and bounds", async () => { let now = 0; let calls = 0; const fetcher = async () => { calls += 1; return new Response("manifest", { headers: { "docker-content-digest": `sha256:${"d".repeat(64)}` }, }); }; const options = { fetch: fetcher, cacheTtlMs: 100, cacheMaxEntries: 1, clock: () => now, }; await resolveRegistryDigest("cache.example.com/team/first:v1", options); await resolveRegistryDigest("cache.example.com/team/first:v1", options); expect(calls).toBe(1); now = 100; await resolveRegistryDigest("cache.example.com/team/first:v1", options); expect(calls).toBe(2); await resolveRegistryDigest("cache.example.com/team/second:v1", options); await resolveRegistryDigest("cache.example.com/team/first:v1", options); expect(calls).toBe(4); }); test("does not cache failed resolutions or share entries across credentials", async () => { let calls = 0; const failing = async () => { calls += 1; return new Response("unavailable", { status: 503 }); }; const options = { fetch: failing, cacheTtlMs: 1_000 }; await expect( resolveRegistryDigest("failure.example.com/team/image:v1", options), ).rejects.toThrow("503"); await expect( resolveRegistryDigest("failure.example.com/team/image:v1", options), ).rejects.toThrow("503"); expect(calls).toBe(2); const authorizedCalls: string[] = []; const authorized = async ( _input: string | URL | Request, init?: RequestInit, ) => { authorizedCalls.push(new Headers(init?.headers).get("authorization")!); return new Response("manifest", { headers: { "docker-content-digest": `sha256:${"e".repeat(64)}` }, }); }; for (const username of ["one", "two"]) { await resolveRegistryDigest("credentials.example.com/team/image:v1", { fetch: authorized, credentials: { username, password: "password" }, }); } expect(authorizedCalls).toHaveLength(2); }); test("resolves through a trusted internal registry origin", async () => { const expected = `sha256:${"c".repeat(64)}` as const; let requested = ""; await expect( resolveRegistryDigest("registry.example.com/team/image:v1", { origin: "http://registry.registry.svc.cluster.local:5000/", insecure: true, fetch: async (input) => { requested = String(input); return new Response("manifest", { headers: { "docker-content-digest": expected }, }); }, }), ).resolves.toBe(expected); expect(requested).toBe( "http://registry.registry.svc.cluster.local:5000/v2/team/image/manifests/v1", ); }); test("follows a standard bearer challenge and hashes a digest-less response", async () => { const body = '{"schemaVersion":2}'; const expected = `sha256:${createHash("sha256").update(body).digest("hex")}` as const; const calls: Array<{ url: string; authorization: string | null }> = []; const fetcher = async ( input: string | URL | Request, init?: RequestInit, ) => { const url = String(input); const authorization = new Headers(init?.headers).get("authorization"); calls.push({ url, authorization }); if (url.startsWith("https://auth.example/token")) { expect(new URL(url).searchParams.get("scope")).toBe( "repository:team/image:pull", ); expect(authorization).toBe( `Basic ${Buffer.from("user:pass").toString("base64")}`, ); return Response.json({ access_token: "registry-token" }); } if (authorization !== "Bearer registry-token") { return new Response("unauthorized", { status: 401, headers: { "www-authenticate": 'Bearer realm="https://auth.example/token",service="registry.example.com"', }, }); } return new Response(body, { headers: { "content-type": "application/vnd.oci.image.manifest.v1+json", }, }); }; expect( await resolveRegistryDigest("registry.example.com/team/image:v2", { fetch: fetcher, credentials: { username: "user", password: "pass" }, }), ).toBe(expected); expect(calls).toHaveLength(3); expect(calls[2]?.authorization).toBe("Bearer registry-token"); }); test("rejects unsupported challenges and malformed advertised digests", async () => { const unauthorized = async () => new Response("no", { status: 401, headers: { "www-authenticate": 'Basic realm="registry"' }, }); await expect( resolveRegistryDigest("registry.example.com/team/image", { fetch: unauthorized, }), ).rejects.toThrow("401"); const malformed = async () => new Response("body", { headers: { "docker-content-digest": "sha256:bad" }, }); await expect( resolveRegistryDigest("registry.example.com/team/image", { fetch: malformed, }), ).rejects.toThrow("Invalid SHA-256"); }); });