import assert from "node:assert/strict"; import { test } from "node:test"; import { publishRelease, type ReleaseInput } from "./release-client.js"; const input: ReleaseInput = { credential: "synthetic-test-value-not-a-real-credential", version: "1.2.3", commit: "a".repeat(40), notes: "Verified changes", jar: new Uint8Array([0x50, 0x4b, 0x03, 0x04]), }; function success(init: RequestInit): Response { return Response.json({ id: 42, draft: init.method !== "PATCH", tag_name: "v1.2.3", name: "purpur-potato-1.2.3.jar", size: input.jar.length, }); } test("creates a draft on the fixed repository and exact source commit, without following redirects", async () => { const calls: { url: string; init: RequestInit }[] = []; const id = await publishRelease(input, async (url, init) => { calls.push({ url, init }); return success(init); }); assert.ok(calls.length >= 1); const first = calls[0]!; assert.equal(first.url, "https://git.garvis.dev/api/v1/repos/dmg/purpur-potato/releases"); assert.equal(first.init.method, "POST"); assert.equal(first.init.redirect, "error"); assert.equal(new Headers(first.init.headers).get("authorization"), `token ${input.credential}`); assert.deepEqual(JSON.parse(String(first.init.body)), { tag_name: "v1.2.3", target_commitish: input.commit, name: "v1.2.3", body: input.notes, draft: true, prerelease: false, }); assert.equal(id, 42); }); test("uploads the exact versioned bytes before publishing the draft", async () => { const calls: { url: string; init: RequestInit }[] = []; await publishRelease(input, async (url, init) => { calls.push({ url, init }); return success(init); }); assert.equal(calls.length, 3); assert.equal(calls[1]!.url, "https://git.garvis.dev/api/v1/repos/dmg/purpur-potato/releases/42/assets?name=purpur-potato-1.2.3.jar"); assert.equal(calls[1]!.init.method, "POST"); assert.deepEqual(new Uint8Array(await new Response(calls[1]!.init.body).arrayBuffer()), input.jar); assert.equal(new Headers(calls[1]!.init.headers).get("content-type"), "application/octet-stream"); assert.equal(calls[2]!.init.method, "PATCH"); assert.equal(calls[2]!.url, "https://git.garvis.dev/api/v1/repos/dmg/purpur-potato/releases/42"); assert.deepEqual(JSON.parse(String(calls[2]!.init.body)), { draft: false }); for (const call of calls) { assert.equal(call.init.redirect, "error"); assert.equal(new Headers(call.init.headers).get("authorization"), `token ${input.credential}`); assert.ok(!call.url.includes(input.credential)); } }); for (const failureStep of [1, 2, 3]) { for (const status of [302, 401, 409, 500]) { test(`stops at step ${failureStep} on HTTP ${status} without leaking API error bodies`, async () => { let calls = 0; await assert.rejects(publishRelease(input, async (_url, init) => { calls++; if (calls === failureStep) return new Response(input.credential, { status }); return success(init); }), (error: unknown) => { assert.ok(error instanceof Error); assert.ok(error.message.includes(String(status))); assert.ok(!error.message.includes(input.credential)); return true; }); assert.equal(calls, failureStep, "Do not retry, overwrite an asset or publish after a failed step"); }); } } test("sanitizes transport errors and does not follow a redirect with the credential", async () => { await assert.rejects(publishRelease(input, async () => { throw new Error(`diagnostic containing ${input.credential}`); }), { message: "Release API request failed." }); }); for (const invalid of [ { credential: "" }, { credential: "header\r\ninjection" }, { version: "../../latest" }, { version: "1.0.0-SNAPSHOT" }, { commit: "main" }, { jar: new Uint8Array() }, ]) { test(`rejects invalid ${Object.keys(invalid)[0]} before any network request`, async () => { let calls = 0; await assert.rejects(publishRelease({ ...input, ...invalid }, async () => { calls++; return Response.json({ id: 42 }); }), { message: "Invalid release input." }); assert.equal(calls, 0); }); } for (const body of ["not JSON", "null", JSON.stringify({ id: -1 }), JSON.stringify({ id: "../other" }), JSON.stringify({ id: 42, draft: false, tag_name: "v1.2.3" })]) { test(`rejects malformed or already-public draft response: ${body}`, async () => { let calls = 0; await assert.rejects(publishRelease(input, async () => { calls++; return new Response(body); }), { message: "Invalid draft release response." }); assert.equal(calls, 1); }); } for (const [failureStep, body] of [ [2, {}], [2, { name: "other.jar", size: 4 }], [2, { name: "purpur-potato-1.2.3.jar", size: 0 }], [3, { id: 42, draft: true, tag_name: "v1.2.3" }], [3, { id: 77, draft: false, tag_name: "v1.2.3" }], [3, { id: 42, draft: false, tag_name: "v8.8.8" }], ] as const) { test(`requires a matching asset and completed publication: ${JSON.stringify(body)}`, async () => { let calls = 0; await assert.rejects(publishRelease(input, async (_url, init) => { calls++; return calls === failureStep ? Response.json(body) : success(init); }), { message: failureStep === 2 ? "Invalid release asset response." : "Invalid published release response." }); assert.equal(calls, failureStep); }); }