| 1 | // node --test scripts/cli-release.test.mjs |
| 2 | import assert from "node:assert/strict"; |
| 3 | import { createPrivateKey } from "node:crypto"; |
| 4 | import { mkdtempSync, readFileSync, rmSync, writeFileSync } from "node:fs"; |
| 5 | import { tmpdir } from "node:os"; |
| 6 | import { join } from "node:path"; |
| 7 | import { test } from "node:test"; |
| 8 | |
| 9 | import { BUILDER, TARGETS, builderArgs, builderScript, manifest, sha256, version } from "./cli-release.mjs"; |
| 10 | import { keygen, signBytes, verifyBytes } from "./runner-release.mjs"; |
| 11 | |
| 12 | test("a workflow's build uses the job's Cargo registry, which the crates cache restores", () => { |
| 13 | const job = builderArgs({ root: "/home/runner/work/repo", env: { GITHUB_ACTIONS: "true" }, home: "/home/node" }); |
| 14 | assert.ok(job.includes("/home/node/.cargo/registry:/usr/local/cargo/registry"), job.join(" ")); |
| 15 | assert.ok(job.includes("/home/runner/work/repo:/src")); |
| 16 | assert.equal(job.at(-1), BUILDER); |
| 17 | // Elsewhere a Docker volume keeps it. |
| 18 | assert.ok(builderArgs({ root: "/x", env: {}, home: "/h" }).includes("g1t-cargo-registry:/usr/local/cargo/registry")); |
| 19 | // What the container wrote as root goes back to the user, even when the build fails. |
| 20 | const script = builderScript("x86_64-unknown-linux-musl", "1000:1000"); |
| 21 | assert.match(script, /^trap 'chown -R 1000:1000 \/src\/target\/zig \/usr\/local\/cargo\/registry' EXIT; set -e;/); |
| 22 | assert.ok(!builderScript("t", null).includes("chown")); |
| 23 | }); |
| 24 | |
| 25 | test("the version is crates/g1t's", () => { |
| 26 | assert.match(version(), /^\d+\.\d+\.\d+/); |
| 27 | }); |
| 28 | |
| 29 | test("the manifest and SHA256SUMS name each binary that was built", () => { |
| 30 | const dir = mkdtempSync(join(tmpdir(), "cli-release-")); |
| 31 | try { |
| 32 | writeFileSync(join(dir, TARGETS["linux-x64"].file), "linux"); |
| 33 | writeFileSync(join(dir, TARGETS["windows-x64"].file), "windows"); |
| 34 | const m = manifest(dir, "0.2.0", new Date("2026-10-12T00:00:00Z")); |
| 35 | assert.deepEqual(m, { |
| 36 | version: "0.2.0", |
| 37 | published_at: "2026-10-12T00:00:00.000Z", |
| 38 | files: { |
| 39 | "linux-x64": { name: "g1t-linux-x64", sha256: sha256("linux") }, |
| 40 | "windows-x64": { name: "g1t-windows-x64.exe", sha256: sha256("windows") }, |
| 41 | }, |
| 42 | }); |
| 43 | // The install scripts read `<sha256> <name>` lines. |
| 44 | assert.equal( |
| 45 | readFileSync(join(dir, "SHA256SUMS"), "utf8"), |
| 46 | `${sha256("linux")} g1t-linux-x64\n${sha256("windows")} g1t-windows-x64.exe\n`, |
| 47 | ); |
| 48 | assert.equal(readFileSync(join(dir, "latest.json"), "utf8"), readFileSync(join(dir, "manifest.json"), "utf8")); |
| 49 | const keys = keygen(); |
| 50 | const key = createPrivateKey({ key: Buffer.from(keys.private, "base64"), format: "der", type: "pkcs8" }); |
| 51 | const bytes = readFileSync(join(dir, "latest.json")); |
| 52 | assert.ok(verifyBytes(bytes, signBytes(bytes, key), keys.public)); |
| 53 | } finally { |
| 54 | rmSync(dir, { recursive: true, force: true }); |
| 55 | } |
| 56 | }); |
| 57 | |
| 58 | test("a manifest of nothing is refused", () => { |
| 59 | const dir = mkdtempSync(join(tmpdir(), "cli-release-")); |
| 60 | try { |
| 61 | assert.throws(() => manifest(dir, "0.2.0"), /no binaries/); |
| 62 | } finally { |
| 63 | rmSync(dir, { recursive: true, force: true }); |
| 64 | } |
| 65 | }); |